/*fun test program to imitate merths*/

#include <errno.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#include "libusb.h"

typedef enum 
{
	PID_UNKNOWN		= 0,
	PID_TIGLUSB     = 0xE001,
	PID_TI89TM		= 0xE004,
	PID_TI84P		= 0xE003,
	PID_TI84P_SE    = 0xE008,
	PID_NSPIRE      = 0xE012,
} UsbPid;

#define VID_TI    0x0451
#define BUFFERSIZE 256

static struct libusb_device *dev = NULL;
static struct libusb_device_handle *devh = NULL;
static int inEP = 0x81;
static int outEP = 0x02;
static char buf[BUFFERSIZE];

const char* tigl_strerror(enum libusb_error errcode)
{
	switch (errcode)
	{
		case LIBUSB_SUCCESS:
			return "Success";
		case LIBUSB_ERROR_IO:
			return "Input/output error";
		case LIBUSB_ERROR_INVALID_PARAM:
			return "Invalid parameter";
		case LIBUSB_ERROR_ACCESS:
			return "Access denied (insufficient permissions)";
		case LIBUSB_ERROR_NO_DEVICE:
			return "No such device (it may have been disconnected)";
		case LIBUSB_ERROR_NOT_FOUND:
			return "Entity not found";
		case LIBUSB_ERROR_BUSY:
			return "Resource busy";
		case LIBUSB_ERROR_TIMEOUT:
			return "Operation timed out";
		case LIBUSB_ERROR_OVERFLOW:
			return "Overflow";
		case LIBUSB_ERROR_PIPE:
			return "Pipe error";
		case LIBUSB_ERROR_INTERRUPTED:
			return "System call interrupted (perhaps due to signal)";
		case LIBUSB_ERROR_NO_MEM:
			return "Insufficient memory";
		case LIBUSB_ERROR_NOT_SUPPORTED:
			return "Operation not supported or unimplemented on this platform";
		case LIBUSB_ERROR_OTHER:
			return "Other error";
	}
	return "Unknown error";
}

/*static int find_ti_device(void)
{
	devh = libusb_open_device_with_vid_pid(NULL, VID_TI, PID_TI84P_SE);
	return devh ? 0 : -EIO;
}*/
static int find_ti_device(void)
{
	libusb_device **list;
	ssize_t cnt = libusb_get_device_list(NULL, &list);
	ssize_t i = 0;
	int j = 0;

	if (cnt <= 0)
	{
		return 0;
	}

	for (i = 0; i < cnt; i++)
	{
		libusb_device *device = list[i];
		struct libusb_device_descriptor desc;
		int r = libusb_get_device_descriptor(device, &desc);
		if (r < 0)
		{
			fprintf(stderr, "failed to get device descriptor");
			return r;
		}
		if ((desc.idVendor == VID_TI) && ((desc.idProduct == PID_TI84P_SE) || (desc.idProduct == PID_TI84P)))
		{
			j=libusb_open(device, &devh);
			break;
		}
	}
	return j;
}

static int send_buffer(void){
	int ret, tmp;

	ret = libusb_bulk_transfer(devh, outEP, (unsigned char*)buf, strlen(buf), &tmp, 0);

	if (ret == LIBUSB_ERROR_TIMEOUT)
	{
		fprintf(stderr, "libusb_bulk_transfer (%s).\n", tigl_strerror(ret));
		return ret;
	}
	else if (ret < 0)
	{
		fprintf(stderr, "libusb_bulk_transfer (%s).\n", tigl_strerror(ret));
		return ret;
	}
	
	return 0;
}

int main(void) {

	int r = 1;

	r = libusb_init(NULL);
	if (r < 0) {
		fprintf(stderr, "failed to initialise libusb\n");
		exit(1);
	}

	r = find_ti_device();
	if (r < 0) {
		fprintf(stderr, "Could not find/open device\n");
		goto out;
	}

	r = libusb_claim_interface(devh, 0);
	if (r < 0) {
		fprintf(stderr, "usb_claim_interface error %d\n", r);
		goto out;
	}
	printf("claimed interface\n");

	while (1) {
		fgets(buf, sizeof(buf), stdin);
		if (strcasecmp(buf, "quit\n")==0) {
			break;
		}
		send_buffer();
	}
	
	libusb_release_interface(devh, 0);
out:
	libusb_close(devh);
	libusb_exit(NULL);
	return r >= 0 ? r : -r;
}
