Main Page | Data Structures | File List | Data Fields | Globals | Related Pages

writebdf.c

Go to the documentation of this file.
00001 
00020 /*
00021 NeuroServer
00022  
00023 A collection of programs to translate between EEG data and TCP network
00024 messages. This is a part of the OpenEEG project, see http://openeeg.sf.net
00025 for details.
00026     
00027 Copyright (C) 2003, 2004 Rudi Cilibrasi (cilibrar@ofb.net)
00028      
00029 This library is free software; you can redistribute it and/or
00030 modify it under the terms of the GNU Lesser General Public
00031 License as published by the Free Software Foundation; either
00032 version 2.1 of the License, or (at your option) any later version.
00033          
00034 This library is distributed in the hope that it will be useful,
00035 but WITHOUT ANY WARRANTY; without even the implied warranty of
00036 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00037 Lesser General Public License for more details.
00038              
00039 You should have received a copy of the GNU Lesser General Public
00040 License along with this library; if not, write to the Free Software
00041 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00042 */
00043                 
00044 #include <assert.h>
00045 #include <openedf.h>
00046 #include <string.h>
00047 #include <stdlib.h>
00048 #include <sys/time.h>
00049 #include <pctimer.h>
00050 #include <ctype.h>
00051 #include <nsutil.h>
00052 #include <nsnet.h>
00053 
00054 const char *helpText =
00055 "writeedf   v 0.35 by Rudi Cilibrasi, Moritz von Buttlar\n"
00056 "\n"
00057 "Usage:  writeedf [options] <filename>\n"
00058 "\n"
00059 "        -p port          Port number to use (default 8336)\n"
00060 "        -n hostname      Host name of the NeuroCaster server to connect to\n"
00061 "                         (this defaults to 'localhost')\n"
00062 "        -s <num>         Only record this many seconds.\n"
00063 "                         (default is to record until interrupted)\n"
00064 "        -e <intnum>      Integer ID specifying which EEG to log (default: 0)\n"
00065 "        -b               use bdf format (same as edf, only 24 bits/sample) \n"
00066 "        -c               write as CSV array (can be imported to Excel, Scilab,etc.)"
00067 "The filename specifies the new EDF file to create.\n"
00068 ;
00069 
00070 #define MINLINELENGTH 4
00071 #define DELIMS " \r\n"
00072 
00075 struct Options {
00076         char hostname[MAXLEN];  
00077         unsigned short port;    
00078         char filename[MAXLEN];  
00079         int eegNum;             
00080         int isFilenameSet;      
00081         int isBdf;              
00082         int isArray;            
00083         int isLimittedTime;     
00084         double seconds;         
00085 };
00086  
00087 
00088 struct EDFDecodedConfig cfg;    
00089 static struct OutputBuffer ob;  
00090 struct InputBuffer ib;          
00091 char lineBuf[MAXLEN];           
00092 int blockCounter = 0;           
00093 
00094 char *dataarray;                
00095 long samples[MAXCHANNELS];      
00096 
00097 size_t sampleSize;              
00098 unsigned int frameCount;        
00099 struct Options opts;            
00100 
00103 void resetSampleBuffer()
00104 {
00105         frameCount = 0;
00106 }
00107 
00110 void writeSampleBuffer(unsigned int Channel,unsigned int SampleNr, char Byte0, char Byte1, char Byte2) {
00111  if (opts.isBdf) {
00112   dataarray[Channel*cfg.chan[0].sampleCount*sampleSize+SampleNr*sampleSize]=Byte0;
00113   dataarray[Channel*cfg.chan[0].sampleCount*sampleSize+SampleNr*sampleSize+1]=Byte1;
00114   dataarray[Channel*cfg.chan[0].sampleCount*sampleSize+SampleNr*sampleSize+2]=Byte2;
00115  }
00116  else {
00117   dataarray[Channel*cfg.chan[0].sampleCount*sampleSize+SampleNr*sampleSize]=Byte1;
00118   dataarray[Channel*cfg.chan[0].sampleCount*sampleSize+SampleNr*sampleSize+1]=Byte2;
00119  }
00120 }
00121 
00124 void initSampleBuffer()
00125 {
00126         if (opts.isBdf) 
00127          sampleSize=sizeof(unsigned char[3]);   
00128         else 
00129          sampleSize=sizeof(unsigned char[2]);   
00130         dataarray = (unsigned char *) malloc(cfg.hdr.dataRecordChannels*
00131                      sampleSize*cfg.chan[0].sampleCount*sizeof(unsigned char) ); 
00132         resetSampleBuffer();
00133         assert(dataarray != NULL && "Cannot allocate memory!");
00134 }
00135 
00136 
00139 void writeBufferToFile()
00140 {
00141         FILE *fp;
00142         fp = fopen(opts.filename, "a");
00143         rprintf("File opened for block write, frameCount: %d \n",frameCount);
00144         assert(fp != NULL && "Cannot open file!");      
00146         fseek(fp, 0, SEEK_END);
00148         fwrite(dataarray, sizeof(unsigned char) , cfg.hdr.dataRecordChannels*frameCount*sampleSize, fp);
00149         fclose(fp);
00150         rprintf("Wrote block %d\n", blockCounter);
00151         blockCounter += 1;
00152         resetSampleBuffer();
00153 }
00154 
00155 
00158 void handleSamples(int packetCounter, int channels)
00159 {
00160         static int lastPacketCounter = 0;
00161         int i;
00162         unsigned char c1,c2,c3=0;
00163         if (lastPacketCounter + 1 != packetCounter && packetCounter != 0 && lastPacketCounter != 0) {
00164                 rprintf("May have missed packet: got packetCounters %d and %d\n", lastPacketCounter, packetCounter);
00165         }
00166         lastPacketCounter = packetCounter;
00167         for (i = 3; i < channels+3; ++i) {
00168 //         rprintf("Writing data from Channel: %d Value: %d Sample: %d to buffer \n",i,samples[i],frameCount);
00169 
00170 // Now we have to convert a 4 byte 2s complement long number into a 3 or 2 byte 2s complement number.
00171 // This is done by removing the most significant 8 or 16 bits and adding the sign bit to the most significant
00172 // bit of the remaining number. The result is saved in three unsigned char bytes.
00173          if (opts.isBdf) {
00174            c1=((samples[i])  & (0xff));             // get lowest byte
00175            c2=((samples[i]>>8) & (0xff));
00176            c3=((samples[i]>>16) & (0xff));          // get highest byte
00177        //   if ( ((samples[i]>>24) & (0x80))==(0x80)) c3=c3+(0x80); // set highest bit (number is negative)
00178          }
00179          else {
00180            c1=((samples[i])  & (0xff));             // get lowest byte
00181            c2=((samples[i]>>8) & (0xff));
00182            if ((samples[i]>>16) & (0x80)) c2=c2+(0x80); // set highest bit (number is negative)
00183          }
00184          
00185          rprintf(" Sample: %d c1: %d c2: %d c3: %d \n",samples[i],c1,c2,c3);
00186          writeSampleBuffer(i-3,frameCount,c1,c2,c3);    
00187         }
00188         frameCount += 1;
00189         if (frameCount==cfg.chan[0].sampleCount) {
00190          writeBufferToFile();
00191         }
00192 }
00193 
00194 
00195 
00196 
00200 int isANumber(const char *str) {
00201         int i;
00202         for (i = 0; str[i]; ++i)
00203                 if ( (!isdigit(str[i])) && (!(str[i]=='-')) )
00204                         return 0;
00205         return 1;
00206 }
00207 
00210 void serverDied(void)
00211 {
00212         rprintf("Server died!\n");
00213         exit(1);
00214 }
00215 
00216 
00217 
00218 int main(int argc, char **argv)
00219 {
00220         char EDFPacket[MAXHEADERLEN];   
00221         char cmdbuf[80];
00222         int EDFLen = MAXHEADERLEN;
00223         FILE *fp;
00224         fd_set toread;
00225         int linePos = 0;
00226         int i;
00227         double tStart;
00228         sock_t sock_fd;
00229         int retval;
00230 
00231         strcpy(opts.hostname, DEFAULTHOST);
00232         opts.port = DEFAULTPORT;
00233         opts.isBdf=0;
00234         opts.seconds=100000;
00235         for (i = 1; i < argc; ++i) {
00236                 char *opt = argv[i];
00237                 if (opt[0] == '-') {
00238                         switch (opt[1]) {
00239                                 case 'h':
00240                                         printf("%s", helpText);
00241                                         exit(0);
00242                                         break;
00243                                 case 's':
00244                                         opts.seconds = atof(argv[i+1]);
00245                                         opts.isLimittedTime = 1;
00246                                         i += 1;
00247                                         break;
00248                                 case 'e':
00249                                         opts.eegNum = atoi(argv[i+1]);
00250                                         i += 1;
00251                                         break;
00252                                 case 'n':
00253                                         strcpy(opts.hostname, argv[i+1]);
00254                                         i += 1;
00255                                         break;
00256                                 case 'p':
00257                                         opts.port = atoi(argv[i+1]);
00258                                         i += 1;
00259                                         break;
00260                                 case 'b':
00261                                         opts.isBdf=1;
00262                                         break;                                  
00263                                 case 'c':
00264                                         opts.isArray=1;
00265                                         break;                                  
00266                                 }
00267                         }
00268                 else {
00269                         if (opts.isFilenameSet) {
00270                                 fprintf(stderr, "Error: only one edf file allowed: %s and %s\n",
00271                                                 opts.filename, argv[i]);
00272                                 exit(1);
00273                         }
00274                         strcpy(opts.filename, argv[i]);
00275                         opts.isFilenameSet = 1;
00276                 }
00277         }
00279         if (!opts.isFilenameSet) {
00280                 fprintf(stderr, "Must supply the filename of the EDF to write.\n");
00281                 exit(1);
00282         }
00284         fp = fopen(opts.filename, "wb");
00285         assert(fp != NULL && "Cannot open file!");
00286 
00288         rinitNetworking();
00289         sock_fd = rsocket();
00290         if (sock_fd < 0) {
00291                 perror("socket");
00292                 rexit(1);
00293         }
00294 
00295         retval = rconnectName(sock_fd, opts.hostname, opts.port);
00296         if (retval != 0) {
00297                 rprintf("connect error\n");
00298                 rexit(1);
00299         }
00300 
00301         rprintf("Socket connected.\n");
00302         fflush(stdout);
00303 
00305         writeString(sock_fd, "display\n", &ob);
00306         getOK(sock_fd, &ib);
00307         rprintf("Finished display, doing getheader.\n");
00308         sprintf(cmdbuf, "getheader %d\n", opts.eegNum);
00309         writeString(sock_fd, cmdbuf, &ob);
00310         getOK(sock_fd, &ib);
00311         if (isEOF(sock_fd, &ib))
00312                 serverDied();
00313         EDFLen = readline(sock_fd, EDFPacket, sizeof(EDFPacket), &ib);
00314         rprintf("Got EDF Header <%s>\n", EDFPacket);
00315         
00317         readEDFString(&cfg, EDFPacket, EDFLen);
00319         if ( (cfg.hdr.dataFormat[0]=='2') && (cfg.hdr.dataFormat[1]=='4') ) {
00320          opts.isBdf=1;
00321          rprintf("24bit data format auto detected \n");
00322         }
00323         rprintf("Header Record bytes: %d \n",cfg.hdr.headerRecordBytes);
00324         
00326         if (opts.isArray==0) fwrite(EDFPacket, 1, cfg.hdr.headerRecordBytes, fp);
00327         fclose(fp);
00328         
00329         initSampleBuffer();
00330         rprintf("Now sending watch command \n");        
00331         sprintf(cmdbuf, "watch %d\n", opts.eegNum);
00332         writeString(sock_fd, cmdbuf, &ob);
00333         getOK(sock_fd, &ib);
00334         tStart = pctimer();
00335         FD_ZERO(&toread);
00336         FD_SET(sock_fd, &toread);
00337         rprintf("Starting data read loop \n");
00338         while ( (tStart+opts.seconds) > pctimer() ) {
00339                         char *cur;
00340                         int curParam = 0;
00341                         int packetCounter=0, channels=0;
00342                         rselect(sock_fd+1, &toread, NULL, NULL);
00343                         linePos = readline(sock_fd, lineBuf, sizeof(EDFPacket), &ib);
00344                         if (isEOF(sock_fd, &ib)) {
00345                          rprintf("EOF sock_fd \n");
00346                          break;
00347                         }
00348                         if (linePos < MINLINELENGTH)
00349                                 continue;
00350                         if (lineBuf[0] != '!')
00351                                 continue;
00352                         curParam=0;     
00353                         for (cur = strtok(lineBuf, DELIMS); cur ; cur = strtok(NULL, DELIMS)) {
00354                                 if (isANumber(cur)){
00355                                  samples[curParam]=atol(cur);
00356                                  rprintf("Nr.: %d \t Wert:  %d \t \n",curParam,samples[curParam]);
00357                                  curParam++;
00358                                 }
00359                         }
00361                         if (curParam < 3)
00362                                 continue;
00363                         packetCounter=samples[1];       
00364                         channels=samples[2];    
00365                         rprintf("got samples, channels: %d \t packetCounter: %d \n",channels,packetCounter);
00366                         handleSamples(packetCounter,channels);
00367                 }
00368                 
00369                 
00370         rprintf("Ending data read loop \n");
00371 
00372         return 0;
00373 }

Generated on Tue Feb 8 00:05:17 2005 for Neuroserver by doxygen 1.3.3