#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>     /* for _delay_ms() */
#include <avr/pgmspace.h>
#include <avr/wdt.h>

#include "usbdrv.h"
#include "oddebug.h"
#include "usbconfig.h"
#include "interface.h"

#include "i2c.h"
#include "eeprom.h"
#include "serno.h"
#include "adc.h"
#include "usbtenki_cmds.h"

static char g_auto_mode = 1;


static unsigned char xor_buf(unsigned char *buf, int len)
{
	unsigned char x=0;
	while (len--) {
		x ^= *buf;
		buf++;
	}
	return x;
}

uchar   usbFunctionSetup(uchar data[8])
{
	static uchar    replyBuf[8];
	int replen=0, res;
	int total_channels;
	int sensors_channels;
	int num_adc_channels=0;//EEPROM_ADC_CHIPS_SIZE;

	DBG1(0x40, data , 3);
	
	g_auto_mode = 0;
	sensors_channels = sensors_getNumChannels();
	total_channels = sensors_channels + num_adc_channels;
	
    usbMsgPtr = replyBuf;

	switch (data[1])
	{
		case USBTENKI_GET_RAW:
			if (data[2] >= total_channels) 
				break;

			replyBuf[0] = USBTENKI_GET_RAW;

			if (data[2] >= sensors_channels)
			{
				unsigned short val;
//				ADCSRA |= (1<<ADSC); /* start conversion */
//				while (!(ADCSRA & (1<<ADIF))) 
//					{ /* do nothing... */ };
//				replyBuf[2] = ADCL;
//				replyBuf[1] = ADCH;
				// Take 5 samples at 10ms intervals and
				// average them.
				val = adc_sample(data[2] - sensors_channels,
								5,
								10);
				replyBuf[1] = val >> 8;
				replyBuf[2] = val & 0xff;
				res = 2;
			}
			else
			{
				res = sensors_getRaw(data[2], &replyBuf[1]);

				if (res<0) {
					replyBuf[0] = USBTENKI_ERROR;
					replen = 1;
					break;
				}
			}

			replyBuf[res+1] = xor_buf(replyBuf, res+1);
			replen = res + 2;
			break;

		case USBTENKI_GET_CHIP_ID:
			if (data[2] >= total_channels) 
				break;

			replyBuf[0] = USBTENKI_GET_CHIP_ID;
			if (data[2] >= sensors_channels) {
				replyBuf[1] = g_eeprom_data.adc_chips[(data[2]-sensors_channels)];
			} else {
				replyBuf[1] = sensors_getChipID(data[2]);
			}
			replyBuf[2] = xor_buf(replyBuf, 2);
			replen = 3;
			break;

		case USBTENKI_GET_NUM_CHANNELS:
			replyBuf[0] = USBTENKI_GET_NUM_CHANNELS;
			replyBuf[1] = total_channels;
			replyBuf[2] = xor_buf(replyBuf, 2);
			replen = 3;
			break;

		case USBTENKI_RE_INIT:
			replyBuf[0] = USBTENKI_RE_INIT;
			replyBuf[1] = (uchar) sensors_init();
			replyBuf[2] = xor_buf(replyBuf, 2);
			replen = 3;
			break;
		
		case USBTENKI_SET_SERIAL:
			if (data[2] == 0xff) {
				serno_store();
			} else {
				serno_setChar(data[2], data[3]);
			}
			replyBuf[0] = USBTENKI_SET_SERIAL;
			replyBuf[1] = xor_buf(replyBuf, 1);
			replen = 2;
			break;

		case USBTENKI_SET_ADC_CHIP:
			if (data[2] >= num_adc_channels)
				break;

			g_eeprom_data.adc_chips[data[2]] = data[3];
			eeprom_commit();

			replyBuf[0] = USBTENKI_SET_ADC_CHIP;
			replyBuf[1] = xor_buf(replyBuf, 1);
			replen = 2;
			break;
    }
	DBG1(0x41, replyBuf , replen);
	
	return replen;
}

int main(void)
{
	uchar   i;

    wdt_enable(WDTO_1S);
    odDebugInit();

	DBG1(0x30, 0 , 0);
	
	// all input by default
	PORTC= 0xff;
	DDRC = 0x00;

	// set demux ports to out
	DDA0  |= _BV(BDA0);
	DDA1  |= _BV(BDA1);
	DDA2  |= _BV(BDA2);
	DDA3  |= _BV(BDA3);

	adc_init();
	DBG1(0x31, 0 , 0);
	eeprom_init();
	DBG1(0x32, 0 , 0);
	serno_init();
	DBG1(0x33, 0 , 0);
	i2c_init();
	DBG1(0x34, 0 , 0);

 	if (sensors_init()) 
 		while(1) { } /* watchdog will reset me! */
	
	DBG1(0x35, 0 , 0);

    usbInit();
	DBG1(0x36, 0 , 0);
    usbDeviceDisconnect();  /* enforce re-enumeration, do this while interrupts are disabled! */
	DBG1(0x37, 0 , 0);
    i = 0;
    while(--i){             /* fake USB disconnect for > 250 ms */
        wdt_reset();
        _delay_ms(1);
    }
	DBG1(0x38, 0 , 0);
    usbDeviceConnect();
	DBG1(0x39, 0 , 0);

    sei();
	DBG1(0x3a, 0 , 0);

    for(;;){    /* main event loop */
        wdt_reset();
        usbPoll();
    
    }


    return 0;
}

