// -------------------------------------------------------------------------- // // main.cpp -- does the gui, handles the calls to the sercomm stuff // // -------------------------------------------------------------------------- #include #include "main.h" #include "comm.h" // -------------------------------------------------------------------------- // Various parameters defining the layout of the GUI int WIN_W; int WIN_H; int INFO_W = 190; int INFO_H = 160; int INFO_Y = 110; int SPC = 6; int LBL_H = 20; int LBL_W = 70; int EXIT_W = 75; int EXIT_H = 25; int WLBL_H = 15; int WLBL_W = 250; int CLR_W = 58; int CLR_H = 18; int SU_H = 200; int CHT_H = INFO_H+LBL_H+CLR_H+2*SPC; int CHT_W = 500; int FILE_W = 58; int FILE_H = 18; // Flags for checking if: int PORTS_ASSIGNED; // the ports have been assigned (can't poll unless they have) int poll=0; // are we polling? // The GUI Objects Fl_Window *window; Fl_Browser *gsr, *hr, *eb, *status; Fl_Output *gsr_port, *hr_port, *eb_port; Fl_Button *poll_butt; Fl_Button *gsr_file_butt; Fl_Chart *gsr_cht, *hr_cht, *eb_cht; int file_set = 0; // flags for checking if output filename is set int file_out = 0; // flags for checking if we're writing out to file const char *fname; // filename pointers HANDLE gsr_file, hr_file, eb_file; // file pointers int gsr_max = 0, gsr_min = 64000; char str[400]; double gsr_writetime_diff = 0; double gsr_readtime_diff = 0; double gsr_interval_err = 0; double gsr_last_readtime = 0; double gsr_last_writetime = 0; int gsr_count = 0; int gsr_first = 1; // --------------------------------------------------------------------------------- void exit_cb (Fl_Widget *, void *) { file_quit(); exit(0); } // Clear the debugging windows void clear_status_cb(Fl_Widget *, void *) { status->clear(); } void clear_gsr_cb (Fl_Widget *, void *) { gsr->clear(); gsr_cht->clear(); } void clear_hr_cb (Fl_Widget *, void *) { hr->clear(); hr_cht->clear();} void clear_eb_cb (Fl_Widget *, void *) { eb->clear(); eb_cht->clear();} // Print out the error in the GSR interval void info_cb (Fl_Widget *, void *) { write(0,"Mean GSR:"); sprintf(str,"readtime diff: %14.8f",gsr_readtime_diff/(1.0*gsr_count)); write(0,str); sprintf(str,"writetime diff: %14.8f",gsr_writetime_diff/(1.0*gsr_count)); write(0,str); sprintf(str,"interval err: %14.8f",gsr_interval_err/(1.0*gsr_count)); write(0,str); } // Get files to write out to. void set_outfile_cb (Fl_Widget *, void *) { char fn[300]; file_set = 0; while (!file_set) { fname = fl_input("Enter the file name (prefix) for the output file(s):"); sprintf(fn,"Data%\\%s-gsr.txt",fname); // uses directory "Data" in current path (ideally, I should check that \Data exists) gsr_file = CreateFile(fn, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); // assuming that if the gsr file exists, so does the hr and eb files if (gsr_file == INVALID_HANDLE_VALUE) { if (fl_ask("File Exists, Overwrite?")) { sprintf(fn,"Data%\\%s-gsr.txt",fname); gsr_file = CreateFile(fn, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); sprintf(str,"Opened file: %s",fn); write(1,str); sprintf(fn,"Data%\\%s-hr.txt",fname); hr_file = CreateFile(fn, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); sprintf(str,"Opened file: %s",fn); write(2,str); sprintf(fn,"Data%\\%s-eb.txt",fname); eb_file = CreateFile(fn, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); sprintf(str,"Opened file: %s-",fn); write(3,str); file_set = 1; } } else { sprintf(str,"Opened file: %s",fn); write(1,str); sprintf(fn,"Data%\\%s-hr.txt",fname); hr_file = CreateFile(fn, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); sprintf(str,"Opened file: %s",fn); write(2,str); sprintf(fn,"Data%\\%s-eb.txt",fname); eb_file = CreateFile(fn, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); sprintf(str,"Opened file: %s-",fn); write(3,str); file_set = 1; } } } // Handles the "output" button that determines if we're writing to file or not void do_output_cb (Fl_Widget *, void *) { if (!file_set) set_outfile_cb (NULL,NULL); // make sure filename is set file_out = file_out?0:1; // set flag so stuff gets dumped to file } // Handle all calculations to write out to file. Note that the HR and EB functions are stubbed out. void write_to_file (int which, int value, int interval, double writetime, double readtime) { char str[400]; DWORD bytesWritten; sprintf(str,"out: %i %i %.3f %.3f", value,interval/1000,readtime, writetime); //write(which,str); if (file_out) { sprintf(str,"%10i %10.4f %20.9f %20.9f%c%c", value,interval/1000.0,readtime, writetime,13,10); switch (which) { case 1: if (!gsr_first) { gsr_readtime_diff += readtime - gsr_last_readtime; gsr_writetime_diff += writetime - gsr_last_writetime; gsr_interval_err += (interval/1000.0) + (writetime-readtime); gsr_last_readtime = readtime; gsr_last_writetime = writetime; gsr_count++; } else { gsr_last_readtime = readtime; gsr_last_writetime = writetime; gsr_first = 0; } if (!WriteFile(gsr_file, str, strlen(str), &bytesWritten, NULL)) write(1,"File write failed."); break; case 2: if (!WriteFile(hr_file, str, strlen(str), &bytesWritten, NULL)) write(2,"File write failed."); break; case 3: if (!WriteFile(eb_file, str, strlen(str), &bytesWritten, NULL)) write(3,"File write failed."); break; } } } // Handle file cleanup void file_quit (void) { if (file_set) { CloseHandle(gsr_file); CloseHandle(hr_file); CloseHandle(eb_file); } } void ap_cb (Fl_Widget *, void *) { if (assign_ports()) { write(0,""); PORTS_ASSIGNED=1; } } void poll_cb (Fl_Widget *, void *) { if (PORTS_ASSIGNED) { if (poll==0) { poll=1; polling(); } else poll=0; } else write(0,"Ports not assigned."); } // Draw the data points on the different graphs void graph(int i, float val) { switch (i) { case 1: gsr_cht->add(val,NULL,FL_BLUE); if (val > gsr_max) gsr_max = (int) val; if (val < gsr_min) gsr_min = (int) val; gsr_cht->bounds(gsr_min, gsr_max); break; case 2: hr_cht->add(val,NULL,FL_RED); break; case 3: eb_cht->add(val,NULL,FL_GREEN); break; default: break; } Fl::check(); } // Prints to the different debugging windows. void write(int i, char *str) { switch (i) { case 0: status->add(str); status->bottomline(status->size()); break; case 1: gsr->add(str); gsr->bottomline(gsr->size()); break; case 2: hr->add(str); hr->bottomline(hr->size()); break; case 3: eb->add(str); eb->bottomline(eb->size()); break; default: break; } Fl::check(); } // Check for GUI events int do_ui_check(void) { Fl::check(); if (poll) return 1; else return 0; } // Set the label saying which port a device is on. void update_label (int i, char *str) { switch (i) { case 1: gsr_port->value(str); gsr_port->textfont(FL_HELVETICA_BOLD); break; case 2: hr_port->value(str); hr_port->textfont(FL_HELVETICA_BOLD); break; case 3: eb_port->value(str); eb_port->textfont(FL_HELVETICA_BOLD); break; default: break; } Fl::check(); } // The main procedure for drawing the GUI. See www.fltk.org for details on using the fltk elements. void setup_window (void) { int y=0, x=0; WIN_W = CHT_W + 2*INFO_W + 10*SPC; WIN_H = 8*SPC + WLBL_H + 3*(5*SPC+LBL_H+INFO_H+CLR_H) +EXIT_H; window = new Fl_Window(WIN_W, WIN_H); x+=2*SPC; y+=2*SPC; Fl_Box *win_label = new Fl_Box(x,y, WLBL_W, WLBL_H, "Physiological Monitoring Serial Comm"); y+=WLBL_H+3*SPC; win_label->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); win_label->labelsize(24); Fl_Box *s = new Fl_Box(FL_DOWN_BOX, x,y, INFO_W+2*SPC, 3*(5*SPC+LBL_H+INFO_H+CLR_H)+CLR_H,""); x+=SPC; y+=SPC; Fl_Box *status_label = new Fl_Box(x, y, LBL_W, LBL_H, "Status"); y+=LBL_H+SPC; status = new Fl_Browser(x,y, INFO_W, INFO_H+2*(5*SPC+LBL_H+INFO_H+CLR_H), ""); y+=INFO_H+SPC+2*(5*SPC+LBL_H+INFO_H+CLR_H); Fl_Button *status_clr_butt = new Fl_Button(x,y, CLR_W, CLR_H, "Clear"); x+=SPC+CLR_W; Fl_Button *ap_butt = new Fl_Button(x,y, CLR_W, CLR_H, "&Assign"); x+=SPC+CLR_W; poll_butt = new Fl_Button(x,y, CLR_W, CLR_H, "&Poll"); x-=2*(SPC+CLR_W); y+=SPC+CLR_H; Fl_Button *info_butt = new Fl_Button (x,y, CLR_W,CLR_H, "&Info"); x+=SPC+CLR_W; Fl_Button *gsr_file_butt = new Fl_Button(x,y, FILE_W, FILE_H, "Set File"); x+=SPC+FILE_W; Fl_Button *gsr_output_butt = new Fl_Button(x,y, CLR_W, FILE_H, "Output"); x+=SPC+CLR_W; x+= INFO_W+2*SPC-3*(SPC+CLR_W); y-=3*SPC+LBL_H+INFO_H+SPC+2*(5*SPC+LBL_H+INFO_H+CLR_H)+CLR_H; Fl_Box *g = new Fl_Box(FL_DOWN_BOX, x,y, 4*SPC+INFO_W+CHT_W, 4*SPC+INFO_H+CLR_H+LBL_H, ""); x+=SPC; y+=SPC; Fl_Box *gsr_label = new Fl_Box(x,y, LBL_W, LBL_H, "GSR"); gsr_port = new Fl_Output(x+INFO_W-LBL_W, y, LBL_W, LBL_H, ""); x+=INFO_W+SPC; gsr_cht = new Fl_Chart(x,y, CHT_W, CHT_H, ""); x-=INFO_W+SPC; y+=LBL_H+SPC; gsr = new Fl_Browser(x,y, INFO_W,INFO_H,""); y+=INFO_H+SPC; Fl_Button *gsr_clr_butt = new Fl_Button(x,y, CLR_W, CLR_H, "Clear"); x-=SPC; y+=CLR_H+2*SPC; Fl_Box *h = new Fl_Box(FL_DOWN_BOX, x,y, 4*SPC+INFO_W+CHT_W, 4*SPC+INFO_H+CLR_H+LBL_H, ""); x+=SPC; y+=SPC; Fl_Box *hr_label = new Fl_Box(x,y, LBL_W, LBL_H, "Heart Rate"); hr_port = new Fl_Output(x+INFO_W-LBL_W, y, LBL_W, LBL_H, ""); x+=INFO_W+SPC; hr_cht = new Fl_Chart(x,y, CHT_W, CHT_H, ""); x-=INFO_W+SPC; y+=LBL_H+SPC; hr = new Fl_Browser(x,y, INFO_W,INFO_H,""); y+=INFO_H+SPC; Fl_Button *hr_clr_butt = new Fl_Button(x,y, CLR_W, CLR_H, "Clear"); x-=SPC; y+=CLR_H+2*SPC; Fl_Box *e = new Fl_Box(FL_DOWN_BOX, x,y, 4*SPC+INFO_W+CHT_W, 4*SPC+INFO_H+CLR_H+LBL_H, ""); x+=SPC; y+=SPC; Fl_Box *eb_label = new Fl_Box(x,y, LBL_W, LBL_H, "Blink"); eb_port = new Fl_Output(x+INFO_W-LBL_W, y, LBL_W, LBL_H, ""); x+=INFO_W+SPC; eb_cht = new Fl_Chart(x,y, CHT_W, CHT_H, ""); x-=INFO_W+SPC; y+=LBL_H+SPC; eb = new Fl_Browser(x,y,INFO_W,INFO_H,""); y+=INFO_H+SPC; Fl_Button *eb_clr_butt = new Fl_Button(x,y, CLR_W, CLR_H, "Clear"); x-=SPC+CLR_W; y+=CLR_H+2*SPC; status_label->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); status_label->labelfont(FL_HELVETICA_BOLD); gsr_label->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); gsr_label->labelfont(FL_HELVETICA_BOLD); hr_label->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); hr_label->labelfont(FL_HELVETICA_BOLD); eb_label->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); eb_label->labelfont(FL_HELVETICA_BOLD); gsr_port->value("Unassigned"); gsr_port->textsize(11); hr_port->value("Unassigned"); hr_port->textsize(11); eb_port->value("Unassigned"); eb_port->textsize(11); status->textfont(FL_COURIER); status->textsize(10); gsr->textfont(FL_COURIER); gsr->textsize(9); gsr->add("Waiting..."); hr->textfont(FL_COURIER); hr->textsize(9); hr->add("Waiting..."); eb->textfont(FL_COURIER); eb->textsize(9); eb->add("Waiting..."); status_clr_butt->callback(clear_status_cb); status_clr_butt->labelsize(10); gsr_clr_butt->callback(clear_gsr_cb); gsr_clr_butt->labelsize(10); hr_clr_butt->callback(clear_hr_cb); hr_clr_butt->labelsize(10); eb_clr_butt->callback(clear_eb_cb); eb_clr_butt->labelsize(10); gsr_file_butt->callback(set_outfile_cb); gsr_file_butt->labelsize(10); gsr_output_butt->callback(do_output_cb); gsr_output_butt->labelsize(10); gsr_output_butt->type(FL_TOGGLE_BUTTON); info_butt->callback(info_cb); info_butt->labelsize(10); ap_butt->callback(ap_cb); ap_butt->labelsize(10); poll_butt->callback(poll_cb); poll_butt->labelsize(10); poll_butt->type(FL_TOGGLE_BUTTON); gsr_cht->autosize(1); gsr_cht->type(FL_LINE_CHART); gsr_cht->color(FL_WHITE); gsr_cht->maxsize(100); hr_cht->autosize(1); hr_cht->type(FL_LINE_CHART); hr_cht->color(FL_WHITE); hr_cht->maxsize(100); eb_cht->autosize(1); eb_cht->type(FL_SPIKE_CHART); eb_cht->color(FL_WHITE); eb_cht->maxsize(100); hr_cht->bounds(60,160); Fl_Button *exit_butt = new Fl_Button(WIN_W-2*SPC-EXIT_W, WIN_H-2*SPC-EXIT_H, EXIT_W, EXIT_H, "E&xit"); exit_butt->callback(exit_cb); window->end(); } int main (int argc, char **argv) { setup_window(); window->show(argc, argv); PORTS_ASSIGNED = 0; // Originally was going to have control of the main event loop centered here. Instead, the polling procedure // freezes the GUI until it's ready, then calls the update function above. This could be replaced with FL::Run(); while (1) { Fl::check(); } return 0; }