#define UART1_USE_AS_MODBUS

//#include "config/default/definitions.h"
#include "modbus.h"  
#include "modbus_User.h"
//#include "inc/hw_types.h"
//#include "inc/hw_memmap.h"
#include "inc/hw_cputimer.h"
//#include "inc/hw_sci.h"
#include "driverlib/gpio.h"
#include "driverlib/sci.h"
#include "board.h"

#define MCU_UART_QTY 1

uint8_t my_MCU_UART_QTY = MCU_UART_QTY;
uint16_t TMR1_PeriodGet(void)
{
    //translate to up counter value
    return (0xffffu - HWREGH(CPUTIMER0_BASE + CPUTIMER_O_PRD));
}


uint16_t TMR1_CounterGet(void)
{
    //translate to up counter value      
    return (0xFFFFu-HWREGH(CPUTIMER0_BASE + CPUTIMER_O_TIM));
}

//only for decrease memory consumed , not for architecture difference  
#if MCU_UART_QTY==-1    //Simulink will craete MCU_UART_QTY=-1 when we don't use Uart
    uint8_t LinearBufferTx1[1]; 
    LinearBuf_type LinearTx1;  
    uint8_t LinearBufferTx2[1];
    LinearBuf_type LinearTx2;    
    uint8_t LinearBufferTx3[1];
    LinearBuf_type LinearTx3;  
    uint8_t LinearBufferTx4[1];
    LinearBuf_type LinearTx4;   

    uint8_t RingBufferRx1[1]; 
    RingBuf_type  RingRx1;  
    uint8_t RingBufferRx2[1];
    RingBuf_type RingRx2;    
    uint8_t RingBufferRx3[1];
    RingBuf_type RingRx3;  
    uint8_t RingBufferRx4[1];
    RingBuf_type RingRx4; 
#endif
#if MCU_UART_QTY==1    
    #ifdef UART1_USE_AS_MODBUS
    uint8_t LinearBufferTx1[256]; 
    uint8_t RingBufferRx1[256];
    #else
    uint8_t LinearBufferTx1[1]; 
    uint8_t RingBufferRx1[1];     
    #endif



    LinearBuf_type LinearTx1;  
    uint8_t LinearBufferTx2[1];
    LinearBuf_type LinearTx2;    
    uint8_t LinearBufferTx3[1];
    LinearBuf_type LinearTx3;  
    uint8_t LinearBufferTx4[1];
    LinearBuf_type LinearTx4;

    RingBuf_type RingRx1;
    uint8_t RingBufferRx2[1];
    RingBuf_type RingRx2;
    uint8_t RingBufferRx3[1];
    RingBuf_type RingRx3;
    uint8_t RingBufferRx4[1];
    RingBuf_type RingRx4; 
#endif
#if MCU_UART_QTY==2    
    #ifdef UART1_USE_AS_MODBUS
    uint8_t LinearBufferTx1[256]; 
    uint8_t RingBufferRx1[256];
    #else
    uint8_t LinearBufferTx1[1];
    uint8_t RingBufferRx1[1];
    #endif

    #ifdef UART2_USE_AS_MODBUS
    uint8_t LinearBufferTx2[256];
    uint8_t RingBufferRx2[256];
    #else
    uint8_t LinearBufferTx2[1];
    uint8_t RingBufferRx2[1];
    #endif

    LinearBuf_type LinearTx1;
    LinearBuf_type LinearTx2;  
    uint8_t LinearBufferTx3[1];
    LinearBuf_type LinearTx3; 
    uint8_t LinearBufferTx4[1];
    LinearBuf_type LinearTx4;  

    RingBuf_type RingRx1;
    RingBuf_type RingRx2;
    uint8_t RingBufferRx3[1];
    RingBuf_type RingRx3;
    uint8_t RingBufferRx4[1];
    RingBuf_type RingRx4;
#endif
#if MCU_UART_QTY==3    
    #ifdef UART1_USE_AS_MODBUS
    uint8_t LinearBufferTx1[256]; 
    uint8_t RingBufferRx1[256];

    #else
    uint8_t LinearBufferTx1[1];
    uint8_t RingBufferRx1[1];


    #endif

    #ifdef UART2_USE_AS_MODBUS
    uint8_t LinearBufferTx2[256];
    uint8_t RingBufferRx2[256];

    #else
    uint8_t LinearBufferTx2[1];
    uint8_t RingBufferRx2[1];

    #endif

    #ifdef UART3_USE_AS_MODBUS
    uint8_t LinearBufferTx3[256];
    uint8_t RingBufferRx3[256];


    #else
    uint8_t LinearBufferTx3[1];
    uint8_t RingBufferRx3[1];


    #endif


    LinearBuf_type LinearTx1;
    LinearBuf_type LinearTx2;
    LinearBuf_type LinearTx3;
    uint8_t LinearBufferTx4[1];
    LinearBuf_type LinearTx4;

    RingBuf_type RingRx1;
    RingBuf_type RingRx2;
    RingBuf_type RingRx3;
    uint8_t RingBufferRx4[1];
    RingBuf_type RingRx4;   
#endif
#if MCU_UART_QTY==4    
    #ifdef UART1_USE_AS_MODBUS
    uint8_t LinearBufferTx1[256]; 
    uint8_t RingBufferRx1[256];
    #else
    uint8_t LinearBufferTx1[1];
    uint8_t RingBufferRx1[1];
    #endif

    #ifdef UART2_USE_AS_MODBUS
    uint8_t LinearBufferTx2[256];
    uint8_t RingBufferRx2[256];
    #else
    uint8_t LinearBufferTx2[1];
    uint8_t RingBufferRx2[1];
    #endif

    #ifdef UART3_USE_AS_MODBUS
    uint8_t LinearBufferTx3[256];
    uint8_t RingBufferRx3[256];
    #else
    uint8_t LinearBufferTx3[1];
    uint8_t RingBufferRx3[1];
    #endif

    #ifdef UART4_USE_AS_MODBUS
    uint8_t LinearBufferTx4[256];
    uint8_t RingBufferRx4[256];
    #else
    uint8_t LinearBufferTx4[1];
    uint8_t RingBufferRx4[1];
    #endif

    LinearBuf_type LinearTx1;
    LinearBuf_type LinearTx2;
    LinearBuf_type LinearTx3;
    LinearBuf_type LinearTx4;

    RingBuf_type RingRx1;
    RingBuf_type RingRx2;
    RingBuf_type RingRx3;
    RingBuf_type RingRx4;   
#endif   

#ifdef UART1_USE_AS_MODBUS 
    //because defined in uart1.h
    extern volatile uint16_t tick4rxd1;    //Uart1 rxd tick  (Also used for txd)
    extern volatile uint16_t tmr4rxd1;    //Uart1 rxd timer1 value  (Also used for txd)    
    bool  UART1_TransmitDone(void)
    {
    
        if (LinearTx1.index)  {
            return(false);
        }
        //  return   (!SCI_isTransmitterBusy(SCIA_BASE));
        // Check if the FIFO is empty.
        // If not, the transmitter is still busy.
        if(SCI_getTxFIFOStatus(SCIA_BASE) != SCI_FIFO_TX0)
        {
            return(false);
        }
        
        // Check the TXEMPTY flag directly to ensure the shift register is also empty.
        // This part of the logic is from SCI_isTransmitterBusy() non-FIFO implementation.
        // If the TXEMPTY flag is not set, the transmitter is still busy.
        if((HWREGH(SCIA_BASE + SCI_O_CTL2) & SCI_CTL2_TXEMPTY) != SCI_CTL2_TXEMPTY)
        {
            return(false);
        }
        
        // If both the FIFO and the shift register are empty, the transmitter is idle.
        return(true);   
    }
    
#else
    volatile uint16_t tick4rxd1;    //Uart1 rxd tick  (Also used for txd)
    volatile uint16_t tmr4rxd1;    //Uart1 rxd timer1 value  (Also used for txd)
    bool  UART1_TransmitDone(void)
    {
    
        return true;
    }
    
#endif
#ifdef UART2_USE_AS_MODBUS    
    //because defined in uart2.h
    extern volatile uint16_t tick4rxd2;    //Uart2 rxd tick
    extern volatile uint16_t tmr4rxd2;    //Uart2 rxd timer1 value
    bool  UART2_TransmitDone(void)
    {
        if (LinearTx2.index)  {
            return(false);
        }
        //  return   (!SCI_isTransmitterBusy(SCIB_BASE));
        // Check if the FIFO is empty.
        // If not, the transmitter is still busy.
        if(SCI_getTxFIFOStatus(SCIB_BASE) != SCI_FIFO_TX0)
        {
            return(false);
        }
        
        // Check the TXEMPTY flag directly to ensure the shift register is also empty.
        // This part of the logic is from SCI_isTransmitterBusy() non-FIFO implementation.
        // If the TXEMPTY flag is not set, the transmitter is still busy.
        if((HWREGH(SCIB_BASE + SCI_O_CTL2) & SCI_CTL2_TXEMPTY) != SCI_CTL2_TXEMPTY)
        {
            return(false);
        }
        
        // If both the FIFO and the shift register are empty, the transmitter is idle.
        return(true);   
    }
    
#else
    volatile uint16_t tick4rxd2;    //Uart2 rxd tick
    volatile uint16_t tmr4rxd2;    //Uart2 rxd timer1 value
    bool  UART2_TransmitDone(void)
    {
        return true;
    }  
#endif
#ifdef UART3_USE_AS_MODBUS 
    //because defined in uart3.h
    extern volatile uint16_t tick4rxd3;    //Uart3 rxd tick
    extern volatile uint16_t tmr4rxd3;    //Uart3 rxd timer1 value
    bool  UART3_TransmitDone(void)
    {
        if (LinearTx3.index)  {
            return(false);
        }
        //  return   (!SCI_isTransmitterBusy(SCIC_BASE));
        // Check if the FIFO is empty.
        // If not, the transmitter is still busy.
        if(SCI_getTxFIFOStatus(SCIC_BASE) != SCI_FIFO_TX0)
        {
            return(false);
        }
        
        // Check the TXEMPTY flag directly to ensure the shift register is also empty.
        // This part of the logic is from SCI_isTransmitterBusy() non-FIFO implementation.
        // If the TXEMPTY flag is not set, the transmitter is still busy.
        if((HWREGH(SCIC_BASE + SCI_O_CTL2) & SCI_CTL2_TXEMPTY) != SCI_CTL2_TXEMPTY)
        {
            return(false);
        }
        
        // If both the FIFO and the shift register are empty, the transmitter is idle.
        return(true);   
    }
#else
    volatile uint16_t tick4rxd3;    //Uart3 rxd tick
    volatile uint16_t tmr4rxd3;    //Uart3 rxd timer1 value
    bool  UART3_TransmitDone(void)
    {
        return true;
    }   
#endif
#ifdef UART4_USE_AS_MODBUS 
    //because defined in uart4.h
    extern volatile uint16_t tick4rxd4;    //Uart4 rxd tick
    extern volatile uint16_t tmr4rxd4;    //Uart4 rxd timer1 value
    bool  UART4_TransmitDone(void)
    {
        if (LinearTx4.index)  {
            return(false);
        }
        //  return   (!SCI_isTransmitterBusy(SCID_BASE));
        // Check if the FIFO is empty.
        // If not, the transmitter is still busy.
        if(SCI_getTxFIFOStatus(SCID_BASE) != SCI_FIFO_TX0)
        {
            return(false);
        }
        
        // Check the TXEMPTY flag directly to ensure the shift register is also empty.
        // This part of the logic is from SCI_isTransmitterBusy() non-FIFO implementation.
        // If the TXEMPTY flag is not set, the transmitter is still busy.
        if((HWREGH(SCID_BASE + SCI_O_CTL2) & SCI_CTL2_TXEMPTY) != SCI_CTL2_TXEMPTY)
        {
            return(false);
        }
        
        // If both the FIFO and the shift register are empty, the transmitter is idle.
        return(true);   
    }
#else
    volatile uint16_t tick4rxd4;    //Uart4 rxd tick
    volatile uint16_t tmr4rxd4;    //Uart4 rxd timer1 value  
    bool  UART4_TransmitDone(void)
    {
        return true;
    } 
#endif

    


void __attribute__((weak)) EnableUART1_RS485Receive (unsigned char enable) // enable=1 => receive enable
{
    //Add your code
    // enable = 0 => TRANSMIT DATA, 0 = "output". enable = 1 => RECEIVE DATA, 1 = "input"
    if(enable==TX_DATA){                                      // Set the pin
          //LATBbits.LATB2=1;
        //GPIO_writePin(TxEnable,1);
          //TX1_Enable_SetHigh();
	}else{                                              //Clear the pin
          //LATBbits.LATB2=0;
        //GPIO_writePin(TxEnable,0);
         //TX1_Enable_SetLow();
	}
}
void __attribute__((weak)) EnableUART2_RS485Receive (unsigned char enable) 
{
    //Add your code
    // enable = 0 => TRANSMIT DATA, 0 = "output". enable = 1 => RECEIVE DATA, 1 = "input"
    if(enable==TX_DATA){                                      // Set the pin
          //LATBbits.LATB11=1;
        //TX2_Enable_SetHigh();
	}else{                                              //Clear the pin
          //LATBbits.LATB11=0;
        //TX2_Enable_SetLow();
	}
}
void __attribute__((weak)) EnableUART3_RS485Receive (unsigned char enable) 
{
    //Add your code
}
void __attribute__((weak)) EnableUART4_RS485Receive (unsigned char enable) 
{
    //Add your code
}

    

bool  UART1_IsRxReady(void)
{
    #ifdef UART1_USE_AS_MODBUS
		return !(RingRx1.index_w == RingRx1.index_r);
    #else
        return 0;
    #endif
    
    
}
void  UART1_ClearAll(void)
{
    #ifdef UART1_USE_AS_MODBUS
	    //SCI_resetRxFIFO(SCIA_BASE);  //Even though non-fifo
        RingBuffClear(&RingRx1);
        LinearBuffClear(&LinearTx1);
        //SCI_resetTxFIFO(SCIA_BASE);            
    #endif
    

}
void  UART1_User_WriteBuffer( uint8_t *buffer , unsigned int numbytes )
{
   #ifdef UART1_USE_AS_MODBUS
   //disable Tx Ready Int          
   //SCI_clearInterruptStatus(SCIA_BASE, SCI_INT_TXRDY);
   //SCI_disableInterrupt(SCIA_BASE,SCI_INT_TXRDY);
   SCI_writeCharNonBlocking(SCIA_BASE, LinearTx1.data[0]);  //At lease , we must transmit first byte.
   //Enable Tx empty interrupt
   /*if (LinearTx1.index>1) {
       EALLOW;
       SCI_enableInterrupt(SCIA_BASE, SCI_INT_TXRDY|SCI_INT_RXRDY_BRKDT);
       EDIS;

   }*/
   //and then do nothing, let TX ISR handle  because we have written into linear buffer   
   #endif    
  
}
uint8_t  UART1_ReadX( void)
{
    #ifdef UART1_USE_AS_MODBUS
        return RingBuffReadByte(&RingRx1);
    #else
        return 0;
    #endif       
}

bool  UART2_IsRxReady(void)
{
    #ifdef UART2_USE_AS_MODBUS
		return !(RingRx2.index_w == RingRx2.index_r);
    #else
        return 0;
    #endif
    
}
void  UART2_ClearAll(void)
{
    #ifdef UART2_USE_AS_MODBUS
	    //SCI_resetRxFIFO(SCIB_BASE);  //Even though non-fifo
        RingBuffClear(&RingRx2);
        LinearBuffClear(&LinearTx2);
        //SCI_resetTxFIFO(SCIB_BASE);            
    #endif
    
}
void  UART2_User_WriteBuffer( uint8_t *buffer , unsigned int numbytes )
{
   #ifdef UART2_USE_AS_MODBUS
   SCI_writeCharNonBlocking(SCIB_BASE, LinearTx2.data[0]);  //At lease , we must transmit first byte. 
   #endif   
}
uint8_t  UART2_ReadX( void)
{
    #ifdef UART2_USE_AS_MODBUS
        return RingBuffReadByte(&RingRx2);
    #else
        return 0;
    #endif        
}
    
bool  UART3_IsRxReady(void)
{
    #ifdef UART3_USE_AS_MODBUS
		return !(RingRx3.index_w == RingRx3.index_r);
    #else
        return 0;
    #endif
}    
void  UART3_ClearAll(void)
{
    #ifdef UART3_USE_AS_MODBUS
	    //SCI_resetRxFIFO(SCIC_BASE);  //Even though non-fifo
        RingBuffClear(&RingRx3);
        LinearBuffClear(&LinearTx3);
        //SCI_resetTxFIFO(SCIC_BASE);            
    #endif
}
void  UART3_User_WriteBuffer( uint8_t *buffer , unsigned int numbytes )
{
    #ifdef UART3_USE_AS_MODBUS
    SCI_writeCharNonBlocking(SCIC_BASE, LinearTx3.data[0]);  //At lease , we must transmit first byte.   
    #endif   
}
uint8_t  UART3_ReadX( void)
{
    #ifdef UART3_USE_AS_MODBUS
        return RingBuffReadByte(&RingRx3);
    #else
        return 0;
    #endif    
    
}

bool UART4_IsRxReady(void)
{
    #ifdef UART4_USE_AS_MODBUS
		return !(RingRx4.index_w == RingRx4.index_r);
    #else
        return 0;
    #endif    
}
void UART4_ClearAll(void){
    #ifdef UART4_USE_AS_MODBUS
	    //SCI_resetRxFIFO(SCID_BASE);  //Even though non-fifo
        RingBuffClear(&RingRx4);
        LinearBuffClear(&LinearTx4);
        //SCI_resetTxFIFO(SCID_BASE);            
    #endif
}
void  UART4_User_WriteBuffer( uint8_t *buffer , unsigned int numbytes )
{
    #ifdef UART4_USE_AS_MODBUS
    SCI_writeCharNonBlocking(SCID_BASE, LinearTx4.data[0]);  //At lease , we must transmit first byte. 
    #endif   
}
uint8_t  UART4_ReadX( void)
{
    #ifdef UART4_USE_AS_MODBUS
        return RingBuffReadByte(&RingRx4);
    #else
        return 0;
    #endif    
   
}



















































































































































































































































































































































































































































































































































































