diff options
Diffstat (limited to '')
37 files changed, 5091 insertions, 3099 deletions
diff --git a/Java/com/phidgets/AdvancedServoPhidget.java b/Java/com/phidgets/AdvancedServoPhidget.java index 1aa485a..db33e2a 100644 --- a/Java/com/phidgets/AdvancedServoPhidget.java +++ b/Java/com/phidgets/AdvancedServoPhidget.java @@ -314,7 +314,7 @@ public final class AdvancedServoPhidget extends Phidget  	 * Sets the speed ramping state.  	 * <p>  	 * Disable speed ramping to disable velocity and acceleration control. With speed ramping disabled, the servo will be sent to -	 * the desired position immediately upon recieving the command. This is how the regular Phidget Servo Controller works. +	 * the desired position immediately upon receiving the command. This is how the regular Phidget Servo Controller works.  	 * <p>  	 * This is turned on by default.  	 * diff --git a/Java/com/phidgets/Dictionary.java b/Java/com/phidgets/Dictionary.java index 0afde5e..211bdfc 100644 --- a/Java/com/phidgets/Dictionary.java +++ b/Java/com/phidgets/Dictionary.java @@ -228,7 +228,7 @@ public class Dictionary  	}  	/**  	 * Closes this Dictionary. -	 * This will shut down all threads dealing with this Dictionary and you won't recieve any more events. +	 * This will shut down all threads dealing with this Dictionary and you won't receive any more events.  	 *   	 * @throws PhidgetException If this Dictionary is not opened.   	 */ diff --git a/Java/com/phidgets/IRPhidget.java b/Java/com/phidgets/IRPhidget.java index 8418d74..6a1d198 100644 --- a/Java/com/phidgets/IRPhidget.java +++ b/Java/com/phidgets/IRPhidget.java @@ -1,239 +1,239 @@ -
 -/*
 - * Copyright 2010 Phidgets Inc.  All rights reserved.
 - */
 -
 -package com.phidgets;
 -import java.util.Iterator;
 -import java.util.LinkedList;
 -import com.phidgets.event.*;
 -/**
 - * This class represents a Phidget IR. All methods
 - * to send and receive IR data are implemented in this class.
 - * <p>
 - * The Phidget IR Receiver-Transmitter can send and receive Consumer-IR signals. Ability to learn and re-transmit codes, 
 - * as well as low-level access to raw data, is provided.
 - * 
 - * @author Phidgets Inc.
 - */
 -public final class IRPhidget extends Phidget
 -{
 -	public IRPhidget () throws PhidgetException
 -	{
 -		super (create ());
 -	}
 -	private static native long create () throws PhidgetException;
 -
 -	/**
 -	 * Represents a long space (greater then 327,670 microseconds) in raw data. 
 -	 * This can be considered a period of no IR activity. This is used with {@link #readRaw readRaw}
 -	 */
 -	public static final int RAWDATA_LONGSPACE = 0x7fffffff;
 -
 -	/**
 -	 * Transmits a code.
 -	 * @param code the code to transmit
 -	 * @param codeInfo the code specification
 -	 * @throws PhidgetException If this Phidget is not opened and attached.
 -	 * See {@link com.phidgets.Phidget#open(int) open} for information on determining if a device is attached.
 -	 */
 -	public native void transmit (IRCode code, IRCodeInfo codeInfo) throws PhidgetException;
 -	/**
 -	 * Transmits a repeat. This needs to be called within the gap time of a transmit to be meaningful.
 -	 * @throws PhidgetException If this Phidget is not opened and attached.
 -	 * See {@link com.phidgets.Phidget#open(int) open} for information on determining if a device is attached.
 -	 */
 -	public native void transmitRepeat () throws PhidgetException;
 -	/**
 -	 * Transmits raw data.
 -	 * @param data data in microseconds, must start and end with a pulse
 -	 * @param offset offset in the data array to start transmitting
 -	 * @param count number of elements of data to transmit
 -	 * @param gap gap size in microseconds
 -	 * @param carrierFrequency carrier frequency in kHz
 -	 * @param dutyCycle duty cycle in percent
 -	 * @throws PhidgetException If this Phidget is not opened and attached.
 -	 * See {@link com.phidgets.Phidget#open(int) open} for information on determining if a device is attached.
 -	 */
 -	public native void transmitRaw (int[]data, int offset, int count, int gap, int carrierFrequency, int dutyCycle) throws PhidgetException;
 -	/**
 -	 * Transmits raw data.
 -	 * @param data data in microseconds, must start and end with a pulse
 -	 * @throws PhidgetException If this Phidget is not opened and attached.
 -	 * See {@link com.phidgets.Phidget#open(int) open} for information on determining if a device is attached.
 -	 */
 -	public final void transmitRaw (int[]data) throws PhidgetException
 -	{
 -		transmitRaw (data, 0, data.length, 0, 0, 0);
 -	}
 -	/**
 -	 * Transmits raw data.
 -	 * @param data data in microseconds, must start and end with a pulse
 -	 * @param gap gap size in microseconds
 -	 * @throws PhidgetException If this Phidget is not opened and attached.
 -	 * See {@link com.phidgets.Phidget#open(int) open} for information on determining if a device is attached.
 -	 */
 -	public final void transmitRaw (int[]data, int gap) throws PhidgetException
 -	{
 -		transmitRaw (data, 0, data.length, gap, 0, 0);
 -	}
 -	/**
 -	 * Transmits raw data.
 -	 * @param data data in microseconds, must start and end with a pulse
 -	 * @param offset offset in the data array to start transmitting
 -	 * @param count number of elements of data to transmit
 -	 * @throws PhidgetException If this Phidget is not opened and attached.
 -	 * See {@link com.phidgets.Phidget#open(int) open} for information on determining if a device is attached.
 -	 */
 -	public final void transmitRaw (int[]data, int offset, int count) throws PhidgetException
 -	{
 -		transmitRaw (data, offset, count, 0, 0, 0);
 -	}
 -	/**
 -	 * Transmits raw data.
 -	 * @param data data in microseconds, must start and end with a pulse
 -	 * @param offset offset in the data array to start transmitting
 -	 * @param count number of elements of data to transmit
 -	 * @param gap gap size in microseconds
 -	 * @throws PhidgetException If this Phidget is not opened and attached.
 -	 * See {@link com.phidgets.Phidget#open(int) open} for information on determining if a device is attached.
 -	 */
 -	public final void transmitRaw (int[]data, int offset, int count, int gap) throws PhidgetException
 -	{
 -		transmitRaw (data, offset, count, gap, 0, 0);
 -	}
 -	/**
 -	 * Reads raw data. Use {@link #RAWDATA_LONGSPACE RAWDATA_LONGSPACE} to detect gaps in IR data.
 -	 * @param buffer array into which data will be read.
 -	 * @param offset offset in data to start writing
 -	 * @param count maximum ammount of data to read
 -	 * @return ammount of data read
 -	 * @throws PhidgetException If this Phidget is not opened and attached.
 -	 * See {@link com.phidgets.Phidget#open(int) open} for information on determining if a device is attached.
 -	 */
 -	public native int readRaw (int[]buffer, int offset, int count) throws PhidgetException;
 -	/**
 -	 * Reads raw data. Use {@link #RAWDATA_LONGSPACE RAWDATA_LONGSPACE} to detect gaps in IR data.
 -	 * @param buffer array into which data will be read.
 -	 * @return ammount of data read
 -	 * @throws PhidgetException If this Phidget is not opened and attached.
 -	 * See {@link com.phidgets.Phidget#open(int) open} for information on determining if a device is attached.
 -	 */
 -	public final int readRaw (int[]buffer) throws PhidgetException
 -	{
 -		return readRaw (buffer, 0, buffer.length);
 -	}
 -	/**
 -	 * Returns the last recieved code. This is updated right after the code event returns.
 -	 * @return last code
 -	 * @throws PhidgetException If this Phidget is not opened and attached. 
 -	 * See {@link com.phidgets.Phidget#open(int) open} for information on determining if a device is attached.
 -	 */
 -	public native IRCode getLastCode () throws PhidgetException;
 -	/**
 -	 * Returns the last learned code. This is updated right after the learn event returns.
 -	 * @return last learned code
 -	 * @throws PhidgetException If this Phidget is not opened and attached. 
 -	 * See {@link com.phidgets.Phidget#open(int) open} for information on determining if a device is attached.
 -	 */
 -	public native IRLearnedCode getLastLearnedCode () throws PhidgetException;
 -
 -	private final void enableDeviceSpecificEvents (boolean b)
 -	{
 -		enableCodeEvents (b && codeListeners.size () > 0);
 -		enableLearnEvents (b && learnListeners.size () > 0);
 -		enableRawDataEvents (b && rawDataListeners.size () > 0);
 -	}
 -	/**
 -	 * Adds a code listener. The code handler is a method that will be called when a new code is
 -	 seen by the reader. The event is fired on each code, including repetitions.
 -	 * <p>
 -	 * There is no limit on the number of code handlers that can be registered for a particular Phidget.
 -	 * 
 -	 * @param l An implemetation of the {@link com.phidgets.event.CodeListener CodeListener} interface
 -	 */
 -	public final void addCodeListener (CodeListener l)
 -	{
 -		synchronized (codeListeners)
 -		{
 -			codeListeners.add (l);
 -			enableCodeEvents (true);
 -	}} private LinkedList codeListeners = new LinkedList ();
 -	private long nativeCodeHandler = 0;
 -	public final void removeCodeListener (CodeListener l)
 -	{
 -		synchronized (codeListeners)
 -		{
 -			codeListeners.remove (l);
 -			enableCodeEvents (codeListeners.size () > 0);
 -	}} private void fireCode (CodeEvent e)
 -	{
 -		synchronized (codeListeners)
 -		{
 -			for (Iterator it = codeListeners.iterator (); it.hasNext ();)
 -				((CodeListener) it.next ()).code (e);
 -		}
 -	}
 -	private native void enableCodeEvents (boolean b);
 -	/**
 -	 * Adds a code learn listener. The learn handler is a method that will be called when a new code is
 -	 learned by the reader. This requires that the code be repeated several times.
 -	 * <p>
 -	 * There is no limit on the number of learn handlers that can be registered for a particular Phidget.
 -	 * 
 -	 * @param l An implemetation of the {@link com.phidgets.event.LearnListener LearnListener} interface
 -	 */
 -	public final void addLearnListener (LearnListener l)
 -	{
 -		synchronized (learnListeners)
 -		{
 -			learnListeners.add (l);
 -			enableLearnEvents (true);
 -	}} private LinkedList learnListeners = new LinkedList ();
 -	private long nativeLearnHandler = 0;
 -	public final void removeLearnListener (LearnListener l)
 -	{
 -		synchronized (learnListeners)
 -		{
 -			learnListeners.remove (l);
 -			enableLearnEvents (learnListeners.size () > 0);
 -	}} private void fireLearn (LearnEvent e)
 -	{
 -		synchronized (learnListeners)
 -		{
 -			for (Iterator it = learnListeners.iterator (); it.hasNext ();)
 -				((LearnListener) it.next ()).learn (e);
 -		}
 -	}
 -	private native void enableLearnEvents (boolean b);
 -	/**
 -	 * Adds a rawData listener. The rawData handler is a method that will be called when a raw IR data is recieved.
 -	 * <p>
 -	 * There is no limit on the number of rawData handlers that can be registered for a particular Phidget.
 -	 * 
 -	 * @param l An implemetation of the {@link com.phidgets.event.RawDataListener RawDataListener} interface
 -	 */
 -	public final void addRawDataListener (RawDataListener l)
 -	{
 -		synchronized (rawDataListeners)
 -		{
 -			rawDataListeners.add (l);
 -			enableRawDataEvents (true);
 -	}} private LinkedList rawDataListeners = new LinkedList ();
 -	private long nativeRawDataHandler = 0;
 -	public final void removeRawDataListener (RawDataListener l)
 -	{
 -		synchronized (rawDataListeners)
 -		{
 -			rawDataListeners.remove (l);
 -			enableRawDataEvents (rawDataListeners.size () > 0);
 -	}} private void fireRawData (RawDataEvent e)
 -	{
 -		synchronized (rawDataListeners)
 -		{
 -			for (Iterator it = rawDataListeners.iterator (); it.hasNext ();)
 -				((RawDataListener) it.next ()).rawData (e);
 -		}
 -	}
 -	private native void enableRawDataEvents (boolean b);
 -}
 + +/* + * Copyright 2010 Phidgets Inc.  All rights reserved. + */ + +package com.phidgets; +import java.util.Iterator; +import java.util.LinkedList; +import com.phidgets.event.*; +/** + * This class represents a Phidget IR. All methods + * to send and receive IR data are implemented in this class. + * <p> + * The Phidget IR Receiver-Transmitter can send and receive Consumer-IR signals. Ability to learn and re-transmit codes,  + * as well as low-level access to raw data, is provided. + *  + * @author Phidgets Inc. + */ +public final class IRPhidget extends Phidget +{ +	public IRPhidget () throws PhidgetException +	{ +		super (create ()); +	} +	private static native long create () throws PhidgetException; + +	/** +	 * Represents a long space (greater then 327,670 microseconds) in raw data.  +	 * This can be considered a period of no IR activity. This is used with {@link #readRaw readRaw} +	 */ +	public static final int RAWDATA_LONGSPACE = 0x7fffffff; + +	/** +	 * Transmits a code. +	 * @param code the code to transmit +	 * @param codeInfo the code specification +	 * @throws PhidgetException If this Phidget is not opened and attached. +	 * See {@link com.phidgets.Phidget#open(int) open} for information on determining if a device is attached. +	 */ +	public native void transmit (IRCode code, IRCodeInfo codeInfo) throws PhidgetException; +	/** +	 * Transmits a repeat. This needs to be called within the gap time of a transmit to be meaningful. +	 * @throws PhidgetException If this Phidget is not opened and attached. +	 * See {@link com.phidgets.Phidget#open(int) open} for information on determining if a device is attached. +	 */ +	public native void transmitRepeat () throws PhidgetException; +	/** +	 * Transmits raw data. +	 * @param data data in microseconds, must start and end with a pulse +	 * @param offset offset in the data array to start transmitting +	 * @param count number of elements of data to transmit +	 * @param gap gap size in microseconds +	 * @param carrierFrequency carrier frequency in kHz +	 * @param dutyCycle duty cycle in percent +	 * @throws PhidgetException If this Phidget is not opened and attached. +	 * See {@link com.phidgets.Phidget#open(int) open} for information on determining if a device is attached. +	 */ +	public native void transmitRaw (int[]data, int offset, int count, int gap, int carrierFrequency, int dutyCycle) throws PhidgetException; +	/** +	 * Transmits raw data. +	 * @param data data in microseconds, must start and end with a pulse +	 * @throws PhidgetException If this Phidget is not opened and attached. +	 * See {@link com.phidgets.Phidget#open(int) open} for information on determining if a device is attached. +	 */ +	public final void transmitRaw (int[]data) throws PhidgetException +	{ +		transmitRaw (data, 0, data.length, 0, 0, 0); +	} +	/** +	 * Transmits raw data. +	 * @param data data in microseconds, must start and end with a pulse +	 * @param gap gap size in microseconds +	 * @throws PhidgetException If this Phidget is not opened and attached. +	 * See {@link com.phidgets.Phidget#open(int) open} for information on determining if a device is attached. +	 */ +	public final void transmitRaw (int[]data, int gap) throws PhidgetException +	{ +		transmitRaw (data, 0, data.length, gap, 0, 0); +	} +	/** +	 * Transmits raw data. +	 * @param data data in microseconds, must start and end with a pulse +	 * @param offset offset in the data array to start transmitting +	 * @param count number of elements of data to transmit +	 * @throws PhidgetException If this Phidget is not opened and attached. +	 * See {@link com.phidgets.Phidget#open(int) open} for information on determining if a device is attached. +	 */ +	public final void transmitRaw (int[]data, int offset, int count) throws PhidgetException +	{ +		transmitRaw (data, offset, count, 0, 0, 0); +	} +	/** +	 * Transmits raw data. +	 * @param data data in microseconds, must start and end with a pulse +	 * @param offset offset in the data array to start transmitting +	 * @param count number of elements of data to transmit +	 * @param gap gap size in microseconds +	 * @throws PhidgetException If this Phidget is not opened and attached. +	 * See {@link com.phidgets.Phidget#open(int) open} for information on determining if a device is attached. +	 */ +	public final void transmitRaw (int[]data, int offset, int count, int gap) throws PhidgetException +	{ +		transmitRaw (data, offset, count, gap, 0, 0); +	} +	/** +	 * Reads raw data. Use {@link #RAWDATA_LONGSPACE RAWDATA_LONGSPACE} to detect gaps in IR data. +	 * @param buffer array into which data will be read. +	 * @param offset offset in data to start writing +	 * @param count maximum ammount of data to read +	 * @return ammount of data read +	 * @throws PhidgetException If this Phidget is not opened and attached. +	 * See {@link com.phidgets.Phidget#open(int) open} for information on determining if a device is attached. +	 */ +	public native int readRaw (int[]buffer, int offset, int count) throws PhidgetException; +	/** +	 * Reads raw data. Use {@link #RAWDATA_LONGSPACE RAWDATA_LONGSPACE} to detect gaps in IR data. +	 * @param buffer array into which data will be read. +	 * @return ammount of data read +	 * @throws PhidgetException If this Phidget is not opened and attached. +	 * See {@link com.phidgets.Phidget#open(int) open} for information on determining if a device is attached. +	 */ +	public final int readRaw (int[]buffer) throws PhidgetException +	{ +		return readRaw (buffer, 0, buffer.length); +	} +	/** +	 * Returns the last received code. This is updated right after the code event returns. +	 * @return last code +	 * @throws PhidgetException If this Phidget is not opened and attached.  +	 * See {@link com.phidgets.Phidget#open(int) open} for information on determining if a device is attached. +	 */ +	public native IRCode getLastCode () throws PhidgetException; +	/** +	 * Returns the last learned code. This is updated right after the learn event returns. +	 * @return last learned code +	 * @throws PhidgetException If this Phidget is not opened and attached.  +	 * See {@link com.phidgets.Phidget#open(int) open} for information on determining if a device is attached. +	 */ +	public native IRLearnedCode getLastLearnedCode () throws PhidgetException; + +	private final void enableDeviceSpecificEvents (boolean b) +	{ +		enableCodeEvents (b && codeListeners.size () > 0); +		enableLearnEvents (b && learnListeners.size () > 0); +		enableRawDataEvents (b && rawDataListeners.size () > 0); +	} +	/** +	 * Adds a code listener. The code handler is a method that will be called when a new code is +	 seen by the reader. The event is fired on each code, including repetitions. +	 * <p> +	 * There is no limit on the number of code handlers that can be registered for a particular Phidget. +	 *  +	 * @param l An implemetation of the {@link com.phidgets.event.CodeListener CodeListener} interface +	 */ +	public final void addCodeListener (CodeListener l) +	{ +		synchronized (codeListeners) +		{ +			codeListeners.add (l); +			enableCodeEvents (true); +	}} private LinkedList codeListeners = new LinkedList (); +	private long nativeCodeHandler = 0; +	public final void removeCodeListener (CodeListener l) +	{ +		synchronized (codeListeners) +		{ +			codeListeners.remove (l); +			enableCodeEvents (codeListeners.size () > 0); +	}} private void fireCode (CodeEvent e) +	{ +		synchronized (codeListeners) +		{ +			for (Iterator it = codeListeners.iterator (); it.hasNext ();) +				((CodeListener) it.next ()).code (e); +		} +	} +	private native void enableCodeEvents (boolean b); +	/** +	 * Adds a code learn listener. The learn handler is a method that will be called when a new code is +	 learned by the reader. This requires that the code be repeated several times. +	 * <p> +	 * There is no limit on the number of learn handlers that can be registered for a particular Phidget. +	 *  +	 * @param l An implemetation of the {@link com.phidgets.event.LearnListener LearnListener} interface +	 */ +	public final void addLearnListener (LearnListener l) +	{ +		synchronized (learnListeners) +		{ +			learnListeners.add (l); +			enableLearnEvents (true); +	}} private LinkedList learnListeners = new LinkedList (); +	private long nativeLearnHandler = 0; +	public final void removeLearnListener (LearnListener l) +	{ +		synchronized (learnListeners) +		{ +			learnListeners.remove (l); +			enableLearnEvents (learnListeners.size () > 0); +	}} private void fireLearn (LearnEvent e) +	{ +		synchronized (learnListeners) +		{ +			for (Iterator it = learnListeners.iterator (); it.hasNext ();) +				((LearnListener) it.next ()).learn (e); +		} +	} +	private native void enableLearnEvents (boolean b); +	/** +	 * Adds a rawData listener. The rawData handler is a method that will be called when a raw IR data is received. +	 * <p> +	 * There is no limit on the number of rawData handlers that can be registered for a particular Phidget. +	 *  +	 * @param l An implemetation of the {@link com.phidgets.event.RawDataListener RawDataListener} interface +	 */ +	public final void addRawDataListener (RawDataListener l) +	{ +		synchronized (rawDataListeners) +		{ +			rawDataListeners.add (l); +			enableRawDataEvents (true); +	}} private LinkedList rawDataListeners = new LinkedList (); +	private long nativeRawDataHandler = 0; +	public final void removeRawDataListener (RawDataListener l) +	{ +		synchronized (rawDataListeners) +		{ +			rawDataListeners.remove (l); +			enableRawDataEvents (rawDataListeners.size () > 0); +	}} private void fireRawData (RawDataEvent e) +	{ +		synchronized (rawDataListeners) +		{ +			for (Iterator it = rawDataListeners.iterator (); it.hasNext ();) +				((RawDataListener) it.next ()).rawData (e); +		} +	} +	private native void enableRawDataEvents (boolean b); +} diff --git a/Java/com/phidgets/Manager.java b/Java/com/phidgets/Manager.java index 7e7cafb..d0e5f85 100644 --- a/Java/com/phidgets/Manager.java +++ b/Java/com/phidgets/Manager.java @@ -64,7 +64,7 @@ public class Manager  	/**  	 * The default constructor. Creating a Phidget Manager object will initialize the  	 * attach and detach handlers internally, but {@link #open() open} still needs to be called -	 * to actually recieve event notifications. +	 * to actually receive event notifications.  	 */  	public Manager() throws PhidgetException  	{ @@ -195,7 +195,7 @@ public class Manager  	/**  	 * Shuts down the Phidget Manager. This method should be called to close down the Phidget Manager. -	 * Events will no longer be recieved. This method gets calledd automatically when the class is +	 * Events will no longer be received. This method gets called automatically when the class is  	 * destroyed so calling it is not required.  	 */  	public final void close() throws PhidgetException { diff --git a/Java/com/phidgets/Phidget.java b/Java/com/phidgets/Phidget.java index e2d611c..444779a 100644 --- a/Java/com/phidgets/Phidget.java +++ b/Java/com/phidgets/Phidget.java @@ -675,7 +675,7 @@ public class Phidget  	/**  	 * Closes this Phidget. -	 * This will shut down all threads dealing with this Phidget and you won't recieve any more events. +	 * This will shut down all threads dealing with this Phidget and you won't receive any more events.  	 *   	 * @throws PhidgetException If this Phidget is not opened.   	 */ diff --git a/Java/com/phidgets/PhidgetException.java b/Java/com/phidgets/PhidgetException.java index f33d345..1ace535 100644 --- a/Java/com/phidgets/PhidgetException.java +++ b/Java/com/phidgets/PhidgetException.java @@ -52,7 +52,7 @@ public class PhidgetException extends java.lang.Exception {  	/**  	 * Invalid argument exception. "Invalid argument passed to function."  	 * <P> -	 * This exception is thrown whenever a function recieves an unexpected null pointer, or a value that is out of range. ie setting a motor's speed to 101 when the maximum is 100. +	 * This exception is thrown whenever a function receives an unexpected null pointer, or a value that is out of range. ie setting a motor's speed to 101 when the maximum is 100.  	 * <p>  	 * This is returned by {@link #getErrorNumber getErrorNumber}  	 */ diff --git a/Makefile.am b/Makefile.am index 793dbd8..5e0ccf4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,6 +2,9 @@  AM_CFLAGS = -I$(top_srcdir) -I$(top_srcdir)/utils -I$(top_srcdir)/dict -I$(top_srcdir)/linux -I$(top_srcdir)/include -D_LINUX +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libphidget21.pc +  lib_LTLIBRARIES = libphidget21.la  # Rules for unpdating the libtool version: @@ -85,7 +88,6 @@ libphidget21_la_SOURCES = cphidget.c \  	cthread.h \  	phidget21.c \  	phidget21int.h \ -	linux/cusblinux.c \  	dict/pdict.c \  	dict/pdict.h \  	dict/pdictclient.c \ @@ -119,6 +121,7 @@ EXTRA_DIST = examples/ifkit.c \  	hotplug/phidgets.usermap \  	hotplug/phidgets \  	version.sh \ +	libphidget21.pc.in \  	Java/com/phidgets/DictionaryKeyListener.java \  	Java/com/phidgets/TextLCDPhidget.java \  	Java/com/phidgets/SpatialEventData.java \ @@ -231,6 +234,12 @@ libphidget21_la_SOURCES += utils/cvtutf.c  libphidget21_la_SOURCES += utils/cvtutf.h  AM_CFLAGS += -DUSE_INTERNAL_UNICONV  endif + +if NEW_LIBUSB +libphidget21_la_SOURCES += linux/cusblinux-1.0.c +else +libphidget21_la_SOURCES += linux/cusblinux.c +endif  if ZEROCONF_AVAHI  libphidget21_la_SOURCES += linux/zeroconf_avahi.c \ @@ -355,11 +364,13 @@ phidget21matlab.h:  	@echo "Making $@"  	@echo "/*" > $@  	@echo " * Phidget21 Header for Matlab" >> $@ -	@echo " * -All pointers to structs have been changed to long, as Matlab seems" >> $@ +	@echo " * -All pointers to structs have been changed to void *, as Matlab seems" >> $@  	@echo " *  to be unhappy with either the undefined stucts or the double pointers." >> $@  	@echo " */" >> $@ -	@$(CC) -g -E -P -D_LINUX -DEXTERNALPROTO -DREMOVE_DEPRECATED phidget21int.h | sed -e "s/extern \"C\" //g" | sed -e "s/struct [a-zA-Z_]* \*/long /" >> $@ +	@cat cppheader >> $@ +	@$(CC) -g -E -P -D_LINUX -DEXTERNALPROTO -DREMOVE_DEPRECATED phidget21int.h | sed -e "s/extern \"C\" //g" | sed -e "s/struct [a-zA-Z_]* \*/void * /" >> $@  	@cat cphidgetconstants.h >> $@ +	@cat cppfooter >> $@  phidget21.jar:  	@echo "Making $@" diff --git a/Makefile.in b/Makefile.in index 486ed1a..7945472 100644 --- a/Makefile.in +++ b/Makefile.in @@ -16,6 +16,7 @@  @SET_MAKE@ +  VPATH = @srcdir@  pkgdatadir = $(datadir)/@PACKAGE@  pkgincludedir = $(includedir)/@PACKAGE@ @@ -39,7 +40,9 @@ host_triplet = @host@  @ZEROCONF_FALSE@am__append_2 = -DNO_ZEROCONF  @INTERNAL_UNICONV_TRUE@am__append_3 = utils/cvtutf.c utils/cvtutf.h  @INTERNAL_UNICONV_TRUE@am__append_4 = -DUSE_INTERNAL_UNICONV -@ZEROCONF_AVAHI_TRUE@am__append_5 = linux/zeroconf_avahi.c \ +@NEW_LIBUSB_TRUE@am__append_5 = linux/cusblinux-1.0.c +@NEW_LIBUSB_FALSE@am__append_6 = linux/cusblinux.c +@ZEROCONF_AVAHI_TRUE@am__append_7 = linux/zeroconf_avahi.c \  @ZEROCONF_AVAHI_TRUE@	linux/avahi-client/client.h \  @ZEROCONF_AVAHI_TRUE@	linux/avahi-client/lookup.h \  @ZEROCONF_AVAHI_TRUE@	linux/avahi-client/publish.h \ @@ -59,21 +62,21 @@ host_triplet = @host@  @ZEROCONF_AVAHI_TRUE@	linux/avahi-common/timeval.h \  @ZEROCONF_AVAHI_TRUE@	linux/avahi-common/watch.h -@ZEROCONF_BONJOUR_TRUE@am__append_6 = zeroconf.c \ +@ZEROCONF_BONJOUR_TRUE@am__append_8 = zeroconf.c \  @ZEROCONF_BONJOUR_TRUE@	include/dns_sd.h -@ZEROCONF_LOOKUP_TRUE@am__append_7 = zeroconf_lookup.c -@ZEROCONF_LOOKUP_TRUE@am__append_8 = -DZEROCONF_LOOKUP -@LABVIEW_TRUE@am__append_9 = labview/phidget_labview.c \ +@ZEROCONF_LOOKUP_TRUE@am__append_9 = zeroconf_lookup.c +@ZEROCONF_LOOKUP_TRUE@am__append_10 = -DZEROCONF_LOOKUP +@LABVIEW_TRUE@am__append_11 = labview/phidget_labview.c \  @LABVIEW_TRUE@	labview/phidget_labview.h -@LABVIEW_TRUE@am__append_10 = -DCOMPILE_PHIDGETS_LABVIEW \ +@LABVIEW_TRUE@am__append_12 = -DCOMPILE_PHIDGETS_LABVIEW \  @LABVIEW_TRUE@	-I$(LABVIEW_CINTOOLS_PATH) \  @LABVIEW_TRUE@	-L$(LABVIEW_CINTOOLS_PATH) \  @LABVIEW_TRUE@	-Wl,-rpath,$(LABVIEW_CINTOOLS_PATH) -llv -@DEBUG_TRUE@am__append_11 = -D_DEBUG -DDEBUG -@JNI_TRUE@am__append_12 = -I$(top_srcdir)/include/jni -I$(top_srcdir)/include/jni/linux -@JNI_TRUE@am__append_13 = Java/com_phidgets_Phidget.c \ +@DEBUG_TRUE@am__append_13 = -D_DEBUG -DDEBUG +@JNI_TRUE@am__append_14 = -I$(top_srcdir)/include/jni -I$(top_srcdir)/include/jni/linux +@JNI_TRUE@am__append_15 = Java/com_phidgets_Phidget.c \  @JNI_TRUE@	Java/com_phidgets_Phidget.h \  @JNI_TRUE@	Java/com_phidgets_AccelerometerPhidget.c \  @JNI_TRUE@	Java/com_phidgets_AccelerometerPhidget.h \ @@ -133,8 +136,9 @@ host_triplet = @host@  subdir = .  DIST_COMMON = README $(am__configure_deps) $(include_HEADERS) \  	$(srcdir)/Makefile.am $(srcdir)/Makefile.in \ -	$(top_srcdir)/configure AUTHORS COPYING ChangeLog INSTALL NEWS \ -	config.guess config.sub depcomp install-sh ltmain.sh missing +	$(srcdir)/libphidget21.pc.in $(top_srcdir)/configure AUTHORS \ +	COPYING ChangeLog INSTALL NEWS config.guess config.sub depcomp \ +	install-sh ltmain.sh missing  ACLOCAL_M4 = $(top_srcdir)/aclocal.m4  am__aclocal_m4_deps = $(top_srcdir)/configure.ac  am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ @@ -142,7 +146,7 @@ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \  am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \   configure.lineno config.status.lineno  mkinstalldirs = $(install_sh) -d -CONFIG_CLEAN_FILES = +CONFIG_CLEAN_FILES = libphidget21.pc  CONFIG_CLEAN_VPATH_FILES =  am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;  am__vpath_adj = case $$p in \ @@ -165,7 +169,8 @@ am__nobase_list = $(am__nobase_strip_setup); \  am__base_list = \    sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \    sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' -am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)" +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgconfigdir)" \ +	"$(DESTDIR)$(includedir)"  LTLIBRARIES = $(lib_LTLIBRARIES)  libphidget21_la_LIBADD =  am__libphidget21_la_SOURCES_DIST = cphidget.c cphidget.h \ @@ -191,12 +196,12 @@ am__libphidget21_la_SOURCES_DIST = cphidget.c cphidget.h \  	cphidgetsbc.c cphidgetsbc.h clog.c clog.h csocketevents.c \  	csocketevents.h csocketopen.c csocket.h cphidgetconstants.c \  	cphidgetconstants.h cphidgetlist.c cphidgetlist.h cthread.c \ -	cthread.h phidget21.c phidget21int.h linux/cusblinux.c \ -	dict/pdict.c dict/pdict.h dict/pdictclient.c \ -	dict/pdictclient.h dict/pdict-impl.h utils/md5.c utils/md5.h \ -	utils/utils.c utils/utils.h utils/ptree.c utils/ptree.h \ -	utils/plist.c utils/plist.h cppheader cppfooter zeroconf.h \ -	utils/cvtutf.c utils/cvtutf.h linux/zeroconf_avahi.c \ +	cthread.h phidget21.c phidget21int.h dict/pdict.c dict/pdict.h \ +	dict/pdictclient.c dict/pdictclient.h dict/pdict-impl.h \ +	utils/md5.c utils/md5.h utils/utils.c utils/utils.h \ +	utils/ptree.c utils/ptree.h utils/plist.c utils/plist.h \ +	cppheader cppfooter zeroconf.h utils/cvtutf.c utils/cvtutf.h \ +	linux/cusblinux-1.0.c linux/cusblinux.c linux/zeroconf_avahi.c \  	linux/avahi-client/client.h linux/avahi-client/lookup.h \  	linux/avahi-client/publish.h linux/avahi-common/address.h \  	linux/avahi-common/alternative.h linux/avahi-common/cdecl.h \ @@ -255,11 +260,13 @@ am__libphidget21_la_SOURCES_DIST = cphidget.c cphidget.h \  	include/jni/linux/jawt_md.h include/jni/linux/jni_md.h  am__objects_1 =  @INTERNAL_UNICONV_TRUE@am__objects_2 = cvtutf.lo -@ZEROCONF_AVAHI_TRUE@am__objects_3 = zeroconf_avahi.lo -@ZEROCONF_BONJOUR_TRUE@am__objects_4 = zeroconf.lo -@ZEROCONF_LOOKUP_TRUE@am__objects_5 = zeroconf_lookup.lo -@LABVIEW_TRUE@am__objects_6 = phidget_labview.lo -@JNI_TRUE@am__objects_7 = com_phidgets_Phidget.lo \ +@NEW_LIBUSB_TRUE@am__objects_3 = cusblinux-1.0.lo +@NEW_LIBUSB_FALSE@am__objects_4 = cusblinux.lo +@ZEROCONF_AVAHI_TRUE@am__objects_5 = zeroconf_avahi.lo +@ZEROCONF_BONJOUR_TRUE@am__objects_6 = zeroconf.lo +@ZEROCONF_LOOKUP_TRUE@am__objects_7 = zeroconf_lookup.lo +@LABVIEW_TRUE@am__objects_8 = phidget_labview.lo +@JNI_TRUE@am__objects_9 = com_phidgets_Phidget.lo \  @JNI_TRUE@	com_phidgets_AccelerometerPhidget.lo \  @JNI_TRUE@	com_phidgets_AdvancedServoPhidget.lo \  @JNI_TRUE@	com_phidgets_AnalogPhidget.lo \ @@ -291,11 +298,11 @@ am_libphidget21_la_OBJECTS = cphidget.lo cphidgetaccelerometer.lo \  	cphidgettextled.lo cphidgetweightsensor.lo cphidgetmanager.lo \  	cphidgetdictionary.lo cphidgetgeneric.lo cphidgetsbc.lo \  	clog.lo csocketevents.lo csocketopen.lo cphidgetconstants.lo \ -	cphidgetlist.lo cthread.lo phidget21.lo cusblinux.lo pdict.lo \ +	cphidgetlist.lo cthread.lo phidget21.lo pdict.lo \  	pdictclient.lo md5.lo utils.lo ptree.lo plist.lo \  	$(am__objects_1) $(am__objects_2) $(am__objects_3) \  	$(am__objects_4) $(am__objects_5) $(am__objects_6) \ -	$(am__objects_7) +	$(am__objects_7) $(am__objects_8) $(am__objects_9)  libphidget21_la_OBJECTS = $(am_libphidget21_la_OBJECTS)  AM_V_lt = $(am__v_lt_$(V))  am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) @@ -332,6 +339,7 @@ am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))  am__v_GEN_0 = @echo "  GEN   " $@;  SOURCES = $(libphidget21_la_SOURCES)  DIST_SOURCES = $(am__libphidget21_la_SOURCES_DIST) +DATA = $(pkgconfig_DATA)  HEADERS = $(include_HEADERS)  ETAGS = etags  CTAGS = ctags @@ -461,8 +469,10 @@ top_builddir = @top_builddir@  top_srcdir = @top_srcdir@  AM_CFLAGS = -I$(top_srcdir) -I$(top_srcdir)/utils -I$(top_srcdir)/dict \  	-I$(top_srcdir)/linux -I$(top_srcdir)/include -D_LINUX \ -	$(am__append_2) $(am__append_4) $(am__append_8) \ -	$(am__append_10) $(am__append_11) $(am__append_12) +	$(am__append_2) $(am__append_4) $(am__append_10) \ +	$(am__append_12) $(am__append_13) $(am__append_14) +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libphidget21.pc  lib_LTLIBRARIES = libphidget21.la  # Rules for unpdating the libtool version: @@ -498,14 +508,14 @@ libphidget21_la_SOURCES = cphidget.c cphidget.h cphidgetmacros.h \  	cphidgetsbc.c cphidgetsbc.h clog.c clog.h csocketevents.c \  	csocketevents.h csocketopen.c csocket.h cphidgetconstants.c \  	cphidgetconstants.h cphidgetlist.c cphidgetlist.h cthread.c \ -	cthread.h phidget21.c phidget21int.h linux/cusblinux.c \ -	dict/pdict.c dict/pdict.h dict/pdictclient.c \ -	dict/pdictclient.h dict/pdict-impl.h utils/md5.c utils/md5.h \ -	utils/utils.c utils/utils.h utils/ptree.c utils/ptree.h \ -	utils/plist.c utils/plist.h cppheader cppfooter \ -	$(am__append_1) $(am__append_3) $(am__append_5) \ -	$(am__append_6) $(am__append_7) $(am__append_9) \ -	$(am__append_13) +	cthread.h phidget21.c phidget21int.h dict/pdict.c dict/pdict.h \ +	dict/pdictclient.c dict/pdictclient.h dict/pdict-impl.h \ +	utils/md5.c utils/md5.h utils/utils.c utils/utils.h \ +	utils/ptree.c utils/ptree.h utils/plist.c utils/plist.h \ +	cppheader cppfooter $(am__append_1) $(am__append_3) \ +	$(am__append_5) $(am__append_6) $(am__append_7) \ +	$(am__append_8) $(am__append_9) $(am__append_11) \ +	$(am__append_15)  include_HEADERS = phidget21.h  CLEANFILES = phidget21.h phidget21matlab.h phidget21.jar Java/com/phidgets/*.class Java/com/phidgets/event/*.class  EXTRA_DIST = examples/ifkit.c \ @@ -518,6 +528,7 @@ EXTRA_DIST = examples/ifkit.c \  	hotplug/phidgets.usermap \  	hotplug/phidgets \  	version.sh \ +	libphidget21.pc.in \  	Java/com/phidgets/DictionaryKeyListener.java \  	Java/com/phidgets/TextLCDPhidget.java \  	Java/com/phidgets/SpatialEventData.java \ @@ -657,6 +668,8 @@ $(top_srcdir)/configure:  $(am__configure_deps)  $(ACLOCAL_M4):  $(am__aclocal_m4_deps)  	$(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)  $(am__aclocal_m4_deps): +libphidget21.pc: $(top_builddir)/config.status $(srcdir)/libphidget21.pc.in +	cd $(top_builddir) && $(SHELL) ./config.status $@  install-libLTLIBRARIES: $(lib_LTLIBRARIES)  	@$(NORMAL_INSTALL)  	test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @@ -752,6 +765,7 @@ distclean-compile:  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/csocketevents.Plo@am__quote@  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/csocketopen.Plo@am__quote@  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cthread.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cusblinux-1.0.Plo@am__quote@  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cusblinux.Plo@am__quote@  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cvtutf.Plo@am__quote@  @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md5.Plo@am__quote@ @@ -791,14 +805,6 @@ distclean-compile:  @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@  @am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $< -cusblinux.lo: linux/cusblinux.c -@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cusblinux.lo -MD -MP -MF $(DEPDIR)/cusblinux.Tpo -c -o cusblinux.lo `test -f 'linux/cusblinux.c' || echo '$(srcdir)/'`linux/cusblinux.c -@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cusblinux.Tpo $(DEPDIR)/cusblinux.Plo -@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='linux/cusblinux.c' object='cusblinux.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@	$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cusblinux.lo `test -f 'linux/cusblinux.c' || echo '$(srcdir)/'`linux/cusblinux.c -  pdict.lo: dict/pdict.c  @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT pdict.lo -MD -MP -MF $(DEPDIR)/pdict.Tpo -c -o pdict.lo `test -f 'dict/pdict.c' || echo '$(srcdir)/'`dict/pdict.c  @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/pdict.Tpo $(DEPDIR)/pdict.Plo @@ -855,6 +861,22 @@ cvtutf.lo: utils/cvtutf.c  @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@  @am__fastdepCC_FALSE@	$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cvtutf.lo `test -f 'utils/cvtutf.c' || echo '$(srcdir)/'`utils/cvtutf.c +cusblinux-1.0.lo: linux/cusblinux-1.0.c +@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cusblinux-1.0.lo -MD -MP -MF $(DEPDIR)/cusblinux-1.0.Tpo -c -o cusblinux-1.0.lo `test -f 'linux/cusblinux-1.0.c' || echo '$(srcdir)/'`linux/cusblinux-1.0.c +@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cusblinux-1.0.Tpo $(DEPDIR)/cusblinux-1.0.Plo +@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='linux/cusblinux-1.0.c' object='cusblinux-1.0.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@	$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cusblinux-1.0.lo `test -f 'linux/cusblinux-1.0.c' || echo '$(srcdir)/'`linux/cusblinux-1.0.c + +cusblinux.lo: linux/cusblinux.c +@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cusblinux.lo -MD -MP -MF $(DEPDIR)/cusblinux.Tpo -c -o cusblinux.lo `test -f 'linux/cusblinux.c' || echo '$(srcdir)/'`linux/cusblinux.c +@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cusblinux.Tpo $(DEPDIR)/cusblinux.Plo +@am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='linux/cusblinux.c' object='cusblinux.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@	$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cusblinux.lo `test -f 'linux/cusblinux.c' || echo '$(srcdir)/'`linux/cusblinux.c +  zeroconf_avahi.lo: linux/zeroconf_avahi.c  @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zeroconf_avahi.lo -MD -MP -MF $(DEPDIR)/zeroconf_avahi.Tpo -c -o zeroconf_avahi.lo `test -f 'linux/zeroconf_avahi.c' || echo '$(srcdir)/'`linux/zeroconf_avahi.c  @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/zeroconf_avahi.Tpo $(DEPDIR)/zeroconf_avahi.Plo @@ -1079,6 +1101,26 @@ clean-libtool:  distclean-libtool:  	-rm -f libtool config.lt +install-pkgconfigDATA: $(pkgconfig_DATA) +	@$(NORMAL_INSTALL) +	test -z "$(pkgconfigdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" +	@list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ +	for p in $$list; do \ +	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ +	  echo "$$d$$p"; \ +	done | $(am__base_list) | \ +	while read files; do \ +	  echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \ +	  $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \ +	done + +uninstall-pkgconfigDATA: +	@$(NORMAL_UNINSTALL) +	@list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ +	files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ +	test -n "$$files" || exit 0; \ +	echo " ( cd '$(DESTDIR)$(pkgconfigdir)' && rm -f" $$files ")"; \ +	cd "$(DESTDIR)$(pkgconfigdir)" && rm -f $$files  install-includeHEADERS: $(include_HEADERS)  	@$(NORMAL_INSTALL)  	test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)" @@ -1300,9 +1342,9 @@ distcleancheck: distclean  	       exit 1; } >&2  check-am: all-am  check: check-am -all-am: Makefile $(LTLIBRARIES) $(HEADERS) +all-am: Makefile $(LTLIBRARIES) $(DATA) $(HEADERS)  installdirs: -	for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"; do \ +	for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(includedir)"; do \  	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \  	done  install: install-am @@ -1356,7 +1398,7 @@ info: info-am  info-am: -install-data-am: install-includeHEADERS +install-data-am: install-includeHEADERS install-pkgconfigDATA  	@$(NORMAL_INSTALL)  	$(MAKE) $(AM_MAKEFLAGS) install-data-hook  install-dvi: install-dvi-am @@ -1406,7 +1448,8 @@ ps: ps-am  ps-am: -uninstall-am: uninstall-includeHEADERS uninstall-libLTLIBRARIES +uninstall-am: uninstall-includeHEADERS uninstall-libLTLIBRARIES \ +	uninstall-pkgconfigDATA  .MAKE: install-am install-data-am install-exec-am install-strip @@ -1421,12 +1464,13 @@ uninstall-am: uninstall-includeHEADERS uninstall-libLTLIBRARIES  	install-dvi-am install-exec install-exec-am install-exec-hook \  	install-html install-html-am install-includeHEADERS \  	install-info install-info-am install-libLTLIBRARIES \ -	install-man install-pdf install-pdf-am install-ps \ -	install-ps-am install-strip installcheck installcheck-am \ -	installdirs maintainer-clean maintainer-clean-generic \ -	mostlyclean mostlyclean-compile mostlyclean-generic \ -	mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ -	uninstall-am uninstall-includeHEADERS uninstall-libLTLIBRARIES +	install-man install-pdf install-pdf-am install-pkgconfigDATA \ +	install-ps install-ps-am install-strip installcheck \ +	installcheck-am installdirs maintainer-clean \ +	maintainer-clean-generic mostlyclean mostlyclean-compile \ +	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ +	tags uninstall uninstall-am uninstall-includeHEADERS \ +	uninstall-libLTLIBRARIES uninstall-pkgconfigDATA  distclean-local: @@ -1450,11 +1494,13 @@ phidget21matlab.h:  	@echo "Making $@"  	@echo "/*" > $@  	@echo " * Phidget21 Header for Matlab" >> $@ -	@echo " * -All pointers to structs have been changed to long, as Matlab seems" >> $@ +	@echo " * -All pointers to structs have been changed to void *, as Matlab seems" >> $@  	@echo " *  to be unhappy with either the undefined stucts or the double pointers." >> $@  	@echo " */" >> $@ -	@$(CC) -g -E -P -D_LINUX -DEXTERNALPROTO -DREMOVE_DEPRECATED phidget21int.h | sed -e "s/extern \"C\" //g" | sed -e "s/struct [a-zA-Z_]* \*/long /" >> $@ +	@cat cppheader >> $@ +	@$(CC) -g -E -P -D_LINUX -DEXTERNALPROTO -DREMOVE_DEPRECATED phidget21int.h | sed -e "s/extern \"C\" //g" | sed -e "s/struct [a-zA-Z_]* \*/void * /" >> $@  	@cat cphidgetconstants.h >> $@ +	@cat cppfooter >> $@  phidget21.jar:  	@echo "Making $@" @@ -1,5 +1,5 @@                            Phidgets for Linux -                    Version 2.1.8, 22 February 2011 +                      Version 2.1.8, 3 May 2012  Installation  ============ @@ -17,10 +17,13 @@ zeroconf if it is available.  Requirements  ============ -libusb 0.1 +libusb 1.0     This is generally already installed. The libusb dev files may need to -be installed - this is usually a package called libusb-dev. +be installed - this is usually a package called libusb-1.0-0-dev. If +libusb-1.0 is not available, libusb-0.1 will be used as a fallback, +however, libusb-0.1 is not recommended because of a memory leak which +will never be fixed.     Some embedded systems / older distros may need to manually set up  the userspace USB device tree. Usually this is handled by udev and  @@ -54,6 +57,10 @@ Options       make LABVIEW_CINTOOLS_PATH=/usr/local/natinst/LabVIEW-2010/cintools     Note: replace 'LabVIEW-2010' with your version +    +   To use old libusb-0.1 +    +     ./configure --enable-oldlibusb  Usage  ===== @@ -1,6 +1,6 @@  #! /bin/sh  # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.64 for Phidget21 C Library 2.1.8.20120216. +# Generated by GNU Autoconf 2.64 for Phidget21 C Library 2.1.8.20120507.  #  # Report bugs to <support@phidgets.com>.  # @@ -698,8 +698,8 @@ MAKEFLAGS=  # Identity of this package.  PACKAGE_NAME='Phidget21 C Library'  PACKAGE_TARNAME='libphidget' -PACKAGE_VERSION='2.1.8.20120216' -PACKAGE_STRING='Phidget21 C Library 2.1.8.20120216' +PACKAGE_VERSION='2.1.8.20120507' +PACKAGE_STRING='Phidget21 C Library 2.1.8.20120507'  PACKAGE_BUGREPORT='support@phidgets.com'  PACKAGE_URL='www.phidgets.com' @@ -749,6 +749,8 @@ INTERNAL_UNICONV_FALSE  INTERNAL_UNICONV_TRUE  RUN_LDCONFIG_FALSE  RUN_LDCONFIG_TRUE +NEW_LIBUSB_FALSE +NEW_LIBUSB_TRUE  LABVIEW_FALSE  LABVIEW_TRUE  ZEROCONF_LOOKUP_FALSE @@ -887,6 +889,7 @@ enable_debug  enable_zeroconf  enable_zeroconf_lookup  enable_labview +enable_oldlibusb  enable_ldconfig  '        ac_precious_vars='build_alias @@ -1440,7 +1443,7 @@ if test "$ac_init_help" = "long"; then    # Omit some internal or obsolete options to make the list less imposing.    # This message is too long to be a string in the A/UX 3.1 sh.    cat <<_ACEOF -\`configure' configures Phidget21 C Library 2.1.8.20120216 to adapt to many kinds of systems. +\`configure' configures Phidget21 C Library 2.1.8.20120507 to adapt to many kinds of systems.  Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1510,7 +1513,7 @@ fi  if test -n "$ac_init_help"; then    case $ac_init_help in -     short | recursive ) echo "Configuration of Phidget21 C Library 2.1.8.20120216:";; +     short | recursive ) echo "Configuration of Phidget21 C Library 2.1.8.20120507:";;     esac    cat <<\_ACEOF @@ -1532,6 +1535,7 @@ Optional Features:    --enable-zeroconf    Turn on zeroconf, choose avahi or bonjour    --enable-zeroconf-lookup    Turn on zeroconf lookup    --enable-labview    Turn on Labview support +  --enable-oldlibusb    Use libusb-0.1 instead of 1.0    --disable-ldconfig      do not update dynamic linker cache using ldconfig  Optional Packages: @@ -1619,7 +1623,7 @@ fi  test -n "$ac_init_help" && exit $ac_status  if $ac_init_version; then    cat <<\_ACEOF -Phidget21 C Library configure 2.1.8.20120216 +Phidget21 C Library configure 2.1.8.20120507  generated by GNU Autoconf 2.64  Copyright (C) 2009 Free Software Foundation, Inc. @@ -1897,7 +1901,7 @@ cat >config.log <<_ACEOF  This file contains any messages produced by compilers while  running configure, to aid debugging if configure makes a mistake. -It was created by Phidget21 C Library $as_me 2.1.8.20120216, which was +It was created by Phidget21 C Library $as_me 2.1.8.20120507, which was  generated by GNU Autoconf 2.64.  Invocation command line was    $ $0 $@ @@ -2705,7 +2709,7 @@ fi  # Define the identity of the package.   PACKAGE='libphidget' - VERSION='2.1.8.20120216' + VERSION='2.1.8.20120507'  cat >>confdefs.h <<_ACEOF @@ -4382,13 +4386,13 @@ if test "${lt_cv_nm_interface+set}" = set; then :  else    lt_cv_nm_interface="BSD nm"    echo "int some_variable = 0;" > conftest.$ac_ext -  (eval echo "\"\$as_me:4385: $ac_compile\"" >&5) +  (eval echo "\"\$as_me:4389: $ac_compile\"" >&5)    (eval "$ac_compile" 2>conftest.err)    cat conftest.err >&5 -  (eval echo "\"\$as_me:4388: $NM \\\"conftest.$ac_objext\\\"\"" >&5) +  (eval echo "\"\$as_me:4392: $NM \\\"conftest.$ac_objext\\\"\"" >&5)    (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)    cat conftest.err >&5 -  (eval echo "\"\$as_me:4391: output\"" >&5) +  (eval echo "\"\$as_me:4395: output\"" >&5)    cat conftest.out >&5    if $GREP 'External.*some_variable' conftest.out > /dev/null; then      lt_cv_nm_interface="MS dumpbin" @@ -5594,7 +5598,7 @@ ia64-*-hpux*)    ;;  *-*-irix6*)    # Find out which ABI we are using. -  echo '#line 5597 "configure"' > conftest.$ac_ext +  echo '#line 5601 "configure"' > conftest.$ac_ext    if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5    (eval $ac_compile) 2>&5    ac_status=$? @@ -7120,11 +7124,11 @@ else     -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \     -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \     -e 's:$: $lt_compiler_flag:'` -   (eval echo "\"\$as_me:7123: $lt_compile\"" >&5) +   (eval echo "\"\$as_me:7127: $lt_compile\"" >&5)     (eval "$lt_compile" 2>conftest.err)     ac_status=$?     cat conftest.err >&5 -   echo "$as_me:7127: \$? = $ac_status" >&5 +   echo "$as_me:7131: \$? = $ac_status" >&5     if (exit $ac_status) && test -s "$ac_outfile"; then       # The compiler can only warn and ignore the option if not recognized       # So say no if there are warnings other than the usual output. @@ -7459,11 +7463,11 @@ else     -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \     -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \     -e 's:$: $lt_compiler_flag:'` -   (eval echo "\"\$as_me:7462: $lt_compile\"" >&5) +   (eval echo "\"\$as_me:7466: $lt_compile\"" >&5)     (eval "$lt_compile" 2>conftest.err)     ac_status=$?     cat conftest.err >&5 -   echo "$as_me:7466: \$? = $ac_status" >&5 +   echo "$as_me:7470: \$? = $ac_status" >&5     if (exit $ac_status) && test -s "$ac_outfile"; then       # The compiler can only warn and ignore the option if not recognized       # So say no if there are warnings other than the usual output. @@ -7564,11 +7568,11 @@ else     -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \     -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \     -e 's:$: $lt_compiler_flag:'` -   (eval echo "\"\$as_me:7567: $lt_compile\"" >&5) +   (eval echo "\"\$as_me:7571: $lt_compile\"" >&5)     (eval "$lt_compile" 2>out/conftest.err)     ac_status=$?     cat out/conftest.err >&5 -   echo "$as_me:7571: \$? = $ac_status" >&5 +   echo "$as_me:7575: \$? = $ac_status" >&5     if (exit $ac_status) && test -s out/conftest2.$ac_objext     then       # The compiler can only warn and ignore the option if not recognized @@ -7619,11 +7623,11 @@ else     -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \     -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \     -e 's:$: $lt_compiler_flag:'` -   (eval echo "\"\$as_me:7622: $lt_compile\"" >&5) +   (eval echo "\"\$as_me:7626: $lt_compile\"" >&5)     (eval "$lt_compile" 2>out/conftest.err)     ac_status=$?     cat out/conftest.err >&5 -   echo "$as_me:7626: \$? = $ac_status" >&5 +   echo "$as_me:7630: \$? = $ac_status" >&5     if (exit $ac_status) && test -s out/conftest2.$ac_objext     then       # The compiler can only warn and ignore the option if not recognized @@ -10002,7 +10006,7 @@ else    lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2    lt_status=$lt_dlunknown    cat > conftest.$ac_ext <<_LT_EOF -#line 10005 "configure" +#line 10009 "configure"  #include "confdefs.h"  #if HAVE_DLFCN_H @@ -10098,7 +10102,7 @@ else    lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2    lt_status=$lt_dlunknown    cat > conftest.$ac_ext <<_LT_EOF -#line 10101 "configure" +#line 10105 "configure"  #include "confdefs.h"  #if HAVE_DLFCN_H @@ -11230,63 +11234,6 @@ else    as_fn_error "Missing libpthread!" "$LINENO" 5  fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing usb_find_busses" >&5 -$as_echo_n "checking for library containing usb_find_busses... " >&6; } -if test "${ac_cv_search_usb_find_busses+set}" = set; then : -  $as_echo_n "(cached) " >&6 -else -  ac_func_search_save_LIBS=$LIBS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h.  */ - -/* Override any GCC internal prototype to avoid an error. -   Use char because int might match the return type of a GCC -   builtin and then its argument prototype would still apply.  */ -#ifdef __cplusplus -extern "C" -#endif -char usb_find_busses (); -int -main () -{ -return usb_find_busses (); -  ; -  return 0; -} -_ACEOF -for ac_lib in '' usb; do -  if test -z "$ac_lib"; then -    ac_res="none required" -  else -    ac_res=-l$ac_lib -    LIBS="-l$ac_lib  $ac_func_search_save_LIBS" -  fi -  if ac_fn_c_try_link "$LINENO"; then : -  ac_cv_search_usb_find_busses=$ac_res -fi -rm -f core conftest.err conftest.$ac_objext \ -    conftest$ac_exeext -  if test "${ac_cv_search_usb_find_busses+set}" = set; then : -  break -fi -done -if test "${ac_cv_search_usb_find_busses+set}" = set; then : - -else -  ac_cv_search_usb_find_busses=no -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_usb_find_busses" >&5 -$as_echo "$ac_cv_search_usb_find_busses" >&6; } -ac_res=$ac_cv_search_usb_find_busses -if test "$ac_res" != no; then : -  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - -else -  as_fn_error "Missing libusb!" "$LINENO" 5 -fi  # we need iconv - if it's not available in libc, look for the 'libiconv' function from libiconv.so  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing iconv" >&5 @@ -11523,6 +11470,204 @@ else  fi +# Check whether --enable-oldlibusb was given. +if test "${enable_oldlibusb+set}" = set; then : +  enableval=$enable_oldlibusb; case "${enableval}" in +	yes) newlibusb=false ;; +	no)  newlibusb=true ;; +	*) as_fn_error "bad value ${enableval} for --enable-oldlibusb" "$LINENO" 5 ;; +esac +else +  newlibusb=true +fi + + +if test "$newlibusb" = "true"; then +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing libusb_init" >&5 +$as_echo_n "checking for library containing libusb_init... " >&6; } +if test "${ac_cv_search_libusb_init+set}" = set; then : +  $as_echo_n "(cached) " >&6 +else +  ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h.  */ + +/* Override any GCC internal prototype to avoid an error. +   Use char because int might match the return type of a GCC +   builtin and then its argument prototype would still apply.  */ +#ifdef __cplusplus +extern "C" +#endif +char libusb_init (); +int +main () +{ +return libusb_init (); +  ; +  return 0; +} +_ACEOF +for ac_lib in '' usb-1.0; do +  if test -z "$ac_lib"; then +    ac_res="none required" +  else +    ac_res=-l$ac_lib +    LIBS="-l$ac_lib  $ac_func_search_save_LIBS" +  fi +  if ac_fn_c_try_link "$LINENO"; then : +  ac_cv_search_libusb_init=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ +    conftest$ac_exeext +  if test "${ac_cv_search_libusb_init+set}" = set; then : +  break +fi +done +if test "${ac_cv_search_libusb_init+set}" = set; then : + +else +  ac_cv_search_libusb_init=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_libusb_init" >&5 +$as_echo "$ac_cv_search_libusb_init" >&6; } +ac_res=$ac_cv_search_libusb_init +if test "$ac_res" != no; then : +  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" +  newlibusb=true +else +  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing usb_find_busses" >&5 +$as_echo_n "checking for library containing usb_find_busses... " >&6; } +if test "${ac_cv_search_usb_find_busses+set}" = set; then : +  $as_echo_n "(cached) " >&6 +else +  ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h.  */ + +/* Override any GCC internal prototype to avoid an error. +   Use char because int might match the return type of a GCC +   builtin and then its argument prototype would still apply.  */ +#ifdef __cplusplus +extern "C" +#endif +char usb_find_busses (); +int +main () +{ +return usb_find_busses (); +  ; +  return 0; +} +_ACEOF +for ac_lib in '' usb; do +  if test -z "$ac_lib"; then +    ac_res="none required" +  else +    ac_res=-l$ac_lib +    LIBS="-l$ac_lib  $ac_func_search_save_LIBS" +  fi +  if ac_fn_c_try_link "$LINENO"; then : +  ac_cv_search_usb_find_busses=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ +    conftest$ac_exeext +  if test "${ac_cv_search_usb_find_busses+set}" = set; then : +  break +fi +done +if test "${ac_cv_search_usb_find_busses+set}" = set; then : + +else +  ac_cv_search_usb_find_busses=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_usb_find_busses" >&5 +$as_echo "$ac_cv_search_usb_find_busses" >&6; } +ac_res=$ac_cv_search_usb_find_busses +if test "$ac_res" != no; then : +  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" +  newlibusb=false +else +  as_fn_error "Missing libusb!" "$LINENO" 5 +fi + +fi + +else +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing usb_find_busses" >&5 +$as_echo_n "checking for library containing usb_find_busses... " >&6; } +if test "${ac_cv_search_usb_find_busses+set}" = set; then : +  $as_echo_n "(cached) " >&6 +else +  ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h.  */ + +/* Override any GCC internal prototype to avoid an error. +   Use char because int might match the return type of a GCC +   builtin and then its argument prototype would still apply.  */ +#ifdef __cplusplus +extern "C" +#endif +char usb_find_busses (); +int +main () +{ +return usb_find_busses (); +  ; +  return 0; +} +_ACEOF +for ac_lib in '' usb; do +  if test -z "$ac_lib"; then +    ac_res="none required" +  else +    ac_res=-l$ac_lib +    LIBS="-l$ac_lib  $ac_func_search_save_LIBS" +  fi +  if ac_fn_c_try_link "$LINENO"; then : +  ac_cv_search_usb_find_busses=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ +    conftest$ac_exeext +  if test "${ac_cv_search_usb_find_busses+set}" = set; then : +  break +fi +done +if test "${ac_cv_search_usb_find_busses+set}" = set; then : + +else +  ac_cv_search_usb_find_busses=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_usb_find_busses" >&5 +$as_echo "$ac_cv_search_usb_find_busses" >&6; } +ac_res=$ac_cv_search_usb_find_busses +if test "$ac_res" != no; then : +  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" +  newlibusb=false +else +  as_fn_error "Missing libusb!" "$LINENO" 5 +fi + +fi + + if test x$newlibusb = xtrue; then +  NEW_LIBUSB_TRUE= +  NEW_LIBUSB_FALSE='#' +else +  NEW_LIBUSB_TRUE='#' +  NEW_LIBUSB_FALSE= +fi + +  # Check whether --enable-ldconfig was given.  if test "${enable_ldconfig+set}" = set; then :    enableval=$enable_ldconfig; @@ -11548,8 +11693,11 @@ else  fi +  ac_config_files="$ac_config_files Makefile examples/Makefile" +ac_config_files="$ac_config_files libphidget21.pc" +  cat >confcache <<\_ACEOF  # This file is a shell script that caches the results of configure  # tests run on this system so they can be shared between configure @@ -11731,6 +11879,10 @@ if test -z "${LABVIEW_TRUE}" && test -z "${LABVIEW_FALSE}"; then    as_fn_error "conditional \"LABVIEW\" was never defined.  Usually this means the macro was only invoked conditionally." "$LINENO" 5  fi +if test -z "${NEW_LIBUSB_TRUE}" && test -z "${NEW_LIBUSB_FALSE}"; then +  as_fn_error "conditional \"NEW_LIBUSB\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi  if test -z "${RUN_LDCONFIG_TRUE}" && test -z "${RUN_LDCONFIG_FALSE}"; then    as_fn_error "conditional \"RUN_LDCONFIG\" was never defined.  Usually this means the macro was only invoked conditionally." "$LINENO" 5 @@ -12147,7 +12299,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1  # report actual input values of CONFIG_FILES etc. instead of their  # values after options handling.  ac_log=" -This file was extended by Phidget21 C Library $as_me 2.1.8.20120216, which was +This file was extended by Phidget21 C Library $as_me 2.1.8.20120507, which was  generated by GNU Autoconf 2.64.  Invocation command line was    CONFIG_FILES    = $CONFIG_FILES @@ -12203,7 +12355,7 @@ Phidget21 C Library home page: <www.phidgets.com>."  _ACEOF  cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1  ac_cs_version="\\ -Phidget21 C Library config.status 2.1.8.20120216 +Phidget21 C Library config.status 2.1.8.20120507  configured by $0, generated by GNU Autoconf 2.64,    with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" @@ -12572,6 +12724,7 @@ do      "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;;      "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;      "examples/Makefile") CONFIG_FILES="$CONFIG_FILES examples/Makefile" ;; +    "libphidget21.pc") CONFIG_FILES="$CONFIG_FILES libphidget21.pc" ;;    *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;;    esac diff --git a/configure.ac b/configure.ac index 559e4da..f49f25e 100644 --- a/configure.ac +++ b/configure.ac @@ -25,8 +25,7 @@ AC_SEARCH_LIBS([sqrt], [m], [],  	AC_MSG_ERROR([Missing libm!]))  AC_SEARCH_LIBS([pthread_join], [pthread], [],   	AC_MSG_ERROR([Missing libpthread!])) -AC_SEARCH_LIBS([usb_find_busses], [usb], [],  -	AC_MSG_ERROR([Missing libusb!])) +  # we need iconv - if it's not available in libc, look for the 'libiconv' function from libiconv.so  AC_SEARCH_LIBS([iconv], [iconv], [],   	AC_SEARCH_LIBS([libiconv], [iconv], [],  @@ -81,6 +80,25 @@ AC_ARG_ENABLE([labview],  esac],[labview=false])  AM_CONDITIONAL([LABVIEW], [test x$labview = xtrue]) +AC_ARG_ENABLE([oldlibusb], +[  --enable-oldlibusb    Use libusb-0.1 instead of 1.0], +[case "${enableval}" in +	yes) newlibusb=false ;; +	no)  newlibusb=true ;; +	*) AC_MSG_ERROR([bad value ${enableval} for --enable-oldlibusb]) ;; +esac],[newlibusb=true]) + +if test "$newlibusb" = "true"; then +AC_SEARCH_LIBS([libusb_init], [usb-1.0], [newlibusb=true],  +	AC_SEARCH_LIBS([usb_find_busses], [usb], [newlibusb=false],  +	AC_MSG_ERROR([Missing libusb!]))) +else +AC_SEARCH_LIBS([usb_find_busses], [usb], [newlibusb=false],  +	AC_MSG_ERROR([Missing libusb!])) +fi + +AM_CONDITIONAL([NEW_LIBUSB], [test x$newlibusb = xtrue]) +  AC_ARG_ENABLE([ldconfig],  [AS_HELP_STRING([--disable-ldconfig],[do not update dynamic linker cache using ldconfig])],  , @@ -89,6 +107,7 @@ AM_CONDITIONAL([RUN_LDCONFIG], [test "${enable_ldconfig}" = "yes"])  AM_CONDITIONAL([INTERNAL_UNICONV], [test x$internaluniconv = xtrue]) +  AC_CONFIG_FILES([Makefile                   examples/Makefile]) -AC_OUTPUT +AC_OUTPUT([libphidget21.pc]) @@ -6,6 +6,8 @@  #include "cphidgetlist.h"  #include "utils.h" +static int CPhidgetGPP_dataInput(CPhidgetHandle phid, unsigned char *buffer, int length); +  int print_debug_messages = FALSE;  CPhidgetListHandle ActiveDevices = 0; @@ -120,8 +122,8 @@ int CCONV CPhidget_areEqual(void *arg1, void *arg2)  	if(phid1->specificDevice && phid2->specificDevice)  	{  		// If one is open serial and the other is open label -		if(phid1->specificDevice == PHIDGETOPEN_SERIAL && phid2->specificDevice == PHIDGETOPEN_LABEL || -			phid1->specificDevice == PHIDGETOPEN_LABEL && phid2->specificDevice == PHIDGETOPEN_SERIAL) +		if((phid1->specificDevice == PHIDGETOPEN_SERIAL && phid2->specificDevice == PHIDGETOPEN_LABEL) || +			(phid1->specificDevice == PHIDGETOPEN_LABEL && phid2->specificDevice == PHIDGETOPEN_SERIAL))  			return PFALSE;  		// If one is open serial but they have different serials @@ -279,14 +281,14 @@ int CPhidget_read(CPhidgetHandle phid)  	TESTPTR(phid) -	if (CPhidget_statusFlagIsSet(phid->status, PHIDGET_ATTACHED_FLAG) -		|| CPhidget_statusFlagIsSet(phid->status, PHIDGET_ATTACHING_FLAG)) { -		result = CUSBReadPacket((CPhidgetHandle)phid, -		    phid->lastReadPacket); -		if (result) return result; -		if (phid->fptrData) -			result= phid->fptrData((CPhidgetHandle)phid, -			    phid->lastReadPacket, phid->inputReportByteLength); +	if (CPhidget_statusFlagIsSet(phid->status, PHIDGET_ATTACHED_FLAG) || CPhidget_statusFlagIsSet(phid->status, PHIDGET_ATTACHING_FLAG)) +	{ +		if((result = CUSBReadPacket((CPhidgetHandle)phid, phid->lastReadPacket)) != EPHIDGET_OK) +			return result; +		if((phid->lastReadPacket[0] & PHID_USB_GENERAL_PACKET_FLAG) && deviceSupportsGeneralUSBProtocol(phid)) +			result = CPhidgetGPP_dataInput(phid, phid->lastReadPacket, phid->inputReportByteLength); +		else if (phid->fptrData) +			result= phid->fptrData(phid, phid->lastReadPacket, phid->inputReportByteLength);  		return result;  	}  	return EPHIDGET_NOTATTACHED; @@ -503,6 +505,10 @@ netdone:  		if(!ActiveDevices && !ActivePhidgetManagers)  		{  			JoinCentralThread(); +			//Shut down USB +#if defined(_LINUX) && !defined(_ANDROID) +			CUSBUninit(); +#endif  		}  	}  	CPhidget_clearStatusFlag(&phid->status, PHIDGET_OPENED_FLAG, &phid->lock); @@ -572,7 +578,14 @@ CPhidget_getDeviceName(CPhidgetHandle phid, const char **buffer)  		&& !CPhidget_statusFlagIsSet(phid->status, PHIDGET_DETACHING_FLAG))  		return EPHIDGET_NOTATTACHED; -	*buffer = (char *)phid->deviceDef->pdd_name; +	if(phid->deviceIDSpec == PHIDID_FIRMWARE_UPGRADE) +	{ +		if(!phid->firmwareUpgradeName[0]) +			snprintf(phid->firmwareUpgradeName, 30, "%s %s", phid->usbProduct, phid->deviceDef->pdd_name); +		*buffer = phid->firmwareUpgradeName; +	} +	else +		*buffer = (char *)phid->deviceDef->pdd_name;  	return EPHIDGET_OK;  } @@ -719,7 +732,7 @@ CPhidget_setDeviceLabel(CPhidgetHandle phid, const char *buffer)  	else  	{ -#if defined(_WINDOWS) && !defined(WINCE) +#if 0// defined(_WINDOWS) && !defined(WINCE)  		//setLabel not supported on Windows only (Windows CE does support it)  		return EPHIDGET_UNSUPPORTED;  #else @@ -816,6 +829,9 @@ CPhidget_setDeviceLabel(CPhidgetHandle phid, const char *buffer)  			}  			else   			{ +#if defined(_WINDOWS) && !defined(WINCE) +				if(ret != EPHIDGET_UNSUPPORTED) +#endif  				LOG(PHIDGET_LOG_ERROR, "Something unexpected happened trying to set the label. Try again.");  				return ret;  			} @@ -1261,6 +1277,7 @@ int attachActiveDevice(CPhidgetHandle activeDevice, CPhidgetHandle attachedDevic  	activeDevice->CPhidgetFHandle = malloc(wcslen(attachedDevice->CPhidgetFHandle)*sizeof(WCHAR)+10);  	wcsncpy((WCHAR *)activeDevice->CPhidgetFHandle, attachedDevice->CPhidgetFHandle, wcslen(attachedDevice->CPhidgetFHandle)+1);  	activeDevice->deviceIDSpec = attachedDevice->deviceIDSpec; +	activeDevice->deviceUID = attachedDevice->deviceUID;  	activeDevice->deviceDef = attachedDevice->deviceDef;  #endif  #endif @@ -1269,6 +1286,7 @@ int attachActiveDevice(CPhidgetHandle activeDevice, CPhidgetHandle attachedDevic  	//Android also uses the file handle to open the device  	activeDevice->CPhidgetFHandle = strdup(attachedDevice->CPhidgetFHandle);  	activeDevice->deviceIDSpec = attachedDevice->deviceIDSpec; +	activeDevice->deviceUID = attachedDevice->deviceUID;  	activeDevice->deviceDef = attachedDevice->deviceDef;  #endif @@ -1287,6 +1305,7 @@ int attachActiveDevice(CPhidgetHandle activeDevice, CPhidgetHandle attachedDevic  			activeDevice->serialNumber = -1;  		}  		activeDevice->deviceIDSpec = 0; +		activeDevice->deviceUID = 0;  		return result;  	} @@ -1541,39 +1560,15 @@ int labelHasWrapError(int serialNumber, char *labelBuf)  	return PFALSE;  } -//takes the label string buffer from the USB device and outputs a UTF-8 version -int decodeLabelString(char *labelBuf, char *out, int serialNumber) +int UTF16toUTF8(char *in, int inLen, char *out)  { -	//out NEEDS to be zeroed out, or we'll end up with a UTF-8 string with no terminating NULL -	ZEROMEM(out, MAX_LABEL_STORAGE); -	 -	//this returns true only if our descriptor is > 16 bytes and has the error, so we truncate -	if (labelHasWrapError(serialNumber, labelBuf)) -	{ -		int i; -		for(i=16;i<labelBuf[0];i++) -			labelBuf[i] = 0x00; -		labelBuf[0] = 16; -		LOG(PHIDGET_LOG_WARNING, "Detected getLabel error - label is being truncated to first 7 characters. Please setLabel again to correct this."); -	} -	 -	//check if the label is stored as UTF-8 directly -	if(labelBuf[0] > 4 && labelBuf[2] == (char)0xFF && labelBuf[3] == (char)0xFF) -	{ -		LOG(PHIDGET_LOG_DEBUG, "Found a wrap-around bug style label."); -		memcpy(out, &labelBuf[4], labelBuf[0]-4); -		out[labelBuf[0]-4] = '\0'; -	} -	//otherwise it's stored as UTF-16LE -	else -	{  #ifdef USE_INTERNAL_UNICONV -		unsigned char *utf8label = (unsigned char *)out; -		unsigned char *utf8labelEnd = utf8label + MAX_LABEL_STORAGE; -		unichar *utf16label = (unichar *)&labelBuf[2]; -		unichar *utf16labelEnd = utf16label + ((labelBuf[0]-2) / 2); +		unsigned char *utf8string = (unsigned char *)out; +		unsigned char *utf8stringEnd = utf8string + MAX_LABEL_STORAGE; +		unichar *utf16string = (unichar *)in; +		unichar *utf16stringEnd = utf16string + (inLen / 2);  		ConversionResult resp; -		resp = NSConvertUTF16toUTF8(&utf16label, utf16labelEnd, &utf8label, utf8labelEnd); +		resp = NSConvertUTF16toUTF8(&utf16string, utf16stringEnd, &utf8string, utf8stringEnd);  		if(resp != ok)  		{ @@ -1591,13 +1586,11 @@ int decodeLabelString(char *labelBuf, char *out, int serialNumber)  			}  			return EPHIDGET_INVALIDARG;  		} -		  #else -	   #ifndef _WINDOWS -		char *utf16label = &labelBuf[2]; -		char *utf8label = (char *)out; -		size_t inBytes = labelBuf[0]-2; // Up to MAX_LABEL_STORAGE bytes read +		char *utf16string = in; +		char *utf8string = (char *)out; +		size_t inBytes = inLen; // Up to MAX_LABEL_STORAGE bytes read  		size_t outBytes = (MAX_LABEL_STORAGE); //UTF-16 characters are two bytes each.  		iconv_t conv;  		size_t resp; @@ -1605,7 +1598,7 @@ int decodeLabelString(char *labelBuf, char *out, int serialNumber)  		if (conv == (iconv_t)(-1))  			return EPHIDGET_UNEXPECTED; -		resp = iconv(conv, &utf16label, &inBytes, &utf8label, &outBytes); +		resp = iconv(conv, &utf16string, &inBytes, &utf8string, &outBytes);  		iconv_close(conv); @@ -1615,23 +1608,389 @@ int decodeLabelString(char *labelBuf, char *out, int serialNumber)  				case EINVAL:  				case E2BIG:  				default: -					LOG (PHIDGET_LOG_ERROR, "Unexpected error converting label to UTF-8: %s.", strerror (errno)); +					LOG (PHIDGET_LOG_ERROR, "Unexpected error converting string to UTF-8: %s.", strerror (errno));  					return EPHIDGET_UNEXPECTED;  			}  		}   #else -		//labelData in NULL terminated -		int bytesWritten = WideCharToMultiByte(CP_UTF8, 0, (wchar_t *)&labelBuf[2], -1, out, MAX_LABEL_STORAGE+1, NULL, NULL); +		//stringData in NULL terminated +		int bytesWritten = WideCharToMultiByte(CP_UTF8, 0, (wchar_t *)in, -1, out, MAX_LABEL_STORAGE+1, NULL, NULL);  		//Error  		if(!bytesWritten)  		{ -			LOG(PHIDGET_LOG_ERROR, "Unable to convert label to UTF-8!"); +			LOG(PHIDGET_LOG_ERROR, "Unable to convert string to UTF-8!");  			return EPHIDGET_UNEXPECTED;  		}   #endif  #endif +	return EPHIDGET_OK; +} + +//takes the label string buffer from the USB device and outputs a UTF-8 version +int decodeLabelString(char *labelBuf, char *out, int serialNumber) +{ +	//out NEEDS to be zeroed out, or we'll end up with a UTF-8 string with no terminating NULL +	ZEROMEM(out, MAX_LABEL_STORAGE); +	 +	//this returns true only if our descriptor is > 16 bytes and has the error, so we truncate +	if (labelHasWrapError(serialNumber, labelBuf)) +	{ +		int i; +		for(i=16;i<labelBuf[0];i++) +			labelBuf[i] = 0x00; +		labelBuf[0] = 16; +		LOG(PHIDGET_LOG_WARNING, "Detected getLabel error - label is being truncated to first 7 characters. Please setLabel again to correct this."); +	} +	 +	//check if the label is stored as UTF-8 directly +	if(labelBuf[0] > 4 && labelBuf[2] == (char)0xFF && labelBuf[3] == (char)0xFF) +	{ +		LOG(PHIDGET_LOG_DEBUG, "Found a wrap-around bug style label."); +		memcpy(out, &labelBuf[4], labelBuf[0]-4); +		out[labelBuf[0]-4] = '\0'; +	} +	//otherwise it's stored as UTF-16LE +	else +	{ +		return UTF16toUTF8(&labelBuf[2], labelBuf[0]-2, out);  	}  	return EPHIDGET_OK;  } + +CPhidget_DeviceUID CPhidget_getUID(CPhidget_DeviceID id, int version) +{ +	const CPhidgetUniqueDeviceDef *uidList = Phid_Unique_Device_Def; +	int i = 0; + +	while (uidList->pdd_uid) +	{ +		if(uidList->pdd_id == id && version >= uidList->pdd_vlow && version < uidList->pdd_vhigh)\ +			return uidList->pdd_uid; +		i++; +		uidList++; +	} + +	//Should never get here! +	LOG(PHIDGET_LOG_DEBUG, "We have a Phidgets that doesn't match and Device UID!"); +	return PHIDUID_NOTHING; +} + + + +/** + * General Packet Protocol + * + * These are devices on the new M3. They all support this protocol. + *  MSB is set is buf[0] for incoming and outgoing packets. + */ + +int deviceSupportsGeneralUSBProtocol(CPhidgetHandle phid) +{ +	switch(phid->deviceUID) +	{ +		case PHIDUID_SPATIAL_ACCEL_3AXIS_1041: +		case PHIDUID_SPATIAL_ACCEL_3AXIS_1043: +		case PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1042: +		case PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1044: +			return PTRUE; + +		case PHIDUID_FIRMWARE_UPGRADE: +			return PTRUE; + +		case PHIDUID_GENERIC: +			return PTRUE; + +		default: +			return PFALSE; +	} +} + +static int CPhidgetGPP_dataInput(CPhidgetHandle phid, unsigned char *buffer, int length) +{ +	int result = EPHIDGET_OK; + +	//if response bits are set (0x00 is ignore), then store response +	if(buffer[0] & 0x3f) +		phid->GPPResponse = buffer[0]; + +	return result; +} + +int GPP_getResponse(CPhidgetHandle phid, int packetType, int timeout) +{ +	while((phid->GPPResponse & 0x3f) != packetType && timeout > 0) +	{ +		SLEEP(20); +		timeout -= 20; +	} + +	//Didn't get the response! +	if((phid->GPPResponse & 0x3f) != packetType) +	{ +		return EPHIDGET_TIMEOUT; +	} + +	if(phid->GPPResponse & PHID_USB_GENERAL_PACKET_FAIL) +		return EPHIDGET_UNEXPECTED; + +	return EPHIDGET_OK; +} + +int CCONV CPhidgetGPP_upgradeFirmware(CPhidgetHandle phid, unsigned char *data, int length) +{ +	int result, i, j, index, indexEnd; +	unsigned char *buffer; +	TESTPTR(phid) +	if (!CPhidget_statusFlagIsSet(phid->status, PHIDGET_ATTACHED_FLAG)) +		return EPHIDGET_NOTATTACHED; + +	if(!deviceSupportsGeneralUSBProtocol(phid)) +		return EPHIDGET_UNSUPPORTED; + +	buffer = (unsigned char *) malloc(phid->outputReportByteLength); +	ZEROMEM(buffer, phid->outputReportByteLength); +	 +	CThread_mutex_lock(&phid->writelock); + +	phid->GPPResponse = 0; + +	index = ((length & 0xf000) >> 12) + 1; +	indexEnd = length & 0xfff; +	j = 0; +	while (index) +	{ +		int secLength = length - ((index - 1) * 0x1000); +		if(secLength > 0x1000) secLength = 0x1000; + +		buffer[0] = PHID_USB_GENERAL_PACKET_FLAG | PHID_USB_GENERAL_PACKET_FIRMWARE_UPGRADE_WRITE_SECTOR; +		buffer[1] = index; +		buffer[2] = secLength; +		buffer[3] = secLength >> 8; + +		for(i=4;i<phid->outputReportByteLength && j<indexEnd;i++,j++) +			buffer[i] = data[j]; + +		if((result = CUSBSendPacket((CPhidgetHandle)phid, buffer)) != EPHIDGET_OK) +			goto done; + +		while(j<indexEnd && result == EPHIDGET_OK) +		{ +			buffer[0] = PHID_USB_GENERAL_PACKET_FLAG | PHID_USB_GENERAL_PACKET_CONTINUATION; +			for(i=1;i<phid->outputReportByteLength && j<indexEnd;i++,j++) +				buffer[i] = data[j]; + +			if((result = CUSBSendPacket((CPhidgetHandle)phid, buffer)) != EPHIDGET_OK) +				goto done; +		} +		index--; +		indexEnd+=0x1000; +	} + +done: + +	result = GPP_getResponse(phid, PHID_USB_GENERAL_PACKET_FIRMWARE_UPGRADE_WRITE_SECTOR, 200); + +	CThread_mutex_unlock(&phid->writelock); + +	free(buffer); + +	return result; +} + +int CCONV CPhidgetGPP_eraseFirmware(CPhidgetHandle phid) +{ +	int result; +	unsigned char *buffer; +	TESTPTR(phid) +	if (!CPhidget_statusFlagIsSet(phid->status, PHIDGET_ATTACHED_FLAG)) +		return EPHIDGET_NOTATTACHED; + +	if(!deviceSupportsGeneralUSBProtocol(phid)) +		return EPHIDGET_UNSUPPORTED; + +	buffer = (unsigned char *) malloc(phid->outputReportByteLength); +	ZEROMEM(buffer, phid->outputReportByteLength); +	 +	buffer[0] = PHID_USB_GENERAL_PACKET_FLAG | PHID_USB_GENERAL_PACKET_FIRMWARE_UPGRADE_ERASE; +	 +	CThread_mutex_lock(&phid->writelock); + +	phid->GPPResponse = 0; +	if((result = CUSBSendPacket((CPhidgetHandle)phid, buffer)) == EPHIDGET_OK) +		result = GPP_getResponse(phid, PHID_USB_GENERAL_PACKET_FIRMWARE_UPGRADE_ERASE, 200); + +	CThread_mutex_unlock(&phid->writelock); +	free(buffer); + +	return result; +} + +int CCONV CPhidgetGPP_reboot_firmwareUpgrade(CPhidgetHandle phid) +{ +	int result; +	unsigned char *buffer; +	TESTPTR(phid) +	if (!CPhidget_statusFlagIsSet(phid->status, PHIDGET_ATTACHED_FLAG)) +		return EPHIDGET_NOTATTACHED; + +	if(!deviceSupportsGeneralUSBProtocol(phid)) +		return EPHIDGET_UNSUPPORTED; + +	buffer = (unsigned char *) malloc(phid->outputReportByteLength); +	ZEROMEM(buffer, phid->outputReportByteLength); +	 +	buffer[0] = PHID_USB_GENERAL_PACKET_FLAG | PHID_USB_GENERAL_PACKET_REBOOT_FIRMWARE_UPGRADE; +	 +	result = CUSBSendPacket((CPhidgetHandle)phid, buffer); + +	free(buffer); + +	return result; +} + +int CCONV CPhidgetGPP_reboot_ISP(CPhidgetHandle phid) +{ +	int result; +	unsigned char *buffer; +	TESTPTR(phid) +	if (!CPhidget_statusFlagIsSet(phid->status, PHIDGET_ATTACHED_FLAG)) +		return EPHIDGET_NOTATTACHED; + +	if(!deviceSupportsGeneralUSBProtocol(phid)) +		return EPHIDGET_UNSUPPORTED; + +	buffer = (unsigned char *) malloc(phid->outputReportByteLength); +	ZEROMEM(buffer, phid->outputReportByteLength); +	 +	buffer[0] = PHID_USB_GENERAL_PACKET_FLAG | PHID_USB_GENERAL_PACKET_REBOOT_ISP; +	 +	result = CUSBSendPacket((CPhidgetHandle)phid, buffer); + +	free(buffer); + +	return result; +} + +int CCONV CPhidgetGPP_writeFlash(CPhidgetHandle phid) +{ +	int result; +	unsigned char *buffer; +	TESTPTR(phid) +	if (!CPhidget_statusFlagIsSet(phid->status, PHIDGET_ATTACHED_FLAG)) +		return EPHIDGET_NOTATTACHED; + +	if(!deviceSupportsGeneralUSBProtocol(phid)) +		return EPHIDGET_UNSUPPORTED; + +	buffer = (unsigned char *) malloc(phid->outputReportByteLength); +	ZEROMEM(buffer, phid->outputReportByteLength); +	 +	buffer[0] = PHID_USB_GENERAL_PACKET_FLAG | PHID_USB_GENERAL_PACKET_WRITE_FLASH; +	 +	result = CUSBSendPacket((CPhidgetHandle)phid, buffer); + +	free(buffer); + +	return result; +} + +int CCONV CPhidgetGPP_zeroConfig(CPhidgetHandle phid) +{ +	int result; +	unsigned char *buffer; +	TESTPTR(phid) +	if (!CPhidget_statusFlagIsSet(phid->status, PHIDGET_ATTACHED_FLAG)) +		return EPHIDGET_NOTATTACHED; + +	if(!deviceSupportsGeneralUSBProtocol(phid)) +		return EPHIDGET_UNSUPPORTED; + +	buffer = (unsigned char *) malloc(phid->outputReportByteLength); +	ZEROMEM(buffer, phid->outputReportByteLength); +	 +	buffer[0] = PHID_USB_GENERAL_PACKET_FLAG | PHID_USB_GENERAL_PACKET_ZERO_CONFIG; +	 +	result = CUSBSendPacket((CPhidgetHandle)phid, buffer); + +	free(buffer); + +	return result; +} + +int CCONV CPhidgetGPP_setLabel(CPhidgetHandle phid, const char *label) +{ +	unsigned char buffer[26] = {0}; +	int result; +	TESTPTR(phid) +	if (!CPhidget_statusFlagIsSet(phid->status, PHIDGET_ATTACHED_FLAG)) +		return EPHIDGET_NOTATTACHED; + +	if(!deviceSupportsGeneralUSBProtocol(phid)) +		return EPHIDGET_UNSUPPORTED; + +	//Label Table Header is: 0x0010001A +    buffer[3] = 0x00; //header high byte +    buffer[2] = 0x10; +    buffer[1] = 0x00; +    buffer[0] = 0x1a; //header low byte + +	memcpy(buffer+4, label, label[0]); + +	//Label Table index is: 0 +	if((result=CPhidgetGPP_setDeviceWideConfigTable(phid, buffer, 26, 0))==EPHIDGET_OK) +		return CPhidgetGPP_writeFlash(phid); +	return result; +} + +static int CPhidgetGPP_setConfigTable(CPhidgetHandle phid, unsigned char *data, int length, int index, int packetType) +{ +	int result, i, j; +	unsigned char *buffer; +	TESTPTR(phid) +	if (!CPhidget_statusFlagIsSet(phid->status, PHIDGET_ATTACHED_FLAG)) +		return EPHIDGET_NOTATTACHED; + +	if(!deviceSupportsGeneralUSBProtocol(phid)) +		return EPHIDGET_UNSUPPORTED; + +	buffer = (unsigned char *) malloc(phid->outputReportByteLength); +	ZEROMEM(buffer, phid->outputReportByteLength); +	 +	buffer[0] = PHID_USB_GENERAL_PACKET_FLAG | packetType; +	buffer[1] = index; +	for(i=2,j=0;i<phid->outputReportByteLength && j<length;i++,j++) +		buffer[i] = data[j]; + +	CThread_mutex_lock(&phid->writelock); + +	if((result = CUSBSendPacket((CPhidgetHandle)phid, buffer)) != EPHIDGET_OK) +		goto done; + +	while(j<length && result == EPHIDGET_OK) +	{ +		buffer[0] = PHID_USB_GENERAL_PACKET_FLAG | PHID_USB_GENERAL_PACKET_CONTINUATION; +		for(i=1;i<phid->outputReportByteLength && j<length;i++,j++) +			buffer[i] = data[j]; +		if((result = CUSBSendPacket((CPhidgetHandle)phid, buffer)) != EPHIDGET_OK) +			goto done; +	} + +done: +	CThread_mutex_unlock(&phid->writelock); + +	free(buffer); + +	return result; +} + +int CCONV CPhidgetGPP_setDeviceSpecificConfigTable(CPhidgetHandle phid, unsigned char *data, int length, int index) +{ +	return CPhidgetGPP_setConfigTable(phid, data, length, index, PHID_USB_GENERAL_PACKET_SET_DS_TABLE); +} + +int CCONV CPhidgetGPP_setDeviceWideConfigTable(CPhidgetHandle phid, unsigned char *data, int length, int index) +{ +	return CPhidgetGPP_setConfigTable(phid, data, length, index, PHID_USB_GENERAL_PACKET_SET_DW_TABLE); +}
\ No newline at end of file @@ -102,6 +102,13 @@ typedef struct {  	const char *pdd_name;  } CPhidgetDeviceDef; +typedef struct { +	CPhidget_DeviceUID pdd_uid; +	CPhidget_DeviceID pdd_id; +	int pdd_vlow; +	int pdd_vhigh; +} CPhidgetUniqueDeviceDef; +  struct _CPhidget {  	CPhidgetRemoteHandle networkInfo; //NULL if local, !NULL if remote  	int(CCONV *fptrError)(CPhidgetHandle , void *, int, const char *); @@ -129,6 +136,7 @@ struct _CPhidget {  	int specificDevice;  	CPhidget_DeviceClass deviceID;  	CPhidget_DeviceID deviceIDSpec; +	CPhidget_DeviceUID deviceUID;  	const CPhidgetDeviceDef *deviceDef;  	//int Phid_Device_Def_index;  	int deviceVersion; @@ -140,6 +148,9 @@ struct _CPhidget {  	unsigned short inputReportByteLength;  	char label[MAX_LABEL_STORAGE];  	char *escapedLabel; //for webservice +	char usbProduct[64]; +	char firmwareUpgradeName[30]; +	unsigned char GPPResponse;  	int(CCONV *fptrInit)(CPhidgetHandle);  	int(CCONV *fptrClear)(CPhidgetHandle);  	int(CCONV *fptrEvents)(CPhidgetHandle); @@ -191,6 +202,7 @@ extern int phidgetLocksInitialized;  extern CThread_mutex_t activeDevicesLock, attachedDevicesLock;  extern const CPhidgetDeviceDef Phid_Device_Def[]; +extern const CPhidgetUniqueDeviceDef Phid_Unique_Device_Def[];  void CPhidgetFHandle_free(void *arg);  int CPhidget_read(CPhidgetHandle phid); @@ -209,8 +221,11 @@ double timeSince(TIME *start);  void setTimeNow(TIME *now);  int encodeLabelString(const char *buffer, char *out, int *outLen);  int decodeLabelString(char *labelBuf, char *out, int serialNumber); +int UTF16toUTF8(char *in, int inBytes, char *out);  int labelHasWrapError(int serialNumber, char *labelBuf);  void CPhidgetErrorEvent_free(void *arg); +CPhidget_DeviceUID CPhidget_getUID(CPhidget_DeviceID id, int version); +int deviceSupportsGeneralUSBProtocol(CPhidgetHandle phid);  PHIDGET21_API int CCONV CPhidget_areEqual(void *arg1, void *arg2);  PHIDGET21_API int CCONV CPhidget_areExtraEqual(void *arg1, void *arg2); @@ -221,6 +236,37 @@ PHIDGET21_API int CCONV CPhidget_create(CPhidgetHandle *phid);  PHIDGET21_API int CCONV CPhidget_calibrate_gainoffset(CPhidgetHandle phid, int index, unsigned short offset, unsigned long gain); +//Some constants and function for new M3 Phidgets (General Packet Protocol) + +PHIDGET21_API int CCONV CPhidgetGPP_reboot_firmwareUpgrade(CPhidgetHandle phid); +PHIDGET21_API int CCONV CPhidgetGPP_reboot_ISP(CPhidgetHandle phid); +PHIDGET21_API int CCONV CPhidgetGPP_setLabel(CPhidgetHandle phid, const char *buffer); +int CCONV CPhidgetGPP_setDeviceSpecificConfigTable(CPhidgetHandle phid, unsigned char *data, int length, int index); +int CCONV CPhidgetGPP_setDeviceWideConfigTable(CPhidgetHandle phid, unsigned char *data, int length, int index); +PHIDGET21_API int CCONV CPhidgetGPP_upgradeFirmware(CPhidgetHandle phid, unsigned char *data, int length); +PHIDGET21_API int CCONV CPhidgetGPP_eraseFirmware(CPhidgetHandle phid); + +//Bit 7 (MSB) +#define PHID_USB_GENERAL_PACKET_FLAG 0x80 + +//Bit 6 (used for return value on IN stream) +#define PHID_USB_GENERAL_PACKET_SUCCESS	0x00 +#define PHID_USB_GENERAL_PACKET_FAIL	0x40 + +//Bits 0-5 (up to 31 types) +#define PHID_USB_GENERAL_PACKET_IGNORE 0x00 +#define PHID_USB_GENERAL_PACKET_REBOOT_FIRMWARE_UPGRADE	0x01 +#define PHID_USB_GENERAL_PACKET_REBOOT_ISP 0x02 +//This is more data for when we need to send more then will fit in a single packet. +#define PHID_USB_GENERAL_PACKET_CONTINUATION 0x03 +#define PHID_USB_GENERAL_PACKET_ZERO_CONFIG 0x04 +#define PHID_USB_GENERAL_PACKET_WRITE_FLASH 0x05 +#define PHID_USB_GENERAL_PACKET_FIRMWARE_UPGRADE_WRITE_SECTOR 0x06 +#define PHID_USB_GENERAL_PACKET_SET_DS_TABLE 0x07 +#define PHID_USB_GENERAL_PACKET_SET_DW_TABLE 0x08 +#define PHID_USB_GENERAL_PACKET_FIRMWARE_UPGRADE_ERASE 0x09 + +  #endif  #include "cphidgetmacros.h" diff --git a/cphidgetadvancedservo.c b/cphidgetadvancedservo.c index 12419cb..8b5624b 100644 --- a/cphidgetadvancedservo.c +++ b/cphidgetadvancedservo.c @@ -310,7 +310,7 @@ CPHIDGETDATA(AdvancedServo)  		else  			phid->motorPositionEcho[i] = position[i];  		if(velocity[i] > phid->velocityMaxLimit || velocity[i] < -phid->velocityMaxLimit) -			LOG(PHIDGET_LOG_WARNING, "Phidget advanced servo recieved out of range velocity data: %lE", velocity[i]); +			LOG(PHIDGET_LOG_WARNING, "Phidget advanced servo received out of range velocity data: %lE", velocity[i]);  		else  			phid->motorVelocityEcho[i] = velocity[i]; @@ -570,8 +570,8 @@ CSETINDEX(AdvancedServo,Acceleration,double)  	TESTDEVICETYPE(PHIDCLASS_ADVANCEDSERVO)  	TESTATTACHED  	TESTINDEX(phid.attr.advancedservo.numMotors) -	TESTRANGE(servo_us_to_degrees_vel(phid->servoParams[Index], phid->accelerationMin, PFALSE),  -		servo_us_to_degrees_vel(phid->servoParams[Index], phid->accelerationMax, PFALSE)) +	TESTRANGE(servo_us_to_degrees_vel(phid->servoParams[Index], phid->accelerationMin, PFALSE)-0.5,  +		servo_us_to_degrees_vel(phid->servoParams[Index], phid->accelerationMax, PFALSE)+0.5)  	newVal = servo_degrees_to_us_vel(phid->servoParams[Index], newVal); @@ -620,8 +620,8 @@ CSETINDEX(AdvancedServo,VelocityLimit,double)  	TESTDEVICETYPE(PHIDCLASS_ADVANCEDSERVO)  	TESTATTACHED  	TESTINDEX(phid.attr.advancedservo.numMotors) -	TESTRANGE(servo_us_to_degrees_vel(phid->servoParams[Index], phid->velocityMin, PTRUE)-0.5,  -		servo_us_to_degrees_vel(phid->servoParams[Index], phid->velocityMax[Index]+0.5, PTRUE)) +	TESTRANGE(servo_us_to_degrees_vel(phid->servoParams[Index], phid->velocityMin, PFALSE)-0.5,  +		servo_us_to_degrees_vel(phid->servoParams[Index], phid->velocityMax[Index], PFALSE)+0.5)  	newVal = servo_degrees_to_us_vel(phid->servoParams[Index], newVal); @@ -684,8 +684,8 @@ CSETINDEX(AdvancedServo,Position,double)  	TESTDEVICETYPE(PHIDCLASS_ADVANCEDSERVO)  	TESTATTACHED  	TESTINDEX(phid.attr.advancedservo.numMotors) -	TESTRANGE(servo_us_to_degrees(phid->servoParams[Index], phid->motorPositionMin[Index], PTRUE)-0.5,  -		servo_us_to_degrees(phid->servoParams[Index], phid->motorPositionMax[Index], PTRUE)+0.5) +	TESTRANGE(servo_us_to_degrees(phid->servoParams[Index], phid->motorPositionMin[Index], PFALSE)-0.5,  +		servo_us_to_degrees(phid->servoParams[Index], phid->motorPositionMax[Index], PFALSE)+0.5)  	newVal = servo_degrees_to_us(phid->servoParams[Index], newVal); diff --git a/cphidgetattr.h b/cphidgetattr.h index c1b33f6..b8a8fce 100644 --- a/cphidgetattr.h +++ b/cphidgetattr.h @@ -240,6 +240,9 @@ typedef enum  {  	PHIDID_TEXTLED_4x8						= 0x048,	/**< Phidget TextLED 4x8 (1040) */  	PHIDID_WEIGHTSENSOR						= 0x072,	/**< Phidget Weight Sensor (1050) */ +	/* Device in firmware upgrade mode */ +	PHIDID_FIRMWARE_UPGRADE					= 0x098, +	  #if defined(DEBUG) || !defined(EXTERNALPROTO)  	/* Nothing device */  	PHIDID_NOTHING							= 1, @@ -257,5 +260,109 @@ typedef enum  {  #endif  } CPhidget_DeviceID;  /** @} */ + +typedef enum  { +	PHIDUID_NOTHING							=1, + +	PHIDUID_ACCELEROMETER_2AXIS_2G, +	PHIDUID_ACCELEROMETER_2AXIS_10G, +	PHIDUID_ACCELEROMETER_2AXIS_5G, +	PHIDUID_ACCELEROMETER_3AXIS_3G,	 + +	PHIDUID_ADVANCEDSERVO_1MOTOR, + +	PHIDUID_ADVANCEDSERVO_8MOTOR, +	PHIDUID_ADVANCEDSERVO_8MOTOR_PGOOD_FLAG, +	PHIDUID_ADVANCEDSERVO_8MOTOR_CURSENSE_FIX, + +	PHIDUID_ANALOG_4OUTPUT, + +	PHIDUID_BRIDGE_4INPUT, + +	PHIDUID_ENCODER_1ENCODER_1INPUT_OLD, +	PHIDUID_ENCODER_1ENCODER_1INPUT_v1, +	PHIDUID_ENCODER_1ENCODER_1INPUT_v2, +	PHIDUID_ENCODER_HS_1ENCODER, +	PHIDUID_ENCODER_HS_4ENCODER_4INPUT, + +	PHIDUID_FREQUENCYCOUNTER_2INPUT, + +	PHIDUID_GPS, + +	PHIDUID_INTERFACEKIT_0_0_4_NO_ECHO, +	PHIDUID_INTERFACEKIT_0_0_4, +	PHIDUID_INTERFACEKIT_0_0_8, +	PHIDUID_INTERFACEKIT_0_5_7, +	PHIDUID_INTERFACEKIT_0_8_8_w_LCD, +	PHIDUID_INTERFACEKIT_0_16_16_NO_ECHO, +	PHIDUID_INTERFACEKIT_0_16_16_BITBUG, +	PHIDUID_INTERFACEKIT_0_16_16, +	PHIDUID_INTERFACEKIT_2_2_2, +	PHIDUID_INTERFACEKIT_2_8_8, +	PHIDUID_INTERFACEKIT_4_8_8, +	PHIDUID_INTERFACEKIT_8_8_8_NO_ECHO, +	PHIDUID_INTERFACEKIT_8_8_8, +	PHIDUID_INTERFACEKIT_8_8_8_FAST, +	PHIDUID_INTERFACEKIT_8_8_8_w_LCD_NO_ECHO, +	PHIDUID_INTERFACEKIT_8_8_8_w_LCD, +	PHIDUID_INTERFACEKIT_8_8_8_w_LCD_FAST, +	PHIDUID_INTERFACEKIT_TOUCH_SLIDER, +	PHIDUID_INTERFACEKIT_TOUCH_ROTARY, + +	PHIDUID_IR, + +	PHIDUID_LED_64, +	PHIDUID_LED_64_ADV, + +	PHIDUID_MOTORCONTROL_1MOTOR, +	PHIDUID_MOTORCONTROL_HC_2MOTOR, +	PHIDUID_MOTORCONTROL_LV_2MOTOR_4INPUT, + +	PHIDUID_PHSENSOR, + +	PHIDUID_RFID_OLD, +	PHIDUID_RFID, +	PHIDUID_RFID_2OUTPUT_NO_ECHO, +	PHIDUID_RFID_2OUTPUT, +	PHIDUID_RFID_2OUTPUT_ADVANCED, + +	PHIDUID_SERVO_1MOTOR_OLD, +	PHIDUID_SERVO_4MOTOR_OLD, +	PHIDUID_SERVO_1MOTOR_NO_ECHO, +	PHIDUID_SERVO_1MOTOR, +	PHIDUID_SERVO_4MOTOR_NO_ECHO, +	PHIDUID_SERVO_4MOTOR, + +	PHIDUID_SPATIAL_ACCEL_3AXIS_1049, +	PHIDUID_SPATIAL_ACCEL_3AXIS_1041, +	PHIDUID_SPATIAL_ACCEL_3AXIS_1043, +	PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1056, +	PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1056_NEG_GAIN, +	PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1042, +	PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1044, + +	PHIDUID_STEPPER_BIPOLAR_1MOTOR, +	PHIDUID_STEPPER_UNIPOLAR_4MOTOR, + +	PHIDUID_TEMPERATURESENSOR_OLD, +	PHIDUID_TEMPERATURESENSOR, +	PHIDUID_TEMPERATURESENSOR_AD22100, +	PHIDUID_TEMPERATURESENSOR_TERMINAL_BLOCKS, +	PHIDUID_TEMPERATURESENSOR_4, +	PHIDUID_TEMPERATURESENSOR_IR, + +	PHIDUID_TEXTLCD_2x20, +	PHIDUID_TEXTLCD_2x20_w_8_8_8, +	PHIDUID_TEXTLCD_2x20_w_8_8_8_BRIGHTNESS, +	PHIDUID_TEXTLCD_ADAPTER, + +	PHIDUID_TEXTLED_1x8, +	PHIDUID_TEXTLED_4x8, + +	PHIDUID_WEIGHTSENSOR, + +	PHIDUID_GENERIC, +	PHIDUID_FIRMWARE_UPGRADE +} CPhidget_DeviceUID;  #endif diff --git a/cphidgetconstants.c b/cphidgetconstants.c index 95b36e9..3b5f77b 100644 --- a/cphidgetconstants.c +++ b/cphidgetconstants.c @@ -147,7 +147,121 @@ const CPhidgetDeviceDef Phid_Device_Def[PHIDGET_DEVICE_COUNT+1] = {  { PHIDID_INTERFACEKIT_0_0_8,			PHIDCLASS_INTERFACEKIT,		0x6C2, 0x81,	0, { UFINTS(ifkit,				 0,  0,  8 ) },	"Phidget InterfaceKit 0/0/8"},  { PHIDID_ADVANCEDSERVO_1MOTOR,			PHIDCLASS_ADVANCEDSERVO,	0x6C2, 0x82,	0, { UFINTS(advancedservo,		 1         ) },	"Phidget Advanced Servo Controller 1-motor"}, +{ PHIDID_FIRMWARE_UPGRADE,				PHIDCLASS_GENERIC,			0x6C2, 0x98,	0, { UFINTS(dummy,				 0,  0,  0 ) },	"Firmware Upgrade"},	  { PHIDID_GENERIC,						PHIDCLASS_GENERIC,			0x6C2, 0x99,	0, { UFINTS(dummy,				 0,  0,  0 ) },	"Phidget Generic Device"},				//generic device - used for prototyping  { 0 } //ending null  }; + +/* + * List Every unique device - in terms of packet protocol + * 0,9999 for version means any version + * matching is >= lower version, < higher version + */ +const CPhidgetUniqueDeviceDef Phid_Unique_Device_Def[] = { +	{PHIDUID_NOTHING,									PHIDUID_NOTHING,						  0,	  0},	// Invalid +	 +	{PHIDUID_ACCELEROMETER_2AXIS_2G,					PHIDID_ACCELEROMETER_2AXIS,				  0,	200},	// <200 +	{PHIDUID_ACCELEROMETER_2AXIS_10G,					PHIDID_ACCELEROMETER_2AXIS,				200,	300},	// 200 - <300 +	{PHIDUID_ACCELEROMETER_2AXIS_5G,					PHIDID_ACCELEROMETER_2AXIS,				300,	400},	// 300 - <400 +	{PHIDUID_ACCELEROMETER_3AXIS_3G,					PHIDID_ACCELEROMETER_3AXIS,				400,	500},	// 400 - <500 + +	{PHIDUID_ADVANCEDSERVO_1MOTOR,						PHIDID_ADVANCEDSERVO_1MOTOR,			100,	200},	// 100 - <200 +	{PHIDUID_ADVANCEDSERVO_8MOTOR,						PHIDID_ADVANCEDSERVO_8MOTOR,			100,	200},	// 100 - <200 +	{PHIDUID_ADVANCEDSERVO_8MOTOR_PGOOD_FLAG,			PHIDID_ADVANCEDSERVO_8MOTOR,			200,	300},	// 200 - <300 +	{PHIDUID_ADVANCEDSERVO_8MOTOR_CURSENSE_FIX,			PHIDID_ADVANCEDSERVO_8MOTOR,			300,	400},	// 300 - <400 + +	{PHIDUID_ANALOG_4OUTPUT,							PHIDID_ANALOG_4OUTPUT,					100,	200},	// 100 - <200 + +	{PHIDUID_BRIDGE_4INPUT,								PHIDID_BRIDGE_4INPUT,					100,	200},	// 100 - <200 + +	{PHIDUID_ENCODER_1ENCODER_1INPUT_OLD,				PHIDID_ENCODER_1ENCODER_1INPUT,			  0,	101},	// <=100 +	{PHIDUID_ENCODER_1ENCODER_1INPUT_v1,				PHIDID_ENCODER_1ENCODER_1INPUT,			101,	110},	// 101 - <110 +	{PHIDUID_ENCODER_1ENCODER_1INPUT_v2,				PHIDID_ENCODER_1ENCODER_1INPUT,			110,	300},	// 110 - <300 +	{PHIDUID_ENCODER_HS_1ENCODER,						PHIDID_ENCODER_HS_1ENCODER,				300,	400},	// 300 - <400 +	{PHIDUID_ENCODER_HS_4ENCODER_4INPUT,				PHIDID_ENCODER_HS_4ENCODER_4INPUT,		100,	200},	// 100 - <200 + +	{PHIDUID_FREQUENCYCOUNTER_2INPUT,					PHIDID_FREQUENCYCOUNTER_2INPUT,			  0,	200},	// < 200 + +	{PHIDUID_GPS,										PHIDID_GPS,								  0,   9999},	// ANY + +	{PHIDUID_INTERFACEKIT_0_0_4_NO_ECHO,				PHIDID_INTERFACEKIT_0_0_4,				  0,	704},	// <704 +	{PHIDUID_INTERFACEKIT_0_0_4,						PHIDID_INTERFACEKIT_0_0_4,				704,	800},	// 704 - <800 +	{PHIDUID_INTERFACEKIT_0_0_8,						PHIDID_INTERFACEKIT_0_0_8,				  0,   9999},	// ANY +	{PHIDUID_INTERFACEKIT_0_5_7,						PHIDID_INTERFACEKIT_0_5_7,				  0,   9999},	// ANY +	{PHIDUID_INTERFACEKIT_0_8_8_w_LCD,					PHIDID_INTERFACEKIT_0_8_8_w_LCD,		  0,   9999},	// ANY +	{PHIDUID_INTERFACEKIT_0_16_16_NO_ECHO,				PHIDID_INTERFACEKIT_0_16_16,			  0,	601},	// <=600 +	{PHIDUID_INTERFACEKIT_0_16_16_BITBUG,				PHIDID_INTERFACEKIT_0_16_16,			601,	602},	// 601 +	{PHIDUID_INTERFACEKIT_0_16_16,						PHIDID_INTERFACEKIT_0_16_16,			602,	700},	// 602 - <700 +	{PHIDUID_INTERFACEKIT_2_2_2,						PHIDID_INTERFACEKIT_2_2_2,				  0,	200},	// <200 +	{PHIDUID_INTERFACEKIT_2_8_8,						PHIDID_INTERFACEKIT_2_8_8,				  0,   9999},	// ANY +	{PHIDUID_INTERFACEKIT_4_8_8,						PHIDID_INTERFACEKIT_4_8_8,				  0,	101},	// <=100 +	{PHIDUID_INTERFACEKIT_8_8_8_NO_ECHO,				PHIDID_INTERFACEKIT_8_8_8,				  0,	821},	// <=820 +	{PHIDUID_INTERFACEKIT_8_8_8,						PHIDID_INTERFACEKIT_8_8_8,				821,	900},	// 821 - <900 +	{PHIDUID_INTERFACEKIT_8_8_8_FAST,					PHIDID_INTERFACEKIT_8_8_8,				900,   1000},	// 900 - <1000 +	{PHIDUID_INTERFACEKIT_8_8_8_w_LCD_NO_ECHO,			PHIDID_INTERFACEKIT_8_8_8_w_LCD,		  0,	120},	// <120 +	{PHIDUID_INTERFACEKIT_8_8_8_w_LCD,					PHIDID_INTERFACEKIT_8_8_8_w_LCD,		120,	200},	// 120 - <200 +	{PHIDUID_INTERFACEKIT_8_8_8_w_LCD_FAST,				PHIDID_INTERFACEKIT_8_8_8_w_LCD,		200,	300},	// 200 - <300 +	{PHIDUID_INTERFACEKIT_TOUCH_SLIDER,					PHIDID_LINEAR_TOUCH,					  0,   9999},	// ANY +	{PHIDUID_INTERFACEKIT_TOUCH_ROTARY,					PHIDID_ROTARY_TOUCH,					  0,   9999},	// ANY + +	{PHIDUID_IR,										PHIDID_IR,								100,	200},	// 100 - <200 + +	{PHIDUID_LED_64,									PHIDID_LED_64,							100,	300},	// 100 - <300 +	{PHIDUID_LED_64_ADV,								PHIDID_LED_64_ADV,						100,	200},	// 100 - <200 + +	{PHIDUID_MOTORCONTROL_1MOTOR,						PHIDID_MOTORCONTROL_1MOTOR,				100, 	200},	// 100 - <200 +	{PHIDUID_MOTORCONTROL_HC_2MOTOR,					PHIDID_MOTORCONTROL_HC_2MOTOR,			100,	200},	// 100 - <200 +	{PHIDUID_MOTORCONTROL_LV_2MOTOR_4INPUT,				PHIDID_MOTORCONTROL_LV_2MOTOR_4INPUT,	100,	200},	// 100 - <200 + +	{PHIDUID_PHSENSOR,									PHIDID_PHSENSOR,						100,	200},	// 100 - <200 + +	{PHIDUID_RFID_OLD,									PHIDID_RFID,							  0,	104},	// <=103 +	{PHIDUID_RFID,										PHIDID_RFID,							104,	200},	// 104 - <200 +	{PHIDUID_RFID_2OUTPUT_NO_ECHO,						PHIDID_RFID_2OUTPUT,					200,	201},	// 200 +	{PHIDUID_RFID_2OUTPUT,								PHIDID_RFID_2OUTPUT,					201,	300},	// 201 - <300 +	{PHIDUID_RFID_2OUTPUT_ADVANCED,						PHIDID_RFID_2OUTPUT_ADVANCED,			100,	200},	// 100 - <200 + +	{PHIDUID_SERVO_1MOTOR_OLD,							PHIDID_SERVO_1MOTOR_OLD,				200,	201},	// 200 +	{PHIDUID_SERVO_1MOTOR_OLD,							PHIDID_SERVO_1MOTOR,					200,	201},	// 200 +	{PHIDUID_SERVO_4MOTOR_OLD,							PHIDID_SERVO_4MOTOR_OLD,				200,	201},	// 200 +	{PHIDUID_SERVO_4MOTOR_OLD,							PHIDID_SERVO_4MOTOR,					200,	201},	// 200 +	{PHIDUID_SERVO_1MOTOR_NO_ECHO,						PHIDID_SERVO_1MOTOR,					300,	313},	// 300 - 312 +	{PHIDUID_SERVO_1MOTOR,								PHIDID_SERVO_1MOTOR,					313,	400},	// 313 - <400 +	{PHIDUID_SERVO_4MOTOR_NO_ECHO,						PHIDID_SERVO_4MOTOR,					300,	313},	// 300 - 312 +	{PHIDUID_SERVO_4MOTOR,								PHIDID_SERVO_4MOTOR,					313,	400},	// 313 - <400 + +	{PHIDUID_SPATIAL_ACCEL_3AXIS_1049,					PHIDID_SPATIAL_ACCEL_3AXIS,				  0,	200},	// <200 +	{PHIDUID_SPATIAL_ACCEL_3AXIS_1041,					PHIDID_SPATIAL_ACCEL_3AXIS,				200,	300},	// 200 - <300 +	{PHIDUID_SPATIAL_ACCEL_3AXIS_1043,					PHIDID_SPATIAL_ACCEL_3AXIS,				300,	400},	// 300 - <400 +	{PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1056,			PHIDID_SPATIAL_ACCEL_GYRO_COMPASS,		  0,	200},	// <200 +	{PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1056_NEG_GAIN,	PHIDID_SPATIAL_ACCEL_GYRO_COMPASS,		200,	300},	// 200 - <300 +	{PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1042,			PHIDID_SPATIAL_ACCEL_GYRO_COMPASS,		300,	400},	// 300 - <400 +	{PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1044,			PHIDID_SPATIAL_ACCEL_GYRO_COMPASS,		400,	500},	// 400 - <500 + +	{PHIDUID_STEPPER_BIPOLAR_1MOTOR,					PHIDID_BIPOLAR_STEPPER_1MOTOR,			100,	200},	// 100 - <200 +	{PHIDUID_STEPPER_UNIPOLAR_4MOTOR,					PHIDID_UNIPOLAR_STEPPER_4MOTOR,			100,	200},	// 100 - <200 + +	{PHIDUID_TEMPERATURESENSOR_OLD,						PHIDID_TEMPERATURESENSOR,				  0,	200},	// <200 +	{PHIDUID_TEMPERATURESENSOR,							PHIDID_TEMPERATURESENSOR,				200,	300},	// 200 - <300 +	{PHIDUID_TEMPERATURESENSOR_AD22100,					PHIDID_TEMPERATURESENSOR,				300,	400},	// 300 - <400 +	{PHIDUID_TEMPERATURESENSOR_TERMINAL_BLOCKS,			PHIDID_TEMPERATURESENSOR,				400,	500},	// 400 - <500 +	{PHIDUID_TEMPERATURESENSOR_4,						PHIDID_TEMPERATURESENSOR_4,				100,	200},	// 100 - <200 +	{PHIDUID_TEMPERATURESENSOR_IR,						PHIDID_TEMPERATURESENSOR_IR,			100,	200},	// 100 - <200 + +	{PHIDUID_TEXTLCD_2x20,								PHIDID_TEXTLCD_2x20,					  0,   9999},	// ANY +	{PHIDUID_TEXTLCD_2x20,								PHIDID_TEXTLCD_2x20_CUSTOM,				  0,   9999},	// ANY +	{PHIDUID_TEXTLCD_2x20,								PHIDID_TEXTLCD_2x20_w_0_8_8,			  0,   9999},	// ANY +	{PHIDUID_TEXTLCD_2x20_w_8_8_8,						PHIDID_TEXTLCD_2x20_w_8_8_8,			  0,	200},	// <200 +	{PHIDUID_TEXTLCD_2x20_w_8_8_8_BRIGHTNESS,			PHIDID_TEXTLCD_2x20_w_8_8_8,			200,   9999},	// 200+ +	{PHIDUID_TEXTLCD_ADAPTER,							PHIDID_TEXTLCD_ADAPTER,					  0,   9999},	// ANY + +	{PHIDUID_TEXTLED_1x8,								PHIDID_TEXTLED_1x8,						111,	114},	// 111 - 113 +	{PHIDUID_TEXTLED_4x8,								PHIDID_TEXTLED_4x8,						200,	300},	// 200 - <300 + +	{PHIDUID_WEIGHTSENSOR,								PHIDID_WEIGHTSENSOR,					  0,   9999},	// ANY + +	{PHIDUID_FIRMWARE_UPGRADE,							PHIDID_FIRMWARE_UPGRADE,				  0,   9999},	// ANY +	{PHIDUID_GENERIC,									PHIDID_GENERIC,							  0,   9999},	// ANY +	{ 0 } //ending null +}; diff --git a/cphidgetconstantsinternal.h b/cphidgetconstantsinternal.h index 5659bec..216fe89 100644 --- a/cphidgetconstantsinternal.h +++ b/cphidgetconstantsinternal.h @@ -124,7 +124,7 @@  // this needs to reflect the size of Phid_DeviceName
  #define PHIDGET_DEVICE_CLASS_COUNT		24
  // this needs to reflect the size of Phid_Device_Def (not including the null end)
 -#define PHIDGET_DEVICE_COUNT			54
 +#define PHIDGET_DEVICE_COUNT			55
  #endif
 diff --git a/cphidgetgps.c b/cphidgetgps.c index 8215107..d97ac05 100644 --- a/cphidgetgps.c +++ b/cphidgetgps.c @@ -76,7 +76,7 @@ CPHIDGETINIT(GPS)  	CUSBSendPacket((CPhidgetHandle)phid, buffer);*/  	//read some initial data - rate is 10Hz so we shouldn't have to wait long -	//This ensures we have recieved at least one GGA and one RMC +	//This ensures we have received at least one GGA and one RMC  	readtries = 30; //250ms  	while((phid->fix==PUNK_BOOL || phid->haveTime==PUNK_BOOL || phid->haveDate==PUNK_BOOL) && readtries)  	{ diff --git a/cphidgetmanager.c b/cphidgetmanager.c index eecdb04..d0f918b 100644 --- a/cphidgetmanager.c +++ b/cphidgetmanager.c @@ -125,6 +125,7 @@ int CPhidgetDetachEvent(CPhidgetHandle phid) {  				travPhid->fptrDetach((CPhidgetHandle)travPhid, travPhid->fptrDetachptr);  			travPhid->deviceIDSpec = 0; +			travPhid->deviceUID = 0;  #if !defined(_MACOSX) && !defined(WINCE)  			CPhidgetFHandle_free(travPhid->CPhidgetFHandle); @@ -298,6 +299,10 @@ int CCONV CPhidgetManager_close(CPhidgetManagerHandle phidm)  	if(!ActiveDevices && !ActivePhidgetManagers)  	{  		JoinCentralThread(); +		//Shut down USB +#if defined(_LINUX) && !defined(_ANDROID) +		CUSBUninit(); +#endif  	}  	CPhidget_clearStatusFlag(&phidm->status, PHIDGET_OPENED_FLAG, &phidm->lock); diff --git a/cphidgetspatial.c b/cphidgetspatial.c index 41a8048..2feccce 100644 --- a/cphidgetspatial.c +++ b/cphidgetspatial.c @@ -1,1382 +1,1665 @@ -#include "stdafx.h"
 -#include "cphidgetspatial.h"
 -#include "cusb.h"
 -#include "math.h"
 -#include "csocket.h"
 -#include "cthread.h"
 -
 -// === Internal Functions === //
 -static double getCorrectedField(CPhidgetSpatialHandle phid, double fields[], int axis);
 -
 -//clearVars - sets all device variables to unknown state
 -CPHIDGETCLEARVARS(Spatial)
 -	int i = 0;
 -
 -	phid->dataRateMin = PUNI_INT;
 -	phid->dataRate = PUNI_INT;
 -	phid->dataRateMax = PUNI_INT;
 -
 -	phid->accelerationMax = PUNI_DBL;
 -	phid->accelerationMin = PUNI_DBL;
 -	phid->angularRateMax = PUNI_DBL;
 -	phid->angularRateMin = PUNI_DBL;
 -	phid->magneticFieldMax = PUNI_DBL;
 -	phid->magneticFieldMin = PUNI_DBL;
 -	phid->interruptRate = PUNI_INT;
 -
 -	phid->spatialDataNetwork = PUNI_BOOL;
 -
 -	for (i = 0; i<SPATIAL_MAX_ACCELAXES; i++)
 -	{
 -		phid->accelAxis[i] = PUNI_DBL;
 -	}
 -	for (i = 0; i<SPATIAL_MAX_GYROAXES; i++)
 -	{
 -		phid->gyroAxis[i] = PUNI_DBL;
 -	}
 -	for (i = 0; i<SPATIAL_MAX_COMPASSAXES; i++)
 -	{
 -		phid->compassAxis[i] = PUNI_DBL;
 -	}
 -	return EPHIDGET_OK;
 -}
 -
 -//initAfterOpen - sets up the initial state of an object, reading in packets from the device if needed
 -//				  used during attach initialization - on every attach
 -CPHIDGETINIT(Spatial)
 -	int i = 0;
 -
 -	TESTPTR(phid);
 -
 -	//Setup max/min values
 -	switch(phid->phid.deviceIDSpec)
 -	{
 -		case PHIDID_SPATIAL_ACCEL_3AXIS:
 -			if (phid->phid.deviceVersion < 200)
 -			{
 -				phid->accelerationMax = 5.1;
 -				phid->accelerationMin = -5.1;
 -				phid->interruptRate = 8;
 -				phid->dataRateMin = SPATIAL_MIN_DATA_RATE;
 -				phid->dataRate = phid->interruptRate;
 -				phid->dataRateMax = 1; //actual data rate
 -				phid->angularRateMax = 0;
 -				phid->angularRateMin = 0;
 -				phid->magneticFieldMax = 0;
 -				phid->magneticFieldMin = 0;
 -				phid->calDataValid = PFALSE;
 -			}
 -			else
 -				return EPHIDGET_BADVERSION;
 -			break;
 -		case PHIDID_SPATIAL_ACCEL_GYRO_COMPASS:
 -			if (phid->phid.deviceVersion < 300)
 -			{
 -				phid->accelerationMax = 5.1;
 -				phid->accelerationMin = -5.1;
 -				phid->interruptRate = 8;
 -				phid->dataRateMin = SPATIAL_MIN_DATA_RATE;
 -				phid->dataRate = phid->interruptRate;
 -				phid->dataRateMax = 4; //actual data rate
 -				phid->angularRateMax = 400.1;
 -				phid->angularRateMin = -400.1;
 -				phid->magneticFieldMax = 4.1;
 -				phid->magneticFieldMin = -4.1;
 -				phid->userMagField = 1.0;
 -				phid->calDataValid = PFALSE;
 -			}
 -			// 1042 (Digital 3/3/3)
 -			else if (phid->phid.deviceVersion  >= 300 && phid->phid.deviceVersion < 400)
 -			{
 -				phid->accelerationMax = 5.1;
 -				phid->accelerationMin = -5.1;
 -				phid->interruptRate = 8;
 -				phid->dataRateMin = SPATIAL_MIN_DATA_RATE;
 -				phid->dataRate = phid->interruptRate;
 -				phid->dataRateMax = 4; //actual data rate
 -				phid->angularRateMax = 400.1;
 -				phid->angularRateMin = -400.1;
 -				phid->magneticFieldMax = 4.1;
 -				phid->magneticFieldMin = -4.1;
 -				phid->userMagField = 1.0;
 -				phid->calDataValid = PFALSE;
 -			}
 -			// 1044 (1056 Replacement)
 -			else if (phid->phid.deviceVersion  >= 400 && phid->phid.deviceVersion < 500)
 -			{
 -				phid->accelerationMax = 5.1;
 -				phid->accelerationMin = -5.1;
 -				phid->interruptRate = 4;
 -				phid->dataRateMin = SPATIAL_MIN_DATA_RATE;
 -				phid->dataRate = 8;//phid->interruptRate;
 -				phid->dataRateMax = 4; //actual data rate
 -				phid->angularRateMax = 400.1;
 -				phid->angularRateMin = -400.1;
 -				phid->magneticFieldMax = 10.1;
 -				phid->magneticFieldMin = -10.1;
 -				phid->userMagField = 1.0;
 -				phid->calDataValid = PFALSE;
 -			}
 -			else
 -				return EPHIDGET_BADVERSION;
 -			break;
 -		default:
 -			return EPHIDGET_UNEXPECTED;
 -	}
 -
 -	//initialize triggers, set data arrays to unknown
 -	for (i = 0; i<phid->phid.attr.spatial.numAccelAxes; i++)
 -	{
 -		phid->accelAxis[i] = PUNK_DBL;
 -		phid->accelGain1[i] = PUNK_DBL;
 -		phid->accelGain2[i] = PUNK_DBL;
 -		phid->accelOffset[i] = PUNK_INT;
 -	}
 -	for (i = 0; i<phid->phid.attr.spatial.numGyroAxes; i++)
 -	{
 -		phid->gyroAxis[i] = PUNK_DBL;
 -		phid->gryoCorrection[i] = 0;
 -		phid->gyroGain1[i] = PUNK_DBL;
 -		phid->gyroGain2[i] = PUNK_DBL;
 -		phid->gyroOffset[i] = PUNK_INT;
 -	}
 -	for (i = 0; i<phid->phid.attr.spatial.numCompassAxes; i++)
 -	{
 -		phid->compassAxis[i] = PUNK_DBL;
 -		phid->userCompassGain[i] = 1.0;
 -	}
 -	phid->bufferReadPtr = 0;
 -	phid->bufferWritePtr = 0;
 -	phid->timestamp.seconds = 0;
 -	phid->timestamp.microseconds = 0;
 -	phid->lastEventTime.seconds = 0;
 -	phid->lastEventTime.microseconds = 0;
 -	phid->latestDataTime.seconds = 0;
 -	phid->latestDataTime.microseconds = 0;
 -
 -	phid->lastTimeCounterValid = PFALSE;
 -	phid->doZeroGyro = PFALSE;
 -
 -	//get calibration values
 -	switch(phid->phid.deviceIDSpec) {
 -		case PHIDID_SPATIAL_ACCEL_3AXIS:
 -			// 1041, 1043 - no streamed calibration values
 -			if (phid->phid.deviceVersion >= 200)
 -				break;
 -		case PHIDID_SPATIAL_ACCEL_GYRO_COMPASS:
 -			// 1042, 1044 - no streamed calibration values
 -			if (phid->phid.deviceVersion >= 300)
 -				break;
 -			else
 -			{
 -				unsigned char buffer[8] = { 0 };
 -				int result;
 -				int readCount = 125; // up to 1 second of data - should be PLENTY
 -				//ask for calibration values
 -				buffer[0] = SPATIAL_READCALIB;
 -				if ((result = CUSBSendPacket((CPhidgetHandle)phid, buffer)) != EPHIDGET_OK)
 -					return result;
 -				while(phid->calDataValid == PFALSE && readCount--)
 -				{
 -					//note that Windows queues up to 32 packets, so we need to read at least this many to get the calibration packet
 -					CPhidget_read((CPhidgetHandle)phid);
 -				}
 -				if(!phid->calDataValid)
 -					return EPHIDGET_UNEXPECTED;
 -			}
 -			break;
 -		default:
 -			break;
 -	}
 -
 -	//issue one read
 -	//this should fill in the data because the dataRate is the interrupt rate
 -	CPhidget_read((CPhidgetHandle)phid);
 -
 -	return EPHIDGET_OK;
 -}
 -
 -//dataInput - parses device packets
 -CPHIDGETDATA(Spatial)
 -	int i = 0, j = 0, count = 0, dataRate = phid->dataRate, cal;
 -	unsigned char doneGyroZero = PFALSE;
 -	double accelAvg[SPATIAL_MAX_ACCELAXES], angularRateAvg[SPATIAL_MAX_ACCELAXES], magneticFieldAvg[SPATIAL_MAX_ACCELAXES], magneticFieldCorr[SPATIAL_MAX_ACCELAXES];
 -	CPhidgetSpatial_SpatialEventDataHandle *eventData;
 -	
 -	ZEROMEM(accelAvg, sizeof(accelAvg));
 -	ZEROMEM(angularRateAvg, sizeof(angularRateAvg));
 -	ZEROMEM(magneticFieldAvg, sizeof(magneticFieldAvg));
 -
 -	if (length<0) return EPHIDGET_INVALIDARG;
 -	TESTPTR(phid);
 -	TESTPTR(buffer);
 -
 -	//Parse device packets - store data locally
 -	switch(phidG->deviceIDSpec)
 -	{
 -		case PHIDID_SPATIAL_ACCEL_3AXIS:
 -			if (phid->phid.deviceVersion < 200)
 -			{
 -				int data;
 -				double accelUncalib[3] = {0,0,0};
 -				int time;
 -				
 -				//top 2 bits in buffer[0] are packet type
 -				switch(buffer[0] & 0xc0)
 -				{
 -					case SPATIAL_PACKET_DATA:
 -						if(phid->calDataValid)
 -						{
 -							count = buffer[0] / 3;
 -							if(count == 0)
 -								goto done;
 -
 -							//this timestamp is for the latest data
 -							time = ((unsigned short)buffer[1]<<8) + (unsigned short)buffer[2];
 -							if(phid->lastTimeCounterValid)
 -							{
 -								//0-255 ms
 -								int timechange = (unsigned short)((unsigned short)time - (unsigned short)phid->lastTimeCounter);
 -								timechange *= 1000; //us
 -
 -								phid->timestamp.seconds = phid->timestamp.seconds + (phid->timestamp.microseconds + timechange) / 1000000;
 -								phid->timestamp.microseconds = (phid->timestamp.microseconds + timechange) % 1000000;
 -							}
 -							else
 -							{
 -								phid->lastTimeCounterValid = PTRUE;
 -							}
 -							phid->lastTimeCounter = time;
 -
 -							//add data to data buffer
 -							for(i=0;i<count;i++)
 -							{
 -								//LIS344ALH - Vdd/15 V/g - 0x1fff/15 = 0x222 (546.06666666666666666666666666667)
 -								for(j=0;j<3;j++)
 -								{
 -									data = ((unsigned short)buffer[3 + j * 2 + i * 6]<<8) + (unsigned short)buffer[4 + j * 2 + i * 6];
 -									accelUncalib[j] = ((double)data - 0x0fff) / 546.066667;
 -								}
 -								accelUncalib[1] = -accelUncalib[1]; //reverse Y-axis
 -								//Apply offsets
 -								for(j=0;j<3;j++)
 -								{
 -									accelUncalib[j] -= phid->accelOffset[j];
 -								}
 -								//X
 -								if(accelUncalib[0] > 0)
 -									phid->dataBuffer[phid->bufferWritePtr].acceleration[0] = accelUncalib[0] * phid->accelGain1[0] + accelUncalib[1] * phid->accelFactor1[0] + accelUncalib[2] * phid->accelFactor2[0];
 -								else
 -									phid->dataBuffer[phid->bufferWritePtr].acceleration[0] = accelUncalib[0] * phid->accelGain2[0] + accelUncalib[1] * phid->accelFactor1[0] + accelUncalib[2] * phid->accelFactor2[0];
 -								//Y
 -								if(accelUncalib[1] > 0)
 -									phid->dataBuffer[phid->bufferWritePtr].acceleration[1] = accelUncalib[1] * phid->accelGain1[1] + accelUncalib[0] * phid->accelFactor1[1] + accelUncalib[2] * phid->accelFactor2[1];
 -								else
 -									phid->dataBuffer[phid->bufferWritePtr].acceleration[1] = accelUncalib[1] * phid->accelGain2[1] + accelUncalib[0] * phid->accelFactor1[1] + accelUncalib[2] * phid->accelFactor2[1];
 -								//Z
 -								if(accelUncalib[2] > 0)
 -									phid->dataBuffer[phid->bufferWritePtr].acceleration[2] = accelUncalib[2] * phid->accelGain1[2] + accelUncalib[0] * phid->accelFactor1[2] + accelUncalib[1] * phid->accelFactor2[2];
 -								else
 -									phid->dataBuffer[phid->bufferWritePtr].acceleration[2] = accelUncalib[2] * phid->accelGain2[2] + accelUncalib[0] * phid->accelFactor1[2] + accelUncalib[1] * phid->accelFactor2[2];
 -
 -
 -								phid->latestDataTime.seconds = phid->timestamp.seconds + (phid->timestamp.microseconds + (i + 1) * phid->dataRateMax * 1000) / 1000000;
 -								phid->latestDataTime.microseconds = (phid->timestamp.microseconds + (i + 1) * phid->dataRateMax * 1000) % 1000000;
 -
 -								phid->dataBuffer[phid->bufferWritePtr].timestamp = phid->latestDataTime;
 -
 -								phid->bufferWritePtr++;
 -								if(phid->bufferWritePtr >= SPATIAL_DATA_BUFFER_SIZE)
 -									phid->bufferWritePtr = 0;
 -							}
 -						}
 -						break;
 -					case SPATIAL_PACKET_CALIB:
 -						for (i = 0; i<phid->phid.attr.spatial.numAccelAxes; i++)
 -						{
 -							cal = ((unsigned short)buffer[i*7 + 1]<<4) + ((unsigned short)buffer[i*7 + 2]>>4);
 -							phid->accelGain1[i] = cal / (4096/0.4) + 0.8;
 -							cal = (((unsigned short)buffer[i*7 + 2]<<8) & 0x0F00) | ((unsigned short)buffer[i*7 + 3]);
 -							phid->accelGain2[i] = cal / (4096/0.4) + 0.8;
 -							cal = (unsigned short)((unsigned short)buffer[i*7 + 4]<<8) + (unsigned short)buffer[i*7 + 5];
 -							phid->accelOffset[i] = cal / (65535 / 1.0) - 0.5;
 -							cal = (unsigned char)buffer[i*7 + 6];
 -							phid->accelFactor1[i] = cal / (256 / 0.2) - 0.1;
 -							cal = (unsigned char)buffer[i*7 + 7];
 -							phid->accelFactor2[i] = cal / (256 / 0.2) - 0.1;
 -							//LOG(PHIDGET_LOG_INFO, "Accel(%d) Calib: %1.4lf, %1.4lf, %1.4lf, %1.4lf, %1.4lf", i, 
 -							//	phid->accelGain1[i], phid->accelGain2[i], phid->accelOffset[i], phid->accelFactor1[i], phid->accelFactor2[i]);
 -						}
 -						phid->calDataValid = PTRUE;
 -						break;
 -				}
 -			}
 -			else
 -				return EPHIDGET_UNEXPECTED;
 -			break;
 -		case PHIDID_SPATIAL_ACCEL_GYRO_COMPASS:
 -			if (phidG->deviceVersion < 300)
 -			{
 -				//top 2 bits in buffer[0] are packet type
 -				switch(buffer[0])
 -				{
 -					case SPATIAL_PACKET_DATA:
 -						if(phid->calDataValid)
 -						{
 -							int data;
 -							double accelUncalib[3] = {0,0,0};
 -							double gyroUncalib[3] = {0,0,0};
 -							int time;
 -							
 -							count = (buffer[1] & 0x1f) / 9;
 -							if(count == 0)
 -								goto done;
 -
 -							//this timestamp is for the latest data
 -							time = ((unsigned short)buffer[2]<<8) + (unsigned short)buffer[3];
 -							if(phid->lastTimeCounterValid)
 -							{
 -								//0-255 ms
 -								int timechange = (unsigned short)((unsigned short)time - (unsigned short)phid->lastTimeCounter);
 -								timechange *= 1000; //us
 -
 -								phid->timestamp.seconds = phid->timestamp.seconds + (phid->timestamp.microseconds + timechange) / 1000000;
 -								phid->timestamp.microseconds = (phid->timestamp.microseconds + timechange) % 1000000;
 -							}
 -							else
 -							{
 -								phid->lastTimeCounterValid = PTRUE;
 -							}
 -							phid->lastTimeCounter = time;
 -
 -							//add data to data buffer
 -							for(i=0;i<count;i++)
 -							{
 -								//LIS344ALH - Vdd/15 V/g - 0xffff/15 = 0x1111 (4369.0)
 -								for(j=0;j<3;j++)
 -								{
 -									data = ((unsigned short)buffer[4 + j * 2 + i * 18]<<8) + (unsigned short)buffer[5 + j * 2 + i * 18];
 -									accelUncalib[j] = ((double)data - 0x7fff) / 4369.0;
 -								}
 -								accelUncalib[1] = -accelUncalib[1]; //reverse Y-axis
 -								//Apply offsets
 -								for(j=0;j<3;j++)
 -								{
 -									accelUncalib[j] -= phid->accelOffset[j];
 -								}
 -								//X
 -								if(accelUncalib[0] > 0)
 -									phid->dataBuffer[phid->bufferWritePtr].acceleration[0] = accelUncalib[0] * phid->accelGain1[0] + accelUncalib[1] * phid->accelFactor1[0] + accelUncalib[2] * phid->accelFactor2[0];
 -								else
 -									phid->dataBuffer[phid->bufferWritePtr].acceleration[0] = accelUncalib[0] * phid->accelGain2[0] + accelUncalib[1] * phid->accelFactor1[0] + accelUncalib[2] * phid->accelFactor2[0];
 -								//Y
 -								if(accelUncalib[1] > 0)
 -									phid->dataBuffer[phid->bufferWritePtr].acceleration[1] = accelUncalib[1] * phid->accelGain1[1] + accelUncalib[0] * phid->accelFactor1[1] + accelUncalib[2] * phid->accelFactor2[1];
 -								else
 -									phid->dataBuffer[phid->bufferWritePtr].acceleration[1] = accelUncalib[1] * phid->accelGain2[1] + accelUncalib[0] * phid->accelFactor1[1] + accelUncalib[2] * phid->accelFactor2[1];
 -								//Z
 -								if(accelUncalib[2] > 0)
 -									phid->dataBuffer[phid->bufferWritePtr].acceleration[2] = accelUncalib[2] * phid->accelGain1[2] + accelUncalib[0] * phid->accelFactor1[2] + accelUncalib[1] * phid->accelFactor2[2];
 -								else
 -									phid->dataBuffer[phid->bufferWritePtr].acceleration[2] = accelUncalib[2] * phid->accelGain2[2] + accelUncalib[0] * phid->accelFactor1[2] + accelUncalib[1] * phid->accelFactor2[2];
 -
 -								//ADC ref is 0-3.3V - 50.355uV/bit, gyro zero rate is 1.23V, 2.5mV/deg/s - these voltages are fixed, non-ratiometric to Vref
 -								// 1 / 0.000050355 = 19859 (1V)
 -								// 1.23 * 19859 = 24427
 -								// 0.0025 * 19859 = 49.6477bits/deg/s
 -								for(j=0;j<3;j++)
 -								{
 -									data = ((unsigned short)buffer[10 + j * 2 + i * 18]<<8) + (unsigned short)buffer[11 + j * 2 + i * 18];
 -									if(j==1)
 -										gyroUncalib[j] = ((double)(data-24427) + phid->gyroOffset[j]) / 49.6477;
 -									else
 -										gyroUncalib[j] = ((double)-(data-24427) + phid->gyroOffset[j]) / 49.6477; //reverse X/Z-axis
 -								}
 -								//0 - we multiply these by their gains so revered axes will still appear positive and get the correct gain
 -								if((gyroUncalib[0] * phid->gyroGain1[0]) > 0)
 -									phid->dataBuffer[phid->bufferWritePtr].angularRate[0] = gyroUncalib[0] * phid->gyroGain1[0] - gyroUncalib[1] * phid->gyroFactor1[0] - gyroUncalib[2] * phid->gyroFactor2[0];
 -								else
 -									phid->dataBuffer[phid->bufferWritePtr].angularRate[0] = gyroUncalib[0] * phid->gyroGain2[0] - gyroUncalib[1] * phid->gyroFactor1[0] - gyroUncalib[2] * phid->gyroFactor2[0];
 -								//1
 -								if((gyroUncalib[1] * phid->gyroGain1[1]) > 0)
 -									phid->dataBuffer[phid->bufferWritePtr].angularRate[1] = gyroUncalib[1] * phid->gyroGain1[1] - gyroUncalib[0] * phid->gyroFactor1[1] - gyroUncalib[2] * phid->gyroFactor2[1];
 -								else
 -									phid->dataBuffer[phid->bufferWritePtr].angularRate[1] = gyroUncalib[1] * phid->gyroGain2[1] - gyroUncalib[0] * phid->gyroFactor1[1] - gyroUncalib[2] * phid->gyroFactor2[1];
 -								//2
 -								if((gyroUncalib[2] * phid->gyroGain1[2]) > 0)
 -									phid->dataBuffer[phid->bufferWritePtr].angularRate[2] = gyroUncalib[2] * phid->gyroGain1[2] - gyroUncalib[0] * phid->gyroFactor1[2] - gyroUncalib[1] * phid->gyroFactor2[2];
 -								else
 -									phid->dataBuffer[phid->bufferWritePtr].angularRate[2] = gyroUncalib[2] * phid->gyroGain2[2] - gyroUncalib[0] * phid->gyroFactor1[2] - gyroUncalib[1] * phid->gyroFactor2[2];
 -
 -								//checks if compass data is valid
 -								//Note: we miss ~7 samples (28ms) every second while the compass is callibrating
 -								if(buffer[1] & (0x80 >> i))
 -								{
 -									//ADC 50.355uV/bit (0-3.3V)
 -									//ideal compass midpoint is 0x7FFF (32767) (1.65V) 
 -									//valid range for zero field offset is: 0.825V - 2.475V (16384-49151) (+-16384)
 -									// Note that this may be less (~3x) because the Gain is less, but I'm not sure. (+-5460)
 -									//valid output voltage range is defined as 0.165V - 3.135V (3277-62258), 
 -									// so we can't really trust values outside of this, though we do seem to get valid data...
 -									//ideal sensitivity is 250mV/gauss (ext. resistor), valid range is 195 - 305
 -									// 1 / 0.000050355 = 19859 (1Volt)
 -									// 0.250 * 19859 = 4964.75 bits/gauss (1.0 gain) (ideal) - valid range is (3861-6068) (+-1103)
 -									//We have defined the compass gain multiplier to be based on 6500bits/gauss to keep the math resonable,
 -									// so we must use that value here. Implications?
 -									//The largest range we can guarantee is:
 -									// 16384-3277/6068 = +-2.16 gauss or, more likely: +-3.96 gauss
 -									// Ideal is: 32767-3277/4964.75 = +-5.94 gauss
 -									// we can tell from the incoming data whether it's valid or not, 
 -									// we'll probably have more range in one dirrection then the other because of offset.
 -									for(j=0;j<phid->phid.attr.spatial.numCompassAxes; j++)
 -									{
 -										data = ((unsigned short)buffer[16 + i * 18 + j * 2]<<8) + (unsigned short)buffer[17 + i * 18 + j * 2];
 -										//if we are not within (3277-62258), data is not valid
 -										if(data < 3277)
 -										{
 -											phid->dataBuffer[phid->bufferWritePtr].magneticField[j] = phid->magneticFieldMin;
 -											break;
 -										}
 -										if(data > 62258)
 -										{
 -											phid->dataBuffer[phid->bufferWritePtr].magneticField[j] = phid->magneticFieldMax;
 -											break;
 -										}
 -
 -										//if gain or offset don't make sense, throw out data
 -										//if(phid->compassGain[j] > 6068 || phid->compassGain[j] < 3861 || 
 -										if(phid->compassGain[j] > 6068 || phid->compassGain[j] < 2500 || //lower gains seem to be common
 -											phid->compassOffset[j] > 5460 || phid->compassOffset[j] < -5460)
 -										{
 -											if(data > 32767)
 -												phid->dataBuffer[phid->bufferWritePtr].magneticField[j] = phid->magneticFieldMax;
 -											else
 -												phid->dataBuffer[phid->bufferWritePtr].magneticField[j] = phid->magneticFieldMin;
 -											break;
 -										}
 -
 -										//Convert ADC to Gauss
 -										phid->dataBuffer[phid->bufferWritePtr].magneticField[j] = 
 -											-((double)data - 0x7fff - phid->compassOffset[j]) / phid->compassGain[j];
 -
 -										//constrain to max/min
 -										//ie if field is 4.02 and max is 4.1, make it 4.1, since real max is 4.0
 -										if(phid->dataBuffer[phid->bufferWritePtr].magneticField[j] > (phid->magneticFieldMax - 0.1))
 -											phid->dataBuffer[phid->bufferWritePtr].magneticField[j] = phid->magneticFieldMax;
 -										if(phid->dataBuffer[phid->bufferWritePtr].magneticField[j] < (phid->magneticFieldMin + 0.1))
 -											phid->dataBuffer[phid->bufferWritePtr].magneticField[j] = phid->magneticFieldMin;
 -									}
 -
 -								}
 -								else
 -								{
 -									phid->dataBuffer[phid->bufferWritePtr].magneticField[0] = PUNK_DBL;
 -									phid->dataBuffer[phid->bufferWritePtr].magneticField[1] = PUNK_DBL;
 -									phid->dataBuffer[phid->bufferWritePtr].magneticField[2] = PUNK_DBL;
 -								}
 -
 -								phid->latestDataTime.seconds = phid->timestamp.seconds + (phid->timestamp.microseconds + (i + 1) * phid->dataRateMax * 1000) / 1000000;
 -								phid->latestDataTime.microseconds = (phid->timestamp.microseconds + (i + 1) * phid->dataRateMax * 1000) % 1000000;
 -
 -								phid->dataBuffer[phid->bufferWritePtr].timestamp = phid->latestDataTime;
 -
 -								phid->bufferWritePtr++;
 -								if(phid->bufferWritePtr >= SPATIAL_DATA_BUFFER_SIZE)
 -									phid->bufferWritePtr = 0;
 -							}
 -						}
 -						break;
 -					case SPATIAL_PACKET_CALIB:
 -						for (i = 0; i<phid->phid.attr.spatial.numAccelAxes; i++)
 -						{
 -							cal = ((unsigned short)buffer[i*7 + 1]<<4) + ((unsigned short)buffer[i*7 + 2]>>4);
 -							phid->accelGain1[i] = cal / (4096/0.4) + 0.8;
 -							cal = (((unsigned short)buffer[i*7 + 2]<<8) & 0x0F00) | ((unsigned short)buffer[i*7 + 3]);
 -							phid->accelGain2[i] = cal / (4096/0.4) + 0.8;
 -							cal = (unsigned short)((unsigned short)buffer[i*7 + 4]<<8) + (unsigned short)buffer[i*7 + 5];
 -							phid->accelOffset[i] = cal / (65535 / 1.0) - 0.5;
 -							cal = (unsigned char)buffer[i*7 + 6];
 -							phid->accelFactor1[i] = cal / (256 / 0.2) - 0.1;
 -							cal = (unsigned char)buffer[i*7 + 7];
 -							phid->accelFactor2[i] = cal / (256 / 0.2) - 0.1;
 -							//LOG(PHIDGET_LOG_INFO, "Accel(%d) Calib: %1.4lf, %1.4lf, %1.4lf, %1.4lf, %1.4lf", i, 
 -							//	phid->accelGain1[i], phid->accelGain2[i], phid->accelOffset[i], phid->accelFactor1[i], phid->accelFactor2[i]);
 -						}
 -						for (j=0; j<phid->phid.attr.spatial.numGyroAxes; i++,j++)
 -						{
 -							if (phidG->deviceVersion < 200)
 -							{
 -								cal = ((unsigned short)buffer[i*7 + 1]<<4) + ((unsigned short)buffer[i*7 + 2]>>4);
 -								phid->gyroGain1[j] = cal / (4096/0.4) + 0.8;
 -								cal = (((unsigned short)buffer[i*7 + 2]<<8) & 0x0F00) | ((unsigned short)buffer[i*7 + 3]);
 -								phid->gyroGain2[j] = cal / (4096/0.4) + 0.8;
 -							}
 -							//Allow for negative gains
 -							else if (phidG->deviceVersion >= 200 && phidG->deviceVersion < 300)
 -							{
 -								cal = ((signed short)((signed char)buffer[i*7 + 1])<<4) + ((unsigned short)buffer[i*7 + 2]>>4);
 -								phid->gyroGain1[j] = cal / (4096/0.4) + (cal > 0 ? 0.9 : -0.9);
 -								cal = ((((unsigned short)buffer[i*7 + 2]<<8) & 0x0F00) | ((unsigned short)buffer[i*7 + 3]) ) << 4;
 -								cal = (signed short)cal >> 4;
 -								phid->gyroGain2[j] = cal / (4096/0.4) + (cal > 0 ? 0.9 : -0.9);
 -							}
 -							cal = (signed short)((unsigned short)buffer[i*7 + 4]<<8) + (unsigned short)buffer[i*7 + 5];
 -							phid->gyroOffset[j] = cal;
 -							cal = (unsigned char)buffer[i*7 + 6];
 -							phid->gyroFactor1[j] = cal / (256 / 0.1) - 0.05;
 -							cal = (unsigned char)buffer[i*7 + 7];
 -							phid->gyroFactor2[j] = cal / (256 / 0.1) - 0.05;
 -
 -//Zero out calibrations
 -#if 0
 -							phid->gyroGain1[j] = 1;
 -							phid->gyroGain2[j] = 1;
 -							phid->gyroOffset[j] = 0;
 -							phid->gyroFactor1[j] = 0;
 -							phid->gyroFactor2[j] = 0;
 -#endif
 -
 -							LOG(PHIDGET_LOG_VERBOSE, "Gyro(%d) Calib: %1.4lf, %1.4lf, %1.4lf, %1.4lf, %1.4lf", j, 
 -								phid->gyroGain1[j], phid->gyroGain2[j], phid->gyroOffset[j], phid->gyroFactor1[j], phid->gyroFactor2[j]);
 -						}
 -						for(j=0;j<phid->phid.attr.spatial.numCompassAxes; j++)
 -						{
 -							phid->compassOffset[j] = (signed short)((unsigned short)buffer[j*4 + 49]<<8) + (unsigned short)buffer[j*4 + 50];
 -							phid->compassGain[j] = ((unsigned short)buffer[j*4 + 51]<<8) + (unsigned short)buffer[j*4 + 52];
 -							//phid->compassGain[j] = 4964;
 -						}
 -						//LOG(PHIDGET_LOG_INFO, "Compass Gain: %d, %d, %d", phid->compassGain[0], phid->compassGain[1], phid->compassGain[2]);
 -						//LOG(PHIDGET_LOG_INFO, "Compass Offset: %d, %d, %d", phid->compassOffset[0], phid->compassOffset[1], phid->compassOffset[2]);
 -						phid->calDataValid = PTRUE;
 -						break;
 -				}
 -			}
 -			// 1044 (1056 Replacement) and 1042 (low-cost 3/3/3)
 -			else if (phidG->deviceVersion  >= 300 && phidG->deviceVersion < 500)
 -			{				//top 2 bits in buffer[0] are packet type
 -				switch(buffer[0])
 -				{
 -					case SPATIAL_PACKET_DATA:
 -					{
 -						int data;
 -						int time;
 -						
 -						count = buffer[1] & 0x03;
 -						if(count == 0)
 -							goto done;
 -
 -						//this timestamp is for the latest data
 -						time = ((unsigned short)buffer[2]<<8) + (unsigned short)buffer[3];
 -						//LOG(PHIDGET_LOG_DEBUG, "TimeStamp: %6d",time);
 -						if(phid->lastTimeCounterValid)
 -						{
 -							//1-255 ms
 -							int timechange = (unsigned short)((unsigned short)time - (unsigned short)phid->lastTimeCounter);
 -							timechange *= 1000; //us
 -
 -							if(timechange > 500000)
 -								LOG(PHIDGET_LOG_DEBUG, "Timechange: %d",timechange);
 -
 -							phid->timestamp.seconds = phid->timestamp.seconds + (phid->timestamp.microseconds + timechange) / 1000000;
 -							phid->timestamp.microseconds = (phid->timestamp.microseconds + timechange) % 1000000;
 -						}
 -						else
 -						{
 -							phid->lastTimeCounterValid = PTRUE;
 -						}
 -						phid->lastTimeCounter = time;
 -
 -						//add data to data buffer
 -						for(i=0;i<count;i++)
 -						{
 -							//digital accel
 -							if(buffer[1] & (0x08 >> i))
 -							{
 -								LOG(PHIDGET_LOG_DEBUG, "digital accel");
 -								//+-8g resolution is 1g/1024/bit
 -								for(j=0;j<3;j++)
 -								{
 -									short accelData = 
 -										(signed short)((unsigned short)buffer[4 + j * 2 + i * 18]<<8) + (unsigned short)buffer[5 + j * 2 + i * 18];
 -
 -									if(j==0)
 -										phid->dataBuffer[phid->bufferWritePtr].acceleration[j] = -((double)accelData / 1024.0);
 -									else
 -										phid->dataBuffer[phid->bufferWritePtr].acceleration[j] = (double)accelData / 1024.0;
 -								}
 -							}
 -							//analog accel
 -							else
 -							{
 -								//KXR94-2050 - 660 mV/g (VCC/5) - 0xffff/5 = 0x3333 (13107.0)
 -								for(j=0;j<3;j++)
 -								{
 -									data = ((unsigned short)buffer[4 + j * 2 + i * 18]<<8) + (unsigned short)buffer[5 + j * 2 + i * 18];
 -									if(j==2)
 -										phid->dataBuffer[phid->bufferWritePtr].acceleration[j] = ((double)data - 0x7fff) / 13107;
 -									else
 -										phid->dataBuffer[phid->bufferWritePtr].acceleration[j] = -((double)data - 0x7fff) / 13107;
 -								}
 -								phid->dataBuffer[phid->bufferWritePtr].acceleration[1] = -phid->dataBuffer[phid->bufferWritePtr].acceleration[1]; //reverse Y-axis
 -							}
 -
 -							//digital gyro
 -							if(buffer[1] & (0x20 >> i))
 -							{
 -								LOG(PHIDGET_LOG_DEBUG, "digital gyro");
 -								//2000dps
 -								// 0.07 dps/digit
 -								for(j=0;j<3;j++)
 -								{
 -									short gyroData = 
 -										(signed short)((unsigned short)buffer[10 + j * 2 + i * 18]<<8) + (unsigned short)buffer[11 + j * 2 + i * 18];
 -
 -									phid->dataBuffer[phid->bufferWritePtr].angularRate[j] = (double)gyroData * 0.07;
 -								}
 -							}
 -							//analog gyro
 -							else
 -							{
 -								//ADC ref is 0-3.3V - 50.355uV/bit, gyro zero rate is 1.5V, X/Y: 2.5mV/deg/s Z: 3.572mV/deg/s
 -								// these voltages are fixed, non-ratiometric to Vref
 -								// 1 / 0.000050355 = 19859 (1V)
 -								// 1.5 * 19859 = 29789
 -								// 0.0025 * 19859 = 49.6477bits/deg/s
 -								// 0.003572 * 19859 = 70.936348bits/deg/s
 -								for(j=0;j<3;j++)
 -								{
 -									data = ((unsigned short)buffer[10 + j * 2 + i * 18]<<8) + (unsigned short)buffer[11 + j * 2 + i * 18];
 -									if(j==0)
 -										phid->dataBuffer[phid->bufferWritePtr].angularRate[j] = ((double)-(data-29789)) / 49.6477; //reverse X-axis
 -									else if(j==2)
 -										phid->dataBuffer[phid->bufferWritePtr].angularRate[j] = ((double)-(data-29789)) / 70.936348; //reverse Z-axis
 -									else
 -										phid->dataBuffer[phid->bufferWritePtr].angularRate[j] = ((double)(data-29789)) / 49.6477;
 -								}
 -							}
 -
 -							//LOG(PHIDGET_LOG_DEBUG, "ADC Values: %1.3lf, %1.3lf, %1.3lf, %1.3lf, %1.3lf, %1.3lf", dataTrack[0], dataTrack[1], dataTrack[2], dataTrack[3], dataTrack[4], dataTrack[5]);
 -
 -							//checks if compass data is valid
 -							if(buffer[1] & (0x80 >> i))
 -							{
 -								for(j=0;j<phid->phid.attr.spatial.numCompassAxes; j++)
 -								{
 -									short magData = 
 -										(signed short)((unsigned short)buffer[16 + i * 18 + j * 2]<<8) + (unsigned short)buffer[17 + i * 18 + j * 2];
 -
 -									//each bit is 0.1 uT
 -
 -
 -									//Convert to Gauss (divide by 1000)
 -									if(j==1)
 -										phid->dataBuffer[phid->bufferWritePtr].magneticField[j] = -(magData / 1000.0);
 -									else
 -										phid->dataBuffer[phid->bufferWritePtr].magneticField[j] = magData / 1000.0;
 -
 -									//constrain to max/min
 -									//ie if field is 4.02 and max is 4.1, make it 4.1, since real max is 4.0
 -									if(phid->dataBuffer[phid->bufferWritePtr].magneticField[j] > (phid->magneticFieldMax - 0.1))
 -										phid->dataBuffer[phid->bufferWritePtr].magneticField[j] = phid->magneticFieldMax;
 -									if(phid->dataBuffer[phid->bufferWritePtr].magneticField[j] < (phid->magneticFieldMin + 0.1))
 -										phid->dataBuffer[phid->bufferWritePtr].magneticField[j] = phid->magneticFieldMin;
 -								}
 -
 -							}
 -							else
 -							{
 -								phid->dataBuffer[phid->bufferWritePtr].magneticField[0] = PUNK_DBL;
 -								phid->dataBuffer[phid->bufferWritePtr].magneticField[1] = PUNK_DBL;
 -								phid->dataBuffer[phid->bufferWritePtr].magneticField[2] = PUNK_DBL;
 -							}
 -
 -							phid->latestDataTime.seconds = phid->timestamp.seconds + (phid->timestamp.microseconds + (i + 1) * phid->dataRateMax * 1000) / 1000000;
 -							phid->latestDataTime.microseconds = (phid->timestamp.microseconds + (i + 1) * phid->dataRateMax * 1000) % 1000000;
 -
 -							//LOG(PHIDGET_LOG_DEBUG, "Time: %d:%d",phid->latestDataTime.seconds,phid->latestDataTime.microseconds);
 -
 -							phid->dataBuffer[phid->bufferWritePtr].timestamp = phid->latestDataTime;
 -
 -							phid->bufferWritePtr++;
 -							if(phid->bufferWritePtr >= SPATIAL_DATA_BUFFER_SIZE)
 -								phid->bufferWritePtr = 0;
 -						}
 -
 -						break;
 -					}
 -				}
 -			}
 -			else
 -				return EPHIDGET_UNEXPECTED;
 -			break;
 -		default:
 -			return EPHIDGET_UNEXPECTED;
 -	}
 -
 -	if(phid->doZeroGyro)
 -	{
 -		//done
 -		if(timestampdiff(phid->latestDataTime, phid->dataBuffer[phid->gyroZeroReadPtr].timestamp) >= SPATIAL_ZERO_GYRO_TIME)
 -		{
 -			double gryoCorrectionTemp[SPATIAL_MAX_GYROAXES] = {0,0,0};
 -			int gryoCorrectionCount = 0;
 -
 -			while(phid->gyroZeroReadPtr != phid->bufferWritePtr)
 -			{
 -				for (i = 0; i<phid->phid.attr.spatial.numGyroAxes; i++)
 -				{
 -					gryoCorrectionTemp[i] += phid->dataBuffer[phid->gyroZeroReadPtr].angularRate[i];
 -				}
 -
 -				phid->gyroZeroReadPtr++;
 -				if(phid->gyroZeroReadPtr >= SPATIAL_DATA_BUFFER_SIZE)
 -					phid->gyroZeroReadPtr = 0;
 -
 -				gryoCorrectionCount++;
 -			}
 -			
 -			for (i = 0; i<phid->phid.attr.spatial.numGyroAxes; i++)
 -			{
 -				phid->gryoCorrection[i] = gryoCorrectionTemp[i] / (double)gryoCorrectionCount;
 -			}
 -
 -			doneGyroZero = PTRUE;
 -		}
 -	}
 -
 -	//see if it's time for an event
 -	if(timestampdiff(phid->latestDataTime, phid->lastEventTime) >= dataRate)
 -	{
 -		CPhidget_Timestamp tempTime;
 -		//int lastPtr;
 -		int accelCounter[SPATIAL_MAX_ACCELAXES], angularRateCounter[SPATIAL_MAX_ACCELAXES], magneticFieldCounter[SPATIAL_MAX_ACCELAXES];
 -
 -		int dataPerEvent = 0;
 -
 -		int multipleDataPerEvent = PFALSE;
 -
 -		if(dataRate < phid->interruptRate)
 -			multipleDataPerEvent = PTRUE;
 -
 -		//max of 16 data per event
 -		eventData = malloc(16 * sizeof(CPhidgetSpatial_SpatialEventDataHandle));
 -		
 -		for(j=0;;j++)
 -		{
 -			//makes sure we read all data
 -			if(phid->bufferReadPtr == phid->bufferWritePtr || j>=16)
 -			{
 -				dataPerEvent = j;
 -				break;
 -			}
 -
 -			eventData[j] = malloc(sizeof(CPhidgetSpatial_SpatialEventData));
 -			ZEROMEM(accelCounter, sizeof(accelCounter));
 -			ZEROMEM(angularRateCounter, sizeof(angularRateCounter));
 -			ZEROMEM(magneticFieldCounter, sizeof(magneticFieldCounter));
 -
 -			tempTime = phid->dataBuffer[phid->bufferReadPtr].timestamp;
 -
 -			//average data for each stage
 -			while(phid->bufferReadPtr != phid->bufferWritePtr && 
 -				(!multipleDataPerEvent || timestampdiff(phid->dataBuffer[phid->bufferReadPtr].timestamp, tempTime) < dataRate))
 -			{
 -				for (i = 0; i<phid->phid.attr.spatial.numAccelAxes; i++)
 -				{
 -					if(phid->dataBuffer[phid->bufferReadPtr].acceleration[i] != PUNK_DBL)
 -					{
 -						if(phid->dataBuffer[phid->bufferReadPtr].acceleration[i] > phid->accelerationMax)
 -							phid->dataBuffer[phid->bufferReadPtr].acceleration[i] = phid->accelerationMax;
 -						if(phid->dataBuffer[phid->bufferReadPtr].acceleration[i] < phid->accelerationMin) 
 -							phid->dataBuffer[phid->bufferReadPtr].acceleration[i] = phid->accelerationMin;
 -						accelAvg[i] += phid->dataBuffer[phid->bufferReadPtr].acceleration[i];
 -						accelCounter[i]++;
 -					}
 -				}
 -				for (i = 0; i<phid->phid.attr.spatial.numGyroAxes; i++)
 -				{
 -					if(phid->dataBuffer[phid->bufferReadPtr].angularRate[i] != PUNK_DBL)
 -					{
 -						double rate = phid->dataBuffer[phid->bufferReadPtr].angularRate[i] - phid->gryoCorrection[i];
 -
 -						if(rate > phid->angularRateMax) 
 -							angularRateAvg[i] += phid->angularRateMax;
 -						else if(rate < phid->angularRateMin) 
 -							angularRateAvg[i] += phid->angularRateMin;
 -						else
 -							angularRateAvg[i] += rate;
 -						angularRateCounter[i]++;
 -					}
 -				}
 -				for (i = 0; i<phid->phid.attr.spatial.numCompassAxes; i++)
 -				{
 -					if(phid->dataBuffer[phid->bufferReadPtr].magneticField[i] != PUNK_DBL)
 -					{
 -						if(phid->dataBuffer[phid->bufferReadPtr].magneticField[i] > phid->magneticFieldMax) 
 -							phid->dataBuffer[phid->bufferReadPtr].magneticField[i] = phid->magneticFieldMax;
 -						if(phid->dataBuffer[phid->bufferReadPtr].magneticField[i] < phid->magneticFieldMin) 
 -							phid->dataBuffer[phid->bufferReadPtr].magneticField[i] = phid->magneticFieldMin;
 -						magneticFieldAvg[i] += phid->dataBuffer[phid->bufferReadPtr].magneticField[i];
 -						magneticFieldCounter[i]++;
 -					}
 -				}
 -
 -				//lastPtr = phid->bufferReadPtr;
 -
 -				phid->bufferReadPtr++;
 -				if(phid->bufferReadPtr >= SPATIAL_DATA_BUFFER_SIZE)
 -					phid->bufferReadPtr = 0;
 -			}
 -
 -			for (i = 0; i<phid->phid.attr.spatial.numAccelAxes; i++)
 -			{
 -				if(accelCounter[i] > 0)
 -					eventData[j]->acceleration[i] = round_double(accelAvg[i] / (double)accelCounter[i], 5);
 -				else
 -					eventData[j]->acceleration[i] = PUNK_DBL;
 -				accelAvg[i] = 0;
 -			}
 -			for (i = 0; i<phid->phid.attr.spatial.numGyroAxes; i++)
 -			{
 -				if(angularRateCounter[i] > 0)
 -				{
 -					if(phid->doZeroGyro && !doneGyroZero)
 -						eventData[j]->angularRate[i] = 0;
 -					else
 -						eventData[j]->angularRate[i] = round_double(angularRateAvg[i] / (double)angularRateCounter[i], 5);
 -				}
 -				else
 -					eventData[j]->angularRate[i] = PUNK_DBL;
 -				angularRateAvg[i] = 0;
 -			}
 -			for (i = 0; i<phid->phid.attr.spatial.numCompassAxes; i++)
 -			{
 -				if(magneticFieldCounter[i] > 0)
 -					eventData[j]->magneticField[i] = round_double(magneticFieldAvg[i] / (double)magneticFieldCounter[i], 5);
 -				else
 -					eventData[j]->magneticField[i] = PUNK_DBL;
 -				magneticFieldAvg[i] = 0;
 -			}
 -			eventData[j]->timestamp = tempTime;
 -		}
 -
 -		//correct magnetic field data in the event structure
 -		for( j = 0; j < dataPerEvent; j++)
 -		{
 -			for (i = 0; i<phid->phid.attr.spatial.numCompassAxes; i++)
 -			{
 -				magneticFieldCorr[i] = eventData[j]->magneticField[i];
 -			}
 -			for (i = 0; i<phid->phid.attr.spatial.numCompassAxes; i++)
 -			{
 -				if(eventData[j]->magneticField[i] != PUNK_DBL)
 -				{
 -					eventData[j]->magneticField[i] = getCorrectedField(phid, magneticFieldCorr, i);
 -				}
 -			}
 -		}
 -
 -		//store to local structure
 -		ZEROMEM(accelCounter, sizeof(accelCounter));
 -		ZEROMEM(angularRateCounter, sizeof(angularRateCounter));
 -		ZEROMEM(magneticFieldCounter, sizeof(magneticFieldCounter));
 -		for( j = 0; j < dataPerEvent; j++)
 -		{
 -			for (i = 0; i<phid->phid.attr.spatial.numAccelAxes; i++)
 -			{
 -				if(eventData[j]->acceleration[i] != PUNK_DBL)
 -				{
 -					accelAvg[i] += eventData[j]->acceleration[i];
 -					accelCounter[i]++;
 -				}
 -			}
 -			for (i = 0; i<phid->phid.attr.spatial.numGyroAxes; i++)
 -			{
 -				if(eventData[j]->angularRate[i] != PUNK_DBL)
 -				{
 -					angularRateAvg[i] += eventData[j]->angularRate[i];
 -					angularRateCounter[i]++;
 -				}
 -			}
 -			for (i = 0; i<phid->phid.attr.spatial.numCompassAxes; i++)
 -			{
 -				if(eventData[j]->magneticField[i] != PUNK_DBL)
 -				{
 -					magneticFieldAvg[i] += eventData[j]->magneticField[i];
 -					magneticFieldCounter[i]++;
 -				}
 -			}
 -		}
 -
 -		//Set local get data to averages
 -		for (i = 0; i<phid->phid.attr.spatial.numAccelAxes; i++)
 -		{
 -			if(accelCounter[i] > 0)
 -				phid->accelAxis[i] = round_double(accelAvg[i] / (double)accelCounter[i], 5);
 -			else
 -				phid->accelAxis[i] = PUNK_DBL;
 -		}
 -		for (i = 0; i<phid->phid.attr.spatial.numGyroAxes; i++)
 -		{
 -			if(angularRateCounter[i] > 0)
 -			{
 -				if(phid->doZeroGyro && !doneGyroZero)
 -					phid->gyroAxis[i] = 0;
 -				else
 -					phid->gyroAxis[i] = round_double(angularRateAvg[i] / (double)angularRateCounter[i], 5);
 -			}
 -			else
 -				phid->gyroAxis[i] = PUNK_DBL;
 -		}
 -		for (i = 0; i<phid->phid.attr.spatial.numCompassAxes; i++)
 -		{
 -			if(magneticFieldCounter[i] > 0)
 -				phid->compassAxis[i] = round_double(magneticFieldAvg[i] / (double)magneticFieldCounter[i], 5);
 -			else
 -				phid->compassAxis[i] = PUNK_DBL;
 -		}
 -		
 -		//send out any events
 -		FIRE(SpatialData, eventData, dataPerEvent);
 -
 -		phid->lastEventTime = phid->latestDataTime;
 -
 -		for(i=0;i<dataPerEvent;i++)
 -			free(eventData[i]);
 -		free(eventData);
 -	}
 -done:
 -
 -	//this will signal the zero function to return;
 -	if(doneGyroZero)
 -		phid->doZeroGyro = PFALSE;
 -
 -	return EPHIDGET_OK;
 -}
 -
 -//eventsAfterOpen - sends out an event for all valid data, used during attach initialization
 -CPHIDGETINITEVENTS(Spatial)
 -	TESTPTR(phid);
 -	//don't need to worry, because the interrupts come at a set rate
 -	return EPHIDGET_OK;
 -}
 -
 -//getPacket - not used for spatial
 -CGETPACKET(Spatial)
 -	return EPHIDGET_UNEXPECTED;
 -}
 -
 -static double getCorrectedField(CPhidgetSpatialHandle phid, double fields[], int axis)
 -{
 -	switch(axis)
 -	{
 -	case 0:
 -		return phid->userMagField * 
 -			(phid->userCompassGain[0] * (fields[0] - phid->userCompassOffset[0])
 -			+ phid->userCompassTransform[0] * (fields[1] - phid->userCompassOffset[1])
 -			+ phid->userCompassTransform[1] * (fields[2] - phid->userCompassOffset[2]));
 -	case 1:
 -		return phid->userMagField * 
 -			(phid->userCompassGain[1] * (fields[1] - phid->userCompassOffset[1])
 -			+ phid->userCompassTransform[2] * (fields[0] - phid->userCompassOffset[0])
 -			+ phid->userCompassTransform[3] * (fields[2] - phid->userCompassOffset[2]));
 -	case 2:
 -		return phid->userMagField * 
 -			(phid->userCompassGain[2] * (fields[2] - phid->userCompassOffset[2])
 -			+ phid->userCompassTransform[4] * (fields[0] - phid->userCompassOffset[0])
 -			+ phid->userCompassTransform[5] * (fields[1] - phid->userCompassOffset[1]));
 -	default:
 -		return 0;
 -	}
 -}
 -
 -// === Exported Functions === //
 -
 -//create and initialize a device structure
 -CCREATE(Spatial, PHIDCLASS_SPATIAL)
 -
 -//event setup functions
 -CFHANDLE(Spatial, SpatialData, CPhidgetSpatial_SpatialEventDataHandle *, int)
 -
 -CGET(Spatial,AccelerationAxisCount,int)
 -	TESTPTRS(phid,pVal) 
 -	TESTDEVICETYPE(PHIDCLASS_SPATIAL)
 -	TESTATTACHED
 -
 -	MASGN(phid.attr.spatial.numAccelAxes)
 -}
 -CGET(Spatial,GyroAxisCount,int)
 -	TESTPTRS(phid,pVal) 
 -	TESTDEVICETYPE(PHIDCLASS_SPATIAL)
 -	TESTATTACHED
 -
 -	MASGN(phid.attr.spatial.numGyroAxes)
 -}
 -CGET(Spatial,CompassAxisCount,int)
 -	TESTPTRS(phid,pVal) 
 -	TESTDEVICETYPE(PHIDCLASS_SPATIAL)
 -	TESTATTACHED
 -
 -	MASGN(phid.attr.spatial.numCompassAxes)
 -}
 -
 -CGETINDEX(Spatial,Acceleration,double)
 -	TESTPTRS(phid,pVal) 	
 -	TESTDEVICETYPE(PHIDCLASS_SPATIAL)
 -	TESTATTACHED
 -	TESTINDEX(phid.attr.spatial.numAccelAxes)
 -	TESTMASGN(accelAxis[Index], PUNK_DBL)
 -
 -	MASGN(accelAxis[Index])
 -}
 -
 -CGETINDEX(Spatial,AccelerationMax,double)
 -	TESTPTRS(phid,pVal) 	
 -	TESTDEVICETYPE(PHIDCLASS_SPATIAL)
 -	TESTATTACHED
 -	TESTINDEX(phid.attr.spatial.numAccelAxes)
 -	TESTMASGN(accelerationMax, PUNK_DBL)
 -
 -	MASGN(accelerationMax)
 -}
 -
 -CGETINDEX(Spatial,AccelerationMin,double)
 -	TESTPTRS(phid,pVal) 	
 -	TESTDEVICETYPE(PHIDCLASS_SPATIAL)
 -	TESTATTACHED
 -	TESTINDEX(phid.attr.spatial.numAccelAxes)
 -	TESTMASGN(accelerationMin, PUNK_DBL)
 -
 -	MASGN(accelerationMin)
 -}
 -
 -CGETINDEX(Spatial,AngularRate,double)
 -	TESTPTRS(phid,pVal) 	
 -	TESTDEVICETYPE(PHIDCLASS_SPATIAL)
 -	TESTATTACHED
 -
 -	switch(phid->phid.deviceIDSpec)
 -	{
 -		case PHIDID_SPATIAL_ACCEL_GYRO_COMPASS:
 -			TESTINDEX(phid.attr.spatial.numGyroAxes)
 -			TESTMASGN(gyroAxis[Index], PUNK_DBL)
 -			MASGN(gyroAxis[Index])
 -		case PHIDID_SPATIAL_ACCEL_3AXIS:
 -		default:
 -			return EPHIDGET_UNSUPPORTED;
 -	}
 -}
 -
 -CGETINDEX(Spatial,AngularRateMax,double)
 -	TESTPTRS(phid,pVal) 	
 -	TESTDEVICETYPE(PHIDCLASS_SPATIAL)
 -	TESTATTACHED
 -
 -	switch(phid->phid.deviceIDSpec)
 -	{
 -		case PHIDID_SPATIAL_ACCEL_GYRO_COMPASS:
 -			TESTINDEX(phid.attr.spatial.numGyroAxes)
 -			TESTMASGN(angularRateMax, PUNK_DBL)
 -			MASGN(angularRateMax)
 -		case PHIDID_SPATIAL_ACCEL_3AXIS:
 -		default:
 -			return EPHIDGET_UNSUPPORTED;
 -	}
 -}
 -
 -CGETINDEX(Spatial,AngularRateMin,double)
 -	TESTPTRS(phid,pVal) 	
 -	TESTDEVICETYPE(PHIDCLASS_SPATIAL)
 -	TESTATTACHED
 -
 -	switch(phid->phid.deviceIDSpec)
 -	{
 -		case PHIDID_SPATIAL_ACCEL_GYRO_COMPASS:
 -			TESTINDEX(phid.attr.spatial.numGyroAxes)
 -			TESTMASGN(angularRateMin, PUNK_DBL)
 -			MASGN(angularRateMin)
 -		case PHIDID_SPATIAL_ACCEL_3AXIS:
 -		default:
 -			return EPHIDGET_UNSUPPORTED;
 -	}
 -}
 -
 -CGETINDEX(Spatial,MagneticField,double)
 -	TESTPTRS(phid,pVal) 	
 -	TESTDEVICETYPE(PHIDCLASS_SPATIAL)
 -	TESTATTACHED
 -
 -	switch(phid->phid.deviceIDSpec)
 -	{
 -		case PHIDID_SPATIAL_ACCEL_GYRO_COMPASS:
 -			TESTINDEX(phid.attr.spatial.numCompassAxes)
 -			TESTMASGN(compassAxis[Index], PUNK_DBL)
 -			MASGN(compassAxis[Index])
 -		case PHIDID_SPATIAL_ACCEL_3AXIS:
 -		default:
 -			return EPHIDGET_UNSUPPORTED;
 -	}
 -}
 -
 -CGETINDEX(Spatial,MagneticFieldMax,double)
 -	TESTPTRS(phid,pVal) 	
 -	TESTDEVICETYPE(PHIDCLASS_SPATIAL)
 -	TESTATTACHED
 -
 -	switch(phid->phid.deviceIDSpec)
 -	{
 -		case PHIDID_SPATIAL_ACCEL_GYRO_COMPASS:
 -			TESTINDEX(phid.attr.spatial.numCompassAxes)
 -			TESTMASGN(magneticFieldMax, PUNK_DBL)
 -			MASGN(magneticFieldMax)
 -		case PHIDID_SPATIAL_ACCEL_3AXIS:
 -		default:
 -			return EPHIDGET_UNSUPPORTED;
 -	}
 -}
 -
 -CGETINDEX(Spatial,MagneticFieldMin,double)
 -	TESTPTRS(phid,pVal) 	
 -	TESTDEVICETYPE(PHIDCLASS_SPATIAL)
 -	TESTATTACHED
 -
 -	switch(phid->phid.deviceIDSpec)
 -	{
 -		case PHIDID_SPATIAL_ACCEL_GYRO_COMPASS:
 -			TESTINDEX(phid.attr.spatial.numCompassAxes)
 -			TESTMASGN(magneticFieldMin, PUNK_DBL)
 -			MASGN(magneticFieldMin)
 -		case PHIDID_SPATIAL_ACCEL_3AXIS:
 -		default:
 -			return EPHIDGET_UNSUPPORTED;
 -	}
 -}
 -
 -CSET(Spatial,DataRate,int)
 -	TESTPTR(phid)
 -	TESTDEVICETYPE(PHIDCLASS_SPATIAL)
 -	TESTATTACHED
 -	TESTRANGE(phid->dataRateMax, phid->dataRateMin)
 -
 -	//make sure it's a power of 2, or 1
 -	if(newVal < phid->interruptRate)
 -	{
 -		int temp = phid->dataRateMax;
 -		unsigned char good = FALSE;
 -		while(temp <= newVal)
 -		{
 -			if(temp == newVal)
 -			{
 -				good = TRUE;
 -				break;
 -			}
 -			temp *= 2;
 -		}
 -		if(!good)
 -			return EPHIDGET_INVALIDARG;
 -	}
 -	//make sure it's divisible by interruptRate
 -	else
 -	{
 -		if(newVal%phid->interruptRate)
 -			return EPHIDGET_INVALIDARG;
 -	}
 -
 -	if(CPhidget_statusFlagIsSet(phid->phid.status, PHIDGET_REMOTE_FLAG))
 -		ADDNETWORKKEY(DataRate, "%d", dataRate);
 -	else
 -		phid->dataRate = newVal;
 -
 -	return EPHIDGET_OK;
 -}
 -CGET(Spatial,DataRate,int)
 -	TESTPTRS(phid,pVal) 	
 -	TESTDEVICETYPE(PHIDCLASS_SPATIAL)
 -	TESTATTACHED
 -	TESTMASGN(dataRate, PUNK_INT)
 -
 -	MASGN(dataRate)
 -}
 -
 -CGET(Spatial,DataRateMax,int)
 -	TESTPTRS(phid,pVal) 	
 -	TESTDEVICETYPE(PHIDCLASS_SPATIAL)
 -	TESTATTACHED
 -	TESTMASGN(dataRateMax, PUNK_INT)
 -
 -	MASGN(dataRateMax)
 -}
 -
 -CGET(Spatial,DataRateMin,int)
 -	TESTPTRS(phid,pVal) 	
 -	TESTDEVICETYPE(PHIDCLASS_SPATIAL)
 -	TESTATTACHED
 -	TESTMASGN(dataRateMin, PUNK_INT)
 -
 -	MASGN(dataRateMin)
 -}
 -
 -PHIDGET21_API int CCONV CPhidgetSpatial_zeroGyro(CPhidgetSpatialHandle phid)
 -{
 -	TESTPTR(phid) 
 -	TESTDEVICETYPE(PHIDCLASS_SPATIAL)
 -	TESTATTACHED
 -	if(phid->phid.attr.spatial.numGyroAxes==0)
 -		return EPHIDGET_UNSUPPORTED;
 -
 -	if(CPhidget_statusFlagIsSet(phid->phid.status, PHIDGET_REMOTE_FLAG))
 -	{
 -		int newVal = phid->flip^1;
 -		ADDNETWORKKEY(ZeroGyro, "%d", flip);
 -	}
 -	else
 -	{
 -		if(!phid->doZeroGyro)
 -		{
 -			phid->gyroZeroReadPtr = phid->bufferReadPtr;
 -			phid->doZeroGyro = PTRUE;
 -		}
 -	}
 -
 -	return EPHIDGET_OK;
 -}
 -
 -PHIDGET21_API int CCONV CPhidgetSpatial_resetCompassCorrectionParameters(
 -	CPhidgetSpatialHandle phid)
 -{
 -	TESTPTR(phid) 	
 -	TESTDEVICETYPE(PHIDCLASS_SPATIAL)
 -	TESTATTACHED
 -
 -	switch(phid->phid.deviceIDSpec)
 -	{
 -		case PHIDID_SPATIAL_ACCEL_GYRO_COMPASS:
 -			if(CPhidget_statusFlagIsSet(phid->phid.status, PHIDGET_REMOTE_FLAG))
 -			{
 -				char newVal[1024];
 -				sprintf(newVal, "1,0,0,0,1,1,1,0,0,0,0,0,0");
 -				ADDNETWORKKEY(CompassCorrectionParams, "%s", compassCorrectionParamsString);
 -			}
 -			else
 -			{
 -				phid->userMagField = 1;
 -
 -				phid->userCompassOffset[0] = 0;
 -				phid->userCompassOffset[1] = 0;
 -				phid->userCompassOffset[2] = 0;
 -
 -				phid->userCompassGain[0] = 1;
 -				phid->userCompassGain[1] = 1;
 -				phid->userCompassGain[2] = 1;
 -
 -				phid->userCompassTransform[0] = 0;
 -				phid->userCompassTransform[1] = 0;
 -				phid->userCompassTransform[2] = 0;
 -				phid->userCompassTransform[3] = 0;
 -				phid->userCompassTransform[4] = 0;
 -				phid->userCompassTransform[5] = 0;
 -			}
 -			return EPHIDGET_OK;
 -		case PHIDID_SPATIAL_ACCEL_3AXIS:
 -		default:
 -			return EPHIDGET_UNSUPPORTED;
 -	}
 -}
 -PHIDGET21_API int CCONV CPhidgetSpatial_setCompassCorrectionParameters(
 -	CPhidgetSpatialHandle phid, 
 -	double magField, 
 -	double offset0, double offset1, double offset2, 
 -	double gain0, double gain1, double gain2, 
 -	double T0, double T1, double T2, double T3, double T4, double T5)
 -{
 -	TESTPTR(phid) 	
 -	TESTDEVICETYPE(PHIDCLASS_SPATIAL)
 -	TESTATTACHED
 -
 -	switch(phid->phid.deviceIDSpec)
 -	{
 -		case PHIDID_SPATIAL_ACCEL_GYRO_COMPASS:
 -			//Magnetic Field 0.1-1000
 -			if(magField < 0.1 || magField > 1000)
 -				return EPHIDGET_INVALIDARG;
 -			//Offsets need to be 0+-5.0
 -			if(offset0 < -5 || offset0 > 5)
 -				return EPHIDGET_INVALIDARG;
 -			if(offset1 < -5 || offset1 > 5)
 -				return EPHIDGET_INVALIDARG;
 -			if(offset2 < -5 || offset2 > 5)
 -				return EPHIDGET_INVALIDARG;
 -			//Gains need to be 0-15.0
 -			if(gain0 < 0 || gain0 > 15)
 -				return EPHIDGET_INVALIDARG;
 -			if(gain1 < 0 || gain1 > 15)
 -				return EPHIDGET_INVALIDARG;
 -			if(gain2 < 0 || gain2 > 15)
 -				return EPHIDGET_INVALIDARG;
 -			//T params 0+-5.0
 -			if(T0 < -5 || T0 > 5)
 -				return EPHIDGET_INVALIDARG;
 -			if(T1 < -5 || T1 > 5)
 -				return EPHIDGET_INVALIDARG;
 -			if(T2 < -5 || T2 > 5)
 -				return EPHIDGET_INVALIDARG;
 -			if(T3 < -5 || T3 > 5)
 -				return EPHIDGET_INVALIDARG;
 -			if(T4 < -5 || T4 > 5)
 -				return EPHIDGET_INVALIDARG;
 -			if(T5 < -5 || T5 > 5)
 -				return EPHIDGET_INVALIDARG;
 -
 -			if(CPhidget_statusFlagIsSet(phid->phid.status, PHIDGET_REMOTE_FLAG))
 -			{
 -				char newVal[1024];
 -				sprintf(newVal, "%lE,%lE,%lE,%lE,%lE,%lE,%lE,%lE,%lE,%lE,%lE,%lE,%lE",
 -					magField, offset0, offset1, offset2, gain0, gain1, gain2, T0, T1, T2, T3, T4, T5);
 -				ADDNETWORKKEY(CompassCorrectionParams, "%s", compassCorrectionParamsString);
 -			}
 -			else
 -			{
 -				phid->userMagField = magField;
 -
 -				phid->userCompassOffset[0] = offset0;
 -				phid->userCompassOffset[1] = offset1;
 -				phid->userCompassOffset[2] = offset2;
 -
 -				phid->userCompassGain[0] = gain0;
 -				phid->userCompassGain[1] = gain1;
 -				phid->userCompassGain[2] = gain2;
 -
 -				phid->userCompassTransform[0] = T0;
 -				phid->userCompassTransform[1] = T1;
 -				phid->userCompassTransform[2] = T2;
 -				phid->userCompassTransform[3] = T3;
 -				phid->userCompassTransform[4] = T4;
 -				phid->userCompassTransform[5] = T5;
 -			}
 -
 -			return EPHIDGET_OK;
 -		case PHIDID_SPATIAL_ACCEL_3AXIS:
 -		default:
 -			return EPHIDGET_UNSUPPORTED;
 -	}
 -}
 -
 -//Maybe add these later
 -/*
 -CGET(Spatial,GyroHeading,double)
 -	TESTPTRS(phid,pVal) 	
 -	TESTDEVICETYPE(PHIDCLASS_SPATIAL)
 -	TESTATTACHED
 -	TESTMASGN(gyroHeading, PUNK_DBL)
 -
 -	MASGN(gyroHeading)
 -}
 -
 -CGET(Spatial,CompassHeading,double)
 -	TESTPTRS(phid,pVal) 	
 -	TESTDEVICETYPE(PHIDCLASS_SPATIAL)
 -	TESTATTACHED
 -	TESTMASGN(compassHeading, PUNK_DBL)
 -
 -	MASGN(compassHeading)
 -}*/
 +#include "stdafx.h" +#include "cphidgetspatial.h" +#include "cusb.h" +#include "math.h" +#include "csocket.h" +#include "cthread.h" + +// === Internal Functions === // +static double getCorrectedField(CPhidgetSpatialHandle phid, double fields[], int axis); + +//clearVars - sets all device variables to unknown state +CPHIDGETCLEARVARS(Spatial) +	int i = 0; + +	phid->dataRateMin = PUNI_INT; +	phid->dataRate = PUNI_INT; +	phid->dataRateMax = PUNI_INT; + +	phid->accelerationMax = PUNI_DBL; +	phid->accelerationMin = PUNI_DBL; +	phid->angularRateMax = PUNI_DBL; +	phid->angularRateMin = PUNI_DBL; +	phid->magneticFieldMax = PUNI_DBL; +	phid->magneticFieldMin = PUNI_DBL; +	phid->interruptRate = PUNI_INT; + +	phid->spatialDataNetwork = PUNI_BOOL; + +	for (i = 0; i<SPATIAL_MAX_ACCELAXES; i++) +	{ +		phid->accelAxis[i] = PUNI_DBL; +	} +	for (i = 0; i<SPATIAL_MAX_GYROAXES; i++) +	{ +		phid->gyroAxis[i] = PUNI_DBL; +	} +	for (i = 0; i<SPATIAL_MAX_COMPASSAXES; i++) +	{ +		phid->compassAxis[i] = PUNI_DBL; +	} +	return EPHIDGET_OK; +} + +//initAfterOpen - sets up the initial state of an object, reading in packets from the device if needed +//				  used during attach initialization - on every attach +CPHIDGETINIT(Spatial) +	int i = 0; + +	TESTPTR(phid); + +	//Setup max/min values +	switch(phid->phid.deviceUID) +	{ +		case PHIDUID_SPATIAL_ACCEL_3AXIS_1049: +			phid->accelerationMax = 5.1; +			phid->accelerationMin = -5.1; +			phid->interruptRate = 8; +			phid->dataRateMin = SPATIAL_MIN_DATA_RATE; +			phid->dataRate = phid->interruptRate; +			phid->dataRateMax = 1; //actual data rate +			phid->angularRateMax = 0; +			phid->angularRateMin = 0; +			phid->magneticFieldMax = 0; +			phid->magneticFieldMin = 0; +			phid->calDataValid = PFALSE; +			break; + +		case PHIDUID_SPATIAL_ACCEL_3AXIS_1041: +		case PHIDUID_SPATIAL_ACCEL_3AXIS_1043: +			phid->accelerationMax = 8.1; +			phid->accelerationMin = -8.1; +			phid->interruptRate = 8; +			phid->dataRateMin = SPATIAL_MIN_DATA_RATE; +			phid->dataRate = phid->interruptRate; +			phid->dataRateMax = 1; //actual data rate +			phid->angularRateMax = 0; +			phid->angularRateMin = 0; +			phid->magneticFieldMax = 0; +			phid->magneticFieldMin = 0; +			phid->calDataValid = PFALSE; +			break; + +		case PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1056: +		case PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1056_NEG_GAIN: +			phid->accelerationMax = 5.1; +			phid->accelerationMin = -5.1; +			phid->interruptRate = 8; +			phid->dataRateMin = SPATIAL_MIN_DATA_RATE; +			phid->dataRate = phid->interruptRate; +			phid->dataRateMax = 4; //actual data rate +			phid->angularRateMax = 400.1; +			phid->angularRateMin = -400.1; +			phid->magneticFieldMax = 4.1; +			phid->magneticFieldMin = -4.1; +			phid->userMagField = 1.0; +			phid->calDataValid = PFALSE; +			break; + +		case PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1042: +		case PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1044: +			phid->accelerationMax = 8.1; +			phid->accelerationMin = -8.1; +			phid->interruptRate = 4; +			phid->dataRateMin = SPATIAL_MIN_DATA_RATE; +			phid->dataRate = 8; +			phid->dataRateMax = 4; //actual data rate +			phid->angularRateMax = 2000.1; +			phid->angularRateMin = -2000.1; +			phid->magneticFieldMax = 5.6; +			phid->magneticFieldMin = -5.6; +			phid->userMagField = 1.0; +			phid->calDataValid = PFALSE; +			break; + +		default: +			return EPHIDGET_UNEXPECTED; +	} + +	//initialize triggers, set data arrays to unknown +	for (i = 0; i<phid->phid.attr.spatial.numAccelAxes; i++) +	{ +		phid->accelAxis[i] = PUNK_DBL; +		phid->accelGain1[i] = PUNK_DBL; +		phid->accelGain2[i] = PUNK_DBL; +		phid->accelOffset[i] = PUNK_INT; +	} +	for (i = 0; i<phid->phid.attr.spatial.numGyroAxes; i++) +	{ +		phid->gyroAxis[i] = PUNK_DBL; +		phid->gryoCorrection[i] = 0; +		phid->gyroGain1[i] = PUNK_DBL; +		phid->gyroGain2[i] = PUNK_DBL; +		phid->gyroOffset[i] = PUNK_INT; +	} +	for (i = 0; i<phid->phid.attr.spatial.numCompassAxes; i++) +	{ +		phid->compassAxis[i] = PUNK_DBL; +		phid->userCompassGain[i] = 1.0; +	} +	phid->bufferReadPtr = 0; +	phid->bufferWritePtr = 0; +	phid->timestamp.seconds = 0; +	phid->timestamp.microseconds = 0; +	phid->lastEventTime.seconds = 0; +	phid->lastEventTime.microseconds = 0; +	phid->latestDataTime.seconds = 0; +	phid->latestDataTime.microseconds = 0; + +	phid->lastTimeCounterValid = PFALSE; +	phid->doZeroGyro = PFALSE; + +	//get calibration values +	switch(phid->phid.deviceUID) { +		case PHIDUID_SPATIAL_ACCEL_3AXIS_1049: +		case PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1056: +		case PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1056_NEG_GAIN: +			{ +				unsigned char buffer[8] = { 0 }; +				int result; +				int readCount = 125; // up to 1 second of data - should be PLENTY +				//ask for calibration values +				buffer[0] = SPATIAL_READCALIB; +				if ((result = CUSBSendPacket((CPhidgetHandle)phid, buffer)) != EPHIDGET_OK) +					return result; +				while(phid->calDataValid == PFALSE && readCount--) +				{ +					//note that Windows queues up to 32 packets, so we need to read at least this many to get the calibration packet +					CPhidget_read((CPhidgetHandle)phid); +				} +				if(!phid->calDataValid) +					return EPHIDGET_UNEXPECTED; +			} +			break; +		// No streamed Calibration +		case PHIDUID_SPATIAL_ACCEL_3AXIS_1041: +		case PHIDUID_SPATIAL_ACCEL_3AXIS_1043: +		case PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1042: +		case PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1044: +		default: +			break; +	} + +	//issue one read +	//this should fill in the data because the dataRate is the interrupt rate +	CPhidget_read((CPhidgetHandle)phid); + +	return EPHIDGET_OK; +} + +static void updateTimestamp(CPhidgetSpatialHandle phid, int time) +{ +	if(phid->lastTimeCounterValid) +	{ +		//1-255 ms +		int timechange = (unsigned short)((unsigned short)time - (unsigned short)phid->lastTimeCounter); +		timechange *= 1000; //us + +		//if(timechange > 500000) +		//	LOG(PHIDGET_LOG_DEBUG, "Timechange: %d",timechange); + +		phid->timestamp.seconds = phid->timestamp.seconds + (phid->timestamp.microseconds + timechange) / 1000000; +		phid->timestamp.microseconds = (phid->timestamp.microseconds + timechange) % 1000000; +	} +	else +	{ +		phid->lastTimeCounterValid = PTRUE; +	} +	phid->lastTimeCounter = time; +} + +//dataInput - parses device packets +CPHIDGETDATA(Spatial) +	int i = 0, j = 0, count = 0, dataRate = phid->dataRate, cal; +	unsigned char doneGyroZero = PFALSE; +	double accelAvg[SPATIAL_MAX_ACCELAXES], angularRateAvg[SPATIAL_MAX_ACCELAXES], magneticFieldAvg[SPATIAL_MAX_ACCELAXES], magneticFieldCorr[SPATIAL_MAX_ACCELAXES]; +	CPhidgetSpatial_SpatialEventDataHandle *eventData; +	 +	ZEROMEM(accelAvg, sizeof(accelAvg)); +	ZEROMEM(angularRateAvg, sizeof(angularRateAvg)); +	ZEROMEM(magneticFieldAvg, sizeof(magneticFieldAvg)); + +	if (length<0) return EPHIDGET_INVALIDARG; +	TESTPTR(phid); +	TESTPTR(buffer); + +	//Parse device packets - store data locally +	switch(phidG->deviceUID) +	{ +		case PHIDUID_SPATIAL_ACCEL_3AXIS_1049: +		{ +			int data; +			double accelUncalib[3] = {0,0,0}; +			int time; +			 +			//top 2 bits in buffer[0] are packet type +			switch(buffer[0] & 0xc0) +			{ +				case SPATIAL_PACKET_DATA: +					if(phid->calDataValid) +					{ +						count = buffer[0] / 3; +						if(count == 0) +							goto done; + +						//this timestamp is for the latest data +						time = ((unsigned short)buffer[1]<<8) + (unsigned short)buffer[2]; +						if(phid->lastTimeCounterValid) +						{ +							//0-255 ms +							int timechange = (unsigned short)((unsigned short)time - (unsigned short)phid->lastTimeCounter); +							timechange *= 1000; //us + +							phid->timestamp.seconds = phid->timestamp.seconds + (phid->timestamp.microseconds + timechange) / 1000000; +							phid->timestamp.microseconds = (phid->timestamp.microseconds + timechange) % 1000000; +						} +						else +						{ +							phid->lastTimeCounterValid = PTRUE; +						} +						phid->lastTimeCounter = time; + +						//add data to data buffer +						for(i=0;i<count;i++) +						{ +							//LIS344ALH - Vdd/15 V/g - 0x1fff/15 = 0x222 (546.06666666666666666666666666667) +							for(j=0;j<3;j++) +							{ +								data = ((unsigned short)buffer[3 + j * 2 + i * 6]<<8) + (unsigned short)buffer[4 + j * 2 + i * 6]; +								accelUncalib[j] = ((double)data - 0x0fff) / 546.066667; +							} +							accelUncalib[1] = -accelUncalib[1]; //reverse Y-axis +							//Apply offsets +							for(j=0;j<3;j++) +							{ +								accelUncalib[j] -= phid->accelOffset[j]; +							} +							//X +							if(accelUncalib[0] > 0) +								phid->dataBuffer[phid->bufferWritePtr].acceleration[0] = accelUncalib[0] * phid->accelGain1[0] + accelUncalib[1] * phid->accelFactor1[0] + accelUncalib[2] * phid->accelFactor2[0]; +							else +								phid->dataBuffer[phid->bufferWritePtr].acceleration[0] = accelUncalib[0] * phid->accelGain2[0] + accelUncalib[1] * phid->accelFactor1[0] + accelUncalib[2] * phid->accelFactor2[0]; +							//Y +							if(accelUncalib[1] > 0) +								phid->dataBuffer[phid->bufferWritePtr].acceleration[1] = accelUncalib[1] * phid->accelGain1[1] + accelUncalib[0] * phid->accelFactor1[1] + accelUncalib[2] * phid->accelFactor2[1]; +							else +								phid->dataBuffer[phid->bufferWritePtr].acceleration[1] = accelUncalib[1] * phid->accelGain2[1] + accelUncalib[0] * phid->accelFactor1[1] + accelUncalib[2] * phid->accelFactor2[1]; +							//Z +							if(accelUncalib[2] > 0) +								phid->dataBuffer[phid->bufferWritePtr].acceleration[2] = accelUncalib[2] * phid->accelGain1[2] + accelUncalib[0] * phid->accelFactor1[2] + accelUncalib[1] * phid->accelFactor2[2]; +							else +								phid->dataBuffer[phid->bufferWritePtr].acceleration[2] = accelUncalib[2] * phid->accelGain2[2] + accelUncalib[0] * phid->accelFactor1[2] + accelUncalib[1] * phid->accelFactor2[2]; + + +							phid->latestDataTime.seconds = phid->timestamp.seconds + (phid->timestamp.microseconds + (i + 1) * phid->dataRateMax * 1000) / 1000000; +							phid->latestDataTime.microseconds = (phid->timestamp.microseconds + (i + 1) * phid->dataRateMax * 1000) % 1000000; + +							phid->dataBuffer[phid->bufferWritePtr].timestamp = phid->latestDataTime; + +							phid->bufferWritePtr++; +							if(phid->bufferWritePtr >= SPATIAL_DATA_BUFFER_SIZE) +								phid->bufferWritePtr = 0; +						} +					} +					break; +				case SPATIAL_PACKET_CALIB: +					for (i = 0; i<phid->phid.attr.spatial.numAccelAxes; i++) +					{ +						cal = ((unsigned short)buffer[i*7 + 1]<<4) + ((unsigned short)buffer[i*7 + 2]>>4); +						phid->accelGain1[i] = cal / (4096/0.4) + 0.8; +						cal = (((unsigned short)buffer[i*7 + 2]<<8) & 0x0F00) | ((unsigned short)buffer[i*7 + 3]); +						phid->accelGain2[i] = cal / (4096/0.4) + 0.8; +						cal = (unsigned short)((unsigned short)buffer[i*7 + 4]<<8) + (unsigned short)buffer[i*7 + 5]; +						phid->accelOffset[i] = cal / (65535 / 1.0) - 0.5; +						cal = (unsigned char)buffer[i*7 + 6]; +						phid->accelFactor1[i] = cal / (256 / 0.2) - 0.1; +						cal = (unsigned char)buffer[i*7 + 7]; +						phid->accelFactor2[i] = cal / (256 / 0.2) - 0.1; +						//LOG(PHIDGET_LOG_INFO, "Accel(%d) Calib: %1.4lf, %1.4lf, %1.4lf, %1.4lf, %1.4lf", i,  +						//	phid->accelGain1[i], phid->accelGain2[i], phid->accelOffset[i], phid->accelFactor1[i], phid->accelFactor2[i]); +					} +					phid->calDataValid = PTRUE; +					break; +			} +			break; +		} +		// 1043 (1049 Replacement v300) and 1041 (low-cost 0/0/3 v200) +		case PHIDUID_SPATIAL_ACCEL_3AXIS_1041: +		case PHIDUID_SPATIAL_ACCEL_3AXIS_1043: +		{ +			int time; +			int analogOrDigital = ((unsigned short)buffer[1]<<8) + (unsigned short)buffer[2]; +			count = buffer[0]; + +			if(count == 0) +				goto done; + +			//this timestamp is for the latest data +			time = ((unsigned short)buffer[3]<<8) + (unsigned short)buffer[4]; +			updateTimestamp(phid, time); + +			//add data to data buffer +			for(i=0;i<count;i++) +			{ +				int countOffset = i * 6; //Each set of samples is 6 bytes +				for(j=0;j<3;j++) +				{ +					int indexOffset = j * 2; //Each value is 2 bytes +					short accelData	= (signed short)((unsigned short)buffer[5 + indexOffset + countOffset]<<8) + (unsigned short)buffer[6 + indexOffset + countOffset]; + +					//digital accel +					if(analogOrDigital & (0x01 << i)) +						phid->dataBuffer[phid->bufferWritePtr].acceleration[j] = (double)accelData / SPATIAL_MMA8451Q_BITS_PER_G; +					//analog accel +					else +						phid->dataBuffer[phid->bufferWritePtr].acceleration[j] = (double)accelData / SPATIAL_KXR94_2050_w_AD7689_BITS_PER_G; +				} + +				phid->latestDataTime.seconds = phid->timestamp.seconds + (phid->timestamp.microseconds + (i + 1) * phid->dataRateMax * 1000) / 1000000; +				phid->latestDataTime.microseconds = (phid->timestamp.microseconds + (i + 1) * phid->dataRateMax * 1000) % 1000000; + +				phid->dataBuffer[phid->bufferWritePtr].timestamp = phid->latestDataTime; + +				phid->bufferWritePtr++; +				if(phid->bufferWritePtr >= SPATIAL_DATA_BUFFER_SIZE) +					phid->bufferWritePtr = 0; +			} +			break; +		} +		case PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1056: +		case PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1056_NEG_GAIN: +			//top 2 bits in buffer[0] are packet type +			switch(buffer[0]) +			{ +				case SPATIAL_PACKET_DATA: +					if(phid->calDataValid) +					{ +						int data; +						double accelUncalib[3] = {0,0,0}; +						double gyroUncalib[3] = {0,0,0}; +						int time; +						 +						count = (buffer[1] & 0x1f) / 9; +						if(count == 0) +							goto done; + +						//this timestamp is for the latest data +						time = ((unsigned short)buffer[2]<<8) + (unsigned short)buffer[3]; +						if(phid->lastTimeCounterValid) +						{ +							//0-255 ms +							int timechange = (unsigned short)((unsigned short)time - (unsigned short)phid->lastTimeCounter); +							timechange *= 1000; //us + +							phid->timestamp.seconds = phid->timestamp.seconds + (phid->timestamp.microseconds + timechange) / 1000000; +							phid->timestamp.microseconds = (phid->timestamp.microseconds + timechange) % 1000000; +						} +						else +						{ +							phid->lastTimeCounterValid = PTRUE; +						} +						phid->lastTimeCounter = time; + +						//add data to data buffer +						for(i=0;i<count;i++) +						{ +							//LIS344ALH - Vdd/15 V/g - 0xffff/15 = 0x1111 (4369.0) +							for(j=0;j<3;j++) +							{ +								data = ((unsigned short)buffer[4 + j * 2 + i * 18]<<8) + (unsigned short)buffer[5 + j * 2 + i * 18]; +								accelUncalib[j] = ((double)data - 0x7fff) / 4369.0; +							} +							accelUncalib[1] = -accelUncalib[1]; //reverse Y-axis +							//Apply offsets +							for(j=0;j<3;j++) +							{ +								accelUncalib[j] -= phid->accelOffset[j]; +							} +							//X +							if(accelUncalib[0] > 0) +								phid->dataBuffer[phid->bufferWritePtr].acceleration[0] = accelUncalib[0] * phid->accelGain1[0] + accelUncalib[1] * phid->accelFactor1[0] + accelUncalib[2] * phid->accelFactor2[0]; +							else +								phid->dataBuffer[phid->bufferWritePtr].acceleration[0] = accelUncalib[0] * phid->accelGain2[0] + accelUncalib[1] * phid->accelFactor1[0] + accelUncalib[2] * phid->accelFactor2[0]; +							//Y +							if(accelUncalib[1] > 0) +								phid->dataBuffer[phid->bufferWritePtr].acceleration[1] = accelUncalib[1] * phid->accelGain1[1] + accelUncalib[0] * phid->accelFactor1[1] + accelUncalib[2] * phid->accelFactor2[1]; +							else +								phid->dataBuffer[phid->bufferWritePtr].acceleration[1] = accelUncalib[1] * phid->accelGain2[1] + accelUncalib[0] * phid->accelFactor1[1] + accelUncalib[2] * phid->accelFactor2[1]; +							//Z +							if(accelUncalib[2] > 0) +								phid->dataBuffer[phid->bufferWritePtr].acceleration[2] = accelUncalib[2] * phid->accelGain1[2] + accelUncalib[0] * phid->accelFactor1[2] + accelUncalib[1] * phid->accelFactor2[2]; +							else +								phid->dataBuffer[phid->bufferWritePtr].acceleration[2] = accelUncalib[2] * phid->accelGain2[2] + accelUncalib[0] * phid->accelFactor1[2] + accelUncalib[1] * phid->accelFactor2[2]; + +							//ADC ref is 0-3.3V - 50.355uV/bit, gyro zero rate is 1.23V, 2.5mV/deg/s - these voltages are fixed, non-ratiometric to Vref +							// 1 / 0.000050355 = 19859 (1V) +							// 1.23 * 19859 = 24427 +							// 0.0025 * 19859 = 49.6477bits/deg/s +							for(j=0;j<3;j++) +							{ +								data = ((unsigned short)buffer[10 + j * 2 + i * 18]<<8) + (unsigned short)buffer[11 + j * 2 + i * 18]; +								if(j==1) +									gyroUncalib[j] = ((double)(data-24427) + phid->gyroOffset[j]) / 49.6477; +								else +									gyroUncalib[j] = ((double)-(data-24427) + phid->gyroOffset[j]) / 49.6477; //reverse X/Z-axis +							} +							//0 - we multiply these by their gains so revered axes will still appear positive and get the correct gain +							if((gyroUncalib[0] * phid->gyroGain1[0]) > 0) +								phid->dataBuffer[phid->bufferWritePtr].angularRate[0] = gyroUncalib[0] * phid->gyroGain1[0] - gyroUncalib[1] * phid->gyroFactor1[0] - gyroUncalib[2] * phid->gyroFactor2[0]; +							else +								phid->dataBuffer[phid->bufferWritePtr].angularRate[0] = gyroUncalib[0] * phid->gyroGain2[0] - gyroUncalib[1] * phid->gyroFactor1[0] - gyroUncalib[2] * phid->gyroFactor2[0]; +							//1 +							if((gyroUncalib[1] * phid->gyroGain1[1]) > 0) +								phid->dataBuffer[phid->bufferWritePtr].angularRate[1] = gyroUncalib[1] * phid->gyroGain1[1] - gyroUncalib[0] * phid->gyroFactor1[1] - gyroUncalib[2] * phid->gyroFactor2[1]; +							else +								phid->dataBuffer[phid->bufferWritePtr].angularRate[1] = gyroUncalib[1] * phid->gyroGain2[1] - gyroUncalib[0] * phid->gyroFactor1[1] - gyroUncalib[2] * phid->gyroFactor2[1]; +							//2 +							if((gyroUncalib[2] * phid->gyroGain1[2]) > 0) +								phid->dataBuffer[phid->bufferWritePtr].angularRate[2] = gyroUncalib[2] * phid->gyroGain1[2] - gyroUncalib[0] * phid->gyroFactor1[2] - gyroUncalib[1] * phid->gyroFactor2[2]; +							else +								phid->dataBuffer[phid->bufferWritePtr].angularRate[2] = gyroUncalib[2] * phid->gyroGain2[2] - gyroUncalib[0] * phid->gyroFactor1[2] - gyroUncalib[1] * phid->gyroFactor2[2]; + +							//checks if compass data is valid +							//Note: we miss ~7 samples (28ms) every second while the compass is callibrating +							if(buffer[1] & (0x80 >> i)) +							{ +								//ADC 50.355uV/bit (0-3.3V) +								//ideal compass midpoint is 0x7FFF (32767) (1.65V)  +								//valid range for zero field offset is: 0.825V - 2.475V (16384-49151) (+-16384) +								// Note that this may be less (~3x) because the Gain is less, but I'm not sure. (+-5460) +								//valid output voltage range is defined as 0.165V - 3.135V (3277-62258),  +								// so we can't really trust values outside of this, though we do seem to get valid data... +								//ideal sensitivity is 250mV/gauss (ext. resistor), valid range is 195 - 305 +								// 1 / 0.000050355 = 19859 (1Volt) +								// 0.250 * 19859 = 4964.75 bits/gauss (1.0 gain) (ideal) - valid range is (3861-6068) (+-1103) +								//We have defined the compass gain multiplier to be based on 6500bits/gauss to keep the math resonable, +								// so we must use that value here. Implications? +								//The largest range we can guarantee is: +								// 16384-3277/6068 = +-2.16 gauss or, more likely: +-3.96 gauss +								// Ideal is: 32767-3277/4964.75 = +-5.94 gauss +								// we can tell from the incoming data whether it's valid or not,  +								// we'll probably have more range in one dirrection then the other because of offset. +								for(j=0;j<phid->phid.attr.spatial.numCompassAxes; j++) +								{ +									data = ((unsigned short)buffer[16 + i * 18 + j * 2]<<8) + (unsigned short)buffer[17 + i * 18 + j * 2]; +									//if we are not within (3277-62258), data is not valid +									if(data < 3277) +									{ +										phid->dataBuffer[phid->bufferWritePtr].magneticField[j] = phid->magneticFieldMin; +										break; +									} +									if(data > 62258) +									{ +										phid->dataBuffer[phid->bufferWritePtr].magneticField[j] = phid->magneticFieldMax; +										break; +									} + +									//if gain or offset don't make sense, throw out data +									//if(phid->compassGain[j] > 6068 || phid->compassGain[j] < 3861 ||  +									if(phid->compassGain[j] > 6068 || phid->compassGain[j] < 2500 || //lower gains seem to be common +										phid->compassOffset[j] > 5460 || phid->compassOffset[j] < -5460) +									{ +										if(data > 32767) +											phid->dataBuffer[phid->bufferWritePtr].magneticField[j] = phid->magneticFieldMax; +										else +											phid->dataBuffer[phid->bufferWritePtr].magneticField[j] = phid->magneticFieldMin; +										break; +									} + +									//Convert ADC to Gauss +									phid->dataBuffer[phid->bufferWritePtr].magneticField[j] =  +										-((double)data - 0x7fff - phid->compassOffset[j]) / phid->compassGain[j]; + +									//constrain to max/min +									//ie if field is 4.02 and max is 4.1, make it 4.1, since real max is 4.0 +									if(phid->dataBuffer[phid->bufferWritePtr].magneticField[j] > (phid->magneticFieldMax - 0.1)) +										phid->dataBuffer[phid->bufferWritePtr].magneticField[j] = phid->magneticFieldMax; +									if(phid->dataBuffer[phid->bufferWritePtr].magneticField[j] < (phid->magneticFieldMin + 0.1)) +										phid->dataBuffer[phid->bufferWritePtr].magneticField[j] = phid->magneticFieldMin; +								} + +							} +							else +							{ +								phid->dataBuffer[phid->bufferWritePtr].magneticField[0] = PUNK_DBL; +								phid->dataBuffer[phid->bufferWritePtr].magneticField[1] = PUNK_DBL; +								phid->dataBuffer[phid->bufferWritePtr].magneticField[2] = PUNK_DBL; +							} + +							phid->latestDataTime.seconds = phid->timestamp.seconds + (phid->timestamp.microseconds + (i + 1) * phid->dataRateMax * 1000) / 1000000; +							phid->latestDataTime.microseconds = (phid->timestamp.microseconds + (i + 1) * phid->dataRateMax * 1000) % 1000000; + +							phid->dataBuffer[phid->bufferWritePtr].timestamp = phid->latestDataTime; + +							phid->bufferWritePtr++; +							if(phid->bufferWritePtr >= SPATIAL_DATA_BUFFER_SIZE) +								phid->bufferWritePtr = 0; +						} +					} +					break; +				case SPATIAL_PACKET_CALIB: +					for (i = 0; i<phid->phid.attr.spatial.numAccelAxes; i++) +					{ +						cal = ((unsigned short)buffer[i*7 + 1]<<4) + ((unsigned short)buffer[i*7 + 2]>>4); +						phid->accelGain1[i] = cal / (4096/0.4) + 0.8; +						cal = (((unsigned short)buffer[i*7 + 2]<<8) & 0x0F00) | ((unsigned short)buffer[i*7 + 3]); +						phid->accelGain2[i] = cal / (4096/0.4) + 0.8; +						cal = (unsigned short)((unsigned short)buffer[i*7 + 4]<<8) + (unsigned short)buffer[i*7 + 5]; +						phid->accelOffset[i] = cal / (65535 / 1.0) - 0.5; +						cal = (unsigned char)buffer[i*7 + 6]; +						phid->accelFactor1[i] = cal / (256 / 0.2) - 0.1; +						cal = (unsigned char)buffer[i*7 + 7]; +						phid->accelFactor2[i] = cal / (256 / 0.2) - 0.1; +						//LOG(PHIDGET_LOG_INFO, "Accel(%d) Calib: %1.4lf, %1.4lf, %1.4lf, %1.4lf, %1.4lf", i,  +						//	phid->accelGain1[i], phid->accelGain2[i], phid->accelOffset[i], phid->accelFactor1[i], phid->accelFactor2[i]); +					} +					for (j=0; j<phid->phid.attr.spatial.numGyroAxes; i++,j++) +					{ +						if (phidG->deviceUID == PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1056) +						{ +							cal = ((unsigned short)buffer[i*7 + 1]<<4) + ((unsigned short)buffer[i*7 + 2]>>4); +							phid->gyroGain1[j] = cal / (4096/0.4) + 0.8; +							cal = (((unsigned short)buffer[i*7 + 2]<<8) & 0x0F00) | ((unsigned short)buffer[i*7 + 3]); +							phid->gyroGain2[j] = cal / (4096/0.4) + 0.8; +						} +						//Allow for negative gains +						else if (phidG->deviceUID == PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1056_NEG_GAIN) +						{ +							cal = ((signed short)((signed char)buffer[i*7 + 1])<<4) + ((unsigned short)buffer[i*7 + 2]>>4); +							phid->gyroGain1[j] = cal / (4096/0.4) + (cal > 0 ? 0.9 : -0.9); +							cal = ((((unsigned short)buffer[i*7 + 2]<<8) & 0x0F00) | ((unsigned short)buffer[i*7 + 3]) ) << 4; +							cal = (signed short)cal >> 4; +							phid->gyroGain2[j] = cal / (4096/0.4) + (cal > 0 ? 0.9 : -0.9); +						} +						cal = (signed short)((unsigned short)buffer[i*7 + 4]<<8) + (unsigned short)buffer[i*7 + 5]; +						phid->gyroOffset[j] = cal; +						cal = (unsigned char)buffer[i*7 + 6]; +						phid->gyroFactor1[j] = cal / (256 / 0.1) - 0.05; +						cal = (unsigned char)buffer[i*7 + 7]; +						phid->gyroFactor2[j] = cal / (256 / 0.1) - 0.05; + +//Zero out calibrations +#if 0 +						phid->gyroGain1[j] = 1; +						phid->gyroGain2[j] = 1; +						phid->gyroOffset[j] = 0; +						phid->gyroFactor1[j] = 0; +						phid->gyroFactor2[j] = 0; +#endif + +						LOG(PHIDGET_LOG_VERBOSE, "Gyro(%d) Calib: %1.4lf, %1.4lf, %1.4lf, %1.4lf, %1.4lf", j,  +							phid->gyroGain1[j], phid->gyroGain2[j], phid->gyroOffset[j], phid->gyroFactor1[j], phid->gyroFactor2[j]); +					} +					for(j=0;j<phid->phid.attr.spatial.numCompassAxes; j++) +					{ +						phid->compassOffset[j] = (signed short)((unsigned short)buffer[j*4 + 49]<<8) + (unsigned short)buffer[j*4 + 50]; +						phid->compassGain[j] = ((unsigned short)buffer[j*4 + 51]<<8) + (unsigned short)buffer[j*4 + 52]; +						//phid->compassGain[j] = 4964; +					} +					//LOG(PHIDGET_LOG_INFO, "Compass Gain: %d, %d, %d", phid->compassGain[0], phid->compassGain[1], phid->compassGain[2]); +					//LOG(PHIDGET_LOG_INFO, "Compass Offset: %d, %d, %d", phid->compassOffset[0], phid->compassOffset[1], phid->compassOffset[2]); +					phid->calDataValid = PTRUE; +					break; +			} +			break; + +		case PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1042: +		case PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1044: +		{ +			int time; +			int flags = buffer[1]; +			count = buffer[0]; + +			if(count == 0) +				goto done; + +			//this timestamp is for the latest data +			time = ((unsigned short)buffer[2]<<8) + (unsigned short)buffer[3]; +			updateTimestamp(phid, time); + +			//add data to data buffer +			for(i=0;i<count;i++) +			{ +				int countOffset = i * 18; //Each set of samples is 18 bytes +				for(j=0;j<3;j++) +				{ +					int indexOffset = j * 2; //Each value is 2 bytes +					short accelData	= (signed short)((unsigned short)buffer[ 4 + indexOffset + countOffset] << 8) + (unsigned short)buffer[ 5 + indexOffset + countOffset]; +					short gyroData  = (signed short)((unsigned short)buffer[10 + indexOffset + countOffset] << 8) + (unsigned short)buffer[11 + indexOffset + countOffset]; +					short magData   = (signed short)((unsigned short)buffer[16 + indexOffset + countOffset] << 8) + (unsigned short)buffer[17 + indexOffset + countOffset]; + +					//digital accel +					if(flags & (0x02 >> i)) +						phid->dataBuffer[phid->bufferWritePtr].acceleration[j] = (double)accelData / SPATIAL_MMA8451Q_BITS_PER_G; +					//analog accel +					else +						phid->dataBuffer[phid->bufferWritePtr].acceleration[j] = (double)accelData / SPATIAL_KXR94_2050_w_AD7689_BITS_PER_G; +					 +					//digital gyro +					if(flags & (0x08 >> i)) +							phid->dataBuffer[phid->bufferWritePtr].angularRate[j] = (double)gyroData / SPATIAL_L3GD20_BITS_PER_DPS; +					//analog gyro +					else +						if(j==2) +							phid->dataBuffer[phid->bufferWritePtr].angularRate[j] = (double)(gyroData) / SPATIAL_LY330ALH_w_AD7689_BITS_PER_DPS; +						else +							phid->dataBuffer[phid->bufferWritePtr].angularRate[j] = (double)(gyroData) / SPATIAL_LRP410AL_w_AD7689_BITS_PER_DPS; +									 +					//compass valid +					if(flags & (0x20 >> i)) +						phid->dataBuffer[phid->bufferWritePtr].magneticField[j] = magData / SPATIAL_HMC5883L_BITS_PER_GAUSS; +					//no compass data +					else +						phid->dataBuffer[phid->bufferWritePtr].magneticField[j] = PUNK_DBL; +				} + +				phid->latestDataTime.seconds = phid->timestamp.seconds + (phid->timestamp.microseconds + (i + 1) * phid->dataRateMax * 1000) / 1000000; +				phid->latestDataTime.microseconds = (phid->timestamp.microseconds + (i + 1) * phid->dataRateMax * 1000) % 1000000; + +				phid->dataBuffer[phid->bufferWritePtr].timestamp = phid->latestDataTime; + +				phid->bufferWritePtr++; +				if(phid->bufferWritePtr >= SPATIAL_DATA_BUFFER_SIZE) +					phid->bufferWritePtr = 0; +			} +			break; +		} +		default: +			return EPHIDGET_UNEXPECTED; +	} + +	if(phid->doZeroGyro) +	{ +		//done +		if(timestampdiff(phid->latestDataTime, phid->dataBuffer[phid->gyroZeroReadPtr].timestamp) >= SPATIAL_ZERO_GYRO_TIME) +		{ +			double gryoCorrectionTemp[SPATIAL_MAX_GYROAXES] = {0,0,0}; +			int gryoCorrectionCount = 0; + +			while(phid->gyroZeroReadPtr != phid->bufferWritePtr) +			{ +				for (i = 0; i<phid->phid.attr.spatial.numGyroAxes; i++) +				{ +					gryoCorrectionTemp[i] += phid->dataBuffer[phid->gyroZeroReadPtr].angularRate[i]; +				} + +				phid->gyroZeroReadPtr++; +				if(phid->gyroZeroReadPtr >= SPATIAL_DATA_BUFFER_SIZE) +					phid->gyroZeroReadPtr = 0; + +				gryoCorrectionCount++; +			} +			 +			for (i = 0; i<phid->phid.attr.spatial.numGyroAxes; i++) +			{ +				phid->gryoCorrection[i] = gryoCorrectionTemp[i] / (double)gryoCorrectionCount; +			} + +			doneGyroZero = PTRUE; +		} +	} + +	//see if it's time for an event +	if(timestampdiff(phid->latestDataTime, phid->lastEventTime) >= dataRate) +	{ +		CPhidget_Timestamp tempTime; +		//int lastPtr; +		int accelCounter[SPATIAL_MAX_ACCELAXES], angularRateCounter[SPATIAL_MAX_ACCELAXES], magneticFieldCounter[SPATIAL_MAX_ACCELAXES]; + +		int dataPerEvent = 0; + +		int multipleDataPerEvent = PFALSE; + +		if(dataRate < phid->interruptRate) +			multipleDataPerEvent = PTRUE; + +		//max of 16 data per event +		eventData = malloc(16 * sizeof(CPhidgetSpatial_SpatialEventDataHandle)); +		 +		for(j=0;;j++) +		{ +			//makes sure we read all data +			if(phid->bufferReadPtr == phid->bufferWritePtr || j>=16) +			{ +				dataPerEvent = j; +				break; +			} + +			eventData[j] = malloc(sizeof(CPhidgetSpatial_SpatialEventData)); +			ZEROMEM(accelCounter, sizeof(accelCounter)); +			ZEROMEM(angularRateCounter, sizeof(angularRateCounter)); +			ZEROMEM(magneticFieldCounter, sizeof(magneticFieldCounter)); + +			tempTime = phid->dataBuffer[phid->bufferReadPtr].timestamp; + +			//average data for each stage +			while(phid->bufferReadPtr != phid->bufferWritePtr &&  +				(!multipleDataPerEvent || timestampdiff(phid->dataBuffer[phid->bufferReadPtr].timestamp, tempTime) < dataRate)) +			{ +				for (i = 0; i<phid->phid.attr.spatial.numAccelAxes; i++) +				{ +					if(phid->dataBuffer[phid->bufferReadPtr].acceleration[i] != PUNK_DBL) +					{ +						if(phid->dataBuffer[phid->bufferReadPtr].acceleration[i] > phid->accelerationMax) +							phid->dataBuffer[phid->bufferReadPtr].acceleration[i] = phid->accelerationMax; +						if(phid->dataBuffer[phid->bufferReadPtr].acceleration[i] < phid->accelerationMin)  +							phid->dataBuffer[phid->bufferReadPtr].acceleration[i] = phid->accelerationMin; +						accelAvg[i] += phid->dataBuffer[phid->bufferReadPtr].acceleration[i]; +						accelCounter[i]++; +					} +				} +				for (i = 0; i<phid->phid.attr.spatial.numGyroAxes; i++) +				{ +					if(phid->dataBuffer[phid->bufferReadPtr].angularRate[i] != PUNK_DBL) +					{ +						double rate = phid->dataBuffer[phid->bufferReadPtr].angularRate[i] - phid->gryoCorrection[i]; + +						if(rate > phid->angularRateMax)  +							angularRateAvg[i] += phid->angularRateMax; +						else if(rate < phid->angularRateMin)  +							angularRateAvg[i] += phid->angularRateMin; +						else +							angularRateAvg[i] += rate; +						angularRateCounter[i]++; +					} +				} +				for (i = 0; i<phid->phid.attr.spatial.numCompassAxes; i++) +				{ +					if(phid->dataBuffer[phid->bufferReadPtr].magneticField[i] != PUNK_DBL) +					{ +						if(phid->dataBuffer[phid->bufferReadPtr].magneticField[i] > phid->magneticFieldMax)  +							phid->dataBuffer[phid->bufferReadPtr].magneticField[i] = phid->magneticFieldMax; +						if(phid->dataBuffer[phid->bufferReadPtr].magneticField[i] < phid->magneticFieldMin)  +							phid->dataBuffer[phid->bufferReadPtr].magneticField[i] = phid->magneticFieldMin; +						magneticFieldAvg[i] += phid->dataBuffer[phid->bufferReadPtr].magneticField[i]; +						magneticFieldCounter[i]++; +					} +				} + +				//lastPtr = phid->bufferReadPtr; + +				phid->bufferReadPtr++; +				if(phid->bufferReadPtr >= SPATIAL_DATA_BUFFER_SIZE) +					phid->bufferReadPtr = 0; +			} + +			for (i = 0; i<phid->phid.attr.spatial.numAccelAxes; i++) +			{ +				if(accelCounter[i] > 0) +					eventData[j]->acceleration[i] = round_double(accelAvg[i] / (double)accelCounter[i], 5); +				else +					eventData[j]->acceleration[i] = PUNK_DBL; +				accelAvg[i] = 0; +			} +			for (i = 0; i<phid->phid.attr.spatial.numGyroAxes; i++) +			{ +				if(angularRateCounter[i] > 0) +				{ +					if(phid->doZeroGyro && !doneGyroZero) +						eventData[j]->angularRate[i] = 0; +					else +						eventData[j]->angularRate[i] = round_double(angularRateAvg[i] / (double)angularRateCounter[i], 5); +				} +				else +					eventData[j]->angularRate[i] = PUNK_DBL; +				angularRateAvg[i] = 0; +			} +			for (i = 0; i<phid->phid.attr.spatial.numCompassAxes; i++) +			{ +				if(magneticFieldCounter[i] > 0) +					eventData[j]->magneticField[i] = round_double(magneticFieldAvg[i] / (double)magneticFieldCounter[i], 5); +				else +					eventData[j]->magneticField[i] = PUNK_DBL; +				magneticFieldAvg[i] = 0; +			} +			eventData[j]->timestamp = tempTime; +		} + +		//correct magnetic field data in the event structure +		// But only on devices that don't do this in Firmware! +		switch(phid->phid.deviceUID) +		{ +			case PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1056: +			case PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1056_NEG_GAIN: +				for( j = 0; j < dataPerEvent; j++) +				{ +					for (i = 0; i<phid->phid.attr.spatial.numCompassAxes; i++) +					{ +						magneticFieldCorr[i] = eventData[j]->magneticField[i]; +					} +					for (i = 0; i<phid->phid.attr.spatial.numCompassAxes; i++) +					{ +						if(eventData[j]->magneticField[i] != PUNK_DBL) +						{ +							eventData[j]->magneticField[i] = getCorrectedField(phid, magneticFieldCorr, i); +						} +					} +				} +				break; +			case PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1042: +			case PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1044: +			default: +				break; +		} + +		//store to local structure +		ZEROMEM(accelCounter, sizeof(accelCounter)); +		ZEROMEM(angularRateCounter, sizeof(angularRateCounter)); +		ZEROMEM(magneticFieldCounter, sizeof(magneticFieldCounter)); +		for( j = 0; j < dataPerEvent; j++) +		{ +			for (i = 0; i<phid->phid.attr.spatial.numAccelAxes; i++) +			{ +				if(eventData[j]->acceleration[i] != PUNK_DBL) +				{ +					accelAvg[i] += eventData[j]->acceleration[i]; +					accelCounter[i]++; +				} +			} +			for (i = 0; i<phid->phid.attr.spatial.numGyroAxes; i++) +			{ +				if(eventData[j]->angularRate[i] != PUNK_DBL) +				{ +					angularRateAvg[i] += eventData[j]->angularRate[i]; +					angularRateCounter[i]++; +				} +			} +			for (i = 0; i<phid->phid.attr.spatial.numCompassAxes; i++) +			{ +				if(eventData[j]->magneticField[i] != PUNK_DBL) +				{ +					magneticFieldAvg[i] += eventData[j]->magneticField[i]; +					magneticFieldCounter[i]++; +				} +			} +		} + +		//Set local get data to averages +		for (i = 0; i<phid->phid.attr.spatial.numAccelAxes; i++) +		{ +			if(accelCounter[i] > 0) +				phid->accelAxis[i] = round_double(accelAvg[i] / (double)accelCounter[i], 5); +			else +				phid->accelAxis[i] = PUNK_DBL; +		} +		for (i = 0; i<phid->phid.attr.spatial.numGyroAxes; i++) +		{ +			if(angularRateCounter[i] > 0) +			{ +				if(phid->doZeroGyro && !doneGyroZero) +					phid->gyroAxis[i] = 0; +				else +					phid->gyroAxis[i] = round_double(angularRateAvg[i] / (double)angularRateCounter[i], 5); +			} +			else +				phid->gyroAxis[i] = PUNK_DBL; +		} +		for (i = 0; i<phid->phid.attr.spatial.numCompassAxes; i++) +		{ +			if(magneticFieldCounter[i] > 0) +				phid->compassAxis[i] = round_double(magneticFieldAvg[i] / (double)magneticFieldCounter[i], 5); +			else +				phid->compassAxis[i] = PUNK_DBL; +		} +		 +		//send out any events +		FIRE(SpatialData, eventData, dataPerEvent); + +		phid->lastEventTime = phid->latestDataTime; + +		for(i=0;i<dataPerEvent;i++) +			free(eventData[i]); +		free(eventData); +	} +done: + +	//this will signal the zero function to return; +	if(doneGyroZero) +		phid->doZeroGyro = PFALSE; + +	return EPHIDGET_OK; +} + +//eventsAfterOpen - sends out an event for all valid data, used during attach initialization +CPHIDGETINITEVENTS(Spatial) +	TESTPTR(phid); +	//don't need to worry, because the interrupts come at a set rate +	return EPHIDGET_OK; +} + +//getPacket - not used for spatial +CGETPACKET(Spatial) +	return EPHIDGET_UNEXPECTED; +} + +static double getCorrectedField(CPhidgetSpatialHandle phid, double fields[], int axis) +{ +	switch(axis) +	{ +	case 0: +		return phid->userMagField *  +			(phid->userCompassGain[0] * (fields[0] - phid->userCompassOffset[0]) +			+ phid->userCompassTransform[0] * (fields[1] - phid->userCompassOffset[1]) +			+ phid->userCompassTransform[1] * (fields[2] - phid->userCompassOffset[2])); +	case 1: +		return phid->userMagField *  +			(phid->userCompassGain[1] * (fields[1] - phid->userCompassOffset[1]) +			+ phid->userCompassTransform[2] * (fields[0] - phid->userCompassOffset[0]) +			+ phid->userCompassTransform[3] * (fields[2] - phid->userCompassOffset[2])); +	case 2: +		return phid->userMagField *  +			(phid->userCompassGain[2] * (fields[2] - phid->userCompassOffset[2]) +			+ phid->userCompassTransform[4] * (fields[0] - phid->userCompassOffset[0]) +			+ phid->userCompassTransform[5] * (fields[1] - phid->userCompassOffset[1])); +	default: +		return 0; +	} +} + +// Accel and Gyro tables are the same structure - just different table IDs. +static int setCalibrationValues_inFirmware(CPhidgetSpatialHandle phid, int tableID, int index, +	double gainPositive[3], double gainNegative[3], double offset[3], double factor1[3], double factor2[3]) +{ +	unsigned char buffer[SPATIAL_ACCEL_GYRO_CALIB_TABLE_LENGTH] = {0}; +	int i; +	double offsetMultipliers[3]; +	unsigned int header; + +	TESTPTR(phid) +	TESTDEVICETYPE(PHIDCLASS_SPATIAL) +	TESTATTACHED + +	if(!deviceSupportsGeneralUSBProtocol((CPhidgetHandle)phid)) +		return EPHIDGET_UNSUPPORTED; + +	switch(phid->phid.deviceUID) +	{ +		case PHIDUID_SPATIAL_ACCEL_3AXIS_1043: +			if(index == SPATIAL_ANALOG_ACCEL_CALIB_TABLE_INDEX) +			{ +				offsetMultipliers[0] = offsetMultipliers[1] = offsetMultipliers[2] = SPATIAL_KXR94_2050_w_AD7689_BITS_PER_G; +				break; +			} +		case PHIDUID_SPATIAL_ACCEL_3AXIS_1041: +			if(index == SPATIAL_DIGITAL_ACCEL_CALIB_TABLE_INDEX) +			{ +				offsetMultipliers[0] = offsetMultipliers[1] = offsetMultipliers[2] = SPATIAL_MMA8451Q_BITS_PER_G; +				break; +			} +			else +				return EPHIDGET_UNSUPPORTED; + +		case PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1044: +			if(index == SPATIAL_ANALOG_GYRO_CALIB_TABLE_INDEX) +			{ +				offsetMultipliers[0] = offsetMultipliers[1] = SPATIAL_LRP410AL_w_AD7689_BITS_PER_DPS; +				offsetMultipliers[2] = SPATIAL_LY330ALH_w_AD7689_BITS_PER_DPS; +				break; +			} +			if(index == SPATIAL_ANALOG_ACCEL_CALIB_TABLE_INDEX) +			{ +				offsetMultipliers[0] = offsetMultipliers[1] = offsetMultipliers[2] = SPATIAL_KXR94_2050_w_AD7689_BITS_PER_G; +				break; +			} +		case PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1042: +			if(index == SPATIAL_DIGITAL_GYRO_CALIB_TABLE_INDEX) +			{ +				offsetMultipliers[0] = offsetMultipliers[1] = offsetMultipliers[2] = SPATIAL_L3GD20_BITS_PER_DPS; +				break; +			} +			if(index == SPATIAL_DIGITAL_ACCEL_CALIB_TABLE_INDEX) +			{ +				offsetMultipliers[0] = offsetMultipliers[1] = offsetMultipliers[2] = SPATIAL_MMA8451Q_BITS_PER_G; +				break; +			} +			else +				return EPHIDGET_UNSUPPORTED; +		default: +			return EPHIDGET_UNSUPPORTED; +	} + +	header = (((unsigned int)tableID) << 20) | SPATIAL_ACCEL_GYRO_CALIB_TABLE_LENGTH; + +    buffer[3] = header >> 24; //header high byte +    buffer[2] = header >> 16; +    buffer[1] = header >> 8; +    buffer[0] = header >> 0; //header low byte + +	for(i=0;i<3;i++) +	{ +		int int32Offset = i * 4; +		int temp; + +		temp = round(gainPositive[i] * (double)0x10000); +		buffer[int32Offset +  7] = temp >> 24; +		buffer[int32Offset +  6] = temp >> 16; +		buffer[int32Offset +  5] = temp >> 8; +		buffer[int32Offset +  4] = temp >> 0; +		 +		temp = round(gainNegative[i] * (double)0x10000); +		buffer[int32Offset + 19] = temp >> 24; +		buffer[int32Offset + 18] = temp >> 16; +		buffer[int32Offset + 17] = temp >> 8; +		buffer[int32Offset + 16] = temp >> 0; + +		temp = round(offset[i] * offsetMultipliers[i]); +		buffer[int32Offset + 31] = temp >> 24; +		buffer[int32Offset + 30] = temp >> 16; +		buffer[int32Offset + 29] = temp >> 8; +		buffer[int32Offset + 28] = temp >> 0; + +		temp = round(factor1[i] * (double)0x10000); +		buffer[int32Offset + 43] = temp >> 24; +		buffer[int32Offset + 42] = temp >> 16; +		buffer[int32Offset + 41] = temp >> 8; +		buffer[int32Offset + 40] = temp >> 0; + +		temp = round(factor2[i] * (double)0x10000); +		buffer[int32Offset + 55] = temp >> 24; +		buffer[int32Offset + 54] = temp >> 16; +		buffer[int32Offset + 53] = temp >> 8; +		buffer[int32Offset + 52] = temp >> 0; +	} + +	if(CPhidget_statusFlagIsSet(phid->phid.status, PHIDGET_REMOTE_FLAG)) +	{ +		//TODO - maybe, maybe not. +		return EPHIDGET_UNSUPPORTED; +	} +	else +		return CPhidgetGPP_setDeviceSpecificConfigTable((CPhidgetHandle)phid, buffer, SPATIAL_ACCEL_GYRO_CALIB_TABLE_LENGTH, index); +} + +static int setCompassCorrectionTable_inFimrware( +	CPhidgetSpatialHandle phid,  +	double magField,  +	double offset0, double offset1, double offset2,  +	double gain0, double gain1, double gain2,  +	double T0, double T1, double T2, double T3, double T4, double T5) +{ +	unsigned char buffer[SPATIAL_COMPASS_CALIB_TABLE_LENGTH] = {0}; +	int i; +	int gains[3], offsets[3], transforms[6], mag; +	TESTPTR(phid) +	if (!CPhidget_statusFlagIsSet(phid->phid.status, PHIDGET_ATTACHED_FLAG)) +		return EPHIDGET_NOTATTACHED; + +	if(!deviceSupportsGeneralUSBProtocol((CPhidgetHandle)phid)) +		return EPHIDGET_UNSUPPORTED; + +	//compass calibration table Header is: 0x3EA00038 +    buffer[3] = 0x3E; //header high byte +    buffer[2] = 0xA0; +    buffer[1] = 0x00; +    buffer[0] = SPATIAL_COMPASS_CALIB_TABLE_LENGTH; //header low byte + +	//Mag Field (x0x10000) +	mag = round(magField * (double)0x10000); +    buffer[7] = mag >> 24; +    buffer[6] = mag >> 16; +    buffer[5] = mag >> 8; +    buffer[4] = mag >> 0; + +	//Gain (x0x10000) +	gains[0] = round(gain0 * (double)0x10000); +	gains[1] = round(gain1 * (double)0x10000); +	gains[2] = round(gain2 * (double)0x10000); +	for(i=0;i<3;i++) +	{ +		buffer[i*4+11] = gains[i] >> 24; +		buffer[i*4+10] = gains[i] >> 16; +		buffer[i*4+9] = gains[i] >> 8; +		buffer[i*4+8] = gains[i] >> 0; +	} + +	//Offset +	offsets[0] = round(offset0 * (double)SPATIAL_HMC5883L_BITS_PER_GAUSS); +	offsets[1] = round(offset1 * (double)SPATIAL_HMC5883L_BITS_PER_GAUSS); +	offsets[2] = round(offset2 * (double)SPATIAL_HMC5883L_BITS_PER_GAUSS); +	for(i=0;i<3;i++) +	{ +		buffer[i*4+23] = offsets[i] >> 24; +		buffer[i*4+22] = offsets[i] >> 16; +		buffer[i*4+21] = offsets[i] >> 8; +		buffer[i*4+20] = offsets[i] >> 0; +	} + +	//Transforms (x0x10000) +	transforms[0] = round(T0 * (double)0x10000); +	transforms[1] = round(T1 * (double)0x10000); +	transforms[2] = round(T2 * (double)0x10000); +	transforms[3] = round(T3 * (double)0x10000); +	transforms[4] = round(T4 * (double)0x10000); +	transforms[5] = round(T5 * (double)0x10000); +	for(i=0;i<6;i++) +	{ +		buffer[i*4+35] = transforms[i] >> 24; +		buffer[i*4+34] = transforms[i] >> 16; +		buffer[i*4+33] = transforms[i] >> 8; +		buffer[i*4+32] = transforms[i] >> 0; +	} + +	//Label Table index is: 0 +	return CPhidgetGPP_setDeviceSpecificConfigTable((CPhidgetHandle)phid, buffer, SPATIAL_COMPASS_CALIB_TABLE_LENGTH, SPATIAL_COMPASS_CALIB_TABLE_INDEX); +} + +// === Exported Functions === // + +//create and initialize a device structure +CCREATE(Spatial, PHIDCLASS_SPATIAL) + +//event setup functions +CFHANDLE(Spatial, SpatialData, CPhidgetSpatial_SpatialEventDataHandle *, int) + +CGET(Spatial,AccelerationAxisCount,int) +	TESTPTRS(phid,pVal)  +	TESTDEVICETYPE(PHIDCLASS_SPATIAL) +	TESTATTACHED + +	MASGN(phid.attr.spatial.numAccelAxes) +} +CGET(Spatial,GyroAxisCount,int) +	TESTPTRS(phid,pVal)  +	TESTDEVICETYPE(PHIDCLASS_SPATIAL) +	TESTATTACHED + +	MASGN(phid.attr.spatial.numGyroAxes) +} +CGET(Spatial,CompassAxisCount,int) +	TESTPTRS(phid,pVal)  +	TESTDEVICETYPE(PHIDCLASS_SPATIAL) +	TESTATTACHED + +	MASGN(phid.attr.spatial.numCompassAxes) +} + +CGETINDEX(Spatial,Acceleration,double) +	TESTPTRS(phid,pVal) 	 +	TESTDEVICETYPE(PHIDCLASS_SPATIAL) +	TESTATTACHED +	TESTINDEX(phid.attr.spatial.numAccelAxes) +	TESTMASGN(accelAxis[Index], PUNK_DBL) + +	MASGN(accelAxis[Index]) +} + +CGETINDEX(Spatial,AccelerationMax,double) +	TESTPTRS(phid,pVal) 	 +	TESTDEVICETYPE(PHIDCLASS_SPATIAL) +	TESTATTACHED +	TESTINDEX(phid.attr.spatial.numAccelAxes) +	TESTMASGN(accelerationMax, PUNK_DBL) + +	MASGN(accelerationMax) +} + +CGETINDEX(Spatial,AccelerationMin,double) +	TESTPTRS(phid,pVal) 	 +	TESTDEVICETYPE(PHIDCLASS_SPATIAL) +	TESTATTACHED +	TESTINDEX(phid.attr.spatial.numAccelAxes) +	TESTMASGN(accelerationMin, PUNK_DBL) + +	MASGN(accelerationMin) +} + +CGETINDEX(Spatial,AngularRate,double) +	TESTPTRS(phid,pVal) 	 +	TESTDEVICETYPE(PHIDCLASS_SPATIAL) +	TESTATTACHED + +	switch(phid->phid.deviceIDSpec) +	{ +		case PHIDID_SPATIAL_ACCEL_GYRO_COMPASS: +			TESTINDEX(phid.attr.spatial.numGyroAxes) +			TESTMASGN(gyroAxis[Index], PUNK_DBL) +			MASGN(gyroAxis[Index]) +		case PHIDID_SPATIAL_ACCEL_3AXIS: +		default: +			return EPHIDGET_UNSUPPORTED; +	} +} + +CGETINDEX(Spatial,AngularRateMax,double) +	TESTPTRS(phid,pVal) 	 +	TESTDEVICETYPE(PHIDCLASS_SPATIAL) +	TESTATTACHED + +	switch(phid->phid.deviceIDSpec) +	{ +		case PHIDID_SPATIAL_ACCEL_GYRO_COMPASS: +			TESTINDEX(phid.attr.spatial.numGyroAxes) +			TESTMASGN(angularRateMax, PUNK_DBL) +			MASGN(angularRateMax) +		case PHIDID_SPATIAL_ACCEL_3AXIS: +		default: +			return EPHIDGET_UNSUPPORTED; +	} +} + +CGETINDEX(Spatial,AngularRateMin,double) +	TESTPTRS(phid,pVal) 	 +	TESTDEVICETYPE(PHIDCLASS_SPATIAL) +	TESTATTACHED + +	switch(phid->phid.deviceIDSpec) +	{ +		case PHIDID_SPATIAL_ACCEL_GYRO_COMPASS: +			TESTINDEX(phid.attr.spatial.numGyroAxes) +			TESTMASGN(angularRateMin, PUNK_DBL) +			MASGN(angularRateMin) +		case PHIDID_SPATIAL_ACCEL_3AXIS: +		default: +			return EPHIDGET_UNSUPPORTED; +	} +} + +CGETINDEX(Spatial,MagneticField,double) +	TESTPTRS(phid,pVal) 	 +	TESTDEVICETYPE(PHIDCLASS_SPATIAL) +	TESTATTACHED + +	switch(phid->phid.deviceIDSpec) +	{ +		case PHIDID_SPATIAL_ACCEL_GYRO_COMPASS: +			TESTINDEX(phid.attr.spatial.numCompassAxes) +			TESTMASGN(compassAxis[Index], PUNK_DBL) +			MASGN(compassAxis[Index]) +		case PHIDID_SPATIAL_ACCEL_3AXIS: +		default: +			return EPHIDGET_UNSUPPORTED; +	} +} + +CGETINDEX(Spatial,MagneticFieldMax,double) +	TESTPTRS(phid,pVal) 	 +	TESTDEVICETYPE(PHIDCLASS_SPATIAL) +	TESTATTACHED + +	switch(phid->phid.deviceIDSpec) +	{ +		case PHIDID_SPATIAL_ACCEL_GYRO_COMPASS: +			TESTINDEX(phid.attr.spatial.numCompassAxes) +			TESTMASGN(magneticFieldMax, PUNK_DBL) +			MASGN(magneticFieldMax) +		case PHIDID_SPATIAL_ACCEL_3AXIS: +		default: +			return EPHIDGET_UNSUPPORTED; +	} +} + +CGETINDEX(Spatial,MagneticFieldMin,double) +	TESTPTRS(phid,pVal) 	 +	TESTDEVICETYPE(PHIDCLASS_SPATIAL) +	TESTATTACHED + +	switch(phid->phid.deviceIDSpec) +	{ +		case PHIDID_SPATIAL_ACCEL_GYRO_COMPASS: +			TESTINDEX(phid.attr.spatial.numCompassAxes) +			TESTMASGN(magneticFieldMin, PUNK_DBL) +			MASGN(magneticFieldMin) +		case PHIDID_SPATIAL_ACCEL_3AXIS: +		default: +			return EPHIDGET_UNSUPPORTED; +	} +} + +CSET(Spatial,DataRate,int) +	TESTPTR(phid) +	TESTDEVICETYPE(PHIDCLASS_SPATIAL) +	TESTATTACHED +	TESTRANGE(phid->dataRateMax, phid->dataRateMin) + +	//make sure it's a power of 2, or 1 +	if(newVal < phid->interruptRate) +	{ +		int temp = phid->dataRateMax; +		unsigned char good = FALSE; +		while(temp <= newVal) +		{ +			if(temp == newVal) +			{ +				good = TRUE; +				break; +			} +			temp *= 2; +		} +		if(!good) +			return EPHIDGET_INVALIDARG; +	} +	//make sure it's divisible by interruptRate +	else +	{ +		if(newVal%phid->interruptRate) +			return EPHIDGET_INVALIDARG; +	} + +	if(CPhidget_statusFlagIsSet(phid->phid.status, PHIDGET_REMOTE_FLAG)) +		ADDNETWORKKEY(DataRate, "%d", dataRate); +	else +		phid->dataRate = newVal; + +	return EPHIDGET_OK; +} +CGET(Spatial,DataRate,int) +	TESTPTRS(phid,pVal) 	 +	TESTDEVICETYPE(PHIDCLASS_SPATIAL) +	TESTATTACHED +	TESTMASGN(dataRate, PUNK_INT) + +	MASGN(dataRate) +} + +CGET(Spatial,DataRateMax,int) +	TESTPTRS(phid,pVal) 	 +	TESTDEVICETYPE(PHIDCLASS_SPATIAL) +	TESTATTACHED +	TESTMASGN(dataRateMax, PUNK_INT) + +	MASGN(dataRateMax) +} + +CGET(Spatial,DataRateMin,int) +	TESTPTRS(phid,pVal) 	 +	TESTDEVICETYPE(PHIDCLASS_SPATIAL) +	TESTATTACHED +	TESTMASGN(dataRateMin, PUNK_INT) + +	MASGN(dataRateMin) +} + +PHIDGET21_API int CCONV CPhidgetSpatial_zeroGyro(CPhidgetSpatialHandle phid) +{ +	int result = EPHIDGET_OK; +	TESTPTR(phid)  +	TESTDEVICETYPE(PHIDCLASS_SPATIAL) +	TESTATTACHED +	if(phid->phid.attr.spatial.numGyroAxes==0) +		return EPHIDGET_UNSUPPORTED; + +	if(CPhidget_statusFlagIsSet(phid->phid.status, PHIDGET_REMOTE_FLAG)) +	{ +		int newVal = phid->flip^1; +		ADDNETWORKKEY(ZeroGyro, "%d", flip); +	} +	else +	{ +		switch(phid->phid.deviceUID) +		{ +			case PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1042: +			case PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1044: +			{ +				unsigned char buffer[8] = { 0 }; +				buffer[0] = SPATIAL_ZERO_GYRO; +				result = CUSBSendPacket((CPhidgetHandle)phid, buffer); +				break; +			} +			case PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1056: +			case PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1056_NEG_GAIN: +				if(!phid->doZeroGyro) +				{ +					phid->gyroZeroReadPtr = phid->bufferReadPtr; +					phid->doZeroGyro = PTRUE; +				} +				break; +			default: +				return EPHIDGET_UNEXPECTED; +		} +	} + +	return EPHIDGET_OK; +} + +PHIDGET21_API int CCONV CPhidgetSpatial_resetCompassCorrectionParameters( +	CPhidgetSpatialHandle phid) +{ +	TESTPTR(phid) 	 +	TESTDEVICETYPE(PHIDCLASS_SPATIAL) +	TESTATTACHED + +	switch(phid->phid.deviceIDSpec) +	{ +		case PHIDID_SPATIAL_ACCEL_GYRO_COMPASS: +			if(CPhidget_statusFlagIsSet(phid->phid.status, PHIDGET_REMOTE_FLAG)) +			{ +				char newVal[1024]; +				sprintf(newVal, "1,0,0,0,1,1,1,0,0,0,0,0,0"); +				ADDNETWORKKEY(CompassCorrectionParams, "%s", compassCorrectionParamsString); +			} +			else +			{ +				switch(phid->phid.deviceUID) +				{ +					case PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1056: +					case PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1056_NEG_GAIN: + +						phid->userMagField = 1; + +						phid->userCompassOffset[0] = 0; +						phid->userCompassOffset[1] = 0; +						phid->userCompassOffset[2] = 0; + +						phid->userCompassGain[0] = 1; +						phid->userCompassGain[1] = 1; +						phid->userCompassGain[2] = 1; + +						phid->userCompassTransform[0] = 0; +						phid->userCompassTransform[1] = 0; +						phid->userCompassTransform[2] = 0; +						phid->userCompassTransform[3] = 0; +						phid->userCompassTransform[4] = 0; +						phid->userCompassTransform[5] = 0; +						break; +					case PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1042: +					case PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1044: +						return setCompassCorrectionTable_inFimrware(phid, +							1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0); +					default: +						return EPHIDGET_UNEXPECTED; +				} +			} +			return EPHIDGET_OK; +		case PHIDID_SPATIAL_ACCEL_3AXIS: +		default: +			return EPHIDGET_UNSUPPORTED; +	} +} +PHIDGET21_API int CCONV CPhidgetSpatial_setCompassCorrectionParameters( +	CPhidgetSpatialHandle phid,  +	double magField,  +	double offset0, double offset1, double offset2,  +	double gain0, double gain1, double gain2,  +	double T0, double T1, double T2, double T3, double T4, double T5) +{ +	TESTPTR(phid) 	 +	TESTDEVICETYPE(PHIDCLASS_SPATIAL) +	TESTATTACHED + +	switch(phid->phid.deviceIDSpec) +	{ +		case PHIDID_SPATIAL_ACCEL_GYRO_COMPASS: +			//Magnetic Field 0.1-1000 +			if(magField < 0.1 || magField > 1000) +				return EPHIDGET_INVALIDARG; +			//Offsets need to be 0+-5.0 +			if(offset0 < -5 || offset0 > 5) +				return EPHIDGET_INVALIDARG; +			if(offset1 < -5 || offset1 > 5) +				return EPHIDGET_INVALIDARG; +			if(offset2 < -5 || offset2 > 5) +				return EPHIDGET_INVALIDARG; +			//Gains need to be 0-15.0 +			if(gain0 < 0 || gain0 > 15) +				return EPHIDGET_INVALIDARG; +			if(gain1 < 0 || gain1 > 15) +				return EPHIDGET_INVALIDARG; +			if(gain2 < 0 || gain2 > 15) +				return EPHIDGET_INVALIDARG; +			//T params 0+-5.0 +			if(T0 < -5 || T0 > 5) +				return EPHIDGET_INVALIDARG; +			if(T1 < -5 || T1 > 5) +				return EPHIDGET_INVALIDARG; +			if(T2 < -5 || T2 > 5) +				return EPHIDGET_INVALIDARG; +			if(T3 < -5 || T3 > 5) +				return EPHIDGET_INVALIDARG; +			if(T4 < -5 || T4 > 5) +				return EPHIDGET_INVALIDARG; +			if(T5 < -5 || T5 > 5) +				return EPHIDGET_INVALIDARG; + +			if(CPhidget_statusFlagIsSet(phid->phid.status, PHIDGET_REMOTE_FLAG)) +			{ +				char newVal[1024]; +				sprintf(newVal, "%lE,%lE,%lE,%lE,%lE,%lE,%lE,%lE,%lE,%lE,%lE,%lE,%lE", +					magField, offset0, offset1, offset2, gain0, gain1, gain2, T0, T1, T2, T3, T4, T5); +				ADDNETWORKKEY(CompassCorrectionParams, "%s", compassCorrectionParamsString); +			} +			else +			{ +				switch(phid->phid.deviceUID) +				{ +					case PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1056: +					case PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1056_NEG_GAIN: + +						phid->userMagField = magField; + +						phid->userCompassOffset[0] = offset0; +						phid->userCompassOffset[1] = offset1; +						phid->userCompassOffset[2] = offset2; + +						phid->userCompassGain[0] = gain0; +						phid->userCompassGain[1] = gain1; +						phid->userCompassGain[2] = gain2; + +						phid->userCompassTransform[0] = T0; +						phid->userCompassTransform[1] = T1; +						phid->userCompassTransform[2] = T2; +						phid->userCompassTransform[3] = T3; +						phid->userCompassTransform[4] = T4; +						phid->userCompassTransform[5] = T5; +						break; + +					case PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1042: +					case PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1044: +						return setCompassCorrectionTable_inFimrware(phid, +							magField, offset0, offset1, offset2, +							gain0, gain1, gain2, T0, T1, T2, T3, T4, T5); +					default: +						return EPHIDGET_UNEXPECTED; +				} +			} +			return EPHIDGET_OK; +		case PHIDID_SPATIAL_ACCEL_3AXIS: +		default: +			return EPHIDGET_UNSUPPORTED; +	} +} + + +CSET(Spatial,AnalogDigitalMode,CPhidgetSpatial_AnalogDigitalMode) +	TESTPTR(phid) +	TESTDEVICETYPE(PHIDCLASS_SPATIAL) +	TESTATTACHED +	TESTRANGE(SPATIAL_ANALOG_AND_DIGITAL, SPATIAL_DIGITAL) + +	switch(phid->phid.deviceUID) +	{ +		case PHIDUID_SPATIAL_ACCEL_3AXIS_1043: +		case PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1044: +		{ +			if(CPhidget_statusFlagIsSet(phid->phid.status, PHIDGET_REMOTE_FLAG)) +			{ +				//TODO +			} +			else +			{ +				unsigned char buffer[8] = { 0 }; +				buffer[0] = SPATIAL_SET_POLLING_TYPE; +				buffer[1] = newVal; +				return CUSBSendPacket((CPhidgetHandle)phid, buffer); +			} +		} +		default: +			return EPHIDGET_UNSUPPORTED; +	} +} + +PHIDGET21_API int CCONV CPhidgetSpatial_unZeroGyro(CPhidgetSpatialHandle phid) +{ +	TESTPTR(phid) +	TESTDEVICETYPE(PHIDCLASS_SPATIAL) +	TESTATTACHED + +	switch(phid->phid.deviceUID) +	{ +		case PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1042: +		case PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1044: +		{ +			if(CPhidget_statusFlagIsSet(phid->phid.status, PHIDGET_REMOTE_FLAG)) +			{ +				//TODO +			} +			else +			{ +				unsigned char buffer[8] = { 0 }; +				buffer[0] = SPATIAL_UNZERO_GYRO; +				return CUSBSendPacket((CPhidgetHandle)phid, buffer); +			} +		} +		default: +			return EPHIDGET_UNSUPPORTED; +	} +} + +PHIDGET21_API int CCONV CPhidgetSpatial_setDigitalGyroCalibrationValues(CPhidgetSpatialHandle phid, +	double gainPositive[3], double gainNegative[3], double offset[3], double factor1[3], double factor2[3]) +{ +	return setCalibrationValues_inFirmware(phid, SPATIAL_GyroCalibTable_ID, SPATIAL_DIGITAL_GYRO_CALIB_TABLE_INDEX, +		gainPositive, gainNegative, offset, factor1, factor2); +} + +PHIDGET21_API int CCONV CPhidgetSpatial_setAnalogGyroCalibrationValues(CPhidgetSpatialHandle phid, +	double gainPositive[3], double gainNegative[3], double offset[3], double factor1[3], double factor2[3]) +{ +	return setCalibrationValues_inFirmware(phid, SPATIAL_GyroCalibTable_ID, SPATIAL_ANALOG_GYRO_CALIB_TABLE_INDEX, +		gainPositive, gainNegative, offset, factor1, factor2); +} + +PHIDGET21_API int CCONV CPhidgetSpatial_setDigitalAccelCalibrationValues(CPhidgetSpatialHandle phid, +	double gainPositive[3], double gainNegative[3], double offset[3], double factor1[3], double factor2[3]) +{ +	return setCalibrationValues_inFirmware(phid, SPATIAL_AccelCalibTable_ID, SPATIAL_DIGITAL_ACCEL_CALIB_TABLE_INDEX, +		gainPositive, gainNegative, offset, factor1, factor2); +} + +PHIDGET21_API int CCONV CPhidgetSpatial_setAnalogAccelCalibrationValues(CPhidgetSpatialHandle phid, +	double gainPositive[3], double gainNegative[3], double offset[3], double factor1[3], double factor2[3]) +{ +	return setCalibrationValues_inFirmware(phid, SPATIAL_AccelCalibTable_ID, SPATIAL_ANALOG_ACCEL_CALIB_TABLE_INDEX, +		gainPositive, gainNegative, offset, factor1, factor2); +} + + + +//Maybe add these later +/* +CGET(Spatial,GyroHeading,double) +	TESTPTRS(phid,pVal) 	 +	TESTDEVICETYPE(PHIDCLASS_SPATIAL) +	TESTATTACHED +	TESTMASGN(gyroHeading, PUNK_DBL) + +	MASGN(gyroHeading) +} + +CGET(Spatial,CompassHeading,double) +	TESTPTRS(phid,pVal) 	 +	TESTDEVICETYPE(PHIDCLASS_SPATIAL) +	TESTATTACHED +	TESTMASGN(compassHeading, PUNK_DBL) + +	MASGN(compassHeading) +}*/ diff --git a/cphidgetspatial.h b/cphidgetspatial.h index 8d9fdb7..a24d758 100644 --- a/cphidgetspatial.h +++ b/cphidgetspatial.h @@ -172,6 +172,32 @@ PHIDGET21_API int CCONV CPhidgetSpatial_resetCompassCorrectionParameters(CPhidge   */
  CHDREVENT(Spatial,SpatialData,CPhidgetSpatial_SpatialEventDataHandle *data, int dataCount)
 +//These are for a prototype device - hide until it's released
 +#if !defined(EXTERNALPROTO) || defined(DEBUG)
 +
 +#define SPATIAL_ANALOG_AND_DIGITAL	0x00
 +#define SPATIAL_ANALOG				0x01
 +#define SPATIAL_DIGITAL				0x02
 +
 +typedef enum {
 +	PHIDGET_SPATIAL_ANALOG_AND_DIGITAL = 0,	/**< Analog failover to digital */
 +	PHIDGET_SPATIAL_ANALOG,					/**< Analog only */
 +	PHIDGET_SPATIAL_DIGITAL,				/**< Digital only */
 +}  CPhidgetSpatial_AnalogDigitalMode;
 +
 +CHDRSET(Spatial, AnalogDigitalMode, CPhidgetSpatial_AnalogDigitalMode mode)
 +PHIDGET21_API int CCONV CPhidgetSpatial_unZeroGyro(CPhidgetSpatialHandle phid);
 +PHIDGET21_API int CCONV CPhidgetSpatial_setDigitalGyroCalibrationValues(CPhidgetSpatialHandle phid,
 +	double gainPositive[3], double gainNegative[3], double offset[3], double factor1[3], double factor2[3]);
 +PHIDGET21_API int CCONV CPhidgetSpatial_setAnalogGyroCalibrationValues(CPhidgetSpatialHandle phid,
 +	double gainPositive[3], double gainNegative[3], double offset[3], double factor1[3], double factor2[3]);
 +PHIDGET21_API int CCONV CPhidgetSpatial_setDigitalAccelCalibrationValues(CPhidgetSpatialHandle phid,
 +	double gainPositive[3], double gainNegative[3], double offset[3], double factor1[3], double factor2[3]);
 +PHIDGET21_API int CCONV CPhidgetSpatial_setAnalogAccelCalibrationValues(CPhidgetSpatialHandle phid,
 +	double gainPositive[3], double gainNegative[3], double offset[3], double factor1[3], double factor2[3]);
 +
 +#endif
 +
  #ifndef EXTERNALPROTO
  #define SPATIAL_MAX_ACCELAXES 3
 @@ -183,16 +209,72 @@ CHDREVENT(Spatial,SpatialData,CPhidgetSpatial_SpatialEventDataHandle *data, int  //1 second is the longest between events that we support
  #define SPATIAL_MIN_DATA_RATE 1000
  //add 200ms for timing differences (late events, etc) - should be plenty
 -#define SPATIAL_DATA_BUFFER_SIZE ((SPATIAL_MIN_DATA_RATE + 200)/SPATIAL_MAX_DATA_RATE)
 -//1 second of data to zero the gyro - make sure DATA_BUFFER_SIZE is big enough to hold this much data
 +#define SPATIAL_DATA_BUFFER_SIZE ((SPATIAL_MIN_DATA_RATE * 2 + 200)/SPATIAL_MAX_DATA_RATE)
 +//2 seconds of data to zero the gyro - make sure DATA_BUFFER_SIZE is big enough to hold this much data
  #define SPATIAL_ZERO_GYRO_TIME 2000
  //packet types
  //IN
 -#define SPATIAL_PACKET_DATA	0x00
 -#define SPATIAL_PACKET_CALIB 0x80
 +#define SPATIAL_PACKET_DATA		0x00
 +#define SPATIAL_PACKET_CALIB	0x80
  //OUT
 -#define SPATIAL_READCALIB 0x01
 +#define SPATIAL_READCALIB			0x01
 +#define SPATIAL_SET_POLLING_TYPE	0x02
 +#define SPATIAL_ZERO_GYRO			0x03
 +#define SPATIAL_UNZERO_GYRO			0x04
 +
 +//M3 Spatial calibration table indexes
 +#define SPATIAL_DIGITAL_ACCEL_CALIB_TABLE_INDEX		0
 +#define SPATIAL_ANALOG_ACCEL_CALIB_TABLE_INDEX		1
 +#define SPATIAL_DIGITAL_GYRO_CALIB_TABLE_INDEX		2
 +#define SPATIAL_ANALOG_GYRO_CALIB_TABLE_INDEX		3
 +#define SPATIAL_COMPASS_CALIB_TABLE_INDEX			4
 +#define SPATIAL_COMPASS_TEMP_CALIB_TABLE_INDEX		5
 +
 +#define SPATIAL_ACCEL_GYRO_CALIB_TABLE_LENGTH		64
 +#define SPATIAL_COMPASS_CALIB_TABLE_LENGTH			56
 +
 +#define SPATIAL_GyroCalibTable_ID 		1000
 +#define SPATIAL_AccelCalibTable_ID 		1001
 +
 +/**
 + * M3 Spatial constants (1041, 1042, 1043, 1044)
 + *  -Values are transmitted as signed integers with a unit of 'bits'
 + *  -Values are calibrated in-firmware
 + *  -Values are centered at zero
 + *
 + * Precision Voltage Ref is 3.3 V
 + * AD7689 ADC is 16-bit
 + *
 + * LPR410AL x,y Analog Gyro is 2.5 mV/dps and +-400 dps
 + * LY330ALH z-axis Analog Gyro is 3.752 mV/dps and +-300 dps
 + * L3GD20 Digital Gyro is 70 mdps/bit and +-2000 dps
 + *
 + * KXR94-2050 Analog Accelerometer is 660 mV/g and +-2g
 + * MMA8451Q Digital Accelerometer is 1024 bits/g and +-8g
 + *
 + * HMC5883L Digital Compass is 3.03 mG/bit and +-5.6 Gauss
 + **/
 +#define SPATIAL_VOLTAGE_REF 3.3
 +#define SPATIAL_AD7689_BITS_PER_VOLT (0x10000 / SPATIAL_VOLTAGE_REF)
 +
 +#define SPATIAL_LPR410AL_VOLTS_PER_DPS 0.0025
 +#define SPATIAL_LRP410AL_w_AD7689_BITS_PER_DPS (SPATIAL_LPR410AL_VOLTS_PER_DPS * SPATIAL_AD7689_BITS_PER_VOLT)
 +
 +#define SPATIAL_LY330ALH_VOLTS_PER_DPS 0.003752
 +#define SPATIAL_LY330ALH_w_AD7689_BITS_PER_DPS (SPATIAL_LY330ALH_VOLTS_PER_DPS * SPATIAL_AD7689_BITS_PER_VOLT)
 +
 +#define SPATIAL_L3GD20_DPS_PER_BIT 0.07
 +#define SPATIAL_L3GD20_BITS_PER_DPS (1 / SPATIAL_L3GD20_DPS_PER_BIT)
 +
 +#define SPATIAL_KXR94_2050_VOLTS_PER_G 0.660
 +#define SPATIAL_KXR94_2050_w_AD7689_BITS_PER_G (SPATIAL_KXR94_2050_VOLTS_PER_G * SPATIAL_AD7689_BITS_PER_VOLT)
 +
 +#define SPATIAL_MMA8451Q_BITS_PER_G 1024
 +
 +#define SPATIAL_HMC5883L_GAUSS_PER_BIT 0.00303
 +#define SPATIAL_HMC5883L_BITS_PER_GAUSS (1 / SPATIAL_HMC5883L_GAUSS_PER_BIT)
 +
  struct _CPhidgetSpatial {
  	CPhidget phid;
 diff --git a/cphidgetstepper.c b/cphidgetstepper.c index 5b7ead2..0da3dc6 100644 --- a/cphidgetstepper.c +++ b/cphidgetstepper.c @@ -238,7 +238,7 @@ CPHIDGETDATA(Stepper)  			phid->motorPositionEcho[i] = position[i];  		if(speed[i] > phid->motorSpeedMax || speed[i] < -phid->motorSpeedMax) -			LOG(PHIDGET_LOG_WARNING, "Phidget stepper recieved out of range speed data: %lE", speed[i]); +			LOG(PHIDGET_LOG_WARNING, "Phidget stepper received out of range speed data: %lE", speed[i]);  		else  			phid->motorSpeedEcho[i] = speed[i]; diff --git a/csocketevents.c b/csocketevents.c index 9291994..6ad4ca1 100644 --- a/csocketevents.c +++ b/csocketevents.c @@ -2003,6 +2003,7 @@ void network_phidget_event_handler(const char *key, const char *val, unsigned in  					CPhidget_clearStatusFlag(&phid->status, PHIDGET_DETACHING_FLAG, NULL);  					phid->deviceIDSpec = 0; +					phid->deviceUID = 0;  					ZEROMEM(&phid->attr, sizeof(CPhidgetAttr));  					if(phid->specificDevice != PHIDGETOPEN_LABEL)  						ZEROMEM(phid->label, MAX_LABEL_STORAGE); @@ -2032,6 +2033,9 @@ void network_phidget_event_handler(const char *key, const char *val, unsigned in  			{  				LOG(PHIDGET_LOG_VERBOSE, "Got all initkeys, run attach - %d/%d", phid->keyCount, phid->initKeys); +				//Set UID +				phid->deviceUID = CPhidget_getUID(phid->deviceIDSpec, phid->deviceVersion); +  				CPhidget_setStatusFlag(&phid->status, PHIDGET_ATTACHED_FLAG, &phid->lock);  				SET_RUNNING_EVENT(phid) @@ -2114,6 +2118,7 @@ void network_manager_event_handler(const char *key, const char *val, unsigned in  		phid->serialNumber = serialNumber;  		phid->deviceIDSpec = (unsigned short)strtol(deviceIDSpec, NULL, 10);  		phid->deviceVersion = strtol(version, NULL, 10); +		phid->deviceUID = CPhidget_getUID(phid->deviceIDSpec, phid->deviceVersion);  		phid->specificDevice = PHIDGETOPEN_SERIAL; //so it actually compares the serial  		for(i = 1;i<PHIDGET_DEVICE_COUNT;i++) diff --git a/csocketopen.c b/csocketopen.c index caaecfc..4c12f5d 100644 --- a/csocketopen.c +++ b/csocketopen.c @@ -1269,7 +1269,7 @@ start:  			{  				//if we've been waiting too long, then signal disconnect  				double waitTime = timeSince(&server->lastHeartbeatTime); -				//if we haven't recieved any heartbeats, set the timeout high (4*4 = 16 seconds) +				//if we haven't received any heartbeats, set the timeout high (4*4 = 16 seconds)  				//This is so that really slow connections will get through the auth stage  				double avgPingTime = ((server->avgHeartbeatTimeCount > 0) ? (server->avgHeartbeatTime / server->avgHeartbeatTimeCount) : 4.0); @@ -5,6 +5,10 @@  #include "cusb.h"  #include "cphidgetlist.h" +#if defined(_MACOSX) && !defined(_IPHONE) +#include "macusb.h" +#endif +  CThread_func_return_t CentralThreadFunction(CThread_func_arg_t arg);  static CThread CentralThread; @@ -112,7 +116,7 @@ JoinCentralThread()  }  /* - * registers a device to recieve events and be polled by the central + * registers a device to receive events and be polled by the central   * thread This needs to start the central thread if it's not yet   * running.  */ @@ -13,13 +13,18 @@ void CUSBCleanup();  int CUSBSetupNotifications();  int CUSBRefreshLabelString(CPhidgetHandle phid);  #if defined(_LINUX) && !defined(_ANDROID) -int CUSBGetDeviceCapabilities(CPhidgetHandle phid, struct usb_device *dev, -    struct usb_dev_handle *udev); +void CUSBUninit();  #else  int CUSBGetDeviceCapabilities(CPhidgetHandle phid, HANDLE DeviceHandle);  #endif  #endif +#ifdef _IPHONE +int CPhidgetManager_setupNotifications(CFRunLoopRef runloop); +int CPhidgetManager_teardownNotifications(); +int reenumerateDevice(CPhidgetHandle phid); +#endif +  PHIDGET21_API int CCONV CUSBReadPacket(CPhidgetHandle phidA, unsigned char *buffer);  PHIDGET21_API int CCONV CUSBSendPacket(CPhidgetHandle phidA, unsigned char *buffer); diff --git a/dict/pdictclient.c b/dict/pdictclient.c index 987d6bc..75c61b0 100644 --- a/dict/pdictclient.c +++ b/dict/pdictclient.c @@ -184,7 +184,7 @@ pdc_init(void)  	if ((res = regcomp(&pendingex, PENDING_PATTERN, REG_EXTENDED)) != 0) {  		LOG_STDERR(PHIDGET_LOG_CRITICAL, "pending report pattern compilation error %d", res); -		ABORT(); +		abort();  	}  	initialized = 1;  	return 1; diff --git a/examples/manager.c b/examples/manager.c index 412b7de..74bddbd 100644 --- a/examples/manager.c +++ b/examples/manager.c @@ -53,7 +53,7 @@ int main()  {    CPhidgetManagerHandle phidm; -  //CPhidget_enableLogging(PHIDGET_LOG_VERBOSE, NULL); +  CPhidget_enableLogging(PHIDGET_LOG_VERBOSE, NULL);    CPhidgetManager_create(&phidm);    CPhidgetManager_set_OnAttach_Handler(phidm, gotAttach, NULL); diff --git a/libphidget21.pc.in b/libphidget21.pc.in new file mode 100644 index 0000000..1801775 --- /dev/null +++ b/libphidget21.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libphidget +Description: Phidgets library +Version: @VERSION@ +Libs: -L${libdir} -lphidget21 +Cflags: -I${includedir}
\ No newline at end of file diff --git a/linux/cusblinux-1.0.c b/linux/cusblinux-1.0.c new file mode 100644 index 0000000..4b43b1d --- /dev/null +++ b/linux/cusblinux-1.0.c @@ -0,0 +1,659 @@ +/* + *  cusblinux.cpp + * + *  Filled in by Daniel Risacher on 6/21/05 + *  Filled in more by Patrick McNeil on 6/27/05 + *  Copyright 2005 Phidgets Inc. All rights reserved. + * + */ + +#include "stdafx.h" +#include "cusb.h" +#include <libusb-1.0/libusb.h> + +int CUSBCloseHandle(CPhidgetHandle phid) { +	int ret = 0; +	int result = EPHIDGET_OK; +	 +	if (!phid) +		return EPHIDGET_INVALIDARG; + +	CPhidget_clearStatusFlag(&phid->status, PHIDGET_ATTACHED_FLAG, &phid->lock); +	 +	if (phid->deviceHandle == NULL) +		return EPHIDGET_NOTATTACHED; + +	CThread_join(&phid->readThread); +		 +	if((ret = libusb_release_interface((libusb_device_handle *) phid->deviceHandle, phid->deviceDef->pdd_iid)) != 0) +	{ +		switch(ret) +		{ +			case LIBUSB_ERROR_NO_DEVICE: +				//usb_release_interface called after the device was unplugged +				LOG(PHIDGET_LOG_WARNING, "libusb_release_interface called on unplugged device."); +				break; +			default: +				LOG(PHIDGET_LOG_ERROR, "libusb_release_interface failed with error code: %d", ret); +		} +	} +	 +	//if we notice that PHIDGET_USB_ERROR_FLAG is set, then reset this device before closing +	//this gives us a better chance of getting it back if something has gone wrong. +	if(CPhidget_statusFlagIsSet(phid->status, PHIDGET_USB_ERROR_FLAG)) +	{ +		LOG(PHIDGET_LOG_WARNING,"PHIDGET_USB_ERROR_FLAG is set - resetting device."); +		if((ret = libusb_reset_device((libusb_device_handle *) phid->deviceHandle)) != 0) +		{ +			LOG(PHIDGET_LOG_ERROR, "libusb_reset_device failed with error code: %d", ret); +			result = EPHIDGET_UNEXPECTED; +		} +	} +	 +	libusb_close((libusb_device_handle *) phid->deviceHandle); +	 +	phid->deviceHandle = NULL; +	 +	return result; +} + +int CUSBSendPacket(CPhidgetHandle phid, unsigned char *buffer) { +	int BytesWritten = 0, ret; + +	if (!phid) +		return EPHIDGET_INVALIDARG; +		 +	if (!CPhidget_statusFlagIsSet(phid->status, PHIDGET_ATTACHED_FLAG) +		&& !CPhidget_statusFlagIsSet(phid->status, PHIDGET_ATTACHING_FLAG)) +		return EPHIDGET_NOTATTACHED; +		 +	if (phid->deviceHandle == NULL) +	{ +		LOG(PHIDGET_LOG_WARNING,"Handle for writing is not valid"); +		return EPHIDGET_UNEXPECTED; +	} +		 +	if(phid->interruptOutEndpoint) +	{ +		ret = libusb_interrupt_transfer((libusb_device_handle *)phid->deviceHandle,  +										   LIBUSB_ENDPOINT_OUT | phid->deviceDef->pdd_iid+1,  +										   (char *)buffer,  +										   phid->outputReportByteLength, /* size */ +										   &BytesWritten, +										   500); /* FIXME? timeout */ +	} +	else +	{ +		BytesWritten = libusb_control_transfer((libusb_device_handle *)phid->deviceHandle,  +						LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, +						LIBUSB_REQUEST_SET_CONFIGURATION, +						0x0200, /* value */ +						phid->deviceDef->pdd_iid, /* index*/ +						(char *)buffer,  +						phid->outputReportByteLength, /* size */ +						500); /* FIXME? timeout */ +		ret = BytesWritten; +	} +					 +	if(ret < 0) +	{ +		switch(ret) +		{ +			case LIBUSB_ERROR_TIMEOUT: //important case? +					return EPHIDGET_TIMEOUT; +			case LIBUSB_ERROR_NO_DEVICE: +				//device is gone - unplugged. +				LOG(PHIDGET_LOG_INFO, "Device was unplugged - detach."); +				return EPHIDGET_NOTATTACHED; +			default: +				LOG(PHIDGET_LOG_ERROR, "libusb_control_msg failed with error code: %d", ret); +				return EPHIDGET_UNEXPECTED; +		} +	} + +	if (BytesWritten != phid->outputReportByteLength) +	{ +		LOG(PHIDGET_LOG_WARNING,"Failure in CUSBSendPacket - Report Length" +			": %d, bytes written: %d", +		    (int)phid->outputReportByteLength, (int)BytesWritten); +		return EPHIDGET_UNEXPECTED; +	} +	 +	return EPHIDGET_OK; +} + +int CUSBSetLabel(CPhidgetHandle phid, char *buffer) { +	int BytesWritten = 0; +	int size = buffer[0]; +	 +	if(size>22) return EPHIDGET_INVALID; +	 +	if (!phid) +		return EPHIDGET_INVALIDARG; +		 +	if (!CPhidget_statusFlagIsSet(phid->status, PHIDGET_ATTACHED_FLAG) +		&& !CPhidget_statusFlagIsSet(phid->status, PHIDGET_ATTACHING_FLAG)) +		return EPHIDGET_NOTATTACHED; +		 +	if (phid->deviceHandle == NULL) +	{ +		LOG(PHIDGET_LOG_WARNING,"Handle for writing is not valid"); +		return EPHIDGET_UNEXPECTED; +	} +		 +	BytesWritten = libusb_control_transfer((libusb_device_handle *)phid->deviceHandle,  +					LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE, +					LIBUSB_REQUEST_SET_DESCRIPTOR, +					0x0304, /* value */ +					0x0409, /* index*/ +					(char *)buffer,  +					size, /* size */ +					500); /* FIXME? timeout */ +					 +	if(BytesWritten < 0) +	{ +		switch(BytesWritten) +		{ +		case LIBUSB_ERROR_TIMEOUT: //important case?	 +		default: +			LOG(PHIDGET_LOG_INFO, "usb_control_msg failed with error code: %d", BytesWritten); +			return EPHIDGET_UNSUPPORTED; +		} +	} + +	if (BytesWritten != size) +	{ +		LOG(PHIDGET_LOG_WARNING,"Failure in CUSBSetLabel - Report Length" +			": %d, bytes written: %d", +		    size, (int)BytesWritten); +		return EPHIDGET_UNEXPECTED; +	} +	 +	return EPHIDGET_OK; +} + +/* Buffer should be at least 8 bytes long */ +int CUSBReadPacket(CPhidgetHandle phid, unsigned char *buffer) { +	int BytesRead = 0, ret; +	 +	if (!phid) +		return EPHIDGET_INVALIDARG; +		 +	if (!CPhidget_statusFlagIsSet(phid->status, PHIDGET_ATTACHED_FLAG) +		&& !CPhidget_statusFlagIsSet(phid->status, PHIDGET_ATTACHING_FLAG)) +		return EPHIDGET_NOTATTACHED; +		 +	if (phid->deviceHandle == NULL) +	{ +		LOG(PHIDGET_LOG_WARNING,"Handle for writing is not valid"); +		return EPHIDGET_UNEXPECTED; +	} +	 +	ret = libusb_interrupt_transfer((libusb_device_handle *)phid->deviceHandle,  +				LIBUSB_ENDPOINT_IN | phid->deviceDef->pdd_iid+1,  +				(char *)buffer,  +				phid->inputReportByteLength, +				&BytesRead, +				500); +				 +	if (ret != 0) +	{ +		switch(ret) +		{ +			// A timeout occured, but we'll just try again +			case LIBUSB_ERROR_TIMEOUT: +				LOG(PHIDGET_LOG_VERBOSE, "libusb_interrupt_transfer timeout"); +				return EPHIDGET_TIMEOUT; +			case LIBUSB_ERROR_BUSY: +				//This happens when someone else calls claim_interface on this interface (a manager for ex.) - basically just wait until they release it. +				//This will happen if an open occurs in another app which (for some reason) can steal the interface from this one. +				LOG(PHIDGET_LOG_INFO, "Device is busy on Read - try again."); +				return EPHIDGET_TRYAGAIN; +			case LIBUSB_ERROR_NO_DEVICE: +				//device is gone - unplugged. +				LOG(PHIDGET_LOG_INFO, "Device was unplugged - detach."); +				return EPHIDGET_NOTATTACHED; +			case LIBUSB_ERROR_PIPE: +			case LIBUSB_ERROR_OVERFLOW: +			default: +				LOG(PHIDGET_LOG_ERROR, "libusb_interrupt_transfer returned: %d \"%s\"", ret); +				goto tryagain; +		} +	} + +	if (BytesRead != phid->inputReportByteLength) +	{ +		//Generally means the device was unplugged, but can mean that there is not enough Interrupt bandwidth +		//We keep trying and we'll get data, just not all data +		LOG(PHIDGET_LOG_WARNING,"Failure in CUSBReadPacket - Report Length" +			": %d, bytes read: %d. Probably trying to use too many Phidgets at once, and some data is being lost.", +		    (int)phid->inputReportByteLength, (int)BytesRead); +		goto tryagain; +	} +	 +	phid->tryAgainCounter = 0; +	return EPHIDGET_OK; +	 +	//if we see too many tryagains in a row, then we assume something has actually gone wrong and reset the device +tryagain: +	phid->tryAgainCounter++; +	if(phid->tryAgainCounter > 30) //this will be hit in < 1 second for all devices +	{ +		LOG(PHIDGET_LOG_ERROR, "CUSBReadPacket returned EPHIDGET_TRYAGAIN too many times in a row - reset device."); +		phid->tryAgainCounter = 0; +		return EPHIDGET_UNEXPECTED; +	} +	return EPHIDGET_TRYAGAIN; +} + +static int getLabelString(CPhidgetHandle phid, struct libusb_device_handle *handle) +{	 +	int len = 0; +	char labelBuf[22]; +	memset(labelBuf, 0, sizeof(labelBuf)); +	 +	//Note that this returns the whole descriptor, including the length and type bytes +	len = libusb_get_string_descriptor(handle, 4, 0, (char *)labelBuf, 22); +	 +	if(len < 0) +	{ +		switch(len) +		{ +			case LIBUSB_ERROR_TIMEOUT: //important case? +			default: +				LOG(PHIDGET_LOG_INFO, "libusb_get_string_descriptor failed in CUSBGetDeviceCapabilities with error code: %d while reading label\ +					- this probably just means the device doesn't support labels, so this is fine.", len); +		} +		phid->label[0]='\0'; +		return EPHIDGET_OK; +	} +	else +		return decodeLabelString(labelBuf, phid->label, phid->serialNumber); +} + +int CUSBRefreshLabelString(CPhidgetHandle phid) +{ +	return getLabelString(phid, (struct libusb_device_handle *)phid->deviceHandle); +} + +int CUSBGetDeviceCapabilities(CPhidgetHandle phid, struct libusb_device *dev, struct libusb_device_handle *udev) { +	unsigned char buf[255]; +	int len = 0, i = 0, j, ret; +	const struct libusb_interface_descriptor *interfaceDesc; +	struct libusb_config_descriptor *configDesc = NULL; +	 +	memset(buf, 0, sizeof(buf)); +	 +	//Get config descriptor +	if((ret = libusb_get_active_config_descriptor(dev, &configDesc)) == 0) +	{ +		interfaceDesc = NULL; +		 +		//Find the interface Descriptor +		for(i=0; i<configDesc->bNumInterfaces; i++) +		{ +			for(j=0; j<configDesc->interface[i].num_altsetting; j++) +			{ +				if(configDesc->interface[i].altsetting[j].bInterfaceNumber == phid->deviceDef->pdd_iid) +				{ +					interfaceDesc = &configDesc->interface[i].altsetting[j]; +					break; +				} +			} +		} +		 +		if(interfaceDesc == NULL) +		{ +			LOG(PHIDGET_LOG_ERROR, "Couldn't find interface descriptor!"); +			ret = EPHIDGET_UNEXPECTED; +			goto done; +		} +		 +		if(interfaceDesc->bNumEndpoints == 2) +		{ +			LOG(PHIDGET_LOG_INFO, "Using Interrupt OUT Endpoint for Host->Device communication."); +			phid->interruptOutEndpoint = PTRUE; +		} +		else +		{ +			LOG(PHIDGET_LOG_INFO, "Using Control Endpoint for Host->Device communication."); +			phid->interruptOutEndpoint = PFALSE; +		} +	} +	else +	{ +		LOG(PHIDGET_LOG_ERROR, "libusb_get_active_config_descriptor failed in CUSBGetDeviceCapabilities with error code: %d", ret); +		ret = EPHIDGET_UNEXPECTED; +		goto done; +	} +	 +	//Get a HID descriptor +	len = libusb_control_transfer(udev, LIBUSB_ENDPOINT_IN+1,  +						LIBUSB_REQUEST_GET_DESCRIPTOR, +						(LIBUSB_DT_REPORT << 8) + 0, phid->deviceDef->pdd_iid, (char*)buf,  +						sizeof(buf), 500 /* ms timeout */); +						 +	if(len < 0) +	{ +		switch(len) +		{ +		case LIBUSB_ERROR_TIMEOUT: //important case? +		default: +				LOG(PHIDGET_LOG_ERROR, "usb_control_msg failed in CUSBGetDeviceCapabilities with error code: %d", len); +				ret = EPHIDGET_UNEXPECTED; +				goto done; +		} +	} +	 +	if(len >= 10) +	{	 +		for(i=10;i<len;i++) { +			if(buf[i]==0x81 && buf[i-2]==0x95) +				phid->inputReportByteLength=buf[i-1]; +			else if(buf[i]==0x81 && buf[i-4]==0x95) +				phid->inputReportByteLength=buf[i-3]; +			if(buf[i]==0x91 && buf[i-2]==0x95) +				phid->outputReportByteLength=buf[i-1]; +			else if(buf[i]==0x91 && buf[i-4]==0x95) +				phid->outputReportByteLength=buf[i-3]; +		} +	} +	else +	{ +		LOG(PHIDGET_LOG_ERROR, "Couldn't get report lengths in CUSBGetDeviceCapabilities"); +		ret = EPHIDGET_UNEXPECTED; +		goto done; +	} +	 +	ret = getLabelString(phid, udev); +	 +done: +	if(configDesc) +		libusb_free_config_descriptor(configDesc); +	return ret; +} + +libusb_context * libusbContext = NULL; +void CUSBUninit() +{ +	if(libusbContext) +	{ +		LOG(PHIDGET_LOG_INFO, "Deinitializing libusb"); +		libusb_exit(libusbContext); +		libusbContext = NULL; +	} +} + +int CUSBBuildList(CPhidgetList **curList) { +	int MemberIndex, i, j, ret = EPHIDGET_OK, found; +	unsigned long Length; +	CPhidgetList *traverse; +	Length = 0; +	MemberIndex = 0; +	CPhidgetHandle phid; +	char unique_name[20]; +	libusb_device **list = NULL; +	 +	TESTPTR(curList) +	 +	if(!libusbContext) +	{ +		LOG(PHIDGET_LOG_INFO, "Initializing libusb"); +		if((ret = libusb_init(&libusbContext)) != 0) +		{ +			LOG(PHIDGET_LOG_ERROR, "libusb_init failed with error code: %d", ret); +			libusbContext = NULL; +			goto done; +		} +	} +	 +	ssize_t cnt = libusb_get_device_list(NULL, &list); +	if(cnt < 0) +	{ +		LOG(PHIDGET_LOG_ERROR, "libusb_get_device_list failed with error code: %d", cnt); +		goto done; +	} +	 +	//search through all USB devices +	for (j = 0; j < cnt; j++)  +	{ +		libusb_device *device = list[j]; +		 +		snprintf(unique_name,20,"%d/%d",libusb_get_bus_number(device), libusb_get_device_address(device)); +		 +		found = PFALSE; +		if (AttachedDevices) { +			// we need to loop all the way through because composite devices will appear twice in the list with the same 'unique' name +			for (traverse = AttachedDevices; traverse; traverse=traverse->next) { +				if (!strcmp((char *)traverse->phid->CPhidgetFHandle, unique_name)) { +					CList_addToList((CListHandle *)curList, traverse->phid, CPhidget_areEqual); +					found = PTRUE; +				} +			} +			if(found) goto next; +		} +		 +		struct libusb_device_descriptor	desc; +		if((ret = libusb_get_device_descriptor(device, &desc)) != 0) +		{ +			LOG(PHIDGET_LOG_ERROR, "libusb_get_device_descriptor failed with error code: %d", ret); +			goto next; +		} +		 +		//LOG(PHIDGET_LOG_DEBUG, "Device %d: %04x %04x", j, desc.idVendor, desc.idProduct); +	 +		for (i = 1; i<PHIDGET_DEVICE_COUNT; i++) {	  +			if ((desc.idVendor == Phid_Device_Def[i].pdd_vid) &&  +				(desc.idProduct == Phid_Device_Def[i].pdd_pid)) +			{ +				if (!(phid = (CPhidgetHandle)malloc(sizeof (*phid)))) +				{ +					ret = EPHIDGET_NOMEMORY; +					goto done; +				} +				ZEROMEM(phid, sizeof(*phid)); +				 +				//LOG(PHIDGET_LOG_DEBUG,"New Device: %s",(char *)Phid_DeviceName[Phid_Device_Def[i].pdd_did]); +				 +				libusb_device_handle *handle = NULL; +				if (libusb_open(device, &handle) == 0) +				{ +					if (desc.bcdDevice < 0x100)  +						phid->deviceVersion = desc.bcdDevice * 100; +					else +						phid->deviceVersion = ((desc.bcdDevice >> 8) * 100) + ((desc.bcdDevice & 0xff)); +					phid->deviceType = (char *)Phid_DeviceName[Phid_Device_Def[i].pdd_did]; + +					CPhidget_setStatusFlag(&phid->status, PHIDGET_ATTACHED_FLAG, &phid->lock); +					phid->deviceIDSpec = Phid_Device_Def[i].pdd_sdid; +					phid->deviceUID = CPhidget_getUID(phid->deviceIDSpec, phid->deviceVersion); +					phid->deviceDef = &Phid_Device_Def[i]; +					phid->deviceID = Phid_Device_Def[i].pdd_did; +					phid->ProductID = desc.idProduct; +					phid->VendorID = desc.idVendor; +					 +					if (desc.iSerialNumber) { +						char string[256]; +						memset(string, 0, 256); +						if((ret = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, string, sizeof(string))) < 0) +						{ +							LOG(PHIDGET_LOG_ERROR, "libusb_get_string_descriptor_ascii failed with error code: %d", ret); +							LOG(PHIDGET_LOG_INFO, "This usually means you need to run as root"); +							libusb_close(handle); +							free(phid); +							goto next; +						} +						else +						{ +							phid->serialNumber = atol(string); +							getLabelString(phid, handle); +						} +					} +					phid->specificDevice = TRUE; +					phid->attr = Phid_Device_Def[i].pdd_attr; +					 +					if(!(phid->CPhidgetFHandle = strdup(unique_name))) +					{ +						ret = EPHIDGET_NOMEMORY; +						goto done; +					} +					 +					LOG(PHIDGET_LOG_INFO, "New device in CUSBBuildList: %s", (char *)phid->CPhidgetFHandle); + +					libusb_close(handle); +					CList_addToList((CListHandle *)curList, phid, CPhidget_areEqual); +				} //if(udev) +				else +				{ +					free(phid); +					libusb_close(handle); +				} +			} //vendor, product ids match +		} /* iterate over phidget device table */ +next: ; +	} /* iterate over USB devices */ +	 +done: +	if(list)	 +		libusb_free_device_list(list, 1); +    return ret; +} + +void CUSBCleanup(void) +{ +	; +} +/*  +	CUSBOpenHandle takes a CPhidgetInfo structure, with  +	ProductID/VendorID/SerialNumber filled in. + +	Serial number is always filled in. +*/ +int CUSBOpenHandle(CPhidgetHandle phid) +{ +	int idVendor; +	int idProduct; +	int serial = 0; +	int i, j,ret = EPHIDGET_OK; +	libusb_device **list = NULL; +	 +	ssize_t cnt = libusb_get_device_list(NULL, &list); +	 +	if(cnt < 0) +	{ +		LOG(PHIDGET_LOG_ERROR, "libusb_get_device_list failed with error code: %d", cnt); +		goto done; +	} +	 +	//search through all USB devices +	for (j = 0; j < cnt; j++)  +	{ +		libusb_device *device = list[j]; +		 +		struct libusb_device_descriptor	desc; +		if((ret = libusb_get_device_descriptor(device, &desc)) != 0) +		{ +			LOG(PHIDGET_LOG_ERROR, "libusb_get_device_descriptor failed with error code: %d", ret); +			goto next; +		} +		 +		for (i = 1; i<PHIDGET_DEVICE_COUNT; i++) { +			if (Phid_Device_Def[i].pdd_did == phid->deviceID) { +				idVendor = Phid_Device_Def[i].pdd_vid; +				idProduct = Phid_Device_Def[i].pdd_pid; +				if ((desc.idVendor == idVendor) && (desc.idProduct == idProduct)) { +					 +					/* the vend/prod matches! */ +					libusb_device_handle *handle = NULL; +					if (libusb_open(device, &handle) == 0) +					{ +						serial = -1; +						if (desc.iSerialNumber) { +							char string[256]; +							if((ret = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, string, sizeof(string))) < 0) +							{ +								LOG(PHIDGET_LOG_WARNING, "libusb_get_string_descriptor_ascii failed with error code: %d", ret); +								LOG(PHIDGET_LOG_INFO, "This usually means you need to run as root"); +								libusb_close(handle); +								goto next; +							} +							else +							{ +								serial = atol(string); +							} +						} +						if (serial == phid->serialNumber) { +							//Detach any Kernel Drivers +							if((ret = libusb_kernel_driver_active(handle, Phid_Device_Def[i].pdd_iid)) < 0) +							{ +								LOG(PHIDGET_LOG_WARNING, "libusb_kernel_driver_active failed with error code: %d", ret); +							} +							else if(ret == 1) +							{ +								LOG(PHIDGET_LOG_INFO, "Kernel driver is active - will attempt a detach"); +								if((ret = libusb_detach_kernel_driver(handle, Phid_Device_Def[i].pdd_iid)) != 0) +								{ +									LOG(PHIDGET_LOG_WARNING, "libusb_detach_kernel_driver failed with error code: %d", ret); +								} +								else +								{ +									LOG(PHIDGET_LOG_INFO, "Successfully detached kernel driver"); +								} +							} +							 +							if((ret = libusb_claim_interface(handle, Phid_Device_Def[i].pdd_iid)) != 0) +							{ +								LOG(PHIDGET_LOG_WARNING, "libusb_claim_interface failed with error code: %d", ret); +								libusb_close(handle); +							} +							else +							{ +								/* the serialnum is okay */ +						 +								phid->deviceHandle = (HANDLE)handle; +								phid->deviceIDSpec = Phid_Device_Def[i].pdd_sdid; +								phid->deviceDef = &Phid_Device_Def[i]; +								phid->deviceType = (char *)Phid_DeviceName[Phid_Device_Def[i].pdd_did]; +		 +								phid->ProductID = idProduct; +								phid->VendorID = idVendor; +								if (desc.bcdDevice < 0x100) +									phid->deviceVersion = desc.bcdDevice * 100; +								else +									phid->deviceVersion = ((desc.bcdDevice >> 8) * 100) + ((desc.bcdDevice & 0xff)); +									 +								phid->deviceUID = CPhidget_getUID(phid->deviceIDSpec, phid->deviceVersion); +								phid->serialNumber = serial; +		 +								if((ret = CUSBGetDeviceCapabilities(phid, device, handle))) +								{ +									LOG(PHIDGET_LOG_ERROR, "CUSBGetDeviceCapabilities returned nonzero code: %d", ret); +								} + +								phid->attr = Phid_Device_Def[i].pdd_attr; +		 +								ret = EPHIDGET_OK; +								goto done; +							} /* usb_claim_interface */ +						} /* serial matches */ +						else +						{ +							libusb_close(handle); +						} +					} /* udev open */ +					else +					{ +						libusb_close(handle); +						LOG(PHIDGET_LOG_WARNING, "usb_open failed - bad permission or what?"); +					} +				} /* vendor/product match */ +			} /* deviceID matches in table */ +		} /* iterate over phidget device table */ +next: ; +	} /* iterate over USB devices */ +done: +	if(list)	 +		libusb_free_device_list(list, 1); +	 +  	return ret; +} diff --git a/linux/cusblinux.c b/linux/cusblinux.c index 3a12fca..5e4886c 100644 --- a/linux/cusblinux.c +++ b/linux/cusblinux.c @@ -9,6 +9,12 @@  #include "stdafx.h"  #include "cusb.h" +#include <usb.h> + +int CUSBGetDeviceCapabilities(CPhidgetHandle phid, struct usb_device *dev, struct usb_dev_handle *udev); + +void CUSBUninit() +{}  int CUSBCloseHandle(CPhidgetHandle phid) {  	int ret = 0; @@ -472,6 +478,7 @@ int CUSBBuildList(CPhidgetList **curList) {  						CPhidget_setStatusFlag(&phid->status, PHIDGET_ATTACHED_FLAG, &phid->lock);  						phid->deviceIDSpec = Phid_Device_Def[i].pdd_sdid; +						phid->deviceUID = CPhidget_getUID(phid->deviceIDSpec, phid->deviceVersion);  						phid->deviceDef = &Phid_Device_Def[i];  						phid->deviceID = Phid_Device_Def[i].pdd_did;  						phid->ProductID = dev->descriptor.idProduct; @@ -634,7 +641,9 @@ int CUSBOpenHandle(CPhidgetHandle phid)  									if (dev->descriptor.bcdDevice < 0x100)  										phid->deviceVersion = dev->descriptor.bcdDevice * 100;  									else -										phid->deviceVersion = ((dev->descriptor.bcdDevice >> 8) * 100) + ((dev->descriptor.bcdDevice & 0xff));			 +										phid->deviceVersion = ((dev->descriptor.bcdDevice >> 8) * 100) + ((dev->descriptor.bcdDevice & 0xff)); +										 +									phid->deviceUID = CPhidget_getUID(phid->deviceIDSpec, phid->deviceVersion);  									phid->serialNumber = serial;  									if((ret = CUSBGetDeviceCapabilities(phid, dev, udev))) diff --git a/linux/zeroconf_avahi.c b/linux/zeroconf_avahi.c index 98187bf..9b205b3 100644 --- a/linux/zeroconf_avahi.c +++ b/linux/zeroconf_avahi.c @@ -301,6 +301,7 @@ void PhidFromTXT(CPhidgetHandle phid, uint16_t txtLen, const char *txtRecord)  		phid->deviceType = Phid_DeviceName[phid->deviceID];
  		free(type);
  	}
 +	phid->deviceUID = CPhidget_getUID(phid->deviceIDSpec, phid->deviceVersion);
  	phid->networkInfo->mdns = PTRUE;
 diff --git a/phidget21.h b/phidget21.h index 363a29e..c9f62ea 100644 --- a/phidget21.h +++ b/phidget21.h @@ -95,7 +95,89 @@ typedef enum {   PHIDID_TEXTLED_1x8 = 0x049,   PHIDID_TEXTLED_4x8 = 0x048,   PHIDID_WEIGHTSENSOR = 0x072, + PHIDID_FIRMWARE_UPGRADE = 0x098,  } CPhidget_DeviceID; +typedef enum { + PHIDUID_NOTHING =1, + PHIDUID_ACCELEROMETER_2AXIS_2G, + PHIDUID_ACCELEROMETER_2AXIS_10G, + PHIDUID_ACCELEROMETER_2AXIS_5G, + PHIDUID_ACCELEROMETER_3AXIS_3G, + PHIDUID_ADVANCEDSERVO_1MOTOR, + PHIDUID_ADVANCEDSERVO_8MOTOR, + PHIDUID_ADVANCEDSERVO_8MOTOR_PGOOD_FLAG, + PHIDUID_ADVANCEDSERVO_8MOTOR_CURSENSE_FIX, + PHIDUID_ANALOG_4OUTPUT, + PHIDUID_BRIDGE_4INPUT, + PHIDUID_ENCODER_1ENCODER_1INPUT_OLD, + PHIDUID_ENCODER_1ENCODER_1INPUT_v1, + PHIDUID_ENCODER_1ENCODER_1INPUT_v2, + PHIDUID_ENCODER_HS_1ENCODER, + PHIDUID_ENCODER_HS_4ENCODER_4INPUT, + PHIDUID_FREQUENCYCOUNTER_2INPUT, + PHIDUID_GPS, + PHIDUID_INTERFACEKIT_0_0_4_NO_ECHO, + PHIDUID_INTERFACEKIT_0_0_4, + PHIDUID_INTERFACEKIT_0_0_8, + PHIDUID_INTERFACEKIT_0_5_7, + PHIDUID_INTERFACEKIT_0_8_8_w_LCD, + PHIDUID_INTERFACEKIT_0_16_16_NO_ECHO, + PHIDUID_INTERFACEKIT_0_16_16_BITBUG, + PHIDUID_INTERFACEKIT_0_16_16, + PHIDUID_INTERFACEKIT_2_2_2, + PHIDUID_INTERFACEKIT_2_8_8, + PHIDUID_INTERFACEKIT_4_8_8, + PHIDUID_INTERFACEKIT_8_8_8_NO_ECHO, + PHIDUID_INTERFACEKIT_8_8_8, + PHIDUID_INTERFACEKIT_8_8_8_FAST, + PHIDUID_INTERFACEKIT_8_8_8_w_LCD_NO_ECHO, + PHIDUID_INTERFACEKIT_8_8_8_w_LCD, + PHIDUID_INTERFACEKIT_8_8_8_w_LCD_FAST, + PHIDUID_INTERFACEKIT_TOUCH_SLIDER, + PHIDUID_INTERFACEKIT_TOUCH_ROTARY, + PHIDUID_IR, + PHIDUID_LED_64, + PHIDUID_LED_64_ADV, + PHIDUID_MOTORCONTROL_1MOTOR, + PHIDUID_MOTORCONTROL_HC_2MOTOR, + PHIDUID_MOTORCONTROL_LV_2MOTOR_4INPUT, + PHIDUID_PHSENSOR, + PHIDUID_RFID_OLD, + PHIDUID_RFID, + PHIDUID_RFID_2OUTPUT_NO_ECHO, + PHIDUID_RFID_2OUTPUT, + PHIDUID_RFID_2OUTPUT_ADVANCED, + PHIDUID_SERVO_1MOTOR_OLD, + PHIDUID_SERVO_4MOTOR_OLD, + PHIDUID_SERVO_1MOTOR_NO_ECHO, + PHIDUID_SERVO_1MOTOR, + PHIDUID_SERVO_4MOTOR_NO_ECHO, + PHIDUID_SERVO_4MOTOR, + PHIDUID_SPATIAL_ACCEL_3AXIS_1049, + PHIDUID_SPATIAL_ACCEL_3AXIS_1041, + PHIDUID_SPATIAL_ACCEL_3AXIS_1043, + PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1056, + PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1056_NEG_GAIN, + PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1042, + PHIDUID_SPATIAL_ACCEL_GYRO_COMPASS_1044, + PHIDUID_STEPPER_BIPOLAR_1MOTOR, + PHIDUID_STEPPER_UNIPOLAR_4MOTOR, + PHIDUID_TEMPERATURESENSOR_OLD, + PHIDUID_TEMPERATURESENSOR, + PHIDUID_TEMPERATURESENSOR_AD22100, + PHIDUID_TEMPERATURESENSOR_TERMINAL_BLOCKS, + PHIDUID_TEMPERATURESENSOR_4, + PHIDUID_TEMPERATURESENSOR_IR, + PHIDUID_TEXTLCD_2x20, + PHIDUID_TEXTLCD_2x20_w_8_8_8, + PHIDUID_TEXTLCD_2x20_w_8_8_8_BRIGHTNESS, + PHIDUID_TEXTLCD_ADAPTER, + PHIDUID_TEXTLED_1x8, + PHIDUID_TEXTLED_4x8, + PHIDUID_WEIGHTSENSOR, + PHIDUID_GENERIC, + PHIDUID_FIRMWARE_UPGRADE +} CPhidget_DeviceUID;   int CPhidget_open(CPhidgetHandle phid, int serialNumber);   int CPhidget_openLabel(CPhidgetHandle phid, const char *label);   int CPhidget_close(CPhidgetHandle phid); @@ -135,7 +217,6 @@ typedef struct _CPhidgetDictionaryListener *CPhidgetDictionaryListenerHandle;      int( *fptr)(CPhidgetDictionaryHandle, void *userPtr, int errorCode, const char *errorString), void *userPtr);   int CPhidgetDictionary_addKey(CPhidgetDictionaryHandle dict, const char *key, const char *value, int persistent);   int CPhidgetDictionary_removeKey(CPhidgetDictionaryHandle dict, const char *pattern); -  typedef int( *CPhidgetDictionary_OnKeyChange_Function)(CPhidgetDictionaryHandle dict, void *userPtr,   const char *key, const char *value, CPhidgetDictionary_keyChangeReason reason);   int CPhidgetDictionary_set_OnKeyChange_Handler(CPhidgetDictionaryHandle dict, CPhidgetDictionaryListenerHandle *dictlistener, const char *pattern, @@ -161,11 +242,6 @@ typedef struct _CPhidgetManager *CPhidgetManagerHandle;   int CPhidgetManager_set_OnServerDisconnect_Handler(CPhidgetManagerHandle phidm, int ( *fptr)(CPhidgetManagerHandle phidm, void *userPtr), void *userPtr);   int CPhidgetManager_getServerID(CPhidgetManagerHandle phidm, const char **serverID);   int CPhidgetManager_getServerAddress(CPhidgetManagerHandle phidm, const char **address, int *port); - - - - -   int CPhidgetManager_getServerStatus(CPhidgetManagerHandle phidm, int *serverStatus);   int CPhidget_openRemote(CPhidgetHandle phid, int serial, const char *serverID, const char *password);   int CPhidget_openLabelRemote(CPhidgetHandle phid, const char *label, const char *serverID, const char *password); @@ -249,15 +325,7 @@ typedef enum {   int CPhidgetAdvancedServo_getEngaged(CPhidgetAdvancedServoHandle phid, int index, int *engagedState);   int CPhidgetAdvancedServo_setEngaged(CPhidgetAdvancedServoHandle phid, int index, int engagedState);   int CPhidgetAdvancedServo_getStopped(CPhidgetAdvancedServoHandle phid, int index, int *stoppedState); - -   int CPhidgetAdvancedServo_getServoType(CPhidgetAdvancedServoHandle phid, int index, CPhidget_ServoType *servoType); - - - - - -   int CPhidgetAdvancedServo_setServoType(CPhidgetAdvancedServoHandle phid, int index, CPhidget_ServoType servoType);   int CPhidgetAdvancedServo_setServoParameters(CPhidgetAdvancedServoHandle phid, int index, double min_us,double max_us,double degrees,double velocity_max);  typedef struct _CPhidgetAnalog *CPhidgetAnalogHandle; @@ -48,6 +48,9 @@  #ifdef _WINDOWS  // Defines & Include for Windows only +	#ifndef AI_ADDRCONFIG +		#define AI_ADDRCONFIG   0x00000400  // Resolution only if global address configured +	#endif  	//On Windows (but not WinCE), compile in Labview functions  	#ifndef WINCE @@ -232,11 +235,6 @@  	#elif _LINUX  		// Defines & Include for Linux Only - -        // No libusb on Android -        #ifndef _ANDROID -            #include <usb.h> -        #endif  		#include <assert.h>  		#include <dlfcn.h> diff --git a/utils/utils.c b/utils/utils.c index 57611f2..22d2ec8 100644 --- a/utils/utils.c +++ b/utils/utils.c @@ -911,7 +911,7 @@ tryagain:  		return 0;  	} else  	{ -		pu_log(PUL_VERB,0,"Recieved: \"%s\"", (char *)buf); +		pu_log(PUL_VERB,0,"Received: \"%s\"", (char *)buf);  		return res;  	}  } @@ -1,2 +1,2 @@  #!/bin/bash -echo -n 2.1.8.20120216 +echo -n 2.1.8.20120507 @@ -1,1231 +1,1232 @@ -#include "stdafx.h" -#include "csocket.h" -#include "csocketevents.h" -#include "cphidgetlist.h" -#include "cphidgetmanager.h" -#include "cphidgetdictionary.h" -#include "cphidgetsbc.h" -#include "zeroconf.h" -#include "dns_sd.h" - -#ifdef ZEROCONF_RUNTIME_LINKING -//function prototypes for run-time loaded library -typedef DNSServiceErrorType (DNSSD_API * DNSServiceRegisterType)  -(DNSServiceRef *,DNSServiceFlags,uint32_t,const char *, - const char *,const char *,const char *,uint16_t,uint16_t, - const void *,DNSServiceRegisterReply,void *); -typedef DNSServiceErrorType (DNSSD_API * DNSServiceProcessResultType) (DNSServiceRef); -typedef void (DNSSD_API * DNSServiceRefDeallocateType) (DNSServiceRef); -typedef DNSServiceErrorType (DNSSD_API * DNSServiceAddRecordType) -(DNSServiceRef, DNSRecordRef *, DNSServiceFlags,  - uint16_t, uint16_t, const void *, uint32_t); -typedef DNSServiceErrorType (DNSSD_API * DNSServiceUpdateRecordType) -(DNSServiceRef, DNSRecordRef, DNSServiceFlags,  - uint16_t, const void *, uint32_t); -typedef DNSServiceErrorType (DNSSD_API * DNSServiceRemoveRecordType) -(DNSServiceRef, DNSRecordRef, DNSServiceFlags); -typedef DNSServiceErrorType (DNSSD_API * DNSServiceBrowseType) -(DNSServiceRef *, DNSServiceFlags, uint32_t, const char *, - const char *, DNSServiceBrowseReply, void *); -typedef DNSServiceErrorType (DNSSD_API * DNSServiceResolveType) -(DNSServiceRef *, DNSServiceFlags, uint32_t, const char *, - const char *, const char *, DNSServiceResolveReply,  - void *context); -typedef DNSServiceErrorType (DNSSD_API * DNSServiceQueryRecordType) -(DNSServiceRef *, DNSServiceFlags, uint32_t, const char *, - uint16_t, uint16_t, DNSServiceQueryRecordReply, void *context); -typedef int (DNSSD_API * DNSServiceConstructFullNameType) -(char *, const char *, const char *, const char *); -typedef int (DNSSD_API * DNSServiceRefSockFDType) (DNSServiceRef sdRef); -#else -#define DNSServiceRegisterPtr DNSServiceRegister -#define DNSServiceProcessResultPtr DNSServiceProcessResult -#define DNSServiceRefDeallocatePtr DNSServiceRefDeallocate -#define DNSServiceAddRecordPtr DNSServiceAddRecord -#define DNSServiceUpdateRecordPtr DNSServiceUpdateRecord -#define DNSServiceRemoveRecordPtr DNSServiceRemoveRecord -#define DNSServiceBrowsePtr DNSServiceBrowse -#define DNSServiceResolvePtr DNSServiceResolve -#define DNSServiceQueryRecordPtr DNSServiceQueryRecord -#define DNSServiceConstructFullNamePtr DNSServiceConstructFullName -#define DNSServiceRefSockFDPtr DNSServiceRefSockFD -#endif - -int Dns_sdInitialized = FALSE; -int Dns_sdBrowsing = FALSE; -int stopBrowsing = FALSE; -DNSServiceRef zeroconf_browse_ws_ref  = NULL; -DNSServiceRef zeroconf_browse_sbc_ref  = NULL; -DNSServiceRef zeroconf_browse_phidget_ref  = NULL; - -pthread_t dns_thread = NULL; - -#ifdef ZEROCONF_RUNTIME_LINKING - -//DNS_SD functions -DNSServiceRegisterType DNSServiceRegisterPtr = NULL; -DNSServiceProcessResultType DNSServiceProcessResultPtr = NULL; -DNSServiceRefDeallocateType DNSServiceRefDeallocatePtr = NULL; -DNSServiceAddRecordType DNSServiceAddRecordPtr = NULL; -DNSServiceUpdateRecordType DNSServiceUpdateRecordPtr = NULL; -DNSServiceRemoveRecordType DNSServiceRemoveRecordPtr = NULL; -DNSServiceBrowseType DNSServiceBrowsePtr = NULL; -DNSServiceResolveType DNSServiceResolvePtr = NULL; -DNSServiceQueryRecordType DNSServiceQueryRecordPtr = NULL; -DNSServiceConstructFullNameType DNSServiceConstructFullNamePtr = NULL; -DNSServiceRefSockFDType DNSServiceRefSockFDPtr = NULL; - -#ifdef _WINDOWS -HMODULE dllHandle = NULL; -#elif _LINUX -void *libHandle = NULL; -#endif -#endif - - -static uint8_t *InternalTXTRecordSearch -( - uint16_t         txtLen, - const void       *txtRecord, - const char       *key, - unsigned long    *keylen - ) -{ -	uint8_t *p = (uint8_t*)txtRecord; -	uint8_t *e = p + txtLen; -	*keylen = (unsigned long) strlen(key); -	while (p<e) -	{ -		uint8_t *x = p; -		p += 1 + p[0]; -		if (p <= e && *keylen <= x[0] && !strncmp(key, (char*)x+1, *keylen)) -			if (*keylen == x[0] || x[1+*keylen] == '=') return(x); -	} -	return(NULL); -} - -const void * TXTRecordGetValuePtrPtr -( - uint16_t         txtLen, - const void       *txtRecord, - const char       *key, - uint8_t          *valueLen - ) -{ -	unsigned long keylen; -	uint8_t *item = InternalTXTRecordSearch(txtLen, txtRecord, key, &keylen); -	if (!item || item[0] <= keylen) return(NULL);	// If key not found, or found with no value, return NULL -	*valueLen = (uint8_t)(item[0] - (keylen + 1)); -	return (item + 1 + keylen + 1); -} - -int dns_callback_thread(void *ptr) -{     -    int nfds; -    fd_set readfds; -    struct timeval tv; -    int result; -	 -	int ws_fd = DNSServiceRefSockFDPtr(zeroconf_browse_ws_ref); -	int sbc_fd = DNSServiceRefSockFDPtr(zeroconf_browse_sbc_ref); -	int phidget_fd = DNSServiceRefSockFDPtr(zeroconf_browse_phidget_ref); -	 -	nfds = ws_fd; -	if(sbc_fd>nfds) -		nfds = sbc_fd; -	if(phidget_fd > nfds) -		nfds = phidget_fd; -	nfds++; -	 -	while (!stopBrowsing) -	{ -		FD_ZERO(&readfds); -		FD_SET(ws_fd, &readfds); -		FD_SET(sbc_fd, &readfds); -		FD_SET(phidget_fd, &readfds); -		 -		//100ms -		tv.tv_sec = 0; -		tv.tv_usec = 100000; -		 -		result = select(nfds, &readfds, (fd_set*)NULL, (fd_set*)NULL, &tv); -		if (result > 0) -		{ -			DNSServiceErrorType err = kDNSServiceErr_NoError; -			if (FD_ISSET(ws_fd, &readfds)) -			{ -				if ((err = DNSServiceProcessResultPtr(zeroconf_browse_ws_ref)) != kDNSServiceErr_NoError) -					stopBrowsing = 1; -			} -			if (FD_ISSET(sbc_fd, &readfds)) -			{ -				if ((err = DNSServiceProcessResultPtr(zeroconf_browse_sbc_ref)) != kDNSServiceErr_NoError) -					stopBrowsing = 1; -			} -			if (FD_ISSET(phidget_fd, &readfds)) -			{ -				if ((err = DNSServiceProcessResultPtr(zeroconf_browse_phidget_ref)) != kDNSServiceErr_NoError) -					stopBrowsing = 1; -			} -		} -		else if(result == SOCKET_ERROR) -		{ -			LOG(PHIDGET_LOG_DEBUG, "select(  ) returned %d errno %d %s\n", result, errno, strerror(errno)); -			if (errno != EINTR) -				stopBrowsing = 1; -		} -		//result==0 means timeout, loop around again -	} -	return EPHIDGET_OK; -} - -void PhidFromTXT(CPhidgetHandle phid, uint16_t txtLen, const char *txtRecord) -{ -	int i = 0; -	short txtver; -	//char *label = NULL; -	char temp[128]; -	//unsigned int labelLen = 0; -	 -	uint8_t valLen = 0; -	const char *valPtr = NULL; -	 -	//txt version -	if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "txtvers", &valLen))) return; -	memcpy(temp, valPtr, valLen); -	temp[valLen] = '\0'; -	txtver = (short)strtol(temp, NULL, 10); -	 -	//Serial Number -	if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "serial", &valLen))) return; -	memcpy(temp, valPtr, valLen); -	temp[valLen] = '\0'; -	phid->serialNumber = strtol(temp, NULL, 10); -	phid->specificDevice = PHIDGETOPEN_SERIAL; -	 -	//version -	if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "version", &valLen))) return; -	memcpy(temp, valPtr, valLen); -	temp[valLen] = '\0'; -	phid->deviceVersion = strtol(temp, NULL, 10); -	 -	//label -	if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "label", &valLen))) return; -	if(valLen >= MAX_LABEL_STORAGE) valLen = MAX_LABEL_STORAGE-1; -	memcpy(phid->label, valPtr, valLen); -	phid->label[valLen] = '\0'; -	/*	memcpy(temp, valPtr, valLen); -	 temp[valLen] = '\0'; -	 unescape(temp, &label, &labelLen); -	 if(labelLen > MAX_LABEL_STORAGE-1) labelLen = MAX_LABEL_STORAGE-1; -	 memcpy(phid->label, label, labelLen); -	 phid->label[labelLen] = '\0'; -	 free(label);*/ -	 -	//server_id -	if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "server_id", &valLen))) return; -	free(phid->networkInfo->zeroconf_server_id); -	if(!(phid->networkInfo->zeroconf_server_id = malloc(valLen+1))) return; -	ZEROMEM(phid->networkInfo->zeroconf_server_id, valLen+1); -	memcpy(phid->networkInfo->zeroconf_server_id, valPtr, valLen); -	 -	// things added in version 2 of the txt -	if(txtver >= 2) -	{ -		//Device ID -		if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "id", &valLen))) return; -		memcpy(temp, valPtr, valLen); -		temp[valLen] = '\0'; -		phid->deviceIDSpec = strtol(temp, NULL, 10); -		 -		for(i = 1;i<PHIDGET_DEVICE_COUNT;i++) -			if(phid->deviceIDSpec == Phid_Device_Def[i].pdd_sdid) break; -		phid->deviceDef = &Phid_Device_Def[i]; -		phid->attr = Phid_Device_Def[i].pdd_attr; -		 -		//Device Class -		if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "class", &valLen))) return; -		memcpy(temp, valPtr, valLen); -		temp[valLen] = '\0'; -		phid->deviceID = strtol(temp, NULL, 10); -		phid->deviceType = Phid_DeviceName[phid->deviceID]; -	} -	//Old version uses string searching, but some devices have the same name with different IDs -	else -	{ -		char *name = NULL; -		char *type = NULL; -		 -		//name -		if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "name", &valLen))) return; -		if(!(name = malloc(valLen+1))) return; -		ZEROMEM(name, valLen+1); -		memcpy(name, valPtr, valLen); -		for(i = 0;i<PHIDGET_DEVICE_COUNT;i++) -		{ -			if(!strcmp(name, Phid_Device_Def[i].pdd_name)) -			{ -				phid->deviceIDSpec = Phid_Device_Def[i].pdd_sdid; -				phid->deviceDef = &Phid_Device_Def[i]; -				phid->attr = Phid_Device_Def[i].pdd_attr; -				break; -			} -		} -		free(name); -		 -		//type -		if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "type", &valLen))) return; -		if(!(type = malloc(valLen+1))) return; -		ZEROMEM(type, valLen+1); -		memcpy(type, valPtr, valLen); -		phid->deviceID = phidget_type_to_id(type); -		phid->deviceType = Phid_DeviceName[phid->deviceID]; -		free(type); -	} -	 -	phid->networkInfo->mdns = PTRUE; -	 -} - -void DNSServiceQueryRecord_Phidget_CallBack -( - DNSServiceRef                       DNSServiceRef, - DNSServiceFlags                     flags, - uint32_t                            interfaceIndex, - DNSServiceErrorType                 errorCode, - const char                          *fullname, - uint16_t                            rrtype, - uint16_t                            rrclass, - uint16_t                            rdlen, - const void                          *rdata, - uint32_t                            ttl, - void                                *context - ) -{ -	if (errorCode != kDNSServiceErr_NoError) -		LOG(PHIDGET_LOG_ERROR, "DNSServiceQueryRecord_Phidget_CallBack returned error: %d\n", errorCode); -	else -	{ -		CPhidgetHandle phid = (CPhidgetHandle)context; -		LOG(PHIDGET_LOG_INFO, "DNSServiceQueryRecord_Phidget_CallBack: %s (%d)",fullname,interfaceIndex); -		 -		PhidFromTXT(phid, rdlen, rdata); -	} -} - -void SBCFromTXT(CPhidgetSBCHandle sbc, uint16_t txtLen, const char *txtRecord) -{ -	char *hversion = NULL, *txtver = NULL; -	 -	uint8_t valLen = 0; -	const char *valPtr = NULL; -	 -	//txt version -	if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "txtvers", &valLen))) return; -	if(!(txtver = malloc(valLen+1))) return; -	ZEROMEM(txtver, valLen+1); -	memcpy(txtver, valPtr, valLen); -	sbc->txtver = (short)strtol(txtver, NULL, 10); -	free(txtver); -	 -	//Firmware version -	if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "fversion", &valLen))) return; -	if(valLen > 12) valLen = 12; -	memcpy(sbc->fversion, valPtr, valLen); -	sbc->fversion[valLen] = '\0'; -	 -	//Hardware version -	if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "hversion", &valLen))) return; -	if(!(hversion = malloc(valLen+1))) return; -	ZEROMEM(hversion, valLen+1); -	memcpy(hversion, valPtr, valLen); -	sbc->hversion = (short)strtol(hversion, NULL, 10); -	free(hversion); -	 -	// things added in version 2 of the txt -	if(sbc->txtver >= 2) -	{ -		//Hostname -		if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "hostname", &valLen))) return; -		if(valLen > 128) valLen = 128; -		memcpy(sbc->hostname, valPtr, valLen); -		sbc->hostname[valLen] = '\0'; -	} -	// things added in version 3 of the txt -	if(sbc->txtver >= 3) -	{ -		//Device Name -		if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "name", &valLen))) return; -		if(valLen > 128) valLen = 128; -		memcpy(sbc->deviceName, valPtr, valLen); -		sbc->deviceName[valLen] = '\0'; -	} -	else -	{ -		sprintf(sbc->deviceName, "PhidgetSBC"); -	} -} - -void DNSServiceQueryRecord_SBC_CallBack -( - DNSServiceRef                       DNSServiceRef, - DNSServiceFlags                     flags, - uint32_t                            interfaceIndex, - DNSServiceErrorType                 errorCode, - const char                          *fullname, - uint16_t                            rrtype, - uint16_t                            rrclass, - uint16_t                            rdlen, - const void                          *rdata, - uint32_t                            ttl, - void                                *context - ) -{ -	if (errorCode != kDNSServiceErr_NoError) -		LOG(PHIDGET_LOG_ERROR, "DNSServiceQueryRecord_sbc_CallBack returned error: %d\n", errorCode); -	else -	{ -		CPhidgetSBCHandle sbc = (CPhidgetSBCHandle)context; -		LOG(PHIDGET_LOG_INFO, "DNSServiceQueryRecord_sbc_CallBack: %s (%d)",fullname,interfaceIndex); -		 -		SBCFromTXT(sbc, rdlen, rdata); -	} -} - -void DNSServiceBrowse_Phidget_CallBack(DNSServiceRef service, -									   DNSServiceFlags flags, -									   uint32_t interfaceIndex, -									   DNSServiceErrorType errorCode, -									   const char * name, -									   const char * type, -									   const char * domain, -									   void * context) -{ -	if (errorCode != kDNSServiceErr_NoError) -		LOG(PHIDGET_LOG_ERROR, "Dns_sd_BrowseCallBack returned error: %d\n", errorCode); -	else -	{     -		DNSServiceErrorType error; -		DNSServiceRef  serviceRef; -		char fullname[kDNSServiceMaxDomainName]; -		 -		CPhidgetHandle phid; -		CPhidgetHandle found_phid; -		CPhidgetManagerList *trav; -		 -		DNSServiceConstructFullNamePtr(fullname, name, type, domain); -		 -		LOG(PHIDGET_LOG_INFO, "DNSServiceBrowse_Phidget_CallBack: %s (%s, %s, %d)",name,type,domain,interfaceIndex); -		 -		if((CPhidget_create(&phid))) return; -		if((CPhidgetRemote_create(&phid->networkInfo))) return; -		 -		phid->networkInfo->zeroconf_name = strdup(name); -		phid->networkInfo->zeroconf_type = strdup(type); -		phid->networkInfo->zeroconf_domain = strdup(domain); -		phid->networkInfo->zeroconf_interface = interfaceIndex; -		 -		if(flags & kDNSServiceFlagsAdd) -		{ -			error = DNSServiceQueryRecordPtr(&serviceRef, 0, interfaceIndex, fullname, -											 kDNSServiceType_TXT, kDNSServiceClass_IN, DNSServiceQueryRecord_Phidget_CallBack, phid); -			if (error == kDNSServiceErr_NoError) -			{ -				DNSServiceProcessResultPtr(serviceRef); -				DNSServiceRefDeallocatePtr(serviceRef); -				CThread_mutex_lock(&zeroconfPhidgetsLock); -				CThread_mutex_lock(&activeRemoteManagersLock); -				 -				CPhidget_setStatusFlag(&phid->status, PHIDGET_ATTACHED_FLAG, &phid->lock); -				CPhidget_setStatusFlag(&phid->status, PHIDGET_REMOTE_FLAG, &phid->lock); -				 -				if(CList_findInList((CListHandle)zeroconfPhidgets, phid, CPhidget_areExtraEqual, (void **)&found_phid) == EPHIDGET_OK) -				{ -					//Only do a detach/attach cycle if something's different -					if(found_phid->serialNumber == phid->serialNumber -					   && found_phid->deviceVersion == phid->deviceVersion -					   && !strcmp(found_phid->label, phid->label) -					   && !strcmp(found_phid->networkInfo->zeroconf_server_id, phid->networkInfo->zeroconf_server_id)) -					{ -						//prefer local. domain -						if((strcmp(domain, found_phid->networkInfo->zeroconf_domain) != 0) && !(strcmp(domain, "local."))) -						{ -							free(found_phid->networkInfo->zeroconf_domain); -							found_phid->networkInfo->zeroconf_domain = phid->networkInfo->zeroconf_domain; -							phid->networkInfo->zeroconf_domain = NULL; -						} -						CPhidgetRemote_free(phid->networkInfo); -						CPhidget_free(phid); -						CThread_mutex_unlock(&activeRemoteManagersLock); -						CThread_mutex_unlock(&zeroconfPhidgetsLock); -						return; -					} -					 -					//set detaching status -					CPhidget_clearStatusFlag(&found_phid->status, PHIDGET_ATTACHED_FLAG, &found_phid->lock); -					CPhidget_setStatusFlag(&found_phid->status, PHIDGET_DETACHING_FLAG, &found_phid->lock); -					 -					//Remove from list - don't free until after detach event -					CList_removeFromList((CListHandle *)&zeroconfPhidgets, found_phid, CPhidget_areExtraEqual, FALSE, NULL); -					 -					for (trav=activeRemoteManagers; trav; trav = trav->next) -					{ -						if(trav->phidm->networkInfo->requested_address==NULL -						   && (trav->phidm->networkInfo->requested_serverID == NULL || !strcmp(trav->phidm->networkInfo->requested_serverID,found_phid->networkInfo->zeroconf_server_id))) -						{ -							CList_removeFromList((CListHandle *)&trav->phidm->AttachedPhidgets, found_phid, CPhidget_areExtraEqual, PFALSE, NULL); -							 -							if (trav->phidm->fptrDetachChange && trav->phidm->state == PHIDGETMANAGER_ACTIVE) -								trav->phidm->fptrDetachChange((CPhidgetHandle)found_phid, trav->phidm->fptrDetachChangeptr); -						} -					} -					CPhidgetRemote_free(found_phid->networkInfo); -					CPhidget_free(found_phid); -				} -				 -				CPhidget_setStatusFlag(&phid->status, PHIDGET_SERVER_CONNECTED_FLAG, &phid->lock); -				 -				//now add it -				CList_addToList((CListHandle *)&zeroconfPhidgets, phid, CPhidget_areExtraEqual); -				//managers -				for (trav=activeRemoteManagers; trav; trav = trav->next) -				{ -					if(trav->phidm->networkInfo->requested_address==NULL -					   && (trav->phidm->networkInfo->requested_serverID == NULL || !strcmp(trav->phidm->networkInfo->requested_serverID,phid->networkInfo->zeroconf_server_id))) -					{ -						CList_addToList((CListHandle *)&trav->phidm->AttachedPhidgets, phid, CPhidget_areExtraEqual); -						 -						if (trav->phidm->fptrAttachChange && trav->phidm->state == PHIDGETMANAGER_ACTIVE) -							trav->phidm->fptrAttachChange((CPhidgetHandle)phid, trav->phidm->fptrAttachChangeptr); -					} -				} -				 -				CThread_mutex_unlock(&activeRemoteManagersLock); -				CThread_mutex_unlock(&zeroconfPhidgetsLock); -			} -			else -				LOG(PHIDGET_LOG_ERROR, "DNSServiceQueryRecordPtr returned error: %d\n", error); -		} -		else -		{ -			//have to fill in phid manually from just the name -			int i; -			char *name_copy = strdup(name); -			for(i=0;i<(int)strlen(name_copy);i++) -				if(name_copy[i] == '(') break; -			if(i<=1) return; -			name_copy[strlen(name_copy)-1]='\0'; -			name_copy[i-1] = '\0'; -			phid->serialNumber = strtol(name_copy+i+1, NULL, 10); -			//we need to set this so it checks the serial numbers for a match -			phid->specificDevice = PHIDGETOPEN_SERIAL; -			for(i = 0;i<PHIDGET_DEVICE_COUNT;i++) -				if(!strcmp(name_copy, Phid_Device_Def[i].pdd_name)) break; -			phid->deviceDef = &Phid_Device_Def[i]; -			//phid->deviceIDSpec = Phid_Device_Def[i].pdd_sdid; -			phid->deviceIDSpec = 0; //Needs to be 0 because the name can be ambiguous (ie 1018/1200) - we will still match on serial/device class, which is enough for uniqueness -			phid->attr = Phid_Device_Def[i].pdd_attr; -			phid->deviceID = Phid_Device_Def[i].pdd_did; -			phid->deviceType = Phid_DeviceName[phid->deviceID]; -			phid->networkInfo->mdns = PTRUE; -			 -			CThread_mutex_lock(&zeroconfPhidgetsLock); -			CThread_mutex_lock(&activeRemoteManagersLock); -			 -			CPhidget_clearStatusFlag(&phid->status, PHIDGET_ATTACHED_FLAG, &phid->lock); -			CPhidget_setStatusFlag(&phid->status, PHIDGET_DETACHING_FLAG, &phid->lock); -			 -			if(!CList_findInList((CListHandle)zeroconfPhidgets, phid, CPhidget_areEqual, (void **)&found_phid)) -			{ -				CPhidget_clearStatusFlag(&found_phid->status, PHIDGET_ATTACHED_FLAG, &found_phid->lock); -				CPhidget_setStatusFlag(&found_phid->status, PHIDGET_DETACHING_FLAG, &found_phid->lock); -				CPhidget_setStatusFlag(&found_phid->status, PHIDGET_REMOTE_FLAG, &found_phid->lock); -				CPhidget_clearStatusFlag(&found_phid->status, PHIDGET_SERVER_CONNECTED_FLAG, &found_phid->lock); -				 -				CList_removeFromList((CListHandle *)&zeroconfPhidgets, found_phid, CPhidget_areExtraEqual, FALSE, NULL); -				//managers -				for (trav=activeRemoteManagers; trav; trav = trav->next) -				{ -					if(trav->phidm->networkInfo->requested_address==NULL -					   && (trav->phidm->networkInfo->requested_serverID == NULL || !strcmp(trav->phidm->networkInfo->requested_serverID,found_phid->networkInfo->zeroconf_server_id))) -					{ -						CList_removeFromList((CListHandle *)&trav->phidm->AttachedPhidgets, found_phid, CPhidget_areExtraEqual, PFALSE, NULL); -						 -						if (trav->phidm->fptrDetachChange && trav->phidm->state == PHIDGETMANAGER_ACTIVE) -							trav->phidm->fptrDetachChange((CPhidgetHandle)found_phid, trav->phidm->fptrDetachChangeptr); -					} -				} -				CPhidget_clearStatusFlag(&found_phid->status, PHIDGET_DETACHING_FLAG, &found_phid->lock); -				CPhidgetRemote_free(found_phid->networkInfo); -				CPhidget_free(found_phid); -			} -			CPhidgetRemote_free(phid->networkInfo); -			CPhidget_free(phid); -			 -			CThread_mutex_unlock(&activeRemoteManagersLock); -			CThread_mutex_unlock(&zeroconfPhidgetsLock); -			free(name_copy); -		} -	} -} - -void DNSServiceBrowse_sbc_CallBack(DNSServiceRef service, -								   DNSServiceFlags flags, -								   uint32_t interfaceIndex, -								   DNSServiceErrorType errorCode, -								   const char * name, -								   const char * type, -								   const char * domain, -								   void * context) -{ -	if (errorCode != kDNSServiceErr_NoError) -		LOG(PHIDGET_LOG_ERROR, "Dns_sbc_BrowseCallBack returned error: %d\n", errorCode); -	else -	{     -		DNSServiceErrorType error; -		DNSServiceRef  serviceRef; -		char fullname[kDNSServiceMaxDomainName]; -		 -		CPhidgetSBCHandle sbc; -		CPhidgetSBCHandle found_sbc; -		CPhidgetSBCManagerList *trav; -		 -		DNSServiceConstructFullNamePtr(fullname, name, type, domain); -		 -		 -		if((CPhidgetSBC_create(&sbc))) return; -		if((CPhidgetRemote_create(&sbc->networkInfo))) return; -		 -		sbc->networkInfo->zeroconf_name = strdup(name); -		sbc->networkInfo->zeroconf_type = strdup(type); -		sbc->networkInfo->zeroconf_domain = strdup(domain); -		sbc->networkInfo->zeroconf_interface = interfaceIndex; -		sbc->networkInfo->mdns = PTRUE; -		 -		strncpy(sbc->mac, name+12, 18); //name == 'PhidgetSBC (??:??:??:??:??:??)' -		sbc->mac[17] = '\0'; -		 -		if(flags & kDNSServiceFlagsAdd) -		{ -			LOG(PHIDGET_LOG_INFO, "DNSServiceBrowse_sbc_CallBack (Add): %s",name); -			error = DNSServiceQueryRecordPtr(&serviceRef, 0, interfaceIndex, fullname, -											 kDNSServiceType_TXT, kDNSServiceClass_IN, DNSServiceQueryRecord_SBC_CallBack, sbc); -			if (error == kDNSServiceErr_NoError) -			{ -				DNSServiceProcessResultPtr(serviceRef); -				DNSServiceRefDeallocatePtr(serviceRef); -				 -				CThread_mutex_lock(&zeroconfSBCsLock); -				CThread_mutex_lock(&activeSBCManagersLock); -				 -				//Check if it's in the list and if it's different, remove it to make way for the new one -				// (Sometimes, we don't get a proper detach notification) -				if(CList_findInList((CListHandle)zeroconfSBCs, sbc, CPhidgetSBC_areEqual, (void **)&found_sbc) == EPHIDGET_OK) -				{ -					if(CPhidgetSBC_areExtraEqual(found_sbc, sbc) != PTRUE) //A version number has changed -					{ -						//make sure zeroconf_ref is not pending -						if(found_sbc->networkInfo) -						{ -							CThread_mutex_lock(&found_sbc->networkInfo->zeroconf_ref_lock); -							if(found_sbc->networkInfo->zeroconf_ref) -							{ -								DNSServiceRefDeallocatePtr((DNSServiceRef)found_sbc->networkInfo->zeroconf_ref); -								found_sbc->networkInfo->zeroconf_ref = NULL; -							} -							CThread_mutex_unlock(&found_sbc->networkInfo->zeroconf_ref_lock); -						} -						 -						//Remove from list - don't free until after detach event -						CList_removeFromList((CListHandle *)&zeroconfSBCs, found_sbc, CPhidgetSBC_areEqual, PFALSE, NULL); -						 -						for (trav=activeSBCManagers; trav; trav = trav->next) -						{ -							if (trav->sbcm->fptrDetachChange && trav->sbcm->state == PHIDGETMANAGER_ACTIVE) -								trav->sbcm->fptrDetachChange((CPhidgetSBCHandle)found_sbc, trav->sbcm->fptrDetachChangeptr); -						} -						 -						CPhidgetSBC_free(found_sbc); -						 -						//now we fall through and add back to new one -					} -					else //Nothing has changed, we didn't remove, don't add -					{ -						//prefer local. domain -						if((strcmp(domain, found_sbc->networkInfo->zeroconf_domain) != 0) && !(strcmp(domain, "local."))) -						{ -							free(found_sbc->networkInfo->zeroconf_domain); -							found_sbc->networkInfo->zeroconf_domain = sbc->networkInfo->zeroconf_domain; -							sbc->networkInfo->zeroconf_domain = NULL; -						} -						CPhidgetSBC_free(sbc); -						goto dontadd; -					} -				} -				 -				//now add it -				CList_addToList((CListHandle *)&zeroconfSBCs, sbc, CPhidgetSBC_areEqual); -				 -				//send out events -				for (trav=activeSBCManagers; trav; trav = trav->next) -				{ -					if (trav->sbcm->fptrAttachChange && trav->sbcm->state == PHIDGETMANAGER_ACTIVE) -						trav->sbcm->fptrAttachChange((CPhidgetSBCHandle)sbc, trav->sbcm->fptrAttachChangeptr); -					 -				} -			dontadd: -				 -				CThread_mutex_unlock(&activeSBCManagersLock); -				CThread_mutex_unlock(&zeroconfSBCsLock); -			} -			else -				LOG(PHIDGET_LOG_ERROR, "DNSServiceQueryRecordPtr returned error: %d\n", error); -		} -		else -		{ -			 -			LOG(PHIDGET_LOG_INFO, "DNSServiceBrowse_sbc_CallBack (Remove): %s",name); -			CThread_mutex_lock(&zeroconfSBCsLock); -			CThread_mutex_lock(&activeSBCManagersLock); -			 -			//make sure zeroconf_ref is not pending -			if(sbc->networkInfo) -			{ -				CThread_mutex_lock(&sbc->networkInfo->zeroconf_ref_lock); -				if(sbc->networkInfo->zeroconf_ref) -				{ -					DNSServiceRefDeallocatePtr((DNSServiceRef)sbc->networkInfo->zeroconf_ref); -					sbc->networkInfo->zeroconf_ref = NULL; -				} -				CThread_mutex_unlock(&sbc->networkInfo->zeroconf_ref_lock); -			} -			 -			if(CList_findInList((CListHandle)zeroconfSBCs, sbc, CPhidgetSBC_areEqual, (void **)&found_sbc) == EPHIDGET_OK) -			{ -				CList_removeFromList((CListHandle *)&zeroconfSBCs, found_sbc, CPhidgetSBC_areEqual, PFALSE, NULL); -				//managers -				for (trav=activeSBCManagers; trav; trav = trav->next) -				{ -					if (trav->sbcm->fptrDetachChange && trav->sbcm->state == PHIDGETMANAGER_ACTIVE) -						trav->sbcm->fptrDetachChange((CPhidgetSBCHandle)found_sbc, trav->sbcm->fptrDetachChangeptr); -				} -				CPhidgetSBC_free(found_sbc); -			} -			 -			CThread_mutex_unlock(&activeSBCManagersLock); -			CThread_mutex_unlock(&zeroconfSBCsLock); -			 -			CPhidgetSBC_free(sbc); -		} -	} -} - -void DNSServiceBrowse_ws_CallBack(DNSServiceRef service, -								  DNSServiceFlags flags, -								  uint32_t interfaceIndex, -								  DNSServiceErrorType errorCode, -								  const char * name, -								  const char * type, -								  const char * domain, -								  void * context) -{ -	if (errorCode != kDNSServiceErr_NoError) -		LOG(PHIDGET_LOG_ERROR, "DNSServiceBrowse_ws_CallBack returned error: %d\n", errorCode); -	else -	{ -		char fullname[kDNSServiceMaxDomainName]; -		 -		CPhidgetRemoteHandle networkInfo; -		if((CPhidgetRemote_create(&networkInfo))) return; -		 -		networkInfo->zeroconf_name = strdup(name); -		networkInfo->zeroconf_server_id = strdup(name); -		networkInfo->zeroconf_type = strdup(type); -		networkInfo->zeroconf_domain = strdup(domain); -		networkInfo->zeroconf_interface = interfaceIndex; -		 -		DNSServiceConstructFullNamePtr(fullname, name, type, domain); -		 -		LOG(PHIDGET_LOG_INFO, "DNSServiceBrowse_ws_CallBack: %s (%s, %s, %d)",name,type,domain,interfaceIndex); -		 -		CThread_mutex_lock(&zeroconfServersLock); -		if(flags & kDNSServiceFlagsAdd) -		{ -			if(CList_addToList((CListHandle *)&zeroconfServers, networkInfo, CPhidgetRemote_areEqual) != EPHIDGET_OK) -				CPhidgetRemote_free(networkInfo); -		} -		else -		{ -			CList_removeFromList((CListHandle *)&zeroconfServers, networkInfo, CPhidgetRemote_areEqual, TRUE, CPhidgetRemote_free); -		} -		CThread_mutex_unlock(&zeroconfServersLock); -	} -} - -int cancelPendingZeroconfLookups(CPhidgetRemoteHandle networkInfo) -{	 -	if(networkInfo->zeroconf_ref != NULL) -	{ -		DNSServiceRefDeallocatePtr((DNSServiceRef)networkInfo->zeroconf_ref); -		networkInfo->zeroconf_ref = NULL; -	} -	return EPHIDGET_OK; -} - - -void DNSServiceQueryRecord_CallBack -( - DNSServiceRef                       DNSServiceRef, - DNSServiceFlags                     flags, - uint32_t                            interfaceIndex, - DNSServiceErrorType                 errorCode, - const char                          *fullname, - uint16_t                            rrtype, - uint16_t                            rrclass, - uint16_t                            rdlen, - const void                          *rdata, - uint32_t                            ttl, - void                                *context - ) -{ -	 -	CPhidgetRemoteHandle networkInfo = (CPhidgetRemoteHandle)context; -	 -	if (errorCode != kDNSServiceErr_NoError) -	{ -		LOG(PHIDGET_LOG_ERROR, "DNSServiceQueryRecord_CallBack returned error: %d\n", errorCode); -		networkInfo->zeroconf_ipaddr = NULL; -	} -	else if(networkInfo->zeroconf_ipaddr == NULL) -	{ -		if(rrtype == kDNSServiceType_A && rdlen == 4) -		{ -			struct in_addr ip; -			memcpy(&ip, rdata, 4); -			 -			networkInfo->zeroconf_ipaddr = strdup(inet_ntoa(ip)); -		} -		//NOTE: Windows doesn't have inet_ntop -		/* -		else if(rrtype == kDNSServiceType_AAAA && rdlen == 16) -		{ -			struct in6_addr ip; -			memcpy(&ip, rdata, 16); -			 -			if((networkInfo->zeroconf_ipaddr = malloc(200)) != NULL) -			{ -				networkInfo->zeroconf_ipaddr = strdup(inet_ntop(AF_INET6, &ip, networkInfo->zeroconf_ipaddr, 200)); -			} -		} -		*/ - -		LOG(PHIDGET_LOG_INFO, "DNSServiceQueryRecord_CallBack: %s (%s %d)",fullname, networkInfo->zeroconf_ipaddr, interfaceIndex); -	} -	else -		LOG(PHIDGET_LOG_INFO, "DNSServiceQueryRecord_CallBack (extra, not used): %s (%d)",fullname, interfaceIndex); -} - -int getZeroconfIPAddr(CPhidgetRemoteHandle networkInfo) -{ -	DNSServiceErrorType error; -	 -	LOG(PHIDGET_LOG_VERBOSE, "Resolving IP Address for: %s, %s, %s, %s, %d", -		networkInfo->zeroconf_name, //name -		networkInfo->zeroconf_type, // service type -		networkInfo->zeroconf_domain, //domain -		networkInfo->zeroconf_host, -		networkInfo->zeroconf_interface); -	 -	//already a lookup pending? cancel it and start a new one... -	CThread_mutex_lock(&networkInfo->zeroconf_ref_lock); -	if(networkInfo->zeroconf_ref != NULL) -	{ -		DNSServiceRefDeallocatePtr((DNSServiceRef)networkInfo->zeroconf_ref); -		networkInfo->zeroconf_ref = NULL; -	} -	 -	free(networkInfo->zeroconf_ipaddr); -	networkInfo->zeroconf_ipaddr = NULL; -	 -	error = DNSServiceQueryRecordPtr((DNSServiceRef *)&networkInfo->zeroconf_ref, -									 0,  // no flags -									 networkInfo->zeroconf_interface, -									 networkInfo->zeroconf_host, //hostname -									 kDNSServiceType_A, // IPv4 address for now.. -									 kDNSServiceClass_IN, // service class -									 DNSServiceQueryRecord_CallBack, -									 networkInfo); -	if (error != kDNSServiceErr_NoError) -	{ -		LOG(PHIDGET_LOG_ERROR, "DNSServiceQueryRecordPtr returned error: %d\n", error); -		networkInfo->zeroconf_ref = NULL; -		CThread_mutex_unlock(&networkInfo->zeroconf_ref_lock); -		return EPHIDGET_NETWORK; -	} -	else -	{ -		DNSServiceProcessResultPtr((DNSServiceRef)networkInfo->zeroconf_ref); -		DNSServiceRefDeallocatePtr((DNSServiceRef)networkInfo->zeroconf_ref); -		networkInfo->zeroconf_ref = NULL; -		CThread_mutex_unlock(&networkInfo->zeroconf_ref_lock); -		LOG(PHIDGET_LOG_VERBOSE, "Successfull lookup: %s",networkInfo->zeroconf_host); -		return EPHIDGET_OK; -	} -	 -} - -void DNSServiceResolve_CallBack( -								DNSServiceRef						sdRef, -								DNSServiceFlags                     flags, -								uint32_t                            interfaceIndex, -								DNSServiceErrorType                 errorCode, -								const char                          *fullname, -								const char                          *hosttarget, -								uint16_t                            port, -								uint16_t                            txtLen, -								const unsigned char					*txtRecord, -								void                                *context) -{	 -	CPhidgetRemoteHandle networkInfo = (CPhidgetRemoteHandle)context; -	 -	 -	if (errorCode != kDNSServiceErr_NoError) -	{ -		LOG(PHIDGET_LOG_ERROR, "DNSServiceResolve_CallBack returned error: %d\n", errorCode); -		networkInfo->zeroconf_host = NULL; -		networkInfo->zeroconf_port = NULL; -	} -	else if(!networkInfo->zeroconf_host && !networkInfo->zeroconf_port) -	{ -		 -		LOG(PHIDGET_LOG_INFO, "DNSServiceResolve_CallBack: %s (%s:%d %d)",fullname, hosttarget, ntohs(port), interfaceIndex); -		 -		networkInfo->zeroconf_host = strdup(hosttarget); -		networkInfo->zeroconf_port = malloc(10); -		snprintf(networkInfo->zeroconf_port, 10, "%d", ntohs(port)); -	} -	else -		LOG(PHIDGET_LOG_INFO, "DNSServiceResolve_CallBack (extra, not used): %s (%s:%d %d)",fullname, hosttarget, ntohs(port), interfaceIndex); -} - -int getZeroconfHostPort(CPhidgetRemoteHandle networkInfo) -{ -	DNSServiceErrorType error; -	 -	LOG(PHIDGET_LOG_VERBOSE, "Resolving host:port for: %s, %s, %s", -		networkInfo->zeroconf_name, //name -		networkInfo->zeroconf_type, // service type -		networkInfo->zeroconf_domain //domain -		); -	 -	//already a lookup pending? cancel it and start a new one... -	CThread_mutex_lock(&networkInfo->zeroconf_ref_lock); -	if(networkInfo->zeroconf_ref != NULL) -	{ -		DNSServiceRefDeallocatePtr((DNSServiceRef)networkInfo->zeroconf_ref); -		networkInfo->zeroconf_ref = NULL; -	} -	 -	free(networkInfo->zeroconf_host); -	networkInfo->zeroconf_host = NULL; -	free(networkInfo->zeroconf_port); -	networkInfo->zeroconf_port = NULL; -	 -	error = DNSServiceResolvePtr((DNSServiceRef *)&networkInfo->zeroconf_ref, -								 0,  // no flags -								 0,  // all interfaces -								 //networkInfo->zeroconf_interface,  // interface this service was discovered on -								 networkInfo->zeroconf_name, //name -								 networkInfo->zeroconf_type, // service type -								 networkInfo->zeroconf_domain, //domain -								 DNSServiceResolve_CallBack, -								 networkInfo);     // no context -	if (error != kDNSServiceErr_NoError) -	{ -		LOG(PHIDGET_LOG_ERROR, "getZeroconfHostPort returned error: %d\n", error); -		networkInfo->zeroconf_ref = NULL; -		CThread_mutex_unlock(&networkInfo->zeroconf_ref_lock); -		return EPHIDGET_NETWORK; -	} -	else -	{ -		DNSServiceProcessResultPtr((DNSServiceRef)networkInfo->zeroconf_ref); -		DNSServiceRefDeallocatePtr((DNSServiceRef)networkInfo->zeroconf_ref); -		networkInfo->zeroconf_ref = NULL; -		LOG(PHIDGET_LOG_VERBOSE, "Successfull host:port lookup: %s:%s",networkInfo->zeroconf_host,networkInfo->zeroconf_port); -		CThread_mutex_unlock(&networkInfo->zeroconf_ref_lock); -		//Don't bother - we aren't going to use it anyways -		//This is just another way to lookup the IP address - from the DNS record -		//getZeroconfIPAddr(networkInfo); -		return EPHIDGET_OK; -	} -} - -int refreshZeroconf(CPhidgetRemoteHandle networkInfo, DNSServiceQueryRecordReply callBack, void *userPtr) -{ -	DNSServiceErrorType error; -	char fullname[kDNSServiceMaxDomainName]; -	 -	LOG(PHIDGET_LOG_VERBOSE, "Refreshing zeroconf on: 0x%x",networkInfo); -	 -	//already a lookup pending? cancel it and start a new one... -	CThread_mutex_lock(&networkInfo->zeroconf_ref_lock); -	 -	DNSServiceConstructFullNamePtr(fullname, networkInfo->zeroconf_name, networkInfo->zeroconf_type, networkInfo->zeroconf_domain); -	 -	if(networkInfo->zeroconf_ref != NULL) -	{ -		DNSServiceRefDeallocatePtr((DNSServiceRef)networkInfo->zeroconf_ref); -		networkInfo->zeroconf_ref = NULL; -	} -	error = DNSServiceQueryRecordPtr((DNSServiceRef *)&networkInfo->zeroconf_ref, -									 0,  // no flags -									 networkInfo->zeroconf_interface, -									 fullname, //name -									 kDNSServiceType_TXT, // service type -									 kDNSServiceClass_IN, // service class -									 callBack, -									 userPtr); -	if (error != kDNSServiceErr_NoError) -	{ -		LOG(PHIDGET_LOG_ERROR, "DNSServiceQueryRecordPtr returned error: %d\n", error); -		networkInfo->zeroconf_ref = NULL; -		CThread_mutex_unlock(&networkInfo->zeroconf_ref_lock); -		return EPHIDGET_NETWORK; -	} -	else -	{ -		DNSServiceProcessResultPtr((DNSServiceRef)networkInfo->zeroconf_ref); -		DNSServiceRefDeallocatePtr((DNSServiceRef)networkInfo->zeroconf_ref); -		networkInfo->zeroconf_ref = NULL; -		CThread_mutex_unlock(&networkInfo->zeroconf_ref_lock); -		LOG(PHIDGET_LOG_VERBOSE, "Successfull refresh."); -		return EPHIDGET_OK; -	} -} - -int refreshZeroconfSBC(CPhidgetSBCHandle sbc) -{ -	return refreshZeroconf(sbc->networkInfo, DNSServiceQueryRecord_SBC_CallBack, sbc); -} - -int refreshZeroconfPhidget(CPhidgetHandle phid) -{ -	return refreshZeroconf(phid->networkInfo, DNSServiceQueryRecord_Phidget_CallBack, phid); -} - -int InitializeZeroconf() -{ -	DNSServiceErrorType error; -	CThread_mutex_lock(&zeroconfInitLock); -	if(!Dns_sdInitialized) -	{ -#ifdef ZEROCONF_RUNTIME_LINKING -		 -#ifdef _WINDOWS -		if(!(dllHandle = LoadLibrary(L"dnssd.dll"))) -		{ -			DWORD error = GetLastError(); -			switch(error) -			{ -				case ERROR_MOD_NOT_FOUND: -					LOG(PHIDGET_LOG_DEBUG,"LoadLibrary failed - module could not be found"); -					break; -				default: -					LOG(PHIDGET_LOG_DEBUG,"LoadLibrary failed with error code: %d", error); -			} -			CThread_mutex_unlock(&zeroconfInitLock); -			return EPHIDGET_UNEXPECTED; -		} -		 -		// If the handle is valid, try to get the function address.  -		if (NULL != dllHandle)  -		{  -			//Get pointers to our functions using GetProcAddress: -#ifdef WINCE -			DNSServiceRegisterPtr = (DNSServiceRegisterType)GetProcAddress(dllHandle, L"DNSServiceRegister"); -			DNSServiceProcessResultPtr = (DNSServiceProcessResultType)GetProcAddress(dllHandle, L"DNSServiceProcessResult"); -			DNSServiceRefDeallocatePtr = (DNSServiceRefDeallocateType)GetProcAddress(dllHandle, L"DNSServiceRefDeallocate"); -			DNSServiceAddRecordPtr = (DNSServiceAddRecordType)GetProcAddress(dllHandle, L"DNSServiceAddRecord"); -			DNSServiceUpdateRecordPtr = (DNSServiceUpdateRecordType)GetProcAddress(dllHandle, L"DNSServiceUpdateRecord"); -			DNSServiceRemoveRecordPtr = (DNSServiceRemoveRecordType)GetProcAddress(dllHandle, L"DNSServiceRemoveRecord"); -			DNSServiceBrowsePtr = (DNSServiceBrowseType)GetProcAddress(dllHandle, L"DNSServiceBrowse"); -			DNSServiceResolvePtr = (DNSServiceResolveType)GetProcAddress(dllHandle, L"DNSServiceResolve"); -			DNSServiceQueryRecordPtr = (DNSServiceQueryRecordType)GetProcAddress(dllHandle, L"DNSServiceQueryRecord"); -			DNSServiceConstructFullNamePtr = (DNSServiceConstructFullNameType)GetProcAddress(dllHandle, L"DNSServiceConstructFullName"); -			DNSServiceRefSockFDPtr = (DNSServiceRefSockFDType)GetProcAddress(dllHandle, L"DNSServiceRefSockFD"); -#else -			DNSServiceRegisterPtr = (DNSServiceRegisterType)GetProcAddress(dllHandle, "DNSServiceRegister"); -			DNSServiceProcessResultPtr = (DNSServiceProcessResultType)GetProcAddress(dllHandle, "DNSServiceProcessResult"); -			DNSServiceRefDeallocatePtr = (DNSServiceRefDeallocateType)GetProcAddress(dllHandle, "DNSServiceRefDeallocate"); -			DNSServiceAddRecordPtr = (DNSServiceAddRecordType)GetProcAddress(dllHandle, "DNSServiceAddRecord"); -			DNSServiceUpdateRecordPtr = (DNSServiceUpdateRecordType)GetProcAddress(dllHandle, "DNSServiceUpdateRecord"); -			DNSServiceRemoveRecordPtr = (DNSServiceRemoveRecordType)GetProcAddress(dllHandle, "DNSServiceRemoveRecord"); -			DNSServiceBrowsePtr = (DNSServiceBrowseType)GetProcAddress(dllHandle, "DNSServiceBrowse"); -			DNSServiceResolvePtr = (DNSServiceResolveType)GetProcAddress(dllHandle, "DNSServiceResolve"); -			DNSServiceQueryRecordPtr = (DNSServiceQueryRecordType)GetProcAddress(dllHandle, "DNSServiceQueryRecord"); -			DNSServiceConstructFullNamePtr = (DNSServiceConstructFullNameType)GetProcAddress(dllHandle, "DNSServiceConstructFullName"); -			DNSServiceRefSockFDPtr = (DNSServiceRefSockFDType)GetProcAddress(dllHandle, "DNSServiceRefSockFD"); -#endif -			 -			Dns_sdInitialized = ( -								 NULL != DNSServiceRegisterPtr &&  -								 NULL != DNSServiceProcessResultPtr && -								 NULL != DNSServiceRefDeallocatePtr && -								 NULL != DNSServiceAddRecordPtr && -								 NULL != DNSServiceUpdateRecordPtr && -								 NULL != DNSServiceRemoveRecordPtr && -								 NULL != DNSServiceQueryRecordPtr && -								 NULL != DNSServiceConstructFullNamePtr && -								 NULL != DNSServiceRefSockFDPtr); -		} -		 -		if(!Dns_sdInitialized) -		{ -			LOG(PHIDGET_LOG_DEBUG,"InitializeZeroconf failed somehow..."); -			CThread_mutex_unlock(&zeroconfInitLock); -			return EPHIDGET_UNSUPPORTED; -		} -		 -#elif _LINUX -		libHandle = dlopen("libdns_sd.so",RTLD_LAZY); -		if(!libHandle) -		{ -			LOG(PHIDGET_LOG_WARNING, "dlopen failed with error: %s", dlerror()); -			LOG(PHIDGET_LOG_WARNING, "Assuming that zeroconf is not supported on this machine."); -			CThread_mutex_unlock(&zeroconfInitLock); -			return EPHIDGET_UNSUPPORTED; -		} -		 -		//Get pointers to our functions using dlsym: -		if(!(DNSServiceRegisterPtr = (DNSServiceRegisterType)dlsym(libHandle, "DNSServiceRegister"))) goto dlsym_err; -		if(!(DNSServiceProcessResultPtr = (DNSServiceProcessResultType)dlsym(libHandle, "DNSServiceProcessResult"))) goto dlsym_err; -		if(!(DNSServiceRefDeallocatePtr = (DNSServiceRefDeallocateType)dlsym(libHandle, "DNSServiceRefDeallocate"))) goto dlsym_err; -		if(!(DNSServiceAddRecordPtr = (DNSServiceAddRecordType)dlsym(libHandle, "DNSServiceAddRecord"))) goto dlsym_err; -		if(!(DNSServiceUpdateRecordPtr = (DNSServiceUpdateRecordType)dlsym(libHandle, "DNSServiceUpdateRecord"))) goto dlsym_err; -		if(!(DNSServiceRemoveRecordPtr = (DNSServiceRemoveRecordType)dlsym(libHandle, "DNSServiceRemoveRecord"))) goto dlsym_err; -		if(!(DNSServiceBrowsePtr = (DNSServiceBrowseType)dlsym(libHandle, "DNSServiceBrowse"))) goto dlsym_err; -		if(!(DNSServiceResolvePtr = (DNSServiceResolveType)dlsym(libHandle, "DNSServiceResolve"))) goto dlsym_err; -		if(!(DNSServiceQueryRecordPtr = (DNSServiceQueryRecordType)dlsym(libHandle, "DNSServiceQueryRecord"))) goto dlsym_err; -		if(!(DNSServiceConstructFullNamePtr = (DNSServiceConstructFullNameType)dlsym(libHandle, "DNSServiceConstructFullName"))) goto dlsym_err; -		if(!(DNSServiceRefSockFDPtr = (DNSServiceRefSockFDType)dlsym(libHandle, "DNSServiceRefSockFD"))) goto dlsym_err; -		 -		goto dlsym_good; -		 -	dlsym_err: -		LOG(PHIDGET_LOG_WARNING, "dlsym failed with error: %s", dlerror()); -		LOG(PHIDGET_LOG_WARNING, "Assuming that zeroconf is not supported on this machine."); -		CThread_mutex_unlock(&zeroconfInitLock); -		return EPHIDGET_UNSUPPORTED; -		 -	dlsym_good: -		Dns_sdInitialized = TRUE; -#endif -		 -#else -		Dns_sdInitialized = TRUE; -#endif -		LOG(PHIDGET_LOG_DEBUG,"InitializeZeroconf - System supports zeroconf."); -	} -	if(!Dns_sdBrowsing) -	{ -		error = DNSServiceBrowsePtr(&zeroconf_browse_ws_ref, -									0,                // no flags -									0,                // all network interfaces -									"_phidget_ws._tcp",     // service type -									"",               // default domains -									DNSServiceBrowse_ws_CallBack, // call back function -									NULL);            // no context -		if (error != kDNSServiceErr_NoError) -		{ -			LOG(PHIDGET_LOG_ERROR,"DNSServiceBrowse on _phidget_ws._tcp failed: %d", error); -			CThread_mutex_unlock(&zeroconfInitLock); -			return EPHIDGET_TRYAGAIN; -		} -		 -		error = DNSServiceBrowsePtr(&zeroconf_browse_sbc_ref, -									0,                // no flags -									0,                // all network interfaces -									"_phidget_sbc._tcp",     // service type -									"",               // default domains -									DNSServiceBrowse_sbc_CallBack, // call back function -									NULL);            // no context -		if (error != kDNSServiceErr_NoError) -		{ -			LOG(PHIDGET_LOG_ERROR,"DNSServiceBrowse on _phidget_sbc._tcp failed: %d", error); -			CThread_mutex_unlock(&zeroconfInitLock); -			return EPHIDGET_TRYAGAIN; -		} -		 -		error = DNSServiceBrowsePtr(&zeroconf_browse_phidget_ref, -									0,                // no flags -									0,                // all network interfaces -									"_phidget._tcp",     // service type -									"",               // default domains -									DNSServiceBrowse_Phidget_CallBack, // call back function -									NULL);            // no context -		if (error != kDNSServiceErr_NoError) -		{ -			LOG(PHIDGET_LOG_ERROR,"DNSServiceBrowse on _phidget._tcp failed: %d", error); -			CThread_mutex_unlock(&zeroconfInitLock); -			return EPHIDGET_TRYAGAIN; -		} -		 -		stopBrowsing = FALSE; -		pthread_create(&dns_thread, NULL, (void *(*)(void *))dns_callback_thread,NULL); -		 -		Dns_sdBrowsing = PTRUE; -		LOG(PHIDGET_LOG_DEBUG,"InitializeZeroconf - Zeroconf browsing active."); -	} -	CThread_mutex_unlock(&zeroconfInitLock); -	return EPHIDGET_OK; -} - -int UninitializeZeroconf() -{ -	void *status; -	CThread_mutex_lock(&zeroconfInitLock); -	if(Dns_sdBrowsing) -	{ -		stopBrowsing = TRUE; -		if(dns_thread) -		{ -			pthread_join(dns_thread, &status); -			dns_thread = NULL; -		} -		 -		if(zeroconf_browse_ws_ref) -		{ -			DNSServiceRefDeallocatePtr(zeroconf_browse_ws_ref); -			zeroconf_browse_ws_ref = NULL; -		} -		if(zeroconf_browse_sbc_ref) -		{ -			DNSServiceRefDeallocatePtr(zeroconf_browse_sbc_ref); -			zeroconf_browse_sbc_ref = NULL; -		} -		if(zeroconf_browse_phidget_ref) -		{ -			DNSServiceRefDeallocatePtr(zeroconf_browse_phidget_ref); -			zeroconf_browse_phidget_ref = NULL; -		} -		 -		CThread_mutex_lock(&zeroconfPhidgetsLock); -		CList_emptyList((CListHandle *)&zeroconfPhidgets, FALSE, NULL); -		CThread_mutex_unlock(&zeroconfPhidgetsLock); -		 -		CThread_mutex_lock(&zeroconfSBCsLock); -		CList_emptyList((CListHandle *)&zeroconfSBCs, FALSE, NULL); -		CThread_mutex_unlock(&zeroconfSBCsLock); -		 -		CThread_mutex_lock(&zeroconfServersLock); -		CList_emptyList((CListHandle *)&zeroconfServers, FALSE, NULL); -		CThread_mutex_unlock(&zeroconfServersLock); -		 -		Dns_sdBrowsing = FALSE; -	} -	CThread_mutex_unlock(&zeroconfInitLock); -	return EPHIDGET_OK; -} - - +#include "stdafx.h"
 +#include "csocket.h"
 +#include "csocketevents.h"
 +#include "cphidgetlist.h"
 +#include "cphidgetmanager.h"
 +#include "cphidgetdictionary.h"
 +#include "cphidgetsbc.h"
 +#include "zeroconf.h"
 +#include "dns_sd.h"
 +
 +#ifdef ZEROCONF_RUNTIME_LINKING
 +//function prototypes for run-time loaded library
 +typedef DNSServiceErrorType (DNSSD_API * DNSServiceRegisterType) 
 +(DNSServiceRef *,DNSServiceFlags,uint32_t,const char *,
 + const char *,const char *,const char *,uint16_t,uint16_t,
 + const void *,DNSServiceRegisterReply,void *);
 +typedef DNSServiceErrorType (DNSSD_API * DNSServiceProcessResultType) (DNSServiceRef);
 +typedef void (DNSSD_API * DNSServiceRefDeallocateType) (DNSServiceRef);
 +typedef DNSServiceErrorType (DNSSD_API * DNSServiceAddRecordType)
 +(DNSServiceRef, DNSRecordRef *, DNSServiceFlags, 
 + uint16_t, uint16_t, const void *, uint32_t);
 +typedef DNSServiceErrorType (DNSSD_API * DNSServiceUpdateRecordType)
 +(DNSServiceRef, DNSRecordRef, DNSServiceFlags, 
 + uint16_t, const void *, uint32_t);
 +typedef DNSServiceErrorType (DNSSD_API * DNSServiceRemoveRecordType)
 +(DNSServiceRef, DNSRecordRef, DNSServiceFlags);
 +typedef DNSServiceErrorType (DNSSD_API * DNSServiceBrowseType)
 +(DNSServiceRef *, DNSServiceFlags, uint32_t, const char *,
 + const char *, DNSServiceBrowseReply, void *);
 +typedef DNSServiceErrorType (DNSSD_API * DNSServiceResolveType)
 +(DNSServiceRef *, DNSServiceFlags, uint32_t, const char *,
 + const char *, const char *, DNSServiceResolveReply, 
 + void *context);
 +typedef DNSServiceErrorType (DNSSD_API * DNSServiceQueryRecordType)
 +(DNSServiceRef *, DNSServiceFlags, uint32_t, const char *,
 + uint16_t, uint16_t, DNSServiceQueryRecordReply, void *context);
 +typedef int (DNSSD_API * DNSServiceConstructFullNameType)
 +(char *, const char *, const char *, const char *);
 +typedef int (DNSSD_API * DNSServiceRefSockFDType) (DNSServiceRef sdRef);
 +#else
 +#define DNSServiceRegisterPtr DNSServiceRegister
 +#define DNSServiceProcessResultPtr DNSServiceProcessResult
 +#define DNSServiceRefDeallocatePtr DNSServiceRefDeallocate
 +#define DNSServiceAddRecordPtr DNSServiceAddRecord
 +#define DNSServiceUpdateRecordPtr DNSServiceUpdateRecord
 +#define DNSServiceRemoveRecordPtr DNSServiceRemoveRecord
 +#define DNSServiceBrowsePtr DNSServiceBrowse
 +#define DNSServiceResolvePtr DNSServiceResolve
 +#define DNSServiceQueryRecordPtr DNSServiceQueryRecord
 +#define DNSServiceConstructFullNamePtr DNSServiceConstructFullName
 +#define DNSServiceRefSockFDPtr DNSServiceRefSockFD
 +#endif
 +
 +int Dns_sdInitialized = FALSE;
 +int Dns_sdBrowsing = FALSE;
 +int stopBrowsing = FALSE;
 +DNSServiceRef zeroconf_browse_ws_ref  = NULL;
 +DNSServiceRef zeroconf_browse_sbc_ref  = NULL;
 +DNSServiceRef zeroconf_browse_phidget_ref  = NULL;
 +
 +pthread_t dns_thread = NULL;
 +
 +#ifdef ZEROCONF_RUNTIME_LINKING
 +
 +//DNS_SD functions
 +DNSServiceRegisterType DNSServiceRegisterPtr = NULL;
 +DNSServiceProcessResultType DNSServiceProcessResultPtr = NULL;
 +DNSServiceRefDeallocateType DNSServiceRefDeallocatePtr = NULL;
 +DNSServiceAddRecordType DNSServiceAddRecordPtr = NULL;
 +DNSServiceUpdateRecordType DNSServiceUpdateRecordPtr = NULL;
 +DNSServiceRemoveRecordType DNSServiceRemoveRecordPtr = NULL;
 +DNSServiceBrowseType DNSServiceBrowsePtr = NULL;
 +DNSServiceResolveType DNSServiceResolvePtr = NULL;
 +DNSServiceQueryRecordType DNSServiceQueryRecordPtr = NULL;
 +DNSServiceConstructFullNameType DNSServiceConstructFullNamePtr = NULL;
 +DNSServiceRefSockFDType DNSServiceRefSockFDPtr = NULL;
 +
 +#ifdef _WINDOWS
 +HMODULE dllHandle = NULL;
 +#elif _LINUX
 +void *libHandle = NULL;
 +#endif
 +#endif
 +
 +
 +static uint8_t *InternalTXTRecordSearch
 +(
 + uint16_t         txtLen,
 + const void       *txtRecord,
 + const char       *key,
 + unsigned long    *keylen
 + )
 +{
 +	uint8_t *p = (uint8_t*)txtRecord;
 +	uint8_t *e = p + txtLen;
 +	*keylen = (unsigned long) strlen(key);
 +	while (p<e)
 +	{
 +		uint8_t *x = p;
 +		p += 1 + p[0];
 +		if (p <= e && *keylen <= x[0] && !strncmp(key, (char*)x+1, *keylen))
 +			if (*keylen == x[0] || x[1+*keylen] == '=') return(x);
 +	}
 +	return(NULL);
 +}
 +
 +const void * TXTRecordGetValuePtrPtr
 +(
 + uint16_t         txtLen,
 + const void       *txtRecord,
 + const char       *key,
 + uint8_t          *valueLen
 + )
 +{
 +	unsigned long keylen;
 +	uint8_t *item = InternalTXTRecordSearch(txtLen, txtRecord, key, &keylen);
 +	if (!item || item[0] <= keylen) return(NULL);	// If key not found, or found with no value, return NULL
 +	*valueLen = (uint8_t)(item[0] - (keylen + 1));
 +	return (item + 1 + keylen + 1);
 +}
 +
 +int dns_callback_thread(void *ptr)
 +{    
 +    int nfds;
 +    fd_set readfds;
 +    struct timeval tv;
 +    int result;
 +	
 +	int ws_fd = DNSServiceRefSockFDPtr(zeroconf_browse_ws_ref);
 +	int sbc_fd = DNSServiceRefSockFDPtr(zeroconf_browse_sbc_ref);
 +	int phidget_fd = DNSServiceRefSockFDPtr(zeroconf_browse_phidget_ref);
 +	
 +	nfds = ws_fd;
 +	if(sbc_fd>nfds)
 +		nfds = sbc_fd;
 +	if(phidget_fd > nfds)
 +		nfds = phidget_fd;
 +	nfds++;
 +	
 +	while (!stopBrowsing)
 +	{
 +		FD_ZERO(&readfds);
 +		FD_SET(ws_fd, &readfds);
 +		FD_SET(sbc_fd, &readfds);
 +		FD_SET(phidget_fd, &readfds);
 +		
 +		//100ms
 +		tv.tv_sec = 0;
 +		tv.tv_usec = 100000;
 +		
 +		result = select(nfds, &readfds, (fd_set*)NULL, (fd_set*)NULL, &tv);
 +		if (result > 0)
 +		{
 +			DNSServiceErrorType err = kDNSServiceErr_NoError;
 +			if (FD_ISSET(ws_fd, &readfds))
 +			{
 +				if ((err = DNSServiceProcessResultPtr(zeroconf_browse_ws_ref)) != kDNSServiceErr_NoError)
 +					stopBrowsing = 1;
 +			}
 +			if (FD_ISSET(sbc_fd, &readfds))
 +			{
 +				if ((err = DNSServiceProcessResultPtr(zeroconf_browse_sbc_ref)) != kDNSServiceErr_NoError)
 +					stopBrowsing = 1;
 +			}
 +			if (FD_ISSET(phidget_fd, &readfds))
 +			{
 +				if ((err = DNSServiceProcessResultPtr(zeroconf_browse_phidget_ref)) != kDNSServiceErr_NoError)
 +					stopBrowsing = 1;
 +			}
 +		}
 +		else if(result == SOCKET_ERROR)
 +		{
 +			LOG(PHIDGET_LOG_DEBUG, "select(  ) returned %d errno %d %s\n", result, errno, strerror(errno));
 +			if (errno != EINTR)
 +				stopBrowsing = 1;
 +		}
 +		//result==0 means timeout, loop around again
 +	}
 +	return EPHIDGET_OK;
 +}
 +
 +void PhidFromTXT(CPhidgetHandle phid, uint16_t txtLen, const char *txtRecord)
 +{
 +	int i = 0;
 +	short txtver;
 +	//char *label = NULL;
 +	char temp[128];
 +	//unsigned int labelLen = 0;
 +	
 +	uint8_t valLen = 0;
 +	const char *valPtr = NULL;
 +	
 +	//txt version
 +	if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "txtvers", &valLen))) return;
 +	memcpy(temp, valPtr, valLen);
 +	temp[valLen] = '\0';
 +	txtver = (short)strtol(temp, NULL, 10);
 +	
 +	//Serial Number
 +	if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "serial", &valLen))) return;
 +	memcpy(temp, valPtr, valLen);
 +	temp[valLen] = '\0';
 +	phid->serialNumber = strtol(temp, NULL, 10);
 +	phid->specificDevice = PHIDGETOPEN_SERIAL;
 +	
 +	//version
 +	if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "version", &valLen))) return;
 +	memcpy(temp, valPtr, valLen);
 +	temp[valLen] = '\0';
 +	phid->deviceVersion = strtol(temp, NULL, 10);
 +	
 +	//label
 +	if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "label", &valLen))) return;
 +	if(valLen >= MAX_LABEL_STORAGE) valLen = MAX_LABEL_STORAGE-1;
 +	memcpy(phid->label, valPtr, valLen);
 +	phid->label[valLen] = '\0';
 +	/*	memcpy(temp, valPtr, valLen);
 +	 temp[valLen] = '\0';
 +	 unescape(temp, &label, &labelLen);
 +	 if(labelLen > MAX_LABEL_STORAGE-1) labelLen = MAX_LABEL_STORAGE-1;
 +	 memcpy(phid->label, label, labelLen);
 +	 phid->label[labelLen] = '\0';
 +	 free(label);*/
 +	
 +	//server_id
 +	if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "server_id", &valLen))) return;
 +	free(phid->networkInfo->zeroconf_server_id);
 +	if(!(phid->networkInfo->zeroconf_server_id = malloc(valLen+1))) return;
 +	ZEROMEM(phid->networkInfo->zeroconf_server_id, valLen+1);
 +	memcpy(phid->networkInfo->zeroconf_server_id, valPtr, valLen);
 +	
 +	// things added in version 2 of the txt
 +	if(txtver >= 2)
 +	{
 +		//Device ID
 +		if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "id", &valLen))) return;
 +		memcpy(temp, valPtr, valLen);
 +		temp[valLen] = '\0';
 +		phid->deviceIDSpec = strtol(temp, NULL, 10);
 +		
 +		for(i = 1;i<PHIDGET_DEVICE_COUNT;i++)
 +			if(phid->deviceIDSpec == Phid_Device_Def[i].pdd_sdid) break;
 +		phid->deviceDef = &Phid_Device_Def[i];
 +		phid->attr = Phid_Device_Def[i].pdd_attr;
 +		
 +		//Device Class
 +		if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "class", &valLen))) return;
 +		memcpy(temp, valPtr, valLen);
 +		temp[valLen] = '\0';
 +		phid->deviceID = strtol(temp, NULL, 10);
 +		phid->deviceType = Phid_DeviceName[phid->deviceID];
 +	}
 +	//Old version uses string searching, but some devices have the same name with different IDs
 +	else
 +	{
 +		char *name = NULL;
 +		char *type = NULL;
 +		
 +		//name
 +		if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "name", &valLen))) return;
 +		if(!(name = malloc(valLen+1))) return;
 +		ZEROMEM(name, valLen+1);
 +		memcpy(name, valPtr, valLen);
 +		for(i = 0;i<PHIDGET_DEVICE_COUNT;i++)
 +		{
 +			if(!strcmp(name, Phid_Device_Def[i].pdd_name))
 +			{
 +				phid->deviceIDSpec = Phid_Device_Def[i].pdd_sdid;
 +				phid->deviceDef = &Phid_Device_Def[i];
 +				phid->attr = Phid_Device_Def[i].pdd_attr;
 +				break;
 +			}
 +		}
 +		free(name);
 +		
 +		//type
 +		if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "type", &valLen))) return;
 +		if(!(type = malloc(valLen+1))) return;
 +		ZEROMEM(type, valLen+1);
 +		memcpy(type, valPtr, valLen);
 +		phid->deviceID = phidget_type_to_id(type);
 +		phid->deviceType = Phid_DeviceName[phid->deviceID];
 +		free(type);
 +	}
 +	
 +	phid->deviceUID = CPhidget_getUID(phid->deviceIDSpec, phid->deviceVersion);
 +	phid->networkInfo->mdns = PTRUE;
 +	
 +}
 +
 +void DNSServiceQueryRecord_Phidget_CallBack
 +(
 + DNSServiceRef                       DNSServiceRef,
 + DNSServiceFlags                     flags,
 + uint32_t                            interfaceIndex,
 + DNSServiceErrorType                 errorCode,
 + const char                          *fullname,
 + uint16_t                            rrtype,
 + uint16_t                            rrclass,
 + uint16_t                            rdlen,
 + const void                          *rdata,
 + uint32_t                            ttl,
 + void                                *context
 + )
 +{
 +	if (errorCode != kDNSServiceErr_NoError)
 +		LOG(PHIDGET_LOG_ERROR, "DNSServiceQueryRecord_Phidget_CallBack returned error: %d\n", errorCode);
 +	else
 +	{
 +		CPhidgetHandle phid = (CPhidgetHandle)context;
 +		LOG(PHIDGET_LOG_INFO, "DNSServiceQueryRecord_Phidget_CallBack: %s (%d)",fullname,interfaceIndex);
 +		
 +		PhidFromTXT(phid, rdlen, rdata);
 +	}
 +}
 +
 +void SBCFromTXT(CPhidgetSBCHandle sbc, uint16_t txtLen, const char *txtRecord)
 +{
 +	char *hversion = NULL, *txtver = NULL;
 +	
 +	uint8_t valLen = 0;
 +	const char *valPtr = NULL;
 +	
 +	//txt version
 +	if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "txtvers", &valLen))) return;
 +	if(!(txtver = malloc(valLen+1))) return;
 +	ZEROMEM(txtver, valLen+1);
 +	memcpy(txtver, valPtr, valLen);
 +	sbc->txtver = (short)strtol(txtver, NULL, 10);
 +	free(txtver);
 +	
 +	//Firmware version
 +	if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "fversion", &valLen))) return;
 +	if(valLen > 12) valLen = 12;
 +	memcpy(sbc->fversion, valPtr, valLen);
 +	sbc->fversion[valLen] = '\0';
 +	
 +	//Hardware version
 +	if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "hversion", &valLen))) return;
 +	if(!(hversion = malloc(valLen+1))) return;
 +	ZEROMEM(hversion, valLen+1);
 +	memcpy(hversion, valPtr, valLen);
 +	sbc->hversion = (short)strtol(hversion, NULL, 10);
 +	free(hversion);
 +	
 +	// things added in version 2 of the txt
 +	if(sbc->txtver >= 2)
 +	{
 +		//Hostname
 +		if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "hostname", &valLen))) return;
 +		if(valLen > 128) valLen = 128;
 +		memcpy(sbc->hostname, valPtr, valLen);
 +		sbc->hostname[valLen] = '\0';
 +	}
 +	// things added in version 3 of the txt
 +	if(sbc->txtver >= 3)
 +	{
 +		//Device Name
 +		if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "name", &valLen))) return;
 +		if(valLen > 128) valLen = 128;
 +		memcpy(sbc->deviceName, valPtr, valLen);
 +		sbc->deviceName[valLen] = '\0';
 +	}
 +	else
 +	{
 +		sprintf(sbc->deviceName, "PhidgetSBC");
 +	}
 +}
 +
 +void DNSServiceQueryRecord_SBC_CallBack
 +(
 + DNSServiceRef                       DNSServiceRef,
 + DNSServiceFlags                     flags,
 + uint32_t                            interfaceIndex,
 + DNSServiceErrorType                 errorCode,
 + const char                          *fullname,
 + uint16_t                            rrtype,
 + uint16_t                            rrclass,
 + uint16_t                            rdlen,
 + const void                          *rdata,
 + uint32_t                            ttl,
 + void                                *context
 + )
 +{
 +	if (errorCode != kDNSServiceErr_NoError)
 +		LOG(PHIDGET_LOG_ERROR, "DNSServiceQueryRecord_sbc_CallBack returned error: %d\n", errorCode);
 +	else
 +	{
 +		CPhidgetSBCHandle sbc = (CPhidgetSBCHandle)context;
 +		LOG(PHIDGET_LOG_INFO, "DNSServiceQueryRecord_sbc_CallBack: %s (%d)",fullname,interfaceIndex);
 +		
 +		SBCFromTXT(sbc, rdlen, rdata);
 +	}
 +}
 +
 +void DNSServiceBrowse_Phidget_CallBack(DNSServiceRef service,
 +									   DNSServiceFlags flags,
 +									   uint32_t interfaceIndex,
 +									   DNSServiceErrorType errorCode,
 +									   const char * name,
 +									   const char * type,
 +									   const char * domain,
 +									   void * context)
 +{
 +	if (errorCode != kDNSServiceErr_NoError)
 +		LOG(PHIDGET_LOG_ERROR, "Dns_sd_BrowseCallBack returned error: %d\n", errorCode);
 +	else
 +	{    
 +		DNSServiceErrorType error;
 +		DNSServiceRef  serviceRef;
 +		char fullname[kDNSServiceMaxDomainName];
 +		
 +		CPhidgetHandle phid;
 +		CPhidgetHandle found_phid;
 +		CPhidgetManagerList *trav;
 +		
 +		DNSServiceConstructFullNamePtr(fullname, name, type, domain);
 +		
 +		LOG(PHIDGET_LOG_INFO, "DNSServiceBrowse_Phidget_CallBack: %s (%s, %s, %d)",name,type,domain,interfaceIndex);
 +		
 +		if((CPhidget_create(&phid))) return;
 +		if((CPhidgetRemote_create(&phid->networkInfo))) return;
 +		
 +		phid->networkInfo->zeroconf_name = strdup(name);
 +		phid->networkInfo->zeroconf_type = strdup(type);
 +		phid->networkInfo->zeroconf_domain = strdup(domain);
 +		phid->networkInfo->zeroconf_interface = interfaceIndex;
 +		
 +		if(flags & kDNSServiceFlagsAdd)
 +		{
 +			error = DNSServiceQueryRecordPtr(&serviceRef, 0, interfaceIndex, fullname,
 +											 kDNSServiceType_TXT, kDNSServiceClass_IN, DNSServiceQueryRecord_Phidget_CallBack, phid);
 +			if (error == kDNSServiceErr_NoError)
 +			{
 +				DNSServiceProcessResultPtr(serviceRef);
 +				DNSServiceRefDeallocatePtr(serviceRef);
 +				CThread_mutex_lock(&zeroconfPhidgetsLock);
 +				CThread_mutex_lock(&activeRemoteManagersLock);
 +				
 +				CPhidget_setStatusFlag(&phid->status, PHIDGET_ATTACHED_FLAG, &phid->lock);
 +				CPhidget_setStatusFlag(&phid->status, PHIDGET_REMOTE_FLAG, &phid->lock);
 +				
 +				if(CList_findInList((CListHandle)zeroconfPhidgets, phid, CPhidget_areExtraEqual, (void **)&found_phid) == EPHIDGET_OK)
 +				{
 +					//Only do a detach/attach cycle if something's different
 +					if(found_phid->serialNumber == phid->serialNumber
 +					   && found_phid->deviceVersion == phid->deviceVersion
 +					   && !strcmp(found_phid->label, phid->label)
 +					   && !strcmp(found_phid->networkInfo->zeroconf_server_id, phid->networkInfo->zeroconf_server_id))
 +					{
 +						//prefer local. domain
 +						if((strcmp(domain, found_phid->networkInfo->zeroconf_domain) != 0) && !(strcmp(domain, "local.")))
 +						{
 +							free(found_phid->networkInfo->zeroconf_domain);
 +							found_phid->networkInfo->zeroconf_domain = phid->networkInfo->zeroconf_domain;
 +							phid->networkInfo->zeroconf_domain = NULL;
 +						}
 +						CPhidgetRemote_free(phid->networkInfo);
 +						CPhidget_free(phid);
 +						CThread_mutex_unlock(&activeRemoteManagersLock);
 +						CThread_mutex_unlock(&zeroconfPhidgetsLock);
 +						return;
 +					}
 +					
 +					//set detaching status
 +					CPhidget_clearStatusFlag(&found_phid->status, PHIDGET_ATTACHED_FLAG, &found_phid->lock);
 +					CPhidget_setStatusFlag(&found_phid->status, PHIDGET_DETACHING_FLAG, &found_phid->lock);
 +					
 +					//Remove from list - don't free until after detach event
 +					CList_removeFromList((CListHandle *)&zeroconfPhidgets, found_phid, CPhidget_areExtraEqual, FALSE, NULL);
 +					
 +					for (trav=activeRemoteManagers; trav; trav = trav->next)
 +					{
 +						if(trav->phidm->networkInfo->requested_address==NULL
 +						   && (trav->phidm->networkInfo->requested_serverID == NULL || !strcmp(trav->phidm->networkInfo->requested_serverID,found_phid->networkInfo->zeroconf_server_id)))
 +						{
 +							CList_removeFromList((CListHandle *)&trav->phidm->AttachedPhidgets, found_phid, CPhidget_areExtraEqual, PFALSE, NULL);
 +							
 +							if (trav->phidm->fptrDetachChange && trav->phidm->state == PHIDGETMANAGER_ACTIVE)
 +								trav->phidm->fptrDetachChange((CPhidgetHandle)found_phid, trav->phidm->fptrDetachChangeptr);
 +						}
 +					}
 +					CPhidgetRemote_free(found_phid->networkInfo);
 +					CPhidget_free(found_phid);
 +				}
 +				
 +				CPhidget_setStatusFlag(&phid->status, PHIDGET_SERVER_CONNECTED_FLAG, &phid->lock);
 +				
 +				//now add it
 +				CList_addToList((CListHandle *)&zeroconfPhidgets, phid, CPhidget_areExtraEqual);
 +				//managers
 +				for (trav=activeRemoteManagers; trav; trav = trav->next)
 +				{
 +					if(trav->phidm->networkInfo->requested_address==NULL
 +					   && (trav->phidm->networkInfo->requested_serverID == NULL || !strcmp(trav->phidm->networkInfo->requested_serverID,phid->networkInfo->zeroconf_server_id)))
 +					{
 +						CList_addToList((CListHandle *)&trav->phidm->AttachedPhidgets, phid, CPhidget_areExtraEqual);
 +						
 +						if (trav->phidm->fptrAttachChange && trav->phidm->state == PHIDGETMANAGER_ACTIVE)
 +							trav->phidm->fptrAttachChange((CPhidgetHandle)phid, trav->phidm->fptrAttachChangeptr);
 +					}
 +				}
 +				
 +				CThread_mutex_unlock(&activeRemoteManagersLock);
 +				CThread_mutex_unlock(&zeroconfPhidgetsLock);
 +			}
 +			else
 +				LOG(PHIDGET_LOG_ERROR, "DNSServiceQueryRecordPtr returned error: %d\n", error);
 +		}
 +		else
 +		{
 +			//have to fill in phid manually from just the name
 +			int i;
 +			char *name_copy = strdup(name);
 +			for(i=0;i<(int)strlen(name_copy);i++)
 +				if(name_copy[i] == '(') break;
 +			if(i<=1) return;
 +			name_copy[strlen(name_copy)-1]='\0';
 +			name_copy[i-1] = '\0';
 +			phid->serialNumber = strtol(name_copy+i+1, NULL, 10);
 +			//we need to set this so it checks the serial numbers for a match
 +			phid->specificDevice = PHIDGETOPEN_SERIAL;
 +			for(i = 0;i<PHIDGET_DEVICE_COUNT;i++)
 +				if(!strcmp(name_copy, Phid_Device_Def[i].pdd_name)) break;
 +			phid->deviceDef = &Phid_Device_Def[i];
 +			//phid->deviceIDSpec = Phid_Device_Def[i].pdd_sdid;
 +			phid->deviceIDSpec = 0; //Needs to be 0 because the name can be ambiguous (ie 1018/1200) - we will still match on serial/device class, which is enough for uniqueness
 +			phid->attr = Phid_Device_Def[i].pdd_attr;
 +			phid->deviceID = Phid_Device_Def[i].pdd_did;
 +			phid->deviceType = Phid_DeviceName[phid->deviceID];
 +			phid->networkInfo->mdns = PTRUE;
 +			
 +			CThread_mutex_lock(&zeroconfPhidgetsLock);
 +			CThread_mutex_lock(&activeRemoteManagersLock);
 +			
 +			CPhidget_clearStatusFlag(&phid->status, PHIDGET_ATTACHED_FLAG, &phid->lock);
 +			CPhidget_setStatusFlag(&phid->status, PHIDGET_DETACHING_FLAG, &phid->lock);
 +			
 +			if(!CList_findInList((CListHandle)zeroconfPhidgets, phid, CPhidget_areEqual, (void **)&found_phid))
 +			{
 +				CPhidget_clearStatusFlag(&found_phid->status, PHIDGET_ATTACHED_FLAG, &found_phid->lock);
 +				CPhidget_setStatusFlag(&found_phid->status, PHIDGET_DETACHING_FLAG, &found_phid->lock);
 +				CPhidget_setStatusFlag(&found_phid->status, PHIDGET_REMOTE_FLAG, &found_phid->lock);
 +				CPhidget_clearStatusFlag(&found_phid->status, PHIDGET_SERVER_CONNECTED_FLAG, &found_phid->lock);
 +				
 +				CList_removeFromList((CListHandle *)&zeroconfPhidgets, found_phid, CPhidget_areExtraEqual, FALSE, NULL);
 +				//managers
 +				for (trav=activeRemoteManagers; trav; trav = trav->next)
 +				{
 +					if(trav->phidm->networkInfo->requested_address==NULL
 +					   && (trav->phidm->networkInfo->requested_serverID == NULL || !strcmp(trav->phidm->networkInfo->requested_serverID,found_phid->networkInfo->zeroconf_server_id)))
 +					{
 +						CList_removeFromList((CListHandle *)&trav->phidm->AttachedPhidgets, found_phid, CPhidget_areExtraEqual, PFALSE, NULL);
 +						
 +						if (trav->phidm->fptrDetachChange && trav->phidm->state == PHIDGETMANAGER_ACTIVE)
 +							trav->phidm->fptrDetachChange((CPhidgetHandle)found_phid, trav->phidm->fptrDetachChangeptr);
 +					}
 +				}
 +				CPhidget_clearStatusFlag(&found_phid->status, PHIDGET_DETACHING_FLAG, &found_phid->lock);
 +				CPhidgetRemote_free(found_phid->networkInfo);
 +				CPhidget_free(found_phid);
 +			}
 +			CPhidgetRemote_free(phid->networkInfo);
 +			CPhidget_free(phid);
 +			
 +			CThread_mutex_unlock(&activeRemoteManagersLock);
 +			CThread_mutex_unlock(&zeroconfPhidgetsLock);
 +			free(name_copy);
 +		}
 +	}
 +}
 +
 +void DNSServiceBrowse_sbc_CallBack(DNSServiceRef service,
 +								   DNSServiceFlags flags,
 +								   uint32_t interfaceIndex,
 +								   DNSServiceErrorType errorCode,
 +								   const char * name,
 +								   const char * type,
 +								   const char * domain,
 +								   void * context)
 +{
 +	if (errorCode != kDNSServiceErr_NoError)
 +		LOG(PHIDGET_LOG_ERROR, "Dns_sbc_BrowseCallBack returned error: %d\n", errorCode);
 +	else
 +	{    
 +		DNSServiceErrorType error;
 +		DNSServiceRef  serviceRef;
 +		char fullname[kDNSServiceMaxDomainName];
 +		
 +		CPhidgetSBCHandle sbc;
 +		CPhidgetSBCHandle found_sbc;
 +		CPhidgetSBCManagerList *trav;
 +		
 +		DNSServiceConstructFullNamePtr(fullname, name, type, domain);
 +		
 +		
 +		if((CPhidgetSBC_create(&sbc))) return;
 +		if((CPhidgetRemote_create(&sbc->networkInfo))) return;
 +		
 +		sbc->networkInfo->zeroconf_name = strdup(name);
 +		sbc->networkInfo->zeroconf_type = strdup(type);
 +		sbc->networkInfo->zeroconf_domain = strdup(domain);
 +		sbc->networkInfo->zeroconf_interface = interfaceIndex;
 +		sbc->networkInfo->mdns = PTRUE;
 +		
 +		strncpy(sbc->mac, name+12, 18); //name == 'PhidgetSBC (??:??:??:??:??:??)'
 +		sbc->mac[17] = '\0';
 +		
 +		if(flags & kDNSServiceFlagsAdd)
 +		{
 +			LOG(PHIDGET_LOG_INFO, "DNSServiceBrowse_sbc_CallBack (Add): %s",name);
 +			error = DNSServiceQueryRecordPtr(&serviceRef, 0, interfaceIndex, fullname,
 +											 kDNSServiceType_TXT, kDNSServiceClass_IN, DNSServiceQueryRecord_SBC_CallBack, sbc);
 +			if (error == kDNSServiceErr_NoError)
 +			{
 +				DNSServiceProcessResultPtr(serviceRef);
 +				DNSServiceRefDeallocatePtr(serviceRef);
 +				
 +				CThread_mutex_lock(&zeroconfSBCsLock);
 +				CThread_mutex_lock(&activeSBCManagersLock);
 +				
 +				//Check if it's in the list and if it's different, remove it to make way for the new one
 +				// (Sometimes, we don't get a proper detach notification)
 +				if(CList_findInList((CListHandle)zeroconfSBCs, sbc, CPhidgetSBC_areEqual, (void **)&found_sbc) == EPHIDGET_OK)
 +				{
 +					if(CPhidgetSBC_areExtraEqual(found_sbc, sbc) != PTRUE) //A version number has changed
 +					{
 +						//make sure zeroconf_ref is not pending
 +						if(found_sbc->networkInfo)
 +						{
 +							CThread_mutex_lock(&found_sbc->networkInfo->zeroconf_ref_lock);
 +							if(found_sbc->networkInfo->zeroconf_ref)
 +							{
 +								DNSServiceRefDeallocatePtr((DNSServiceRef)found_sbc->networkInfo->zeroconf_ref);
 +								found_sbc->networkInfo->zeroconf_ref = NULL;
 +							}
 +							CThread_mutex_unlock(&found_sbc->networkInfo->zeroconf_ref_lock);
 +						}
 +						
 +						//Remove from list - don't free until after detach event
 +						CList_removeFromList((CListHandle *)&zeroconfSBCs, found_sbc, CPhidgetSBC_areEqual, PFALSE, NULL);
 +						
 +						for (trav=activeSBCManagers; trav; trav = trav->next)
 +						{
 +							if (trav->sbcm->fptrDetachChange && trav->sbcm->state == PHIDGETMANAGER_ACTIVE)
 +								trav->sbcm->fptrDetachChange((CPhidgetSBCHandle)found_sbc, trav->sbcm->fptrDetachChangeptr);
 +						}
 +						
 +						CPhidgetSBC_free(found_sbc);
 +						
 +						//now we fall through and add back to new one
 +					}
 +					else //Nothing has changed, we didn't remove, don't add
 +					{
 +						//prefer local. domain
 +						if((strcmp(domain, found_sbc->networkInfo->zeroconf_domain) != 0) && !(strcmp(domain, "local.")))
 +						{
 +							free(found_sbc->networkInfo->zeroconf_domain);
 +							found_sbc->networkInfo->zeroconf_domain = sbc->networkInfo->zeroconf_domain;
 +							sbc->networkInfo->zeroconf_domain = NULL;
 +						}
 +						CPhidgetSBC_free(sbc);
 +						goto dontadd;
 +					}
 +				}
 +				
 +				//now add it
 +				CList_addToList((CListHandle *)&zeroconfSBCs, sbc, CPhidgetSBC_areEqual);
 +				
 +				//send out events
 +				for (trav=activeSBCManagers; trav; trav = trav->next)
 +				{
 +					if (trav->sbcm->fptrAttachChange && trav->sbcm->state == PHIDGETMANAGER_ACTIVE)
 +						trav->sbcm->fptrAttachChange((CPhidgetSBCHandle)sbc, trav->sbcm->fptrAttachChangeptr);
 +					
 +				}
 +			dontadd:
 +				
 +				CThread_mutex_unlock(&activeSBCManagersLock);
 +				CThread_mutex_unlock(&zeroconfSBCsLock);
 +			}
 +			else
 +				LOG(PHIDGET_LOG_ERROR, "DNSServiceQueryRecordPtr returned error: %d\n", error);
 +		}
 +		else
 +		{
 +			
 +			LOG(PHIDGET_LOG_INFO, "DNSServiceBrowse_sbc_CallBack (Remove): %s",name);
 +			CThread_mutex_lock(&zeroconfSBCsLock);
 +			CThread_mutex_lock(&activeSBCManagersLock);
 +			
 +			//make sure zeroconf_ref is not pending
 +			if(sbc->networkInfo)
 +			{
 +				CThread_mutex_lock(&sbc->networkInfo->zeroconf_ref_lock);
 +				if(sbc->networkInfo->zeroconf_ref)
 +				{
 +					DNSServiceRefDeallocatePtr((DNSServiceRef)sbc->networkInfo->zeroconf_ref);
 +					sbc->networkInfo->zeroconf_ref = NULL;
 +				}
 +				CThread_mutex_unlock(&sbc->networkInfo->zeroconf_ref_lock);
 +			}
 +			
 +			if(CList_findInList((CListHandle)zeroconfSBCs, sbc, CPhidgetSBC_areEqual, (void **)&found_sbc) == EPHIDGET_OK)
 +			{
 +				CList_removeFromList((CListHandle *)&zeroconfSBCs, found_sbc, CPhidgetSBC_areEqual, PFALSE, NULL);
 +				//managers
 +				for (trav=activeSBCManagers; trav; trav = trav->next)
 +				{
 +					if (trav->sbcm->fptrDetachChange && trav->sbcm->state == PHIDGETMANAGER_ACTIVE)
 +						trav->sbcm->fptrDetachChange((CPhidgetSBCHandle)found_sbc, trav->sbcm->fptrDetachChangeptr);
 +				}
 +				CPhidgetSBC_free(found_sbc);
 +			}
 +			
 +			CThread_mutex_unlock(&activeSBCManagersLock);
 +			CThread_mutex_unlock(&zeroconfSBCsLock);
 +			
 +			CPhidgetSBC_free(sbc);
 +		}
 +	}
 +}
 +
 +void DNSServiceBrowse_ws_CallBack(DNSServiceRef service,
 +								  DNSServiceFlags flags,
 +								  uint32_t interfaceIndex,
 +								  DNSServiceErrorType errorCode,
 +								  const char * name,
 +								  const char * type,
 +								  const char * domain,
 +								  void * context)
 +{
 +	if (errorCode != kDNSServiceErr_NoError)
 +		LOG(PHIDGET_LOG_ERROR, "DNSServiceBrowse_ws_CallBack returned error: %d\n", errorCode);
 +	else
 +	{
 +		char fullname[kDNSServiceMaxDomainName];
 +		
 +		CPhidgetRemoteHandle networkInfo;
 +		if((CPhidgetRemote_create(&networkInfo))) return;
 +		
 +		networkInfo->zeroconf_name = strdup(name);
 +		networkInfo->zeroconf_server_id = strdup(name);
 +		networkInfo->zeroconf_type = strdup(type);
 +		networkInfo->zeroconf_domain = strdup(domain);
 +		networkInfo->zeroconf_interface = interfaceIndex;
 +		
 +		DNSServiceConstructFullNamePtr(fullname, name, type, domain);
 +		
 +		LOG(PHIDGET_LOG_INFO, "DNSServiceBrowse_ws_CallBack: %s (%s, %s, %d)",name,type,domain,interfaceIndex);
 +		
 +		CThread_mutex_lock(&zeroconfServersLock);
 +		if(flags & kDNSServiceFlagsAdd)
 +		{
 +			if(CList_addToList((CListHandle *)&zeroconfServers, networkInfo, CPhidgetRemote_areEqual) != EPHIDGET_OK)
 +				CPhidgetRemote_free(networkInfo);
 +		}
 +		else
 +		{
 +			CList_removeFromList((CListHandle *)&zeroconfServers, networkInfo, CPhidgetRemote_areEqual, TRUE, CPhidgetRemote_free);
 +		}
 +		CThread_mutex_unlock(&zeroconfServersLock);
 +	}
 +}
 +
 +int cancelPendingZeroconfLookups(CPhidgetRemoteHandle networkInfo)
 +{	
 +	if(networkInfo->zeroconf_ref != NULL)
 +	{
 +		DNSServiceRefDeallocatePtr((DNSServiceRef)networkInfo->zeroconf_ref);
 +		networkInfo->zeroconf_ref = NULL;
 +	}
 +	return EPHIDGET_OK;
 +}
 +
 +
 +void DNSServiceQueryRecord_CallBack
 +(
 + DNSServiceRef                       DNSServiceRef,
 + DNSServiceFlags                     flags,
 + uint32_t                            interfaceIndex,
 + DNSServiceErrorType                 errorCode,
 + const char                          *fullname,
 + uint16_t                            rrtype,
 + uint16_t                            rrclass,
 + uint16_t                            rdlen,
 + const void                          *rdata,
 + uint32_t                            ttl,
 + void                                *context
 + )
 +{
 +	
 +	CPhidgetRemoteHandle networkInfo = (CPhidgetRemoteHandle)context;
 +	
 +	if (errorCode != kDNSServiceErr_NoError)
 +	{
 +		LOG(PHIDGET_LOG_ERROR, "DNSServiceQueryRecord_CallBack returned error: %d\n", errorCode);
 +		networkInfo->zeroconf_ipaddr = NULL;
 +	}
 +	else if(networkInfo->zeroconf_ipaddr == NULL)
 +	{
 +		if(rrtype == kDNSServiceType_A && rdlen == 4)
 +		{
 +			struct in_addr ip;
 +			memcpy(&ip, rdata, 4);
 +			
 +			networkInfo->zeroconf_ipaddr = strdup(inet_ntoa(ip));
 +		}
 +		//NOTE: Windows doesn't have inet_ntop
 +		/*
 +		else if(rrtype == kDNSServiceType_AAAA && rdlen == 16)
 +		{
 +			struct in6_addr ip;
 +			memcpy(&ip, rdata, 16);
 +			
 +			if((networkInfo->zeroconf_ipaddr = malloc(200)) != NULL)
 +			{
 +				networkInfo->zeroconf_ipaddr = strdup(inet_ntop(AF_INET6, &ip, networkInfo->zeroconf_ipaddr, 200));
 +			}
 +		}
 +		*/
 +
 +		LOG(PHIDGET_LOG_INFO, "DNSServiceQueryRecord_CallBack: %s (%s %d)",fullname, networkInfo->zeroconf_ipaddr, interfaceIndex);
 +	}
 +	else
 +		LOG(PHIDGET_LOG_INFO, "DNSServiceQueryRecord_CallBack (extra, not used): %s (%d)",fullname, interfaceIndex);
 +}
 +
 +int getZeroconfIPAddr(CPhidgetRemoteHandle networkInfo)
 +{
 +	DNSServiceErrorType error;
 +	
 +	LOG(PHIDGET_LOG_VERBOSE, "Resolving IP Address for: %s, %s, %s, %s, %d",
 +		networkInfo->zeroconf_name, //name
 +		networkInfo->zeroconf_type, // service type
 +		networkInfo->zeroconf_domain, //domain
 +		networkInfo->zeroconf_host,
 +		networkInfo->zeroconf_interface);
 +	
 +	//already a lookup pending? cancel it and start a new one...
 +	CThread_mutex_lock(&networkInfo->zeroconf_ref_lock);
 +	if(networkInfo->zeroconf_ref != NULL)
 +	{
 +		DNSServiceRefDeallocatePtr((DNSServiceRef)networkInfo->zeroconf_ref);
 +		networkInfo->zeroconf_ref = NULL;
 +	}
 +	
 +	free(networkInfo->zeroconf_ipaddr);
 +	networkInfo->zeroconf_ipaddr = NULL;
 +	
 +	error = DNSServiceQueryRecordPtr((DNSServiceRef *)&networkInfo->zeroconf_ref,
 +									 0,  // no flags
 +									 networkInfo->zeroconf_interface,
 +									 networkInfo->zeroconf_host, //hostname
 +									 kDNSServiceType_A, // IPv4 address for now..
 +									 kDNSServiceClass_IN, // service class
 +									 DNSServiceQueryRecord_CallBack,
 +									 networkInfo);
 +	if (error != kDNSServiceErr_NoError)
 +	{
 +		LOG(PHIDGET_LOG_ERROR, "DNSServiceQueryRecordPtr returned error: %d\n", error);
 +		networkInfo->zeroconf_ref = NULL;
 +		CThread_mutex_unlock(&networkInfo->zeroconf_ref_lock);
 +		return EPHIDGET_NETWORK;
 +	}
 +	else
 +	{
 +		DNSServiceProcessResultPtr((DNSServiceRef)networkInfo->zeroconf_ref);
 +		DNSServiceRefDeallocatePtr((DNSServiceRef)networkInfo->zeroconf_ref);
 +		networkInfo->zeroconf_ref = NULL;
 +		CThread_mutex_unlock(&networkInfo->zeroconf_ref_lock);
 +		LOG(PHIDGET_LOG_VERBOSE, "Successfull lookup: %s",networkInfo->zeroconf_host);
 +		return EPHIDGET_OK;
 +	}
 +	
 +}
 +
 +void DNSServiceResolve_CallBack(
 +								DNSServiceRef						sdRef,
 +								DNSServiceFlags                     flags,
 +								uint32_t                            interfaceIndex,
 +								DNSServiceErrorType                 errorCode,
 +								const char                          *fullname,
 +								const char                          *hosttarget,
 +								uint16_t                            port,
 +								uint16_t                            txtLen,
 +								const unsigned char					*txtRecord,
 +								void                                *context)
 +{	
 +	CPhidgetRemoteHandle networkInfo = (CPhidgetRemoteHandle)context;
 +	
 +	
 +	if (errorCode != kDNSServiceErr_NoError)
 +	{
 +		LOG(PHIDGET_LOG_ERROR, "DNSServiceResolve_CallBack returned error: %d\n", errorCode);
 +		networkInfo->zeroconf_host = NULL;
 +		networkInfo->zeroconf_port = NULL;
 +	}
 +	else if(!networkInfo->zeroconf_host && !networkInfo->zeroconf_port)
 +	{
 +		
 +		LOG(PHIDGET_LOG_INFO, "DNSServiceResolve_CallBack: %s (%s:%d %d)",fullname, hosttarget, ntohs(port), interfaceIndex);
 +		
 +		networkInfo->zeroconf_host = strdup(hosttarget);
 +		networkInfo->zeroconf_port = malloc(10);
 +		snprintf(networkInfo->zeroconf_port, 10, "%d", ntohs(port));
 +	}
 +	else
 +		LOG(PHIDGET_LOG_INFO, "DNSServiceResolve_CallBack (extra, not used): %s (%s:%d %d)",fullname, hosttarget, ntohs(port), interfaceIndex);
 +}
 +
 +int getZeroconfHostPort(CPhidgetRemoteHandle networkInfo)
 +{
 +	DNSServiceErrorType error;
 +	
 +	LOG(PHIDGET_LOG_VERBOSE, "Resolving host:port for: %s, %s, %s",
 +		networkInfo->zeroconf_name, //name
 +		networkInfo->zeroconf_type, // service type
 +		networkInfo->zeroconf_domain //domain
 +		);
 +	
 +	//already a lookup pending? cancel it and start a new one...
 +	CThread_mutex_lock(&networkInfo->zeroconf_ref_lock);
 +	if(networkInfo->zeroconf_ref != NULL)
 +	{
 +		DNSServiceRefDeallocatePtr((DNSServiceRef)networkInfo->zeroconf_ref);
 +		networkInfo->zeroconf_ref = NULL;
 +	}
 +	
 +	free(networkInfo->zeroconf_host);
 +	networkInfo->zeroconf_host = NULL;
 +	free(networkInfo->zeroconf_port);
 +	networkInfo->zeroconf_port = NULL;
 +	
 +	error = DNSServiceResolvePtr((DNSServiceRef *)&networkInfo->zeroconf_ref,
 +								 0,  // no flags
 +								 0,  // all interfaces
 +								 //networkInfo->zeroconf_interface,  // interface this service was discovered on
 +								 networkInfo->zeroconf_name, //name
 +								 networkInfo->zeroconf_type, // service type
 +								 networkInfo->zeroconf_domain, //domain
 +								 DNSServiceResolve_CallBack,
 +								 networkInfo);     // no context
 +	if (error != kDNSServiceErr_NoError)
 +	{
 +		LOG(PHIDGET_LOG_ERROR, "getZeroconfHostPort returned error: %d\n", error);
 +		networkInfo->zeroconf_ref = NULL;
 +		CThread_mutex_unlock(&networkInfo->zeroconf_ref_lock);
 +		return EPHIDGET_NETWORK;
 +	}
 +	else
 +	{
 +		DNSServiceProcessResultPtr((DNSServiceRef)networkInfo->zeroconf_ref);
 +		DNSServiceRefDeallocatePtr((DNSServiceRef)networkInfo->zeroconf_ref);
 +		networkInfo->zeroconf_ref = NULL;
 +		LOG(PHIDGET_LOG_VERBOSE, "Successfull host:port lookup: %s:%s",networkInfo->zeroconf_host,networkInfo->zeroconf_port);
 +		CThread_mutex_unlock(&networkInfo->zeroconf_ref_lock);
 +		//Don't bother - we aren't going to use it anyways
 +		//This is just another way to lookup the IP address - from the DNS record
 +		//getZeroconfIPAddr(networkInfo);
 +		return EPHIDGET_OK;
 +	}
 +}
 +
 +int refreshZeroconf(CPhidgetRemoteHandle networkInfo, DNSServiceQueryRecordReply callBack, void *userPtr)
 +{
 +	DNSServiceErrorType error;
 +	char fullname[kDNSServiceMaxDomainName];
 +	
 +	LOG(PHIDGET_LOG_VERBOSE, "Refreshing zeroconf on: 0x%x",networkInfo);
 +	
 +	//already a lookup pending? cancel it and start a new one...
 +	CThread_mutex_lock(&networkInfo->zeroconf_ref_lock);
 +	
 +	DNSServiceConstructFullNamePtr(fullname, networkInfo->zeroconf_name, networkInfo->zeroconf_type, networkInfo->zeroconf_domain);
 +	
 +	if(networkInfo->zeroconf_ref != NULL)
 +	{
 +		DNSServiceRefDeallocatePtr((DNSServiceRef)networkInfo->zeroconf_ref);
 +		networkInfo->zeroconf_ref = NULL;
 +	}
 +	error = DNSServiceQueryRecordPtr((DNSServiceRef *)&networkInfo->zeroconf_ref,
 +									 0,  // no flags
 +									 networkInfo->zeroconf_interface,
 +									 fullname, //name
 +									 kDNSServiceType_TXT, // service type
 +									 kDNSServiceClass_IN, // service class
 +									 callBack,
 +									 userPtr);
 +	if (error != kDNSServiceErr_NoError)
 +	{
 +		LOG(PHIDGET_LOG_ERROR, "DNSServiceQueryRecordPtr returned error: %d\n", error);
 +		networkInfo->zeroconf_ref = NULL;
 +		CThread_mutex_unlock(&networkInfo->zeroconf_ref_lock);
 +		return EPHIDGET_NETWORK;
 +	}
 +	else
 +	{
 +		DNSServiceProcessResultPtr((DNSServiceRef)networkInfo->zeroconf_ref);
 +		DNSServiceRefDeallocatePtr((DNSServiceRef)networkInfo->zeroconf_ref);
 +		networkInfo->zeroconf_ref = NULL;
 +		CThread_mutex_unlock(&networkInfo->zeroconf_ref_lock);
 +		LOG(PHIDGET_LOG_VERBOSE, "Successfull refresh.");
 +		return EPHIDGET_OK;
 +	}
 +}
 +
 +int refreshZeroconfSBC(CPhidgetSBCHandle sbc)
 +{
 +	return refreshZeroconf(sbc->networkInfo, DNSServiceQueryRecord_SBC_CallBack, sbc);
 +}
 +
 +int refreshZeroconfPhidget(CPhidgetHandle phid)
 +{
 +	return refreshZeroconf(phid->networkInfo, DNSServiceQueryRecord_Phidget_CallBack, phid);
 +}
 +
 +int InitializeZeroconf()
 +{
 +	DNSServiceErrorType error;
 +	CThread_mutex_lock(&zeroconfInitLock);
 +	if(!Dns_sdInitialized)
 +	{
 +#ifdef ZEROCONF_RUNTIME_LINKING
 +		
 +#ifdef _WINDOWS
 +		if(!(dllHandle = LoadLibrary(L"dnssd.dll")))
 +		{
 +			DWORD error = GetLastError();
 +			switch(error)
 +			{
 +				case ERROR_MOD_NOT_FOUND:
 +					LOG(PHIDGET_LOG_DEBUG,"LoadLibrary failed - module could not be found");
 +					break;
 +				default:
 +					LOG(PHIDGET_LOG_DEBUG,"LoadLibrary failed with error code: %d", error);
 +			}
 +			CThread_mutex_unlock(&zeroconfInitLock);
 +			return EPHIDGET_UNEXPECTED;
 +		}
 +		
 +		// If the handle is valid, try to get the function address. 
 +		if (NULL != dllHandle) 
 +		{ 
 +			//Get pointers to our functions using GetProcAddress:
 +#ifdef WINCE
 +			DNSServiceRegisterPtr = (DNSServiceRegisterType)GetProcAddress(dllHandle, L"DNSServiceRegister");
 +			DNSServiceProcessResultPtr = (DNSServiceProcessResultType)GetProcAddress(dllHandle, L"DNSServiceProcessResult");
 +			DNSServiceRefDeallocatePtr = (DNSServiceRefDeallocateType)GetProcAddress(dllHandle, L"DNSServiceRefDeallocate");
 +			DNSServiceAddRecordPtr = (DNSServiceAddRecordType)GetProcAddress(dllHandle, L"DNSServiceAddRecord");
 +			DNSServiceUpdateRecordPtr = (DNSServiceUpdateRecordType)GetProcAddress(dllHandle, L"DNSServiceUpdateRecord");
 +			DNSServiceRemoveRecordPtr = (DNSServiceRemoveRecordType)GetProcAddress(dllHandle, L"DNSServiceRemoveRecord");
 +			DNSServiceBrowsePtr = (DNSServiceBrowseType)GetProcAddress(dllHandle, L"DNSServiceBrowse");
 +			DNSServiceResolvePtr = (DNSServiceResolveType)GetProcAddress(dllHandle, L"DNSServiceResolve");
 +			DNSServiceQueryRecordPtr = (DNSServiceQueryRecordType)GetProcAddress(dllHandle, L"DNSServiceQueryRecord");
 +			DNSServiceConstructFullNamePtr = (DNSServiceConstructFullNameType)GetProcAddress(dllHandle, L"DNSServiceConstructFullName");
 +			DNSServiceRefSockFDPtr = (DNSServiceRefSockFDType)GetProcAddress(dllHandle, L"DNSServiceRefSockFD");
 +#else
 +			DNSServiceRegisterPtr = (DNSServiceRegisterType)GetProcAddress(dllHandle, "DNSServiceRegister");
 +			DNSServiceProcessResultPtr = (DNSServiceProcessResultType)GetProcAddress(dllHandle, "DNSServiceProcessResult");
 +			DNSServiceRefDeallocatePtr = (DNSServiceRefDeallocateType)GetProcAddress(dllHandle, "DNSServiceRefDeallocate");
 +			DNSServiceAddRecordPtr = (DNSServiceAddRecordType)GetProcAddress(dllHandle, "DNSServiceAddRecord");
 +			DNSServiceUpdateRecordPtr = (DNSServiceUpdateRecordType)GetProcAddress(dllHandle, "DNSServiceUpdateRecord");
 +			DNSServiceRemoveRecordPtr = (DNSServiceRemoveRecordType)GetProcAddress(dllHandle, "DNSServiceRemoveRecord");
 +			DNSServiceBrowsePtr = (DNSServiceBrowseType)GetProcAddress(dllHandle, "DNSServiceBrowse");
 +			DNSServiceResolvePtr = (DNSServiceResolveType)GetProcAddress(dllHandle, "DNSServiceResolve");
 +			DNSServiceQueryRecordPtr = (DNSServiceQueryRecordType)GetProcAddress(dllHandle, "DNSServiceQueryRecord");
 +			DNSServiceConstructFullNamePtr = (DNSServiceConstructFullNameType)GetProcAddress(dllHandle, "DNSServiceConstructFullName");
 +			DNSServiceRefSockFDPtr = (DNSServiceRefSockFDType)GetProcAddress(dllHandle, "DNSServiceRefSockFD");
 +#endif
 +			
 +			Dns_sdInitialized = (
 +								 NULL != DNSServiceRegisterPtr && 
 +								 NULL != DNSServiceProcessResultPtr &&
 +								 NULL != DNSServiceRefDeallocatePtr &&
 +								 NULL != DNSServiceAddRecordPtr &&
 +								 NULL != DNSServiceUpdateRecordPtr &&
 +								 NULL != DNSServiceRemoveRecordPtr &&
 +								 NULL != DNSServiceQueryRecordPtr &&
 +								 NULL != DNSServiceConstructFullNamePtr &&
 +								 NULL != DNSServiceRefSockFDPtr);
 +		}
 +		
 +		if(!Dns_sdInitialized)
 +		{
 +			LOG(PHIDGET_LOG_DEBUG,"InitializeZeroconf failed somehow...");
 +			CThread_mutex_unlock(&zeroconfInitLock);
 +			return EPHIDGET_UNSUPPORTED;
 +		}
 +		
 +#elif _LINUX
 +		libHandle = dlopen("libdns_sd.so",RTLD_LAZY);
 +		if(!libHandle)
 +		{
 +			LOG(PHIDGET_LOG_WARNING, "dlopen failed with error: %s", dlerror());
 +			LOG(PHIDGET_LOG_WARNING, "Assuming that zeroconf is not supported on this machine.");
 +			CThread_mutex_unlock(&zeroconfInitLock);
 +			return EPHIDGET_UNSUPPORTED;
 +		}
 +		
 +		//Get pointers to our functions using dlsym:
 +		if(!(DNSServiceRegisterPtr = (DNSServiceRegisterType)dlsym(libHandle, "DNSServiceRegister"))) goto dlsym_err;
 +		if(!(DNSServiceProcessResultPtr = (DNSServiceProcessResultType)dlsym(libHandle, "DNSServiceProcessResult"))) goto dlsym_err;
 +		if(!(DNSServiceRefDeallocatePtr = (DNSServiceRefDeallocateType)dlsym(libHandle, "DNSServiceRefDeallocate"))) goto dlsym_err;
 +		if(!(DNSServiceAddRecordPtr = (DNSServiceAddRecordType)dlsym(libHandle, "DNSServiceAddRecord"))) goto dlsym_err;
 +		if(!(DNSServiceUpdateRecordPtr = (DNSServiceUpdateRecordType)dlsym(libHandle, "DNSServiceUpdateRecord"))) goto dlsym_err;
 +		if(!(DNSServiceRemoveRecordPtr = (DNSServiceRemoveRecordType)dlsym(libHandle, "DNSServiceRemoveRecord"))) goto dlsym_err;
 +		if(!(DNSServiceBrowsePtr = (DNSServiceBrowseType)dlsym(libHandle, "DNSServiceBrowse"))) goto dlsym_err;
 +		if(!(DNSServiceResolvePtr = (DNSServiceResolveType)dlsym(libHandle, "DNSServiceResolve"))) goto dlsym_err;
 +		if(!(DNSServiceQueryRecordPtr = (DNSServiceQueryRecordType)dlsym(libHandle, "DNSServiceQueryRecord"))) goto dlsym_err;
 +		if(!(DNSServiceConstructFullNamePtr = (DNSServiceConstructFullNameType)dlsym(libHandle, "DNSServiceConstructFullName"))) goto dlsym_err;
 +		if(!(DNSServiceRefSockFDPtr = (DNSServiceRefSockFDType)dlsym(libHandle, "DNSServiceRefSockFD"))) goto dlsym_err;
 +		
 +		goto dlsym_good;
 +		
 +	dlsym_err:
 +		LOG(PHIDGET_LOG_WARNING, "dlsym failed with error: %s", dlerror());
 +		LOG(PHIDGET_LOG_WARNING, "Assuming that zeroconf is not supported on this machine.");
 +		CThread_mutex_unlock(&zeroconfInitLock);
 +		return EPHIDGET_UNSUPPORTED;
 +		
 +	dlsym_good:
 +		Dns_sdInitialized = TRUE;
 +#endif
 +		
 +#else
 +		Dns_sdInitialized = TRUE;
 +#endif
 +		LOG(PHIDGET_LOG_DEBUG,"InitializeZeroconf - System supports zeroconf.");
 +	}
 +	if(!Dns_sdBrowsing)
 +	{
 +		error = DNSServiceBrowsePtr(&zeroconf_browse_ws_ref,
 +									0,                // no flags
 +									0,                // all network interfaces
 +									"_phidget_ws._tcp",     // service type
 +									"",               // default domains
 +									DNSServiceBrowse_ws_CallBack, // call back function
 +									NULL);            // no context
 +		if (error != kDNSServiceErr_NoError)
 +		{
 +			LOG(PHIDGET_LOG_ERROR,"DNSServiceBrowse on _phidget_ws._tcp failed: %d", error);
 +			CThread_mutex_unlock(&zeroconfInitLock);
 +			return EPHIDGET_TRYAGAIN;
 +		}
 +		
 +		error = DNSServiceBrowsePtr(&zeroconf_browse_sbc_ref,
 +									0,                // no flags
 +									0,                // all network interfaces
 +									"_phidget_sbc._tcp",     // service type
 +									"",               // default domains
 +									DNSServiceBrowse_sbc_CallBack, // call back function
 +									NULL);            // no context
 +		if (error != kDNSServiceErr_NoError)
 +		{
 +			LOG(PHIDGET_LOG_ERROR,"DNSServiceBrowse on _phidget_sbc._tcp failed: %d", error);
 +			CThread_mutex_unlock(&zeroconfInitLock);
 +			return EPHIDGET_TRYAGAIN;
 +		}
 +		
 +		error = DNSServiceBrowsePtr(&zeroconf_browse_phidget_ref,
 +									0,                // no flags
 +									0,                // all network interfaces
 +									"_phidget._tcp",     // service type
 +									"",               // default domains
 +									DNSServiceBrowse_Phidget_CallBack, // call back function
 +									NULL);            // no context
 +		if (error != kDNSServiceErr_NoError)
 +		{
 +			LOG(PHIDGET_LOG_ERROR,"DNSServiceBrowse on _phidget._tcp failed: %d", error);
 +			CThread_mutex_unlock(&zeroconfInitLock);
 +			return EPHIDGET_TRYAGAIN;
 +		}
 +		
 +		stopBrowsing = FALSE;
 +		pthread_create(&dns_thread, NULL, (void *(*)(void *))dns_callback_thread,NULL);
 +		
 +		Dns_sdBrowsing = PTRUE;
 +		LOG(PHIDGET_LOG_DEBUG,"InitializeZeroconf - Zeroconf browsing active.");
 +	}
 +	CThread_mutex_unlock(&zeroconfInitLock);
 +	return EPHIDGET_OK;
 +}
 +
 +int UninitializeZeroconf()
 +{
 +	void *status;
 +	CThread_mutex_lock(&zeroconfInitLock);
 +	if(Dns_sdBrowsing)
 +	{
 +		stopBrowsing = TRUE;
 +		if(dns_thread)
 +		{
 +			pthread_join(dns_thread, &status);
 +			dns_thread = NULL;
 +		}
 +		
 +		if(zeroconf_browse_ws_ref)
 +		{
 +			DNSServiceRefDeallocatePtr(zeroconf_browse_ws_ref);
 +			zeroconf_browse_ws_ref = NULL;
 +		}
 +		if(zeroconf_browse_sbc_ref)
 +		{
 +			DNSServiceRefDeallocatePtr(zeroconf_browse_sbc_ref);
 +			zeroconf_browse_sbc_ref = NULL;
 +		}
 +		if(zeroconf_browse_phidget_ref)
 +		{
 +			DNSServiceRefDeallocatePtr(zeroconf_browse_phidget_ref);
 +			zeroconf_browse_phidget_ref = NULL;
 +		}
 +		
 +		CThread_mutex_lock(&zeroconfPhidgetsLock);
 +		CList_emptyList((CListHandle *)&zeroconfPhidgets, FALSE, NULL);
 +		CThread_mutex_unlock(&zeroconfPhidgetsLock);
 +		
 +		CThread_mutex_lock(&zeroconfSBCsLock);
 +		CList_emptyList((CListHandle *)&zeroconfSBCs, FALSE, NULL);
 +		CThread_mutex_unlock(&zeroconfSBCsLock);
 +		
 +		CThread_mutex_lock(&zeroconfServersLock);
 +		CList_emptyList((CListHandle *)&zeroconfServers, FALSE, NULL);
 +		CThread_mutex_unlock(&zeroconfServersLock);
 +		
 +		Dns_sdBrowsing = FALSE;
 +	}
 +	CThread_mutex_unlock(&zeroconfInitLock);
 +	return EPHIDGET_OK;
 +}
 +
 +
  | 
