Using Multiple Phidgets: Difference between revisions

From Phidgets Support
No edit summary
 
(40 intermediate revisions by 5 users not shown)
Line 1: Line 1:
[[Category:Programming]]{{Recommended_Flow_Links|{{Flow Page Number|{{PAGENAME}} }} }}
__NOTOC__
Chances are your project with Phidgets is going to involve more than one Phidget channel. Luckily, making a program that deals with multiple Phidgets is done in much the same way as making a program that only deals with one.


It is possible to use more than one Phidget within your program.  The trick lies in using a unique identifier for each one.  You can either hard-code the [[#Using the Serial Number|serial number in by hand]] (the number will be on the bottom of the board, or you can run our example code for the Phidget to obtain it on-screen), or you can use the [[#Using the Manager|Phidget Manager within your program]] to detect attached devices and return their serial numbers and object types.
This video explains the process of using multiple Phidgets in your program:
<center>{{#ev:youtube|17VQNQlrxxU|||||rel=0}}</center>


====Using the Serial Number====
==The Basics==


Each Phidget has a unique serial number.  Using this serial number, you can [[Phidget Programming Basics#Opening the Phidget|open]] the object belonging to a specific Phidget.
To use more than one Phidget channel in you program, simply repeat the ''Create'', ''Address'', and, ''Open'' process for each channel, and remember to ''Close'' them all when done.  


For example, in Java, this would be:
===Addressing Channels===
<div class="source">
 
<syntaxhighlight lang=java>
When you are using more than one Phidget channel in your program, you are going to have to specify some addressing parameters to ensure each software channel connects to the right Phidget.
device.setDeviceSerialNumber();
 
  device.open();
Full descriptions of all the addressing parameters can be found on the [[Addressing Phidgets]] page.
 
===Example===
 
For example, to open two Phidgets, the code might be:
<tabber>
Python=<syntaxhighlight lang=python>
#Set up the first channel as normal
ch = TemperatureSensor()
ch.setDeviceSerialNumber(12345)
ch.setHubPort(4)
ch.setChannel(0)
ch.openWaitForAttachment(5000)
 
#For a second channel, simply repeat the process with different addressing information
ch1 = TemperatureSensor()
ch1.setDeviceSerialNumber(12345)
ch1.setHubPort(3)
ch1.setChannel(0)
ch1.openWaitForAttachment(5000)
   
#Do stuff with your Phidgets here...
 
#Remember to close the channels when done
ch.close()
ch1.close()
</syntaxhighlight>
</syntaxhighlight>
</div>
|-|
Java=<syntaxhighlight lang=java>
//Set up the first channel as normal
TemperatureSensor ch = new TemperatureSensor();
ch.setDeviceSerialNumber(12345);
ch.setHubPort(4);
ch.setChannel(0);
ch.open(5000);
 
//For a second channel, simply repeat the process with different addressing information
TemperatureSensor ch1 = new TemperatureSensor();
ch1.setDeviceSerialNumber(12345);
ch1.setHubPort(3);
ch1.setChannel(0);
ch1.open(5000);
//Do stuff with your Phidgets here...


Or in C:
//Remember to close the channels when done
<div class="source">
ch.close();
<syntaxhighlight lang=cpp>
ch1.close();
Phidget_setDeviceSerialNumber((CPhidgetHandle) device, serialNumber);
Phidget_open((CPhidgetHandle) device);
</syntaxhighlight>
</syntaxhighlight>
</div>
|-|
C#=<syntaxhighlight lang=cSharp>
//Set up the first channel as normal
TemperatureSensor ch = new TemperatureSensor();
ch.DeviceSerialNumber = 12345;
ch.HubPort = 4;
ch.Channel = 0;
ch.Open(5000);


====Using the Label====
//For a second channel, simply repeat the process with different addressing information
TemperatureSensor ch1 = new TemperatureSensor();
ch1.DeviceSerialNumber = 12345;
ch1.HubPort = 3;
ch1.Channel = 0;
ch1.Open(5000);
//Do stuff with your Phidgets here...


This section should be reviewed closer to release once we're sure of Label support
//Remember to close the channels when done
ch.Close();
ch1.Close();
</syntaxhighlight>
|-|
C=<syntaxhighlight lang=c>
//Set up the first channel as normal
PhidgetTemperatureSensorHandle ch;
PhidgetTemperatureSensor_create(&ch);


<font color=red>
Phidget_setDeviceSerialNumber((PhidgetHandle)ch, 12345);
If you want to have a human-readable way to reference your Phidget (as opposed to a serial number), or to have multiple different Phidgets of the same type with the same handle (for re-usable system code), you can use the Label feature of Phidgets.  In many development setups, you can change the label to whatever you like, get the label within your code, and open a Phidget based on its label, for any newer generation Phidget.  The disadvantage of Labels is that they are not available on all operating systems and languages.
Phidget_setHubPort((PhidgetHandle)ch, 4);
Phidget_setChannel((PhidgetHandle)ch, 0);
Phidget_openWaitForAttachment((PhidgetHandle)ch, 5000);


Some limitations are:
//For a second channel, simply repeat the process with different addressing information
* You cannot '''set''' a label using any language in [[OS - Windows|Windows]], for any language
PhidgetTemperatureSensorHandle ch1;
**However, you can get the label of a Phidget on Windows, and open a Phidget by its label
PhidgetTemperatureSensor_create(&ch1);
* [[Language - Android Java|Android Java]] has support for only a subset of the open() functions that use labels, see the [[Language - Android Java|Android Java language page]] for details
* Older Phidgets do not support labels
* [[Language - LabVIEW|LabVIEW]] cannot open by label
* [[Language - Python|Python]] cannot open by label


When opening by label, you would use the {{Code|openLabel("mylabel")}} function (or similar, check the [[Software Overview#Language Support|API for your language]]) rather than the generic open() function.
Phidget_setDeviceSerialNumber((PhidgetHandle)ch1, 12345);
Phidget_setHubPort((PhidgetHandle)ch1, 4);
Phidget_setChannel((PhidgetHandle)ch1, 0);
Phidget_openWaitForAttachment((PhidgetHandle)ch1, 5000);
//Do stuff with your Phidgets here...


Note that setting the label should be done by a separate program.  On a Mac OS computer, you can set a label through the Phidget Preference Pane.  On a Linux computer, you should write a special short program specifically for setting the label.  There are two reasons to '''not''' set a label within your main program:
//Remember to close the channels when done
* If you set a label every time you run that program, when not needing to, you can easily reach the 10,000 re-write limit for the flash that stores the label
Phidget_close((PhidgetHandle)ch);
* If you are using event driven programming, you cannot set the label from any function called from the attach event, as it will hang (on a mutual exclusion lock).
Phidget_close((PhidgetHandle)ch1);
Because of the second point, your special program to set the label on a Phidget should use {{Code|waitForAttach()}} in [[Polling vs. Events|logic code]] and not [[Polling vs. Events|event-driven]] programming
PhidgetTemperatureSensor_delete(&ch);
</font>
PhidgetTemperatureSensor_delete(&ch1);
</syntaxhighlight>
|-|
JavaScript=<syntaxhighlight lang=javascript>
// Set up the first channel as normal
const ch = new phidget22.TemperatureSensor()
ch.deviceSerialNumber = 12345
ch.hubPort = 4
ch.channel = 0
await ch.open(5000)


====Using the Manager====
// For a second channel, simply repeat the process with different addressing information
const ch1 = new phidget22.TemperatureSensor()
ch1.deviceSerialNumber = 12345
ch1.hubPort = 3
ch1.channel = 0
await ch1.open(5000)
// Do stuff with your Phidgets here...


The [[Phidget Manager]] object can detect all Phidgets as they attach to a system.  In your attach handler, you can read the serial number of each Phidget and deal with each one individually. This is the preferred method for systems where you will be using multiple Phidgets and expecting the system to operate long enough (or under harsh enough conditions) that the Phidgets would need to be replaced without having to update the code by hard-coding in serial numbers.
// Remember to close the channels when done
await ch.close()
await ch1.close()
</syntaxhighlight>
</tabber>


This is especially true for running programs [[OS - Phidget SBC#Running a Program Automatically| automatically at scheduled times on the Single Board Computer]], where you would be replacing Phidgets without the benefit of keyboard or screen.
==Similar Phidgets==


For example, in Java (note for Enumerations you also need to include {{Code|java.util.*}}):
If you have a large number of the same Phidget channel and want an easier way to keep track of them all, consider using an array to keep them all together.


<div class="source">
<tabber>
<syntaxhighlight lang=java>
Python=<syntaxhighlight lang=python>
#Create the array of Phidget channels
ch = [DigitalOutput() for i in range (0, 8)]


List<int> serials = new ArrayList<int>();
for i in range (0, 8):
    #Address, then open the channels
    ch[i].setChannel(i)
    ch[i].openWaitForAttachment(5000)


public static void main(String[] args) throws Exception {
#Now you can access each channel by its position in the array
ch[0].setState(True)
ch[1].setState(False)
ch[2].setState(False)
ch[3].setState(True)


  // Create and open the manager
for i in range (0, 8):
  Manager manager = new Manager();
    ch[i].close()
</syntaxhighlight>
|-|
Java=<syntaxhighlight lang=java>
//Create an array for your Phidget channels
DigitalOutput[] ch = new DigitalOutput[8];


  // define the attach handler
for(int i = 0; i < 8; i++) {
  manager.addAttachListener((ManagerAttachEvent ev)->{
    //Create the channels
            Phidget phid = ev.getChannel();
    ch[i] = new DigitalOutput();
            try{
    //Address, then open the channels
                serials.add(phid.getDeviceSerialNumber());
    ch[i].setChannel(i);
            }catch(PhidgetException ex){
    ch[i].open(5000);
                System.out.println(ex.getDescription());
}
            }
  });


  try {
//Now you can access each channel by its position in the array
      manager.open();
ch[0].setState(true);
  } catch (PhidgetException exception) {
ch[1].setState(false);
      printError(exception.getErrorNumber(), exception.getDescription());
ch[2].setState(false);
  }
ch[3].setState(true);


  // Wait for all of the attach events for already-attached Phidgets to resolve
//Close all channels when done
  Thread.sleep(1000);
for(int i=0; i<8; i++) {
    ch[i].close();
}


  // Retrieve the list of attached Phidgets' serial numbers
</syntaxhighlight>
  serials.forEach(serial -> System.out.println(serial));
|-|
C#=<syntaxhighlight lang=cSharp>
//Create an array for your Phidget channels
DigitalOutput[] ch = new DigitalOutput[8];


  // Close the manager
  try {
      manager.close();
  } catch (PhidgetException exception) {
      printError(exception.getErrorNumber(), exception.getDescription());
  }
  manager = null;


  // Do something with names and serial numbers stored above (i.e. open and use Phidget objects)
//Open the channels
  ....
for(int i=0; i<8; i++)
{
    //Create the channels
    ch[i] = new DigitalOutput();
    //Address, then open the channels
    ch[i].Channel = i;
    ch[i].Open(5000);
}
 
//Now you can access each channel by its position in the array
ch[0].State = true;
ch[1].State = false;
ch[2].State = false;
ch[3].State = true;
 
//Close the channels when done
for(int i=0; i<8; i++)
{
    ch[i].Close();
}
</syntaxhighlight>
</syntaxhighlight>
</div>
|-|
C=<syntaxhighlight lang=c>
//Create an array for your Phidget channels
PhidgetDigitalOutputHandle ch[8];


for (int i = 0; i < 8; i++) {
    //Create the channels
    PhidgetDigitalOutput_create(&ch[i]);
    //Address, then open the channels
    Phidget_setChannel((PhidgetHandle)ch[i], i);
    Phidget_openWaitForAttachment((PhidgetHandle)ch[i], 5000);
}


Or, in C:
PhidgetDigitalOutput_setState(ch[0], true);
PhidgetDigitalOutput_setState(ch[1], false);
PhidgetDigitalOutput_setState(ch[2], false);
PhidgetDigitalOutput_setState(ch[3], true);


//Close the channels when done
for (int i = 0; i < 8; i++) {
    Phidget_close((PhidgetHandle)ch[i]);
}
</syntaxhighlight>
|-|
JavaScript=<syntaxhighlight lang=javascript>
// Create the array of Phidget channels
var ch = []


<div class="source">
for(i = 0; i < 8; i++) {
<syntaxhighlight lang=cpp>


int serials[100];
// Create, address, then open the channels
 
var tmp = new phidget22.DigitalInput()
int main() {
tmp.channel = i
await tmp.open(5000)
    // Define the manager handle and create
ch.push(tmp)
    PhidgetManagerHandle device = 0;
    PhidgetManager_create(&device);
    // Set up event handlers
    PhidgetManager_setOnAttachHandler(device, AttachHandler, NULL);
    PhidgetManager_setOnDetachHandler(device, DetachHandler, NULL);
    // Open the Phidget Manager
    PhidgetManager_open(device);
    // Do something with the non-zero numbers stored in the serials[] array, like open(), control, etc.
    ....
    // Close and clean up manager object
    PhidgetManager_close(device);
    PhidgetManager_delete(&device);
    return 0;
}
}


void CCONV AttachHandler(PhidgetManagerHandle manager, void *userptr, PhidgetHandle device) {
// Now you can access each channel by its position in the array
ch[0].state = True
ch[1].state = False
ch[2].state = False
ch[3].state = True


    const char *serialnum;
for(i = 0; i < 8; i++) {
    int i;
await ch[i].close()
    Phidget_getDeviceSerialNumber(device, &serialnum);
    for(i=0; i < 100; i++) {
          if(serials[i] == 0) {
              serials[i] = serialnum;
              break;
          }
    }
   
    if(i == 100)
          printf("Serial array is full.\n");
}
}
</syntaxhighlight>
</tabber>
==Distinguishing Events==


void CCONV DetachHandler(PhidgetManagerHandle manager, void *userptr, PhidgetHandle device) {
When using [[Polling vs. Events|events]], you can either create separate events for each device, or handle multiple devices with the same event (or some combination of both). If multiple devices use the same event handler, you can use the addressing properties of the channel to determine which Phidget channel caused the event.
   
    const char *serialNumber;
    // Get the serial number of the detached device and clear it from the list
    Phidget_getDeviceSerialNumber(device, &serialNumber);


    for(int i=0; i < 100; i++) {
For example, for an Attach Event handler:
          if(serials[i] == serialNumber)
              serials[i] = 0;
    }


<tabber>
Python=
In Python, the channel that fired the event can be accessed from the event handler using the {{code|self}} parameter (the first parameter in the list).
<syntaxhighlight lang=python>
#Declare the event handler
def onAttachHandler(self):
    #You can access the Phidget that fired the event using the "self" parameter
    ph = self
    deviceSerialNumber = ph.getDeviceSerialNumber()
...
#Declare your object. Replace "DigitalInput" with the object for your Phidget
ch = DigitalInput()
...
#Assign the handler that will be called when the event occurs
ch.setOnAttachHandler(onAttachHandler)
</syntaxhighlight>
|-|
Java=
In Java, you can call {{code|getSource()}} on the event parameter to get the Phidget that caused the event.
<syntaxhighlight lang=java>
//Declare the event listener
public static AttachListener onAttach = new AttachListener() {
    @Override
    public void onAttach(AttachEvent e) {
        //You can access the Phidget that fired the event by calling "getSource()"
        //on the event parameter.
        //Replace "DigitalInput" with the object for your Phidget.
        DigitalInput ph = (DigitalInput) e.getSource();
        int deviceSerialNumber = ph.getDeviceSerialNumber();
    }
};
...
//Declare your object. Replace "DigitalInput" with the object for your Phidget.
DigitalInput ch;
...
//Assign the event listener that will be called when the event occurs
ch.addAttachListener(onAttach);
</syntaxhighlight>
|-|
C#=
In C#, you can access the Phidget that fired the event by typecasting the {{code|sender}} parameter to the appropriate Phidget object type.
<syntaxhighlight lang=cSharp>
//Declare the event handler
void attach(object sender, Phidget22.Events.AttachEventArgs e) {
    //You can access the Phidget that fired the event by typecasting "sender"
    //to the appropriate Phidget object type.
    //Replace "DigitalInput" with the object for your Phidget.
    DigitalInput ph = ((DigitalInput)sender);
    int deviceSerial = ph.DeviceSerialNumber;
}
...
//Declare your object. Replace "DigitalInput" with the object for your Phidget.
DigitalInput ch;
...
//Assign the handler that will be called when the event occurs
ch.Attach += attach;
</syntaxhighlight>
|-|
C=
In C, you can access the Phidget that fired the event using the first parameter of the event handler.
<syntaxhighlight lang=c>
//Declare the event handler
static void CCONV onAttachHandler(PhidgetHandle ph, void *ctx) {
    //You can access the Phidget that fired the event by using the first parameter
    //of the event handler
    int deviceSerialNumber;
    Phidget_getDeviceSerialNumber(ph, &deviceSerialNumber);
}
}
...
//Declare your object. Replace "PhidgetDigitalInputHandle" with the handle for your Phidget object.
PhidgetDigitalInputHandle ch;
...
//Assign the handler that will be called when the event occurs
Phidget_setOnAttachHandler((PhidgetHandle)ch, onAttachHandler, NULL);
</syntaxhighlight>
|-|
JavaScript=
In JavaScript, you can access the Phidget that fired the event using the 'this' property.
<syntaxhighlight lang=c>
// Declare your object. Replace "DigitalInput" with the object for your Phidget
const ch = new phidget22.DigitalInput()


// Assign the handler that will be called when the event occurs
ch.onAttach = function {
    // You can access the Phidget that fired the event using the "this" parameter
    let deviceSerial = this.deviceSerialNumber
}
</syntaxhighlight>
</syntaxhighlight>
</div>
</tabber>


In either example, serial numbers are gathered as Phidgets attached so they can be used later. You may want to gather other pieces of data such as device name and channel number for your program to eventually use.
==Referencing Other Phidgets from Events==


====Distinguishing Events====
When using multiple Phidgets in the same program, you may want to access one Phidget from the within an event caused by another. There are simple ways of doing this for all languages, though the specifics depend on the programming language you are using:


If you are using [[Polling vs. Events|event-driven code]], once you have correctly opened multiple Phidgets of different types, they will have different event handlers and hence you will know what Phidget triggered which event. 
<tabber>
If you are using multiple Phidgets of the same type, or you are trying to determine within general events (such as Attach Events) which Phidget triggered the event, you can then check the serial number (or device type) of the triggering device and act accordingly.
Python=
Python is dynamically interpreted, and objects follow a less rigid structure than in other languages. To access another Phidget from an event handler, you can add the second Phidget's handle as an attribute of the Phidget object that will be triggering the event. Then, you can access the second Phidget using the corresponding attribute from the {{code|self}} parameter of the event.


For example, in Java, your [[Phidget_Programming_Basics#Attaching_the_Phidget|attach event handler]] might look like this:
For example, if we wanted to make a Digital Output channel follow the state of a button:
<div class="source">
<syntaxhighlight lang=python>
def onStateChangeHandler(self, state):
    #Be sure the other Phidget you are trying to access is attached before using it
    if(self.linkedOutput.getAttached()):
        self.linkedOutput.setState(state)
 
button = DigitalInput()
output = DigitalOutput()
 
#Addressing info here
 
#Here we create an attribute of input called "linkedOutput", and assign it the handle for output
button.linkedOutput = output
button.setOnStateChangeHandler(onStateChangeHandler)
 
#Be sure to open any channels you are using within events before the channels
#that cause the events.
#This gives them a chance to be attached before the event tries to use them.
output.openWaitForAttachment(5000)
button.openWaitForAttachment(5000)
 
# The rest of your code here....
</syntaxhighlight>
|-|
Java=
In Java, chances are your event handlers are defined in the same class as the Phidget handles. In this case, you can simply reference Phidgets in the event handlers the same way as you would in the rest of your code.
 
For example, if we wanted to make a Digital Output channel follow the state of a button:
<syntaxhighlight lang=java>
<syntaxhighlight lang=java>
     detachHandler = new DetachListener() {  
public class MultiPhidgetExample {
         public void detached(DetachEvent event) {
      
             int serialNumber = ((Phidget)event.getSource()).getSerialNumber();
    private static DigitalInput button = null;
             // Do something according to serialNumber
    private static DigitalOutput output = null;
     }   }
   
    public static DigitalInputStateChangeListener onStateChange =
        new DigitalInputStateChangeListener() {
         @Override
        public void onStateChange(DigitalInputStateChangeEvent e) {
 
            //Be sure the other Phidget you are trying to access is attached before using it
            if(output.getAttached() == true)
                output.setState(e.getState());
        }
    };
   
    public static void main(String[] args) throws Exception {
        try {
             button = new DigitalInput();
output = new DigitalOutput();
 
            //Set Any Addressing Parameters Here
 
            button.addStateChangeListener(onStateChange);
 
            //Be sure to open any channels you are using within events before the channels
            //that cause the events.
            //This gives them a chance to be attached before the event tries to use them.
            output.open(5000);
            button.open(5000);
           
             // The rest of your code here...
           
        } catch (PhidgetException ex) {
            System.out.println(ex.getDescription());
        }
     }
}
</syntaxhighlight>
</syntaxhighlight>
</div>
|-|
C#=
In C#, chances are your event handlers are defined in the same class as the Phidget handles. In this case, you can simply reference Phidgets in the event handlers the same way as you would in the rest of your code.


For example, if we wanted to make a Digital Output channel follow the state of a button:
<syntaxhighlight lang=cSharp>
namespace ConsoleApplication
{
    class Program
    {
        private static DigitalInput button = null;
        private static DigitalOutput output = null;


Or in C:
        private static void onStateChange(object sender,
<div class="source">
                              DigitalInputStateChangeEventArgs e)
<syntaxhighlight lang=cpp>
        {
    int AttachHandler(CPhidgetHandle device, void *userptr) {
            //Be sure the other Phidget you are trying to access is attached before using it
int serialNo;
            if (output.Attached == true)
CPhidget_getSerialNumber(device, &serialNo);
                output.State = e.State;
        // Do something according to serialNumber
        }
 
        static void Main(string[] args)
        {
            button = new DigitalInput();
            output = new DigitalOutput();
           
            //Set Any Addressing Parameters Here
           
            button.StateChange += onStateChange;
 
            //Be sure to open any channels you are using within events before the channels
            //that cause the events.
            //This gives them a chance to be attached before the event tries to use them.
            output.Open(5000);
            button.Open(5000);
           
            //The rest of your code here...
        }
     }
     }
}
</syntaxhighlight>
</syntaxhighlight>
</div>
|-|
C=
In C, all event handler declarations have a context pointer that can be pointed at any object you choose. This can be a set of relevant data, or even a Phidget handle. If you pass a Phidget handle as the context pointer for an event, you can access the passed Phidget from the event as follows:


=== Further Reading ===
For example, if we wanted to make a Digital Output channel follow the state of a button:
<syntaxhighlight lang=C>
static void CCONV onStateChangeHandler(PhidgetDigitalInputHandle pdih, void *ctx, int state) {
    int attached;
    //Extract our output handle from the context pointer
    PhidgetDigitalOutputHandle linkedOutput = (PhidgetDigitalOutputHandle)ctx;


[[Phidget Programming Basics]] - Here you can find the basic concepts to help you get started with making your own programs that use Phidgets.
    //Be sure the other Phidget you are trying to access is attached before using it
    Phidget_getAttached((PhidgetHandle)linkedOutput, &attached);


[[Data Interval/Change Trigger]] - Learn about these two properties that control how much data comes in from your sensors.
    if(attached)
        PhidgetDigitalOutput_setState(linkedOutput, state);


[[Polling vs. Events]] - Your program can gather data in either a polling-driven or event-driven manner. Learn the difference to determine which is best for your application.
}


[[Logging, Exceptions, and Errors]] - Learn about all the tools you can use to debug your program.
int main() {
    PhidgetDigitalInputHandle button = NULL;
    PhidgetDigitalOutputHandle output = NULL;
 
    PhidgetDigitalInput_create(&button);
    PhidgetDigitalOutput_create(&output);
   
    //Addressing info here
 
    //Here we pass the handle for "output" as the context pointer so we can access it from the event
    PhidgetDigitalInput_setOnStateChangeHandler(ch, onStateChangeHandler, output);
   
    //Be sure to open any channels you are using within events before the channels
    //that cause the events.
    //This gives them a chance to be attached before the event tries to use them.
    Phidget_openWaitForAttachment((PhidgetHandle)output, 5000);
    Phidget_openWaitForAttachment((PhidgetHandle)button, 5000);
 
    //The rest of your code here...
 
}
</syntaxhighlight>
|-|
JavaScript=
JavaScript is dynamically interpreted, and objects follow a less rigid structure than in other languages. To access another Phidget from an event handler, you can add the second Phidget's handle as a property of the Phidget object that will be triggering the event. Then, you can access the second Phidget using the corresponding property from the {{code|this}} parameter of the event.
 
For example, if we wanted to make a Digital Output channel follow the state of a button:
<syntaxhighlight lang=javaScript>
 
    const button = new phidget22.DigitalInput();
    const output = new phidget22.DigitalOutput();
...
    //Here we create an attribute of input called "linkedOutput", and assign it the handle for output
    button.linkedOutput = output;
    button.onStateChange = function(state){
        //Be sure the other Phidget you are trying to access is attached before using it
        if(this.linkedOutput.attached)
          this.linkedOutput.state = state;
}
 
    await output.open();
    await button.open();
 
    //The rest of your code here...
</syntaxhighlight>
</tabber>


[[Phidget Network Server]] - Phidgets can be controlled and communicated with over your network- either wirelessly or over ethernet.
==What's Next?==
Now that you know how to use multiple Phidgets in your program, we should discuss how to find the features available to you by using the Phidget22 API.


[[Best Phidgets Practices]] - Good programming habits that will save you from common problems when writing code for your Phidgets.
{{Flow_Navigation_Buttons|{{Flow Page Number|{{PAGENAME}} }} }}

Latest revision as of 21:05, 19 April 2022

 Phidget Programming Basics: Using Multiple PhidgetsTOC Icon.png Table of Contents

Nav Back Arrow.png Nav Back Hover.png WhiteTab1.png HoverTab1.jpg WhiteTab2.png HoverTab2.jpg WhiteTab3.png HoverTab3.jpg WhiteTab4.png HoverTab4.jpg WhiteTab5.png HoverTab5.jpg WhiteTab6.png HoverTab6.jpg WhiteTab7.png HoverTab7.jpg WhiteTab8.png HoverTab8.jpg WhiteTab9.png HoverTab9.jpg WhiteTab10.png HoverTab10.jpg WhiteTab11.png HoverTab11.jpg GreenTab12.png WhiteTab13.png HoverTab13.jpg WhiteTab14.png HoverTab14.jpg WhiteTab15.png HoverTab15.jpg WhiteTab16.png HoverTab16.jpg Nav Next Arrow.png Nav Next Hover.png


12 . Using Multiple Phidgets

Chances are your project with Phidgets is going to involve more than one Phidget channel. Luckily, making a program that deals with multiple Phidgets is done in much the same way as making a program that only deals with one.

This video explains the process of using multiple Phidgets in your program:

The Basics

To use more than one Phidget channel in you program, simply repeat the Create, Address, and, Open process for each channel, and remember to Close them all when done.

Addressing Channels

When you are using more than one Phidget channel in your program, you are going to have to specify some addressing parameters to ensure each software channel connects to the right Phidget.

Full descriptions of all the addressing parameters can be found on the Addressing Phidgets page.

Example

For example, to open two Phidgets, the code might be:

#Set up the first channel as normal
ch = TemperatureSensor()
ch.setDeviceSerialNumber(12345)
ch.setHubPort(4)
ch.setChannel(0)
ch.openWaitForAttachment(5000)

#For a second channel, simply repeat the process with different addressing information
ch1 = TemperatureSensor()
ch1.setDeviceSerialNumber(12345)
ch1.setHubPort(3)
ch1.setChannel(0)
ch1.openWaitForAttachment(5000)
 
#Do stuff with your Phidgets here...

#Remember to close the channels when done
ch.close()
ch1.close()
//Set up the first channel as normal
TemperatureSensor ch = new TemperatureSensor();
ch.setDeviceSerialNumber(12345);
ch.setHubPort(4);
ch.setChannel(0);
ch.open(5000);

//For a second channel, simply repeat the process with different addressing information
TemperatureSensor ch1 = new TemperatureSensor();
ch1.setDeviceSerialNumber(12345); 
ch1.setHubPort(3);
ch1.setChannel(0);
ch1.open(5000);
 
//Do stuff with your Phidgets here...

//Remember to close the channels when done
ch.close();
ch1.close();
//Set up the first channel as normal
TemperatureSensor ch = new TemperatureSensor();
ch.DeviceSerialNumber = 12345;
ch.HubPort = 4;
ch.Channel = 0;
ch.Open(5000);

//For a second channel, simply repeat the process with different addressing information
TemperatureSensor ch1 = new TemperatureSensor();
ch1.DeviceSerialNumber = 12345; 
ch1.HubPort = 3;
ch1.Channel = 0;
ch1.Open(5000);
 
//Do stuff with your Phidgets here...

//Remember to close the channels when done
ch.Close();
ch1.Close();
//Set up the first channel as normal
PhidgetTemperatureSensorHandle ch;
PhidgetTemperatureSensor_create(&ch);

Phidget_setDeviceSerialNumber((PhidgetHandle)ch, 12345);
Phidget_setHubPort((PhidgetHandle)ch, 4);
Phidget_setChannel((PhidgetHandle)ch, 0);
Phidget_openWaitForAttachment((PhidgetHandle)ch, 5000);

//For a second channel, simply repeat the process with different addressing information
PhidgetTemperatureSensorHandle ch1;
PhidgetTemperatureSensor_create(&ch1);

Phidget_setDeviceSerialNumber((PhidgetHandle)ch1, 12345);
Phidget_setHubPort((PhidgetHandle)ch1, 4);
Phidget_setChannel((PhidgetHandle)ch1, 0);
Phidget_openWaitForAttachment((PhidgetHandle)ch1, 5000);
 
//Do stuff with your Phidgets here...

//Remember to close the channels when done
Phidget_close((PhidgetHandle)ch);
Phidget_close((PhidgetHandle)ch1);
PhidgetTemperatureSensor_delete(&ch);
PhidgetTemperatureSensor_delete(&ch1);
// Set up the first channel as normal
const ch = new phidget22.TemperatureSensor()
ch.deviceSerialNumber = 12345
ch.hubPort = 4
ch.channel = 0
await ch.open(5000)

// For a second channel, simply repeat the process with different addressing information
const ch1 = new phidget22.TemperatureSensor()
ch1.deviceSerialNumber = 12345
ch1.hubPort = 3
ch1.channel = 0
await ch1.open(5000)
 
// Do stuff with your Phidgets here...

// Remember to close the channels when done
await ch.close()
await ch1.close()

Similar Phidgets

If you have a large number of the same Phidget channel and want an easier way to keep track of them all, consider using an array to keep them all together.

#Create the array of Phidget channels
ch = [DigitalOutput() for i in range (0, 8)]

for i in range (0, 8):
    #Address, then open the channels
    ch[i].setChannel(i)
    ch[i].openWaitForAttachment(5000)

#Now you can access each channel by its position in the array 
ch[0].setState(True)
ch[1].setState(False)
ch[2].setState(False)
ch[3].setState(True)

for i in range (0, 8):
    ch[i].close()
//Create an array for your Phidget channels
DigitalOutput[] ch = new DigitalOutput[8];

for(int i = 0; i < 8; i++) {
    //Create the channels
    ch[i] = new DigitalOutput();
    //Address, then open the channels
    ch[i].setChannel(i);
    ch[i].open(5000);
}

//Now you can access each channel by its position in the array 
ch[0].setState(true);
ch[1].setState(false);
ch[2].setState(false);
ch[3].setState(true);

//Close all channels when done
for(int i=0; i<8; i++) {
    ch[i].close();
}
//Create an array for your Phidget channels
DigitalOutput[] ch = new DigitalOutput[8];


//Open the channels
for(int i=0; i<8; i++)
{
    //Create the channels
    ch[i] = new DigitalOutput();
    //Address, then open the channels
    ch[i].Channel = i;
    ch[i].Open(5000);
}

//Now you can access each channel by its position in the array 
ch[0].State = true;
ch[1].State = false;
ch[2].State = false;
ch[3].State = true;

//Close the channels when done
for(int i=0; i<8; i++)
{
    ch[i].Close();
}
//Create an array for your Phidget channels
PhidgetDigitalOutputHandle ch[8];

for (int i = 0; i < 8; i++) {
    //Create the channels
    PhidgetDigitalOutput_create(&ch[i]);
    //Address, then open the channels
    Phidget_setChannel((PhidgetHandle)ch[i], i);
    Phidget_openWaitForAttachment((PhidgetHandle)ch[i], 5000);
}

PhidgetDigitalOutput_setState(ch[0], true);
PhidgetDigitalOutput_setState(ch[1], false);
PhidgetDigitalOutput_setState(ch[2], false);
PhidgetDigitalOutput_setState(ch[3], true);

//Close the channels when done
for (int i = 0; i < 8; i++) {
    Phidget_close((PhidgetHandle)ch[i]);
}
// Create the array of Phidget channels
var ch = []

for(i = 0; i < 8; i++) {

	// Create, address, then open the channels
	var tmp = new phidget22.DigitalInput()
	tmp.channel = i
	await tmp.open(5000)
	ch.push(tmp)
}

// Now you can access each channel by its position in the array 
ch[0].state = True
ch[1].state = False
ch[2].state = False
ch[3].state = True

for(i = 0; i < 8; i++) {
	await ch[i].close()
}

Distinguishing Events

When using events, you can either create separate events for each device, or handle multiple devices with the same event (or some combination of both). If multiple devices use the same event handler, you can use the addressing properties of the channel to determine which Phidget channel caused the event.

For example, for an Attach Event handler:

In Python, the channel that fired the event can be accessed from the event handler using the self parameter (the first parameter in the list).

#Declare the event handler
def onAttachHandler(self):
    #You can access the Phidget that fired the event using the "self" parameter
    ph = self
    deviceSerialNumber = ph.getDeviceSerialNumber()
...
#Declare your object. Replace "DigitalInput" with the object for your Phidget
ch = DigitalInput()
...
#Assign the handler that will be called when the event occurs
ch.setOnAttachHandler(onAttachHandler)

In Java, you can call getSource() on the event parameter to get the Phidget that caused the event.

//Declare the event listener
public static AttachListener onAttach = new AttachListener() {
    @Override
    public void onAttach(AttachEvent e) {
        //You can access the Phidget that fired the event by calling "getSource()"
        //on the event parameter.
        //Replace "DigitalInput" with the object for your Phidget.
        DigitalInput ph = (DigitalInput) e.getSource();
        int deviceSerialNumber = ph.getDeviceSerialNumber();
    }
};
...
//Declare your object. Replace "DigitalInput" with the object for your Phidget.
DigitalInput ch;
...
//Assign the event listener that will be called when the event occurs
ch.addAttachListener(onAttach);

In C#, you can access the Phidget that fired the event by typecasting the sender parameter to the appropriate Phidget object type.

//Declare the event handler
void attach(object sender, Phidget22.Events.AttachEventArgs e) {
    //You can access the Phidget that fired the event by typecasting "sender"
    //to the appropriate Phidget object type.
    //Replace "DigitalInput" with the object for your Phidget.
    DigitalInput ph = ((DigitalInput)sender);
    int deviceSerial = ph.DeviceSerialNumber;
}
...
//Declare your object. Replace "DigitalInput" with the object for your Phidget.
DigitalInput ch;
...
//Assign the handler that will be called when the event occurs
ch.Attach += attach;

In C, you can access the Phidget that fired the event using the first parameter of the event handler.

//Declare the event handler
static void CCONV onAttachHandler(PhidgetHandle ph, void *ctx) {
    //You can access the Phidget that fired the event by using the first parameter
    //of the event handler
    int deviceSerialNumber;
    Phidget_getDeviceSerialNumber(ph, &deviceSerialNumber);
}
...
//Declare your object. Replace "PhidgetDigitalInputHandle" with the handle for your Phidget object.
PhidgetDigitalInputHandle ch;
...
//Assign the handler that will be called when the event occurs
Phidget_setOnAttachHandler((PhidgetHandle)ch, onAttachHandler, NULL);

In JavaScript, you can access the Phidget that fired the event using the 'this' property.

// Declare your object. Replace "DigitalInput" with the object for your Phidget
const ch = new phidget22.DigitalInput()

// Assign the handler that will be called when the event occurs
ch.onAttach = function {
    // You can access the Phidget that fired the event using the "this" parameter
    let deviceSerial = this.deviceSerialNumber
}

Referencing Other Phidgets from Events

When using multiple Phidgets in the same program, you may want to access one Phidget from the within an event caused by another. There are simple ways of doing this for all languages, though the specifics depend on the programming language you are using:

Python is dynamically interpreted, and objects follow a less rigid structure than in other languages. To access another Phidget from an event handler, you can add the second Phidget's handle as an attribute of the Phidget object that will be triggering the event. Then, you can access the second Phidget using the corresponding attribute from the self parameter of the event.

For example, if we wanted to make a Digital Output channel follow the state of a button:

def onStateChangeHandler(self, state):
    #Be sure the other Phidget you are trying to access is attached before using it
    if(self.linkedOutput.getAttached()):
        self.linkedOutput.setState(state)

button = DigitalInput()
output = DigitalOutput()

#Addressing info here

#Here we create an attribute of input called "linkedOutput", and assign it the handle for output
button.linkedOutput = output
button.setOnStateChangeHandler(onStateChangeHandler)

#Be sure to open any channels you are using within events before the channels
#that cause the events.
#This gives them a chance to be attached before the event tries to use them.
output.openWaitForAttachment(5000)
button.openWaitForAttachment(5000)

# The rest of your code here....

In Java, chances are your event handlers are defined in the same class as the Phidget handles. In this case, you can simply reference Phidgets in the event handlers the same way as you would in the rest of your code.

For example, if we wanted to make a Digital Output channel follow the state of a button:

public class MultiPhidgetExample {
    
    private static DigitalInput button = null;
    private static DigitalOutput output = null;
    
    public static DigitalInputStateChangeListener onStateChange =
        new DigitalInputStateChangeListener() {
        @Override
        public void onStateChange(DigitalInputStateChangeEvent e) {

            //Be sure the other Phidget you are trying to access is attached before using it
            if(output.getAttached() == true)
                output.setState(e.getState());
        }
    };
    
    public static void main(String[] args) throws Exception {
        try {
            button = new DigitalInput();
			output = new DigitalOutput();

            //Set Any Addressing Parameters Here

            button.addStateChangeListener(onStateChange);

            //Be sure to open any channels you are using within events before the channels
            //that cause the events.
            //This gives them a chance to be attached before the event tries to use them.
            output.open(5000);
            button.open(5000);
            
            // The rest of your code here...
            
        } catch (PhidgetException ex) {
            System.out.println(ex.getDescription());
        }
    }
}

In C#, chances are your event handlers are defined in the same class as the Phidget handles. In this case, you can simply reference Phidgets in the event handlers the same way as you would in the rest of your code.

For example, if we wanted to make a Digital Output channel follow the state of a button:

namespace ConsoleApplication
{
    class Program
    {
        private static DigitalInput button = null;
        private static DigitalOutput output = null;

        private static void onStateChange(object sender,
                              DigitalInputStateChangeEventArgs e)
        {
            //Be sure the other Phidget you are trying to access is attached before using it
            if (output.Attached == true)
                output.State = e.State;
        }

        static void Main(string[] args)
        {
            button = new DigitalInput();
            output = new DigitalOutput();
            
            //Set Any Addressing Parameters Here
            
            button.StateChange += onStateChange;

            //Be sure to open any channels you are using within events before the channels
            //that cause the events.
            //This gives them a chance to be attached before the event tries to use them.
            output.Open(5000);
            button.Open(5000);
            
            //The rest of your code here...
        }
    }
}

In C, all event handler declarations have a context pointer that can be pointed at any object you choose. This can be a set of relevant data, or even a Phidget handle. If you pass a Phidget handle as the context pointer for an event, you can access the passed Phidget from the event as follows:

For example, if we wanted to make a Digital Output channel follow the state of a button:

static void CCONV onStateChangeHandler(PhidgetDigitalInputHandle pdih, void *ctx, int state) {
    int attached;
    //Extract our output handle from the context pointer
    PhidgetDigitalOutputHandle linkedOutput = (PhidgetDigitalOutputHandle)ctx;

    //Be sure the other Phidget you are trying to access is attached before using it
    Phidget_getAttached((PhidgetHandle)linkedOutput, &attached);

    if(attached)
        PhidgetDigitalOutput_setState(linkedOutput, state);

}

int main() {
    PhidgetDigitalInputHandle button = NULL;
    PhidgetDigitalOutputHandle output = NULL;

    PhidgetDigitalInput_create(&button);
    PhidgetDigitalOutput_create(&output);
    
    //Addressing info here

    //Here we pass the handle for "output" as the context pointer so we can access it from the event
    PhidgetDigitalInput_setOnStateChangeHandler(ch, onStateChangeHandler, output);
    
    //Be sure to open any channels you are using within events before the channels
    //that cause the events.
    //This gives them a chance to be attached before the event tries to use them.
    Phidget_openWaitForAttachment((PhidgetHandle)output, 5000);
    Phidget_openWaitForAttachment((PhidgetHandle)button, 5000);

    //The rest of your code here...

}

JavaScript is dynamically interpreted, and objects follow a less rigid structure than in other languages. To access another Phidget from an event handler, you can add the second Phidget's handle as a property of the Phidget object that will be triggering the event. Then, you can access the second Phidget using the corresponding property from the this parameter of the event.

For example, if we wanted to make a Digital Output channel follow the state of a button:

    const button = new phidget22.DigitalInput();
    const output = new phidget22.DigitalOutput();
...
    //Here we create an attribute of input called "linkedOutput", and assign it the handle for output
    button.linkedOutput = output;
    button.onStateChange = function(state){
        //Be sure the other Phidget you are trying to access is attached before using it
        if(this.linkedOutput.attached)
           this.linkedOutput.state = state;
}

    await output.open();
    await button.open();

    //The rest of your code here...

What's Next?

Now that you know how to use multiple Phidgets in your program, we should discuss how to find the features available to you by using the Phidget22 API.