Thursday 22 December 2011

Mindwave with XCode

Here's my first functional project for Mindwave in XCode.  (This video is my third attempt to record - The frustration shows through at the beginning)

A few things for you to bear in mind:

Sometimes Mac OS X loses the Mindwave.  There are several ports that are reported and ThinkGear connector will not let you save the changes.  The port that seems to consistently work is /dev/tty.MindWave

If the port is saved as /dev/tty.MindWaveMobile-SPPDev or /dev/tty.MindSet-DevB, the installed software will not work.  I have not yet figured out how to save the port as /dev/tty.MindWave

Also, you will need to include the ThinkGear.bundle file in the XCode project.  (This can be found in the MindSet Development Tools along with a PDF describing how to add it to the project)


Main C Code

#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; 
CFBundleRef thinkGearBundle; // bundle reference

int connectionID = -1; // ThinkGear connection handle

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");

    if (connectionID != -1) {
        TG_Disconnect(connectionID);
        TG_FreeConnection(connectionID);
    }
    
    if (bundleURL)
        CFRelease(bundleURL);
    
    if (thinkGearBundle)
        CFRelease(thinkGearBundle);
    
    exit(1);
    
}

int main (int argc, const char *argv[]) {
    
    signal(SIGINT, siginthandler);
    
    if(argc < 2) {
        fprintf(stderr, "Usage: %s protname\n", argv[0]);
        exit(1);
    }
    
    const char *portname = argv[1];
    int retVal = -1;
    
    int numPackets = 0;
    float signalQuality = 0.0;
    float attention = 0.0;
    float meditation = 0.0;
    
    bundleURL = CFURLCreateWithFileSystemPath(
                                              kCFAllocatorDefault,
                                              CFSTR("ThinkGear.bundle"), 
                                              kCFURLPOSIXPathStyle, 
                                              true);
    
    thinkGearBundle = CFBundleCreate(kCFAllocatorDefault, bundleURL);
    
    if (!thinkGearBundle) {
        fprintf(stderr, "Error: Could not find ThinkGear.bundle. Does it exist in the current directory?\n");
        exit(1);
    }
    
    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"));
    
    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.\n");
        exit(1);
    }
    
    connectionID = TG_GetNewConnectionId();
    
    fprintf(stderr, "Connecting to %s ... ", portname);
    
    retVal = TG_Connect(connectionID, portname, TG_BAUD_9600, TG_STREAM_PACKETS);
    
    if (!retVal) {
        fprintf(stderr, "connected.\n");
        
        while(1) { 
            usleep(500000);
            
            numPackets = TG_ReadPackets(connectionID, -1);
            if (numPackets > 0) {
                signalQuality = TG_GetValue(connectionID, TG_DATA_POOR_SIGNAL);
                attention = TG_GetValue(connectionID, TG_DATA_ATTENTION);
                meditation = TG_GetValue(connectionID, TG_DATA_MEDITATION);
                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;
}


Below is a screen snap of the output from this while it is attached to my cranium. You can see my attention wander then begin to focus once again.



1 comment:

  1. Hey, I managed to get my hands on a MindWave Mobile, however I am not a programer and have very limited knowledge when it comes to xcode, I am wondering if you could provide a bit more info on how you got the read out?

    ReplyDelete