manueller import aus nem CVS checkout (ist eh nur zum testen)
[ds1820tousb.git] / hostsoftware.c
CommitLineData
93ac315e
MPM
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
26int verblev = 1;
27#define VERBPRINT(lev, fmt...) \
28 if (verblev > lev) { \
29 printf(fmt); \
30 fflush(stdout); \
31 }
32int devicenr = 1;
33int runinforeground = 0;
34int 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
49struct 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
59static 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
86void sigpipehandler(int bla) { /* Dummyhandler for catching the event */
87 return;
88}
89
90
91static 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
121static 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
192void 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
224static uint32_t make32bit(unsigned char * d) {
225 return *((uint32_t *)d);
226}
227
228static 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
238static 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
300static 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
334void 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
387static 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
429static 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
442static 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
525int 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.120602 seconds and 4 git commands to generate.