#include "profiler.h"	// EZ-Kit utilities

/*********************************************************************

	Function:		ExceptionHandler
					HWErrorHandler

	Description:	We should never get an exception or hardware error, 
					but just in case we'll catch them and simply turn 
					on all the LEDS should one ever occur.

*********************************************************************/

static ADI_INT_HANDLER(ExceptionHandler)	// exception handler
{
		ezErrorCheck(1);
		return(ADI_INT_RESULT_PROCESSED);
}
		
	
static ADI_INT_HANDLER(HWErrorHandler)		// hardware error handler
{
		ezErrorCheck(1);
		return(ADI_INT_RESULT_PROCESSED);
}

float FloatFromBytes(const unsigned char* pBytes)
{
	float f = 0;

   ((unsigned char*)(&f))[0] = pBytes[0];
   ((unsigned char*)(&f))[1] = pBytes[1];
   ((unsigned char*)(&f))[2] = pBytes[2];
   ((unsigned char*)(&f))[3] = pBytes[3];
	
	return f; 
}

/*********************************************************************

	Function:		Callback

	Description:	Each type of callback event has it's own unique ID 
					so we can use a single callback function for all 
					callback events.  The switch statement tells us 
					which event has occurred.
					
					In the example, we've configured the buffers going
					to the driver for inbound data to generate a callback
					but the buffers going to the driver for outbound 
					data will not generate a callback.  
					
					When we get a callback for an inbound buffer, we
					simply copy the data to the outbound buffer, then
					send the outbound buffer to the device for 
					transmission and re-queue the inbound buffer so that
					it can receive the next piece of data.
					
*********************************************************************/

// Create two buffer chains.  One chain will be used for one of the frames,
// the other chain for the other frame. Note that in this example there
// is only 1 buffer in each chain
ADI_DEV_1D_BUFFER InboundBuffer;
ADI_DEV_1D_BUFFER OutboundBuffer;

// data for the inbound and outbound buffer
u8 InboundData;
u8 OutboundData;

// Deferred Callback Manager data (memory for 1 service plus 4 posted callbacks)
#if defined(USE_DEFERRED_CALLBACKS)
static u8 DCBMgrData[ADI_DCB_QUEUE_SIZE + (ADI_DCB_ENTRY_SIZE)*4];
#endif

// Device Manager data (base memory + memory for 1 device)
static u8 DevMgrData[ADI_DEV_BASE_MEMORY + (ADI_DEV_DEVICE_MEMORY * 1)];

// Handle to the UART driver
static ADI_DEV_DEVICE_HANDLE 	DriverHandle;

// handle to the Device Manager
ADI_DEV_MANAGER_HANDLE 	DeviceManagerHandle;

static void Callback(void *AppHandle, u32 Event, void *pArg)   // call back function specific for UART0
{
	ADI_DEV_BUFFER *pBuffer;			// pointer to the buffer that was processed
//	u32		THR;


	static char charString[80];
	static int charCnt = 0;
	
	static unsigned char DMRecord[31];
	int serialDevice;
	float accelX, accelY, accelZ;
	
	// CASEOF (event type)
	switch (Event) {
		case ADI_DEV_EVENT_BUFFER_PROCESSED:
		
			// identify which buffer is generating the callback
			// we're setup to only get callbacks on inbound buffers so we know this 
			// is an inbound buffer
			pBuffer = (ADI_DEV_BUFFER *)pArg;
			
			serialDevice = 1;
			switch (serialDevice)
			{
				case 1:					//Honeywell PPTR pressure transducer
					charString[charCnt] = InboundData;
					charCnt = charCnt + 1;
					charString[charCnt] = '\0';

					if (InboundData == 0x0D)
					//if( charCnt >= 20)
					{
						printf("%s\r", charString);
						charCnt = 0;
						memset(charString, '\0', 80);
					} 
					break; 
				case 2:					//Microstrain 3DM-GX2
					if( (charCnt == 0)  && (InboundData != 0xC2) )
						break;
					
					DMRecord[charCnt] = InboundData;
					charCnt = charCnt + 1;
					
					if (charCnt == 31)
					{
						accelX = FloatFromBytes(&DMRecord[1]);
						accelY = FloatFromBytes(&DMRecord[5]);
						accelZ = FloatFromBytes(&DMRecord[9]);
						printf("Ax = %8.6f   Ay = %8.6f   Az = %8.6f\n", accelX, accelY, accelZ);
						charCnt = 0;
					} 
					break;
			}

			// requeue the inbound buffer
			ezErrorCheck(adi_dev_Read(DriverHandle, ADI_DEV_1D, (ADI_DEV_BUFFER *)&InboundBuffer));
			
			// cycle the LEDs so it looks like we're doing something important
			ezCycleLEDs();
			break;
		case ADI_UART_EVENT_BREAK_INTERRUPT:
		case ADI_UART_EVENT_FRAMING_ERROR:
		case ADI_UART_EVENT_PARITY_ERROR:
		case ADI_UART_EVENT_OVERRUN_ERROR:
			ezTurnOnAllLEDs();
			while (1) ;
	}
	// return
}


/*********************************************************************
*
*	Function:	SendString
*
*	Description: Transmit a string via the UART
*
*********************************************************************/
void UART_SendString (unsigned char * s)
{
	u32		i;	// count value
	while (*s)
		SendChar((unsigned char) *s++);

// return
}

/*********************************************************************
*
*	Function:	SendChar
*
*	Description: Transmit a character via the UART
*
*********************************************************************/
static void SendChar (unsigned char c)
{

    u32     THRstatus;

   THRstatus = FALSE;  
   while (1){
    if (THRstatus){     // Is the transmitter ready to accept another data?
        OutboundData = c; // yes, send the next data
        // send the outbound buffer
        ezErrorCheck(adi_dev_Write(DriverHandle, ADI_DEV_1D, (ADI_DEV_BUFFER *)&OutboundBuffer));
        break; }
    else
    	// check the transmitter buffer status
       ezErrorCheck(adi_dev_Control(DriverHandle, ADI_UART_CMD_GET_TEMT, (void *)&THRstatus));
	}

// return
}

/*********************************************************************
*
*	Function:	HextoASCII
*
*	Description: Converts Hex value to ASCII equivalent 
*				 & sends via UART
*********************************************************************/
static void HextoASCII (u8 HexValue)	// Converts Hex Value to ASCII equivalent
{
	HexValue &= 0x0F;
	if(HexValue >= 0x0A)
		SendChar(HexValue+0x37);
	else
		SendChar(HexValue+0x30);
}


void UART_Initialize(void)
{
	ADI_DCB_HANDLE			DCBManagerHandle;		// handle to the callback service
	ADI_DEV_MANAGER_HANDLE 	DeviceManagerHandle;	// handle to the Device Manager
	u32 					ResponseCount;			// response counter
	u32 i; //loop variable
	
	ADI_DEV_CMD_VALUE_PAIR ConfigurationTable [] = {	// configuration table for the UART driver
		{ ADI_DEV_CMD_SET_DATAFLOW_METHOD, 	(void *)ADI_DEV_MODE_CHAINED	},
		{ ADI_UART_CMD_SET_DATA_BITS, 		(void *)8						},
		{ ADI_UART_CMD_ENABLE_PARITY, 		(void *)FALSE					},
		{ ADI_UART_CMD_SET_STOP_BITS, 		(void *)1						},
		{ ADI_UART_CMD_SET_BAUD_RATE,		(void *)BAUD_RATE				}, 
		{ ADI_DEV_CMD_END,					NULL							},
	};

	
	// initialize the Interrupt Manager and hook the exception and hardware error interrupts
	// all interrupts are on unique IVGs so we don't need any secondary handler memory
	ezErrorCheck(adi_int_Init(NULL, 0, &ResponseCount, NULL));
	ezErrorCheck(adi_int_CECHook(3, ExceptionHandler, NULL, FALSE));
	ezErrorCheck(adi_int_CECHook(5, HWErrorHandler, NULL, FALSE));
	
	// initialize the Deferred Callback Manager and setup a queue
#if defined(USE_DEFERRED_CALLBACKS)
	ezErrorCheck(adi_dcb_Init(&DCBMgrData[0], ADI_DCB_QUEUE_SIZE, &ResponseCount, NULL));
	ezErrorCheck(adi_dcb_Open(14, &DCBMgrData[ADI_DCB_QUEUE_SIZE], (ADI_DCB_ENTRY_SIZE)*4, &ResponseCount, &DCBManagerHandle));
#else
	DCBManagerHandle = NULL;
#endif

	//Initialize the flag service, memory is not passed because callbacks are not being used
	ezErrorCheck(adi_flag_Init(NULL, 0, &ResponseCount, NULL));	

	//Initialize all LEDS
	for (i = EZ_FIRST_LED; i < EZ_NUM_LEDS; i++){
        ezInitLED(i);
	}
	
	// turn off all LEDs
	ezTurnOffAllLEDs();

	// initialize the Device Manager
	ezErrorCheck(adi_dev_Init(DevMgrData, sizeof(DevMgrData), &ResponseCount, &DeviceManagerHandle, NULL));
	
	// create two buffers that will be initially be placed on the inbound queue
	// only the inbound buffer will have a callback
	InboundBuffer.Data = &InboundData;
	InboundBuffer.ElementCount = 1;
	InboundBuffer.ElementWidth = 1;
	InboundBuffer.CallbackParameter = &InboundBuffer;
	InboundBuffer.ProcessedFlag = FALSE;
	InboundBuffer.pNext = NULL;
	
	OutboundBuffer.Data = &OutboundData;
	OutboundBuffer.ElementCount = 1;
	OutboundBuffer.ElementWidth = 1;
	OutboundBuffer.CallbackParameter = NULL;
	OutboundBuffer.ProcessedFlag = FALSE;
	OutboundBuffer.pNext = NULL;
	
	// open the UART driver for bidirectional data flow
	ezErrorCheck(adi_dev_Open(DeviceManagerHandle, &ADIUARTEntryPoint, 0, NULL, &DriverHandle, ADI_DEV_DIRECTION_BIDIRECTIONAL, NULL, DCBManagerHandle, Callback));
		
	// configure the UART driver with the values from the configuration table
   	ezErrorCheck(adi_dev_Control(DriverHandle, ADI_DEV_CMD_TABLE, ConfigurationTable));
  	
 	// give the device the inbound buffer
	ezErrorCheck(adi_dev_Read(DriverHandle, ADI_DEV_1D, (ADI_DEV_BUFFER *)&InboundBuffer));
	
	// enable data flow
	ezErrorCheck(adi_dev_Control(DriverHandle, ADI_DEV_CMD_SET_DATAFLOW, (void *)TRUE));
}

void UART_Finalize(void)
{
			
	// close down the device driver
	ezErrorCheck(adi_dev_Close(DriverHandle));
	
	// close the Device Manager
	ezErrorCheck(adi_dev_Terminate(DeviceManagerHandle));
	
	// close down the Deferred Callback Manager
#if defined(USE_DEFERRED_CALLBACKS)
	ezErrorCheck(adi_dcb_Terminate());
#endif
}
