demo/tut3: Removed a couple of unused variables.
[comedilib.git] / comedi_board_info / comedi_board_info.c
1 /*
2    This program reads information about a comedi device and
3    displays the information in a human-readable form.
4  */
5
6 #include <stdio.h>
7 #include <comedilib.h>
8 #include <fcntl.h>
9 #include <unistd.h>
10 #include <stdlib.h>
11 #include <errno.h>
12 #include <string.h>
13
14
15 static char * const default_filename = "/dev/comedi0";
16
17 int verbose = 0;
18
19 static const char * const subdevice_types[]={
20         "unused",
21         "analog input",
22         "analog output",
23         "digital input",
24         "digital output",
25         "digital I/O",
26         "counter",
27         "timer",
28         "memory",
29         "calibration",
30         "processor",
31         "serial digital I/O",
32         "pwm"
33 };
34
35 struct subdev_flag {
36         const char *sdf_define;
37         unsigned int bitmask;
38         const char *description;
39 };
40
41 static struct subdev_flag subdev_flags[] = {
42         {"SDF_MAXDATA",0x0010,"maxdata depends on channel"},
43         {"SDF_FLAGS",0x0020,"flags depend on channel"},
44         {"SDF_RANGETYPE",0x0040,"range type depends on channel"},
45         {"SDF_MODE0",0x0080,"can do mode 0"},
46         {"SDF_MODE1",0x0100,"can do mode 1"},
47         {"SDF_MODE2",0x0200,"can do mode 2"},
48         {"SDF_MODE3",0x0400,"can do mode 3"},
49         {"SDF_MODE4",0x0800,"can do mode 4"},
50         {"SDF_SOFT_CALIBRATED",0x2000,"subdevice uses software calibration"},
51         {"SDF_CMD_WRITE",0x4000,"can do asynchronous output commands"},
52         {"SDF_CMD_READ",0x8000,"can do asynchronous input commands"},
53         {"SDF_READABLE",0x00010000,"subdevice can be read"},
54         {"SDF_WRITABLE",0x00020000,"subdevice can be written"},
55         {"SDF_INTERNAL",0x00040000,"subdevice does not have externally visible lines"},
56         {"SDF_GROUND",0x00100000,"can do aref=ground"},
57         {"SDF_COMMON",0x00200000,"can do aref=common"},
58         {"SDF_DIFF",0x00400000,"aref=diff"},
59         {"SDF_OTHER",0x00800000,"can do aref=other"},
60         {"SDF_DITHER",0x01000000,"can do dithering"},
61         {"SDF_DEGLITCH",0x02000000,"can do deglitching"},
62         {"SDF_MMAP",0x04000000,"can do mmap()"},
63         {"SDF_RUNNING",0x08000000,"subdevice is acquiring data"},
64         {"SDF_LSAMPL",0x10000000,"subdevice uses 32-bit samples for commands"},
65         {"SDF_PACKED",0x20000000,"subdevice can do packed DIO"},
66         {0,0,0}};
67
68 void explain_subdevice_flags(char* padding,unsigned int sf) {
69         int i = 0;
70         while (subdev_flags[i].sdf_define) {
71                 if (sf & subdev_flags[i].bitmask)
72                         printf("%s%s:%s\n",
73                                padding,
74                                subdev_flags[i].sdf_define,
75                                subdev_flags[i].description);
76                 i++;
77         }
78 }
79
80 void unit_to_desc(char *udesc,int unit) {
81         switch(unit) {
82         case UNIT_volt: strcpy(udesc," V"); break;
83         case UNIT_mA: strcpy(udesc," mA"); break;
84         case UNIT_none: strcpy(udesc,""); break; 
85         default: sprintf(udesc," (unknown unit %d)",
86                          unit);
87         }
88 }
89
90
91
92 char *tobinary(char *s,int bits,int n)
93 {
94         int bit=1<<n;
95         char *t=s;
96
97         for(;bit;bit>>=1)
98                 *t++=(bits&bit)?'1':'0';
99         *t=0;
100
101         return s;
102 }
103
104
105 char *cmd_src(int src,char *buf)
106 {
107         buf[0]=0;
108
109         if(src&TRIG_NONE)strcat(buf,"none|");
110         if(src&TRIG_NOW)strcat(buf,"now|");
111         if(src&TRIG_FOLLOW)strcat(buf, "follow|");
112         if(src&TRIG_TIME)strcat(buf, "time|");
113         if(src&TRIG_TIMER)strcat(buf, "timer|");
114         if(src&TRIG_COUNT)strcat(buf, "count|");
115         if(src&TRIG_EXT)strcat(buf, "ext|");
116         if(src&TRIG_INT)strcat(buf, "int|");
117 #ifdef TRIG_OTHER
118         if(src&TRIG_OTHER)strcat(buf, "other|");
119 #endif
120
121         if(strlen(buf)==0){
122                 sprintf(buf,"unknown(0x%08x)",src);
123         }else{
124                 buf[strlen(buf)-1]=0;
125         }
126
127         return buf;
128 }
129
130
131
132 void probe_cmd_generic_timed(comedi_t *it,int s,int n_channels,int freq_for_generic_timed)
133 {
134         comedi_cmd cmd;
135         char buf[100];
136
137         printf("  command structure filled with probe_cmd_generic_timed for %d channels:\n",
138                n_channels);
139         if(comedi_get_cmd_generic_timed(it, s, &cmd, n_channels, 1E9/freq_for_generic_timed)<0){
140                 printf("    not supported\n");
141         }else{
142                 printf("    start: %s %d\n",
143                         cmd_src(cmd.start_src,buf),cmd.start_arg);
144                 printf("    scan_begin: %s %d\n",
145                         cmd_src(cmd.scan_begin_src,buf),cmd.scan_begin_arg);
146                 if (verbose) {
147                         if ((cmd.scan_begin_src == TRIG_TIMER)&&(cmd.scan_begin_arg)) {
148                                 printf("      scan_begin_src = TRIG_TIMER:\n"
149                                        "      The sampling rate is defined per scan\n"
150                                        "      meaning all channels are sampled at\n"
151                                        "      the same time. The maximum sampling rate is f=%d Hz\n",
152                                        (int)(1E9/cmd.scan_begin_arg));}
153                 }
154                 printf("    convert: %s %d\n",
155                         cmd_src(cmd.convert_src,buf),cmd.convert_arg);
156                 if (verbose) {
157                         if ((cmd.convert_src == TRIG_TIMER)&&(cmd.convert_arg)) {
158                                 printf("      convert_src = TRIG_TIMER\n"
159                                        "      The sampling rate is defined per channel\n"
160                                        "      meaning that a multiplexer is being switched from\n"
161                                        "      channel to channel at a maximum rate of %d Hz.\n"
162                                        "      The overall sampling rate needs to be divided\n"
163                                        "      by the number of channels and results in f=%d Hz.\n",
164                                        (int)(1E9/cmd.convert_arg),
165                                        (int)(1E9/cmd.convert_arg/n_channels));
166                         }
167                 }
168                 printf("    scan_end: %s %d\n",
169                         cmd_src(cmd.scan_end_src,buf),cmd.scan_end_arg);
170                 printf("    stop: %s %d\n",
171                         cmd_src(cmd.stop_src,buf),cmd.stop_arg);
172         }
173 }
174
175
176
177 void get_command_stuff(comedi_t *it,int s,int n_chans_for_generic_timed,int freq_for_generic_timed)
178 {
179         comedi_cmd cmd;
180         char buf[100];
181
182         if(comedi_get_cmd_src_mask(it,s,&cmd)<0){
183                 printf("    not supported\n");
184         }else{
185                 printf("    start: %s\n",cmd_src(cmd.start_src,buf));
186                 if (cmd.start_src == TRIG_EXT)
187                         printf("    cmd.start_src allows external trigger (TRIG_EXT),"
188                                "    for example from on input pin at the device.\n");
189                 printf("    scan_begin: %s\n",cmd_src(cmd.scan_begin_src,buf));
190                 printf("    convert: %s\n",cmd_src(cmd.convert_src,buf));
191                 printf("    scan_end: %s\n",cmd_src(cmd.scan_end_src,buf));
192                 printf("    stop: %s\n",cmd_src(cmd.stop_src,buf));
193
194                 probe_cmd_generic_timed(it,s,n_chans_for_generic_timed,freq_for_generic_timed);
195         }
196 }
197
198
199                 
200 int main(int argc,char *argv[])
201 {
202         int i,j;
203         int n_subdevices,type;
204         const char *type_str;
205         int chan,n_chans;
206         int n_ranges;
207         int subdev_flags;
208         comedi_range *rng;
209         comedi_t *it;
210         char *filename = default_filename;
211         char c;
212         char strtmp[16];
213         int n_chans_for_generic_timed = 1;
214         int freq_for_generic_timed = 1E9;
215
216         while (-1 != (c = getopt(argc, argv, "hvn:F:"))) {
217                 switch (c) {
218                 case 'n':
219                         n_chans_for_generic_timed = strtoul(optarg, NULL, 0);
220                         break;
221                 case 'F':
222                         freq_for_generic_timed = strtoul(optarg, NULL, 0);
223                         break;
224                 case 'v':
225                         verbose++;
226                         break;
227                 case 'h':
228                 default:
229                         fprintf(stderr,
230                                 "usage: comedi_board_info [OPTIONS] COMEDI_DEVICE\n"
231                                 "   -n    number of channels for async command (default 1)\n"
232                                 "   -F    probing sampling rate for async command (default 1Ghz)\n"
233                                 "   -v    verbose output\n"
234                                 "   -h    this help screen\n");
235                         exit(1);
236                 }
237         }
238
239         if(optind < argc) {
240                 filename = argv[optind];
241         }
242
243         it = comedi_open(filename);
244         if(!it){
245                 comedi_perror(filename);
246                 exit(1);
247         }
248
249         printf("overall info:\n");
250         printf("  version code: 0x%06x\n", comedi_get_version_code(it));
251         printf("  driver name: %s\n", comedi_get_driver_name(it));
252         printf("  board name: %s\n", comedi_get_board_name(it));
253         printf("  number of subdevices: %d\n", n_subdevices = comedi_get_n_subdevices(it));
254
255         for(i = 0; i < n_subdevices; i++){
256                 printf("subdevice %d:\n",i);
257                 type = comedi_get_subdevice_type(it, i);
258                 if(type < (int)(sizeof(subdevice_types) / sizeof(subdevice_types[0]))){
259                         type_str = subdevice_types[type];
260                 }else{
261                         type_str = "UNKNOWN";
262                 }
263                 printf("  type: %d (%s)\n",type,type_str);
264                 if(type==COMEDI_SUBD_UNUSED)
265                         continue;
266                 subdev_flags = comedi_get_subdevice_flags(it, i);
267                 printf("  flags: 0x%08x\n",subdev_flags);
268                 if (verbose) explain_subdevice_flags("          ",subdev_flags);
269                 n_chans=comedi_get_n_channels(it,i);
270                 printf("  number of channels: %d\n",n_chans);
271                 if(!comedi_maxdata_is_chan_specific(it,i)){
272                         printf("  max data value: %lu\n", (unsigned long)comedi_get_maxdata(it,i,0));
273                 }else{
274                         printf("  max data value: (channel specific)\n");
275                         for(chan=0;chan<n_chans;chan++){
276                                 printf("    chan%d: %lu\n",chan,
277                                         (unsigned long)comedi_get_maxdata(it,i,chan));
278                         }
279                 }
280                 printf("  ranges:\n");
281                 if(!comedi_range_is_chan_specific(it,i)){
282                         n_ranges=comedi_get_n_ranges(it,i,0);
283                         printf("    all chans:");
284                         for(j=0;j<n_ranges;j++){
285                                 rng=comedi_get_range(it,i,0,j);
286                                 unit_to_desc(strtmp,rng->unit);
287                                 printf(" [%g%s,%g%s]",rng->min,strtmp,rng->max,strtmp);
288                         }
289                         printf("\n");
290                 }else{
291                         for(chan=0;chan<n_chans;chan++){
292                                 n_ranges=comedi_get_n_ranges(it,i,chan);
293                                 printf("    chan%d:",chan);
294                                 for(j=0;j<n_ranges;j++){
295                                         rng=comedi_get_range(it,i,chan,j);
296                                         unit_to_desc(strtmp,rng->unit);
297                                         printf(" [%g%s,%g%s]",rng->min,strtmp,rng->max,strtmp);
298                                 }
299                                 printf("\n");
300                         }
301                 }
302                 printf("  command:\n");
303                 if (n_chans_for_generic_timed>n_chans)
304                         n_chans_for_generic_timed = n_chans;
305                 if (n_chans_for_generic_timed<1)
306                         n_chans_for_generic_timed = 1;
307                 if (freq_for_generic_timed > 1E9)
308                         freq_for_generic_timed = 1E9;
309                 if (freq_for_generic_timed < 1)
310                         freq_for_generic_timed = 1;
311                 get_command_stuff(it,i,n_chans_for_generic_timed,freq_for_generic_timed);
312         }
313
314         return 0;
315 }
316