Phidget Programming Basics: Difference between revisions

From Phidgets Support
No edit summary
Line 1: Line 1:
[[Category:Programming]]
[[Category:Programming]]
__TOC__
{|
|style="vertical-align:middle; width: 60%;"|
== Before You Start ==
Before trying to start programming Phidgets, you should have a basic understanding of what a Phidget is, and how they can be used. For an introduction to Phidgets, check out [[What is a Phidget?]].


== Phidget Programming Outline ==
This page will explain the concepts behind how Phidgets are used in any software application.
It is important to understand what a Phidget is, and how the hardware and software relate to one another before writing software using the {{Phidget22API}}.  Please refer to [[What is a Phidget?]] for an introduction.
|{{TOC limit|2}}
|}


== Channels ==
To program with Phidgets, it is important to understand how the physical input and output channels of Phidget devices correspond to the software controlling them.


The Phidget software library matches a Phidget device channel with a software channel that is created by a user.
The Phidgets library is very modular, with each part of the device's behaviour split into individual parts called ''Channels''. Each channel represents a single part of a device, such as a single input on a digital input Phidget, the humidity sensor on a humidity Phidget, or one motor on a DC motor controller.
Software channels are each of a class, where that class defines a set of methods, properties, events and errors.  Phidget devices are aware of the channel classes, and expose access to features of the device through the class interface.


To use a Phidget, you'll want to:
Each channel has a ''Channel Class'', corresponding to the type of function the channel is to perform. For example, a TemperatureSensor channel will be used to measure temperature, and an RFID channel will deal with an RFID reader. Each channel class is designed make using channels of that class as similar as possible regardless of the Phidget they are a part of, while also supporting the unique features of each. You can find out what channel classes are available to your Phidget by looking at its [[User_Guides|User Guide]].
# '''[[#Creating a Channel|Create]]''' an instance of the channel class that provides access to the device you want to control.
# '''[[#Opening a Channel|Open]]''' the channel.
# Detect when the channel is '''[[#Attaching a Channel|attached]]''' to the Phidget.
# Use '''[[#Do Things with a Channel|methods and properties]]''' of the attached channel.
# '''[[#Close a Channel|Close]]''' the channel.


Small code snippets are provided for each step in the sections below. [[Language - Java|Java]] and [[Language - C|C]] were selected because Java is a high-level language and C is a low level language.  The best reference to the ''features'' each channel class is the {{Phidget22API}} for your specific language.  This page is intended to be a high-level introduction.
Each channel class has a set of functions tailored to the use of that type of device. For example, a {{Code|VoltageInput}} channel has functions you can use to control and read the Voltage Input, such as setting the data interval or reading the voltage:


== Creating a Channel ==
The set of all functions and other tools used to program with Phidgets is called the Phidgets Application Programming Interface ('''API'''). In addition to features unique to the class, every channel class also includes some functionality common to all channel classes, documented in the Phidgets API under {{Code|Phidget Common}}. For example, every channel has basic functions like {{Code|open()}} and {{Code|close()}}, which are the same no matter which Phidget you're using.


A Phidget device exposes one or more device channels where each channel is an interface to a feature of the hardware. A channel class defines an interface to control and query a channel of the Phidget device. For example, a 1018 - Phidget InterfaceKit device includes support
==Outline of a Program with Phidgets==
for digital input and digital out, and therefore exports <code>DigitalInput</code> and <code>DigitalOutput</code> channels.
[[Image:General_Phidget_Program_Flowchart.png|right|200px]]
Every Phidget channel you use in any program will follow the same life cycle:
# '''[[#Creating a Channel|Create]] a channel:''' Make a variable to keep track of your Phidget
# '''[[#Addressing Phidgets| Address]] the channel:'''  Set some basic parameters to indicate which Phidget to connect to.
#*You can specify as much, or as little as you deem necessary. You can even use a Phidget without specifying any parameters, if your system is simple enough.
# '''[[#Opening a Channel|Open]] the channel:''' Opening the channel will begin trying to match a physical Phidget channel to your software channel.
# '''[[#Attaching a Channel|Detect when the channel is attached]]:''' Your program must wait until a physical Phidget channel has been ''attached'' to your software channel.
#* The attachment process is handled automatically, and will attach to the first available Phidget channel that matches all your specified addressing parameters.
#* A channel is attached when the Phidget libraries link a physical Phidget channel to your software channel.
#* Waiting for attachment can be handled automatically as part of ''opening'' the channel or separately, as best suits your program.
# '''[[#Do Things with a Channel|Do things with the channel]]:''' Send commands to and receive data from your Phidget.
#* This section will encompass the majority of your program. The Phidget API / libraries will make this process as straightforward as possible, and is similar across all types of Phidgets.
# '''[[#Close a Channel|Close]] the channel:''' Once your program is done, you close the Phidget channel.
#* This frees up the Phidget for the next program that might need it.


Phidget devices are controlled by creating an instance of a Phidget channel class.  Each channel class has a function that allows you to '''create''' an instance, and a function to later '''delete''' the instance.
==A Closer Look, with Examples==


For example, in Java:
For a closer look at the parts of a Phidget program, this section will dissect the sections of a Phidget program in more detail. Small code snippets are provided for each step in the sections below to provide a representation of the code.
 
For a look at how these steps are handled in your specific programming language, check out the
'''Write Code''' section of the [[Programming Resources|Language Page]] for your programming language.
 
The best reference to the features of each channel class is the {{Phidget22API}} for your specific device and language.  This page is intended to be a high-level introduction.
 
=== Creating a Channel ===
 
To control a Phidget channel, you must first create an instance of its channel class that will be used to keep track of the channel through your program.
 
For example:


<syntaxhighlight lang=java>
<tabber>
Java=<syntaxhighlight lang=java>
  // Create a new Accelerometer channel
  // Create a new Accelerometer channel
  Accelerometer accel = new Accelerometer();
  Accelerometer accel = new Accelerometer();
Line 35: Line 60:
  RFID rfid = new RFID();
  RFID rfid = new RFID();
</syntaxhighlight>
</syntaxhighlight>
 
|-|
Or in C:
Python=<syntaxhighlight lang=python>
 
# Create a new Accelerometer channel
<syntaxhighlight lang=c>
accel = Accelerometer()
</syntaxhighlight>
<syntaxhighlight lang=python>
# Create a new RFID channel
rfid = RFID()
</syntaxhighlight>
|-|
C#=<syntaxhighlight lang=cSharp>
  // Create a new Accelerometer channel
  // Create a new Accelerometer channel
  PhidgetAccelerometerHandle accel;
  Accelerometer accel = new Accelerometer();
PhidgetAccelerometer_create(&accel);
</syntaxhighlight>
</syntaxhighlight>
<syntaxhighlight lang=c>
<syntaxhighlight lang=cSharp>
  // Create a new RFID channel
  // Create a new RFID channel
  PhidgetRFIDHandle rfid;
  RFID rfid = new RFID();
PhidgetRFID_create(&rfid);
</syntaxhighlight>
</syntaxhighlight>
 
|-|
A channel class will have properties and methods specific to the feature they belong to. For example, the <code>VoltageInput</code> class has a <code>Voltage</code> property that lets you access the current voltage measured by the device, the <code>Accelerometer</code> class has properties to set the sensitivity on each axis and the <code>RFID</code> has a method that writes to a writable RFID tag.
C=<syntaxhighlight lang=c>
 
// Create a new Accelerometer channel
==Addressing Phidgets==
PhidgetAccelerometerHandle ch;
 
PhidgetAccelerometer_create(&ch);
The following video summarizes the basics of how to address the proper channel in your code:
 
 
<center>{{#ev:youtube|XKSenz9txKE}}</center>
 
==== Opening a Channel on a USB Phidget ====
 
[[Image:channel-matching-1.jpg|link=|500px|center]]
 
In this example, a [{{SERVER}}/products.php?product_id=1018 1018 PhidgetInterfaceKit 8/8/8] is connected to a computer. A [{{SERVER}}/products.php?product_id=1108 1108 Magnetic Sensor] is connected to analog port 3 on the 1018. Here's how you would open the channel for the magnetic sensor in Java:
 
<syntaxhighlight lang=java>
VoltageRatioInput ch = new VoltageRatioInput();
ch.setDeviceSerialNumber(324781);
ch.setChannel(3);
ch.openWaitForAttachment(5000);
</syntaxhighlight>
</syntaxhighlight>
Or in C:
<syntaxhighlight lang=c>
<syntaxhighlight lang=c>
PhidgetVoltageRatioInputHandle ch;
// Create a new RFID channel
PhidgetVoltageRatioInput_create(&ch);
PhidgetRFIDHandle ch;
Phidget_setDeviceSerialNumber((PhidgetHandle)ch, 324781);
PhidgetRFID_create(&ch);
Phidget_setChannel((PhidgetHandle)ch, 3);
Phidget_openWaitForAttachment((PhidgetHandle)ch, 5000);
</syntaxhighlight>
</syntaxhighlight>
</tabber>


If you wanted to open digital input 5 in the same example, it would look like this in Java:
===Addressing Phidgets===


<syntaxhighlight lang=java>
In this step you set up the parameters the Phidget library will use to match your software channel to a physical channel on a Phidget.
DigitalInput ch = new DigitalInput();
ch.setDeviceSerialNumber(324781);
ch.setChannel(5);
ch.openWaitForAttachment(5000);
</syntaxhighlight>
 
Or in C:
 
<syntaxhighlight lang=c>
PhidgetDigitalInputHandle ch;
PhidgetDigitalInput_create(&ch);
Phidget_setDeviceSerialNumber((PhidgetHandle)ch, 324781);
Phidget_setChannel((PhidgetHandle)ch, 5);
Phidget_openWaitForAttachment((PhidgetHandle)ch, 5000);
</syntaxhighlight>


==== Opening a VINT Hub Port as a Channel ====
By default, the matching code in the Phidget library will attach the first available Phidget channel that is of the correct channel class. This works well for single Phidgets, but can be insufficient for systems with multiple Phidgets present. If not enough addressing parameters are specified, your software channel may attach to the wrong Phidget.


The ports on a [[What is VINT?|VINT]] Hub can be opened as Digital Inputs, Digital Outputs, Voltage Inputs, or Voltage Ratio Inputs. Suppose you had a [{{SERVER}}/products.php?product_id=HUB0000 HUB0000 VINT Hub] with a [{{SERVER}}/products.php?product_id=1133 1133 Sound Sensor] connected to its fourth port.  
Full descriptions of all the addressing parameters can be found on the [[Addressing Phidgets]] page.


[[Image:channel-matching-2.jpg|link=|500px|center]]
==== Addressing Example ====
 
Here's how you would open it in Java:
 
<syntaxhighlight lang=java>
VoltageInput ch = new VoltageInput();
ch.setDeviceSerialNumber(370181);
ch.setIsHubPortDevice(true);
ch.setHubPort(4);
ch.openWaitForAttachment(5000);
</syntaxhighlight>
 
Or in C:
 
<syntaxhighlight lang=c>
PhidgetVoltageInputHandle ch;
PhidgetVoltageInput_create(&ch);
Phidget_setDeviceSerialNumber((PhidgetHandle)ch, 370181);
Phidget_setIsHubPortDevice((PhidgetHandle)ch, 1);
Phidget_setHubPort((PhidgetHandle)ch, 4);
Phidget_openWaitForAttachment((PhidgetHandle)ch, 5000);
</syntaxhighlight>
 
==== Opening a Channel on a VINT Device ====


In this example, we have a [{{SERVER}}/products.php?product_id=TMP1101 TMP1101 4x Thermocouple Phidget] and a [{{SERVER}}/products.php?product_id=HUB0000 HUB0000 VINT Hub].
In this example, we have a [{{SERVER}}/products.php?product_id=TMP1101 TMP1101 4x Thermocouple Phidget] and a [{{SERVER}}/products.php?product_id=HUB0000 HUB0000 VINT Hub].
Line 133: Line 105:
[[Image:channel-matching-3.jpg|link=|500px|center]]
[[Image:channel-matching-3.jpg|link=|500px|center]]


If we wanted to open both the thermocouple connected to port 0 and the integrated temperature sensor on the board, we first need to figure out which channels those are. Go to the [{{SERVER}}/products.php?product_id=TMP1101 product page for the TMP1101] and click on the API tab. From the table at the top of the tab, we can see that the integrated temperature sensor is TemperatureSensor channel 4. In Java, opening these channels would look like this:
If we wanted to open the thermocouple connected to channel 0, on hub port 2, the Java code would look like:


<syntaxhighlight lang=java>
<tabber>
TemperatureSensor tc = new TemperatureSensor(); // Handle for the thermocouple
Java=<syntaxhighlight lang=java>
TemperatureSensor ic = new TemperatureSensor(); // Handle for the integrated temperature chip
TemperatureSensor tc = new TemperatureSensor(); //Create


tc.setDeviceSerialNumber();
tc.setDeviceSerialNumber(370181); //Address
ic.setDeviceSerialNumber();
tc.setHubPort(2);
tc.setHubPort(2);
ic.setHubPort(2);
tc.setChannel(0);
tc.setChannel(0);
ic.setChannel(4);


tc.openWaitForAttachment(5000);
Net.enableServerDiscovery(ServerType.DEVICE_REMOTE);
ic.openWaitForAttachment(5000);
 
tc.open(5000); //Open
</syntaxhighlight>
</syntaxhighlight>
|-|
Python=<syntaxhighlight lang=python>
tc = TemperatureSensor() #Create


Or in C:
tc.setDeviceSerialNumber(370181) #Address
 
tc.setHubPort(2)
<syntaxhighlight lang=c>
tc.setChannel(0)
PhidgetTemperatureSensorHandle tc; // Handle for the thermocouple
PhidgetTemperatureSensorHandle ic; // Handle for the integrated temperature chip
 
PhidgetTemperatureSensor_create(&tc);
PhidgetTemperatureSensor_create(&ic);


Phidget_setDeviceSerialNumber(tc, 370181);
Net.enableServerDiscovery(PhidgetServerType.PHIDGETSERVER_DEVICEREMOTE)
Phidget_setDeviceSerialNumber(ic, 370181);
Phidget_setHubPort((PhidgetHandle)tc, 2);
Phidget_setHubPort((PhidgetHandle)ic, 2);
Phidget_setChannel((PhidgetHandle)tc, 0);
Phidget_setChannel((PhidgetHandle)ic, 4);


Phidget_openWaitForAttachment((PhidgetHandle)tc, 5000);
tc.openWaitForAttachment(5000); #Open
Phidget_openWaitForAttachment((PhidgetHandle)ic, 5000);
</syntaxhighlight>
</syntaxhighlight>
|-|
C#=<syntaxhighlight lang=cSharp>
TemperatureSensor tc = new TemperatureSensor(); //Create


==== Opening a Channel on a Remote Phidget ====
tc.DeviceSerialNumber = 370181; //Address
tc.HubPort = 2;
tc.Channel = 0;


Suppose you wanted to open a locally connected Phidget remotely over the Network Service, so that you could have multiple programs connecting to it at the same time. In this example, we have a [{{SERVER}}/products.php?product_id=1024 1024 PhidgetRFID] connected to a computer that has the Phidget Network Server enabled.
Net.EnableServerDiscovery(ServerType.DeviceRemote);


[[Image:channel-matching-4.jpg|link=|600px|center]]
tc.openWaitForAttachment(5000); //Open
 
You could open the RFID reader channel remotely with the following code in Java:
 
<syntaxhighlight lang=java>
RFID ch = new RFID();
ch.setDeviceSerialNumber(388624);
ch.setIsRemote(true);
ch.openWaitForAttachment(5000);
</syntaxhighlight>
</syntaxhighlight>
|-|
C=<syntaxhighlight lang=c>
PhidgetTemperatureSensorHandle tc; //Create
PhidgetTemperatureSensor_create(&tc);


Or in C:
PhidgetTemperatureSensor_setDeviceSerialNumber(tc, 370181); //Address
 
PhidgetTemperatureSensor_setHubPort(tc, 2);
<syntaxhighlight lang=c>
PhidgetTemperatureSensor_setChannel(tc, 0);
PhidgetRFIDHandle ch;
PhidgetRFID_create(&ch);


Phidget_setDeviceSerialNumber(ch, 388624);
PhidgetNet_enableServerDiscovery(PHIDGETSERVER_DEVICEREMOTE);
Phidget_setIsRemote(ch, 1);


Phidget_openWaitForAttachment((PhidgetHandle)ch, 5000);
Phidget_openWaitForAttachment((PhidgetHandle)tc, 5000); //Open
</syntaxhighlight>
</syntaxhighlight>
</tabber>


== Opening a Channel ==
=== Opening a Channel ===


After you have created a [[#Creating a Channel| channel instance]], you can call the <code>openWaitForAttachment()</code> method to begin the process of matching the channel to a Phidget device channel.
After you have created and addressed a channel, you need to open it to begin the process of attaching the software channel to a physical channel.


For example, with the <code>Accelerometer</code> channel in Java:
For example, in Java:


<syntaxhighlight lang=java>
<tabber>
  accel.openWaitForAttachment(5000);
Java=<syntaxhighlight lang=java>
ch.open(5000);
</syntaxhighlight>
|-|
  Python=<syntaxhighlight lang=python>
ch.openWaitForAttachment(5000);
</syntaxhighlight>
|-|
C#=<syntaxhighlight lang=cSharp>
ch.Open(5000);
</syntaxhighlight>
|-|
C=<syntaxhighlight lang=c>
Phdiget_openWaitForAttachment((PhidgetHandle)ch, 5000);
</syntaxhighlight>
</syntaxhighlight>
</tabber>


Or in C:
''In Java and C# <code>open()</code> is overloaded. In other languages, you would use <code>openWaitForAttachment(5000)</code> to perform the same function.''


<syntaxhighlight lang=c>
The <code>openWaitForAttachment()</code> function will hold the program until a Phidget channel matching the one you specified is attached, or the function times out. There is a similar function called <code>open()</code> that will do the attachment process in the background, and allow your program to continue before the channel has been attached.
Phidget_openWaitForAttachment((PhidgetHandle) accel, 5000);
</syntaxhighlight>


To see how to use <code>openWaitForAttachment()</code> in other languages, please refer to the {{Phidget22API}}.
The <code>open()</code> and <code>openWaitForAttachment()</code> functions only begin the process of matching the channel handle you created to a channel of a Phidget device, and do not actually ''open'' the Phidget itself. An open channel that does not match any Phidget channels at first can still attach to a matching channel that is plugged in long after it was first opened.


There is also a non-blocking version of <code>openWaitForAttachment()</code> called <code>open()</code>.
=== Attaching a Channel ===


The <code>open()</code> and <code>openWaitForAttachment()</code> functions begin the process of matching the channel handle you created to a channel of a Phidget device, and do not actually ''open'' the Phidget itself.  An open channel may match a new Phidget device when it is plugged in if that channel has not already found a Phidget device channel that meets its criteria.
When a channel is open (and not ''attached''), the system will continue to try to match it with a
Phidget device channel until either a match is found, or the channel is closed.


<code>open()</code> and <code>openWaitForAttachment()</code> can be used without specifying any addressing properties. In this case the system will match a channel with the first Phidget device channel that matches the channel class.  The channel class itself is an implied addressing parameter.
Any one physical channel can only be attached to one software channel at a time.  For example, if you connected a single Phidget Accelerometer to a computer, and you created and opened two software <code>Accelerometer</code> channels, only one of the channels would attach while the other would remain ''open'' but not ''attached''. If the ''attached'' channel were to be closed, the other software channel would then attach to the Accelerometer.


If there is more than one Phidget connected to the computer that supports the channel class, the <code>DeviceSerialNumber</code> property must be set determine which Phidget will match.


If the Phidget connected to the computer has more than one channel of the same classes, the <code>Channel</code> property must be set to determine which Phidget device channel will match.
When the software channel is matched with a physical channel, the channel is ''attached'' and an <code>Attach</code> event is fired.


If the Phidget Network Server is enabled on the computer, the <code>IsRemote</code> and <code>IsLocal</code> properties can be used to determine if the channel will match the Phidget device channel or the network channel.
An event handler can be registered to catch the <code>Attach</code> event.  Each channel also has an <code>Attached</code> property that can be read to determine if the channel has been matched to a physical channel.


Please refer to the {{Phidget22API}}, and [[Best Phidgets Practices|Best Practices]] for more information on matching channels to Phidget device channels.
The following examples show how to set an event handler to detect the <code>Attach</code> event:


<tabber>
Java=<syntaxhighlight lang=java>
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);
</syntaxhighlight>
|-|
Python=<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>
|-|
C#=<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=<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>
</tabber>


===Details for Open()===
The attach event handler should be set '''before''' the channel is opened; otherwise, the attach event could occur before the handler is set to deal with it.


Because <code>open()</code> simply enables the process of matching a channel to a Phidget device channel, <code>open()</code> returns immediately and does not wait for the channel to attach to a Phidget device channel. The channel changes state to ''open'', but is not necessarily ''attached''.  Until the channel actually becomes ''attached'' to a Phidget device channel, most of the channel class interface will not be available.


As long as the channel is open (and not ''attached''), the system will continue to try to match it with a
'''Note:''' Once a physical channel is attached to a software channel, it will not be available to attach to another software channel until the first channel is closed.  The one exception is if the Phidget device channel is ''attached'' over the network through the [[Phidget Network Server]]In that case, multiple channels are allowed to match and attach to the Phidget device channel. Some Phidgets, such as motor controllers will never match more than one channel at a time, for safety reasons.
Phidget device channel that has not already been matched with a channel.  The channel can only be matched once, and the Phidget device channel can only be matched onceFor example, if you connected a single Phidget Accelerometer to a computer, and you created and opened two <code>Accelerometer</code> channels, only one of the channels would attach while the other would remain ''open'' but not ''attached''. If the ''attached'' channel were to be closed, the other channel would then attach to the Accelerometer.


When the channel is matched with a Phidget device channel, the channel state is changed to ''attached'' and an event is fired.
=== Do Things with a Channel ===


<code>openWaitForAttachment()</code> will perform the above matching, and hold the program either until the attach event has fired, or until it times out.
After a channel has been ''opened'' and ''attached'', software can control the Phidget through the functions available to its channel class.


'''Note:''' Once a Phidget device channel is matched to a channel, it will not be available to match another channel until the first channel is closed.  The one exception is if the Phidget device channel is ''attached'' over the network through the [[Phidget Network Server]].  In that case, multiple channels are allowed to match and attach to the Phidget device channel. Some Phidgets, such as motor controllers will never match more than one channel at a time.
This is the stage of your program where you can send commands to your channel, and handle the information it sends back.


== Attaching a Channel ==
Generally, we recommend configuring any initial setup for your channel in its <code>Attach</code> handler, so it is set up before your program uses it, and so it can be re-initialized in case it is somehow detached and re-attached (such as if it is unplugged and plugged back in).


When a channel is open (and not ''attached''), the system will continue to try to match it with a
Additionally, you can set up event handlers to handle events from the channel, such as when a state change occurs, or when sensor data is received. Event handlers should be set up before opening the channel to avoid missing events, but they will begin executing during this phase of the program.
Phidget device channel until either a match is found, or the channel is closed. When the channel is matched with a Phidget device channel, the channel state is changed to ''attached'' and an event is fired.


An event handler can be registered to catch the ''attach event'' through the channel's <code>Attach</code> event.  Each channel also has an <code>Attached</code> property that can be read to determine if the class has
For example, with a Voltage Input channel, you could set up an event handler to process Voltage Change events.
been matched to a Phidget device channel.


To set an event handler to detect the attach in Java:
<tabber>
 
Java=<syntaxhighlight lang=java>
<syntaxhighlight lang=java>
//Declare the event listener
  //create a Phidget accelerometer channel:
public static VoltageInputVoltageChangeListener onVoltageChange = new VoltageInputVoltageChangeListener() {
  Accelerometer accel = new Accelerometer();
    @Override
  accel.addAttachListener((AttachEvent ae) -> {
    public void onVoltageChange(VoltageInputVoltageChangeEvent e) {
      Accelerometer accel = (Accelerometer) ae.getSource();
        System.out.println("Voltage: " + e.getVoltage());
      // Do things after attachment (i.e. read data, control the device)
    }
      }
};
  });
...
VoltageInput ch;
...
//Assign the event listener that will be called when the event occurs
ch.addVoltageChangeListener(onVoltageChange);
</syntaxhighlight>
|-|
Python=<syntaxhighlight lang=python>
#Declare the event handler
def onVoltageChangeHandler(self, voltage):
    print("Voltage: " + str(voltage))
...
ch = VoltageInput()
...
#Assign the handler that will be called when the event occurs
ch.setOnVoltageChangeHandler(onVoltageChangeHandler)
</syntaxhighlight>
|-|
C#=<syntaxhighlight lang=cSharp>
//Declare the event handler
void voltageChange(object sender, Phidget22.Events.VoltageChangeEventArgs e) {
    Console.WriteLine("Voltage: " + e.Voltage.ToString());
}
...
VoltageInput ch;
...
//Assign the handler that will be called when the event occurs
ch.VoltageChange += voltageChange;
</syntaxhighlight>
</syntaxhighlight>
 
|-|
Or in C:
C=<syntaxhighlight lang=c>
 
//Declare the event handler
<syntaxhighlight lang=c>
static void CCONV onVoltageChangeHandler(PhidgetVoltageInputHandle ph, void *ctx, double voltage) {
  // Define the attach handler function
    printf("Voltage: %lf\n", voltage);
  void CCONV
}
  onAttachedEventHandler(PhidgetHandle channel, void *userPtr) {
...
      printf("A channel has been attached\n");
PhidgetVoltageInputHandle ch;
      // Do things after attachment (i.e. read data, control the device)
...
  }
//Assign the handler that will be called when the event occurs
 
Phidget_setOnVoltageChangeHandler(ch, onVoltageChangeHandler, NULL);
  int
  main(int argc, char **argv) {
    // .....Then, in the main code create the channel and set the attach handler:
    PhidgetAccelerometerHandle accel;
    PhidgetAccelerometer_create(&accel);
    Phidget_setOnAttachHandler((PhidgetHandle)accel, onAttachedEventHandler, NULL);
    // other stuff in main
  }
</syntaxhighlight>
</syntaxhighlight>
</tabber>


The attach event handler should be set '''before''' the channel is opened; otherwise, the attach event could occur before the handler is set.
== Do Things with a Channel ==
After a channel has been ''opened'' and ''attached'', software can control the Phidget device via the channel class interface.
Like setting an event handler that executes [[#Attaching a Channel|when the channels is attached]], handlers can be set to receive events when a state change occurs, or sensor data is received.
A Voltage Input channel for example, like one supported by the  [{{SERVER}}/products.php?product_id=1018 1018 Phidget Interface Kit], can set an event handler that gets called as the voltage is processed.


In Java, this would look like:
Alternately, data from the device can be accessed from the main body of a program using the associated properties. Note that the values returned by getting the values of these properties will be the same as the value from the latest event associated with the property.


<syntaxhighlight lang=java>
<tabber>
  // After creating and opening a VoltageInput channel called "sensorIn"
Java=<syntaxhighlight lang=java>
  sensorIn.addVoltageChangeListener((VoltageInputVoltageChangeEvent de) -> {
double val = ch.getVoltage();
            System.out.println("Voltage: " + de.getVoltage());
  });
</syntaxhighlight>
</syntaxhighlight>
 
|-|
Or in C:
Python=<syntaxhighlight lang=python>
 
val = ch.getVoltage()
<syntaxhighlight lang=c>
  void CCONV
  onVoltageChangeHandler(PhidgetVoltageInputHandle voltageInput, void *ctx, double voltage) {
printf("Voltage: %lf V\n", voltage);
  }
 
  // .....Then, in the main code:
  // After creating and opening a VoltageInput channel called "sensorIn"
  PhidgetVoltageInput_setOnVoltageChangeHandler(sensorIn, onVoltageChangeHandler, NULL);
</syntaxhighlight>
</syntaxhighlight>
 
|-|
The voltage value delivered in the above snippets could also be accessed via the <code>Voltage</code> property of the channel. Properties that have related events are automatically updated each time the event is received by the channel, and calls between events always return the value set by the last event.
  C#=<syntaxhighlight lang=cSharp>
 
double val = ch.Voltage;
<syntaxhighlight lang=java>
    double val = sensorIn.getVoltage();
</syntaxhighlight>
</syntaxhighlight>
 
|-|
Or, in C:
C=<syntaxhighlight lang=c>
 
double voltage;
<syntaxhighlight lang=c>
PhidgetVoltageInput_getVoltage(ch, &voltage);
    double val;
    PhidgetVoltageInput_getVoltage(sensorIn, &val);
</syntaxhighlight>
</syntaxhighlight>
</tabber>


===Sensors, Input, and Output===
=== Close a Channel ===


Often, your Phidget will support more than one channel class.  For example a [{{SERVER}}/products.php?product_id=1018 1018 Phidget Interface Kit] has voltage inputs (black sensor ports), digital inputs and digital outputs (green terminal blocks). You can determine the channel classes supported by your Phidget from the product page and the {{Phidget22API}}.
When you are finished with a channel, you should close and (in some languages) delete it.  Once closed, the physical Phidget channel the software channel was matched to will be released, and made available to attach to other software channels.
 
For InterfaceKits like the 1018:
 
* To the voltage inputs, you can attach various sensors (temperature, humidity, light, sound) 
* To the digital inputs, you can attach various input devices (switches)
* To the digital outputs, you can attach simple indicators (LEDs, buzzers, relays)
 
The features and channels supported by each Phidget are many and varied, and we only include general concepts on this page. You can view the complete list of channels supported by a Phidget in the {{Phidget22API}}. Select a device at the top of the screen, select your preferred programming language, and then select which channel class you want to view the documentation for.
 
== Close a Channel ==
 
When you are finished with a channel, you should close and (in some languages) delete it.  Once closed, the Phidget device channel the channel was matched to will be released and made available for another channel to match.


For example, in Java:
For example, in Java:


<syntaxhighlight lang=java>
<tabber>
  device.close();
Java=<syntaxhighlight lang=java>
  device = null;
ch.close();
</syntaxhighlight>
|-|
Python=<syntaxhighlight lang=python>
ch.close()
</syntaxhighlight>
|-|
C#=<syntaxhighlight lang=cSharp>
ch.Close();
</syntaxhighlight>
|-|
C=<syntaxhighlight lang=c>
Phidget_close((PhidgetHandle)ch);
PhidgetDigitalInput_delete(&ch); //Replace DigitalInput with the channel class of your channel
</syntaxhighlight>
</syntaxhighlight>
</tabber>


Or, in C:
<syntaxhighlight lang=c>
Phidget_close((PhidgetHandle)channel);
Phidget_release((PhidgetHandle *)&channel); // will NULL the pointer
</syntaxhighlight>


When you close a channel, it will reset all of the properties of that channel. For example, a digital output will revert back to FALSE when it is closed. If you want to have persistent properties, you can keep the channel open in another process over the [[Phidget Network Server|Network Server]] and open it remotely with your main program. As long as the channel is opened in at least one program or process, its properties will persist.
When you close a channel, it will reset all of the properties of that channel. For example, a digital output will revert back to FALSE when it is closed.


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


[[Data Interval/Change Trigger]] - Learn about these two properties that control how much data comes in from your sensors.
[[Using Multiple Phidgets]] - Tips about using multiple Phidgets in your program.


[[Using Multiple Phidgets]] - How to know you are attaching to the Phidget you want.
[[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.


[[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.
[[Data Interval/Change Trigger]] - Learn about these two properties that control how much data comes in from your sensors.


[[Logging, Exceptions, and Errors]] - Learn about all the tools you can use to debug your program.
[[Logging, Exceptions, and Errors]] - Learn about all the tools you can use to debug your program.

Revision as of 21:38, 31 October 2018

Before You Start

Before trying to start programming Phidgets, you should have a basic understanding of what a Phidget is, and how they can be used. For an introduction to Phidgets, check out What is a Phidget?.

This page will explain the concepts behind how Phidgets are used in any software application.

Channels

To program with Phidgets, it is important to understand how the physical input and output channels of Phidget devices correspond to the software controlling them.

The Phidgets library is very modular, with each part of the device's behaviour split into individual parts called Channels. Each channel represents a single part of a device, such as a single input on a digital input Phidget, the humidity sensor on a humidity Phidget, or one motor on a DC motor controller.

Each channel has a Channel Class, corresponding to the type of function the channel is to perform. For example, a TemperatureSensor channel will be used to measure temperature, and an RFID channel will deal with an RFID reader. Each channel class is designed make using channels of that class as similar as possible regardless of the Phidget they are a part of, while also supporting the unique features of each. You can find out what channel classes are available to your Phidget by looking at its User Guide.

Each channel class has a set of functions tailored to the use of that type of device. For example, a VoltageInput channel has functions you can use to control and read the Voltage Input, such as setting the data interval or reading the voltage:

The set of all functions and other tools used to program with Phidgets is called the Phidgets Application Programming Interface (API). In addition to features unique to the class, every channel class also includes some functionality common to all channel classes, documented in the Phidgets API under Phidget Common. For example, every channel has basic functions like open() and close(), which are the same no matter which Phidget you're using.

Outline of a Program with Phidgets

General Phidget Program Flowchart.png

Every Phidget channel you use in any program will follow the same life cycle:

  1. Create a channel: Make a variable to keep track of your Phidget
  2. Address the channel: Set some basic parameters to indicate which Phidget to connect to.
    • You can specify as much, or as little as you deem necessary. You can even use a Phidget without specifying any parameters, if your system is simple enough.
  3. Open the channel: Opening the channel will begin trying to match a physical Phidget channel to your software channel.
  4. Detect when the channel is attached: Your program must wait until a physical Phidget channel has been attached to your software channel.
    • The attachment process is handled automatically, and will attach to the first available Phidget channel that matches all your specified addressing parameters.
    • A channel is attached when the Phidget libraries link a physical Phidget channel to your software channel.
    • Waiting for attachment can be handled automatically as part of opening the channel or separately, as best suits your program.
  5. Do things with the channel: Send commands to and receive data from your Phidget.
    • This section will encompass the majority of your program. The Phidget API / libraries will make this process as straightforward as possible, and is similar across all types of Phidgets.
  6. Close the channel: Once your program is done, you close the Phidget channel.
    • This frees up the Phidget for the next program that might need it.

A Closer Look, with Examples

For a closer look at the parts of a Phidget program, this section will dissect the sections of a Phidget program in more detail. Small code snippets are provided for each step in the sections below to provide a representation of the code.

For a look at how these steps are handled in your specific programming language, check out the Write Code section of the Language Page for your programming language.

The best reference to the features of each channel class is the Phidget22 API for your specific device and language. This page is intended to be a high-level introduction.

Creating a Channel

To control a Phidget channel, you must first create an instance of its channel class that will be used to keep track of the channel through your program.

For example:

 // Create a new Accelerometer channel
 Accelerometer accel = new Accelerometer();
 // Create a new RFID channel
 RFID rfid = new RFID();
 # Create a new Accelerometer channel
 accel = Accelerometer()
 # Create a new RFID channel
 rfid = RFID()
 // Create a new Accelerometer channel
 Accelerometer accel = new Accelerometer();
 // Create a new RFID channel
 RFID rfid = new RFID();
 // Create a new Accelerometer channel
 PhidgetAccelerometerHandle ch;
 PhidgetAccelerometer_create(&ch);
 // Create a new RFID channel
 PhidgetRFIDHandle ch;
 PhidgetRFID_create(&ch);

Addressing Phidgets

In this step you set up the parameters the Phidget library will use to match your software channel to a physical channel on a Phidget.

By default, the matching code in the Phidget library will attach the first available Phidget channel that is of the correct channel class. This works well for single Phidgets, but can be insufficient for systems with multiple Phidgets present. If not enough addressing parameters are specified, your software channel may attach to the wrong Phidget.

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

Addressing Example

In this example, we have a TMP1101 4x Thermocouple Phidget and a HUB0000 VINT Hub.

Channel-matching-3.jpg

If we wanted to open the thermocouple connected to channel 0, on hub port 2, the Java code would look like:

TemperatureSensor tc = new TemperatureSensor(); //Create

tc.setDeviceSerialNumber(370181); //Address
tc.setHubPort(2);
tc.setChannel(0);

Net.enableServerDiscovery(ServerType.DEVICE_REMOTE);

tc.open(5000); //Open
tc = TemperatureSensor() #Create

tc.setDeviceSerialNumber(370181) #Address
tc.setHubPort(2)
tc.setChannel(0)

Net.enableServerDiscovery(PhidgetServerType.PHIDGETSERVER_DEVICEREMOTE)

tc.openWaitForAttachment(5000); #Open
TemperatureSensor tc = new TemperatureSensor(); //Create

tc.DeviceSerialNumber = 370181; //Address
tc.HubPort = 2;
tc.Channel = 0;

Net.EnableServerDiscovery(ServerType.DeviceRemote);

tc.openWaitForAttachment(5000); //Open
PhidgetTemperatureSensorHandle tc; //Create
PhidgetTemperatureSensor_create(&tc);

PhidgetTemperatureSensor_setDeviceSerialNumber(tc, 370181); //Address
PhidgetTemperatureSensor_setHubPort(tc, 2);
PhidgetTemperatureSensor_setChannel(tc, 0);

PhidgetNet_enableServerDiscovery(PHIDGETSERVER_DEVICEREMOTE);

Phidget_openWaitForAttachment((PhidgetHandle)tc, 5000); //Open

Opening a Channel

After you have created and addressed a channel, you need to open it to begin the process of attaching the software channel to a physical channel.

For example, in Java:

ch.open(5000);
ch.openWaitForAttachment(5000);
ch.Open(5000);
Phdiget_openWaitForAttachment((PhidgetHandle)ch, 5000);

In Java and C# open() is overloaded. In other languages, you would use openWaitForAttachment(5000) to perform the same function.

The openWaitForAttachment() function will hold the program until a Phidget channel matching the one you specified is attached, or the function times out. There is a similar function called open() that will do the attachment process in the background, and allow your program to continue before the channel has been attached.

The open() and openWaitForAttachment() functions only begin the process of matching the channel handle you created to a channel of a Phidget device, and do not actually open the Phidget itself. An open channel that does not match any Phidget channels at first can still attach to a matching channel that is plugged in long after it was first opened.

Attaching a Channel

When a channel is open (and not attached), the system will continue to try to match it with a Phidget device channel until either a match is found, or the channel is closed.

Any one physical channel can only be attached to one software channel at a time. For example, if you connected a single Phidget Accelerometer to a computer, and you created and opened two software Accelerometer channels, only one of the channels would attach while the other would remain open but not attached. If the attached channel were to be closed, the other software channel would then attach to the Accelerometer.


When the software channel is matched with a physical channel, the channel is attached and an Attach event is fired.

An event handler can be registered to catch the Attach event. Each channel also has an Attached property that can be read to determine if the channel has been matched to a physical channel.

The following examples show how to set an event handler to detect the Attach event:

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

The attach event handler should be set before the channel is opened; otherwise, the attach event could occur before the handler is set to deal with it.


Note: Once a physical channel is attached to a software channel, it will not be available to attach to another software channel until the first channel is closed. The one exception is if the Phidget device channel is attached over the network through the Phidget Network Server. In that case, multiple channels are allowed to match and attach to the Phidget device channel. Some Phidgets, such as motor controllers will never match more than one channel at a time, for safety reasons.

Do Things with a Channel

After a channel has been opened and attached, software can control the Phidget through the functions available to its channel class.

This is the stage of your program where you can send commands to your channel, and handle the information it sends back.

Generally, we recommend configuring any initial setup for your channel in its Attach handler, so it is set up before your program uses it, and so it can be re-initialized in case it is somehow detached and re-attached (such as if it is unplugged and plugged back in).

Additionally, you can set up event handlers to handle events from the channel, such as when a state change occurs, or when sensor data is received. Event handlers should be set up before opening the channel to avoid missing events, but they will begin executing during this phase of the program.

For example, with a Voltage Input channel, you could set up an event handler to process Voltage Change events.

//Declare the event listener
public static VoltageInputVoltageChangeListener onVoltageChange = new VoltageInputVoltageChangeListener() {
    @Override
    public void onVoltageChange(VoltageInputVoltageChangeEvent e) {
        System.out.println("Voltage: " + e.getVoltage());
    }
};
...
VoltageInput ch;
...
//Assign the event listener that will be called when the event occurs
ch.addVoltageChangeListener(onVoltageChange);
#Declare the event handler
def onVoltageChangeHandler(self, voltage):
    print("Voltage: " + str(voltage))
...
ch = VoltageInput()
...
#Assign the handler that will be called when the event occurs
ch.setOnVoltageChangeHandler(onVoltageChangeHandler)
//Declare the event handler
void voltageChange(object sender, Phidget22.Events.VoltageChangeEventArgs e) {
    Console.WriteLine("Voltage: " + e.Voltage.ToString());
}
...
VoltageInput ch;
...
//Assign the handler that will be called when the event occurs
ch.VoltageChange += voltageChange;
//Declare the event handler
static void CCONV onVoltageChangeHandler(PhidgetVoltageInputHandle ph, void *ctx, double voltage) {
    printf("Voltage: %lf\n", voltage);
}
...
PhidgetVoltageInputHandle ch;
...
//Assign the handler that will be called when the event occurs
Phidget_setOnVoltageChangeHandler(ch, onVoltageChangeHandler, NULL);


Alternately, data from the device can be accessed from the main body of a program using the associated properties. Note that the values returned by getting the values of these properties will be the same as the value from the latest event associated with the property.

double val = ch.getVoltage();
val = ch.getVoltage()
double val = ch.Voltage;
double voltage;
PhidgetVoltageInput_getVoltage(ch, &voltage);

Close a Channel

When you are finished with a channel, you should close and (in some languages) delete it. Once closed, the physical Phidget channel the software channel was matched to will be released, and made available to attach to other software channels.

For example, in Java:

ch.close();
ch.close()
ch.Close();
Phidget_close((PhidgetHandle)ch);
PhidgetDigitalInput_delete(&ch); //Replace DigitalInput with the channel class of your channel


When you close a channel, it will reset all of the properties of that channel. For example, a digital output will revert back to FALSE when it is closed.

Further Reading

Using Multiple Phidgets - Tips about using multiple Phidgets in your program.

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.

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

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.