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

main.c

Go to the documentation of this file.
00001 /*
00002 NeuroServer
00003 
00004 A collection of programs to translate between EEG data and TCP network
00005 messages. This is a part of the OpenEEG project, see http://openeeg.sf.net
00006 for details.
00007             
00008 Copyright (C) 2003, 2004 Rudi Cilibrasi (cilibrar@ofb.net)
00009                 
00010 This library is free software; you can redistribute it and/or
00011 modify it under the terms of the GNU Lesser General Public
00012 License as published by the Free Software Foundation; either
00013 version 2.1 of the License, or (at your option) any later version.
00014                                 
00015 This library is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018 Lesser General Public License for more details.
00019                                                 
00020 You should have received a copy of the GNU Lesser General Public
00021 License along with this library; if not, write to the Free Software
00022 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00023 */                                                            
00024 
00025 #include <assert.h>
00026 #include <string.h>
00027 #include <stdlib.h>
00028 #include <openedf.h>
00029 #include <sys/time.h>
00030 #include <pctimer.h>
00031 #include <ctype.h>
00032 #include <nsutil.h>
00033 #include <nsnet.h>
00034 
00035 #include <gtk/gtk.h>
00036 
00037 sock_t sock_fd;
00038 char EDFPacket[MAXHEADERLEN];
00039 GIOChannel *neuroserver;
00040 const char *helpText =
00041 "sampleClient   v 0.34 by Rudi Cilibrasi\n"
00042 "\n"
00043 "Usage:  sampleClient [options]\n"
00044 "\n"
00045 "        -p port          Port number to use (default 8336)\n"
00046 "        -n hostname      Host name of the NeuroCaster server to connect to\n"
00047 "                         (this defaults to 'localhost')\n"
00048 "        -e <intnum>      Integer ID specifying which EEG to log (default: 0)\n"
00049 "The filename specifies the new EDF file to create.\n"
00050 ;
00051 
00052 #define MINLINELENGTH 4
00053 #define DELIMS " \r\n"
00054 
00055 struct Options {
00056         char hostname[MAXLEN];
00057         unsigned short port;
00058         char filename[MAXLEN];
00059         int eegNum;
00060         int isFilenameSet;
00061         int isLimittedTime;
00062         double seconds;
00063 };
00064 
00065 static struct OutputBuffer ob;
00066 struct InputBuffer ib;
00067 char lineBuf[MAXLEN];
00068 int linePos = 0;
00069 
00070 struct Options opts;
00071 
00072 void idleHandler(void);
00073 void initGTKSystem(void);
00074 
00075 int isANumber(const char *str) {
00076         int i;
00077         for (i = 0; str[i]; ++i)
00078                 if (!isdigit(str[i]))
00079                         return 0;
00080         return 1;
00081 }
00082 
00083 void serverDied(void)
00084 {
00085         rprintf("Server died!\n");
00086         exit(1);
00087 }
00088 
00089 int main(int argc, char **argv)
00090 {
00091         char cmdbuf[80];
00092         int EDFLen = MAXHEADERLEN;
00093         struct EDFDecodedConfig cfg;
00094         int i;
00095         double t0;
00096         int retval;
00097         strcpy(opts.hostname, DEFAULTHOST);
00098         opts.port = DEFAULTPORT;
00099         gtk_init (&argc, &argv);
00100         for (i = 1; i < argc; ++i) {
00101                 char *opt = argv[i];
00102                 if (opt[0] == '-') {
00103                         switch (opt[1]) {
00104                                 case 'h':
00105                                         printf("%s", helpText);
00106                                         exit(0);
00107                                         break;
00108                                 case 'e':
00109                                         opts.eegNum = atoi(argv[i+1]);
00110                                         i += 1;
00111                                         break;
00112                                 case 'n':
00113                                         strcpy(opts.hostname, argv[i+1]);
00114                                         i += 1;
00115                                         break;
00116                                 case 'p':
00117                                         opts.port = atoi(argv[i+1]);
00118                                         i += 1;
00119                                         break;
00120                         }
00121                 }
00122                 else {
00123                         fprintf(stderr, "Error: option %s not allowed", argv[i]);
00124                         exit(1);
00125                 }
00126         }
00127         rinitNetworking();
00128 
00129         sock_fd = rsocket();
00130         if (sock_fd < 0) {
00131                 perror("socket");
00132                 rexit(1);
00133         }
00134         rprintf("Got socket.\n");
00135 
00136         retval = rconnectName(sock_fd, opts.hostname, opts.port);
00137         if (retval != 0) {
00138                 rprintf("connect error\n");
00139                 rexit(1);
00140         }
00141 
00142         rprintf("Socket connected.\n");
00143 
00144         writeString(sock_fd, "display\n", &ob);
00145         getOK(sock_fd, &ib);
00146         rprintf("Finished display, doing getheader.\n");
00147         sprintf(cmdbuf, "getheader %d\n", opts.eegNum);
00148         writeString(sock_fd, cmdbuf, &ob);
00149         getOK(sock_fd, &ib);
00150         if (isEOF(sock_fd, &ib))
00151                 serverDied();
00152         EDFLen = readline(sock_fd, EDFPacket, sizeof(EDFPacket), &ib);
00153 //      rprintf("Got EDF Header <%s>\n", EDFPacket);
00154         readEDFString(&cfg, EDFPacket, EDFLen);
00155         sprintf(cmdbuf, "watch %d\n", opts.eegNum);
00156         writeString(sock_fd, cmdbuf, &ob);
00157         getOK(sock_fd, &ib);
00158         t0 = pctimer();
00159         initGTKSystem();
00160 /*      for (;;) {
00161                 idleHandler();
00162         }
00163 */
00164         return 0;
00165 }
00166 
00167 #define VIEWWIDTH 768
00168 #define VIEWHEIGHT 128
00169 #define TOPMARGIN 80
00170 #define MARGIN 160
00171 
00172 #define DRAWINGAREAHEIGHT (TOPMARGIN + VIEWHEIGHT*2 + MARGIN)
00173 
00174 #define UPDATEINTERVAL 64
00175 
00176 GtkWidget *window;
00177 GtkWidget *onscreen;
00178 GdkPixmap *offscreen = NULL;
00179 
00180 static int sampleBuf[2][VIEWWIDTH];
00181 static int readSamples = 0;
00182 
00183 void handleSample(int channel, int val)
00184 {
00185         static int updateCounter = 0;
00186         assert(channel == 0 || channel == 1);
00187         if (!(val >= 0 && val < 1024)) {
00188                 printf("Got bad value: %d\n", val);
00189                 exit(0);
00190         }
00191         if (readSamples == VIEWWIDTH-1)
00192                 memmove(&sampleBuf[channel][0], &sampleBuf[channel][1], 
00193                                      sizeof(int)*(VIEWWIDTH-1));
00194         sampleBuf[channel][readSamples] = val;
00195         if (readSamples < VIEWWIDTH-1 && channel == 1)
00196                 readSamples += 1;
00197         if (updateCounter++ % UPDATEINTERVAL == 0) {
00198                 gtk_widget_draw(onscreen, NULL);
00199         }
00200 }
00201 
00202 static gboolean expose_event( GtkWidget *widget, GdkEventExpose *event )
00203 {
00204         int c, i;
00205         if (offscreen == NULL) {
00206                 offscreen = gdk_pixmap_new(widget->window, VIEWWIDTH, DRAWINGAREAHEIGHT, -1);
00207         }
00208         gdk_draw_rectangle (offscreen,
00209                 onscreen->style->white_gc,
00210                 TRUE,
00211                 0, 0,
00212                 onscreen->allocation.width,
00213                 onscreen->allocation.height);
00214                 for (c = 0; c < 2; ++c) {
00215                                 for (i = 1; i < VIEWWIDTH; ++i) {
00216                                         gdk_draw_line(offscreen, onscreen->style->black_gc,
00217                         i-1, 
00218                                                                         TOPMARGIN + c*(VIEWHEIGHT+MARGIN) + (sampleBuf[c][i-1] * VIEWHEIGHT) / 1024,
00219                         i, 
00220                                                                         TOPMARGIN + c*(VIEWHEIGHT+MARGIN) + (sampleBuf[c][i] * VIEWHEIGHT) / 1024);
00221                                 }
00222                         }
00223   gdk_draw_pixmap(widget->window,
00224                   widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
00225                   offscreen,
00226                   event->area.x, event->area.y,
00227                   event->area.x, event->area.y,
00228                   event->area.width, event->area.height);
00229 
00230   return FALSE;
00231 }
00232 
00233 void idleHandler(void)
00234 {
00235         int i;
00236         char *cur;
00237         int vals[MAXCHANNELS + 5];
00238         int curParam = 0;
00239         int devNum, packetCounter, channels, *samples;
00240 
00241 #ifndef __MINGW32__
00242         fd_set toread;
00243 
00244         FD_ZERO(&toread);
00245         FD_SET(sock_fd, &toread);
00246         updateMaxFd(sock_fd);
00247         rselect(max_fd, &toread, NULL, NULL);
00248 #endif
00249         linePos = readline(sock_fd, lineBuf, sizeof(EDFPacket), &ib);
00250         rprintf("Got line retval=<%d>, <%s>\n", linePos, lineBuf);
00251         if (isEOF(sock_fd, &ib))
00252                 exit(0);
00253         if (linePos < MINLINELENGTH)
00254                 return;
00255         if (lineBuf[0] != '!')
00256                 return;
00257         for (cur = strtok(lineBuf, DELIMS); cur ; cur = strtok(NULL, DELIMS)) {
00258                 if (isANumber(cur))
00259                         vals[curParam++] = atoi(cur);
00260         // <devicenum> <packetcounter> <channels> data0 data1 data2 ...
00261                 if (curParam < 3)
00262                         continue;
00263                 devNum = vals[0];
00264                 packetCounter = vals[1];
00265                 channels = vals[2];
00266                 samples = vals + 3;
00267 //                              for (i = 0; i < channels; ++i) {
00268 //                                      rprintf(" %d", samples[i]);
00269 //                              }
00270         }
00271 //      rprintf("Got sample with %d channels: %d\n", channels, packetCounter);
00272                 for (i = 0; i < 2; ++i)
00273                         handleSample(i, samples[i]);
00274 }
00275 
00276 static gboolean destroy_event( GtkWidget *widget, GdkEventExpose *event )
00277 {
00278         exit(0);
00279 }
00280 
00281 gboolean readHandler(GIOChannel *source, GIOCondition cond, gpointer data)
00282 {
00283         idleHandler();
00284         return TRUE;
00285 }
00286 
00287 void initGTKSystem(void)
00288 {
00289         window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
00290         onscreen = (GtkWidget *) gtk_drawing_area_new();
00291         gtk_drawing_area_size((GtkDrawingArea *) onscreen, 
00292                                            VIEWWIDTH, DRAWINGAREAHEIGHT);
00293         gtk_container_add(GTK_CONTAINER (window), onscreen);
00294         g_signal_connect(G_OBJECT(onscreen), "expose_event", G_CALLBACK(expose_event),NULL );
00295         g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(destroy_event), NULL);
00296         gtk_widget_show(onscreen);
00297         gtk_widget_show(window);
00298     
00299         neuroserver = g_io_channel_unix_new(sock_fd);
00300 
00301         g_io_add_watch(neuroserver, G_IO_IN, readHandler, NULL);
00302 
00303         gtk_main ();
00304 
00305 }
00306 

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