Using Multiple Phidgets: Difference between revisions

From Phidgets Support
No edit summary
Line 1: Line 1:
[[Category:Programming]]
[[Category:Programming]]
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.
{|
|style="vertical-align:middle; width: 60%;"|
Chances are your project with Phidgets it 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.


If you haven't read them yet, we recommend first reading the pages on [[What is a Phidget?]] and [[Phidget Programming Basics]] to better understand the contents of this page.
|{{TOC limit|2}}
|}
This video explains the process of using multiple Phidgets in your program:
<center>{{#ev:youtube|c3M8d0nBP4c}}</center>
<center>{{#ev:youtube|c3M8d0nBP4c}}</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===


Any matching properties being set must be set before the channel is opened, as the behaviour of setting matching properties while the channel is open is undefined.
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.


===Using the Channel Class===
Full descriptions of all the addressing parameters can be found on the [[Addressing Phidgets]] page.
[[Image:ChannelClass.jpg|150px|right|thumb|The Phidget's channel classes highlighted in yellow.|link=]]
Each channel exported by a Phidget device has channel class. The channel class describes the type of Phidget being used, and must be known to start interacting with the Phidget. A Phidget can have multiple channels, and they may even have different channel classes, like the example shown in this image. You can find which channel classes are used with your Phidget by finding them listed on the enclosure, or on the '''API''' tab of the product's page.


The {{Code|channelClass}} property is implied by the handle and API you use to communicate with the Phidget. For instance a DigitalOutput channel has a channel class of DigitalOutput, and a HumiditySensor channel has a channel class of HumiditySensor.
===Example===


Get the '''channel class''' with the {{Code|ChannelClass}} property. It's often useful for [[#Distinguishing Events|distinguishing which Phidget channel]] called a shared Attach, Detach, or Error Event Handler.
For example, to open two Phidgets, the code might be:
<tabber>
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);


<br clear="all">
//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...


===Using the Channel ID===
//Remember to close the channels when done
[[Image:ChannelID.jpg|150px|right|thumb|Channel numbers highlighted in yellow.|link=]]
ch.close();
Each channel exported by a Phidget device has an id, normally starting at 0. Channel ID will allow you to distinguish between multiple channels on a single device. If the Phidget has more than one channel class, the numbering starts back at zero for each class. For example, the [{{SERVER}}/?tier=3&catid=64&pcid=57&prodid=962 Thumbstick Phidget] has two VoltageRatioInput channels (IDs 0 and 1), and a single DigitalInput channel (ID 0).
ch1.close();
</syntaxhighlight>
|-|
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)


The {{Code|channel}} property must be set to ensure the device channel the Phidget software library matches is right oneIf the {{Code|channel}} property is not specified, the library will attach to channel 0 if available, and the next available channel if not.
//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 '''channel id''' with the {{Code|Channel}} property.
//Remember to close the channels when done
<br clear="all">
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);


===Using the Hub Port===
//For a second channel, simply repeat the process with different addressing information
[[File:Vint_hub_port.jpg|150px|right|thumb|Numbered ports on a VINT Hub.|link=]]
TemperatureSensor ch1 = new TemperatureSensor();
{{CT|VINTHub|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 specified. If two temperature sensors are attached to the same hub, and the hub port is not specified prior to opening a {{Code|TemperatureSensor}} channel, there is no way to know which temperature sensor will be attached.
ch1.DeviceSerialNumber = 12345;
ch1.HubPort = 3;
ch1.Channel = 0;
ch1.Open(5000);
//Do stuff with your Phidgets here...


Set the '''hub port''' with the {{Code|HubPort}} property.
//Remember to close the channels when done
<br clear="all">
ch.Close();
===Using "Is Hub Port Device"===
ch1.Close();
[[File:IsHubPortDevice.jpg|250px|right|thumb|Examples of devices that would require IsHubPortDevice to be true.|link={{SERVER}}/docs/images/d/d8/IsHubPortDevice.jpg]]
</syntaxhighlight>
VINT ports have the ability to be used with analog sensors 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}}.
|-|
C=<syntaxhighlight lang=c>
//Set up the first channel as normal
PhidgetTemperatureSensorHandle ch;
PhidgetTemperatureSensor_create(&ch);


Set '''is hub port device''' with the {{Code|IsHubPortDevice}} property.
Phidget_setDeviceSerialNumber((PhidgetHandle)ch, 12345);
<br clear="all">
Phidget_setHubPort((PhidgetHandle)ch, 4);
===Using the Serial Number===
Phidget_setChannel((PhidgetHandle)ch, 0);
[[File:SerialNumber.jpg|150px|right|thumb|The serial number on the underside of a Phidget.|link=]]
Phidget_openWaitForAttachment((PhidgetHandle)ch, 5000);
Each Phidget has a unique serial number (VINT devices inherit the serial number of the hub they're connected to). When you use more than one device with 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 underside of the Phidget, or determined by reading the {{Code|DeviceSerialNumber}} property.


Set the '''device serial number''' with the {{Code|DeviceSerialNumber}} property.
//For a second channel, simply repeat the process with different addressing information
<br clear="all">
PhidgetTemperatureSensorHandle ch1;
===Using the Label===
PhidgetTemperatureSensor_create(&ch1);


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:
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...


* You can only write labels to Phidgets that have serial numbers.
//Remember to close the channels when done
* In [[OS - Windows|Windows]], any label can be read, but label can only be written for newer Phidgets that support firmware upgrading.
Phidget_close((PhidgetHandle)ch);
* Some programming languages do not support writing to labels. See the Phidget22 API to see if it's supported in your language.
Phidget_close((PhidgetHandle)ch1);
 
PhidgetTemperatureSensor_delete(&ch);
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.
PhidgetTemperatureSensor_delete(&ch1);
 
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.
 
===Code Examples===
 
For example, in Java, this would be:
<div class="source">
<syntaxhighlight lang=java>
ch.setDeviceSerialNumber(12345);  // match device 12345
ch.setHubPort(4);                // match hub port 4
ch.setChannel(1);                // match channel 1 port 4 dev 12345
ch.open();                        // start matching
 
//for a second device simply repeat this process
ch1.setDeviceSerialNumber(12345);
ch1.setHubPort(3);
ch1.setChannel(1);
ch1.open();
//and so on
.
.
.
</syntaxhighlight>
</div>
 
Or in C:
<div class="source">
<syntaxhighlight lang=c>
Phidget_setDeviceSerialNumber((PhidgetHandle)ch, 12345); // match device 12345
Phidget_setHubPort((PhidgetHandle)ch, 4);                 // match hub port 4
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
Phidget_setDeviceSerialNumber((PhidgetHandle)ch1, 12345);
Phidget_setHubPort((PhidgetHandle)ch1, 2);               
Phidget_setChannel((PhidgetHandle)ch1, 1);               
Phidget_open((PhidgetHandle)ch1);       
//and so on
.
.
.               
</syntaxhighlight>
</syntaxhighlight>
</div>
</tabber>


==Distinguishing Events==
==Distinguishing Events==


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.
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 addressing properties of the channel can be read to determine what device channel the event is from.


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.
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.


==Referencing Phidgets from Events==  
==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. To do so, there are three basic methods of making the Phidget available, depending of the programming language you are using:
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:
Line 123: Line 139:
For example, in Python:
For example, in Python:


<tabber>
Python=
<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.output.getAttached()):
     if(self.output.getAttached()):
         self.output.setState(state)
         self.output.setState(state)
Line 145: Line 162:
input.openWaitForAttachment(5000)
input.openWaitForAttachment(5000)
</syntaxhighlight>
</syntaxhighlight>
|-|
JavaScript=
<syntaxhighlight lang=javaScript>
function stateChange(state) {
    //Be sure the other Phidget you are trying to access is attached before using it
    if(this.output.getAttached())
        this.output.setState(state);
    console.log("State " + state)
}
...
    var input = new phidget22.DigitalInput();
    var output = new phidget22.DigitalOutput();
...
    //Here we create an attribute of input called "output", and assign it the handle for output
    input.output = output;
    input.onStateChange = stateChange;
    output.open();
    input.open();
</syntaxhighlight>
</tabber>


===C===
===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:
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 as a event, you can access the passed Phidget from the event as follows:


<syntaxhighlight lang=C>
<syntaxhighlight lang=C>

Revision as of 22:23, 29 October 2018

Chances are your project with Phidgets it 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.

If you haven't read them yet, we recommend first reading the pages on What is a Phidget? and Phidget Programming Basics to better understand the contents of this page.

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
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
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.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);

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). In the case where multiple devices are handled by the same event handler, the addressing properties of the channel can be read to determine what device channel the event is from.

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 source or sender or ch. In Java, you will need to call getSource() on the event parameter to get the Phidget that caused the event. In JavaScript, you will use the this keyword in your event handler.

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. To do so, there are three basic methods of making the Phidget available, depending of the programming language you are using:

C# and Java

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.

Python and JavaScript

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.

For example, in Python:

def onStateChangeHandler(self, state):
    #Be sure the other Phidget you are trying to access is attached before using it
    if(self.output.getAttached()):
        self.output.setState(state)
    print("State %f" % state)
    return 0

input = DigitalInput()
output = DigitalOutput()

#Addressing info here

#Here we create an attribute of input called "output", and assign it the handle for output
#You can use this exact line in JavaScript
input.output = output
input.setOnStateChangeHandler(onStateChangeHandler)

output.openWaitForAttachment(5000)
input.openWaitForAttachment(5000)

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

    output.open();
    input.open();

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 as a event, you can access the passed Phidget from the event as follows:

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

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

    if(attached)
        PhidgetDigitalOutput_setState(out, state);

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

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

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

    //Here we pass the handle for "out" as the context pointer so we can access it from the event
    PhidgetDigitalInput_setOnStateChangeHandler(ch, onStateChangeHandler, out);


    if (SetAttachDetachError_Handlers((PhidgetHandle)ch))
        goto error;
    
    Phidget_openWaitForAttachment((PhidgetHandle)out, 5000);
    Phidget_openWaitForAttachment((PhidgetHandle)ch, 5000);

    //The rest of your code here

}

Further Reading

Phidget Programming Basics - Here you can find the basic concepts to help you get started with making your own programs that use Phidgets.

Data Interval/Change Trigger - Learn about these two properties that control how much data comes in from your sensors.

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.

Phidget Network Server - Phidgets can be controlled and communicated with over your network- either wirelessly or over ethernet.

Best Phidgets Practices - Good programming habits that will save you from common problems when writing code for your Phidgets.