/*
 * tool/labsw.c - LABSW control tool
 *
 * Written 2011 by Werner Almesberger
 * Copyright 2011 Werner Almesberger
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 */


#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <usb.h>

#include "f32xbase/usb.h"
#include "labsw/ep0.h"
#include "labsw/usb-id.h"


#define FROM_DEV	LABSW_FROM_DEV(0)
#define TO_DEV		LABSW_TO_DEV(0)

#define BUF_SIZE	256


static void identify_labsw(usb_dev_handle *dev)
{
	const struct usb_device *device = usb_device(dev);
	uint8_t ids[3];
	char buf[BUF_SIZE+1];   /* +1 for terminating \0 */
	int res;

	printf("%04x:%04x ",
	    device->descriptor.idVendor, device->descriptor.idProduct);

	res = usb_control_msg(dev, FROM_DEV, LABSW_ID, 0, 0,
	    (char *) ids, sizeof(ids), 1000);
	if (res < 0) {
		fprintf(stderr, "LABSW_ID: %s\n", usb_strerror());
		exit(1);
	}

	printf("protocol %u.%u hw %u\n", ids[0], ids[1], ids[2]);

	res = usb_control_msg(dev, FROM_DEV, LABSW_BUILD, 0, 0,
	    buf, sizeof(buf), 1000);
	if (res < 0) {
		fprintf(stderr, "LABSW_BUILD: %s\n", usb_strerror());
		exit(1);
	}
	buf[res] = 0;
	printf("%10s%s\n", "", buf);
}


static void set(usb_dev_handle *dev, uint16_t value, uint16_t mask)
{
	int res;

	res = usb_control_msg(dev, TO_DEV, LABSW_SET, value, mask,
	    NULL, 0, 1000);
	if (res < 0) {
		fprintf(stderr, "LABSW_SET: %s\n", usb_strerror());
		exit(1);
	}
}


#define	ON_BITS(ch) \
	(LABSW_CH##ch##_RELAY | LABSW_CH##ch##_OPT | LABSW_CH##ch##_R)
#define	OFF_BITS(ch)	LABSW_CH##ch##_G
#define	CHAN_MASK(ch)	(ON_BITS(ch) | OFF_BITS(ch))
#define	REMOTE_BITS	LABSW_MAIN_R
#define	REMOTE_MASK	(LABSW_MAIN_R | LABSW_MAIN_G)


#define	SET_CHAN(ch, on) \
	set(dev, (on ? ON_BITS(ch) : OFF_BITS(ch)) | REMOTE_BITS, \
	    CHAN_MASK(ch) | REMOTE_MASK)


static void query(usb_dev_handle *dev)
{
	uint8_t buf[2];
	int res;

	res = usb_control_msg(dev, FROM_DEV, LABSW_GET, 0, 0,
	    (char *) buf, sizeof(buf), 1000);
	if (res < 0) {
		fprintf(stderr, "LABSW_GET: %s\n", usb_strerror());
		exit(1);
	}
	if (res != 2) {
		fprintf(stderr, "LABSW_GET: expected %u, got %d\n",
		    (unsigned) sizeof(buf), res);
		exit(1);
	}
	printf("%u %u\n", buf[0], buf[1]);
}


int main(int argc, char **argv)
{
	usb_dev_handle *dev;
	int i;

	dev = open_usb(USB_VENDOR, USB_PRODUCT);
	if (!dev) {
		fprintf(stderr, ":-(\n");
		return 1;
	}

	if (argc == 1) {
		identify_labsw(dev);
		return 0;
	}

	for (i = 1; i != argc; i++) {
		if (!strcmp(argv[i], "ch1=0"))
			SET_CHAN(1, 0);
		else if (!strcmp(argv[i], "ch1=1"))
			SET_CHAN(1, 1);
		else if (!strcmp(argv[i], "ch2=0"))
			SET_CHAN(2, 0);
		else if (!strcmp(argv[i], "ch2=1"))
			SET_CHAN(2, 1);
		else if (!strcmp(argv[i], "query"))
			query(dev);
		else if (!strcmp(argv[i], "local"))
			set(dev, 0, 0);
		else {
			fprintf(stderr, "unrecognized command \"%s\"\n",
			    argv[i]);
			exit(1);
		}
	}
	return 0;
}