/*
 * Modbus_RTU.c
 *
 *  Created on: 8. 3. 2020
 *      Author: Ondrej Vitoslavsky
 */


#include "Modbus.h"
#include "Modbus_RTU.h"
#include "Modbus_CRC.h"
#include "Modbus_periph.h"




volatile ModbusState State;
extern volatile ModbusEvent Event;

volatile uint8_t  Receive_Buffer[MODBUS_ADU_SIZE_MAX];
volatile uint16_t Receive_Buffer_Pos;

uint8_t  Transmit_Buffer[MODBUS_ADU_SIZE_MAX];
volatile uint16_t Transmit_Buffer_Count;
volatile uint16_t Transmit_Buffer_Pos;






void Modbus_RTU_Start( void )
{
    State = STATE_INIT;
    Modbus_Serial_Enable(1, 0);
    Modbus_Timers_Enable(1, 0);
}



void Modbus_RTU_FSM( void )
{
    uint8_t	Byte;

    switch (State)
    {
        /*We have to wait until whole frame is received when we
         receive Byte during init or error state*/
    case STATE_INIT:
    case STATE_ERROR:
        Modbus_Get_Byte(&Byte);
        Modbus_Timers_Enable(1,0);
        break;

        /*Waiting for new coming byte, this byte is first byte in frame.
         Starting timers t1.5 and t3.5*/
    case STATE_IDLE:
        //read the character
        Modbus_Get_Byte(&Byte);
        Receive_Buffer_Pos = 0;
        Receive_Buffer[Receive_Buffer_Pos++] = Byte;
        State = STATE_RECEIVE;
        Modbus_Timers_Enable(1,1);
        break;

        //receiving byte and reseting timers. check for frame length.
    case STATE_RECEIVE:
        //read the character
        Modbus_Get_Byte(&Byte);
        if(Receive_Buffer_Pos < MODBUS_ADU_SIZE_MAX)
        {
            Receive_Buffer[Receive_Buffer_Pos++] = Byte;
        }
        else
        {
            State = STATE_ERROR;
        }

        //receiving byte while timer t1.5 has expired means damaged frame
        if(Event==EVENT_T15_EXPIRED){
        	State=STATE_ERROR;
        	break;
        }
        Modbus_Timers_Enable(1,1);
        break;
    case STATE_TRANSMIT:
    	if(Transmit_Buffer_Count != 0)
    		{
    			//send one byte and set another byte from buffer
    			Modbus_Put_Byte(&Transmit_Buffer[Transmit_Buffer_Pos++]);
    			Transmit_Buffer_Count--;
    		}
    		else
    		{
    	        Modbus_Timers_Enable(1,0);
    			//transmission is complete. Disable transmitter and receiver
    			Modbus_Serial_Enable(0, 0);

    	    }
    	break;
    }

}


void Modbus_RTU_Timer35_Expired( void )
{

    switch (State)
    {
        //Timer t3.5 expired. Startup phase is finished.
    case STATE_INIT:
    	State=STATE_IDLE;
        break;

        //Timer t3.5 expired during receiving => new frame was received.
    case STATE_RECEIVE:
		Event=EVENT_FRAME_RECEIVED;
		State=STATE_IDLE;
        break;


        //get back to idle state if error occured during receiving
    case STATE_ERROR:
    	State=STATE_IDLE;
        break;
    case STATE_TRANSMIT:
    	//transmission is complete. Disable transmitter and enable receiver
		Modbus_Serial_Enable(1, 0);
    	break;
    default:
       break;
    }

    Modbus_Timers_Disable(1,1);
}

void Modbus_RTU_Timer15_Expired(void){
    switch (State)
    {
    	/*if timer t1.5 expires, set new event. New character received after
    	 this event means that frame is damaged. If timer t3.5
    	expires after this event, frame is OK*/
    case STATE_RECEIVE:
    	State=EVENT_T15_EXPIRED;
        break;

        //timer expired in any other state state
    default:
       break;
    }
    Modbus_Timers_Disable(0,1);
}
