Phidget Programming Basics: Difference between revisions

From Phidgets Support
No edit summary
Line 2: Line 2:
__TOC__
__TOC__


To use your Phidget within code, you'll want to:
Please refer to [[What is a Phidget]] for an introduction to the concept of Phidgets.
# '''[[#Creating a Software Object|Create]]''' one or more Phidget software objects, which gives you access to functions specific to the features of your device.
# '''[[#Opening the Phidget|Open]]''' the Phidget using the object.
# Detect when a Phidget is '''[[#Attaching the Phidget|attached]]''' (plugged in) by using the object.
# Use '''[[#Do Things with the Phidget|functions]]''' that the object provides, like turning on LEDs, reading sensors, or triggering events on data change.
# '''[[#Close the Phidget|Close]]''' the object, when you are done.


Small code snippets are provided for each step in the sections below.  [[Language - C/C++|C++]] and [[Language - Java|Java]] were selected because Java is a relatively high-level language and C++ is a relatively low level language, thereby showing how specific each language API really isSo, the most useful resource for the ''actual functions'' would be the {{Phidget22API}} for your specific language.  This page is merely a high-level introduction.
The Phidget software library matches a Phidget device channel with a software channel that is created by a user.
Software channels are each of a class, where that class defines a set of methods, properties, events and errorsPhidget 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:
# '''[[#Creating a Software Object|Create]]''' an instance of the channel class that provides access to the device you want to control.
# '''[[#Opening the Phidget|Open]]''' the channel.
# Detect when the channel is '''[[#Attaching the Channel|attached]]'''.
# Use '''[[#Do Things with the Phidget|methods and properties]]''' of the attached channel.
# '''[[#Close the Phidget|Close]]''' the channel.


== Creating a Software Object ==
Small code snippets are provided for each step in the sections below.  [[Language - Java|Java]] and [[Language - C/C++|C]] were selected because Java is a high-level language and C is 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.


Phidget devices are controlled using software objects. A Phidget may have one or more objects, each in charge of a different feature of that device. For example, the 1018 - Phidget InterfaceKit has four possible objects: <code>Digital Input</code>, <code>Digital Output</code>, <code>Voltage Input</code>, and <code>VoltageRatio Input</code>. All software objects have a function that allow you to '''create''' it, and one to '''delete''' it, in addition to handlers that will let you set up functions when certain things happen to the Phidget.
== Creating a Channel ==


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
for digital input and digital out, and therefore exports <code>DigitalInput</code> and <code>DigitalOutput</code> channels.
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.


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


<syntaxhighlight lang=java>
<syntaxhighlight lang=java>
  // Create a new Accelerometer object
  // Create a new Accelerometer object
  Accelerometer accel = new Accelerometer();
  Accelerometer accel = new Accelerometer();
</syntaxhighlight>
</syntaxhighlight>
<syntaxhighlight lang=java>
<syntaxhighlight lang=java>
  // Create a new RFID device object
  // Create a new RFID device object
  RFID rfid = new RFID();
  RFID rfid = new RFID();
</syntaxhighlight>
</syntaxhighlight>


Line 39: Line 37:


<syntaxhighlight lang=c>
<syntaxhighlight lang=c>
  // Create a new Accelerometer object
  // Create a new Accelerometer object
  PhidgetAccelerometerHandle accel = 0;
  PhidgetAccelerometerHandle accel;
  PhidgetAccelerometer_create(&accel);
  PhidgetAccelerometer_create(&accel);
</syntaxhighlight>
</syntaxhighlight>
<syntaxhighlight lang=c>
<syntaxhighlight lang=c>
  // Create a new RFID device object
  // Create a new RFID device object
  PhidgetRFIDHandle rfid = 0;
  PhidgetRFIDHandle rfid;
  PhidgetRFID_create(&rfid);
  PhidgetRFID_create(&rfid);
</syntaxhighlight>
</syntaxhighlight>


Software objects will also have special functions specific to the feature they belong to. For example, the <code>Voltage Input</code> object contains a <code>getVoltage</code> function (or for some languages, a <code>Voltage</code> property) that lets you access the current voltage measured by the input. The accelerometer API includes a function to set the sensitivity on each axis. The RFID API has a function that writes to a writable RFID tag.
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.


== Opening the Phidget ==
== Opening the Channel ==


Phidgets can either be opened when attached directly to a computer, or they can be opened remotely using the [[Phidget Network Server]].  This section deals primarily with opening Phidgets directly.
After you have created a [[#Creating a Software Object| channel instance]], you can call the <code>open()</code> method to begin the process of matching the channel to a Phidget device channel.


Once you have created the [[#Creating a Software Object|software object]], you can call the <code>open()</code> function in your language on that object. <code>open()</code> is part of the generic Phidget API.
For example, with the <code>Accelerometer</code> channel in Java:
For example, with an accelerometer object in Java:


<syntaxhighlight lang=java>
<syntaxhighlight lang=java>
Line 75: Line 65:
</syntaxhighlight>
</syntaxhighlight>


To see how to use open in other languages, have a look at the {{Phidget22API}}.
To see how to use <code>open()</code> in other languages, please refer to the {{Phidget22API}}.


The <code>open()</code> function in any language opens the software object for use, not the hardware itself.  Having the software "open" before the hardware means that the software can capture all events, including multiple attach (plug in) and detach (unplug) events for one <code>open()</code> call.
The <code>open()</code> function begins the process of matching the channel handle you created to a channel of a Phidget device, and does 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 met its criteria.


===Details for Open()===
===Details for Open()===


Open will return immediately once called, because it can be called even if the Phidget to be used is not attached to the system. This is known as an asynchronous call. It’s important to understand that most calls on a Phidget will fail if they are called when the Phidget is not attached - in fact the only calls that are allowed on a detached Phidget are <code>close()</code>, <code>waitForAttachment()</code> and <code>getAttached()</code>.
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
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 once.  For 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.


Open is also pervasive. This means that once open has been called, it will constantly try to stay attached to a Phidget. Even if the Phidget is unplugged from the computer and then plugged back in, you will simply get a Detach event, and then an Attach event. It’s a good idea to handle the Detach event in order to avoid calling the Phidget after it has detached.
When the channels is matched with a Phidget device channel, the channel state is changed to ''attached'' and an event is fired.


'''Note:''' Once a Phidget is opened by an application, it cannot be opened again in another application until closed by the first. When open and attached in software, no other programs or instances can read data from or change the Phidget. This includes it being open via the Windows Control Panel application! The one exception is if the Phidget is controlled ''only'' over the network with the [[Phidget Network Server]], and not directlyThen, you can use multiple remote control programs. Some Phidgets such as motor controllers can never be opened by multiple programs, even if all of the connections are remote.
'''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.


===Channel Matching===
===Channel Matching===


Open can be used without setting any properties (in which case it will try to get the first object of that type it can find), or you can set properties such as <code>DeviceSerialNumber</code>, <code>Channel</code>, or in the case of a remote Phidget,<code>isRemote</code> and <code>ServerName</code> to open a specific device's object. The list of all properties that can be set for open can be found in the {{Phidget22API}}. If there are more than one of the same type of Phidget attached to a computer, and you use open() without specifying the serial number or some other property, there is no way of knowing which Phidget will be opened first. Therefore, it is considered [[Best Phidgets Practices|best practice]] to be specific as possible when setting these properties. In complex systems with many Phidgets, getting to the channel you want can get confusing, so some examples will be provided below.
<code>open()</code> can be used without specifying any matching 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 matching parameter.
 
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.
 
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.
 
Please refer to the {{Phidget22API}}, and [[Best Phidgets Practices|Best Practices]] for more information on matching channels to Phidget device channels.


==== Opening a Channel on a USB Phidget ====
==== Opening a Channel on a USB Phidget ====
Line 115: Line 116:
==== Opening a VINT Hub Port as a Channel ====
==== Opening a VINT Hub Port as a Channel ====


The ports on a [[What is VINT?|VINT]] Hub can be opened as Digital Inputs, Digital Outputs, Voltage Inputs, or VoltageRatio 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 sixth port.  
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 sixth port.  


[[Image:channel-matching-2.jpg|link=|500px]]
[[Image:channel-matching-2.jpg|link=|500px]]
Line 167: Line 168:
</syntaxhighlight>
</syntaxhighlight>


== Attaching the Phidget ==
== Attaching the Channel ==


Physically, attaching a Phidget means plugging it in.  The real guts behind the 'attach' command, however, occur within the software libraries.  The 'attach' event is what makes the final connections between the opened software object and the corresponding thread and events.  This is why all Phidget objects must be attached in software, even those that are not actually plugged in with a cable.  This includes Phidgets used remotely via our [[Phidget Network Server]], it includes Interface Kits on the same board as our Single Board Computer, and it even includes the [[Phidget Manager]] software object, which is a sort of meta-Phidget from which you can [[Phidget Manager|manage other Phidgets]]. When you plug in a Phidget, each software object and each channel that it uses will attach individually. For example, if you plugged in the 1024 - Phidget RFID Read/Write, and you had all of the channels opened and ready for attachment, you would get an attach event for:
When a channel is open (and not ''attached''), the system will continue to try to match it with a
* the RFID object
Phidget device channel until either a match is found, or the channel is closed. When the channels is matched with a Phidget device channel, the channel state is changed to ''attached'' and an event is fired.
* the digital output for the onboard LED
* the digital output for the LED terminal
* and the digital output for the 5V relay terminal.


In your code, you can detect an attachment either with an '''event''' in event-driven programming, or '''waiting''' for it, in logic programming. For information about these two types of programming, see the page on [[Polling vs. Events]].
An event handler can be registered to catch the ''attach event'' through the channel's <code>Attach</code> event. Each channel also has a <code>Attached</code> property that can be read to determine if the class has
been matched to a Phidget device channel.


=== Event Attachment ===
To set an event handler to detect the attach in Java:
 
For example, to use an event to detect attachment in Java:


<syntaxhighlight lang=java>
<syntaxhighlight lang=java>
Line 185: Line 182:
   Accelerometer accel = new Accelerometer();
   Accelerometer accel = new Accelerometer();
   accel.addAttachListener((AttachEvent ae) -> {
   accel.addAttachListener((AttachEvent ae) -> {
       Accelerometer attached = (Accelerometer) ae.getSource();
       Accelerometer accel = (Accelerometer) ae.getSource();
       // Do things after attachment (i.e. read data, control the device)
       // Do things after attachment (i.e. read data, control the device)
       }
       }
Line 191: Line 188:
</syntaxhighlight>
</syntaxhighlight>


Or to use an event to detect attachment in C:
Or in C:


<syntaxhighlight lang=c>
<syntaxhighlight lang=c>
   // Define the attach handler function
   // Define the attach handler function
   void CCONV OnAttachedEventHandler(PhidgetHandle Device, void *userPtr) {
   void CCONV onAttachedEventHandler(PhidgetHandle channel, void *userPtr) {
       printf("A new device has been plugged in!");
       printf("A channel has been attached\n");
       // Do things after attachment (i.e. read data, control the device)
       // Do things after attachment (i.e. read data, control the device)
   }
   }
Line 204: Line 201:
     PhidgetAccelerometerHandle accel;
     PhidgetAccelerometerHandle accel;
     PhidgetAccelerometer_create(&accel);
     PhidgetAccelerometer_create(&accel);
     Phidget_setOnAttachHandler((PhidgetHandle)accel,OnAttachedEventHandler, NULL)
     Phidget_setOnAttachHandler((PhidgetHandle)accel, OnAttachedEventHandler, NULL);
   
   
     // other stuff in main
     // other stuff in main
    return 0;
   }
   }
</syntaxhighlight>
</syntaxhighlight>


Both of the code snippets above do the same thing.  The function <code>AttachHandler(...)</code>/<code>AttachListener(...)</code> is called automatically when a device is plugged in.
You should set the attach event handler '''before''' you <code>open()</code> the channel; otherwise, you may miss attach event if it occurs between opening the channel and setting the handler.
 
You should set the attach event handler '''before you open the Phidget object'''.  Otherwise, you may miss an attach event if it occurs between opening the object and setting the handler.
 
This method for using events to detect attachment can be expanded to other events and more complex control flow.  Where possible, all example code downloads from the [[Software Overview#Language Support|specific language pages]] will use [[Polling vs. Events|event-driven programming]].
 
=== Wait for Attachment ===
 
Waiting for attachment is a straightforward process.  Rather than setting up an event handler to do something every time an attach happens, it simply waits for a device to be plugged in before moving on and doing something once.
In Phidget22, waitForAttachment has been rolled into the open command rather than being a separate function call after opening.
 
For example, waiting for an accelerometer object C:
 
<syntaxhighlight lang=c>
// after opening the Accelerometer object "accel":
int result;
// Wait up to 10000 ms for the accelerometer to be plugged in
result = Phidget_openWaitForAttachment((PhidgetHandle)accel, 10000))
 
if(result != 0) {
    // openWaitForAttachment returns a non-zero error code when it fails
    // you could handle the error in this 'if' statement by printing the error code
}
else {
    // Successful attachment
    // Do things after attachment (i.e. read data, control the device)
}
 
</syntaxhighlight>
 
Or in Java, you simply pass a parameter to the <code>open()</code> call:
 
<syntaxhighlight lang=java>
// After opening the Accelerometer object "accel":
// When provided with a parameter, open will wait for a number of milliseconds equal
// to the timeout parameter provided.
accel.open(10000);
// Do things after attachment (i.e. read data, control the device)
</syntaxhighlight>
 
So, unlike the event model above, a Phidget software object should be opened before waiting for a device to be plugged in.


== Do Things with the Phidget ==
== Do Things with the Phidget ==


After you have a [[#Creating a Software Object|properly created]] Phidget software object, you can actually use methods and properties of that object to do things like turn LEDs on, change output states, or read data from sensors.
After a channel has been ''opened'' and ''attached'', software can control the Phidget device via the channel class interface.


For many Phidgets, you probably want to read data from its sensors or inputs. This might be, say, a sensor plugged in to a [{{SERVER}}/products.php?product_id=1018 1018 Phidget Interface Kit] used in the code snippets below.  You can do this either by detecting changes via [[Polling vs. Events|event driven code]], or polling for new values via [[Polling vs. Events|logic code]].  
The examples below are for a.


'''Details about data handling:'''
Like setting an event handler that executes [[#Event Attachment|when the channels is attached]], event handlers can be set for many Phidget devices when a state change occurs, or sensor data is received.


*When a Phidget is opened, its initial state will be read before it is marked as attached. This allows polling of many properties -- including some data -- even during the Attach event, and anytime afterwards.
For example, for a Voltage Input channel like the ones supported by the  [{{SERVER}}/products.php?product_id=1018 1018 Phidget Interface Kit] you can set an event handler that gets called at a defined interval.
 
*Your computer can poll much faster than the Phidget can respond.  If you poll in a continuous '''<code>while</code>''' loop in byte code, you will probably swamp the Phidget with requests.
 
*Similarly, if you set a value and then immediately read the value on the next line in your program, the Phidget may not have time to finish the set.  In our examples, we use <code>print()</code> statements within loops.  Print functions are relatively slow; you can also use <code>wait()</code> or <code>sleep()</code> depending on your language. This also applies to rapidly changing output properties. For example, if you turn on a digital output and then turn it off in the next line of code, the output will appear to never turn on because the hardware doesn't have time to react. You need to put more instructions (preferably a wait or sleep function) between the two to guarantee that both changes actually happen.
 
*If you are handling data using events as described below, the data event functions will fire when the device is plugged in and its initial state is read.
 
*Some properties have default values, but these should not be trusted. Remember: '''always set''', don’t rely on defaults. Trying to read an uninitialised value with no default will result in an Exception.
 
*Usually by default, a sensor will trigger change events for the quantity it's sensing at a regular time interval (usually 8 ms). If you want to only get change events when the measured value exceeds a certain threshold, you need to set the <code>ChangeTrigger</code>. For example, setting <code>TemperatureChangeTrigger</code> for a thermocouple board.
 
*Often Phidgets will retain their last state unless power is lost. This can give surprising results as the previous state may not always be what you expect. For example, if you open an InterfaceKit and set an output, this output may stay set even after the Phidget is closed. Be sure to set all outputs to their ideal settings before closing the object those outputs belong to.
 
===Capture Data Change with Events===
 
To capture data changes in sensors or inputs as they happen, you need to use [[Polling vs. Events|event driven code]].
 
Like defining an event function that fires [[#Event Attachment|when the Phidget is plugged in]], you can create functions that automatically run when, for example, a sensor value or input value changes.
 
For example, for a VoltageInput object like the ones on a 1018 - PhidgetInterfaceKit, you can create a function that gets called when the input value changes.  You would do this '''before''' the Phidget software object has been [[#Opening the Phidget|opened]].


In Java, this would look like:
In Java, this would look like:
Line 294: Line 228:
</syntaxhighlight>
</syntaxhighlight>


Or to use an event to detect a voltage change in C:
Or in C:


<syntaxhighlight lang=cpp>
<syntaxhighlight lang=c>
   void __stdcall OnVoltageChangeHandler(PhidgetVoltageInputHandle voltageInput, void *userPtr, double voltage) {
   void CCONV onVoltageChangeHandler(PhidgetVoltageInputHandle voltageInput, void *userPtr, double voltage) {
printf("\nVoltage: %lf V", voltage);
printf("\nVoltage: %lf V\n", voltage);
   }
   }


   // .....Then, in the main code:
   // .....Then, in the main code:
   // After creating and opening a VoltageInput object called "sensorIn":
   // After creating and opening a VoltageInput object called "sensorIn":
   PhidgetVoltageInput_setOnVoltageChangeHandler(sensorIn, OnVoltageChangeHandler, NULL);
   PhidgetVoltageInput_setOnVoltageChangeHandler(sensorIn, onVoltageChangeHandler, NULL);
</syntaxhighlight>
</syntaxhighlight>


===Poll for Data Change===
The voltage value delivered in the above snippets could also be accessed via the <code>Voltage</code> property of the channelProperties 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.
 
To poll for sensor data, or output state, you usually want to look for a '''get...Value''' or '''get...State''' function available in the {{Phidget22API}} for your device. Or, in the case of object-oriented langauges like C#, look for a property with the name of the data you want (for example, instead of <code>getTemperature</code>, just use the <code>Temperature</code> property). Then, you simply set up a loop that get the value of a sensor continuously.
 
To poll your software object, the object must already be [[#Opening the Phidget|open]]This is in contrast to the event-driven method above, where all event handlers are declared and attached before opening the object. The easiest thing to do is open the device at the beginning of your program and not close it until the end of the program.  You can poll it any number of times in the intervening period.
 
Note that when you poll the value of a sensor or another attribute, this will probably be within a loop.  When you create this loop, the ''more code'' you have within a loop, the ''more slowly'' your loop will run, and the ''more slowly'' you will be sampling the value in practice. If you have too much code in your loop, this may make you lose data, as described further on the [[Data Interval/Change Trigger]] page.
 
This effect is also felt with interpreted languages (Java, Python) versus purely compiled languages, as the interpreted languages sample more slowly even within an otherwise completely empty loop.
 
So if you want to sample as fast as possible, and capture all of the changes that a sensor produces, you should [[#Capture Data Change with Events|capture data with event programming]].  If you choose not to use the event-driven design, you should keep the code run between polls to a minimum. This way you can sample as quickly as possible.
 
These code snippets assume <code>vin</code> is a VoltageInput object, like one of the inputs on a [{{SERVER}}/products.php?product_id=1018 1018 Phidget Interface Kit 8/8/8]. For example, in Java:


<syntaxhighlight lang=java>
<syntaxhighlight lang=java>
  double val;
    double val = sensorIn.getVoltage();
  for (int i = 0; i < 10; i++) {
}
    val = vin.getVoltage();
    System.out.println("Value: " + val);
  }
</syntaxhighlight>
</syntaxhighlight>


Or, in C, for the Sensor at location 5 on the Interface Kit board:
Or, in C:


<syntaxhighlight lang=cpp>
<syntaxhighlight lang=c>
 
    double val;
  double val;
     PhidgetVoltageInput_getVoltage(sensorIn, &val);
  for (int i = 0; i < 10; i++) {
     PhidgetVoltageInput_getVoltage(vin, &val);
    printf("Value: %f\n", val);
   }
   }
</syntaxhighlight>
</syntaxhighlight>
Line 429: Line 345:
== Close the Phidget ==
== Close the Phidget ==


When you are finished with the Phidget software object at the end of your program, you should close and (in some languages) delete it.
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:
Line 440: Line 356:
Or, in C:
Or, in C:


<syntaxhighlight lang=cpp>
<syntaxhighlight lang=c>
  Phidget_close((CPhidgetHandle) device);
  Phidget_close((PhidgetHandle)channel);
  Phidget_release((CPhidgetHandle) device);
  Phidget_release((PhidgetHandle)&channel); // will NULL the pointer
</syntaxhighlight>
</syntaxhighlight>
The <code>close()</code> call removes the lock that [[#Opening the Phidget|open]] put on the Phidget.  Make sure to close your object, so other software can use those parts of the Phidget!
The close() function also makes sure the thread associated with the Phidget close properly.  Any outstanding writes will block close() until they complete, because writes are guaranteed to complete (unless a device is detached).
Also note that a device should be put into a known state before calling close. For example, if a motor controller is driving a motor and close is called, it will continue to drive the motor even though the application has exited. This may or may not be what you want.  This is a result of the fact that all Phidgets boards will maintain their current state until they are powered down (physically detached from the computer), even when they are closed by the current application.


== Further Reading ==
== Further Reading ==
Line 455: Line 365:
[[Data Interval/Change Trigger]] - Learn about these two properties that control how much data comes in from your sensors.
[[Data Interval/Change Trigger]] - Learn about these two properties that control how much data comes in from your sensors.


[[Using Multiple Phidgets]] - It can be difficult to figure out how to use more than one Phidget in your program. This page will guide you through the steps.
[[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.

Revision as of 20:08, 27 June 2017

Please refer to What is a Phidget for an introduction to the concept of Phidgets.

The Phidget software library matches a Phidget device channel with a software channel that is created by a user. 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:

  1. Create an instance of the channel class that provides access to the device you want to control.
  2. Open the channel.
  3. Detect when the channel is attached.
  4. Use methods and properties of the attached channel.
  5. Close the channel.

Small code snippets are provided for each step in the sections below. Java and C were selected because Java is a high-level language and C is low level language. The best reference to the features each channel class is the Phidget22 API for your specific language. This page is intended to be a high-level introduction.

Creating a Channel

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 for digital input and digital out, and therefore exports DigitalInput and DigitalOutput channels.

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.

For example, in Java:

 // Create a new Accelerometer object
 Accelerometer accel = new Accelerometer();
 // Create a new RFID device object
 RFID rfid = new RFID();

Or in C:

 // Create a new Accelerometer object
 PhidgetAccelerometerHandle accel;
 PhidgetAccelerometer_create(&accel);
 // Create a new RFID device object
 PhidgetRFIDHandle rfid;
 PhidgetRFID_create(&rfid);

A channel class will have properties and methods specific to the feature they belong to. For example, the VoltageInput class has a Voltage property that lets you access the current voltage measured by the device, the Accelerometer class has properties to set the sensitivity on each axis and the RFID has a method that writes to a writable RFID tag.

Opening the Channel

After you have created a channel instance, you can call the open() method to begin the process of matching the channel to a Phidget device channel.

For example, with the Accelerometer channel in Java:

 accel.open();

Or in C:

 Phidget_open((PhidgetHandle) accel);

To see how to use open() in other languages, please refer to the Phidget22 API.

The open() function begins the process of matching the channel handle you created to a channel of a Phidget device, and does 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 met its criteria.

Details for Open()

Because open() simply enables the process of matching a channel to a Phidget device channel, open() 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 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 once. For example, if you connected a single Phidget Accelerometer to a computer, and you created and opened two 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 channel would then attach to the Accelerometer.

When the channels is matched with a Phidget device channel, the channel state is changed to attached and an event is fired.

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.

Channel Matching

open() can be used without specifying any matching 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 matching parameter.

If there is more than one Phidget connected to the computer that supports the channel class, the DeviceSerialNumber 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 Channel property must be set to determine which Phidget device channel will match.

If the Phidget Network Server is enabled on the computer, the IsRemote and IsLocal properties can be used to determine if the channel will match the Phidget device channel or the network channel.

Please refer to the Phidget22 API, and Best Practices for more information on matching channels to Phidget device channels.

Opening a Channel on a USB Phidget

Channel-matching-1.jpg

In this example, a 1018 PhidgetInterfaceKit 8/8/8 is connected to a computer. A 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:

VoltageRatioInput ch = new VoltageRatioInput();
ch.setDeviceSerialNumber(324781);
ch.setChannel(3);
ch.open();

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

DigitalInput ch = new DigitalInput();
ch.setDeviceSerialNumber(324781);
ch.setChannel(5);
ch.open();

Opening a VINT Hub Port as a Channel

The ports on a VINT Hub can be opened as Digital Inputs, Digital Outputs, Voltage Inputs, or Voltage Ratio Inputs. Suppose you had a HUB0000 VINT Hub with a 1133 Sound Sensor connected to its sixth port.

Channel-matching-2.jpg

Here's how you would open it in Java:

VoltageInput ch = new VoltageInput();
ch.setDeviceSerialNumber(370181);
ch.setIsHubPortDevice(true);
ch.setHubPort(6);
ch.open();

Opening a Channel on a VINT Device

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

Channel-matching-3.jpg

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

TemperatureSensor tc = new TemperatureSensor(); // Handle for the thermocouple
TemperatureSensor ic = new TemperatureSensor(); // Handle for the integrated temperature chip

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

tc.open();
ic.open();

Opening a Channel on a Remote Phidget

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 1024 PhidgetRFID connected to a computer that has the Phidget Network Server enabled.

Channel-matching-4.jpg

You could open the RFID reader channel remotely with the following code in Java:

RFID ch = new RFID();
ch.setDeviceSerialNumber(388624);
ch.setIsRemote(true);
ch.open();

Attaching the 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. When the channels 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 Attach event. Each channel also has a Attached property that can be read to determine if the class has been matched to a Phidget device channel.

To set an event handler to detect the attach in Java:

  //create a Phidget accelerometer object:
  Accelerometer accel = new Accelerometer();
  accel.addAttachListener((AttachEvent ae) -> {
      Accelerometer accel = (Accelerometer) ae.getSource();
      // Do things after attachment (i.e. read data, control the device)
      }
  });

Or in C:

  // Define the attach handler function
  void CCONV onAttachedEventHandler(PhidgetHandle channel, void *userPtr) {
      printf("A channel has been attached\n");
      // Do things after attachment (i.e. read data, control the device)
  }

  int main() {
    // .....Then, in the main code create the object and set the attach handler:
    PhidgetAccelerometerHandle accel;
    PhidgetAccelerometer_create(&accel);
    Phidget_setOnAttachHandler((PhidgetHandle)accel, OnAttachedEventHandler, NULL);
 
    // other stuff in main
  }

You should set the attach event handler before you open() the channel; otherwise, you may miss attach event if it occurs between opening the channel and setting the handler.

Do Things with the Phidget

After a channel has been opened and attached, software can control the Phidget device via the channel class interface.

The examples below are for a.

Like setting an event handler that executes when the channels is attached, event handlers can be set for many Phidget devices when a state change occurs, or sensor data is received.

For example, for a Voltage Input channel like the ones supported by the 1018 Phidget Interface Kit you can set an event handler that gets called at a defined interval.

In Java, this would look like:

  // After creating and opening a VoltageInput object called "sensorIn":
  sensorIn.addVoltageChangeListener((VoltageInputVoltageChangeEvent de) -> {
            System.out.println("Voltage: " + de.getVoltage());
  });

Or in C:

  void CCONV onVoltageChangeHandler(PhidgetVoltageInputHandle voltageInput, void *userPtr, double voltage) {				
	printf("\nVoltage: %lf V\n", voltage);
  }

  // .....Then, in the main code:
  // After creating and opening a VoltageInput object called "sensorIn":
  PhidgetVoltageInput_setOnVoltageChangeHandler(sensorIn, onVoltageChangeHandler, NULL);

The voltage value delivered in the above snippets could also be accessed via the Voltage 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.

    double val = sensorIn.getVoltage();
}

Or, in C:

    double val;
    PhidgetVoltageInput_getVoltage(sensorIn, &val);
  }

Sensors, Input, and Output

Often, your Phidget will be something like an 1018 Phidget Interface Kit which has voltage inputs (black plug holes), digital inputs and outputs (green screw attachments). You can learn about the software objects your Phidget uses and how to physically connect them by visiting its product page and the Phidget22 API. For InterfaceKits like the 1018:

  • To the voltage inputs, you can attach various sensors, including sensors for temperature, humidity, light, sound, and so on.
  • To the digital inputs, you can attach various input devices, including switches.
  • To the digital outputs, you can attach simple indicators like LEDs, buzzers, or relays.

You use all of these things in software entirely through the software objects that each one belongs to. For example, to turn off an LED connected to output 1 on on an RFID tag reader, you'll want to set the output at location 1 to "0" (or false). In C, this would be:

  // Create the DigitalOutput software object:
  PhidgetDigitalOutput led_out = 0;
  PhidgetDigitalOutput_create(&led_out);
  Phidget_setChannel((PhidgetHandle)led_out,1);
  // Open and handle the attachment of the DigitalOutput object
  ....

  // Then, turn the LED off, passing first the digitalOutput handle, then the new state:
  PhidgetDigitalOutput_setState(led_out, 0);

Or in Java, this would be:

  // Create the DigitalOutput software object:
  DigitalOutput led_out = new DigitalOutput();
  led_out.setChannel(1);
  // Open and handle the attachment of the digital output object
  ....

  // Then, turn the LED off, passing first the output number, then the new state:
  led_out.setState(0);

Getting a digital input would follow a similar pattern, except you would use the getState function and store the result in a variable instead of passing the function a new output state.

Getting sensor data from a voltage input is a little more complicated because:

  • You must declare the sensor as one of two types (ratiometric or non-ratiometric). If it is ratiometric, use the VoltageRatioInput object to open the channel. If it is non-ratiometric, use the VoltageInput object instead. To find out which your sensor is, read the product information for your specific sensor on our main web site.
  • You must translate the 0-5V reading that you get from the input into the proper units you need (temperature, luminosity, decibels, etc.)

If the sensor comes from Phidgets, you can use the setSensorType method in order to have the conversion done for you.

For example, to obtain the lux from the - PrecisionLightSensor, a non-ratiometric sensor plugged into voltage input 5, you would do this in C:

 // Use the VoltageInput object because the 1127 is non-ratiometric
 PhidgetVoltageInputHandle voltageInput;
 PhidgetVoltageInput_create(&voltageInput)

 // Set the input channel to 5 and open
 Phidget_setChannel(voltageInput, 5);
 Phidget_open(voltageInput);

 // Set the sensor type. For a complete list of Phidgets sensors, see the Sensor Type enum in the API documentation.
 PhidgetVoltageInput_setSensorType(voltageInput, SENSOR_TYPE_1127);

 // Get the sensor value; since the library knows it's an 1127, it will automatically convert from volts to lux.
 int lightLevel;
 PhidgetVoltageInput_getSensorValue(voltageInput, &lightLevel);


Or in Java:

  // Use the VoltageInput object because the 1127 is non-ratiometric
  VoltageInput voltageInput = new VoltageInput();
  
  // Set the input channel to 5 and open
  voltageInput.setChannel(5);
  voltageInput.open();

  // Set the sensor type. For a complete list of Phidgets sensors, see the Sensor Type enum in the API documentation.
  voltageInput.setSensorType(SENSOR_TYPE_1127);

  // Get the sensor value; since the library knows it's an 1127, it will automatically convert from volts to lux.
  int lightLevel = voltageInput.SensorValue();

Learning Everything You Can Do

The things you can do with your particular Phidget are many and varied, so we only include general concepts on this page.

You can view the complete list of functions for your device in the Phidget22 API. Select your device at the top of the screen, select your preferred programming language, and then select which object type you want to view the documentation for.

The API documentation is broken up into sections. The first section is a list of methods (or if you're using an object-oriented language, properties), after that there'll be a list of events and event handlers. After that, there may be sections for enumerations (which are like names that let you select options for certain functions, like SensorType in the earlier example), error events, or structs, depending on the language.

Close the Phidget

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:

  device.close();
  device = null;

Or, in C:

 Phidget_close((PhidgetHandle)channel);
 Phidget_release((PhidgetHandle)&channel); // will NULL the pointer

Further Reading

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

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.

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.