manueller import aus nem CVS checkout (ist eh nur zum testen)
[ds1820tousb.git] / hostsoftware.c
1 /* $Id: hostsoftware.c,v 1.10 2010/07/13 20:12:10 simimeie Exp $
2  * This is the control software for the ds1820-to-usb device that runs
3  * on the USB host to which the device is connected.
4  * You will need libusb and its development headers to compile this.
5  * On Linux, you will usually have to run this as root to be allowed to
6  * access the device, unless you configure udev accordingly.
7  * This is based on powerSwitch.c, included in the reference implementation
8  * from Objective Development Software GmbH for the avrusb library from the
9  * same company.
10  */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <time.h>
16 #include <usb.h>    /* this is libusb, see http://libusb.sourceforge.net/ */
17 #include <sys/socket.h>
18 #include <sys/types.h>
19 #include <netinet/in.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <signal.h>
23 #include <unistd.h>
24 #include <sys/select.h>  /* According to POSIX.1-2001 */
25
26 int verblev = 1;
27 #define VERBPRINT(lev, fmt...) \
28         if (verblev > lev) { \
29           printf(fmt); \
30           fflush(stdout); \
31         }
32 int devicenr = 1;
33 int runinforeground = 0;
34 int restartonerror = 0;
35
36 #define USBDEV_SHARED_VENDOR    0x16C0  /* VOTI */
37 #define USBDEV_SHARED_PRODUCT   0x05DC  /* Obdev's free shared PID */
38 /* Use obdev's generic shared VID/PID pair and follow the rules outlined
39  * in firmware/usbdrv/USBID-License.txt.
40  */
41
42 /* These are the vendor specific SETUP commands implemented by our USB device */
43 #define CMD_ECHO          0  /* echo 2 bytes */
44 #define CMD_STATUS_SHORT  1  /* query device for status */
45 #define CMD_RESCAN        2  /* tell the device to rescan the probe bus */
46 #define CMD_STATUS_LONG   3  /* query device for list of probes and their status */
47 #define CMD_HARDRESET     4  /* reset device and probe bus */
48
49 struct daemondata {
50   unsigned char serial[6];
51   unsigned int port;
52   int fd;
53   time_t lastseen;
54   double lasttemp;
55   unsigned char outputformat[1000];
56   struct daemondata * next;
57 };
58
59 static void usage(char *name)
60 {
61   printf("usage: %s [-v] [-q] [-d n] [-h] command <parameters>\n", name);
62   printf(" -v     more verbose output. can be repeated numerous times.\n");
63   printf(" -q     less verbose output. using this more than once will have no effect.\n");
64   printf(" -d n   Use the n-th device found (default: 1)\n");
65   printf(" -f     relevant for daemon mode only: run in foreground.\n");
66   printf(" -h     show this help\n");
67   printf("Valid commands are:\n");
68   printf(" test     do an echo test with the device\n");
69   printf(" status   query and show device status\n");
70   printf(" rescan   tell the device to rescan its probe bus\n");
71   printf(" reset    tell the device to reset the probe bus and itself\n");
72   printf(" showint  shows 'interrupts' received from the device. These are\n");
73   printf("          not real interrupts, they are USB 'interrupts', and actually\n");
74   printf("          work by polling in regular intervals...\n");
75   printf(" daemon   Daemonize and answer queries. This requires one or more\n");
76   printf("          parameters in the format 'serial:port', where serial is the serial\n");
77   printf("          number of a probe, and port is a TCP port where the data from this\n");
78   printf("          probe is to be served, e.g.: affeaffeaf:31337\n");
79   printf("          optionally, you can give a third parameter, that specifies how the\n");
80   printf("          output to the network should look like, e.g.: affeaffeaf:31337:%%T\n");
81   printf("          Available are: %%S = serial of probe, %%T = temperature,\n");
82   printf("          %%L = last seen timestamp. The default is '%%S %%T'.\n");
83 }
84
85
86 void sigpipehandler(int bla) { /* Dummyhandler for catching the event */
87   return;
88 }
89
90
91 static int  usbGetStringAscii(usb_dev_handle *dev, int index, int langid, char *buf, int buflen)
92 {
93   char    buffer[256];
94   int     rval, i;
95
96   if ((rval = usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) + index, langid, buffer, sizeof(buffer), 1000)) < 0) {
97     return rval;
98   }
99   if (buffer[1] != USB_DT_STRING) {
100     return 0;
101   }
102   if ((unsigned char)buffer[0] < rval) {
103     rval = (unsigned char)buffer[0];
104   }
105   /* lossy conversion to ISO Latin1 */
106   rval /= 2;
107   for (i = 1; i < rval; i++) {
108     if (i > buflen) { /* destination buffer overflow */
109       break;
110     }
111     buf[i-1] = buffer[2 * i];
112     if (buffer[2 * i + 1] != 0) { /* outside of ISO Latin1 range */
113       buf[i-1] = '?';
114     }
115   }
116   buf[i-1] = 0;
117   return i-1;
118 }
119
120
121 static int usbOpenDevice(usb_dev_handle **device, int vendor, char *vendorName, int product, char *productName, int devicerequested)
122 {
123   struct usb_bus      *bus;
124   struct usb_device   *dev;
125   usb_dev_handle      *handle = NULL;
126   static int          didUsbInit = 0;
127   int devicesfound = 0;
128
129   if (!didUsbInit) {
130     didUsbInit = 1;
131     usb_init();
132   }
133   usb_find_busses();
134   usb_find_devices();
135   for (bus = usb_get_busses(); bus; bus = bus->next) {
136     for (dev = bus->devices; dev; dev = dev->next) {
137       if ((dev->descriptor.idVendor == vendor) && (dev->descriptor.idProduct == product)) {
138         char    string[256];
139         int     len;
140         handle = usb_open(dev); /* we need to open the device in order to query strings */
141         if (!handle) {
142           VERBPRINT(1, "Warning: cannot open USB device: %s\n", usb_strerror());
143           continue;
144         }
145         if ((vendorName == NULL) && (productName == NULL)) {  /* name does not matter */
146           /* we found it! */
147           devicesfound++;
148           if (devicesfound == devicerequested) {
149             break;
150           } else {
151             usb_close(handle);
152             handle = NULL;
153             continue;
154           }
155         }
156         /* now check whether the names match: */
157         len = usbGetStringAscii(handle, dev->descriptor.iManufacturer, 0x0409, string, sizeof(string));
158         if (len < 0) {
159           VERBPRINT(1, "Warning: cannot query manufacturer for device: %s\n", usb_strerror());
160         } else {
161           VERBPRINT(3, "seen device from vendor '%s'\n", string);
162           if (strcmp(string, vendorName) == 0) {
163             len = usbGetStringAscii(handle, dev->descriptor.iProduct, 0x0409, string, sizeof(string));
164             if (len < 0) {
165               VERBPRINT(1, "Warning: cannot query product for device: %s\n", usb_strerror());
166             } else {
167               VERBPRINT(3, "seen product '%s'\n", string);
168               if (strcmp(string, productName) == 0) {
169                 devicesfound++;
170                 if (devicesfound == devicerequested) {
171                   break;
172                 }
173               }
174             }
175           }
176           usb_close(handle);
177           handle = NULL;
178         }
179       }
180       if (handle) {
181         break; /* Stop searching */
182       }
183     }
184   }
185   if (handle != NULL) {
186     *device = handle;
187     return 0;
188   }
189   return 1;
190 }
191
192 void dodevicetest(usb_dev_handle * handle)
193 {
194   unsigned char buffer[8];
195   unsigned short int i, v, r;
196   int nBytes;
197   
198   VERBPRINT(0, "Doing device test, this may take some time...\n");
199   /* The test consists of writing 1000 random numbers to the device and checking
200    * the echo. This should discover systematic bit errors (e.g. in bit stuffing).
201    */
202   for (i = 0; i < 1000; i++){
203     VERBPRINT(2, ".");
204     v = rand() & 0xffff;
205     nBytes = usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, CMD_ECHO, v, 0, (char *)buffer, sizeof(buffer), 5000);
206     if (nBytes != 2) {
207       if (nBytes < 0) {
208         fprintf(stderr, "ERROR: USB error: %s\n", usb_strerror());
209       }
210       fprintf(stderr, "ERROR: wrong number of bytes (%d instead of 2) received in iteration %d\n", nBytes, i);
211       fprintf(stderr, "value sent = 0x%x\n", v);
212       exit(1);
213     }
214     r = buffer[0] | (buffer[1] << 8);
215     if (r != v) {
216       fprintf(stderr, "ERROR: data error: received 0x%x instead of 0x%x in iteration %d\n", r, v, i);
217       exit(1);
218     }
219   }
220   VERBPRINT(0, "Test succeeded.\n");
221   exit(0);
222 }
223
224 static uint32_t make32bit(unsigned char * d) {
225   return *((uint32_t *)d);
226 }
227
228 static double maketemp(unsigned char * d) {
229   double res; int32_t t2;
230   t2 = ((d[1] & 0x0F) << 8) + d[0];
231   if (t2 > 0x07FF) { /* Negative temperature */
232     t2 -= 0x1000;
233   }
234   res = (double)t2 * 0.0625L;
235   return res;
236 }
237
238 static void dodevicestatus(usb_dev_handle * handle) {
239   int nBytes; int p; int i;
240   unsigned char buffer[1024]; /* That would be enough for 64 probes... */
241   uint32_t devicetime;
242   unsigned int nprobes;
243   
244   nBytes = usb_control_msg(handle,
245                            USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, CMD_STATUS_SHORT,
246                            0, 0,
247                            (char *)buffer, 8,
248                            5000);
249   if (nBytes < 0) {
250     fprintf(stderr, "ERROR: USB error: %s\n", usb_strerror());
251     exit(1);
252   }
253   if (nBytes != 8) {
254     fprintf(stderr, "ERROR: invalid status received from device (%d bytes)\n", nBytes);
255     exit(1);
256   }
257   printf("Device Version is %02x.%02x\n", buffer[0], buffer[1]);
258   devicetime = make32bit(&buffer[2]);
259   printf("Device time is currently timestamp %u\n", devicetime);
260   nprobes = buffer[6];
261   printf("%u probes supported by device\n", nprobes);
262   if (nprobes >= ((sizeof(buffer)) / 16)) {
263     nprobes = ((sizeof(buffer)) / 16) - 1;
264     printf("Warning: Cannot handle this many probes myself - will only show first %u.\n", buffer[6]);
265   }
266   nBytes = usb_control_msg(handle,
267                            USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, CMD_STATUS_LONG,
268                            0, 0,
269                            (char *)buffer, (nprobes * 16),
270                            5000);
271   if ((nBytes % 16) != 0) {
272     fprintf(stderr, "ERROR: invalid status received from device (%d bytes)\n", nBytes);
273     exit(1);
274   }
275   if (nBytes != (nprobes * 16)) {
276     fprintf(stderr, "WARNING: expected %u probes, got %u.\n", nprobes, (nBytes / 16));
277   }
278   printf("%2s %-12s %2s %10s %10s %-6s\n", "fa", "serial", "fl", "lastseen", "ticksago", "lastvalue");
279   for (p = 0; p < nBytes; p += 16) {
280     printf("%02x ", buffer[p+6]);
281     for (i = 5; i >= 0; i--) {
282       printf("%02x", buffer[p+i]);
283     }
284     if ((buffer[p+7] & 0x01) == 0x01) { /* in USE */
285       printf(" U");
286     } else {
287       printf("  ");
288     }
289     if ((buffer[p+7] & 0x02) == 0x02) { /* Parasite powered */
290       printf("P");
291     } else {
292       printf(" ");
293     }
294     printf(" %10u %10u ", make32bit(&buffer[p+10]),
295                           devicetime - make32bit(&buffer[p+10]));
296     printf("%6.2lf\n", maketemp(&buffer[p+8]));
297   }
298 }
299
300 static void doshowint(usb_dev_handle * handle) {
301   int nBytes; int i;
302   unsigned char buffer[8];
303   
304   printf("Waiting for 'interrupts' from the device - abort with ctrl+c\n");
305   while (1) {
306     nBytes = usb_interrupt_read(handle,
307                                 USB_ENDPOINT_IN | 0x01,
308                                 (char *)buffer, sizeof(buffer),
309                                 0 /* no timeout */ );
310     if (nBytes < 0) {
311       fprintf(stderr, "ERROR: USB error: %s\n", usb_strerror());
312       exit(1);
313     }
314     if (nBytes != 8) {
315       fprintf(stderr, "ERROR: invalid interrupt message received from device (%d bytes instead of 8) - continuing\n", nBytes);
316       continue;
317     }
318     {
319       char tbuf[100];
320       time_t tt;
321       tt = time(NULL);
322       strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %H:%M:%S", localtime(&tt));
323       printf("[%s] ", tbuf);
324     }
325     printf("Data: probeserial='");
326     for (i = 5; i >= 0; i--) {
327       printf("%02x", buffer[i]);
328     }
329     printf("' temp='%6.2lf'\n", maketemp(&buffer[6]));
330   }
331   /* never reached */
332 }
333
334 void logaccess(struct sockaddr * soa, int soalen, char * txt) {
335   struct sockaddr_in * sav4;
336   struct sockaddr_in6 * sav6;
337
338   if (soalen == sizeof(struct sockaddr_in6)) {
339     sav6 = (struct sockaddr_in6 *)soa;
340     if ((sav6->sin6_addr.s6_addr[ 0] == 0)
341      && (sav6->sin6_addr.s6_addr[ 1] == 0)
342      && (sav6->sin6_addr.s6_addr[ 2] == 0)
343      && (sav6->sin6_addr.s6_addr[ 3] == 0)
344      && (sav6->sin6_addr.s6_addr[ 4] == 0)
345      && (sav6->sin6_addr.s6_addr[ 5] == 0)
346      && (sav6->sin6_addr.s6_addr[ 6] == 0)
347      && (sav6->sin6_addr.s6_addr[ 7] == 0)
348      && (sav6->sin6_addr.s6_addr[ 8] == 0)
349      && (sav6->sin6_addr.s6_addr[ 9] == 0)
350      && (sav6->sin6_addr.s6_addr[10] == 0xFF)
351      && (sav6->sin6_addr.s6_addr[11] == 0xFF)) {
352       /* This is really a IPv4 not a V6 access, so log it as
353        * a such. */
354       VERBPRINT(2, "%d.%d.%d.%d\t%s\n", sav6->sin6_addr.s6_addr[12],
355               sav6->sin6_addr.s6_addr[13],
356               sav6->sin6_addr.s6_addr[14],
357               sav6->sin6_addr.s6_addr[15], txt);
358     } else {
359       /* True IPv6 access */
360       VERBPRINT(2, "%x:%x:%x:%x:%x:%x:%x:%x\t%s\n",
361               (sav6->sin6_addr.s6_addr[ 0] << 8) | sav6->sin6_addr.s6_addr[ 1],
362               (sav6->sin6_addr.s6_addr[ 2] << 8) | sav6->sin6_addr.s6_addr[ 3],
363               (sav6->sin6_addr.s6_addr[ 4] << 8) | sav6->sin6_addr.s6_addr[ 5],
364               (sav6->sin6_addr.s6_addr[ 6] << 8) | sav6->sin6_addr.s6_addr[ 7],
365               (sav6->sin6_addr.s6_addr[ 8] << 8) | sav6->sin6_addr.s6_addr[ 9],
366               (sav6->sin6_addr.s6_addr[10] << 8) | sav6->sin6_addr.s6_addr[11],
367               (sav6->sin6_addr.s6_addr[12] << 8) | sav6->sin6_addr.s6_addr[13],
368               (sav6->sin6_addr.s6_addr[14] << 8) | sav6->sin6_addr.s6_addr[15],
369               txt);
370     }
371   } else if (soalen == sizeof(struct sockaddr_in)) {
372     unsigned char brokeni32[4];
373
374     sav4 = (struct sockaddr_in *)soa;
375     brokeni32[0] = (sav4->sin_addr.s_addr & 0xFF000000UL) >> 24;
376     brokeni32[1] = (sav4->sin_addr.s_addr & 0x00FF0000UL) >> 16;
377     brokeni32[2] = (sav4->sin_addr.s_addr & 0x0000FF00UL) >>  8;
378     brokeni32[3] = (sav4->sin_addr.s_addr & 0x000000FFUL) >>  0;
379     VERBPRINT(2, "%d.%d.%d.%d\t%s\n", brokeni32[0], brokeni32[1],
380             brokeni32[2], brokeni32[3], txt);
381   } else {
382     VERBPRINT(2, "!UNKNOWN_ADDRESS_TYPE!\t%s\n", txt);
383   }
384 }
385
386
387 static void printtooutbuf(char * outbuf, int oblen, struct daemondata * dd) {
388   unsigned char * pos = &dd->outputformat[0];
389   while (*pos != 0) {
390     if (*pos == '%') {
391       pos++;
392       if        (*pos == 'S') { /* Serial */
393         int i;
394         for (i = 5; i >= 0; i--) {
395           outbuf += sprintf(outbuf, "%02x", dd->serial[i]);
396         }
397       } else if ((*pos == 'T') || (*pos == 't')) { /* Temperature */
398         if ((dd->lastseen + 60) < time(NULL)) { /* Stale data / no data yet */
399           outbuf += sprintf(outbuf, "%s", "N/A");
400         } else {
401           if (*pos == 'T') { /* fixed width */
402             outbuf += sprintf(outbuf, "%6.2lf", dd->lasttemp);
403           } else { /* variable width. */
404             outbuf += sprintf(outbuf, "%.2lf", dd->lasttemp);
405           }
406         }
407       } else if (*pos == 'r') { /* carriage return */
408         *outbuf = '\r';
409         outbuf++;
410       } else if (*pos == 'n') { /* linefeed / Newline */
411         *outbuf = '\n';
412         outbuf++;
413       } else if (*pos == 'L') { /* Last seen */
414         outbuf += sprintf(outbuf, "%u", (unsigned int)dd->lastseen);
415       } else if (*pos == 0) {
416         *outbuf = 0;
417         return;
418       }
419       pos++;
420     } else {
421       *outbuf = *pos;
422       outbuf++;
423       pos++;
424     }
425   }
426   *outbuf = 0;
427 }
428
429 static void dotryrestart(struct daemondata * dd, char ** argv) {
430   if (restartonerror) {
431     struct daemondata * curdd = dd;
432     while (curdd != NULL) {
433       close(curdd->fd);
434       curdd = curdd->next;
435     }
436     fprintf(stderr, "Will try to restart in %d second(s)...\n", restartonerror);
437     sleep(restartonerror);
438     execv(argv[0], argv);
439   }
440 }
441
442 static void dodaemon(usb_dev_handle * handle, struct daemondata * dd, char ** argv) {
443   fd_set mylsocks;
444   struct daemondata * curdd;
445   struct timeval to;
446   int nBytes;
447   unsigned char buffer[8];
448   int maxfd;
449   int readysocks;
450   
451   while (1) {
452     do {
453       curdd = dd; /* Start from beginning */
454       maxfd = 0;
455       FD_ZERO(&mylsocks);
456       while (curdd != NULL) {
457         FD_SET(curdd->fd, &mylsocks);
458         if (curdd->fd > maxfd) { maxfd = curdd->fd; }
459         curdd = curdd->next;
460       }
461       to.tv_sec = 0; to.tv_usec = 1;
462       if ((readysocks = select((maxfd + 1), &mylsocks, NULL, NULL, &to)) < 0) { /* Error?! */
463         if (errno != EINTR) {
464           perror("ERROR: error on select()");
465           dotryrestart(dd, argv);
466           exit(1);
467         }
468       } else {
469         curdd = dd;
470         while (curdd != NULL) {
471           if (FD_ISSET(curdd->fd, &mylsocks)) {
472             int tmpfd;
473             struct sockaddr_in6 srcad;
474             socklen_t adrlen = sizeof(srcad);
475             tmpfd = accept(curdd->fd, (struct sockaddr *)&srcad, &adrlen);
476             if (tmpfd < 0) {
477               perror("WARNING: Failed to accept() connection");
478             } else {
479               char outbuf[250];
480               printtooutbuf(outbuf, strlen(outbuf), curdd);
481               logaccess((struct sockaddr *)&srcad, adrlen, outbuf);
482               write(tmpfd, outbuf, strlen(outbuf));
483               close(tmpfd);
484             }
485           }
486           curdd = curdd->next;
487         }
488       }
489     } while (readysocks > 0);
490     /* Now check if there is anything available on USB */
491     nBytes = usb_interrupt_read(handle,
492                                 USB_ENDPOINT_IN | 0x01,
493                                 (char *)buffer, sizeof(buffer),
494                                 100 /* short timeout - but can't be shorter, else no data is seen? strange. */ );
495     if (nBytes < 0) { /* error reported by libusb */
496       /* As nice as libusb is, the documentation is just HORROR. And so is
497        * this interface: This is the best way I have found to check if the
498        * error is actually a timeout. I would expect something like an
499        * usb_errno variable one can poll, but no... */
500       if (nBytes != -ETIMEDOUT) {
501         fprintf(stderr, "ERROR: USB error: %s\n", usb_strerror());
502         dotryrestart(dd, argv);
503         exit(1);
504       }
505     } else if (nBytes != 8) { /* No error but wrong number of bytes */
506       fprintf(stderr, "WARNING: invalid interrupt message received from device (%d bytes instead of 8) - continuing\n", nBytes);
507     } else {
508       VERBPRINT(3, "interrupt data received from device %02x%02x%02x%02x%02x%02x ",
509                    buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]);
510       curdd = dd;
511       while (curdd != NULL) {
512         if (memcmp(&curdd->serial[0], &buffer[0], 6) == 0) {
513           /* This belongs here - update! */
514           curdd->lasttemp = maketemp(&buffer[6]);
515           VERBPRINT(3, "temp = %.2f\n", curdd->lasttemp);
516           curdd->lastseen = time(NULL);
517         }
518         curdd = curdd->next;
519       }
520     }
521   }
522   /* never reached */
523 }
524
525 int main(int argc, char ** argv)
526 {
527   usb_dev_handle * handle = NULL;
528   unsigned char buffer[8];
529   int nBytes;
530   int curarg;
531
532   for (curarg = 1; curarg < argc; curarg++) {
533     if        (strcmp(argv[curarg], "-v") == 0) {
534       verblev++;
535     } else if (strcmp(argv[curarg], "-q") == 0) {
536       verblev--;
537     } else if (strcmp(argv[curarg], "-f") == 0) {
538       runinforeground = 1;
539     } else if (strcmp(argv[curarg], "-h") == 0) {
540       usage(argv[0]); exit(0);
541     } else if (strcmp(argv[curarg], "--help") == 0) {
542       usage(argv[0]); exit(0);
543     } else if (strcmp(argv[curarg], "--restartonerror") == 0) {
544       restartonerror++;
545     } else if (strcmp(argv[curarg], "-d") == 0) {
546       curarg++;
547       if (curarg >= argc) {
548         fprintf(stderr, "ERROR: -d requires a numeric parameter >= 1!\n");
549         usage(argv[0]); exit(1);
550       }
551       devicenr = strtoul(argv[curarg], NULL, 10);
552       if (devicenr <= 0) {
553         fprintf(stderr, "ERROR: -d requires a numeric parameter >= 1!\n");
554         usage(argv[0]); exit(1);
555       }
556     } else {
557       /* Unknown - must be the command. */
558       break;
559     }
560   }
561   if (curarg == argc) {
562     fprintf(stderr, "ERROR: No command given!\n");
563     usage(argv[0]);
564     exit(1);
565   }
566   usb_init();
567   if (usbOpenDevice(&handle, USBDEV_SHARED_VENDOR, "www.poempelfox.de", USBDEV_SHARED_PRODUCT, "ds1820tousb", devicenr) != 0) {
568     fprintf(stderr, "ERROR: Could not find the ds1820tousb device nr. %d on the USB.\n", devicenr);
569     exit(1);
570   }
571   if (usb_claim_interface(handle, 0) < 0) {
572     fprintf(stderr, "ERROR: Failed to claim ds1820tousb device nr. %d on the USB: %s\n", devicenr, usb_strerror());
573     exit(1);
574   }
575   if        (strcmp(argv[curarg], "test") == 0) {
576     dodevicetest(handle);
577   } else if (strcmp(argv[1], "status") == 0) {
578     dodevicestatus(handle);
579   } else if (strcmp(argv[curarg], "rescan") == 0) {
580     nBytes = usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, CMD_RESCAN, 0, 0, (char *)buffer, sizeof(buffer), 5000);
581     if (nBytes < 0) {
582       fprintf(stderr, "ERROR: USB error: %s\n", usb_strerror());
583     } else {
584       if (nBytes == 1) {
585         switch(buffer[0]) {
586         case 23:
587           VERBPRINT(0, "Device responded: OK, scheduling rescan\n");
588           break;
589         case 42:
590           VERBPRINT(0, "Device responded: rescan already scheduled or in progress\n");
591           break;
592         default:
593           fprintf(stderr, "ERROR: Invalid reply to rescan command from device (unknown status %02x)\n", buffer[0]);
594           break;
595         };
596       } else {
597         fprintf(stderr, "ERROR: Invalid reply to rescan command from device (%d bytes instead of 1)\n", nBytes);
598       }
599     }
600   } else if (strcmp(argv[curarg], "reset") == 0) {
601     nBytes = usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, CMD_HARDRESET, 0, 0, (char *)buffer, sizeof(buffer), 5000);
602     VERBPRINT(1, "%d bytes received as reply.\n", nBytes);
603     VERBPRINT(0, "%s\n", "Reset command sent. If this worked, you should see an USB disconnect and reconnect now\n");
604   } else if (strcmp(argv[curarg], "showint") == 0) { /* More of a debug mode: Show interrupt data */
605     doshowint(handle);
606   } else if (strcmp(argv[curarg], "daemon") == 0) { /* Daemon mode */
607     struct daemondata * mydaemondata = NULL;
608     curarg++;
609     do {
610       int l; int optval;
611       struct daemondata * newdd;
612       struct sockaddr_in6 soa;
613       
614       if (curarg >= argc) continue;
615       newdd = calloc(sizeof(struct daemondata), 1);
616       newdd->next = mydaemondata;
617       mydaemondata = newdd;
618       l = sscanf(argv[curarg], "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx:%u:%999[^\n]",
619                  &mydaemondata->serial[5], &mydaemondata->serial[4], &mydaemondata->serial[3], &mydaemondata->serial[2],
620                  &mydaemondata->serial[1], &mydaemondata->serial[0], &mydaemondata->port, &mydaemondata->outputformat[0]);
621       if (l < 7) {
622         fprintf(stderr, "ERROR: failed to parse daemon command parameter '%s'\n", argv[curarg]);
623         exit(1);
624       }
625       if (l == 7) {
626         strcpy((char *)&mydaemondata->outputformat[0], "%S %T");
627       }
628       /* Open the port */
629       mydaemondata->fd = socket(PF_INET6, SOCK_STREAM, 0);
630       soa.sin6_family = AF_INET6;
631       soa.sin6_addr = in6addr_any;
632       soa.sin6_port = htons(mydaemondata->port);
633       optval = 1;
634       setsockopt(mydaemondata->fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
635       if (bind(mydaemondata->fd, (struct sockaddr *)&soa, sizeof(soa)) < 0) {
636         perror("Bind failed");
637         printf("Could not bind to port %u\n", mydaemondata->port);
638         exit(1);
639       }
640       if (listen(mydaemondata->fd, 20) < 0) { /* Large Queue as we block for some time while reading USB! */
641         perror("Listen failed");
642         exit(1);
643       }
644       curarg++;
645     } while (curarg < argc);
646     if (mydaemondata == NULL) {
647       fprintf(stderr, "ERROR: the daemon command requires parameters.\n");
648       exit(1);
649     }
650     /* the good old doublefork trick from 'systemprogrammierung 1' */
651     if (runinforeground != 1) {
652       int ourpid;
653       VERBPRINT(2, "launching into the background...\n");
654       ourpid = fork();
655       if (ourpid < 0) {
656         perror("Ooops, fork() #1 failed");
657         exit(1);
658       }
659       if (ourpid == 0) { /* We're the child */
660         ourpid = fork(); /* fork again */
661         if (ourpid < 0) {
662           perror("Ooooups. fork() #2 failed");
663           exit(1);
664         }
665         if (ourpid == 0) { /* Child again */
666           /* Just don't exit, we'll continue below. */
667         } else { /* Parent */
668           exit(0); /* Just exit */
669         }
670       } else { /* Parent */
671         exit(0); /* Just exit */
672       }
673     }
674     {
675       struct sigaction sia;
676       sia.sa_handler = sigpipehandler;
677       sigemptyset(&sia.sa_mask); /* If we don't do this, we're likely */
678       sia.sa_flags = 0;          /* to die from 'broken pipe'! */
679       sigaction(SIGPIPE, &sia, NULL);
680     }
681     dodaemon(handle, mydaemondata, argv);
682   } else {
683     fprintf(stderr, "ERROR: Command '%s' is unknown.\n", argv[curarg]);
684     usage(argv[0]);
685     exit(1);
686   }
687   usb_close(handle);
688   return 0;
689 }
This page took 0.071828 seconds and 3 git commands to generate.