Made a simple OpenEEG reader.

2008-11-10
2013-06-06
  • Tuomas Karmakallio

    based on cateeg.c and some basic P2 decoders,
    the intention of this program is to provide a minimal
    interface for any other program to receive data from the openeeg
    without having to work out the port and packet reading.

    C++, windows based port reading.
    I would like to put this somewhere, even perhaps on the main
    opneEEG page once it has been approved.

    Notes: not sure if naming it a lib is really spot on, might change that..

    REM Usage

    #include "modeegLib.h"

    declare
        modeegLib modLib;
    initialize
        modLib.initEEG();
    run
        if (EEGActive){
            modLib.readEEG();           
        }
    read
        int valuech1 = modLib.values[0][0];
        int valuech2 = modLib.values[1][0];
    the values can be read directly from the start of the pipe [ch][0])
    no need to move a readhead along

    Features: call init and read from outside
    does not crash if device is not powered on

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <string.h>
    #include <assert.h>
    #include <io.h>

    #define P2_CHANNELS 2   // P2 channels ( 6 + 4 aux available )

    #define DEFAULT_COM        "COM1"
    #define DEFAULT_BAUD    57600

    #define DEV_RBUFSIZ        10240    // com port read buffer size
    #define DEV_WBUFSIZ        4096    // com port write buffer size (unneeded)

    #define P2_CHANNELS 2   // P2 channels ( 6 + 4 aux available )
    #define P2_PACKET_BYTES  17         // P2 Packet size
    #define READ_BUFFER_SIZE  512            // read buffer, before decode
    #define SAMPLE_AMOUNT 16 //512 // amount of actual samples kept in memory

    char *progName = "catEEG";

    bool showP2decode = false;
    bool showMinimalChannelData = true;

    bool EEGActive = true; // always try, turns off if fail
    bool showEEGData = false; // console not checked
    bool showRawBuffer = false;

    int checkNum = 0;

    class modeegLib
    {
       
    public:
            float **samples;
            int **values;
       
    private:

           
            HANDLE    hPort; // rem nulled
            FILE    *out ;
            OVERLAPPED o;

            int        c ;
            char    *fileName ;

            char    *portName ;
            int        baudRate ;
            int        quiet ;

            unsigned char rawDataBuffer[READ_BUFFER_SIZE]; // raw bytes
            int errors[SAMPLE_AMOUNT]; // error log 0 clean 1 error

            int inBuffercount;
            int rawBuffercount;

       
           

        void print_error(char *msg)
        {
            void* lpMsgBuf;
           
            double dwError = GetLastError();

            FormatMessage(
                FORMAT_MESSAGE_ALLOCATE_BUFFER |
                FORMAT_MESSAGE_FROM_SYSTEM |
                FORMAT_MESSAGE_IGNORE_INSERTS,
                NULL,
                dwError,
                0, // Default language
                (LPTSTR) &lpMsgBuf,
                0,
                NULL
                );
            if (msg != NULL) {
                fprintf(stderr, "%s: %s: %s\n", progName, msg, lpMsgBuf);
            } else {
                fprintf(stderr, "%s: %s\n", progName, lpMsgBuf);
            }
            LocalFree(lpMsgBuf);
            fflush(stderr);
        }

        void error_exit(char *msg)
        {
            print_error(msg);
            exit(1);
        }

        void usage_exit(char *msg)
        {
            if (msg) {
                fprintf(stderr, "%s: %s\n", progName, msg);
            }
            fprintf(stderr, "Usage: %s [options]\n", progName);
            fprintf(stderr, "Copy EEG data from COM port to stdout.\n");
            fprintf(stderr, "\noptions are:\n");
            fprintf(stderr, "\t-f <filename>   output to <filename> instead of stdout\n");
            fprintf(stderr, "\t                WARNING: if <filename> exists it will be overwritten.\n");
            fprintf(stderr, "\t-p <portname>   read from <portname> instead of %s\n", DEFAULT_COM);
            fprintf(stderr, "\t-b <baudrate>   set speed to <baudrate> instead of %d\n", DEFAULT_BAUD);
            fprintf(stderr, "\t-q              suppress start message\n");
            fprintf(stderr, "\t-h              print this help message\n");
            fprintf(stderr, "\nNote that 8 bit data, no parity, 1 stop bit, no handshaking are always used.\n");

            exit(msg != NULL);
        }

        // SetupConnection sets the port's baud, parity, etc.
        bool SetupConnection(void* hPort, int baudRate)
       
        {
            bool       fRetVal ;
            DCB        dcb ;

            dcb.DCBlength = sizeof(DCB) ;

            GetCommState(hPort, &dcb) ;

            dcb.BaudRate = baudRate;
            dcb.ByteSize = 8;
            dcb.Parity = NOPARITY;
            dcb.StopBits = ONESTOPBIT;
            dcb.fOutxCtsFlow = FALSE;
            dcb.fOutxDsrFlow = FALSE;
            dcb.fInX = FALSE;
            dcb.fOutX = FALSE;
            dcb.fDtrControl = DTR_CONTROL_DISABLE;
            dcb.fRtsControl = RTS_CONTROL_DISABLE;
            dcb.fBinary = TRUE ;
            dcb.fParity = FALSE ;

            fRetVal = SetCommState(hPort, &dcb);

            return (fRetVal) ;
        }

        // ReadCommBlock reads available data up to nMaxLength bytes
        int ReadCommBlock(HANDLE hPort, LPSTR lpszBlock, int nMaxLength)
        {
            BOOL       fReadStat ;
            COMSTAT    ComStat ;
            DWORD      dwErrorFlags;
            DWORD      dwLength;

            // only try to read number of bytes in queue
            ClearCommError( hPort, &dwErrorFlags, &ComStat ) ;
            dwLength = min( (DWORD) nMaxLength, ComStat.cbInQue ) ;

            if (dwLength > 0)
            {
                fReadStat = ReadFile(hPort, lpszBlock, dwLength, &dwLength,NULL);
                if (!fReadStat)
                {
                     dwLength = 0 ;
                    ClearCommError(hPort, &dwErrorFlags, &ComStat ) ;
                    if (dwErrorFlags > 0) {
                        error_exit("ReadCommBlock");
                    }
                }
                if (showEEGData)
                    fprintf(stderr, "read %d bytes from serial port\n",dwLength);
            }

            return (dwLength) ;
        }

        // returns position of start marker

        int find_P2_header(unsigned char* p, int n, int start)
        {
            int i;

            if (start<n)
                for (i = start; i < n; i++)
                {
                    //fprintf(stdout, "p[i]: %X \n",p[i]);
                    if (p[i] == 0xA5) { 
                        if(p[i+1] == 0x5A){
                            if(showP2decode)
                                fprintf(stdout, "found header at: %d \n",i);
                            return i;
                        }
                       
                    }

                }
            return -1;
        }

        public: bool initEEG(){
           
            hPort = NULL;
            out = NULL;
           
            c = 1;
            fileName = NULL;

            // Create an event object for use by WaitCommEvent.
            o.hEvent = CreateEvent(
                NULL,   // default security attributes
                TRUE,   // manual-reset event
                FALSE,  // not signaled
                NULL    // no name
                );
            // Initialize the rest of the OVERLAPPED structure to zero.
            o.Internal = 0;
            o.InternalHigh = 0;
            o.Offset = 0;
            o.OffsetHigh = 0;

            //char    *fileName = "log.txt";
            //out = fopen(fileName, "wb");

            portName = NULL;
            baudRate = 0;
            quiet = 0;

             //allocate memory for one row
             values = (int**)malloc( sizeof(int*));
             // plus channels as columns
             for(int i=0; i< P2_CHANNELS; i++)
             {
                   *(values+i) = (int*)malloc(SAMPLE_AMOUNT *sizeof(int));
             }

             //allocate memory for rows // 4 rows of sample data per channel
             samples = (float**)malloc(4 *sizeof(float*));

             //for each row allocate memory for columns
             for(int i=0; i< P2_CHANNELS; i++)
             {
                   *(samples+i) = (float*)malloc(SAMPLE_AMOUNT *sizeof(float));
             }

             // no ref
            //int errors[SAMPLE_AMOUNT]; // error log 0 clean 1 error

            inBuffercount = 0;
            rawBuffercount = 0;

            if (EEGActive){

                bool connected = false;

                if (!portName) portName = DEFAULT_COM;

                if (!out) {        // default to stdout
                    out = stdout; fileName = "stdout";
                    // set stdout to binary mode
                    _setmode( _fileno( stdout ), _O_BINARY );
                }
                setvbuf(out, NULL, _IONBF, 0);  // unbuffered output

                if (!baudRate) baudRate = DEFAULT_BAUD;

                hPort = CreateFileA(portName,
                    GENERIC_READ | GENERIC_WRITE,
                    0,
                    NULL,
                    OPEN_EXISTING,
                    FILE_FLAG_OVERLAPPED, //FILE_ATTRIBUTE_NORMAL, // | FILE_FLAG_OVERLAPPED,
                    NULL);

                if (hPort == INVALID_HANDLE_VALUE) {
                    error_exit("Opening COM port");
                }else if (!SetCommMask( hPort, EV_RXCHAR )) {
                    error_exit("SetCommMask");
                }else
                    connected = true;

                if (connected)
                    SetupComm(hPort, DEV_RBUFSIZ, DEV_WBUFSIZ);

                if (!SetupConnection(hPort, baudRate)) {
                    connected = false;
                    error_exit("SetupConnection");
                }

                if (!quiet) {
                    fprintf(stderr, "%s: Copying %s at %d baud to %s\n", progName, portName, baudRate, fileName);
                    fprintf(stderr, "Press ctrl-C to quit.\n");
                    fflush(stderr);
                }
            }
            return true;
        }

        public: void readEEG(){

            // loop until ^C
           
            DWORD    dwEvtMask ;
            int        nLength;
            BYTE    inBuf[512];
            int pos = 0;
            int leftoverdataAmount = 0;
            int marker = -1; // marker position in raw buffer
            dwEvtMask = 0;

            assert(o.hEvent);
            if (WaitCommEvent(hPort, &dwEvtMask, &o)){
        //    WaitCommEvent(hPort, &dwEvtMask, NULL); //if no overlap

                if ((dwEvtMask & EV_RXCHAR) == EV_RXCHAR) {
                   
                    do    {

                        if (nLength = ReadCommBlock(hPort, (LPSTR)inBuf, sizeof(inBuf)-1))
                        {
                            if (inBuffercount > 0){

                                if ( showRawBuffer ){
                                    for (char i = 0; i < rawBuffercount; i++){
                                        fprintf(stderr, "%d:%X,", i, rawDataBuffer[i]);
                                       
                                    }
                                fprintf(stdout, "\n");
                                }

                                // REM find header 0x5A 0xA5 combo 
                                marker = find_P2_header((unsigned char *)rawDataBuffer, rawBuffercount,0);
                            }

                            while( marker != -1 ){
                           
                                // rem check the raw data
                                if (showRawBuffer)
                                    fprintf(stdout, "raw buffer size: %d\n",rawBuffercount);
                                int bufferEnd = -1;

                                // check for 17 byte length in buffer
                                if ( rawBuffercount > P2_PACKET_BYTES + marker ) {

                                    // fill the packet
                                    unsigned char packet[P2_PACKET_BYTES];
                                   
                                    // hmm im sure these would be faster - check them
                                    // void * memcpy ( void * destination, const void * source, size_t num );
                                    // memcpy((void *)packet, (const void *)rawDataBuffer[marker], 8);
                                    // do it by hand for the moment
                                   
                                    int start = marker;

                                    for ( char packloop = 0; packloop < P2_PACKET_BYTES; packloop++){

                                        int pos = (start+packloop);
                                        packet[packloop] = rawDataBuffer[pos];

                                        if (showRawBuffer)
                                            fprintf(stdout, "packet %d:%X,",packet[packloop]);
                                    }
                                    if (showRawBuffer)
                                        fprintf(stderr, "\n");
                               

                                    // rem copy rest of data to start of new rawbuffer
                                    // if leftovers, copy
                                    leftoverdataAmount = rawBuffercount - P2_PACKET_BYTES - marker;

                                    if (showRawBuffer)
                                        fprintf(stderr, "leftoverdata: %d\n",leftoverdataAmount);
                               
                                    if (leftoverdataAmount != 0)
                                    {
                                        // kay we need to make *[] here ...
                                        unsigned char* temp = NULL;
                                        temp = new unsigned char [leftoverdataAmount];
                                       
                                        // replace memcpies for now
                                        for (int over = 0; over < leftoverdataAmount; over++){
                                            temp[over] = rawDataBuffer[start+P2_PACKET_BYTES+over];
                                        }
                                        //memcpy((void *)temp,(void *)rawDataBuffer[(marker+8)],leftoverdataAmount);
                                       
                                        // REM check raw clearance
                                        int limit = sizeof( rawDataBuffer ) / sizeof( rawDataBuffer[ 0 ] );
                                       
                                        // hmm this seems awfully slow way to clear the buffer
                                        for( int i = 0 ; i < sizeof( rawDataBuffer ) / sizeof( rawDataBuffer[ 0 ] ) ; ++ i ) {
                                            rawDataBuffer[ i ] = 0 ; // or some other "clear" value }
                                        }

                                        // raw should be zeroed now, copy leftovers into the raw

                                        //memcpy((void *)rawDataBuffer,(void*)temp,leftoverdataAmount);
                                        for (int over = 0; over < leftoverdataAmount; over++){
                                            rawDataBuffer[over] = temp[over];
                                        }

                                        delete [] temp;

                                        rawBuffercount = leftoverdataAmount;
                                   

                                    }else{
                                        // clear the raw completely - iis this wasting time?
                                        for( int i = 0 ; i < sizeof( rawDataBuffer ) / sizeof( rawDataBuffer[ 0 ] ) ; ++ i ) {
                                            rawDataBuffer[ i ] = 0 ;
                                        }
                                        rawBuffercount = 0;
                                       
                                    }
                                   
                                    // pass packet to decoder
                                    read_P2_fromBuffer((unsigned char*) packet, samples, (char *)errors, 1, values);
                                   
                                    if (rawBuffercount >= P2_PACKET_BYTES)
                                    {
                                        marker = find_P2_header((unsigned char *)rawDataBuffer, rawBuffercount,0 );
                                    }
                                    else marker = -1;       

                                }else marker = -1;
                               

                            }
                       
                            int counter = 0;
                            for (pos = 0; pos < nLength; pos++ )
                           
                            {
                                rawDataBuffer[ rawBuffercount + counter  ] = inBuf[pos];
                                counter++;
                            }

                            rawBuffercount += nLength;
                            inBuffercount += nLength;
                           
                            // write is not necessary unless we want to log stuff
                            //fwrite( (const void *)inBuf, nLength, 1, out);

                            if (showEEGData)
                                fprintf(stderr, "\n inBufferCount: %d\n",inBuffercount);
                            //fflush(out);
                        }
                    } while (nLength > 0) ;
                }
            }
            else
            {
                // comes through here once, then continues

               
                DWORD dwRet = GetLastError();
                if( ERROR_IO_PENDING == dwRet)
                {
                    EEGActive = false;
                    printf("I/O is pending...\n");

                    // To do.
                }
                else
                    printf("Wait failed with error %d.\n", GetLastError());
            }
        }

    /**
    *
    *  p    pointer to stream
    *  chan = samples**
    *  err  is set to err[len]= 1 on errors
    *  max  length of buffer
    *  vals = values**
    *
    */

        static int read_P2_fromBuffer(unsigned char* p, float **chan, char *err, int max, int **vals) {
       
           int len= 0;
           int count= -1;
           unsigned char buf[15];
           int dataout[2] = {0,0};
       

           while (len < max) {
              int ch1, ch2;
              int cnt, a;

              // Check packet header - assuming we are being fed clean packets
              ch1= p[0]; cnt= 0;   

              if (ch1 == EOF) return len;
              while (1) {

                 ch2 = p[1]; // note this used fgets and fread is next used in buf
                
                 if (ch2 == EOF) return len;
                 if (ch1 == 0xa5 && ch2 == 0x5a){break;}
                 err[len]= 1;        // Mark sync error
                 ch1= ch2;
                 if (++cnt > 100) {
               
                     fprintf(stderr, "No start mark found in 100 bytes of data stream");
                     // REM make error message here
                     //error("No start mark found in 100 bytes of data stream");
                 }
              }

              // Read the rest of the packet
               
              int relevantBytes = 15; // full set

              if (P2_CHANNELS == 2)
                    relevantBytes = 8; // 9-15 are ch3+

              for (char i= 0; i<relevantBytes; i++){
           
                  buf [i] = p[2+i]; // skip header bytes
                //fprintf(stdout, "i=%d : cnt=%d : data=%X\n",i,cnt,buf[i]);
              }

              // Check the version number
              if (2 != buf[0]) printf("WARNING: version %d not supported\n", buf[3]);

              // Check the counter.  Note this only checks within the current
              // run of data -- it doesn't check continuity from the last
              // block read.  Also, we could perhaps insert big runs of zeros
              // for gaps in the count, but this does not seem worth it.
              if (count >= 0 && count != buf[1]) err[len]= 1;
                count= 255 & (buf[1] + 1);

              // Convert the data.  Bad data gives error marks

              for (a= 0; a<P2_CHANNELS; a++) {
                int val= (buf[2*a+2]<<8) + buf[2*a+3];
                if (val < 0 || val >= 1024) { err[len]= 1; val= 512; }
               
                int result = (val-512) * (1.0/512.0);
                chan[a][len]= result;

                // read vals OK, check samples
                vals[a][0] = val;
               
                if(showMinimalChannelData){
                    if (a == 0 || a == 1){   
                            fprintf(stdout, "ch%d[%d],",a,val);
                    }
                }
               
              }
              if(showMinimalChannelData)
                fprintf(stdout, "\n");

              // Switch settings on last four channels
              if (P2_CHANNELS != 2)
              {
                  for (a= 0; a<4; a++)
                    chan[6+a][len]= (buf[14] & (8>>a)) ? 1.0 : -1.0;
              }

              len++;
           }
           return len;
        }

     
    /*
        static int read_P2_fromFile(BWFile *ff, BWBlock *bb, FILE *in, float **chan, char *err, int max) {

           int len= 0;
           int count= -1;
           unsigned char buf[15];
      
           while (len < max) {
              int ch1, ch2;
              int cnt, a;

              // First scan forwards to the start-mark
              ch1= fgetc(in); cnt= 0;
              if (ch1 == EOF) return len;
              while (1) {
             ch2= fgetc(in);
             if (ch2 == EOF) return len;
             if (ch1 == 0xa5 && ch2 == 0x5a) break;
             err[len]= 1;        // Mark sync error
             ch1= ch2;
             if (++cnt > 100) error("No start mark found in 100 bytes of data stream");
              }

              // Read the rest of the packet
              if (1 != fread(buf, 15, 1, in)) return len;

              // Check the version number
              if (2 != buf[0]) printf("WARNING: version %d not supported", buf[0]);

              // Check the counter.  Note this only checks within the current
              // run of data -- it doesn't check continuity from the last
              // block read.  Also, we could perhaps insert big runs of zeros
              // for gaps in the count, but this does not seem worth it.
              if (count >= 0 && count != buf[1]) err[len]= 1;
              count= 255 & (buf[1] + 1);

              // Convert the data.  Bad data gives error marks
              for (a= 0; a<6; a++) {
             int val= (buf[2*a+2]<<8) + buf[2*a+3];
             if (val < 0 || val >= 1024) { err[len]= 1; val= 512; }
             chan[a][len]= (val-512) * (1.0/512.0);
              }

              // Switch settings on last four channels
              for (a= 0; a<4; a++)
             chan[6+a][len]= (buf[14] & (8>>a)) ? 1.0 : -1.0;

              len++;
           }
           return len;
        }
    */

        /**
         * Look for a packet sync marker.
         *
         * @param p        packet buffer
         * @param n        maximum number of bytes to scan.
         *
         * @returns Assuming p[i] corresponds to the byte with the sync marker,
         *            the return value is i+1.
         *            If no sync marker was found, the return value is -1.
         */

         int mepckt_find_sync_P3( char* p, int n)
        //int mepckt_find_sync( *p, int n)
        {
            int i;

            for (i = 0; i < n; i++)
            {
                if (p[i] & 0x80) return i+1;
            }
            return -1;
        }

         int mepckt_find_sync_from_position_P3( char* p, int n, int start)
        //int mepckt_find_sync( *p, int n)
        {
            int i;

            for (i = start; i < n; i++)
            {
                if (p[i] & 0x80) return i+1;
            }
            return -1;
        }

        /**
         * Compute the number of channels in a packet, from the packet length.
         * @param n        Number of bytes in a packet.
         *
         * @returns number of channels if >= 0. -1 if the packet length is illegal.
         */

        int mepckt_nchannels_P3(int n)
        {
            n -= 2;
            if ((n < 0) || ((n % 3) != 0)) return -1;
            return (n / 3) * 2;
        }
       

        /**
         * Decode a raw packet from a ModularEEG.
         *
         * @param nch   number of channels in the packet (0, 2, 4 or 6)
         * @param src   start of the raw packet to decode
         * @param dst   will hold the samples, must be large enough for nch samples
         * @param cnt   will hold the packet counter value
         * @param aux   will hold the auxillary byte.
         *
         * @returns nonzero if the packet was successfully decoded.
         *            zero if the sync marker could not be found in the last byte in
         *            the packet, or if sync markers were found before the last byte.
         *
         * @see the ModularEEG firmware for packet format details.
         *
         *
        */

    /*
        int mepckt_decode_P3(char nch, char* src, int* dst, char* cnt, char* aux)
        {
            int i, j;
            int sync;

            assert((nch + 1) & 1);  // nch == odd is illegal

            // Decode and store the header and its sync bits

            *cnt = (src[0] >> 1) & 0x3f;
            *aux = (src[0] << 7) & 0x80 | src[1] & 0x7f;
            sync = (src[0] >> 6) & 2 | (src[1] >> 7) & 1;

            for (i = 0, j = 2; i < (nch >> 1); i++, j += 3)
            {
                // Decode and store even-channel sample
               
               
               
                dst[i << 1] = ((unsigned short) src[j]) & 0x7f |
                    (((unsigned short) src[j+2]) << 3) & 0x380;

                fprintf(stderr, "storing even-channel sample, i: %d value %d \n", i, dst[i << 1]);

                // Decode and store odd-channel sample

               
               
                dst[(i << 1) + 1] = ((unsigned short) src[j+1]) & 0x7f |
                    (((unsigned short) src[j+2]) << 7) & 0x380;

                fprintf(stderr, "storing odd-channel sample, i: %d value %d\n", i, dst[(i << 1) + 1]);

                // Decode and store the sync bits

                sync = (sync << 3) | (int)
                    ((src[j] >> 5) & 4 | (src[j+1] >> 6) & 2 | (src[j+2] >> 7) & 1);
            }
            // The sync marker is last, so sync should be == 1, or there was an error.
            return (sync == 1);
        }
    */
        void showbinary (unsigned char argc)
        {
            // printf("%d in binary ",argc);
            if (argc & 128)printf("1");else printf("0");
            if (argc & 64)printf("1");else printf("0");
            if (argc & 32)printf("1");else printf("0");
            if (argc & 16)printf("1");else printf("0");
            if (argc & 8)printf("1");else printf("0");
            if (argc & 4)printf("1");else printf("0");
            if (argc & 2)printf("1");else printf("0");
            if (argc & 1)printf("1");else printf("0");
           
            //printf("\n");
        }

        const char* makebinaryString (unsigned char argc)
        {
            char str[8];
           
            // printf("%d in binary ",argc);
            if (argc & 128)str[0]=1;    else str[0]=0;
            if (argc & 64) str[1]=1;    else str[1]=0;
            if (argc & 32) str[2]=1;    else str[2]=0;
            if (argc & 16) str[3]=1;    else str[3]=0;
            if (argc & 8)  str[4]=1;    else str[4]=0;
            if (argc & 4)  str[5]=1;    else str[5]=0;
            if (argc & 2)  str[6]=1;    else str[6]=0;
            if (argc & 1)  str[7]=1;    else str[7]=0;
           
            return "str";
           
        }

    };

        ////////// Packet Format Version 2 ////////////

    // 17-byte packets are transmitted from the ModularEEG at 256Hz,
    // using 1 start bit, 8 data bits, 1 stop bit, no parity, 57600 bits per second.

    // Minimal transmission speed is 256Hz * sizeof(modeeg_packet) * 10 = 43520 bps.
    /*
    struct modeeg_packet
    {
            unsigned char        sync0;          // = 0xa5
            unsigned char        sync1;          // = 0x5a
            unsigned char        version;        // = 2
            unsigned char        count;          // packet counter. Increases by 1 each packet.
            int                    data[6];        // 10-bit sample (= 0 - 1023) in big endian (Motorola) format ?? .
            unsigned char       switches;       // State of PD5 to PD2, in bits 3 to 0.
    };*/

    /klzzwxh:10001klzzwxh:10100klzzwxh:10003klzzwxh:10004klzzwxh:10005 6.2 P2 - Firmware Protocolklzzwxh:10101klzzwxh:10006klzzwxh:10007klzzwxh:10008 The P2 Firmware Protocol was the inital transmission protocol of the OpenEEGklzzwxh:10102klzzwxh:10009klzzwxh:10010klzzwxh:10011 project, used by ModularEEG. It is compatible with the ElectricGuru application.klzzwxh:10103klzzwxh:10012klzzwxh:10013klzzwxh:10014 P2 uses 17 data bytes to transmit 6 channels of EEG data:klzzwxh:10104klzzwxh:10015klzzwxh:10016klzzwxh:10017 1: sync0;klzzwxh:10105klzzwxh:10018klzzwxh:10019klzzwxh:10020 // synchronisation byte 1 = 0xa5klzzwxh:10106klzzwxh:10021klzzwxh:10022klzzwxh:10023 2: sync1;klzzwxh:10107klzzwxh:10024klzzwxh:10025klzzwxh:10026 // synchronisation byte 2 = 0x5aklzzwxh:10108klzzwxh:10027klzzwxh:10028klzzwxh:10029 3: version;klzzwxh:10109klzzwxh:10030klzzwxh:10031klzzwxh:10032 // version number = 2klzzwxh:10110klzzwxh:10033klzzwxh:10034klzzwxh:10035 4: count;klzzwxh:10111klzzwxh:10036klzzwxh:10037klzzwxh:10038 // packet counter. Increases by 1 each packet.klzzwxh:10112klzzwxh:10039klzzwxh:10040klzzwxh:10041 5: Chn1lowklzzwxh:10113klzzwxh:10042klzzwxh:10043klzzwxh:10044 // channel 1 low byteklzzwxh:10114klzzwxh:10045klzzwxh:10046klzzwxh:10047 6: Chn1highklzzwxh:10115klzzwxh:10048klzzwxh:10049klzzwxh:10050 // channel 2 high byteklzzwxh:10116klzzwxh:10051klzzwxh:10052klzzwxh:10053 7: Chn2lowklzzwxh:10117klzzwxh:10054klzzwxh:10055klzzwxh:10056 // channel 2 low byteklzzwxh:10118klzzwxh:10057klzzwxh:10058klzzwxh:10059 8: Chn2highklzzwxh:10119klzzwxh:10060klzzwxh:10061klzzwxh:10062 // ...klzzwxh:10120klzzwxh:10063klzzwxh:10064klzzwxh:10065 9: Chn3lowklzzwxh:10121klzzwxh:10066klzzwxh:10067klzzwxh:10068 10: Chn3highklzzwxh:10122klzzwxh:10069klzzwxh:10070klzzwxh:10071 11: Chn4lowklzzwxh:10123klzzwxh:10072klzzwxh:10073klzzwxh:10074 12: Chn4highklzzwxh:10124klzzwxh:10075klzzwxh:10076klzzwxh:10077 13: Chn5lowklzzwxh:10125klzzwxh:10078klzzwxh:10079klzzwxh:10080 14: Chn5highklzzwxh:10126klzzwxh:10081klzzwxh:10082klzzwxh:10083 15: Chn6lowklzzwxh:10127klzzwxh:10084klzzwxh:10085klzzwxh:10086 16: Chn6highklzzwxh:10128klzzwxh:10087klzzwxh:10088klzzwxh:10089 // channel 6 high byteklzzwxh:10129klzzwxh:10090klzzwxh:10091klzzwxh:10092 17: switches;klzzwxh:10130klzzwxh:10093klzzwxh:10094klzzwxh:10095 // State of PD5 to PD2, in bits 3 to 0klzzwxh:10131klzzwxh:10096klzzwxh:10097klzzwxh:10098klzzwxh:10099 klzzwxh:10002/

     
  • kevinvil

    kevinvil - 2010-02-10

    why are the forums here so dead? is there just no community around these projects? Am I in the wrong place?

     

Log in to post a comment.

Get latest updates about Open Source Projects, Conferences and News.

Sign up for the SourceForge newsletter:





No, thanks