From 260123716172d33f44bdc0e4e5422554d139215c Mon Sep 17 00:00:00 2001 From: Jonathan McCrohan Date: Wed, 9 May 2012 00:47:30 +0100 Subject: Imported Upstream version 2.1.8.20120507 --- Java/com/phidgets/AdvancedServoPhidget.java | 2 +- Java/com/phidgets/Dictionary.java | 2 +- Java/com/phidgets/IRPhidget.java | 478 ++--- Java/com/phidgets/Manager.java | 4 +- Java/com/phidgets/Phidget.java | 2 +- Java/com/phidgets/PhidgetException.java | 2 +- Makefile.am | 17 +- Makefile.in | 158 +- README | 13 +- configure | 315 ++- configure.ac | 25 +- cphidget.c | 463 +++- cphidget.h | 46 + cphidgetadvancedservo.c | 14 +- cphidgetattr.h | 107 + cphidgetconstants.c | 114 + cphidgetconstantsinternal.h | 2 +- cphidgetgps.c | 2 +- cphidgetmanager.c | 5 + cphidgetspatial.c | 3047 +++++++++++++++------------ cphidgetspatial.h | 92 +- cphidgetstepper.c | 2 +- csocketevents.c | 5 + csocketopen.c | 2 +- cthread.c | 6 +- cusb.h | 9 +- dict/pdictclient.c | 2 +- examples/manager.c | 2 +- libphidget21.pc.in | 10 + linux/cusblinux-1.0.c | 659 ++++++ linux/cusblinux.c | 11 +- linux/zeroconf_avahi.c | 1 + phidget21.h | 96 +- stdafx.h | 8 +- utils/utils.c | 2 +- version.sh | 2 +- zeroconf.c | 2463 +++++++++++----------- 37 files changed, 5091 insertions(+), 3099 deletions(-) create mode 100644 libphidget21.pc.in create mode 100644 linux/cusblinux-1.0.c 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. *

* 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. *

* 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. - *

- * 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. - *

- * 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. - *

- * 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. - *

- * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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." *

- * 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. *

* 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 . # @@ -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: ." _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 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 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;ioutputReportByteLength && joutputReportByteLength && jwritelock); + + 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;ioutputReportByteLength && jwritelock); + + if((result = CUSBSendPacket((CPhidgetHandle)phid, buffer)) != EPHIDGET_OK) + goto done; + + while(joutputReportByteLength && jwritelock); + + 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; iaccelAxis[i] = PUNI_DBL; - } - for (i = 0; igyroAxis[i] = PUNI_DBL; - } - for (i = 0; icompassAxis[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; iphid.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; iphid.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; iphid.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;iaccelOffset[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; iphid.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;iaccelOffset[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;jphid.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; iphid.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; jphid.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;jphid.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> 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;jphid.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; iphid.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; iphid.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; iphid.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; iphid.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; iphid.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; iphid.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; iphid.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; iphid.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; iphid.attr.spatial.numCompassAxes; i++) - { - magneticFieldCorr[i] = eventData[j]->magneticField[i]; - } - for (i = 0; iphid.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; iphid.attr.spatial.numAccelAxes; i++) - { - if(eventData[j]->acceleration[i] != PUNK_DBL) - { - accelAvg[i] += eventData[j]->acceleration[i]; - accelCounter[i]++; - } - } - for (i = 0; iphid.attr.spatial.numGyroAxes; i++) - { - if(eventData[j]->angularRate[i] != PUNK_DBL) - { - angularRateAvg[i] += eventData[j]->angularRate[i]; - angularRateCounter[i]++; - } - } - for (i = 0; iphid.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; iphid.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; iphid.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; iphid.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;idoZeroGyro = 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; iaccelAxis[i] = PUNI_DBL; + } + for (i = 0; igyroAxis[i] = PUNI_DBL; + } + for (i = 0; icompassAxis[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; iphid.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; iphid.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; iphid.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;iaccelOffset[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; iphid.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;idataBuffer[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;iaccelOffset[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;jphid.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; iphid.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; jphid.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;jphid.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> 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; iphid.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; iphid.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; iphid.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; iphid.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; iphid.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; iphid.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; iphid.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; iphid.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; iphid.attr.spatial.numCompassAxes; i++) + { + magneticFieldCorr[i] = eventData[j]->magneticField[i]; + } + for (i = 0; iphid.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; iphid.attr.spatial.numAccelAxes; i++) + { + if(eventData[j]->acceleration[i] != PUNK_DBL) + { + accelAvg[i] += eventData[j]->acceleration[i]; + accelCounter[i]++; + } + } + for (i = 0; iphid.attr.spatial.numGyroAxes; i++) + { + if(eventData[j]->angularRate[i] != PUNK_DBL) + { + angularRateAvg[i] += eventData[j]->angularRate[i]; + angularRateCounter[i]++; + } + } + for (i = 0; iphid.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; iphid.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; iphid.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; iphid.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;idoZeroGyro = 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;ilastHeartbeatTime); - //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 + +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; ibNumInterfaces; i++) + { + for(j=0; jinterface[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;iinputReportByteLength=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; ideviceVersion = 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; ideviceID) { + 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 + +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 - #endif #include #include 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 (pserialNumber = 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;ideviceIDSpec == 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;ideviceIDSpec = 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;ideviceDef = &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 (pserialNumber = 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;ideviceIDSpec == 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;ideviceIDSpec = 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;ideviceDef = &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; +} + + -- cgit v1.2.3