/ src / hal / components / sampler_usr.c
sampler_usr.c
  1  /********************************************************************
  2  * Description:  sampler_usr.c
  3  *               User space part of "sampler", a HAL component that
  4  *		can be used to sample data from HAL pins and write
  5  *		it to a file at a specific realtime sample rate.
  6  *
  7  * Author: John Kasunich <jmkasunich at sourceforge dot net>
  8  * License: GPL Version 2
  9  *    
 10  * Copyright (c) 2006 All rights reserved.
 11  *
 12  ********************************************************************/
 13  /** This file, 'sampler_usr.c', is the user part of a HAL component
 14      that allows values to be sampled from HAL pins at a uniform 
 15      realtime sample rate, and writes them to a stdout (from which
 16      they can be redirected to a file).  When the realtime module
 17      is loaded, it creates a stream in shared memory and begins capturing
 18      samples to the stream.  Then, the user space program 'hal_ssampler'
 19      is invoked to read from the stream and print to stdout.
 20  
 21      Invoking:
 22  
 23      halsampler [-c chan_num] [-n num_samples] [-t]
 24  
 25      'chan_num', if present, specifies the sampler channel to use.
 26      The default is channel zero.
 27  
 28      'num_samples', if present, specifies the number of samples
 29      to be printed, after which the program will exit.  If ommitted
 30      it will print continuously until killed.
 31  
 32      '-t' tells sampler to print the sample number at the start
 33      of each line.
 34  
 35  */
 36  
 37  /** This program is free software; you can redistribute it and/or
 38      modify it under the terms of version 2 of the GNU General
 39      Public License as published by the Free Software Foundation.
 40      This library is distributed in the hope that it will be useful,
 41      but WITHOUT ANY WARRANTY; without even the implied warranty of
 42      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 43      GNU General Public License for more details.
 44  
 45      You should have received a copy of the GNU General Public
 46      License along with this library; if not, write to the Free Software
 47      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 48  
 49      THE AUTHORS OF THIS LIBRARY ACCEPT ABSOLUTELY NO LIABILITY FOR
 50      ANY HARM OR LOSS RESULTING FROM ITS USE.  IT IS _EXTREMELY_ UNWISE
 51      TO RELY ON SOFTWARE ALONE FOR SAFETY.  Any machinery capable of
 52      harming persons must have provisions for completely removing power
 53      from all motors, etc, before persons enter any danger area.  All
 54      machinery must be designed to comply with local and national safety
 55      codes, and the authors of this software can not, and do not, take
 56      any responsibility for such compliance.
 57  
 58      This code was written as part of the EMC HAL project.  For more
 59      information, go to www.linuxcnc.org.
 60  */
 61  
 62  #include <stdio.h>
 63  #include <stdlib.h>
 64  #include <ctype.h>
 65  #include <string.h>
 66  #include <unistd.h>
 67  #include <signal.h>
 68  #include <time.h>
 69  #include <sys/types.h>
 70  #include <sys/stat.h>
 71  #include <fcntl.h>
 72  
 73  #include "rtapi.h"		/* RTAPI realtime OS API */
 74  #include "hal.h"                /* HAL public API decls */
 75  #include "streamer.h"
 76  
 77  /***********************************************************************
 78  *                  LOCAL FUNCTION DECLARATIONS                         *
 79  ************************************************************************/
 80  
 81  /***********************************************************************
 82  *                         GLOBAL VARIABLES                             *
 83  ************************************************************************/
 84  
 85  int comp_id = -1;	/* -1 means hal_init() not called yet */
 86  int shmem_id = -1;
 87  int exitval = 1;	/* program return code - 1 means error */
 88  int ignore_sig = 0;	/* used to flag critical regions */
 89  char comp_name[HAL_NAME_LEN+1];	/* name for this instance of sampler */
 90  
 91  /***********************************************************************
 92  *                            MAIN PROGRAM                              *
 93  ************************************************************************/
 94  
 95  /* signal handler */
 96  static sig_atomic_t stop;
 97  static void quit(int sig)
 98  {
 99      if ( ignore_sig ) {
100  	return;
101      }
102      stop = 1;
103  }
104  
105  #define BUF_SIZE 4000
106  
107  int main(int argc, char **argv)
108  {
109      int n, channel, tag;
110      long int samples;
111      unsigned this_sample, last_sample=0;
112      char *cp, *cp2;
113      hal_stream_t stream;
114  
115      /* set return code to "fail", clear it later if all goes well */
116      exitval = 1;
117      channel = 0;
118      tag = 0;
119      samples = -1;  /* -1 means run forever */
120      /* FIXME - if I wasn't so lazy I'd learn how to use getopt() here */
121      for ( n = 1 ; n < argc ; n++ ) {
122  	cp = argv[n];
123  	if ( *cp != '-' ) {
124  	    break;
125  	}
126  	switch ( *(++cp) ) {
127  	case 'c':
128  	    if (( *(++cp) == '\0' ) && ( ++n < argc )) { 
129  		cp = argv[n];
130  	    }
131  	    channel = strtol(cp, &cp2, 10);
132  	    if (( *cp2 ) || ( channel < 0 ) || ( channel >= MAX_SAMPLERS )) {
133  		fprintf(stderr,"ERROR: invalid channel number '%s'\n", cp );
134  		exit(1);
135  	    }
136  	    break;
137  	case 'n':
138  	    if (( *(++cp) == '\0' ) && ( ++n < argc )) { 
139  		cp = argv[n];
140  	    }
141  	    samples = strtol(cp, &cp2, 10);
142  	    if (( *cp2 ) || ( samples < 0 )) {
143  		fprintf(stderr, "ERROR: invalid sample count '%s'\n", cp );
144  		exit(1);
145  	    }
146  	    break;
147  	case 't':
148  	    tag = 1;
149  	    break;
150  	default:
151  	    fprintf(stderr,"ERROR: unknown option '%s'\n", cp );
152  	    exit(1);
153  	    break;
154  	}
155      }
156      if(n < argc) {
157  	int fd;
158  	if(argc > n+1) {
159  	    fprintf(stderr, "ERROR: At most one filename may be specified\n");
160  	    exit(1);
161  	}
162  	// make stdout be the named file
163  	fd = open(argv[n], O_WRONLY | O_CREAT, 0666);
164  	close(1);
165  	dup2(fd, 1);
166      }
167      /* register signal handlers - if the process is killed
168         we need to call hal_exit() to free the shared memory */
169      signal(SIGINT, quit);
170      signal(SIGTERM, quit);
171      signal(SIGPIPE, quit);
172      /* connect to HAL */
173      /* create a unique module name, to allow for multiple samplers */
174      snprintf(comp_name, sizeof(comp_name), "halsampler%d", getpid());
175      /* connect to the HAL */
176      ignore_sig = 1;
177      comp_id = hal_init(comp_name);
178      ignore_sig = 0;
179      /* check result */
180      if (comp_id < 0) {
181  	fprintf(stderr, "ERROR: hal_init() failed: %d\n", comp_id );
182  	goto out;
183      }
184      hal_ready(comp_id);
185      int res = hal_stream_attach(&stream, comp_id, SAMPLER_SHMEM_KEY+channel, 0);
186      if (res < 0) {
187  	errno = -res;
188  	perror("hal_stream_attach");
189  	goto out;
190      }
191      int num_pins = hal_stream_element_count(&stream);
192      while ( samples != 0 ) {
193  	union hal_stream_data buf[num_pins];
194  	hal_stream_wait_readable(&stream, &stop);
195  	if(stop) break;
196  	int res = hal_stream_read(&stream, buf, &this_sample);
197  	if (res < 0) {
198  	    errno = -res;
199  	    perror("hal_stream_read");
200  	    goto out;
201  	}
202  	++last_sample;
203  	if ( this_sample != last_sample ) {
204  	    printf ( "overrun\n");
205  	    last_sample = this_sample;
206  	}
207  	if ( tag ) {
208  	    printf ( "%d ", this_sample-1 );
209  	}
210  	for ( n = 0 ; n < num_pins; n++ ) {
211  	    switch ( hal_stream_element_type(&stream, n) ) {
212  	    case HAL_FLOAT:
213  		printf ( "%f ", buf[n].f);
214  		break;
215  	    case HAL_BIT:
216  		if ( buf[n].b ) {
217  		    printf ( "1 " );
218  		} else {
219  		    printf ( "0 " );
220  		}
221  		break;
222  	    case HAL_U32:
223  		printf ( "%lu ", (unsigned long)buf[n].u);
224  		break;
225  	    case HAL_S32:
226  		printf ( "%ld ", (long)buf[n].s);
227  		break;
228  	    default:
229  		/* better not happen */
230  		goto out;
231  	    }
232  	}
233  	printf ( "\n" );
234  	if ( samples > 0 ) {
235  	    samples--;
236  	}
237      }
238      /* run was succesfull */
239      exitval = 0;
240  
241  out:
242      ignore_sig = 1;
243      hal_stream_detach(&stream);
244      if ( comp_id >= 0 ) {
245  	hal_exit(comp_id);
246      }
247      return exitval;
248  }