summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorknolax <1339802534.kk@gmail.com>2015-11-12 10:25:18 -0500
committerknolax <1339802534.kk@gmail.com>2015-11-12 10:25:18 -0500
commit28804e241aab357403e3e963bcf6b4a4a7de82fb (patch)
treeee8fe579967694628d671e5ac3146e2199150351
added the files
-rw-r--r--Finch.c635
-rw-r--r--License.txt5
-rw-r--r--README.md4
-rw-r--r--hidapi.h332
-rwxr-xr-xmainbin0 -> 15260 bytes
-rw-r--r--main.c436
-rw-r--r--makefile2
7 files changed, 1414 insertions, 0 deletions
diff --git a/Finch.c b/Finch.c
new file mode 100644
index 0000000..4cd1200
--- /dev/null
+++ b/Finch.c
@@ -0,0 +1,635 @@
+#if 0
+
+Command/Response Format:
+
+All commands to the Finch are 9 bytes long:
+
+ Byte 0: is always 0x00.
+ Byte 1: is an Ascii character
+ determines the command for the Finch to execute
+ Bytes 2-7: parametric data in binary
+ Byte 8: sequence number
+
+All responses are 8 bytes long:
+
+ Bytes 0-6: sensor data in binary
+ Byte 7: sequence number (from byte 8 of the command)
+
+
+Ascii Command Codes:
+
+ - 'O' - control full-color LEDs (Orbs)
+ Byte 2 = Red Intensity (0-255)
+ Byte 3 = Green Intensity (0-255)
+ Byte 4 = Blue Intensity (0-255)
+
+ - 'M' - control the velocity of the motors
+ Byte 2 = Left Wheel Direction (0:forward, 1:reverse)
+ Byte 3 = Left Wheel Speed (0-255)
+ Byte 4 = Right Wheel Direction (0:forward, 1:reverse)
+ Byte 5 = Right Wheel Speed (0-255)
+ *All zeroes will immediately turn the motors off
+
+ - 'B' - sets the buzzer to chirp for a period of time
+ Byte 2 = Duration in msec (MSB)
+ Byte 3 = Duration in msec (LSB)
+ Byte 4 = Frequency in Hz (MSB)
+ Byte 5 = Frequency in Hz (LSB)
+ *All zeroes will immediately turn the buzzer off
+
+ - 'T' - gets the temperature
+ returns
+ Byte 0 = Temperature Value (0-255)
+ Celsius = (value-127) / 2.4 + 25.0
+
+ - 'L' - gets the values from the two light sensors
+ returns
+ Byte 0 = Left Light Sensor (0-255)
+ Byte 1 = Right Light Sensor (0-255)
+
+ - 'A' - gets the accelerometer values of the X, Y, Z axis, and the tap/shake byte.
+ returns
+ Byte 0 = 153 (decimal)
+ Byte 1 = X-axis (0-63)
+ Byte 2 = Y-axis (0-63)
+ Byte 3 = Z-axis (0-63)
+ if value is 0x00 to 0x1f (positive)
+ g-force = value * 1.5/32.0
+ if value is 0x20 to 0x3f (negative)
+ g-force = (value-64) * 1.5/32.0
+ Byte 4 = Tap/Shaken flag (0-255)
+ If bit 7 (0x80) is a 1, then the Finch has been shaken since the last read
+ If bit 5 (0x20) is a 0, then the Finch has been tapped since the last read
+
+ - 'I' - gets the values of the two obstacle sensors
+ returns
+ Byte 0 = Left Sensor (0:none or 1:obstacle present)
+ Byte 1 = Right Sensor (0:none or 1:obstacle present)
+
+ - 'X' - set all motors and LEDs to off
+
+ - 'R' - turns off the motor and
+ has the Finch go back into color-cycling mode
+
+ - 'z' - send a counter value showing the number of times command-z has been sent
+ used for "keep-alive" or communication tests only
+ returns
+ Byte 0 = Counter (0-255)
+
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "Finch.h"
+
+#ifdef _LINUX_
+#include <pthread.h>
+#include <unistd.h>
+#else
+#include <windows.h>
+#endif
+
+#include "hidapi.h"
+
+/* to be used with Fin_Cmnd */
+#define SEND 0 // command does not have a response
+#define SEND_RECV 1 // response is expected
+
+/* Global Variables */
+static hid_device *finch_handle[8]; // The handle to communicate with the Finch magic numbers because i'm too lazy to realloc
+static int cmnd_count = 0; // number of commands that have been sent
+static int left_speed = 0;
+static int right_speed = 0;
+static int time_to_stop = 0;
+struct hid_device_info * temphidptr; //pointer for the information enum returns
+int finchnum = 0; // counter for getting all finches
+int cfinchnum = 0; // number for controling which finch
+/* local prototypes */
+#ifdef _LINUX_
+void *Fin_Thread(void *arg);
+void *KeyThread(void *arg);
+#else
+void Fin_Thread(void *arg);
+#endif
+int Fin_Cmnd(int flag, char cmnd, unsigned char *buffer);
+
+/** Fin_init(void).
+ * initializes the interface to the finch robot
+ * launches a background thread to prevent the finch from timing out
+ * *Must be called prior to all other finch functions
+ *
+ * input:
+ * none
+ * returns:
+ * -1 if failure
+ */
+int Fin_Init(void)
+{
+#ifdef _LINUX_
+ pthread_t tid;
+#else
+ HANDLE thread_res;
+ DWORD tid;
+#endif
+ //gets all finches
+ temphidptr = hid_enumerate(0x2354,0x1111);
+
+ //wprintf(L"serial %s\n",(*temphidptr).manufacturer_string);
+ printf("vid %i pointer %p\n",(*temphidptr).vendor_id,temphidptr);
+ int res;
+
+ // open a connection to the finch
+ // the Finch communicates using the USB HID protocol
+ // with a VID of 2354 (Hex) and a PID of 1111 (Hex)
+ //takes the result of enumerate and gets device objects for them
+ while (temphidptr != NULL) {
+ finch_handle[finchnum] = hid_open(0x2354, 0x1111, (*temphidptr).serial_number);
+ temphidptr = (*temphidptr).next;
+ finchnum = finchnum + 1;
+ }
+ if (finch_handle == 0)
+ {
+ // failure...
+ printf("Unable to connect to the Finch\n");
+ res = -1;
+ }
+ else
+ {
+ // success... turn off the beak led
+ Fin_LED(0,0,0);
+
+ // create a keep-alive thread
+#ifdef _LINUX_
+ /* create independent thread to monitor the console */
+ pthread_create( &tid, NULL, KeyThread, (void *)0 );
+
+ pthread_create( &tid, NULL, Fin_Thread, (void *)0 );
+#else
+ thread_res = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Fin_Thread,(LPVOID)0,0,(LPDWORD)&tid);
+#endif
+ res = 0;
+ }
+
+ return(res);
+}
+
+
+/** Fin_Exit(void).
+ * go back to idle mode
+ * close the connection
+ *
+ * input:
+ * none
+ * returns:
+ * -1 if failure
+ */
+int Fin_Exit(void)
+{
+ unsigned char IoBuffer[9];
+ int res;
+
+ // reset the Finch to idle mode
+ res = Fin_Cmnd(SEND,'R',IoBuffer);
+ hid_close(finch_handle[cfinchnum]);
+ return(res);
+}
+
+
+/*
+ * background (keep-alive) thread
+ */
+#ifdef _LINUX_
+void *Fin_Thread(void *arg)
+#else
+void Fin_Thread(void *arg)
+#endif
+{
+ unsigned char IoBuffer[9];
+ int res;
+ int save;
+ int count = 0;
+
+ // The Finch has a time-out where it will go back to passive color cycling mode
+ // if no commands are sent within a five second time frame.
+ while(1)
+ {
+ // cmnd_count gets incremented each time something is sent to the finch
+ save = cmnd_count;
+
+ // pause for 1/10 second
+ Sleep(100);
+ if (finch_handle[cfinchnum] == 0)
+ break;
+
+ if (time_to_stop > 0)
+ {
+ // motors running, see if we should stop
+ if (--time_to_stop <= 0)
+ {
+ Fin_Motor(0,0,0);
+ count = 0;
+ continue;
+ }
+ }
+
+ // see if any commands went out over the last second
+ if (save != cmnd_count)
+ {
+ count = 0;
+ continue;
+ }
+
+ // wait for 2 seconds of no commands before sending keep-alive
+ if (++count < 20)
+ continue;
+
+ // request the command count (for keep-alive)
+ res = Fin_Cmnd(SEND_RECV,'z',IoBuffer);
+ count = 0;
+ }
+}
+
+
+/*
+ * send/recv messages to the finch
+ */
+int Fin_Cmnd(int flag, char cmnd, unsigned char *buffer)
+{
+ static unsigned char seq_num = 0;
+ int res = 0;
+
+ // the background thread uses this flag
+ cmnd_count++;
+
+ // all finch commands have a leading 0
+ // followed by an ascii command character
+ // and for commands with a response, insert a sequence number
+ buffer[0] = 0x00;
+ buffer[1] = cmnd;
+ if (flag == SEND_RECV)
+ buffer[8] = ++seq_num;
+
+ while(res == 0)
+ {
+ res = hid_write(finch_handle[cfinchnum], buffer, 9);
+ }
+
+ while (res > 0 && flag == SEND_RECV)
+ {
+ // read back from the finch
+ res = hid_read(finch_handle[cfinchnum], buffer, 9);
+ // make sure the sequence number matches what was sent
+ if (cmnd == 'z' || buffer[7] == seq_num)
+ break;
+ }
+
+ return(res);
+}
+
+
+/** Fin_Motor(tenth, left, right).
+ * set the speed (and duration) of the wheels
+ *
+ * input:
+ * int tenth = motor on time (in tenths of a second)
+ * int left/right = speed of each wheel
+ * must be between +255 and -255
+ * positive values are forward, negative is reverse
+ * use 0,0 to stop
+ * use -1 for time if you want to sets the wheels to a certain speed without turning them off at
+ * a predetermined time (example: Fin_Motor(-1, 200, -200))
+ * returns
+ * -1 if failure
+ */
+int Fin_Motor(int tenth, int left, int right)
+{
+ unsigned char IoBuffer[9];
+ char leftDir = 0;
+ char rightDir = 0;
+ int res;
+
+ // save the motor speed in global variables
+ time_to_stop = 0;
+ left_speed = left;
+ right_speed = right;
+
+ // check for motor stop
+ if (left == 0 && right == 0)
+ tenth = 0;
+
+
+ // If the numbers are negative, set the direction bit to 1,
+ // and make the negative speed positive
+ if (left < 0)
+ {
+ left = -left;
+ leftDir = 1;
+ }
+ if (right < 0)
+ {
+ right = -right;
+ rightDir = 1;
+ }
+
+ // set the direction and speed for each motor
+ IoBuffer[2] = leftDir;
+ IoBuffer[3] = (char)left;
+ IoBuffer[4] = rightDir;
+ IoBuffer[5] = (char)right;
+
+ res = Fin_Cmnd(SEND,'M',IoBuffer);
+ if (res > 0 && tenth > 0)
+ {
+ // have the background thread stop the motors
+ time_to_stop = tenth;
+ }
+
+ return(res);
+}
+
+
+/** Fin_Move(tenth, left, right).
+ * set the speed (and duration) of the wheels, and block the program
+ * from further execution until time is up
+ *
+ * input:
+ * int tenth = motor on time (in tenths of a second), and block time
+ * int left/right = speed of each wheel
+ * must be between +255 and -255
+ * positive values are forward, negative is reverse
+ * returns
+ * -1 if failure
+ */
+int Fin_Move( int tenth, int left, int right )
+{
+ int toReturn = Fin_Motor( tenth, left, right );
+ while (1 && toReturn != -1)
+ {
+ Fin_Speed( &left, &right );
+ if (left == 0 && right == 0)
+ break;
+ }
+ return toReturn;
+}
+
+/** Fin_Speed(*left, *right).
+ * get the current speed of the wheels
+ *
+ * input:
+ * int *left/*right = pointer where to return the speed of each wheel
+ * returns
+ * -1 if failure
+ */
+int Fin_Speed(int *left, int *right)
+{
+ *left = left_speed;
+ *right = right_speed;
+ return(1);
+}
+
+
+/** Fin_LED(red, green, blue).
+ * set the color and intensity of the beak LED
+ *
+ * input:
+ * int red/green/blue = intensity of each color
+ * must be between +255 and 0 (0=off)
+ * returns
+ * -1 if failure
+ */
+int Fin_LED(int red, int green, int blue)
+{
+ unsigned char IoBuffer[9];
+ int res;
+
+ // set the intensity of each led
+ // use 0,0,0 for led off
+ IoBuffer[2] = (char)red;
+ IoBuffer[3] = (char)green;
+ IoBuffer[4] = (char)blue;
+
+ res = Fin_Cmnd(SEND,'O',IoBuffer);
+ return(res);
+}
+
+
+/** Fin_Buzzer(msec, freq).
+ * turn on the buzzer
+ *
+ * input:
+ * int msec = duration in msecs
+ * int freq = frequency in hz
+ * use 0,0 to turn the buzzer off
+ * returns
+ * -1 if failure
+ */
+int Fin_Buzzer(int msec,int freq)
+{
+ unsigned char IoBuffer[9];
+ int res;
+
+ // set the duration and frequencies
+ // use 0,0 for buzzer off
+ IoBuffer[2] = (char)(msec >> 8);
+ IoBuffer[3] = (char)(msec);
+ IoBuffer[4] = (char)(freq >> 8);
+ IoBuffer[5] = (char)(freq);
+
+ res = Fin_Cmnd(SEND,'B',IoBuffer);
+ return(res);
+}
+
+
+/** Fin_Lights(*left, *right).
+ * get light sensor data
+ *
+ * input:
+ * int *left/*right = pointer where to return the light sensor data
+ * returned values range 255 to 0 (0=dark)
+ * returns
+ * -1 if failure
+ */
+int Fin_Lights(int *left, int *right)
+{
+ unsigned char IoBuffer[9];
+ int res;
+
+ *left = 0;
+ *right = 0;
+
+ // request left/right sensors
+ res = Fin_Cmnd(SEND_RECV,'L',IoBuffer);
+
+ if (res > 0)
+ {
+ *left = (int)IoBuffer[0];
+ *right = (int)IoBuffer[1];
+ }
+ return(res);
+}
+
+
+/** Fin_Obstacle(*left, *right).
+ * get obstacle sensor data
+ *
+ * input:
+ * int *left/*right = pointer where to return the obstacle flags
+ * returned value is 1 or 0 (0=no obstacle)
+ * returns
+ * -1 if failure
+ */
+int Fin_Obstacle(int *left, int *right)
+{
+ unsigned char IoBuffer[9];
+ int res;
+
+ *left = 0;
+ *right = 0;
+
+ // get left/right obstacle sensors
+ res = Fin_Cmnd(SEND_RECV,'I',IoBuffer);
+
+ if (res > 0)
+ {
+ *left = (int)IoBuffer[0];
+ *right = (int)IoBuffer[1];
+ }
+ return(res);
+}
+
+
+/** Fin_Temp(*temp).
+ * get temperature sensor data
+ *
+ * input:
+ * float *temp = pointer where to return the temperature
+ * returned value is in celsius (in 1/1000 units)
+ * returns
+ * -1 if failure
+ */
+int Fin_Temp(float *temp)
+{
+ unsigned char IoBuffer[9];
+ int res;
+
+ *temp = 0.0;
+
+ // request temperature data
+ res = Fin_Cmnd(SEND_RECV,'T',IoBuffer);
+
+ if (res > 0)
+ {
+ // convert the data to celsius
+ *temp = (float)(IoBuffer[0] - 127) / 2.4 + 25;
+ }
+ return(res);
+}
+
+
+/** Fin_Accel(*x, *y, *z, *tap, *shake).
+ * get acceleration values and tap/shaken flags
+ *
+ * input:
+ * float *x/*y/*z = pointer where to return the acceleration for each axis
+ * returned value is in 'g' (in 1/1000 units) can be positive or negative
+ * int *tap/*shake = pointer where to return the tap/shaken flags
+ * returned value is 1 or 0 (0=not tap, not shaken)
+ * returns
+ * -1 if failure
+ */
+int Fin_Accel(float *x, float *y, float *z, int *tap, int *shake)
+{
+ float table[3] = {0.0, 0.0, 0.0};
+ unsigned char IoBuffer[9];
+ int res,ofst,data;
+
+ *tap = 0;
+ *shake = 0;
+
+ // request sensor information
+ res = Fin_Cmnd(SEND_RECV,'A',IoBuffer);
+
+ if (res > 0)
+ {
+ // Convert the raw accelerometer data to G-forces
+ for (ofst=0; ofst<3; ofst++)
+ {
+ data = (int)IoBuffer[ofst+1];
+ if (data > 31)
+ data -= 64;
+
+ table[ofst] = (float)data * 1.5 / 32.0;
+ }
+ *x = table[0];
+ *y = table[1];
+ *z = table[2];
+
+ // check the tap/shake sensors
+ *tap = IoBuffer[4] & 0x20 ? 1 : 0 ;
+ *shake = IoBuffer[4] & 0x80 ? 1 : 0 ;
+ }
+
+ return(res);
+}
+
+static char _inpbuf[80];
+
+#ifdef _LINUX_
+static int _key = 0;
+
+/* secondary thread to block waiting for a keypress */
+void *KeyThread(void *arg)
+{
+ while (1)
+ {
+ usleep(1000);
+ gets(_inpbuf);
+ _key = 1;
+ }
+}
+
+int kbhit(void)
+{
+ fflush(stdout);
+ return(_key);
+}
+#endif
+
+/* CheckForKey(void)
+ * check for a keypress: combination of kbhit and getch
+ *
+ * input:
+ * none
+ * return:
+ * 0 = no keyboard entry
+ * else, Ascii character from the keyboard
+ */
+char *CheckForInput(void)
+{
+ /* see if a key has been pressed */
+ if (kbhit() == 0)
+ return(0);
+
+#ifdef _LINUX_
+ _key = 0;
+#else
+ gets(_inpbuf);
+#endif
+ return(_inpbuf);
+}
+// gets max number of finches connected
+int maxfinchnum() {
+ return (finchnum-1);
+}
+// switches current finch, 0-8 , returns 0 on failure
+int switchfinch(num) {
+ if (num <= (finchnum-1)) {
+ cfinchnum = num;
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
diff --git a/License.txt b/License.txt
new file mode 100644
index 0000000..14da792
--- /dev/null
+++ b/License.txt
@@ -0,0 +1,5 @@
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..adbc4c9
--- /dev/null
+++ b/README.md
@@ -0,0 +1,4 @@
+Two new funchtions finchmaxnum() and finchswitch have been added to find the maximum number of finches and switch finches.
+the makefile compiles main.c in arch linux with the hidapi package installed, it is NOT called hidapi32 as the website suggests but hidapi-libusb
+the main program has been modified so that pressing C will allow you to switch the finchbot with finchswitch()
+a compiled version of main for i686 archetecture for arch linux, you need root permisions to run
diff --git a/hidapi.h b/hidapi.h
new file mode 100644
index 0000000..4acc27e
--- /dev/null
+++ b/hidapi.h
@@ -0,0 +1,332 @@
+/*******************************************************
+ HIDAPI - Multi-Platform library for
+ communication with HID devices.
+
+ Alan Ott
+ Signal 11 Software
+
+ 8/22/2009
+
+ Copyright 2009, All Rights Reserved.
+
+ At the discretion of the user of this library,
+ this software may be licensed under the terms of the
+ GNU Public License v3, a BSD-Style license, or the
+ original HIDAPI license as outlined in the LICENSE.txt,
+ LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
+ files located at the root of the source distribution.
+ These files may also be found in the public source
+ code repository located at:
+ http://github.com/signal11/hidapi .
+********************************************************/
+
+/** @file
+ * @defgroup API hidapi API
+ */
+
+#ifndef HIDAPI_H__
+#define HIDAPI_H__
+
+#include <wchar.h>
+
+#ifdef _WIN32
+ #define HID_API_EXPORT __declspec(dllexport)
+ #define HID_API_CALL
+#else
+ #define HID_API_EXPORT /**< API export macro */
+ #define HID_API_CALL /**< API call macro */
+#endif
+
+#define HID_API_EXPORT_CALL HID_API_EXPORT HID_API_CALL /**< API export and call macro*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ struct hid_device_;
+ typedef struct hid_device_ hid_device; /**< opaque hidapi structure */
+
+ /** hidapi info structure */
+ struct hid_device_info {
+ /** Platform-specific device path */
+ char *path;
+ /** Device Vendor ID */
+ unsigned short vendor_id;
+ /** Device Product ID */
+ unsigned short product_id;
+ /** Serial Number */
+ wchar_t *serial_number;
+ /** Device Release Number in binary-coded decimal,
+ also known as Device Version Number */
+ unsigned short release_number;
+ /** Manufacturer String */
+ wchar_t *manufacturer_string;
+ /** Product string */
+ wchar_t *product_string;
+ /** Usage Page for this Device/Interface
+ (Windows/Mac only). */
+ unsigned short usage_page;
+ /** Usage for this Device/Interface
+ (Windows/Mac only).*/
+ unsigned short usage;
+ /** The USB interface which this logical device
+ represents (Linux/libusb implementation only). */
+ int interface_number;
+
+ /** Pointer to the next device */
+ struct hid_device_info *next;
+ };
+
+
+ /** @brief Enumerate the HID Devices.
+
+ This function returns a linked list of all the HID devices
+ attached to the system which match vendor_id and product_id.
+ If @p vendor_id and @p product_id are both set to 0, then
+ all HID devices will be returned.
+
+ @ingroup API
+ @param vendor_id The Vendor ID (VID) of the types of device
+ to open.
+ @param product_id The Product ID (PID) of the types of
+ device to open.
+
+ @returns
+ This function returns a pointer to a linked list of type
+ struct #hid_device, containing information about the HID devices
+ attached to the system, or NULL in the case of failure. Free
+ this linked list by calling hid_free_enumeration().
+ */
+ struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id);
+
+ /** @brief Free an enumeration Linked List
+
+ This function frees a linked list created by hid_enumerate().
+
+ @ingroup API
+ @param devs Pointer to a list of struct_device returned from
+ hid_enumerate().
+ */
+ void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs);
+
+ /** @brief Open a HID device using a Vendor ID (VID), Product ID
+ (PID) and optionally a serial number.
+
+ If @p serial_number is NULL, the first device with the
+ specified VID and PID is opened.
+
+ @ingroup API
+ @param vendor_id The Vendor ID (VID) of the device to open.
+ @param product_id The Product ID (PID) of the device to open.
+ @param serial_number The Serial Number of the device to open
+ (Optionally NULL).
+
+ @returns
+ This function returns a pointer to a #hid_device object on
+ success or NULL on failure.
+ */
+ HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, wchar_t *serial_number);
+
+ /** @brief Open a HID device by its path name.
+
+ The path name be determined by calling hid_enumerate(), or a
+ platform-specific path name can be used (eg: /dev/hidraw0 on
+ Linux).
+
+ @ingroup API
+ @param path The path name of the device to open
+
+ @returns
+ This function returns a pointer to a #hid_device object on
+ success or NULL on failure.
+ */
+ HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path);
+
+ /** @brief Write an Output report to a HID device.
+
+ The first byte of @p data[] must contain the Report ID. For
+ devices which only support a single report, this must be set
+ to 0x0. The remaining bytes contain the report data. Since
+ the Report ID is mandatory, calls to hid_write() will always
+ contain one more byte than the report contains. For example,
+ if a hid report is 16 bytes long, 17 bytes must be passed to
+ hid_write(), the Report ID (or 0x0, for devices with a
+ single report), followed by the report data (16 bytes). In
+ this example, the length passed in would be 17.
+
+ hid_write() will send the data on the first OUT endpoint, if
+ one exists. If it does not, it will send the data through
+ the Control Endpoint (Endpoint 0).
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param data The data to send, including the report number as
+ the first byte.
+ @param length The length in bytes of the data to send.
+
+ @returns
+ This function returns the actual number of bytes written and
+ -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_write(hid_device *device, const unsigned char *data, size_t length);
+
+ /** @brief Read an Input report from a HID device.
+
+ Input reports are returned
+ to the host through the INTERRUPT IN endpoint. The first byte will
+ contain the Report number if the device uses numbered reports.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param data A buffer to put the read data into.
+ @param length The number of bytes to read. For devices with
+ multiple reports, make sure to read an extra byte for
+ the report number.
+
+ @returns
+ This function returns the actual number of bytes read and
+ -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_read(hid_device *device, unsigned char *data, size_t length);
+
+ /** @brief Set the device handle to be non-blocking.
+
+ In non-blocking mode calls to hid_read() will return
+ immediately with a value of 0 if there is no data to be
+ read. In blocking mode, hid_read() will wait (block) until
+ there is data to read before returning.
+
+ Nonblocking can be turned on and off at any time.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param nonblock enable or not the nonblocking reads
+ - 1 to enable nonblocking
+ - 0 to disable nonblocking.
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *device, int nonblock);
+
+ /** @brief Send a Feature report to the device.
+
+ Feature reports are sent over the Control endpoint as a
+ Set_Report transfer. The first byte of @p data[] must
+ contain the Report ID. For devices which only support a
+ single report, this must be set to 0x0. The remaining bytes
+ contain the report data. Since the Report ID is mandatory,
+ calls to hid_send_feature_report() will always contain one
+ more byte than the report contains. For example, if a hid
+ report is 16 bytes long, 17 bytes must be passed to
+ hid_send_feature_report(): the Report ID (or 0x0, for
+ devices which do not use numbered reports), followed by the
+ report data (16 bytes). In this example, the length passed
+ in would be 17.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param data The data to send, including the report number as
+ the first byte.
+ @param length The length in bytes of the data to send, including
+ the report number.
+
+ @returns
+ This function returns the actual number of bytes written and
+ -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *device, const unsigned char *data, size_t length);
+
+ /** @brief Get a feature report from a HID device.
+
+ Make sure to set the first byte of @p data[] to the Report
+ ID of the report to be read. Make sure to allow space for
+ this extra byte in @p data[].
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param data A buffer to put the read data into, including
+ the Report ID. Set the first byte of @p data[] to the
+ Report ID of the report to be read.
+ @param length The number of bytes to read, including an
+ extra byte for the report ID. The buffer can be longer
+ than the actual report.
+
+ @returns
+ This function returns the number of bytes read and
+ -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *device, unsigned char *data, size_t length);
+
+ /** @brief Close a HID device.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ */
+ void HID_API_EXPORT HID_API_CALL hid_close(hid_device *device);
+
+ /** @brief Get The Manufacturer String from a HID device.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param string A wide string buffer to put the data into.
+ @param maxlen The length of the buffer in multiples of wchar_t.
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *device, wchar_t *string, size_t maxlen);
+
+ /** @brief Get The Product String from a HID device.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param string A wide string buffer to put the data into.
+ @param maxlen The length of the buffer in multiples of wchar_t.
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT_CALL hid_get_product_string(hid_device *device, wchar_t *string, size_t maxlen);
+
+ /** @brief Get The Serial Number String from a HID device.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param string A wide string buffer to put the data into.
+ @param maxlen The length of the buffer in multiples of wchar_t.
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *device, wchar_t *string, size_t maxlen);
+
+ /** @brief Get a string from a HID device, based on its string index.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param string_index The index of the string to get.
+ @param string A wide string buffer to put the data into.
+ @param maxlen The length of the buffer in multiples of wchar_t.
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *device, int string_index, wchar_t *string, size_t maxlen);
+
+ /** @brief Get a string describing the last error which occurred.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+
+ @returns
+ This function returns a string containing the last error
+ which occurred or NULL if none has occurred.
+ */
+ HID_API_EXPORT const wchar_t* HID_API_CALL hid_error(hid_device *device);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/main b/main
new file mode 100755
index 0000000..425f601
--- /dev/null
+++ b/main
Binary files differ
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..dde57e5
--- /dev/null
+++ b/main.c
@@ -0,0 +1,436 @@
+#if 0
+Finch Robot Control (finch.exe)
+
+Notes:
+- finch.exe was compiled for a 32-bit windows O/S
+- make sure that the hidapi.dll is in the current working directory
+- plug in the finch-usb cable before starting the program
+
+#endif
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "Finch.h"
+
+#ifdef _LINUX_
+#include <pthread.h>
+#else
+#include <conio.h>
+#include <windows.h>
+#endif
+
+// use this to output the statistics to a disk file
+#define DISKFILE
+
+// represents 5.0 seconds of history data
+#define ENTRIES 50
+
+struct hist {
+ int left;
+ int right;
+ float x;
+ float y;
+ float z;
+};
+
+// place to store last 5.0 seconds of sensor information
+struct hist snapshot[ENTRIES] = {0};
+int snapofst = 0;
+int history = 0;
+
+// local prototypes
+void Help(void);
+void Command(char option);
+char *CheckForInput(void);
+char *GetInput(void);
+void Pause(int msec);
+void Report(void);
+char *AccelText(float x, float y, float z);
+char *PosText(float x, float y, float z);
+
+
+/*
+ * main entrypoint
+ */
+int main(int argc, char* argv[])
+{
+ char *option;
+
+ // attempt to connect to the finch hardware
+ // ...finch must be already plugged into a usb port
+ if (Fin_Init() < 0)
+ exit(1);
+
+ Help();
+
+ while (1)
+ {
+ // throw away any outstanding keyboard characters
+ CheckForInput();
+
+ // wait for a new command
+ // ...accepts a single keypress
+ printf("\nSelect Command (and press ENTER): ");
+ option = GetInput();
+
+ if (*option == 'Q' || *option == 'q')
+ break;
+
+ // perform the command
+ Command(*option);
+ }
+
+ // disconnect before exiting the program
+ Fin_Exit();
+ return(0);
+}
+
+
+/*
+ * display help information
+ */
+void Help(void)
+{
+ // all commands are single letters + <enter>
+ printf("\nMovement:\n");
+ printf(" F - Forward (F:fast, f:slow)\n");
+ printf(" B - Backward (B:fast, b:slow)\n");
+ printf(" L - Left (L:tight turn, l:wide turn)\n");
+ printf(" R - Right (R:tight turn, r:wide turn)\n");
+
+ printf("\nControls:\n");
+ printf(" Y - Led (Y:on/off, y:solid)\n");
+ printf(" Z - Buzzer (Z:on/off, z:continuous)\n");
+
+ printf("\nSensors (upper case is continuous read):\n");
+ printf(" A - Accelerometer\n");
+ printf(" O - Obstacle\n");
+ printf(" S - Light Sensor\n");
+ printf(" T - Temperature\n");
+#ifdef DISKFILE
+ printf(" H - History Report File (H:collect, h:display)\n");
+#else
+ printf(" H - History Report (H:collect, h:display)\n");
+#endif
+
+ printf("\n");
+ printf(" ?- Help\n");
+ printf(" Q- Quit\n");
+}
+
+
+/*
+ * perform the finch command
+ */
+void Command(char option)
+{
+ float fd1,fd2,fd3;
+ int d1,d2,d3;
+ char *textp;
+
+ switch (option)
+ {
+ case '?':
+ // display the help message
+ Help();
+ break;
+
+ // motor on/off (F-fwd, B-back, L-left, R-right)
+ case 'F':
+ Fin_Motor(8,200,200);
+ break;
+ case 'f':
+ Fin_Motor(21,90,90);
+ break;
+
+ case 'B':
+ Fin_Motor(8,-200,-200);
+ break;
+ case 'b':
+ Fin_Motor(21,-90,-90);
+ break;
+
+ case 'L':
+ Fin_Motor(5,-140,140);
+ break;
+ case 'l':
+ Fin_Motor(11,80,200);
+ break;
+
+ case 'R':
+ Fin_Motor(5,140,-140);
+ break;
+ case 'r':
+ Fin_Motor(11,200,80);
+ break;
+
+ // acceleration sensors
+ case 'A':
+ do
+ {
+ Fin_Accel(&fd1,&fd2,&fd3,&d1,&d2);
+ printf("%s %s Tap:%d Shake:%d \r", PosText(fd1,fd2,fd3), AccelText(fd1, fd2, fd3), d1,d2);
+ Sleep(300);
+ } while (!kbhit());
+ printf("\n");
+ break;
+ case 'a':
+ Fin_Accel(&fd1,&fd2,&fd3,&d1,&d2);
+ printf("%s %s Tap:%d Shake:%d\n", PosText(fd1,fd2,fd3), AccelText(fd1, fd2, fd3), d1,d2);
+ break;
+
+ // obstacle sensors
+ case 'O':
+ do
+ {
+ Fin_Obstacle(&d1,&d2);
+ printf("Obstacle -- Left:%d Right:%d \r", d1,d2);
+ Sleep(300);
+ } while (!kbhit());
+ printf("\n");
+ break;
+ case 'o':
+ Fin_Obstacle(&d1,&d2);
+ printf("Obstacle -- Left:%d Right:%d\n", d1,d2);
+ break;
+
+ // light sensors
+ case 'S':
+ do
+ {
+ Fin_Lights(&d1,&d2);
+ printf("Lights -- Left:%3d Right:%3d \r", d1,d2);
+ Sleep(300);
+ } while (!kbhit());
+ printf("\n");
+ break;
+ case 's':
+ Fin_Lights(&d1,&d2);
+ printf("Lights -- Left:%3d Right:%3d\n", d1,d2);
+ break;
+
+ // temperature sensors
+ case 'T':
+ do
+ {
+ Fin_Temp(&fd1);
+ printf("%3.4f Celsius \r", fd1);
+ Sleep(1000);
+ } while (!kbhit());
+ printf("\n");
+ break;
+ case 't':
+ Fin_Temp(&fd1);
+ printf("%3.4f Celsius\n", fd1);
+ break;
+
+ // led colors (blink or continuous)
+ case 'Y':
+ case 'y':
+ printf("Enter the three color values: red,green,blue (0-255): ");
+ textp = GetInput();
+ sscanf(textp,"%d,%d,%d",&d1,&d2,&d3);
+ do
+ {
+ Fin_LED(d1,d2,d3);
+ if (option == 'y')
+ break;
+ Sleep(250);
+ Fin_LED(0,0,0);
+ Sleep(250);
+ } while (!kbhit());
+ break;
+ case 'C':
+ d2 = maxfinchnum();
+ printf("Enter the number of the finch you want to control 0-%d\n",d2);
+ textp = GetInput();
+ sscanf(textp,"%d",&d1);
+ if (switchfinch(d1) == 0) {
+ printf("error not in range\n");
+ }
+ break;
+ // buzzer (blink or continuous)
+ case 'Z':
+ case 'z':
+ printf("Enter the buzzer frequency: ");
+ textp = GetInput();
+ sscanf(textp,"%d",&d1);
+ do
+ {
+ Fin_Buzzer(0xffff,d1);
+ if (option == 'z')
+ break;
+ Sleep(250);
+ Fin_Buzzer(0,0);
+ Sleep(250);
+ } while (!kbhit());
+ break;
+
+ // motor and acceleration history
+ case 'H':
+ history = 1;
+ printf("Reporting on\n");
+ break;
+ case 'h':
+ history = 0;
+ Report();
+ break;
+ }
+}
+
+
+/*
+ * check for a keypress
+ */
+char *GetInput(void)
+{
+ // check for incoming command
+ // collect history if enabled
+ while (!kbhit())
+ Pause(100);
+
+ return(CheckForInput());
+}
+
+
+/*
+ * pause and do the background history collection
+ */
+void Pause(int msec)
+{
+ float fd1,fd2,fd3;
+ int d1,d2;
+
+ while (msec > 0)
+ {
+ Sleep(100);
+ msec -= 100;
+
+ if (history == 0)
+ continue;
+
+ // collect acceleration data
+ Fin_Accel(&fd1,&fd2,&fd3,&d1,&d2);
+ if (++snapofst >= ENTRIES)
+ snapofst = 0;
+
+ // save history of what was detected
+ Fin_Speed(&snapshot[snapofst].left,&snapshot[snapofst].right);
+ snapshot[snapofst].x = fd1;
+ snapshot[snapofst].y = fd2;
+ snapshot[snapofst].z = fd3;
+ }
+}
+
+
+/*
+ * display the history report
+ */
+void Report(void)
+{
+ int indx,max;
+#ifdef DISKFILE
+ FILE *disk;
+
+ disk = fopen("Finch.Txt", "w+");
+ if (disk == NULL)
+ return;
+#endif
+
+ // display a report of what happened in the last ENTRIES x 1/10 seconds
+ indx = snapofst;
+ for (max=1; max<=ENTRIES; max++)
+ {
+ if (++indx >= ENTRIES)
+ indx = 0;
+
+#ifdef DISKFILE
+ fprintf(disk,"Time:%3d.%d Left:%4d Right:%4d %s\n",
+ max/10, max%10, snapshot[indx].left, snapshot[indx].right,
+ AccelText(snapshot[indx].x, snapshot[indx].y, snapshot[indx].z));
+#else
+ printf("Time:%3d.%d Left:%4d Right:%4d %s\n",
+ max/10, max%10, snapshot[indx].left, snapshot[indx].right,
+ AccelText(snapshot[indx].x, snapshot[indx].y, snapshot[indx].z));
+#endif
+ }
+
+#ifdef DISKFILE
+ fclose(disk);
+ system("type Finch.txt");
+#endif
+
+}
+
+
+struct posfmt {
+ float min_x;
+ float max_x;
+ float min_y;
+ float max_y;
+ float min_z;
+ float max_z;
+ char *desc;
+};
+
+/* determine if the x,y,z acceleration values are within range */
+int PosTest(struct posfmt *pf, float x, float y, float z)
+{
+ if (x <= pf->min_x)
+ return(0);
+ if (x >= pf->max_x)
+ return(0);
+
+ if (y <= pf->min_y)
+ return(0);
+ if (y >= pf->max_y)
+ return(0);
+
+ if (z <= pf->min_z)
+ return(0);
+ if (z >= pf->max_z)
+ return(0);
+
+ return(1);
+}
+
+char *PosText(float x, float y, float z)
+{
+ static struct posfmt PosTbl[9] = {
+ { -1.5, -0.8, -0.3, 0.3, -0.3, 0.3, "Beak-Up " },
+ { 0.8, 1.5, -0.3, 0.3, -0.3, 0.3, "Beak-Dn " },
+ { 0.2, 0.5, -0.3, 0.3, 0.9, 1.2, "Dn-Hill " },
+ { -0.5, -0.2, -0.3, 0.3, 0.9, 1.2, "Up-Hill " },
+ { -0.5, 0.5, -0.5, 0.5, 0.65, 1.2, "Level " },
+ { -0.5, 0.5, -0.5, 0.5, -1.5, -0.65,"Dn/Up " },
+ { -0.5, 0.5, 0.7, 1.5, -0.5, 0.5, "LftWing-Dn" },
+ { -0.5, 0.5, -1.5,-0.7, -0.5, 0.5, "RgtWing-Dn" },
+ { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, " " }
+ };
+ char *textp;
+ int ofst;
+
+ /* convert an x,y,z acceleration to a description */
+ textp = PosTbl[8].desc;
+ for (ofst=0; ofst<8; ofst++)
+ {
+ if (PosTest(&PosTbl[ofst], x, y, z))
+ {
+ textp = PosTbl[ofst].desc;
+ break;
+ }
+ }
+
+ return(textp);
+}
+
+char *AccelText(float x, float y, float z)
+{
+ static char text[80];
+
+ /* display the x,y,z acceleration values */
+ sprintf(text,"X:%2.5f Y:%2.5f Z:%2.5f",x,y,z);
+ return(text);
+}
diff --git a/makefile b/makefile
new file mode 100644
index 0000000..1a3e631
--- /dev/null
+++ b/makefile
@@ -0,0 +1,2 @@
+main:
+ gcc -pthread -o main main.c Finch.c -lhidapi-libusb