00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
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
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
00161
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
00261 if (curParam < 3)
00262 continue;
00263 devNum = vals[0];
00264 packetCounter = vals[1];
00265 channels = vals[2];
00266 samples = vals + 3;
00267
00268
00269
00270 }
00271
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