scope_files.c
1 /** This file, 'scope_files.c', handles file I/O for halscope. 2 It includes code to save and restore front panel setups, 3 and a clunky way to save captured scope data. 4 */ 5 6 /** Copyright (C) 2003 John Kasunich 7 <jmkasunich AT users DOT sourceforge DOT net> 8 */ 9 10 /** This program is free software; you can redistribute it and/or 11 modify it under the terms of version 2 of the GNU General 12 Public License as published by the Free Software Foundation. 13 This library is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public 19 License along with this library; if not, write to the Free Software 20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 22 THE AUTHORS OF THIS LIBRARY ACCEPT ABSOLUTELY NO LIABILITY FOR 23 ANY HARM OR LOSS RESULTING FROM ITS USE. IT IS _EXTREMELY_ UNWISE 24 TO RELY ON SOFTWARE ALONE FOR SAFETY. Any machinery capable of 25 harming persons must have provisions for completely removing power 26 from all motors, etc, before persons enter any danger area. All 27 machinery must be designed to comply with local and national safety 28 codes, and the authors of this software can not, and do not, take 29 any responsibility for such compliance. 30 31 This code was written as part of the EMC HAL project. For more 32 information, go to www.linuxcnc.org. 33 */ 34 35 #include <sys/types.h> 36 #include <unistd.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <signal.h> 40 #include <ctype.h> 41 #include <string.h> 42 43 #include "rtapi.h" /* RTAPI realtime OS API */ 44 #include "hal.h" /* HAL public API decls */ 45 46 #include <gtk/gtk.h> 47 #include "miscgtk.h" /* generic GTK stuff */ 48 #include "scope_usr.h" /* scope related declarations */ 49 50 /*********************************************************************** 51 * DOCUMENTATION * 52 ************************************************************************/ 53 54 /* Scope setup is stored in the form of a script containing commands 55 that set various parameters. 56 57 Each command consists of a keyword followed by one or more values. 58 Keywords are not case sensitive. 59 */ 60 61 /* 62 THREAD <string> name of thread to sample in 63 MAXCHAN <int> 1,2,4,8,16, maxumum channel count 64 HMULT <int> multiplier, sample every N runs of thread 65 HZOOM <int> 1-9, horizontal zoom setting 66 HPOS <float> 0.0-1.0, horizontal position setting 67 CHAN <int> sets channel for subsequent commands 68 PIN <string> named pin becomes source for channel 69 PARAM <string> named parameter becomes source for channel 70 SIG <string> named signal becomes source for channel 71 CHOFF disables selected channel 72 VSCALE <int> vertical scaling 73 VPOS <float> 0.0-1.0, vertical position setting 74 VOFF <float> vertical offset 75 VAC <float> vertical offset with AC coupling 76 TSOURCE <int> channel number for trigger source 77 TLEVEL <float> 0.0-1.0, trigger level setting 78 TPOS <float> 0.0-1.0, trigger position setting 79 TPOLAR <enum> triger polarity, RISE or FALL 80 TMODE <int> 0 = normal trigger, 1 = auto trigger 81 RMODE <int> 0 = stop, 1 = norm, 2 = single, 3 = roll 82 83 */ 84 85 86 /*********************************************************************** 87 * TYPEDEFS AND DEFINES * 88 ************************************************************************/ 89 90 typedef enum { 91 INT, 92 FLOAT, 93 STRING 94 } arg_type_t; 95 96 typedef struct { 97 const char* name; 98 arg_type_t arg_type; 99 char * (*handler)(void *arg); 100 } cmd_lut_entry_t; 101 102 103 /*********************************************************************** 104 * GLOBAL VARIABLES * 105 ************************************************************************/ 106 107 108 109 /*********************************************************************** 110 * LOCAL FUNCTION PROTOTYPES * 111 ************************************************************************/ 112 113 static int parse_command(char *in); 114 /* the following functions implement halscope config items 115 each is called with a pointer to a single argument (the parser 116 used here allows only one arg per command) and returns NULL if 117 the command succeeded, or an error message if it failed. 118 */ 119 static char *dummy_cmd(void * arg); 120 static char *thread_cmd(void * arg); 121 static char *maxchan_cmd(void * arg); 122 static char *hzoom_cmd(void * arg); 123 static char *hpos_cmd(void * arg); 124 static char *hmult_cmd(void * arg); 125 static char *chan_cmd(void * arg); 126 static char *choff_cmd(void * arg); 127 static char *pin_cmd(void * arg); 128 static char *sig_cmd(void * arg); 129 static char *param_cmd(void * arg); 130 static char *vscale_cmd(void * arg); 131 static char *vpos_cmd(void * arg); 132 static char *voff_cmd(void * arg); 133 static char *voff_ac_cmd(void * arg); 134 static char *tsource_cmd(void * arg); 135 static char *tlevel_cmd(void * arg); 136 static char *tpos_cmd(void * arg); 137 static char *tpolar_cmd(void * arg); 138 static char *tmode_cmd(void * arg); 139 static char *rmode_cmd(void * arg); 140 141 /*********************************************************************** 142 * LOCAL VARIABLES * 143 ************************************************************************/ 144 145 static const cmd_lut_entry_t cmd_lut[25] = 146 { 147 { "thread", STRING, thread_cmd }, 148 { "maxchan", INT, maxchan_cmd }, 149 { "hmult", INT, hmult_cmd }, 150 { "hzoom", INT, hzoom_cmd }, 151 { "hpos", FLOAT, hpos_cmd }, 152 { "chan", INT, chan_cmd }, 153 { "choff", INT, choff_cmd }, 154 { "pin", STRING, pin_cmd }, 155 { "sig", STRING, sig_cmd }, 156 { "param", STRING, param_cmd }, 157 { "vscale", INT, vscale_cmd }, 158 { "vpos", FLOAT, vpos_cmd }, 159 { "vac", FLOAT, voff_ac_cmd }, 160 { "voff", FLOAT, voff_cmd }, 161 { "tsource", INT, tsource_cmd }, 162 { "tlevel", FLOAT, tlevel_cmd }, 163 { "tpos", FLOAT, tpos_cmd }, 164 { "tpolar", INT, tpolar_cmd }, 165 { "tmode", INT, tmode_cmd }, 166 { "rmode", INT, rmode_cmd }, 167 { "", 0, dummy_cmd } 168 }; 169 170 static int deferred_channel; 171 172 /*********************************************************************** 173 * PUBLIC FUNCTION CODE * 174 ************************************************************************/ 175 176 int read_config_file (char *filename) 177 { 178 FILE *fp; 179 char cmd_buf[100]; 180 char *cp; 181 int retval; 182 183 deferred_channel = 0; 184 fp = fopen(filename, "r"); 185 if ( fp == NULL ) { 186 fprintf(stderr, "halscope: config file '%s' could not be opened\n", filename ); 187 return -1; 188 } 189 retval = 0; 190 while ( fgets(cmd_buf, 99, fp) != NULL ) { 191 /* remove trailing newline if present */ 192 cp = cmd_buf; 193 while (( *cp != '\n' ) && ( *cp != '\0' )) { 194 cp++; 195 } 196 *cp = '\0'; 197 /* parse and execute the command */ 198 retval += parse_command(cmd_buf); 199 } 200 fclose(fp); 201 if ( retval < 0 ) { 202 fprintf(stderr, "halscope: config file '%s' caused %d warnings\n", filename, -retval ); 203 return -1; 204 } 205 return 0; 206 } 207 208 209 void write_config_file (char *filename) 210 { 211 FILE *fp; 212 213 fp = fopen(filename, "w"); 214 if ( fp == NULL ) { 215 fprintf(stderr, "halscope: config file '%s' could not be created\n", filename ); 216 return; 217 } 218 write_horiz_config(fp); 219 write_vert_config(fp); 220 write_trig_config(fp); 221 /* write run mode */ 222 if (ctrl_usr->run_mode == NORMAL ) { 223 fprintf(fp, "RMODE 1\n" ); 224 } else if ( ctrl_usr->run_mode == SINGLE ) { 225 fprintf(fp, "RMODE 2\n" ); 226 #if 0 /* FIXME - role mode not implemented yet */ 227 } else if ( ctrl_usr->run_mode == ROLL ) { 228 fprintf(fp, "RMODE 3\n" ); 229 #endif 230 } else { 231 /* stop mode */ 232 fprintf(fp, "RMODE 0\n" ); 233 } 234 fclose(fp); 235 } 236 237 /* writes captured data to disk */ 238 239 void write_log_file (char *filename) 240 { 241 scope_data_t *dptr, *start; 242 scope_horiz_t *horiz; 243 int sample_len, chan_num, sample_period_ns, samples, n; 244 char *label[16]; 245 //scope_disp_t *disp; 246 scope_log_t *log; 247 scope_chan_t *chan; 248 hal_type_t type[16]; 249 FILE *fp; 250 251 252 253 fp = fopen(filename, "w"); 254 if ( fp == NULL ) { 255 fprintf(stderr, "ERROR: log file '%s' could not be created\n", filename ); 256 return; 257 } 258 259 /* fill in local variables */ 260 for (chan_num=0; chan_num<16; chan_num++) { 261 chan = &(ctrl_usr->chan[chan_num]); 262 label[chan_num] = chan->name; 263 type[chan_num] = chan->data_type; 264 } 265 /* sample_len is really the number of channels, don't let it fool you */ 266 sample_len = ctrl_shm->sample_len; 267 //disp = &(ctrl_usr->disp); 268 n=0; 269 samples = ctrl_usr->samples*sample_len ; 270 //fprintf(stderr, "maxsamples = %p \n", maxsamples); 271 log = &(ctrl_usr->log); 272 horiz = &(ctrl_usr->horiz); 273 sample_period_ns = horiz->thread_period_ns * ctrl_shm->mult; 274 275 //for testing, this will be a check box or something eventually 276 log->order=INTERLACED; 277 278 /* write data */ 279 fprintf(fp, "Sampling period is %i nSec \n", sample_period_ns ); 280 281 /* point to the first sample in the display buffer */ 282 start = ctrl_usr->disp_buf ; 283 284 switch (log->order) { 285 case INTERLACED: 286 while (n <= samples) { 287 288 for (chan_num=0; chan_num<sample_len; chan_num++) { 289 dptr=start+n; 290 if ((n%sample_len)==0){ 291 fprintf( fp, "\n"); 292 } 293 write_sample( fp, label[chan_num], dptr, type[chan_num]); 294 /* point to next sample */ 295 n++; 296 } 297 } 298 break; 299 case NOT_INTERLACED: 300 for (chan_num=0; chan_num<sample_len; chan_num++) { 301 n=chan_num; 302 while (n <= samples) { 303 dptr=start+n; 304 write_sample( fp, label[chan_num], dptr, type[chan_num]); 305 fprintf( fp, "\n"); 306 /* point to next sample */ 307 n += sample_len; 308 } 309 } 310 break; 311 } 312 313 fclose(fp); 314 fprintf(stderr, "Log file '%s' written.\n", filename ); 315 } 316 317 /* format the data and print it */ 318 void write_sample(FILE *fp, char *label, scope_data_t *dptr, hal_type_t type) 319 { 320 double data_value; 321 switch (type) { 322 case HAL_BIT: 323 if (dptr->d_u8) { 324 data_value = 1.0; 325 } else { 326 data_value = 0.0; 327 }; 328 break; 329 case HAL_FLOAT: 330 data_value = dptr->d_real; 331 break; 332 case HAL_S32: 333 data_value = dptr->d_s32; 334 break; 335 case HAL_U32: 336 data_value = dptr->d_u32; 337 break; 338 default: 339 data_value = 0.0; 340 break; 341 } 342 /*actually write the data to disk */ 343 /* this should look something like CHAN1 1.234 */ 344 fprintf(fp, "%s %+.14f ", label, data_value ); 345 } 346 347 348 /*********************************************************************** 349 * LOCAL FUNCTION CODE * 350 ************************************************************************/ 351 352 static int parse_command(char *in) 353 { 354 int n; 355 char *cp1, *rv; 356 const char *cp2; 357 int arg_int; 358 double arg_float; 359 char *arg_string; 360 361 n = -1; 362 do { 363 cp1 = in; 364 cp2 = cmd_lut[++n].name; 365 /* skip all matching chars */ 366 while (( *cp2 != '\0') && (tolower(*cp1) == *cp2 )) { 367 cp1++; 368 cp2++; 369 } 370 } while ( *cp2 != '\0' ); 371 /* either a match, or zero length name (last entry) */ 372 if ( cp1 == in ) { 373 /* zero length name, last entry, no match */ 374 if ( *in != '#' ) { 375 /* not a comment, must be a mistake */ 376 fprintf (stderr, "halscope: unknown config command: '%s'\n", in ); 377 return -1; 378 } 379 } 380 switch ( cmd_lut[n].arg_type ) { 381 case STRING: 382 while ( isspace(*cp1) ) { 383 cp1++; 384 } 385 arg_string = cp1; 386 /* find and replace newline at end */ 387 while (( *cp1 != '\n' ) && ( *cp1 != '\0' )) { 388 cp1++; 389 } 390 *cp1 = '\0'; 391 /* call command handler, it returns NULL on success, 392 or an error message on failure */ 393 rv = cmd_lut[n].handler(arg_string); 394 break; 395 case FLOAT: 396 arg_float = strtod(cp1, &cp1); 397 rv = cmd_lut[n].handler(&arg_float); 398 break; 399 case INT: 400 arg_int = strtol(cp1, &cp1, 10); 401 rv = cmd_lut[n].handler(&arg_int); 402 break; 403 default: 404 return -1; 405 break; 406 } 407 /* commands return NULL on success, an error msg on fail */ 408 if ( rv != NULL ) { 409 fprintf(stderr, "halscope: %s: '%s'\n", rv, in ); 410 return -1; 411 } 412 return 0; 413 } 414 415 static char *dummy_cmd(void * arg) 416 { 417 return "command not implemented"; 418 } 419 420 static char *thread_cmd(void * arg) 421 { 422 char *name; 423 int rv; 424 425 name = (char *)(arg); 426 rv = set_sample_thread(name); 427 if ( rv < 0 ) { 428 return "could not find thread"; 429 } 430 return NULL; 431 } 432 433 static char *maxchan_cmd(void * arg) 434 { 435 int *argp, rv; 436 437 argp = (int *)(arg); 438 rv = set_rec_len(*argp); 439 if ( rv < 0 ) { 440 return "could not set record length"; 441 } 442 return NULL; 443 } 444 445 static char *hzoom_cmd(void * arg) 446 { 447 int *argp, rv; 448 449 argp = (int *)(arg); 450 rv = set_horiz_zoom(*argp); 451 if ( rv < 0 ) { 452 return "could not set horizontal zoom"; 453 } 454 return NULL; 455 } 456 457 static char *hpos_cmd(void * arg) 458 { 459 double *argp; 460 int rv; 461 462 argp = (double *)(arg); 463 rv = set_horiz_pos(*argp); 464 if ( rv < 0 ) { 465 return "could not set horizontal position"; 466 } 467 return NULL; 468 } 469 470 static char *hmult_cmd(void * arg) 471 { 472 int *argp, rv; 473 474 argp = (int *)(arg); 475 rv = set_horiz_mult(*argp); 476 if ( rv < 0 ) { 477 return "could not set horizontal multiplier"; 478 } 479 return NULL; 480 } 481 482 static char *chan_cmd(void * arg) 483 { 484 int *argp, chan_num, rv; 485 486 argp = (int *)(arg); 487 chan_num = *argp; 488 deferred_channel = 0; 489 rv = set_active_channel(chan_num); 490 switch (rv) { 491 case 0: 492 // successfull return 493 return NULL; 494 case -1: 495 return "illegal channel number"; 496 case -2: 497 return "too many active channels"; 498 case -3: 499 // no source for channel, OK as long as we get 500 // a subsequent command that specifies a source 501 deferred_channel = chan_num; 502 return NULL; 503 default: 504 return "unknown result"; 505 } 506 } 507 508 static char *choff_cmd(void * arg) 509 { 510 int chan_num; 511 512 if ( deferred_channel != 0 ) { 513 deferred_channel = 0; 514 return NULL; 515 } 516 chan_num = ctrl_usr->vert.selected; 517 set_channel_off(chan_num); 518 return NULL; 519 } 520 521 static char *chan_src_cmd(int src_type, char *src_name) 522 { 523 int chan_num, rv; 524 525 if ( deferred_channel == 0 ) { 526 // changing currently active channel 527 chan_num = ctrl_usr->vert.selected; 528 rv = set_channel_source(chan_num, src_type, src_name); 529 } else { 530 // setting source for previously empty channel 531 chan_num = deferred_channel; 532 rv = set_channel_source(chan_num, src_type, src_name); 533 if ( rv == 0 ) { 534 // got a source now, select the channel 535 return chan_cmd(&chan_num); 536 } 537 } 538 if ( rv < 0 ) { 539 return "object not found"; 540 } 541 return NULL; 542 } 543 544 545 static char *pin_cmd(void * arg) 546 { 547 return chan_src_cmd(0, (char *)(arg)); 548 } 549 550 static char *sig_cmd(void * arg) 551 { 552 return chan_src_cmd(1, (char *)(arg)); 553 } 554 555 static char *param_cmd(void * arg) 556 { 557 return chan_src_cmd(2, (char *)(arg)); 558 } 559 560 static char *vscale_cmd(void * arg) 561 { 562 int *argp, rv; 563 564 argp = (int *)(arg); 565 rv = set_vert_scale(*argp); 566 if ( rv < 0 ) { 567 return "could not set vertical scale"; 568 } 569 return NULL; 570 } 571 572 static char *vpos_cmd(void * arg) 573 { 574 double *argp; 575 int rv; 576 577 argp = (double *)(arg); 578 rv = set_vert_pos(*argp); 579 if ( rv < 0 ) { 580 return "could not set vertical position"; 581 } 582 return NULL; 583 } 584 585 static char *voff_cmd(void * arg) 586 { 587 double *argp; 588 int rv; 589 590 argp = (double *)(arg); 591 rv = set_vert_offset(*argp, 0); 592 if ( rv < 0 ) { 593 return "could not set vertical offset"; 594 } 595 return NULL; 596 } 597 598 599 static char *voff_ac_cmd(void * arg) 600 { 601 double *argp; 602 int rv; 603 604 argp = (double *)(arg); 605 rv = set_vert_offset(*argp, 1); 606 if ( rv < 0 ) { 607 return "could not set vertical offset"; 608 } 609 return NULL; 610 } 611 612 static char *tsource_cmd(void * arg) 613 { 614 int *argp, rv; 615 616 argp = (int *)(arg); 617 rv = set_trigger_source(*argp); 618 if ( rv < 0 ) { 619 return "could not set trigger source"; 620 } 621 return NULL; 622 } 623 624 static char *tlevel_cmd(void * arg) 625 { 626 double *argp; 627 int rv; 628 629 argp = (double *)(arg); 630 rv = set_trigger_level(*argp); 631 if ( rv < 0 ) { 632 return "could not set trigger level"; 633 } 634 return NULL; 635 } 636 637 static char *tpos_cmd(void * arg) 638 { 639 double *argp; 640 int rv; 641 642 argp = (double *)(arg); 643 rv = set_trigger_pos(*argp); 644 if ( rv < 0 ) { 645 return "could not set trigger position"; 646 } 647 return NULL; 648 } 649 650 static char *tpolar_cmd(void * arg) 651 { 652 int *argp; 653 int rv; 654 655 argp = (int *)(arg); 656 rv = set_trigger_polarity(*argp); 657 if ( rv < 0 ) { 658 return "could not set trigger polarity"; 659 } 660 return NULL; 661 } 662 663 static char *tmode_cmd(void * arg) 664 { 665 int *argp; 666 int rv; 667 668 argp = (int *)(arg); 669 rv = set_trigger_mode(*argp); 670 if ( rv < 0 ) { 671 return "could not set trigger mode"; 672 } 673 return NULL; 674 } 675 676 static char *rmode_cmd(void * arg) 677 { 678 int *argp; 679 int rv; 680 681 argp = (int *)(arg); 682 rv = set_run_mode(*argp); 683 if ( rv < 0 ) { 684 return "could not set run mode"; 685 } 686 return NULL; 687 } 688