/*
	general interface to "USB flash device" via usblib
	
	
	credits go to "space2" from forum.se-nse.net
*/
#include "config.h"

#ifdef __LINUXBUILD__

#include "comport_linux_dcu60.h"

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

// 0 = no debug , 1 = read/write completion , 2 = read/write completion with bytes
#define DEBUGOUTPUT 0

// this is in milliseconds
#define TIMEOUT 1000

comportUSB::comportUSB()
{
	strcpy(portname,"");
	dev = NULL;
	speed = 921600;
	readbuffer_size = readbuffer_position = 0;
}

comportUSB::~comportUSB()
{
	close();
}

bool comportUSB::isUSB()
{
	return true;
}

bool comportUSB::open( char*devicename )
{
	int ret;
	
	if (isopen())
		return true;

	// set some default stuff
	speed = 921600;
	if (strcmp( devicename, "") != 0)
	{
		strcpy( portname, devicename );
	}

	struct usb_bus * busses;
	struct usb_bus * bus;

	// find the device
	usb_init();

	printf("Turn off phone. Hold C Button on phone and connect phone. You have 30 seconds.\n");

	// wait 30 sec
	for(int w = 0; w < 30; w++) {
		if (dev) break; // found device
		sleep(1);
		printf("."); fflush(stdout);
		
		usb_find_busses();
		usb_find_devices();
		busses = usb_get_busses();
		
		for (bus = busses; bus; bus = bus->next) {
			struct usb_device * devices = bus->devices;
			struct usb_device * dev;
			for (dev = devices; dev; dev = dev->next) {
				if (dev->descriptor.idVendor == kOurVendorID && dev->descriptor.idProduct == kOurProductID) {
					printf(" FOUND!\n"); fflush(stdout);
					this->dev = dev;
				}
			}
		}
	}

	if (!this->dev) {
		printf(" NOT FOUND\n");
		return false;
	}

	// connect to the device
	dev_handle = usb_open(dev);

	// find the interface
	struct usb_interface_descriptor * if_desc = dev->config[0].interface[0].altsetting;
	if_nr = if_desc->bInterfaceNumber;

	// TODO direction should be checked as well!
	epi_nr = if_desc->endpoint[0].bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK;
	epo_nr = if_desc->endpoint[1].bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK;

	printf("if_nr=%d epi_nr=%d epo_nr=%d\n", if_nr, epi_nr, epo_nr);
	
	// connect to the interface
	ret = usb_claim_interface(dev_handle, if_nr);
	if (ret != 0) {
		perror("usb_claim_interface");
		fprintf(stderr, "usb_claim_interface -> %d\n", ret);
		usb_close(dev_handle);
		dev_handle = NULL;
		dev = NULL;
		return false;
	}

	printf("Phone port opened\n");
	
	return true;
}

bool comportUSB::isopen()
{
	return dev_handle != NULL;
}

void comportUSB::close()
{
	if (isopen()) {
		usb_release_interface(dev_handle, if_nr);
		usb_close(dev_handle);
		dev_handle = NULL;
		dev = NULL;
		printf("Phone port closed\n");
	}
}

bool comportUSB::setspeed( unsigned long newspeed )
{
	if (!isopen())
		return false;

	speed = newspeed;
//	dcu60_configuredevice( dev );
//	dcu60_findinterfaces( dev );
	
	return true;
}

unsigned long comportUSB::sendbyte( unsigned char b )
{
	printf("sendbyte\n");
	int ret = usb_bulk_write(dev_handle, epo_nr, (char*)&b, 1, TIMEOUT);

	if (ret != 1) {
		perror("Send error");
		ret = 0;
	}

	return ret;
}

unsigned long comportUSB::sendbytes( void *b, unsigned long num )
{
	printf("sendbytes(%d)", num); fflush(stdout);
	int ret = usb_bulk_write(dev_handle, epo_nr, (char*)b, num, TIMEOUT);
	printf("-> %d\n", ret);
	
	if (ret < 0) {
		perror("Send error");
		ret = 0;
	}

	return ret;
}

unsigned long comportUSB::recvbyte( void *buffer )
{
	return recvbytes(buffer, 1);
}

unsigned long comportUSB::recvbytes( void *buffer, unsigned long num )
{
	printf("recvbytes(%d)", num); fflush(stdout);

	if (readbuffer_position >= readbuffer_size) {
	    readbuffer_position = readbuffer_size = 0;
	    int ret = usb_bulk_read(dev_handle, epi_nr, (char *)readbuffer, sizeof(readbuffer), TIMEOUT);

	    if (ret < 1) {
		int saved_errno = errno;
		perror("Recv error");
		if (saved_errno == ENODEV)
		    exit(1);
	    } else {
		printf("filled %d", ret);
		readbuffer_size += ret;
	    }
	}

	int ret = readbuffer_position - readbuffer_size;
	if (ret > num)
	    ret = num;

	memcpy(buffer, &readbuffer[readbuffer_position], ret);
	readbuffer_position += ret;

	printf("=%d\n", ret);

	return ret;
}

#endif
