/******************************************************************************/
/* Williams Advanced Engineering    						 Copyright(C) 2020*/
/* Grove          										  All rights reserved */
/*                                                                            */
/******************************************************************************/

#include "Ios_Terminal.h"

/*----------------------------------------------------------------------------*/
/* LOCAL CONSTANT DEFINITIONS                                                 */
/*----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------*/
/* GLOBAL VARIABLE DEFINITIONS                                                */
/*----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------*/
/* LOCAL GLOBAL VARIABLE DEFINITIONS                                          */
/*----------------------------------------------------------------------------*/
                 
char  m_cLineBuffer[LINE_LEN];               //* Working line buffer
uint32  m_uLinePtr;                        //* Working line pointer
uint32  m_uLineEndPtr;                     //* Working line pointer

char  m_cRecallBuff[NUM_RECALLS][LINE_LEN];  //* Recall buffer
uint8 m_bRecallCounter;                    //* which recall buffer

TerminalQueueType tTerminalQueue = {0,0,{0},0,0,{0}};

/*----------------------------------------------------------------------------*/
/*  FUNCTION : fnIosTerminalInitialise                                        */
/*  DESC     : Initialises the RS232 terminal                                 */
/*  PARAMS   : none                                                           */
/*  RETURNS  : none                                                           */
/*----------------------------------------------------------------------------*/
void fnIosTerminalInitialise (void)
{
     uint32 i;

     m_uLinePtr      = 0;                  //* Reset line buffer            
     m_uLineEndPtr   = 0;                  //* Reset line buffer            

     m_bRecallCounter = NUM_RECALLS - 1;   //* which recall buffer

     
     //* Clear recall buffers
     for (i = 0; i < NUM_RECALLS; i++) 
         m_cRecallBuff[i][0] = '\0';    

     for (i = 0; i < TX_BUFFER_LEN; i++)
         tTerminalQueue.bTxQueue[i] = '\0';

     for (i = 0; i < RX_BUFFER_LEN; i++)
         tTerminalQueue.bRxQueue[i] = '\0';

     sciInit ();
}

/*----------------------------------------------------------------------------*/
/*  FUNCTION : fnIosTerminalGetChar                                           */
/*  DESC     : Get new character from the receiver buffer                     */
/*  PARAMS   : none                                                           */
/*  RETURNS  : Returns ASCII character or FALSE if buffer empty               */
/*----------------------------------------------------------------------------*/
uint8  fnIosTerminalGetChar ( long port_number  )
{
    uint8  cCharacter = FALSE;

    if(sciIsRxReady(sciREG))
        cCharacter = sciReceiveByte(sciREG);

    //* Get rid of '\r's
    if (cCharacter == '\r')  cCharacter  = FALSE;

    return (cCharacter);
}
/*----------------------------------------------------------------------------*/
/*  FUNCTION : fnIosTerminalGetStr                                            */
/*  DESC     : Gets a string from the Receiver buffer                         */
/*  PARAMS   : none                                                           */
/*  RETURNS  : Returns pointer to received string                             */
/*----------------------------------------------------------------------------*/
char *fnIosTerminalGetStr(void)
{                   

static uint32 uEscapeSequence = 0;
    char  uNewChar;
    uint32  i;
                        

    //* Drop out if Rx buffer empty
    if ( sciIsRxReady(sciREG) != 1)
        return (NULL);            


    uNewChar = fnIosTerminalGetChar(0);               //* Get first character       

    while (uNewChar != FALSE)                        //* While no more in RX buff  
    {             
          
           if ((uEscapeSequence == 0) && (uNewChar == ESCAPE_CHAR1)) {
                   uEscapeSequence = 1;
           }
           else
           if ((uEscapeSequence == 1) && (uNewChar == ESCAPE_CHAR2)) {
                   uEscapeSequence = 2;
           }
           else
           if (   (uNewChar == CTRL_L)               //* CTRL-L to pull back last      
               || ((uEscapeSequence == 2) && (uNewChar == UP_CHAR))
           ){
               fnIosTerminalPutChar(0, '\r');                //* Back to start of line        
               fnIosTerminalPutStr(cAppPrompt);           //* Print prompt                  
               for  (i=0; i < m_uLinePtr; i++)       //* Delete current line           
                    fnIosTerminalPutChar(0, ' ');
               m_uLinePtr = 0;                       //* Reset line buffer             
               m_cLineBuffer[m_uLinePtr] = '\0';
               fnIosTerminalPutChar(0, '\r');                //* Print prompt                  
               fnIosTerminalPutStr(cAppPrompt);

               strncpy(m_cLineBuffer,m_cRecallBuff[m_bRecallCounter], LINE_LEN);  //* Copy buffer into current line
               m_uLinePtr = strlen(m_cLineBuffer);
               m_uLineEndPtr = m_uLinePtr;
               fnIosTerminalPutStr(m_cLineBuffer);        //* Echo the new line              
               
               //* Cycle through recall buffera
               if (m_bRecallCounter > 0)
                   m_bRecallCounter --;
               else
                   m_bRecallCounter = NUM_RECALLS - 1;
                   
               uEscapeSequence = 0;
                   
           }
           else
           if ((uEscapeSequence == 2) && (uNewChar == LEFT_CHAR)) {
               if (m_uLinePtr > 0) 
               {
                   fnIosTerminalPutChar(0, '\b');                //* Back one char        
                   m_uLinePtr--;
                }
               uEscapeSequence = 0;
                   
           }
           else
           if ((uEscapeSequence == 2) && (uNewChar == RIGHT_CHAR)){
                   if (m_uLinePtr < m_uLineEndPtr)
                    fnIosTerminalPutChar(0, m_cLineBuffer[m_uLinePtr++]); /* Forward one car, actually, reprint the current one */
               uEscapeSequence = 0;
           }
           else
           if (uEscapeSequence == 2) {
               uEscapeSequence = 0;
                   /* Do nothing */
           }
           else                                      //* Backspace... 
           if (    (uNewChar >= START_ASCII)         //* If valid ASCII character  
                && (uNewChar <= END_ASCII  )
           ){                                        //* Put in command buffer     
                fnIosTerminalPutChar(0, uNewChar);     //* Echo character          
               
                for (i=m_uLinePtr; i<m_uLineEndPtr; i++)
                    fnIosTerminalPutChar(0, m_cLineBuffer[i]); /* echo end of the line */
                    
                if (m_uLineEndPtr < (LINE_LEN -1))      //* point to next character  
                    m_uLineEndPtr++;
                    
                while (i != m_uLinePtr) {
                    fnIosTerminalPutChar(0, '\b');                 /* Go back to the edition point */   
                    m_cLineBuffer[i] = m_cLineBuffer[i-1]; /* and update the line buffer */   
                    i--;
                }
                
               /* Finally, copy the new char at its position */
               m_cLineBuffer[m_uLinePtr++] = uNewChar;
           }
           else
           if ((uNewChar == '\b') && (m_uLinePtr > 0)) {

                  fnIosTerminalPutChar(0, '\b');               //* Send BS      */

                  m_uLinePtr--;
               m_uLineEndPtr--;

               for (i = m_uLinePtr; i<(m_uLineEndPtr); i++) {
                   m_cLineBuffer[i] = m_cLineBuffer[i+1];
                   fnIosTerminalPutChar(0, m_cLineBuffer[i]);
               }
               
               fnIosTerminalPutChar(0, ' ');
               
               for (i= m_uLineEndPtr+1; i> m_uLinePtr; i--) {
                      fnIosTerminalPutChar(0, '\b');
               }
               
           }  
           else
           if (uNewChar == '\n') {                         //* LF sets end of line.....     

               fnIosTerminalPutChar(0, '\r');                //* Echo CR and Line feed        
               fnIosTerminalPutChar(0, '\n');

               m_cLineBuffer[m_uLineEndPtr] = '\0';        //* put NULL on end              
                
               //* If a valid string and different to last command 
               if (   (m_uLineEndPtr > 0) 
                   && (strncmp(m_cRecallBuff[NUM_RECALLS-1], m_cLineBuffer, LINE_LEN))
               ){  
                  //* Copy down all old recalls
                  for (i = 0; i < NUM_RECALLS-1; i++)
                      strncpy(m_cRecallBuff[i], m_cRecallBuff[i+1], LINE_LEN);

                  //* insert latest command
                  strcpy(m_cRecallBuff[NUM_RECALLS-1],m_cLineBuffer);
                   
 
               } 
               
               //* Reset recall counter
               m_bRecallCounter = NUM_RECALLS - 1;

               m_uLinePtr = 0;                       //* Reset line ptr               
               m_uLineEndPtr = 0;                    //* Reset line ptr               
               return (m_cLineBuffer);               //* Return complete string       
           }
           
           uNewChar = fnIosTerminalGetChar(0);        //* Get next character           

    }

    return (NULL);                         /* Complete line not ready yet   */
}
/*----------------------------------------------------------------------------*/
/*  FUNCTION : fnIosTerminalTxComplete                                        */
/*  DESC     : Check Tx queue to make sure every thing has been transmitted   */
/*  PARAMS   : none                                                           */
/*  RETURNS  : none                                                           */
/*----------------------------------------------------------------------------*/
uint8 fnIosTerminalTxComplete(void)
{
    uint8 uResult;
    uint32 uNoCharactersWaiting;

    //* Get number of charactrers waiting
    if( tTerminalQueue.wTxNewestEntry < tTerminalQueue.wTxOldestEntry)
        uNoCharactersWaiting = TX_BUFFER_LEN - tTerminalQueue.wTxOldestEntry + tTerminalQueue.wTxNewestEntry;
    else
        uNoCharactersWaiting = tTerminalQueue.wTxNewestEntry - tTerminalQueue.wTxOldestEntry;

    //* CHeck if there are any characters waiting in Tx queue
    if (0 != uNoCharactersWaiting)
        uResult = FALSE;
    else
        uResult = TRUE;

    return uResult;
}

/*----------------------------------------------------------------------------*/
/*  FUNCTION : fnIosFlushTxQueue                                              */
/*  DESC     : Send all the characters waiting in the queue                   */
/*  PARAMS   : none                                                           */
/*  RETURNS  : none                                                           */
/*----------------------------------------------------------------------------*/
void fnIosFlushTxQueue(void)
{
    while(!fnIosTerminalTxComplete())
    {
        fnIosTerminalTx();
    }
}




/*----------------------------------------------------------------------------*/
/*  FUNCTION : fnIosTerminalTx                                                */
/*  DESC     : Polls the transmitter to see if new data can be transmitted    */
/*  PARAMS   : none                                                           */
/*  RETURNS  : none                                                           */
/*----------------------------------------------------------------------------*/
void fnIosTerminalTx(void)
{
	//uint32 TxBaseAddress = sciREG;
    uint32 uNoCharactersWaiting;
    char  cCharacter;
    int i;

     //* Get number of characters waiting
    //uNoCharactersWaiting = uxQueueMessagesWaiting(m_xTransmitQueueHandle);
    if( tTerminalQueue.wTxNewestEntry < tTerminalQueue.wTxOldestEntry)
        uNoCharactersWaiting = TX_BUFFER_LEN - tTerminalQueue.wTxOldestEntry + tTerminalQueue.wTxNewestEntry;
    else
        uNoCharactersWaiting = tTerminalQueue.wTxNewestEntry - tTerminalQueue.wTxOldestEntry;
    
    //* Limit number of characters to write to 16 - 0.5ms at 230400bds
    if (uNoCharactersWaiting > 16) uNoCharactersWaiting = 16;
    
    //* Send up to uNoCharactersWaiting per loop
    for (i = 0; i < uNoCharactersWaiting; i++)
    {
         //* if queue not empty and fifo not full 
         if (sciIsTxReady(sciREG))
         { 
             //* Read transmit character from Tx queue 
             //xQueueReceive( m_xTransmitQueueHandle, &cCharacter , NON_BLOCKING_DELAY);
                                                            
             //* Copy character to UART TX buffer 
 	     	 //XUartPs_WriteReg(TxBaseAddress, XUARTPS_FIFO_OFFSET, cCharacter);
             cCharacter = tTerminalQueue.bTxQueue[tTerminalQueue.wTxOldestEntry];
             sciSend(sciREG, 1, (uint8*)&cCharacter);

             if(tTerminalQueue.wTxOldestEntry < TX_BUFFER_LEN)
                 tTerminalQueue.wTxOldestEntry++;
             else
                 tTerminalQueue.wTxOldestEntry = 0;
         }
         else  
         {  
            //* break loop as we cant write any more data to fifo
          	break;
         } 
    }

}      
/*----------------------------------------------------------------------------*/
/*  FUNCTION : fnIosTerminalRx                                                */
/*  DESC     : Polls the receiver to see if new data has been received        */
/*  PARAMS   : none                                                           */
/*  RETURNS  : none                                                           */
/*----------------------------------------------------------------------------*/
void fnIosTerminalRx(void)
{
	//uint32 RxBaseAddress = STDOUT_BASEADDRESS;
    uint32 uRxFifoData;
    uint32 uRxData;
    uint8  bRxCharacter;

    //* Any data available in receive UART FIFO
    //uRxFifoData = XUartPs_IsReceiveData(RxBaseAddress);

    //* If data in receiver fifo
    //if (uRxFifoData)
    if(sciIsRxReady(sciREG))
    {
       //* Check if there is space in receive queue
//       if (uxQueueSpacesAvailable (m_xReceiveQueueHandle))
//       {
          //* Read character from UART FIFO
          //uRxData = XUartPs_ReadReg(RxBaseAddress, XUARTPS_FIFO_OFFSET);

          //* Rx queue need a uint8
          bRxCharacter  = (uint8)sciReceiveByte(sciREG);
         
          //* Store data in receive queue
          //xQueueSend(m_xReceiveQueueHandle, &bRxCharacter, NON_BLOCKING_DELAY);


          //* Stop watch dog if CTRL-C received      
          //if (bRxCharacter == CTRL_C)
          //   fnIosWatchDogDisable();
//       }

    }

}     
/*----------------------------------------------------------------------------*/
/*  FUNCTION : fnIosTerminalPoll                                              */
/*  DESC     : Polls the terminal receiver and transmitter to test for TX,RX  */
/*  PARAMS   : none                                                           */
/*  RETURNS  : none                                                           */
/*----------------------------------------------------------------------------*/
void fnIosTerminalPoll(void)
{
    //* Check for received characters
    fnIosTerminalRx();
    
    //* Check for received characters to transmit
    fnIosTerminalTx();                       

}
/*----------------------------------------------------------------------------*/
/*  FUNCTION : fnIosTerminalPutChar                                           */
/*  DESC     : Transfers a character to the transmit buffer                   */
/*  PARAMS   : cInChar - Character to print                                   */
/*  RETURNS  : TRUE/FALSE - Pass Fail Flag                                    */
/*----------------------------------------------------------------------------*/
void fnIosTerminalPutChar (long port_number, uint8 character)
{
    char cInChar = character;

    //* Copy character to transmit queue
    //fnIosTerminalCharToTxQueue(cInChar);
    tTerminalQueue.bTxQueue[tTerminalQueue.wTxNewestEntry] = cInChar;

    if(tTerminalQueue.wTxNewestEntry < TX_BUFFER_LEN)
        tTerminalQueue.wTxNewestEntry++;
    else
        tTerminalQueue.wTxNewestEntry = 0;

} 
/*----------------------------------------------------------------------------*/
/*  FUNCTION : fnIosTerminalPutStr                                            */
/*  DESC     : Copy string to the transmit buffer                             */
/*  PARAMS   : *str_ptr : Pointer to character string to be output            */
/*  RETURNS  : none                                                           */
/*----------------------------------------------------------------------------*/
void fnIosTerminalPutStr(const char *str_ptr)
{
    uint16 wSpacesAvailable = 0;
    //* Exit if full line isnt going to fit in print queue  
//    if ( uxQueueSpacesAvailable(m_xTransmitQueueHandle) < MAX_LINE_LENGTH)
//        return;

    // work out available space
    if( tTerminalQueue.wTxNewestEntry < tTerminalQueue.wTxOldestEntry)
        wSpacesAvailable = TX_BUFFER_LEN - ((TX_BUFFER_LEN - tTerminalQueue.wTxOldestEntry) + tTerminalQueue.wTxNewestEntry);

    else if(tTerminalQueue.wTxNewestEntry > tTerminalQueue.wTxOldestEntry)
        wSpacesAvailable = TX_BUFFER_LEN - tTerminalQueue.wTxNewestEntry;

    else
        wSpacesAvailable = TX_BUFFER_LEN;


    if (wSpacesAvailable < (MAX_LINE_LENGTH+2))
            return;

    while (*str_ptr != '\0')                              /* Null terminates   */
    {
        if (*str_ptr == '\n')
          fnIosTerminalPutChar(0, '\r');                  /* If CR send LF     */

        fnIosTerminalPutChar(0, *str_ptr);                  /* wait until space  */
        str_ptr++;                                          /* Increment pointer */
    }
}
/*----------------------------------------------------------------------------*/
/*  FUNCTION : fnIosStdSubPutChar                                             */
/*  DESC     : Transfers a character to the transmit buffer                   */
/*  PARAMS   : cInChar - Character to print                                   */
/*  RETURNS  : TRUE/FALSE - Pass Fail Flag                                    */
/*----------------------------------------------------------------------------*/
uint8 fnIosTerminalCharToTxQueue (char cInChar)
{
    uint8  uResult = FALSE;

    //* Add character to transit queue         
//    if ( xQueueSend( m_xTransmitQueueHandle, &cInChar, NON_BLOCKING_DELAY) == pdTRUE)
//    {
        //* Character sent ok
        uResult = TRUE;
//    }

    return(uResult);
}
/*--------------------------------------------------------------------------*/
