Phidget Programming Basics

From Phidgets Support
Revision as of 20:08, 13 April 2017 by Mparadis (talk | contribs)

The Basic Functions

To use your Phidget within code, you'll want to:

  1. Create one or more Phidget software objects, which gives you access to functions specific to the features of your device.
  2. Open the Phidget using the object.
  3. Detect when a Phidget is attached (plugged in) by using the object.
  4. Use functions that the object provides, like turning on LEDs, reading sensors, or triggering events on data change.
  5. Close the object, when you are done.

Small code snippets are provided for each step in the sections below. C++ and 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 is. So, the most useful resource for the actual functions would be the API documentation for your specific language. This page is merely a high-level introduction.


Creating a Software Object

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: Digital Input, Digital Output, Voltage Input, and VoltageRatio Input. 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.


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 = 0;
 PhidgetAccelerometer_create(&accel);


 // Create a new RFID device object
 PhidgetRFIDHandle rfid = 0;
 PhidgetRFID_create(&rfid);

Software objects will also have special functions specific to the feature they belong to. For example, the Voltage Input object contains a getVoltage function (or for some languages, a Voltage 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.

Opening the Phidget

Phidgets can either be opened when attached directly to a computer, or they can be opened remotely using the Phidget WebService. This section deals primarily with opening Phidgets directly.

Once you have created the software object, you can call the open() function in your language on that object. open() is part of the generic Phidget API. For example, with an accelerometer object in Java:

 accel.open();

Or in C:

 Phidget_open((PhidgetHandle) accel);

To see how to use open in other languages, have a look at the [{{SERVER}/?view=api API documentation].

The open() 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 open() call.

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 close(), waitForAttachment() and getAttached().

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.

Open can be used without setting any properties to try and get the first object of that type it can find, or you can set properties such as DeviceSerialNumber, Channel, or in the case of a remote Phidget,isRemote and ServerName to open a specific device's object. The list of all properties that can be set for open can be found in the API documentation. 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.

If you are looking to do a remote open call, to use the Phidget WebService, you only have to set the isRemote property to change your program from a locally-running one to one that can control a Phidget over the network. We give an in-depth example of using the WebService on each of our operating system pages, we have a brief overview of the WebService (with code snippets) in the Using Phidgets over a Network section, and we often have WebService code snippets on the language pages which do not easily extend from the examples on this page.

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 WebService, and not directly. Then, you can use multiple remote control programs.

Attaching the Phidget

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

  • the RFID object
  • 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 Events vs. Polling.

Event Attachment

For example, to use an event to detect attachment in Java:

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

Or to use an event to detect attachment in C:

  // Define the attach handler function
  void CCONV OnAttachedEventHandler(PhidgetHandle Device, void *userPtr) {
      printf("A new device has been plugged in!");
      // 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

    return 0;

  }

Both of the code snippets above do the same thing. The function AttachHandler(...)/AttachListener(...) is called automatically when a device is plugged in.

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 specific language pages will use 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:

 // 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)
 }

Or in Java, you simply pass a parameter to the open() call:

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

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

After you have a 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.

For many Phidgets, you probably want to read data from its sensors or inputs. This might be, say, a sensor plugged in to a 1018 Phidget Interface Kit used in the code snippets below. You can do this either by detecting changes via event driven code, or polling for new values via logic code.

Details about data handling:

  • 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.
  • Your computer can poll much faster than the Phidget can respond. If you poll in a continuous while 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 print() statements within loops. Print functions are relatively slow; you can also use wait() or sleep() 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 ChangeTrigger. For example, setting TemperatureChangeTrigger 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 event driven code.

Like defining an event function that fires 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 opened.

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 to use an event to detect a voltage change in C:

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

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

Poll for Data Change

To poll for sensor data, or output state, you usually want to look for a get...Value or get...State function available in the API 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 getTemperature, just use the Temperature 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 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 Rate/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 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 vin is a VoltageInput object, like one of the inputs on a 1018 Phidget Interface Kit 8/8/8. For example, in Java:

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

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

  double val;
  for (int i = 0; i < 10; i++) {
    PhidgetVoltageInput_getVoltage(vin, &val);
    printf("Value: %f\n", 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 API Documentation. 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 sensorValue;
 PhidgetVoltageInput_getSensorValue(voltageInput, &sensorValue);


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 sensorValue = 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 API documentation. 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 the Phidget software object at the end of your program, you should close and (in some languages) delete it.

For example, in Java:

  device.close();
  device = null;

Or, in C:

 Phidget_close((CPhidgetHandle) device);
 Phidget_release((CPhidgetHandle) device);

The close() call removes the lock that 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

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 Service - Phidgets can be controlled and communicated with over your network- either wirelessly or over ethernet.