/*
 * EP_BulkIO.c
 *
 * Created: 12.5.2013 20:08:24
 *  Author: Chenda
 */ 
//#include "../usb_commun_tmc.h"
#include "lib_mcu/compiler.h"

#include <inttypes.h>
#include <stdint.h>
#include <stdbool.h>

#include "Common/DataOperations.h"
#include "EP_tasks.h"

//#define  F_CPU 16000000UL
//#include <util/delay.h>

/************************************************************************/
/* Global variables definitions                                         */
/************************************************************************/
static struct st_Bulk_Out stBulkOut;
static struct st_Bulk_Out* spBulkOut = &stBulkOut;
static struct st_Bulk_In stBulkIn;
static struct st_Bulk_In* spBulkIn = &stBulkIn;
static struct st_Interrupt_In stIntIn;
static struct st_Interrupt_In* spIntIn = &stIntIn;
static struct st_Usb_EP_Interface stUsbEpInt;
static struct st_Usb_EP_Interface* spUsbEpInt = &stUsbEpInt;


//static U8 bTag, bTagInverse;		//tags from inbound message to outbound message 

/************************************************************************/
/* Private functions declaration                                        */
/************************************************************************/


/************************************************************************/
/* Public functions                                                     */
/************************************************************************/

struct st_Usb_EP_Interface* USB_EP_GET_INT (void)
{
	return spUsbEpInt;
}

void USB_EP_BULK_OUT_TASK (void)
{
	//static declaration
	static bool			bNewReception = TRUE;
	static uint32_t RemainingTransferSize;
	static uint8_t	*ptr;
	uint8_t bByteCounter = 0;
	uint8_t i;
	
	if (spUsbEpInt->BulkOut.Event <= BULK_INT_EVENT_BUSY) {
		// currently receiving or or no action, no pending not read messages
		Usb_select_endpoint(EP_BULK_OUT);
		if ( Is_usb_receive_out()) {
			// incoming data available
			spUsbEpInt->BulkOut.Event = BULK_INT_EVENT_BUSY;
			if (bNewReception) {
				bNewReception = FALSE;
				// new message reception - receiving bulk header
				ptr = (uint8_t *)spBulkOut;
				for (i = BULK_HEADER_LENGTH ; i ; i--)
				{
					*ptr++ = Usb_read_byte();
					bByteCounter++;
				}			
				RemainingTransferSize = (uint32_t)(spBulkOut->bTransferSizeLowerWordLsb<<0);
				RemainingTransferSize |= (uint32_t)(spBulkOut->bTransferSizeLowerWordMsb<<8);
				RemainingTransferSize |= (uint32_t)(spBulkOut->bTransferSizeUpperWordLsb<<16);
				RemainingTransferSize |= (uint32_t)(spBulkOut->bTransferSizeUpperWordMsb<<24);
				
				spUsbEpInt->BulkOut.msgLength = (uint8_t)RemainingTransferSize;
				spUsbEpInt->BulkOut.bTag = spBulkOut->bTag;
				spUsbEpInt->BulkOut.bTagInvers = spBulkOut->bTagInverse;
				spUsbEpInt->BulkOut.TransferAttributes = spBulkOut->bmTransferAttributes;				
			}
			if (spBulkOut->bMsgID == DEV_DEP_MSG_OUT || spBulkOut->bMsgID == VENDOR_SPECIFIC_OUT) {
				// incoming message contains bulk data
				while (bByteCounter < EP_SIZE_BULK_OUT && RemainingTransferSize > 0)
				{
					*ptr++ = Usb_read_byte();
					bByteCounter++;
					RemainingTransferSize--;
				}
			}
			else {
				// incoming message contain only header
				RemainingTransferSize = 0;
			}
			Usb_ack_receive_out();
			if (RemainingTransferSize == 0)
			{
				bNewReception = TRUE;
				switch(spBulkOut->bMsgID) {
					case DEV_DEP_MSG_OUT:
						spUsbEpInt->BulkOut.Event = BULK_INT_EVENT_DEV_MSG_OUT;
						// move bulk data into interface
						DAT_OPS_MoveData(spBulkOut->bBulkData,spUsbEpInt->BulkOut.msgBuff,spUsbEpInt->BulkOut.msgLength,false);
						break;
					case REQUEST_DEV_DEP_MSG_IN:
						spUsbEpInt->BulkOut.Event = BULK_INT_EVENT_REQ_DEV_MSG_IN;
						break;
					case VENDOR_SPECIFIC_OUT:
						spUsbEpInt->BulkOut.Event = BULK_INT_EVENT_VENDOR_OUT;
						// move bulk data into interface
						DAT_OPS_MoveData(spBulkOut->bBulkData,spUsbEpInt->BulkOut.msgBuff,spUsbEpInt->BulkOut.msgLength,false);
						break;
					case REQUEST_VENDOR_SPECIFIC_IN:
						spUsbEpInt->BulkOut.Event = BULK_INT_EVENT_REQ_VENDOR_IN;
						break;
					default:
						break;
				}
			}
		}
	}
}

void USB_EP_BULK_IN_TASK (void)
{
	//static declaration
	static bool			bNewTransmition = TRUE;
	static uint32_t RemainingTransferSize;
	static uint8_t	*ptr;
	uint8_t bByteCounter = 0;
	uint8_t i;
	
	Usb_select_endpoint(EP_BULK_IN);
	if (Is_usb_read_control_enabled()) {
		// transmitting data is possible
		if (bNewTransmition && spUsbEpInt->BulkIn.Event > BULK_INT_EVENT_BUSY) {
			// start of the new message transmitting
			bNewTransmition = FALSE;
			// setting header for new message
			ptr = (uint8_t *)spBulkIn;
			switch(spUsbEpInt->BulkIn.Event) {
				case BULK_INT_EVENT_DEV_MSG_IN:
					spBulkIn->bMsgID = DEV_DEP_MSG_IN;
					break;
				case BULK_INT_EVENT_VENDOR_IN:
					spBulkIn->bMsgID = VENDOR_SPECIFIC_IN;
					break;
				default:
					break;
			}
			spUsbEpInt->BulkIn.Event = BULK_INT_EVENT_BUSY;
			spBulkIn->bTransferSizeLowerWordLsb = (uint8_t)spUsbEpInt->BulkIn.msgLength;
			spBulkIn->bTransferSizeLowerWordMsb = (uint8_t)(spUsbEpInt->BulkIn.msgLength>>8);
			spBulkIn->bTransferSizeUpperWordLsb = (uint8_t)(spUsbEpInt->BulkIn.msgLength>>16);
			spBulkIn->bTransferSizeUpperWordMsb = (uint8_t)(spUsbEpInt->BulkIn.msgLength>>24);
			spBulkIn->bTag = spUsbEpInt->BulkIn.bTag;
			spBulkIn->bTagInverse = spUsbEpInt->BulkIn.bTagInvers;
			spBulkIn->bmTransferAttributes = spUsbEpInt->BulkIn.TransferAttributes;
			// move message into bulk data
			DAT_OPS_MoveData(spUsbEpInt->BulkIn.msgBuff,spBulkIn->bBulkData,spUsbEpInt->BulkIn.msgLength,false);
			if (spBulkIn->bBulkData[spUsbEpInt->BulkIn.msgLength-1] == 0 && spBulkIn->bmTransferAttributes == EOM) {
				spBulkIn->bBulkData[spUsbEpInt->BulkIn.msgLength] = '\n';
				RemainingTransferSize = (uint32_t)(spUsbEpInt->BulkIn.msgLength + 1);
			}
			else {
				RemainingTransferSize = (uint32_t)spUsbEpInt->BulkIn.msgLength;	
			}
			//RemainingTransferSize = (uint32_t)spUsbEpInt->BulkIn.msgLength;
			for (i = BULK_HEADER_LENGTH ; i ; i--)
			{
				Usb_write_byte(*ptr++);
				bByteCounter++;
			}			
		}
		if (bNewTransmition == FALSE) {
			// continuing in message transmitting
			spUsbEpInt->BulkIn.Event = BULK_INT_EVENT_BUSY;
			while (bByteCounter < EP_SIZE_BULK_IN && RemainingTransferSize > 0)
			{
				Usb_write_byte(*ptr++);
				bByteCounter++;
				RemainingTransferSize--;
			}
			Usb_ack_in_ready();
			if (RemainingTransferSize == 0)
			{
				// message was transmitted
				bNewTransmition = TRUE;
				spUsbEpInt->BulkIn.Event = BULK_INT_EVENT_NO_EVENT;
			}
		}
		else {
			// previous message transmitting done and no upcoming message transmitting
			spUsbEpInt->BulkIn.Event = BULK_INT_EVENT_NO_EVENT;
		}	
	} 
	else {
		// transmitting isn't allowed
		if (spUsbEpInt->BulkIn.Event == BULK_INT_EVENT_NO_EVENT) {
			spUsbEpInt->BulkIn.Event = BULK_INT_EVENT_BUSY;
		}
	}	
}

void USB_EP_INT_IN_TASK (void)
{
	Usb_select_endpoint (EP_INT_IN);					// Select this enpoint
	if (Is_usb_write_enabled())						// Check data can be loaded
	{											// And load dummy data...
		Usb_write_byte (spIntIn->bNotify1);
		Usb_write_byte (spIntIn->bNotify2);
		Usb_ack_in_ready ();
	}
}


// old functions
/*
void BulkOut_task (S_UsbTmcStatusOfMessage *BulkStatus, S_UsbTmcBulkOutMessage *BulkOut) {
	//static declaration
	static bool		blUncompleteReception = FALSE;
	static U8		bRemainingTransferSizeLowerWordLsb;		 //
	static U8		bRemainingTransferSizeLowerWordMsb;      //  Probably never will be used
	static U8		bRemainingTransferSizeUpperWordLsb;      //  Probably never will be used
	static U8		bRemainingTransferSizeUpperWordMsb;      //  Probably never will be used
	static U8		*ptr;
	//temporary declaration
	U8				bByteCounter = 0;
	U8				i;
	
	
	if (BulkStatus->blUnprocessedInboundMessage == FALSE)
	{
		Usb_select_endpoint(EP_BULK_OUT);
		if ( Is_usb_receive_out())
		{
			if (blUncompleteReception == FALSE)
			{
				//lcd_clrscr();
				//lcd_putc('r');
				ptr = BulkOut;
				for (i = BULK_HEADER_LENGTH ; i ; i--) 
				{
					*ptr++ = Usb_read_byte();
					bByteCounter++;
				}				
				bRemainingTransferSizeLowerWordLsb = BulkOut->bTransferSizeLowerWordLsb;
				bRemainingTransferSizeLowerWordMsb = BulkOut->bTransferSizeLowerWordMsb;
				bRemainingTransferSizeUpperWordLsb = BulkOut->bTransferSizeUpperWordLsb;
				bRemainingTransferSizeUpperWordMsb = BulkOut->bTransferSizeUpperWordMsb;
				bTag = BulkOut->bTag; 
				bTagInverse = BulkOut->bTagInverse;
				blUncompleteReception = TRUE;
			} 
			if (BulkOut->bMsgID == DEV_DEP_MSG_OUT || BulkOut->bMsgID == VENDOR_SPECIFIC_OUT)
			// only this types of messages contains data
			{
				while (bByteCounter < EP_SIZE_BULK_OUT && bRemainingTransferSizeLowerWordLsb > 0)
				{
					*ptr++ = Usb_read_byte();
					bByteCounter++;
					bRemainingTransferSizeLowerWordLsb--;
				}
			}
			else
			// message contain only header 
			{
				bRemainingTransferSizeLowerWordLsb = 0;
				bRemainingTransferSizeLowerWordMsb = 0;
				bRemainingTransferSizeUpperWordLsb = 0;
				bRemainingTransferSizeUpperWordMsb = 0;
			}			
			Usb_ack_receive_out();
			if (bRemainingTransferSizeLowerWordLsb == 0)
			{
				blUncompleteReception = FALSE;
				BulkStatus->blUnprocessedInboundMessage = TRUE;	
			}
		}
	}
}

void BulkIn_task (S_UsbTmcStatusOfMessage *BulkStatus, S_UsbTmcBulkInMessage *BulkIn) 
{
	//static declaration
	static bool		blUncompletetransmission = FALSE;
	static U8		bRemainingTransferSizeLowerWordLsb;		 //
	static U8		bRemainingTransferSizeLowerWordMsb;      //  Probably never will be used
	static U8		bRemainingTransferSizeUpperWordLsb;      //  Probably never will be used
	static U8		bRemainingTransferSizeUpperWordMsb;      //  Probably never will be used
	static U8		*ptr;
	//temporary declaration
	U8				bByteCounter = 0;
	U8				s_lcd[80];
	U8				i;
	
	Usb_select_endpoint(EP_BULK_IN);
	if (blUncompletetransmission == FALSE && BulkStatus->blReadyToOutboundMessage == FALSE)
	{
		if ( Is_usb_read_control_enabled() )  
			BulkStatus->blReadyToOutboundMessage = TRUE;
		return;
	} 
	
	if ( !(Is_usb_read_control_enabled()) ) 
		return;
	
	if (blUncompletetransmission == TRUE || BulkStatus->blNewOutboundMessage == TRUE)
	{
		if (BulkStatus->blNewOutboundMessage == TRUE)
		{
			ptr = BulkIn;
			bRemainingTransferSizeLowerWordLsb = BulkIn->bTransferSizeLowerWordLsb;
			bRemainingTransferSizeLowerWordMsb = BulkIn->bTransferSizeLowerWordMsb;
			bRemainingTransferSizeUpperWordLsb = BulkIn->bTransferSizeUpperWordLsb;
			bRemainingTransferSizeUpperWordMsb = BulkIn->bTransferSizeUpperWordMsb;
			BulkIn->bTag = bTag;
			BulkIn->bTagInverse = bTagInverse;
			for (i = BULK_HEADER_LENGTH ; i ; i--)
			{
				Usb_write_byte(*ptr++);
				bByteCounter++;
			}
			blUncompletetransmission = TRUE;
			BulkStatus->blReadyToOutboundMessage = FALSE;
			BulkStatus->blNewOutboundMessage = FALSE;
		}
		while (bByteCounter < EP_SIZE_BULK_IN && bRemainingTransferSizeLowerWordLsb > 0)
		{
			Usb_write_byte(*ptr++);
			bByteCounter++;
			bRemainingTransferSizeLowerWordLsb--;
		}
		Usb_ack_in_ready();
		if (bRemainingTransferSizeLowerWordLsb == 0)
		{
			blUncompletetransmission = FALSE;
		}
	}
	
	//EP_SIZE_BULK_IN
	
	if (BulkStatus->SendBulkMessage)
	{
		Usb_select_endpoint(EP_BULK_IN);		  // Select this enpoint
		if (Is_usb_read_control_enabled())             // Check data can be loaded
		{                                       // And load dummy data...
			BulkStatus->SendBulkMessage = FALSE;
			ptr = &UsbTmcBulkInMessage.bMsgID;
			for(i=0;(UsbTmcBulkInMessage.bTransferSizeLowerWordLsb + BULK_HEADER_LENGTH) > i;i++)
			{
				Usb_write_byte(*ptr++);
			}
			Usb_ack_in_ready();
		}
	}
	
}

//.. Second interface management (interrupt IN endpoint)
void IntIn_task (S_UsbTmcInterruptInHeader *InterruptData) 
{
	//EP_SIZE_INT_IN
	Usb_select_endpoint (EP_INT_IN);					// Select this enpoint
	if (Is_usb_write_enabled())						// Check data can be loaded
	{												// And load dummy data...
		Usb_write_byte (InterruptData->bNotify1);
		Usb_write_byte (InterruptData->bNotify2);
		Usb_ack_in_ready ();
	}
}
*/
/************************************************************************/
/* Private functions                                                    */
/************************************************************************/
