Using Multiple Phidgets: Difference between revisions

From Phidgets Support
No edit summary
Line 121: Line 121:
==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 addressing 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).  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.
 
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.


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


<tabber>
<tabber>
Java=<syntaxhighlight lang=java>
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 Phidgetch = 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
//Declare the event listener
public static DigitalInputAttachListener onAttach = new DigitalInputAttachListener() {
public static DigitalInputAttachListener onAttach = new DigitalInputAttachListener() {
Line 148: Line 163:
</syntaxhighlight>
</syntaxhighlight>
|-|
|-|
Python=<syntaxhighlight lang=python>
C#=
#Declare the event handler
In C#, you can access the Phidget that fired the event by typecasting the {{code|sender}} parameter to the appropriate Phidget object type.
def onAttachHandler(self):
<syntaxhighlight lang=cSharp>
    #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 Phidgetch = DigitalInput()
...
#Assign the handler that will be called when the event occurs
ch.setOnAttachHandler(onAttachHandler)
</syntaxhighlight>
|-|
C#=<syntaxhighlight lang=cSharp>
//Declare the event handler
//Declare the event handler
void attach(object sender, Phidget22.Events.AttachEventArgs e) {
void attach(object sender, Phidget22.Events.AttachEventArgs e) {
Line 178: Line 182:
</syntaxhighlight>
</syntaxhighlight>
|-|
|-|
C=<syntaxhighlight lang=c>
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
//Declare the event handler
static void CCONV onAttachHandler(PhidgetHandle ph, void *ctx) {
static void CCONV onAttachHandler(PhidgetHandle ph, void *ctx) {
Line 197: Line 203:
==Referencing Other 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. There are simple ways of doing this for all languages, though the specifics depend on 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:


<tabber>
<tabber>
Python=
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 to the Phidget object that will be triggering the event. Then, you may access the second Phidget using 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):
Line 216: Line 215:
     if(self.output.getAttached()):
     if(self.output.getAttached()):
         self.output.setState(state)
         self.output.setState(state)
    print("State %f" % state)
    return 0


button = DigitalInput()
button = DigitalInput()
Line 230: Line 227:
output.openWaitForAttachment(5000)
output.openWaitForAttachment(5000)
button.openWaitForAttachment(5000)
button.openWaitForAttachment(5000)
# The rest of your code here....
</syntaxhighlight>
</syntaxhighlight>
|-|
|-|
JavaScript=
Java=
<syntaxhighlight lang=javaScript>
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.
function stateChange(state) {
 
    //Be sure the other Phidget you are trying to access is attached before using it
For example, if we wanted to make a Digital Output channel follow the state of a button:
    if(this.output.getAttached())
<syntaxhighlight lang=java>
         this.output.setState(state);
public class MultiPhidgetExample {
    console.log("State " + state)
   
    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);
 
            output.open(5000);
            button.open(5000);
           
            // The rest of your code here...
           
        } catch (PhidgetException ex) {
            System.out.println(ex.getDescription());
        }
    }
}
}
...
</syntaxhighlight>
    var input = new phidget22.DigitalInput();
|-|
    var output = new phidget22.DigitalOutput();
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.
    //Here we create an attribute of input called "output", and assign it the handle for output
 
    input.output = output;
For example, if we wanted to make a Digital Output channel follow the state of a button:
    input.onStateChange = stateChange;
<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;


    output.open();
            output.Open(5000);
    input.open();
            button.Open(5000);
           
            //The rest of your code here...
        }
    }
}
</syntaxhighlight>
</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:


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) {
Line 268: Line 327:
         PhidgetDigitalOutput_setState(out, state);
         PhidgetDigitalOutput_setState(out, state);


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


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


     PhidgetDigitalInput_create(&ch);
     PhidgetDigitalInput_create(&button);
     PhidgetDigitalOutput_create(&out);
     PhidgetDigitalOutput_create(&out);
      
      
Line 282: Line 340:
     //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 "out" as the context pointer so we can access it from the event
     PhidgetDigitalInput_setOnStateChangeHandler(ch, onStateChangeHandler, out);
     PhidgetDigitalInput_setOnStateChangeHandler(ch, onStateChangeHandler, out);
    if (SetAttachDetachError_Handlers((PhidgetHandle)ch))
        goto error;
      
      
     Phidget_openWaitForAttachment((PhidgetHandle)out, 5000);
     Phidget_openWaitForAttachment((PhidgetHandle)out, 5000);
     Phidget_openWaitForAttachment((PhidgetHandle)ch, 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 to the Phidget object that will be triggering the event. Then, you may access the second Phidget using 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>
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);
}
...
    var button = new phidget22.DigitalInput();
    var output = new phidget22.DigitalOutput();
...
    //Here we create an attribute of input called "output", and assign it the handle for output
    button.output = output;
    button.onStateChange = stateChange;
    output.open();
    button.open();
    //The rest of your code here...
</syntaxhighlight>
</tabber>


=== Further Reading ===
=== Further Reading ===

Revision as of 19:59, 11 February 2019

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). 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 Phidgetch = 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 DigitalInputAttachListener onAttach = new DigitalInputAttachListener() {
    @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);

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 to the Phidget object that will be triggering the event. Then, you may access the second Phidget using 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.output.getAttached()):
        self.output.setState(state)

button = DigitalInput()
output = DigitalOutput()

#Addressing info here

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

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

            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;

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

}

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

    PhidgetDigitalInput_create(&button);
    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);
    
    Phidget_openWaitForAttachment((PhidgetHandle)out, 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 to the Phidget object that will be triggering the event. Then, you may access the second Phidget using 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.output.getAttached())
        this.output.setState(state);
}
...
    var button = new phidget22.DigitalInput();
    var output = new phidget22.DigitalOutput();
...
    //Here we create an attribute of input called "output", and assign it the handle for output
    button.output = output;
    button.onStateChange = stateChange;

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

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