/*
 * PPMsim_Mega8_C.c
 *
 * Created: 2020.12.31. 13:07:26
 * Author : asdma
 */

//#define debug_with_usart //amúgy nem jó, valószínűleg túlságosan lefoglalja az usart kód, ezért láthatja hibásnak a ppmsim-et az usb buszon


#define F_CPU 16000000UL

#define FOSC 16000000
#define BAUD 9600
#define MYUBRR FOSC/16/BAUD-1


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

#include <avr/pgmspace.h>   /* required by usbdrv.h */
#include "usbdrv.h"

/* ------------------------------------------------------------------------- */
/* ----------------------------- USB interface ----------------------------- */
/* ------------------------------------------------------------------------- */

PROGMEM const char usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = { // USB report descriptor, size must match usbconfig.h  
/*	0x05, 0x01,				//USAGE_PAGE (Generic Desktop)
	0x09, 0x05,				//USAGE (Game Pad)
	0xA1, 0x01,				//COLLECTION (Application)
	0xA1, 0x00,				//COLLECTION (Physical)
	0x05, 0x09,				//USAGE_PAGE (Button)
	0x09, 0x01,				//USAGE (Button 1)
	0x09, 0x02,				//USAGE (Button 2)
	0x09, 0x03,				//USAGE (Button 3)
	0x09, 0x04,				//USAGE (Button 4)
	0x09, 0x05,				//USAGE (Button 5)
	0x09, 0x06,				//USAGE (Button 6)
	0x09, 0x07,				//USAGE (Button 7)
	0x09, 0x08,				//USAGE (Button 8)
	0x15, 0x00,				//LOGICAL_MINIMUM (0)
	0x25, 0x01,				//LOGICAL_MAXIMUM (1)
	0x95, 0x08,				//REPORT_COUNT (8)
	0x75, 0x01,				//REPORT_SIZE (1)
	0x81, 0x02,				//INPUT (Data,Var,Abs)
	0x05, 0x01,				//USAGE_PAGE (Generic Desktop)
	0x09, 0x30,				//USAGE (X)
	0x09, 0x31,				//USAGE (Y)
	0x09, 0x32,				//USAGE (Z)
	0x09, 0x35,				//USAGE (Rz)
	0x15, 0x00,				//LOGICAL_MINIMUM (0)
	0x26, 0x1A, 0x40,		//LOGICAL_MAXIMUM (16410)
	0x75, 0x10,				//REPORT_SIZE (16)
	0x95, 0x04,				//REPORT_COUNT (4)
	0x81, 0x02,				//INPUT (Data,Var,Abs)
	0xC0,					//END_COLLECTION
	0xC0,					//END_COLLECTION
*/

//  good descriptor
	0x05, 0x01,//USAGE_PAGE (Generic Desktop)
	0x09, 0x05,//USAGE (Game Pad)
	0xA1, 0x01,//COLLECTION (Application)
	0xA1, 0x00,  //COLLECTION (Physical)
	0x05, 0x01,    //USAGE_PAGE (Generic Desktop)
	0x09, 0x30,    //USAGE (X)
	0x09, 0x31,    //USAGE (Y)
	0x09, 0x32,    //USAGE (Z)
	0x09, 0x35,    //USAGE (Rz)
	0x15, 0x00,    //LOGICAL_MINIMUM (0)
	0x26, 0x1A, 0x40,//LOGICAL_MAXIMUM (16410)
	0x75, 0x10,    //REPORT_SIZE (1)
	0x95, 0x04,    //REPORT_COUNT (4)
	0x81, 0x02,    //INPUT (Data,Var,Abs)
	0xC0,        //END_COLLECTION
	0xC0,      //END_COLLECTION
	
};

//The data described by this descriptor consists of 3 bytes:
//    
//     X7 X6 X5 X4 X3 X2 X1 X0 .... 8 bit unsigned axis x
//     Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 .... 8 bit unsigned axis y
//     Z7 Z6 Z5 Z4 Z3 Z2 Z1 Z0 .... 8 bit unsigned axis z
//     Z7 Z6 Z5 Z4 Z3 Z2 Z1 Z0 .... 8 bit unsigned axis rotation Rz
//	   ...

typedef struct
{
    uint16_t x;
    uint16_t y;
	uint16_t z;
    uint16_t Rz;
	//uchar buttonMask;
}report_t;

static report_t reportBuffer={0};
static uchar    idleRate;   // repeat rate for keyboards, never used for mice 

usbMsgLen_t usbFunctionSetup(uchar data[8]);


void usart_send_uint16_t(uint16_t num);
void usart_send_uint8_t(uint8_t num);
void usart_send_hex_byte(uint8_t num);
void usart_send_enter(void);
void USART_Transmit( unsigned char data );
void USART_Init( unsigned int ubrr);

// a capture-ből kapott min érték kb 15800, a max kb 32200
#define chdb	8//csatornák száma

uint16_t chval[chdb]={0};
uint16_t cptt[chdb+1]={0};//capture data
uint8_t tim1_ovfnum=1;
uint8_t ppmch=0;
uint8_t tmp_btn=0;

int main(void)
{
	//tim 1 input capture init
	//PB0, ICP1 pin
	TCCR1B = (1<<CS10); //1 presc, falling edge
	TIMSK |= (1<<TICIE1) | (1<<TOIE1);//input capture, overflow
	#ifdef debug_with_usart
	USART_Init(MYUBRR);
	#endif
	
	uchar   i;
    wdt_enable(WDTO_1S);
    // Even if you don't use the watchdog, turn it off here. On newer devices,
    // the status of the watchdog (on/off, period) is PRESERVED OVER RESET!
    // RESET status: all port bits are inputs without pull-up.
    // That's the way we need D+ and D-. Therefore we don't need any
    // additional hardware initialization.
    usbInit();
    usbDeviceDisconnect();  // enforce re-enumeration, do this while interrupts are disabled! 
    i = 0;
    while(--i) // fake USB disconnect for > 250 ms 
	{            
        wdt_reset();
        _delay_ms(1);
    }
	usbDeviceConnect();
	sei();
	while(1)// main event loop 
	{        
		wdt_reset();
		usbPoll();
		if(usbInterruptIsReady())
		{
			// called after every poll of the interrupt endpoint
			reportBuffer.x=	chval[0];	
			reportBuffer.y=	chval[1];
			reportBuffer.z=	chval[2];
			reportBuffer.Rz= chval[3];
			//reportBuffer.buttonMask = tmp_btn;
			usbSetInterrupt((void *)&reportBuffer, sizeof(reportBuffer));
		}
	}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
ISR(TIMER1_CAPT_vect)
{
	ppmch++;
	if(tim1_ovfnum>1)	{ ppmch=0;}//find reset
	tim1_ovfnum=0;
	if( (ppmch<=chdb) && (ppmch>=0) )	{cptt[ppmch]=ICR1;};
	if(ppmch==chdb)
	{
		uint8_t i=0;
		for(i=0; i<chdb; i++)
		{
			if(cptt[i] < cptt[i+1])//ha a második capture val nagyobb mint az első, nem volt ovf
			{
				chval[i] = (cptt[i+1]-cptt[i]);
			}
			else
			{
				chval[i] = (cptt[i+1]+(0xffff-cptt[i]));
			}
			if(chval[i]>15800)	{chval[i]=(chval[i]-15800);}
			else{chval[i]=0;}
		}
		tmp_btn=0;
		for(i=4; i<chdb; i++)
		{
			if( chval[i] > 8000 )	{ tmp_btn |= (1<<(i-4));}	else{} 
		}
			
		#ifdef debug_with_usart
		for(uint8_t i=0; i<chdb; i++)
		{
			usart_send_uint16_t(chval[i]);
			USART_Transmit(' ');
		}
		usart_send_enter();
		#endif
		
		ppmch=0;
	}
}

ISR(TIMER1_OVF_vect)
{
	tim1_ovfnum++;
}

usbMsgLen_t usbFunctionSetup(uchar data[8])
{
	usbRequest_t    *rq = (void *)data;
	// The following requests are never used. But since they are required by the specification, we implement them in this example.
	if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS)    // class request type
	{
		if(rq->bRequest == USBRQ_HID_GET_REPORT)  // wValue: ReportType (highbyte), ReportID (lowbyte)
		{
			// we only have one report type, so don't look at wValue
			usbMsgPtr = (usbMsgPtr_t)(void *)&reportBuffer;
			return sizeof(reportBuffer);
		}
		else if(rq->bRequest == USBRQ_HID_GET_IDLE)
		{
			usbMsgPtr = (usbMsgPtr_t)&idleRate;
			return 1;
		}
		else if(rq->bRequest == USBRQ_HID_SET_IDLE)
		{
			idleRate = rq->wValue.bytes[1];
		}
	}
	else
	{
		// no vendor specific requests implemented
	}
	return 0;   // default for not implemented requests: return no data back to host
}

void usart_send_uint16_t(uint16_t num)
{
	USART_Transmit( (((num/100)/100)%10)+'0' );
	USART_Transmit( (((num/100)/10)%10)+'0' );
	USART_Transmit( ((num/100)%10)+'0' );
	USART_Transmit( ((num/10)%10)+'0' );
	USART_Transmit( ((num/1)%10)+'0' );
}

void usart_send_enter(void)
{
	USART_Transmit(0x0a);
	USART_Transmit(0x0d);
}

void USART_Transmit( unsigned char data )
{
	while ( !( UCSRA & (1<<UDRE)) );
	UDR = data;
}

void USART_Init( unsigned int ubrr)
{
	UBRRH = (unsigned char)(ubrr>>8);
	UBRRL = (unsigned char)ubrr;
	UCSRB = (1<<RXEN)|(1<<TXEN);
	UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
}
