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 }