Best Phidgets Practices: Difference between revisions

From Phidgets Support
No edit summary
 
(18 intermediate revisions by 3 users not shown)
Line 1: Line 1:
The purpose of this page is to provide you with a list of "Best Practices" to follow when writing code that uses Phidgets. These guidelines are especially important if your program is going to be used by people other than you, or on many different systems. If you follow these guidelines, you'll probably save yourself a few headaches in the future.
[[Category:Programming]]
The purpose of this page is to provide a list of "Best Practices" to follow when writing code that uses Phidgets. These "Best Practices" are designed to eliminate common mistakes made when using the {{Phidget22API}}, and to help maintain an stable structure while build more complicated systems.


== Keep Event Handlers Short ==
== Check Results ==
Almost every method in the {{Phidget22API}} returns a result code, or throws an exception if the language supports exceptions.  The result code must be checked, and any exception caught, to ensure each operation is successful.  Ignoring results will in the best case cause programs to crash, and in the worst, lead to invalid or unexpected behavior.


Event handlers (specifically the ones that handle data "change" events) are constantly being put on the stack as data comes in on your typical Phidget program. The purpose of these handlers is to give you an opportunity to process each point of data that comes in. For example, you might convert a temperature reading from Celsius to Kelvin, or you might perform a rolling average on data coming in from your load cell. However, problems can arise if you try to do too much in your event handler. Actually, it has less to do with the amount of code and more to do with the type of code that's in your handler.  
== Use Event Handlers ==
The Phidget library supports both polling channel properties to determine state and to get current data values, and the library supports firing events when states change and data is received. Reading channel properties directly is useful to determine the state or current data value at a point in time, but is difficult to implement correctly. Event handlers are more predicable and easier to implement correctly. Unless a program has a specific and obvious reason to access properties directly, event handlers should be used.


Imagine you have an accelerometer that's sending acceleration data every 20 milliseconds. If your change handler takes 21ms to execute, the next data point will be ready before the previous one is done being processed. Now, occasionally going over-time is not a problem, since the Phidgets drivers will queue up to 500 data points before it starts dropping (ignoring) data points. But if your handler consistently takes longer than your sensor's data interval, you're not going to be able to keep up.
== Set Properties in the Attach Handler ==


You can keep the execution time of your event handlers down by avoiding the use of notoriously time-expensive tasks, or by using a separate thread to handle these aspects. Some such tasks include:
An attach event will occur each time a channel is matched. This makes the attach handler the perfect place to initialize properties such as {{Code|DataInterval}}, {{Code|ChangeTrigger}}, gain values, and ranges. If properties are initialize elsewhere, in a situation where the channel detaches temporarily, those properties will revert to defaults during the next attach.  Setting properties within the attach handler ensures they are always the expected values.


* Updating GUI elements
== Keep Event Handlers Short ==
* Waiting for user input
* Writing to a file


Events handlers are called from special dispatch threads within the Phidget library.  Each channel maintains its own queue of events, and these events are processed in order and one at a time.  If a user event handler blocks, or takes longer than the <code>DataInterval</code> of the channel, events will become 'stale', and eventually the system will begin throwing away events.


== Be Specific With Open() ==
For example, if an Accelerometer channel has been configured to receive data every 20 milliseconds and the event handler averages 21ms to execute, the next change event will be ready before the previous one is finished being processed.  Eventually the channel's event queue will fill and the library will begin throwing away events.


When you use {{Code|Open()}} to gain access to a channel on a Phidgets device, it will try to find a channel of the object type that you're using (e.g. {{Code|VoltageInput}}). There are also a number of properties you can set to narrow down which channel gets opened. For example:
A common mistake is to update a GUI, or wait for user input from within an event handler.  Most GUI APIs have support for dispatching updates to the GUI thread, and those should be used. Waiting for user input will block the event handler, and should never be done. Instead, a flag should be set and a loop in another thread should wait for the input.


* The '''serial number''' of the device or the VINT Hub that it's connected to
== Be Specific With Addressing ==
* The '''port''' it's connected to (if it's connected to a VINT Hub)
* The '''channel''' on the device, if it has multiple channels of the same object type
* Whether the channel '''is remote''' or '''is local'''
* The '''server name''', if the device is being accessed over the [[Phidget Network Server]]


If you don't set these properties before calling {{Code|Open()}}, the Phidgets software will grab the first channel that matches. In many cases, this will work just fine. For example, if I have a Phidget temperature sensor connected to my computer, and I try to open a {{Code|TemperatureSensor}} object without setting any of these properties, it will still find and open the correct channel. But what if you also have a DC motor controller connected to your computer? If the motor controller has an on-board temperature sensing chip for safety purposes, opening a {{Code|TemperatureSensor}} object could open either one.  
When you open a Phidget channel, the library tries to attach a channel matching all the addressing properties that have been set. If none of the matching properties are set, the Phidget library will match the first channel of the same class. In simple cases this will be fine. If your program deals with multiple Phidgets, it is always wise to be specific.


Since there's no way to predict what other Phidgets may be plugged into the computer (or available over the network), you should always be as specific as possible when opening a channel.  
For example, if a Phidget temperature sensor is the only device connected to a computer, opening a {{Code|TemperatureSensor}} channel without setting any addressing properties will attach to that temperature sensor; however, if a DC motor controller is connected to the computer, the on-board temperature sensor on the motor controller might attach to the channel instead. This could be prevented by setting a {{code|DeviceSerialNumber}} or {{code|HubPort}}.


== When In Doubt, Open Remotely ==
Since there's no way to predict what other Phidgets may be plugged into a computer (or become available over the network), you should be as specific as possible before opening a channel.


When you use {{Code|Open()}} to gain access to a channel on a Phidgets device, you can either open it '''locally''' or '''remotely''' (if you have the [[Phidget Network Server|Network Server]] enabled). If a channel is opened locally, it can't be opened by any other client for as long as it remains opened. But if a channel is opened remotely, any number of clients can simultaneously connect to it (with the exception of certain devices like motor controllers). Because of this, it's advisable to open your channels remotely in most cases. This way, you'll always be able to open the channel, even if another instance of your program is running.
== Don't Forget to Close() ==


In cases where data rate is crucial (e.g. control loops or other time-sensitive processes) you may want to stick to local connections, since data rate is a bit lower over the network.
Calling {{Code|Close()}} on a channel releases the channel so that it can be matched again, and to ensure your Phidget has stopped. For example, certain motor controllers will maintain speed or continue trying to track the last position they were sent to, if they are not stopped or closed before the program ends. In [[Language_-_LabVIEW|LabVIEW]], the runtime environment executes a program internally, so if {{Code|Close()}} is not called, the LabVIEW environment will continue to tie up the channel despite the program having been stopped.


== Set Properties in the Attach Handler ==
== When In Doubt, Open Remotely ==  
 
When the [[Phidget Network Server|Network Server]] is enabled, a channel can match both a local device channel and a remote channel. The end result would be functionally the same; however, most remote channels support being attached to multiple clients, while a local device channel can only be attached once. Unless the desire is to only allow the device channel to be attached once, or performance is critical, it is more flexible to match the network channel as other clients will still be able to attach to the device channel.
An '''attach''' event will occur any time a channel is successfully opened. This makes the attach handler the perfect place to initialize all of your properties such as {{Code|DataInterval}}, {{Code|ChangeTrigger}}, gain values, and ranges. If you initialize elsewhere, in a situation where the Phidget briefly detaches due to electrical interference or power loss, you'll find that it will attach with the default settings on those properties.  
 
== Don't Forget to Close() ==


Calling {{Code|Close()}} on a locally opened channel frees up the channel so that it can opened by another client. In most cases, it's not actually necessary to call {{Code|Close()}} because as long as your program closes and the process ends, the channel will be freed up regardless. However, it's still a good practice to call {{Code|Close()}} at the end of your program, because some programs and programming languages' processes will continue to run in the background and tie up the channel. For example in [[Language_-_LabVIEW|LabVIEW]], the compiler merely interprets your program and runs the code under its own process. So if you open a channel without closing, the LabVIEW environment will continue to tie up the channel despite having stopped the program you're working on.
See the <code>IsRemote</code> and <code>IsLocal</code> Phidget properties in the {{Phidget22API}}.


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

Latest revision as of 16:42, 4 January 2019

The purpose of this page is to provide a list of "Best Practices" to follow when writing code that uses Phidgets. These "Best Practices" are designed to eliminate common mistakes made when using the Phidget22 API, and to help maintain an stable structure while build more complicated systems.

Check Results

Almost every method in the Phidget22 API returns a result code, or throws an exception if the language supports exceptions. The result code must be checked, and any exception caught, to ensure each operation is successful. Ignoring results will in the best case cause programs to crash, and in the worst, lead to invalid or unexpected behavior.

Use Event Handlers

The Phidget library supports both polling channel properties to determine state and to get current data values, and the library supports firing events when states change and data is received. Reading channel properties directly is useful to determine the state or current data value at a point in time, but is difficult to implement correctly. Event handlers are more predicable and easier to implement correctly. Unless a program has a specific and obvious reason to access properties directly, event handlers should be used.

Set Properties in the Attach Handler

An attach event will occur each time a channel is matched. This makes the attach handler the perfect place to initialize properties such as DataInterval, ChangeTrigger, gain values, and ranges. If properties are initialize elsewhere, in a situation where the channel detaches temporarily, those properties will revert to defaults during the next attach. Setting properties within the attach handler ensures they are always the expected values.

Keep Event Handlers Short

Events handlers are called from special dispatch threads within the Phidget library. Each channel maintains its own queue of events, and these events are processed in order and one at a time. If a user event handler blocks, or takes longer than the DataInterval of the channel, events will become 'stale', and eventually the system will begin throwing away events.

For example, if an Accelerometer channel has been configured to receive data every 20 milliseconds and the event handler averages 21ms to execute, the next change event will be ready before the previous one is finished being processed. Eventually the channel's event queue will fill and the library will begin throwing away events.

A common mistake is to update a GUI, or wait for user input from within an event handler. Most GUI APIs have support for dispatching updates to the GUI thread, and those should be used. Waiting for user input will block the event handler, and should never be done. Instead, a flag should be set and a loop in another thread should wait for the input.

Be Specific With Addressing

When you open a Phidget channel, the library tries to attach a channel matching all the addressing properties that have been set. If none of the matching properties are set, the Phidget library will match the first channel of the same class. In simple cases this will be fine. If your program deals with multiple Phidgets, it is always wise to be specific.

For example, if a Phidget temperature sensor is the only device connected to a computer, opening a TemperatureSensor channel without setting any addressing properties will attach to that temperature sensor; however, if a DC motor controller is connected to the computer, the on-board temperature sensor on the motor controller might attach to the channel instead. This could be prevented by setting a DeviceSerialNumber or HubPort.

Since there's no way to predict what other Phidgets may be plugged into a computer (or become available over the network), you should be as specific as possible before opening a channel.

Don't Forget to Close()

Calling Close() on a channel releases the channel so that it can be matched again, and to ensure your Phidget has stopped. For example, certain motor controllers will maintain speed or continue trying to track the last position they were sent to, if they are not stopped or closed before the program ends. In LabVIEW, the runtime environment executes a program internally, so if Close() is not called, the LabVIEW environment will continue to tie up the channel despite the program having been stopped.

When In Doubt, Open Remotely

When the Network Server is enabled, a channel can match both a local device channel and a remote channel. The end result would be functionally the same; however, most remote channels support being attached to multiple clients, while a local device channel can only be attached once. Unless the desire is to only allow the device channel to be attached once, or performance is critical, it is more flexible to match the network channel as other clients will still be able to attach to the device channel.

See the IsRemote and IsLocal Phidget properties in the Phidget22 API.

Further Reading

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

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

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.

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.