1 /*
2 * Wi-Spy Gen1 USB interface
3 *
4 * Original USB device, polled via HID FEATURE requests. 84 samples, 1MHz
5 * resolution.
6 *
7 * Userspace driver uses libusb
8 *
9 * Includes HORRIBLE hack for Linux to attempt to disconnect a device when
10 * kernel includes in linux/usbdevice_fs.h are mismatched to current kernel
11 * support.
12 *
13 * This code is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This code is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * Extra thanks to Ryan Woodings @ Metageek for interface documentation
24 */
25
26 #include "config.h"
27
28 #include <stdio.h>
29 #include <stdint.h>
30 #include <errno.h>
31 #include <sys/types.h>
32 #include <sys/time.h>
33 #include <signal.h>
34 #include <sys/socket.h>
35 #include <sys/wait.h>
36 #include <stdlib.h>
37 #include <pthread.h>
38 #include <string.h>
39
40 #ifdef SYS_LINUX
41 /* Needed for our own tools */
42 #include <unistd.h>
43 #include <sys/stat.h>
44 #include <sys/ioctl.h>
45
46 /* Kluge around kernel internal/external header breakage */
47 #ifndef __user
48 #define __user
49 #endif
50
51 #include <linux/usbdevice_fs.h>
52 #include <errno.h>
53 /*
54 * Miserable hack to fix some distros which bundle a modern kernel but didn't
55 * update their linux/usbdevice_fs.h files. We define the ioctl locally, in
56 * theory the worst that could happen is that the kernel rejects it anyhow.
57 */
58 #ifndef USBDEVFS_DISCONNECT
59 #warning "Kernel headers dont define USB disconnect support, trying to fake it"
60 #define USBDEVFS_DISCONNECT _IO('U', 22)
61 #endif
62 #endif /* linux hack */
63
64 /* LibUSB stuff */
65 #include <usb.h>
66
67 /* USB HID functions from specs which aren't defined for us */
68 #define HID_GET_REPORT 0x01
69 #define HID_RT_FEATURE 0x03
70 #define TIMEOUT 3000
71
72 /* Wispy1a had a bad vid/pid pair in the flash */
73 #define METAGEEK_WISPY1A_VID 0x04b4
74 #define METAGEEK_WISPY1A_PID 0x0bad
75
76 /* Wispy1b has it's own vid/pid */
77 #define METAGEEK_WISPY1B_VID 0x1781
78 #define METAGEEK_WISPY1B_PID 0x083e
79
80 /* Various settings */
81 #define WISPY1_USB_NUM_SAMPLES 83
82 #define WISPY1_USB_OFFSET_MDBM -97000
83 #define WISPY1_USB_RES_MDBM 1500
84 #define WISPY1_USB_RSSI_MAX 35
85 #define WISPY1_USB_RSSI_CALIBRATE_THRESH 4
86 /* calibration in RSSI, one dB approx 2 RSSI */
87 #define WISPY1_USB_CALIBRATE_MAX 1
88 #define WISPY1_USB_CALIBRATE_SWEEPS 10
89
90 #include "spectool_container.h"
91 #include "wispy_hw_gen1.h"
92
93 /* Aux tracking struct for wispy1 characteristics */
94 typedef struct _wispy1_usb_aux {
95 struct usb_device *dev;
96 struct usb_dev_handle *devhdl;
97
98 time_t last_read;
99
100 /* have we pushed a configure event from sweeps */
101 int configured;
102
103 /* IPC tracking records to the forked process for capturing data */
104 pthread_t usb_thread;
105 int usb_thread_alive;
106
107 /* Has the sweep data buffer been initialized? (ie, did we get a sample at 0) */
108 int sweepbuf_initialized;
109 /* how many sweeps has this device done over the run time? Nice to know, and
110 * we can use it for calibration counters too */
111 int num_sweeps;
112
113 /* Sweep buffer we maintain and return */
114 spectool_sample_sweep *sweepbuf;
115
116 /* Calibration modes. We avoid a "want calibration" by setting it to true */
117 int calibrated;
118 /* Calibration offset */
119 int calibration_mod;
120 /* Only allocated during calibration */
121 int8_t *calibrationbuf;
122
123 int sockpair[2];
124
125 spectool_phy *phydev;
126 } wispy1_usb_aux;
127
128 #ifdef SYS_LINUX
129 /* Libusb doesn't seem to always provide this, so we'll use our own, taken from the
130 * usb_detatch_kernel_driver_np...
131 *
132 * THIS IS A HORRIBLE EVIL HACK THAT SHOULDN'T BE DONE, EVER
133 *
134 */
135 struct local_usb_ioctl {
136 int ifno;
137 int ioctl_code;
138 void *data;
139 };
140
141 struct ghetto_libusb_devhandle {
142 int fd;
143 /* Nooo... so bad. */
144 };
145
wispy_usb_detach_hack(struct usb_dev_handle * dev,int interface,char * errstr)146 int wispy_usb_detach_hack(struct usb_dev_handle *dev, int interface, char *errstr) {
147 struct local_usb_ioctl command;
148 struct ghetto_libusb_devhandle *gdev;
149
150 command.ifno = interface;
151 command.ioctl_code = USBDEVFS_DISCONNECT;
152 command.data = NULL;
153
154 gdev = (struct ghetto_libusb_devhandle *) dev;
155
156 if (ioctl(gdev->fd, USBDEVFS_IOCTL, &command) < 0) {
157 if (errno == EINVAL) {
158 snprintf(errstr, SPECTOOL_ERROR_MAX, "Your kernel doesn't appear to accept "
159 "the USB disconnect command. Either your kernel is too old and "
160 "does not support device removal, or support for removal has "
161 "been changed by your distribution kernel maintainers.");
162 }
163
164 snprintf(errstr, SPECTOOL_ERROR_MAX, "Could not detatch kernel driver from "
165 "interface %d: %s", interface, strerror(errno));
166 return -1;
167 }
168
169 return 0;
170 }
171 #endif /* sys_linux */
172
173 /* Prototypes */
174 int wispy1_usb_open(spectool_phy *);
175 int wispy1_usb_close(spectool_phy *);
176 int wispy1_usb_poll(spectool_phy *);
177 int wispy1_usb_getpollfd(spectool_phy *);
178 void wispy1_usb_setcalibration(spectool_phy *, int);
179 spectool_sample_sweep *wispy1_usb_getsweep(spectool_phy *);
180
wispy1_adler_checksum(const char * buf1,int len)181 uint32_t wispy1_adler_checksum(const char *buf1, int len) {
182 int i;
183 uint32_t s1, s2;
184 char *buf = (char *)buf1;
185 int CHAR_OFFSET = 0;
186
187 s1 = s2 = 0;
188 for (i = 0; i < (len-4); i+=4) {
189 s2 += 4*(s1 + buf[i]) + 3*buf[i+1] + 2*buf[i+2] + buf[i+3] +
190 10*CHAR_OFFSET;
191 s1 += (buf[i+0] + buf[i+1] + buf[i+2] + buf[i+3] + 4*CHAR_OFFSET);
192 }
193
194 for (; i < len; i++) {
195 s1 += (buf[i]+CHAR_OFFSET); s2 += s1;
196 }
197
198 return (s1 & 0xffff) + (s2 << 16);
199 }
200
201 /* Scan for devices */
wispy1_usb_device_scan(spectool_device_list * list)202 int wispy1_usb_device_scan(spectool_device_list *list) {
203 struct usb_bus *bus;
204 struct usb_device *dev;
205 int num_found = 0;
206 wispy1_usb_pair *auxpair;
207 char combopath[128];
208
209 /* Libusb init */
210 usb_init();
211 usb_find_busses();
212 usb_find_devices();
213
214 for (bus = usb_busses; bus; bus = bus->next) {
215 for (dev = bus->devices; dev; dev = dev->next) {
216 if (((dev->descriptor.idVendor == METAGEEK_WISPY1A_VID) &&
217 (dev->descriptor.idProduct == METAGEEK_WISPY1A_PID)) ||
218 ((dev->descriptor.idVendor == METAGEEK_WISPY1B_VID) &&
219 (dev->descriptor.idProduct == METAGEEK_WISPY1B_PID))) {
220
221 /* If we're full up, break */
222 if (list->num_devs == list->max_devs - 1)
223 break;
224
225 auxpair = (wispy1_usb_pair *) malloc(sizeof(wispy1_usb_pair));
226
227 snprintf(auxpair->bus, 64, "%s", bus->dirname);
228 snprintf(auxpair->dev, 64, "%s", dev->filename);
229
230 snprintf(combopath, 128, "%s%s", auxpair->bus, auxpair->dev);
231
232 /* Fill in the list elements */
233 list->list[list->num_devs].device_id =
234 wispy1_adler_checksum(combopath, 128);
235 snprintf(list->list[list->num_devs].name, SPECTOOL_PHY_NAME_MAX,
236 "Wi-Spy v1 USB %u", list->list[list->num_devs].device_id);
237 list->list[list->num_devs].init_func = wispy1_usb_init;
238 list->list[list->num_devs].hw_rec = auxpair;
239
240 list->list[list->num_devs].num_sweep_ranges = 1;
241
242 list->list[list->num_devs].supported_ranges =
243 (spectool_sample_sweep *) malloc(SPECTOOL_SWEEP_SIZE(0));
244
245 /* 2400 to 2484 MHz at 1MHz res */
246 list->list[list->num_devs].supported_ranges[0].name =
247 strdup("2.4GHz ISM");
248 list->list[list->num_devs].supported_ranges[0].start_khz = 2400000;
249 list->list[list->num_devs].supported_ranges[0].end_khz = 2484000;
250 list->list[list->num_devs].supported_ranges[0].res_hz = 1000 * 1000;
251 list->list[list->num_devs].supported_ranges[0].num_samples =
252 WISPY1_USB_NUM_SAMPLES;
253
254 list->list[list->num_devs].supported_ranges[0].amp_offset_mdbm =
255 WISPY1_USB_OFFSET_MDBM;
256 list->list[list->num_devs].supported_ranges[0].amp_res_mdbm =
257 WISPY1_USB_RES_MDBM;
258 list->list[list->num_devs].supported_ranges[0].rssi_max =
259 WISPY1_USB_RSSI_MAX;
260
261 list->num_devs++;
262
263 num_found++;
264 }
265 }
266 }
267
268 return num_found;
269 }
270
wispy1_usb_init(spectool_phy * phydev,spectool_device_rec * rec)271 int wispy1_usb_init(spectool_phy *phydev, spectool_device_rec *rec) {
272 wispy1_usb_pair *auxpair = (wispy1_usb_pair *) rec->hw_rec;
273
274 if (auxpair == NULL)
275 return -1;
276
277 return wispy1_usb_init_path(phydev, auxpair->bus, auxpair->dev);
278 }
279
280 /* Initialize a specific USB device based on bus and device IDs passed by the UI */
wispy1_usb_init_path(spectool_phy * phydev,char * buspath,char * devpath)281 int wispy1_usb_init_path(spectool_phy *phydev, char *buspath, char *devpath) {
282 struct usb_bus *bus = NULL;
283 struct usb_device *dev = NULL;
284
285 struct usb_device *usb_dev_chosen = NULL;
286
287 char combopath[128];
288 uint32_t cid;
289
290 wispy1_usb_aux *auxptr = NULL;
291
292 usb_init();
293 usb_find_busses();
294 usb_find_devices();
295
296 snprintf(combopath, 128, "%s%s", buspath, devpath);
297 cid = wispy24x_adler_checksum(combopath, 128);
298
299 /* Don't know if a smarter way offhand, and we don't do this often, so just
300 * crawl and compare */
301 for (bus = usb_busses; bus; bus = bus->next) {
302 if (strcmp(bus->dirname, buspath))
303 continue;
304
305 for (dev = bus->devices; dev; dev = dev->next) {
306 if (strcmp(dev->filename, devpath))
307 continue;
308
309 if (((dev->descriptor.idVendor == METAGEEK_WISPY1A_VID) &&
310 (dev->descriptor.idProduct == METAGEEK_WISPY1A_PID)) ||
311 ((dev->descriptor.idVendor == METAGEEK_WISPY1B_VID) &&
312 (dev->descriptor.idProduct == METAGEEK_WISPY1B_PID))) {
313 usb_dev_chosen = dev;
314 break;
315 } else {
316 snprintf(phydev->errstr, SPECTOOL_ERROR_MAX,
317 "WISPY1_INIT failed, specified device %u does not "
318 "appear to be a Wi-Spy device", cid);
319 return -1;
320 }
321 }
322 }
323
324 if (usb_dev_chosen == NULL) {
325 snprintf(phydev->errstr, SPECTOOL_ERROR_MAX,
326 "WISPY1_INIT failed, specified device %u does not appear "
327 "to exist.", cid);
328 return -1;
329 }
330
331 /* Build the device record with one sweep capability */
332 phydev->device_spec = (spectool_dev_spec *) malloc(sizeof(spectool_dev_spec));
333
334 phydev->device_spec->device_id = cid;
335
336 /* Default the name to the buspath */
337 snprintf(phydev->device_spec->device_name, SPECTOOL_PHY_NAME_MAX,
338 "Wi-Spy v1 USB %u", cid);
339
340 /* State */
341 phydev->state = SPECTOOL_STATE_CLOSED;
342
343 phydev->min_rssi_seen = -1;
344
345 phydev->device_spec->device_version = 0x01;
346 phydev->device_spec->num_sweep_ranges = 1;
347
348 phydev->device_spec->supported_ranges =
349 (spectool_sample_sweep *) malloc(SPECTOOL_SWEEP_SIZE(0));
350
351 /* 2400 to 2484 MHz at 1MHz res */
352 phydev->device_spec->supported_ranges[0].start_khz = 2400000;
353 phydev->device_spec->supported_ranges[0].end_khz = 2484000;
354 phydev->device_spec->supported_ranges[0].res_hz = 1000 * 1000;
355 phydev->device_spec->supported_ranges[0].num_samples = WISPY1_USB_NUM_SAMPLES;
356
357 phydev->device_spec->supported_ranges[0].amp_offset_mdbm = WISPY1_USB_OFFSET_MDBM;
358 phydev->device_spec->supported_ranges[0].amp_res_mdbm = WISPY1_USB_RES_MDBM;
359 phydev->device_spec->supported_ranges[0].rssi_max = WISPY1_USB_RSSI_MAX;
360
361 /* Copy it into our default range data */
362 phydev->device_spec->default_range = &(phydev->device_spec->supported_ranges[0]);
363
364 phydev->device_spec->cur_profile = 0;
365
366 /* Set up the aux state */
367 auxptr = malloc(sizeof(wispy1_usb_aux));
368 phydev->auxptr = auxptr;
369
370 auxptr->configured = 0;
371
372 auxptr->dev = dev;
373 auxptr->devhdl = NULL;
374 auxptr->phydev = phydev;
375 auxptr->sockpair[0] = -1;
376 auxptr->sockpair[1] = -1;
377 auxptr->sweepbuf_initialized = 0;
378
379 auxptr->sweepbuf =
380 (spectool_sample_sweep *) malloc(SPECTOOL_SWEEP_SIZE(WISPY1_USB_NUM_SAMPLES));
381 auxptr->sweepbuf->start_khz = 2400000;
382 auxptr->sweepbuf->end_khz = 2484000;
383 auxptr->sweepbuf->res_hz = 1000 * 1000;
384 auxptr->sweepbuf->num_samples = WISPY1_USB_NUM_SAMPLES;
385 auxptr->sweepbuf->amp_offset_mdbm = WISPY1_USB_OFFSET_MDBM;
386 auxptr->sweepbuf->amp_res_mdbm = WISPY1_USB_RES_MDBM;
387 auxptr->sweepbuf->rssi_max = WISPY1_USB_RSSI_MAX;
388
389 auxptr->sweepbuf->phydev = phydev;
390
391 /* init to -1 since the first pass at slot 0 increments */
392 auxptr->num_sweeps = -1;
393 /* Default to no calibration */
394 auxptr->calibrated = 1;
395 auxptr->calibration_mod = 0;
396 auxptr->calibrationbuf = NULL;
397
398 phydev->open_func = &wispy1_usb_open;
399 phydev->close_func = &wispy1_usb_close;
400 phydev->poll_func = &wispy1_usb_poll;
401 phydev->pollfd_func = &wispy1_usb_getpollfd;
402 phydev->setcalib_func = &wispy1_usb_setcalibration;
403 phydev->getsweep_func = &wispy1_usb_getsweep;
404 phydev->setposition_func = NULL;
405
406 phydev->draw_agg_suggestion = 5;
407
408 return 0;
409 }
410
wispy1_usb_servicethread(void * aux)411 void *wispy1_usb_servicethread(void *aux) {
412 wispy1_usb_aux *auxptr = (wispy1_usb_aux *) aux;
413
414 int sock;
415 struct usb_device *dev;
416 struct usb_dev_handle *wispy;
417
418 char buf[8];
419 struct timeval tm;
420 int x = 0, error = 0;
421 fd_set wset;
422
423 sigset_t signal_set;
424
425 error = 0;
426
427 sock = auxptr->sockpair[1];
428
429 dev = auxptr->dev;
430 wispy = auxptr->devhdl;
431
432 /* We don't want to see any signals in the child thread */
433 sigfillset(&signal_set);
434 pthread_sigmask(SIG_BLOCK, &signal_set, NULL);
435
436 while (1) {
437 /* wait until we're able to write out to the IPC socket, go into a blocking
438 * select */
439 FD_ZERO(&wset);
440 FD_SET(sock, &wset);
441
442 if (select(sock + 1, NULL, &wset, NULL, NULL) < 0) {
443 snprintf(auxptr->phydev->errstr, SPECTOOL_ERROR_MAX,
444 "wispy1_usb poller failed on IPC write select(): %s",
445 strerror(errno));
446 auxptr->usb_thread_alive = 0;
447 auxptr->phydev->state = SPECTOOL_STATE_ERROR;
448 pthread_exit(NULL);
449 }
450
451 if (auxptr->usb_thread_alive == 0) {
452 auxptr->phydev->state = SPECTOOL_STATE_ERROR;
453 pthread_exit(NULL);
454 }
455
456 if (FD_ISSET(sock, &wset) == 0)
457 continue;
458
459 /* Get new data only if we haven't requeued */
460 if (error == 0) {
461 buf[0] = (char) 0xFF;
462
463 /* grab a HID control */
464 if (usb_control_msg(wispy,
465 USB_ENDPOINT_IN + USB_TYPE_CLASS + USB_RECIP_INTERFACE,
466 HID_GET_REPORT, (HID_RT_FEATURE << 8),
467 0, buf, 8, TIMEOUT) == 0) {
468 snprintf(auxptr->phydev->errstr, SPECTOOL_ERROR_MAX,
469 "wispy1_usb poller failed on usb_control_msg "
470 "HID cmd: %s", strerror(errno));
471 auxptr->usb_thread_alive = 0;
472 auxptr->phydev->state = SPECTOOL_STATE_ERROR;
473 pthread_exit(NULL);
474 }
475
476 if (buf[0] == (char) 0xFF) {
477 snprintf(auxptr->phydev->errstr, SPECTOOL_ERROR_MAX,
478 "wispy1_usb poller failed on usb_control_msg "
479 "HID cmd, no data returned, was the device removed?");
480 auxptr->usb_thread_alive = 0;
481 send(sock, buf, 8, 0);
482 auxptr->phydev->state = SPECTOOL_STATE_ERROR;
483 pthread_exit(NULL);
484 }
485 }
486
487 /* Send it to the IPC remote, re-queue on enobufs */
488 if (send(sock, buf, 8, 0) < 0) {
489 if (errno == ENOBUFS) {
490 error = 1;
491 continue;
492 }
493
494 snprintf(auxptr->phydev->errstr, SPECTOOL_ERROR_MAX,
495 "wispy1_usb poller failed on IPC send: %s",
496 strerror(errno));
497 auxptr->usb_thread_alive = 0;
498 auxptr->phydev->state = SPECTOOL_STATE_ERROR;
499 pthread_exit(NULL);
500 }
501
502 /* Flush and use select as a usleep to wait before reading from USB again */
503 error = 0;
504 tm.tv_sec = 0;
505 tm.tv_usec = 7100;
506 select(0, NULL, NULL, NULL, &tm);
507 }
508
509 auxptr->usb_thread_alive = 0;
510 send(sock, buf, 8, 0);
511 auxptr->phydev->state = SPECTOOL_STATE_ERROR;
512 pthread_exit(NULL);
513 }
514
wispy1_usb_getpollfd(spectool_phy * phydev)515 int wispy1_usb_getpollfd(spectool_phy *phydev) {
516 wispy1_usb_aux *auxptr = (wispy1_usb_aux *) phydev->auxptr;
517
518 if (auxptr->usb_thread_alive == 0) {
519 wispy1_usb_close(phydev);
520 return -1;
521 }
522
523 return auxptr->sockpair[0];
524 }
525
wispy1_usb_open(spectool_phy * phydev)526 int wispy1_usb_open(spectool_phy *phydev) {
527 int pid_status;
528 wispy1_usb_aux *auxptr = (wispy1_usb_aux *) phydev->auxptr;
529
530 /* Make the client/server socketpair */
531 if (socketpair(PF_UNIX, SOCK_DGRAM, 0, auxptr->sockpair) < 0) {
532 snprintf(phydev->errstr, SPECTOOL_ERROR_MAX,
533 "wispy1_usb open failed to create socket pair for capture "
534 "process: %s", strerror(errno));
535 return -1;
536 }
537
538 if ((auxptr->devhdl = usb_open(auxptr->dev)) == NULL) {
539 snprintf(phydev->errstr, SPECTOOL_ERROR_MAX,
540 "wispy1_usb capture process failed to open USB device: %s",
541 strerror(errno));
542 return -1;
543 }
544
545 #ifndef SYS_DARWIN
546 /* Claim the device on non-OSX systems */
547 if (usb_claim_interface(auxptr->devhdl, 0) < 0) {
548 snprintf(phydev->errstr, SPECTOOL_ERROR_MAX,
549 "could not claim interface: %s", usb_strerror());
550 #ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP
551 if (usb_detach_kernel_driver_np(auxptr->devhdl, 0) < 0) {
552 fprintf(stderr, "Could not detach kernel driver %s\n", usb_strerror());
553 snprintf(phydev->errstr, SPECTOOL_ERROR_MAX,
554 "Could not detach device from kernel driver: %s",
555 usb_strerror());
556 #endif
557 #ifdef SYS_LINUX
558 if (wispy24x_usb_detach_hack(auxptr->devhdl, 0, phydev->errstr) < 0) {
559 return -1;
560 }
561
562 usb_set_configuration(auxptr->devhdl, auxptr->dev->config->bConfigurationValue);
563
564 if (usb_claim_interface(auxptr->devhdl, 0) < 0) {
565 snprintf(phydev->errstr, SPECTOOL_ERROR_MAX,
566 "wispy24x_usb capture process detached device but still "
567 "can't claim interface: %s", strerror(errno));
568 return -1;
569 }
570 #else
571 return -1;
572 #endif
573 #ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP
574 }
575 #endif
576 }
577 #endif
578
579 auxptr->usb_thread_alive = 1;
580 auxptr->last_read = time(0);
581
582 if (pthread_create(&(auxptr->usb_thread), NULL,
583 wispy1_usb_servicethread, auxptr) < 0) {
584 snprintf(phydev->errstr, SPECTOOL_ERROR_MAX,
585 "wispy1_usb capture failed to create thread: %s",
586 strerror(errno));
587 auxptr->usb_thread_alive = 0;
588 return -1;
589 }
590
591 /* Update the state */
592 phydev->state = SPECTOOL_STATE_CONFIGURING;
593
594 return 1;
595 }
596
wispy1_usb_close(spectool_phy * phydev)597 int wispy1_usb_close(spectool_phy *phydev) {
598 wispy1_usb_aux *aux;
599
600 if (phydev == NULL)
601 return 0;
602
603 aux = (wispy1_usb_aux *) phydev->auxptr;
604
605 if (aux == NULL)
606 return 0;
607
608 if (aux->usb_thread_alive) {
609 aux->usb_thread_alive = 0;
610 pthread_join(aux->usb_thread, NULL);
611 }
612
613 if (aux->devhdl) {
614 usb_close(aux->devhdl);
615 aux->devhdl = NULL;
616 }
617
618 if (aux->sockpair[0] >= 0) {
619 close(aux->sockpair[0]);
620 aux->sockpair[0] = -1;
621 }
622
623 if (aux->sockpair[1] >= 0) {
624 close(aux->sockpair[1]);
625 aux->sockpair[1] = -1;
626 }
627
628 return 1;
629 }
630
wispy1_usb_getsweep(spectool_phy * phydev)631 spectool_sample_sweep *wispy1_usb_getsweep(spectool_phy *phydev) {
632 wispy1_usb_aux *auxptr = (wispy1_usb_aux *) phydev->auxptr;
633
634 return auxptr->sweepbuf;
635 }
636
wispy1_usb_setcalibration(spectool_phy * phydev,int in_calib)637 void wispy1_usb_setcalibration(spectool_phy *phydev, int in_calib) {
638 wispy1_usb_aux *auxptr = (wispy1_usb_aux *) phydev->auxptr;
639 int x;
640
641 if (in_calib == 0 && auxptr->calibrationbuf != NULL) {
642 free(auxptr->calibrationbuf);
643 auxptr->calibrationbuf = NULL;
644 auxptr->calibrated = 1;
645 phydev->state = SPECTOOL_STATE_RUNNING;
646 }
647
648 if (in_calib != 0 && auxptr->calibrationbuf == NULL) {
649 auxptr->calibrationbuf =
650 (int8_t *) malloc(sizeof(int8_t) * WISPY1_USB_NUM_SAMPLES);
651 auxptr->calibrated = 0;
652 for (x = 0; x < WISPY1_USB_NUM_SAMPLES; x++)
653 auxptr->calibrationbuf[x] = 0;
654 phydev->state = SPECTOOL_STATE_CALIBRATING;
655 }
656 }
657
wispy1_usb_poll(spectool_phy * phydev)658 int wispy1_usb_poll(spectool_phy *phydev) {
659 wispy1_usb_aux *auxptr = (wispy1_usb_aux *) phydev->auxptr;
660 unsigned char lbuf[8];
661 int x, pos, calfreqs, ret;
662 long amptotal;
663 int adjusted_rssi;
664
665 /* Push a configure event before anything else */
666 if (auxptr->configured == 0) {
667 auxptr->configured = 1;
668 return SPECTOOL_POLL_CONFIGURED;
669 }
670
671 /* Use the error set by the polling thread */
672 if (auxptr->usb_thread_alive == 0) {
673 phydev->state = SPECTOOL_STATE_ERROR;
674 wispy1_usb_close(phydev);
675 return SPECTOOL_POLL_ERROR;
676 }
677
678 if ((ret = recv(auxptr->sockpair[0], lbuf, 8, 0)) < 0) {
679 if (auxptr->usb_thread_alive != 0)
680 snprintf(phydev->errstr, SPECTOOL_ERROR_MAX,
681 "wispy1_usb IPC receiver failed to read signal data: %s",
682 strerror(errno));
683 phydev->state = SPECTOOL_STATE_ERROR;
684 return SPECTOOL_POLL_ERROR;
685 }
686
687 if (time(0) - auxptr->last_read > 3) {
688 snprintf(phydev->errstr, SPECTOOL_ERROR_MAX,
689 "wispy1_usb didn't see any data for more than 3 seconds, "
690 "something has gone wrong (was the device removed?)");
691 phydev->state = SPECTOOL_STATE_ERROR;
692 return SPECTOOL_POLL_ERROR;
693 }
694
695 if (ret > 0)
696 auxptr->last_read = time(0);
697
698 /* Initialize the sweep buffer when we get to it
699 * If we haven't gotten around to a 0 state to initialize the buffer, we throw
700 * out the sample data until we do. */
701 if (lbuf[0] == 0) {
702 auxptr->sweepbuf_initialized = 1;
703 auxptr->num_sweeps++;
704
705 /* Init the timestamp for sweep begin */
706 gettimeofday(&(auxptr->sweepbuf->tm_start), NULL);
707
708 /* Catch the beginning of the sample loop and handle calibration if we've
709 * gathered enough data */
710 if (auxptr->calibrated == 0 &&
711 auxptr->num_sweeps >= WISPY1_USB_CALIBRATE_SWEEPS) {
712 amptotal = 0;
713 calfreqs = 0;
714
715 /* Average all the signals below the calibration threshold to get a
716 * level of fuzz to remove. */
717 for (x = 0; x < WISPY1_USB_NUM_SAMPLES; x++) {
718 if (auxptr->calibrationbuf[x] < WISPY1_USB_RSSI_CALIBRATE_THRESH) {
719 amptotal += auxptr->calibrationbuf[x];
720 calfreqs++;
721 }
722 }
723
724 if (calfreqs != 0) {
725 auxptr->calibration_mod =
726 (float) (((float) amptotal / (float) calfreqs) /
727 (float) WISPY1_USB_CALIBRATE_SWEEPS);
728 }
729
730 if (auxptr->calibration_mod > WISPY1_USB_CALIBRATE_MAX)
731 auxptr->calibration_mod = WISPY1_USB_CALIBRATE_MAX;
732
733 /* We're calibrated, destroy the buffer and flag us */
734 auxptr->calibrated = 1;
735 free(auxptr->calibrationbuf);
736 auxptr->calibrationbuf = NULL;
737
738 phydev->state = SPECTOOL_STATE_RUNNING;
739 }
740
741 } else if (auxptr->sweepbuf_initialized == 0) {
742 return SPECTOOL_POLL_NONE;
743 }
744
745 for (x = 0; x < 7; x++) {
746 /* Adjust the RSSI by the calibration */
747 if (lbuf[x+1] > auxptr->calibration_mod)
748 adjusted_rssi = lbuf[x+1] - auxptr->calibration_mod;
749 else
750 adjusted_rssi = lbuf[x+1];
751
752 pos = lbuf[0] + x;
753
754 if (pos >= WISPY1_USB_NUM_SAMPLES) {
755 continue;
756 }
757
758 /* Assume the buffer exists, and write into the calibration record if it's a
759 * maximum */
760 if (auxptr->calibrated == 0 && auxptr->calibrationbuf != NULL) {
761 if (adjusted_rssi > auxptr->calibrationbuf[pos])
762 auxptr->calibrationbuf[pos] = adjusted_rssi;
763 } else {
764 /* write it into the main buffer */
765 auxptr->sweepbuf->sample_data[pos] = adjusted_rssi;
766 }
767
768 if (phydev->min_rssi_seen > adjusted_rssi)
769 phydev->min_rssi_seen = adjusted_rssi;
770
771 }
772
773 /* Flag that a sweep is complete */
774 if (lbuf[0] + 7 >= WISPY1_USB_NUM_SAMPLES &&
775 auxptr->calibrated) {
776 gettimeofday(&(auxptr->sweepbuf->tm_end), NULL);
777 auxptr->sweepbuf->min_rssi_seen = phydev->min_rssi_seen;
778 return SPECTOOL_POLL_SWEEPCOMPLETE;
779 }
780
781 return SPECTOOL_POLL_NONE;
782 }
783
784