/ src / hal / utils / scope_files.c
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