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