#include <stdio.h>
#include <stdint.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/time.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <pthread.h>
#include <string.h>
#include <math.h>

/* Needed for our own tools */
#include <unistd.h>
#include <sys/stat.h>
#include <sys/ioctl.h>

/* Kluge around kernel internal/external header breakage */
#ifndef __user
#define __user
#endif

#include <linux/usbdevice_fs.h>
#include <errno.h>

/* LibUSB stuff */
#include <usb.h>

#include <pcap.h>

int SetChannel(struct usb_dev_handle *devhdl, unsigned int in_channel) {
	uint8_t data[2];
	int ret;

	if (in_channel < 11 || in_channel > 26)
		return -1;

	// Mode set
	data[0] = 0x07;
	data[1] = 0x00;

	if ((ret = usb_bulk_write(devhdl, 0x02, data, 2, 10)) < 0) {
		perror("chan bulk write");
		return ret;
	}

	data[0] = 0x08;
	data[1] = (in_channel & 0xFF);

	if ((ret = usb_bulk_write(devhdl, 0x02, data, 2, 10)) < 0) {
		perror("chan bulk write");
		return ret;
	}

	if ((ret = usb_bulk_read(devhdl, 0x84, data, 1, 10)) < 0) {
		perror("chan bulk read");
		return ret;
	}

	return 0;
}

int main(int argc, char *argv[]) {
	struct usb_bus *bus = NULL;
	struct usb_device *dev = NULL;
	struct usb_dev_handle *devhdl = NULL;
	uint8_t packet[2048];
	int len;
	unsigned int x;
	time_t old_time = time(0);
	unsigned int chan = 0;
	time_t t = time(0);
	char *pcapname;

	pcap_t *dumpfile;
	pcap_dumper_t *dumper;
	struct pcap_pkthdr wh;
	struct timeval tv;

	if (argc < 2) {
		printf("expected logfile\n");
		exit(1);
	}

	pcapname = strdup(argv[1]);

	dumpfile = pcap_open_dead(DLT_IEEE802_15_4, 2048);
	if (dumpfile == NULL) {
		printf("failed to open pcap %s\n", strerror(errno));
		exit(1);
	}

	dumper = pcap_dump_open(dumpfile, pcapname);
	if (dumper == NULL) {
		printf("failed to open pcap file %s: %s\n", pcapname, strerror(errno));
		exit(1);
	}


	usb_init();
	usb_find_busses();
	usb_find_devices();

	for (bus = usb_busses; bus; bus = bus->next) {
		for (dev = bus->devices; dev; dev = dev->next) {
			if (dev->descriptor.idVendor == 0x03eB &&
				dev->descriptor.idProduct == 0x210A)
				break;
		}

		if (dev)
			break;
	}

	if (argc > 1) {
		sscanf(argv[1], "%d", &chan);
		printf("channel: %d\n", chan);
	}

	printf("device: %s\n", dev->filename);

	if ((devhdl = usb_open(dev)) == NULL) {
		fprintf(stderr, "Failed to open device: %s\n", strerror(errno));
		exit(1);
	}

	if (usb_detach_kernel_driver_np(devhdl, 0) < 0) {
		fprintf(stderr, "Failed to detach from kernel: %s\n", usb_strerror());
		fprintf(stderr, "Trying to continue\n");
	}

	usb_set_configuration(devhdl, 1);

	if (usb_claim_interface(devhdl, 0) < 0) {
		fprintf(stderr, "Failed to claim interface: %s\n", usb_strerror());
		exit(1);
	}

#if 0
	if (usb_set_altinterface(devhdl, 0) < 0) {
		fprintf(stderr, "Failed to set altint: %s\n", usb_strerror());
		exit(1);
	}
#endif

	// Initialize
	printf("init\n");
	packet[0] = 0x07; packet[1] = 0x00;
	if (usb_bulk_write(devhdl, 0x02, packet, 2, 1000) < 0) {
		printf("init bulk write failed\n");
	}
	if (usb_bulk_read(devhdl, 0x84, packet, 1, 1000) < 0) {
		printf("init bulk read failed\n");
	}

	printf("channel\n");
	printf("Channel set %d: %d\n", 11 + chan, SetChannel(devhdl, 11 + chan));

	packet[0] = 0x09; 
	usb_bulk_write(devhdl, 0x02, packet, 1, 0);
	usb_bulk_read(devhdl, 0x84, packet, 1, 0);

	while (1) {
		if (time(0) != t) {
			t = time(0);
			chan++;
			chan = chan % 16;
			printf("Channel set %d: %d\n", 11 + chan, SetChannel(devhdl, 11 + chan));
		}
			
		if ((len = usb_bulk_read(devhdl, 0x81, packet, sizeof(packet), 1000)) < 0) {
			continue;
		}

		printf("Got packet len=%d: ", len);
		for (x = 0; x < len; x++) {
			printf("%02hx ", (short int) packet[x]);
		}
		printf("\n");

		gettimeofday(&tv, 0);
		wh.ts.tv_sec = tv.tv_sec;
		wh.ts.tv_usec = tv.tv_usec;
		wh.caplen = wh.len = len - 9;

		pcap_dump((u_char *) dumper, &wh, packet + 9);
		pcap_dump_flush(dumper);

	}

}



