ThinkGear API Mac OS X example

/**
 * This program serves as a simple example of how one can use ThinkGear.bundle inside their Core Foundation
 * (e.g. Cocoa and Carbon-based) apps. For more details on OS X bundles, read:
 * http://developer.apple.com/DOCUMENTATION/CoreFoundation/Conceptual/CFBundles/CFBundles.html
 * 
 * Or check the "How to use the ThinkGear API in Xcode (Mac OS X)" document in the ThinkGear documentation.
 *
 * Note: When executing the program, make sure ThinkGear.bundle is in the same current directory.
 */
 
#include <CoreFoundation/CoreFoundation.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
 
/**
 * Baud rate for use with TG_Connect() and TG_SetBaudrate().
 */
#define TG_BAUD_1200         1200
#define TG_BAUD_2400         2400
#define TG_BAUD_4800         4800
#define TG_BAUD_9600         9600
#define TG_BAUD_57600       57600
#define TG_BAUD_115200     115200
 
/**
 * Data format for use with TG_Connect() and TG_SetDataFormat().
 */
#define TG_STREAM_PACKETS      0
#define TG_STREAM_5VRAW        1
#define TG_STREAM_FILE_PACKETS 2
 
/**
 * Data type that can be requested from TG_GetValue().
 */
#define TG_DATA_BATTERY      0
#define TG_DATA_POOR_SIGNAL  1
#define TG_DATA_ATTENTION    2
#define TG_DATA_MEDITATION   3
#define TG_DATA_RAW          4
#define TG_DATA_DELTA        5
#define TG_DATA_THETA        6
#define TG_DATA_ALPHA1       7
#define TG_DATA_ALPHA2       8
#define TG_DATA_BETA1        9
#define TG_DATA_BETA2       10
#define TG_DATA_GAMMA1      11
#define TG_DATA_GAMMA2      12
 
CFURLRef bundleURL;           // path reference to bundle
CFBundleRef thinkGearBundle;  // bundle reference
 
int connectionID = -1;        // ThinkGear connection handle
 
/*
 * ThinkGear function pointers
 */
 
int (*TG_GetDriverVersion)() = NULL;
int (*TG_GetNewConnectionId)() = NULL;
int (*TG_Connect)(int, const char *, int, int) = NULL;
int (*TG_ReadPackets)(int, int) = NULL;
float (*TG_GetValue)(int, int) = NULL;
int (*TG_Disconnect)(int) = NULL;
void (*TG_FreeConnection)(int) = NULL;
 
/**
 * This function handles signal interrupts. 
 *
 * Basically perform cleanup on the objects and then exit the program.
 */
void siginthandler(int sig){
   fprintf(stderr, "\nDisconnecting...\n");
 
   // close the connection
   if(connectionID != -1){
      TG_Disconnect(connectionID);
      TG_FreeConnection(connectionID);
   }
 
   // release the bundle references
   if(bundleURL)
      CFRelease(bundleURL);
 
   if(thinkGearBundle)
      CFRelease(thinkGearBundle);
 
   exit(1);
}
 
/**
 * The main driver for this program.
 *
 * Handle command-line arguments, initialize the ThinkGear connection,
 * and handle output.
 */
int main (int argc, const char * argv[]) {
   // register the signal interrupt handler
   signal(SIGINT, siginthandler);
 
   // cmd line argument checking
   if(argc < 2){
      fprintf(stderr, "Usage: %s portname\n", argv[0]);
      exit(1);
   }
 
   const char * portname = argv[1];       // port name
   int retVal = -1;                       // return values from TG functions
 
   int numPackets = 0;                    // number of packets returned from ReadPackets
   float signalQuality = 0.0;             // poor signal status
   float attention = 0.0;                 // eSense attention
   float meditation = 0.0;                // eSense meditation
 
   // create the path reference to the bundle
   bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
                                             CFSTR("ThinkGear.bundle"),
                                             kCFURLPOSIXPathStyle,
                                             true);
 
   // create the bundle reference
   thinkGearBundle = CFBundleCreate(kCFAllocatorDefault, bundleURL);
 
   // make sure the bundle actually exists
   if(!thinkGearBundle){
      fprintf(stderr, "Error: Could not find ThinkGear.bundle. Does it exist in the current directory?\n");
      exit(1);
   }
 
   // now start setting the function pointers
   TG_GetDriverVersion =   (void *)CFBundleGetFunctionPointerForName(thinkGearBundle, CFSTR("TG_GetDriverVersion"));
   TG_GetNewConnectionId = (void *)CFBundleGetFunctionPointerForName(thinkGearBundle, CFSTR("TG_GetNewConnectionId"));
   TG_Connect =            (void *)CFBundleGetFunctionPointerForName(thinkGearBundle, CFSTR("TG_Connect"));
   TG_ReadPackets =        (void *)CFBundleGetFunctionPointerForName(thinkGearBundle, CFSTR("TG_ReadPackets"));
   TG_GetValue =           (void *)CFBundleGetFunctionPointerForName(thinkGearBundle, CFSTR("TG_GetValue"));
   TG_Disconnect =         (void *)CFBundleGetFunctionPointerForName(thinkGearBundle, CFSTR("TG_Disconnect"));
   TG_FreeConnection =     (void *)CFBundleGetFunctionPointerForName(thinkGearBundle, CFSTR("TG_FreeConnection"));
 
   // check for any invalid function pointers
   if(!TG_GetDriverVersion || !TG_GetNewConnectionId || !TG_Connect || !TG_ReadPackets ||
      !TG_GetValue || !TG_Disconnect || !TG_FreeConnection){
      fprintf(stderr, "Error: Expected functions in ThinkGear.bundle were not found. Are you using the right version?\n");
      exit(1);
   }
 
   // get the connection ID
   connectionID = TG_GetNewConnectionId();
 
   fprintf(stderr, "Connecting to %s ... ", portname);
 
   // attempt to connect
   retVal = TG_Connect(connectionID, portname, TG_BAUD_9600, TG_STREAM_PACKETS);
 
   // check whether the connection attempt was successful
   if(!retVal){
      fprintf(stderr, "connected.\n"); 
 
      // loop until we get the interrupt signal from the console. control
      // then gets passed onto the signal handler function
      while(1){
         // sleep for half a second
         usleep(500000);
 
         // read the packets from the output stream
         numPackets = TG_ReadPackets(connectionID, -1);
 
         // check whether we've received any new packets
         if(numPackets > 0){
            // if so, parse them
            signalQuality = TG_GetValue(connectionID, TG_DATA_POOR_SIGNAL);
            attention = TG_GetValue(connectionID, TG_DATA_ATTENTION);
            meditation = TG_GetValue(connectionID, TG_DATA_MEDITATION);
 
            // then output everything
            fprintf(stdout, "\rPoorSig: %3.0f, Att: %3.0f, Med: %3.0f", signalQuality, attention, meditation);
            fflush(stdout);
         }
      }
   }
   else {
      fprintf(stderr, "unable to connect. (%d)\n", retVal);
      exit(1);
   }
 
   return 0;
}