#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_sysctl.h"
#include "inc/hw_types.h"
#include "inc/hw_uart.h"
#include "driverlib/debug.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "driverlib/timer.h"
#include "utils/ringbuf.h"
#include "config.h"
#include "telnet.h"
#include "modbusRTU.h"

#if MODBUS_SUPPORT
extern unsigned char g_mbapTransactionIdentifier[];
extern unsigned char g_mbapProtocolIdentifier[];
extern unsigned int  g_mbapADULength[];
extern unsigned char g_mbapSlaveAddress;
extern unsigned char g_mbapFunctionId;
extern tRingBufObject g_sRxBuf[];

 extern void ResetModbusTCPStatemachine(void);
 extern int CheckModbusTCPStatemachine(void);

int i = 0;

void ModbusTimerInit()
{

	g_enableTimer = 0;
	//
    // COnfiguring the Timer0
	//

	TimerConfigure(TIMER0_BASE, TIMER_CFG_32_BIT_PER);

	TimerLoadSet(TIMER0_BASE, TIMER_A,SysCtlClockGet()/20);	 // to configure for 50msec
   
	
	 //
    // Setup the interrupts for the timer timeouts.
    //
    IntEnable(INT_TIMER0A);
    TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
   
}

void ModbusTimerArm(void)
{
 	// Enable the timers.
    //
   TimerEnable(TIMER0_BASE, TIMER_A);
   g_enableTimer = 1;
        
}

void ModbusTimerDisArm(void)
{
	// Disableable the timers.
    //
   TimerDisable(TIMER0_BASE, TIMER_A);
   g_enableTimer = 0;

}


void
Timer0IntHandler(void)
{
    // Clear the timer interrupt.
    //
    TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
    //
  	//
	
	switch(modbusRTUState)
	{
		case  MODBUS_RTU_STATE_IDLE:
		case  MODBUS_RTU_STATE_INIT:
		g_timeOut++;
		if(g_timeOut > 0xF)
			{
			g_timeOut = 0;
		if(!CheckModbusTCPStatemachine())
				{
					ModbusTimerDisArm();
					ResetModbusRTUStatemachine();
					ResetModbusTCPStatemachine();
				}
			}
					break;
		default:
					ModbusTimerDisArm();
					ResetModbusRTUStatemachine();
					ResetModbusTCPStatemachine();
				  	break;
	}

	
}

void CheckModbusRTUStatemachine()
{
if(modbusRTUState ==  MODBUS_RTU_STATE_FRAME_START)
	ResetModbusRTUStatemachine();
}

void SetInitModbusRTUStatemachine(void)
	{
	 modbusRTUState = MODBUS_RTU_STATE_INIT;
	}

 void ResetModbusRTUStatemachine()
{
 modbusRTUState = MODBUS_RTU_STATE_INIT;
}

void initModbusRTUStatemachine()
{
 	int i;

 	g_serialRecvCount = 0;
 	g_slaveAddressRTU = 0x0;
  	g_funcIDRTU = 0x0;
	g_frameLengthRTU = 0x0;
	g_frameDataCount = 0;

 for(i=0;i<RTU_MAX_LENGTH;i++)
 	  g_mbapRTU[i] = 0;
 g_mbapRTU[0] = g_mbapTransactionIdentifier[0];
 g_mbapRTU[1] = g_mbapTransactionIdentifier[1];

 g_mbapRTU[2] = g_mbapProtocolIdentifier[0];
 g_mbapRTU[3] = g_mbapProtocolIdentifier[1];

 g_mbapRTU[4] = g_mbapADULength[0];
 g_mbapRTU[5] = g_mbapADULength[1];

 g_serialRecvCount = 6;
	g_crcRTU[0] = 1;
 	g_crcRTU[1] = 0;

	g_timeOut = 0;

 if(!(!g_mbapRTU[2] && !g_mbapRTU[3]))
 {
 // Protocol ID not valid
  modbusRTUState = MODBUS_RTU_STATE_INVALID;
  return;
 }

 

}



void ModbusRTURecvTCPSend(unsigned char ucChar)
{
	//Enable timer for 3.5 char
	 

	switch(modbusRTUState)
	{
		case  MODBUS_RTU_STATE_IDLE:
					break;
		case  MODBUS_RTU_STATE_INIT:
				initModbusRTUStatemachine();
				modbusRTUState = MODBUS_RTU_STATE_SLAVE_ID;
		
		case MODBUS_RTU_STATE_SLAVE_ID:
					i = 0;			
					g_slaveAddressRTU = ucChar;
					if(	g_slaveAddressRTU == g_mbapSlaveAddress)
					{
				 	g_mbapRTU[g_serialRecvCount] = ucChar;
					g_serialRecvCount++;
					modbusRTUState = MODBUS_RTU_STATE_FUNC_ID;
					ModbusTimerArm();
					}
					else
					{
					 modbusRTUState = MODBUS_RTU_STATE_IDLE;
					 }
					break;
		case MODBUS_RTU_STATE_FUNC_ID:
					g_funcIDRTU = ucChar;
					if(	g_funcIDRTU == g_mbapFunctionId)
					{
				 	g_mbapRTU[g_serialRecvCount] = ucChar;
					g_serialRecvCount++;
						if(g_funcIDRTU == MODBUS_READ_COIL || 
							g_funcIDRTU == MODBUS_READ_DISCRETE_INPUT ||
							g_funcIDRTU == MODBUS_READ_HOLDING_REGISTERS ||
							g_funcIDRTU ==  MODBUS_READ_INPUT_REGISTERS)
							{
								modbusRTUState = MODBUS_RTU_STATE_FRAME_LENGTH;
								ModbusTimerArm();
							}
						else if(g_funcIDRTU == MODBUS_WRITE_SINGLE_COIL || 
							g_funcIDRTU == MODBUS_WRITE_SINGLE_REGISTERS ||
							g_funcIDRTU == MODBUS_WRITE_MULTIPLE_COILS ||
							g_funcIDRTU ==  MODBUS_WRITE_MULTIPLE_REGISTERS)
							{
								g_frameLengthRTU = 4;
								modbusRTUState = MODBUS_RTU_STATE_FRAME_START;
								ModbusTimerArm();	
							}
						else
							 modbusRTUState = MODBUS_RTU_STATE_IDLE;
					}
					else
					{
					 modbusRTUState = MODBUS_RTU_STATE_IDLE;
					}
					break;
		case MODBUS_RTU_STATE_FRAME_LENGTH:
					g_frameLengthRTU = ucChar;
					if(	g_frameLengthRTU < (RTU_MAX_LENGTH - 4))
					{
				 	g_mbapRTU[g_serialRecvCount] = ucChar;
					g_serialRecvCount++;
					modbusRTUState = MODBUS_RTU_STATE_FRAME_START;
					ModbusTimerArm();
					}
					else
					{
					 modbusRTUState = MODBUS_RTU_STATE_IDLE;
					 }
					 break;
		case MODBUS_RTU_STATE_FRAME_START:
					g_mbapRTU[g_serialRecvCount] = ucChar;
					g_serialRecvCount++;
					g_frameDataCount++;
					if(	g_frameDataCount >= g_frameLengthRTU)
					{
				 	modbusRTUState = MODBUS_RTU_STATE_FRAME_CRC1;
					}
					ModbusTimerArm();
					 break;
		
		case  MODBUS_RTU_STATE_FRAME_CRC1:
					g_crcRTU[0] = ucChar;
					g_serialRecvCount++		;
					modbusRTUState = MODBUS_RTU_STATE_FRAME_CRC2;
					ModbusTimerArm();	
					break;

		case  MODBUS_RTU_STATE_FRAME_CRC2:
					g_crcRTU[1] = ucChar;
					g_serialRecvCount++		;
					modbusRTUState = MODBUS_RTU_STATE_FRAME_SENT;	
					
		case  MODBUS_RTU_STATE_FRAME_SENT:
					// Send the Frame 	g_mbapRTU
						for(i = 0; i < (g_serialRecvCount-2); i++)
                       	{
						 if((RingBufFree(&g_sRxBuf[0]) >= 1))
						 	{
							RingBufWriteOne(&g_sRxBuf[0], g_mbapRTU[i]);
							}
                       	}	
					modbusRTUState = MODBUS_RTU_STATE_IDLE;
					ResetModbusTCPStatemachine();
					break;

		case  MODBUS_RTU_STATE_INVALID:
		default:
							ResetModbusRTUStatemachine();
								break;
	}
}


 #endif


