Using Multiple Phidgets: Difference between revisions

From Phidgets Support
No edit summary
No edit summary
(25 intermediate revisions by 3 users not shown)
Line 1: Line 1:
[[Category:Programming]]
[[Category:Programming]]{{Recommended_Flow_Links|{{Flow Page Number|{{PAGENAME}} }} }}
When only one Phidget is connected to a computer, it is pretty easy for a simple program to open and attach to the channels on that one Phidget; however, when the program becomes more complicated or more than one Phidget is connected, attaching to the correct channel can be more difficult.
__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.


<center>{{#ev:youtube|c3M8d0nBP4c}}</center>
This video explains the process of using multiple Phidgets in your program:
<center>{{#ev:youtube|c3M8d0nBP4c|||||rel=0}}</center>


==Matching Channels==
==The Basics==


Before opening a channel, it is important to set enough of the matching properties to ensure the desired device channel is matched.  By default, the matching code in the Phidget library will match the first available device channel that is of the correct class.  For example, if two temperature sensor devices are connected to a computer, it is undefined which will attach when the device serial number is not specified before the channel is opened.
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.  


The best practice is to always specify at least the device serial number and the channel ID of the device channel that should be attached to the user channel.  Even when not strictly necessary, setting as many matching properties as possible can ensure that code will not break in the future.
===Addressing Channels===


===Using the Channel ID===
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.


Each channel exported by a Phidget device has an id, normally starting at 0. The {{Code|channel}} property must be set to ensure the device channel the Phidget software library matches is right one.  If a 4-channel temperature sensor is connected, and the {{Code|channel}} property is not specified, the matching code will attach to channel 0 if available, and the next available channel if not.
Full descriptions of all the addressing parameters can be found on the [[Addressing Phidgets]] page.


Set the '''channel id''' with the {{Code|Channel}} property.
===Example===


===Using the Hub Port===
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)


VINT hubs have a number of ports that VINT devices can be connected to.  To ensure the correct VINT device is attached, the hub port must be specifiedIf two temperature sensors are attached to the same hub, and the hub port is not specified prior to opening a channel, it is undefined which temperature sensor will be attached.
#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...


Set the '''hub port''' with the {{Code|HubPort}} property.
#Remember to close the channels when done
ch.close()
ch1.close()
</syntaxhighlight>
|-|
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);


===Using Is Hub Port Device===
//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...


VINT ports have the ability to be used with analog devices as well as with intelligent VINT Phidgets. If you are trying to use a simple device such as a slider, a 0-5V sensor, a switch, or an LED with the VINT port directly, you will want to set this property to {{Code|TRUE}}. Otherwise this should be left as default or set to {{Code|FALSE}}.
//Remember to close the channels when done
ch.close();
ch1.close();
</syntaxhighlight>
|-|
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);


Set '''is hub port device''' with the {{Code|IsHubPortDevice}} property.
//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...


===Using the Serial Number===
//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);


Each Phidget has a unique serial number (VINT devices inherit the serial number of the hub). When there is more than one device that exports the same channel class, the device serial number must be specified to ensure the channel on the desired device is matched.  The device serial number can be found on a label on the bottom of the Phidget, or determined by reading the {{Code|DeviceSerialNumber}} property.
Phidget_setDeviceSerialNumber((PhidgetHandle)ch, 12345);
Phidget_setHubPort((PhidgetHandle)ch, 4);
Phidget_setChannel((PhidgetHandle)ch, 0);
Phidget_openWaitForAttachment((PhidgetHandle)ch, 5000);


Set the '''device serial number''' with the {{Code|DeviceSerialNumber}} property.
//For a second channel, simply repeat the process with different addressing information
PhidgetTemperatureSensorHandle ch1;
PhidgetTemperatureSensor_create(&ch1);


===Using the Label===
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...


If you want to have a human-readable way to reference your Phidget instead of an arbitrary serial number, you can use the Label feature of Phidgets. You can call the {{Code|WriteLabel}} method to permanently store the desired label in the Phidget's onboard flash. From then on, you can set the {{Code|DeviceLabel}} property of a channel before opening it. The disadvantage of Labels is that they are not available on all operating systems and languages:
//Remember to close the channels when done
Phidget_close((PhidgetHandle)ch);
Phidget_close((PhidgetHandle)ch1);
PhidgetTemperatureSensor_delete(&ch);
PhidgetTemperatureSensor_delete(&ch1);
</syntaxhighlight>
|-|
JavaScript=<syntaxhighlight lang=javascript>
// Set up the first channel as normal
var ch = new phidget22.TemperatureSensor()
ch.setDeviceSerialNumber(12345)
ch.setHubPort(4)
ch.setChannel(0)
ch.open(5000)


* You can only write labels to Phidgets that have serial numbers.
// For a second channel, simply repeat the process with different addressing information
* In [[OS - Windows|Windows]], any label can be read, but label can only be written for newer Phidgets that support firmware upgrading.
var ch1 = new phidget22.TemperatureSensor()
* Some programming languages do not support writing to labels. See the Phidget22 API to see if it's supported in your language.
ch1.setDeviceSerialNumber(12345)
ch1.setHubPort(3)
ch1.setChannel(0)
ch1.open(5000)
// Do stuff with your Phidgets here...


If you have a VINT Hub that has a label written to it, you can use the same label to address any device connected to that hub. See the [[HUB0000_User_Guide|User Guide]] for more information on using labels with the VINT Hub.
// Remember to close the channels when done
ch.close()
ch1.close()
</syntaxhighlight>
</tabber>


Note: You should be careful when writing labels to your Phidgets in your code, because the label is stored in flash which can only be re-written around 10,000 times before it will no longer write. If your program is complex, be sure to test it thoroughly before using {{Code|WriteLabel}} to avoid accidentally burning out the flash.
==Similar Phidgets==


===Code Examples===
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.


For example, in Java, this would be:
<tabber>
<div class="source">
Python=<syntaxhighlight lang=python>
<syntaxhighlight lang=java>
#Create the array of Phidget channels
ch.setDeviceSerialNumber(12345)// match device 12345
ch = [DigitalOutput() for i in range (0, 8)]
ch.setHubPort(4);                 // match hub port 4
 
ch.setChannel(1);                 // match channel 1 port 4 dev 12345
for i in range (0, 8):
ch.open();                       // start matching
    #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()
</syntaxhighlight>
|-|
Java=<syntaxhighlight lang=java>
//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();
}


//for a second device simply repeat this process
ch1.setDeviceSerialNumber(12345);
ch1.setHubPort(3);
ch1.setChannel(1);
ch1.open();
//and so on
.
.
.
</syntaxhighlight>
</syntaxhighlight>
</div>
|-|
C#=<syntaxhighlight lang=cSharp>
//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);
}


Or in C:
//Now you can access each channel by its position in the array
<div class="source">
ch[0].State = true;
<syntaxhighlight lang=c>
ch[1].State = false;
Phidget_setDeviceSerialNumber((PhidgetHandle)ch, 12345); // match device 12345
ch[2].State = false;
Phidget_setHubPort((PhidgetHandle)ch, 4);                 // match hub port 4
ch[3].State = true;
Phidget_setChannel((PhidgetHandle)ch, 1);                 // match channel 1 port 4 dev 12345
Phidget_open((PhidgetHandle)ch);                         // start matching


//for a second device simply repeat this process
//Close the channels when done
Phidget_setDeviceSerialNumber((PhidgetHandle)ch1, 12345);
for(int i=0; i<8; i++)
Phidget_setHubPort((PhidgetHandle)ch1, 2);               
{
Phidget_setChannel((PhidgetHandle)ch1, 1);               
    ch[i].Close();
Phidget_open((PhidgetHandle)ch1);        
}
//and so on
.
.
.               
</syntaxhighlight>
</syntaxhighlight>
</div>
|-|
C=<syntaxhighlight lang=c>
//Create an array for your Phidget channels
PhidgetDigitalOutputHandle ch[8];


==Distinguishing Events==
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);
}


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).  In the case where multiple devices are handled by the same event handler, the matching properties of the channel can be read to determine what device channel the event is from.
PhidgetDigitalOutput_setState(ch[0], true);
PhidgetDigitalOutput_setState(ch[1], false);
PhidgetDigitalOutput_setState(ch[2], false);
PhidgetDigitalOutput_setState(ch[3], true);


The channel that fired the event will always be available in the event handler, regardless of language, though its exact form changes from language to language. In most languages, it is the first parameter in the parameter list, whether it's called {{code|source}} or {{code|sender}} or {{code|ch}}. In Java, you will need to call {{code|getSource()}} on the event parameter to get the Phidget that caused the event. In JavaScript, you will use the {{code|this}} keyword in your event handler.
//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 = []


==Referencing Phidgets from Events==
for(i = 0; i < 8; i++) {


When using multiple Phidgets in the same program, you may want to access one Phidget from the within an event caused by another. To do so, there are three basic methods of making the Phidget available, depending of the programming language you are using:
// Create, address, then open the channels
tmp = new phidget22.DigitalInput()
tmp.setChannel(i)
tmp.open(5000)
ch.push(tmp)
}


===C# and Java===
// 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)


In C# and Java, chances are your event handlers are defined in the same namespace (or 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(i = 0; i < 8; i++) {
ch[i].close()
}
</syntaxhighlight>
</tabber>


===Python and JavaScript===
==Distinguishing Events==


Python and JavaScript are both dynamically interpreted, and objects follow a less rigid structure than in other languages. In these languages, to access another Phidget from an event handler, you can add the second Phidget's handle to the Phidget triggering the event. Then, you may access the second Phidget using the ''self'' parameter of the event.
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.


For example, in Python:
For example, for an Attach Event handler:


<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 the event handler
function onAttachHandler(ch) {
    // You can access the Phidget that fired the event using the "this" parameter
    ph = this
    deviceSerialNumber = ph.getDeviceSerialNumber()
...
// Declare your object. Replace "DigitalInput" with the object for your Phidget
var ch = new phidget22.DigitalInput()
...
// Assign the handler that will be called when the event occurs
ch.onAttach = onAttachHandler
</syntaxhighlight>
</tabber>
==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:
<tabber>
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, if we wanted to make a Digital Output channel follow the state of a button:
<syntaxhighlight lang=python>
<syntaxhighlight lang=python>
def onStateChangeHandler(self, state):
def onStateChangeHandler(self, state):
     #Be sure the other Phidget you are trying to access is attached before using it
     #Be sure the other Phidget you are trying to access is attached before using it
    #In JavaScript, you would use "this" instead of "self", but the idea is the same
     if(self.linkedOutput.getAttached()):
     if(self.output.getAttached()):
         self.linkedOutput.setState(state)
         self.output.setState(state)
    print("State %f" % state)
    return 0


input = DigitalInput()
button = DigitalInput()
output = DigitalOutput()
output = DigitalOutput()


#Addressing info here
#Addressing info here


#Here we create an attribute of input called "output", and assign it the handle for output
#Here we create an attribute of input called "linkedOutput", and assign it the handle for output
#You can use this exact line in JavaScript
button.linkedOutput = output
input.output = output
button.setOnStateChangeHandler(onStateChangeHandler)
input.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)
output.openWaitForAttachment(5000)
input.openWaitForAttachment(5000)
button.openWaitForAttachment(5000)
 
# The rest of your code here....
</syntaxhighlight>
</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>
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();


===C===
            //Set Any Addressing Parameters 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 Phidget handle. If you pass a Phidget handle as the context pointer as a event, you can access the passed Phidget from the event as follows:


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


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


     if(attached)
     if(attached)
         PhidgetDigitalOutput_setState(out, state);
         PhidgetDigitalOutput_setState(linkedOutput, state);


    printf("[State Event] -> State: %d\n", state);
}
}


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


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


     //Here we pass the handle for "out" as the context pointer so we can access it from the event
     //Here we pass the handle for "output" as the context pointer so we can access it from the event
     PhidgetDigitalInput_setOnStateChangeHandler(ch, onStateChangeHandler, out);
     PhidgetDigitalInput_setOnStateChangeHandler(ch, onStateChangeHandler, output);
 
 
    if (SetAttachDetachError_Handlers((PhidgetHandle)ch))
        goto error;
      
      
     Phidget_openWaitForAttachment((PhidgetHandle)out, 5000);
    //Be sure to open any channels you are using within events before the channels
     Phidget_openWaitForAttachment((PhidgetHandle)ch, 5000);
    //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
     //The rest of your code here...


}
}
</syntaxhighlight>
</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.


=== Further Reading ===
For example, if we wanted to make a Digital Output channel follow the state of a button:
<syntaxhighlight lang=javaScript>
function stateChange(state) {
    //Be sure the other Phidget you are trying to access is attached before using it
    if(this.linkedOutput.getAttached())
        this.linkedOutput.setState(state);
}
...
    var button = new phidget22.DigitalInput();
    var 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 = stateChange;


[[Phidget Programming Basics]] - Here you can find the basic concepts to help you get started with making your own programs that use Phidgets.
    output.open();
    button.open();


[[Data Interval/Change Trigger]] - Learn about these two properties that control how much data comes in from your sensors.
    //The rest of your code here...
 
</syntaxhighlight>
[[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.
</tabber>
 
[[Logging, Exceptions, and Errors]] - Learn about all the tools you can use to debug your program.


[[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}} }} }}

Revision as of 20:27, 9 August 2019

 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
var ch = new phidget22.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
var ch1 = new phidget22.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()

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
	tmp = new phidget22.DigitalInput()
	tmp.setChannel(i)
	tmp.open(5000)
	ch.push(tmp)
}

// 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 = 0; i < 8; i++) {
	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 the event handler
function onAttachHandler(ch) {
    // You can access the Phidget that fired the event using the "this" parameter
    ph = this
    deviceSerialNumber = ph.getDeviceSerialNumber()
...
// Declare your object. Replace "DigitalInput" with the object for your Phidget
var ch = new phidget22.DigitalInput()
...
// Assign the handler that will be called when the event occurs
ch.onAttach = onAttachHandler

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:

function stateChange(state) {
    //Be sure the other Phidget you are trying to access is attached before using it
    if(this.linkedOutput.getAttached())
        this.linkedOutput.setState(state);
}
...
    var button = new phidget22.DigitalInput();
    var 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 = stateChange;

    output.open();
    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.