aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJonathan McCrohan <jmccrohan@gmail.com>2012-05-09 00:47:30 +0100
committerJonathan McCrohan <jmccrohan@gmail.com>2012-05-09 00:47:30 +0100
commit260123716172d33f44bdc0e4e5422554d139215c (patch)
tree840e8e6387b96bd6f9afe3ffebc19c781a112f1b
parent0b624384cd52be20e61284551d832b499d7b7707 (diff)
downloadlibphidget21-260123716172d33f44bdc0e4e5422554d139215c.tar.gz
Imported Upstream version 2.1.8.20120507upstream/2.1.8.20120507
-rw-r--r--Java/com/phidgets/AdvancedServoPhidget.java2
-rw-r--r--Java/com/phidgets/Dictionary.java2
-rw-r--r--Java/com/phidgets/IRPhidget.java478
-rw-r--r--Java/com/phidgets/Manager.java4
-rw-r--r--Java/com/phidgets/Phidget.java2
-rw-r--r--Java/com/phidgets/PhidgetException.java2
-rw-r--r--Makefile.am17
-rw-r--r--Makefile.in158
-rw-r--r--README13
-rwxr-xr-xconfigure315
-rw-r--r--configure.ac25
-rw-r--r--cphidget.c463
-rw-r--r--cphidget.h46
-rw-r--r--cphidgetadvancedservo.c14
-rw-r--r--cphidgetattr.h107
-rw-r--r--cphidgetconstants.c114
-rw-r--r--cphidgetconstantsinternal.h2
-rw-r--r--cphidgetgps.c2
-rw-r--r--cphidgetmanager.c5
-rw-r--r--cphidgetspatial.c3047
-rw-r--r--cphidgetspatial.h92
-rw-r--r--cphidgetstepper.c2
-rw-r--r--csocketevents.c5
-rw-r--r--csocketopen.c2
-rw-r--r--cthread.c6
-rw-r--r--cusb.h9
-rw-r--r--dict/pdictclient.c2
-rw-r--r--examples/manager.c2
-rw-r--r--libphidget21.pc.in10
-rw-r--r--linux/cusblinux-1.0.c659
-rw-r--r--linux/cusblinux.c11
-rw-r--r--linux/zeroconf_avahi.c1
-rw-r--r--phidget21.h96
-rw-r--r--stdafx.h8
-rw-r--r--utils/utils.c2
-rwxr-xr-xversion.sh2
-rw-r--r--zeroconf.c2463
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 $@"
diff --git a/README b/README
index af610ab..46e7055 100644
--- a/README
+++ b/README
@@ -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
=====
diff --git a/configure b/configure
index d543cd9..32e9e9d 100755
--- a/configure
+++ b/configure
@@ -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])
diff --git a/cphidget.c b/cphidget.c
index d8d5cb3..a408210 100644
--- a/cphidget.c
+++ b/cphidget.c
@@ -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
diff --git a/cphidget.h b/cphidget.h
index 7962026..3ad3770 100644
--- a/cphidget.h
+++ b/cphidget.h
@@ -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);
diff --git a/cthread.c b/cthread.c
index 4ab5e8a..86f2f9b 100644
--- a/cthread.c
+++ b/cthread.c
@@ -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.
*/
diff --git a/cusb.h b/cusb.h
index 3c24a11..eda2b16 100644
--- a/cusb.h
+++ b/cusb.h
@@ -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;
diff --git a/stdafx.h b/stdafx.h
index fce61f2..bf5389d 100644
--- a/stdafx.h
+++ b/stdafx.h
@@ -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;
}
}
diff --git a/version.sh b/version.sh
index 366dee6..34fc206 100755
--- a/version.sh
+++ b/version.sh
@@ -1,2 +1,2 @@
#!/bin/bash
-echo -n 2.1.8.20120216
+echo -n 2.1.8.20120507
diff --git a/zeroconf.c b/zeroconf.c
index df72b91..81b030c 100644
--- a/zeroconf.c
+++ b/zeroconf.c
@@ -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;
+}
+
+