/******************************************************************************
 * @file     main.c
 * @brief    Main program body
 * @version  V4.0.0
 * @date     30-July-2026
 *
 * @note
 * Copyright (C) 2022 Spintrol Electronic Technology (Shanghai) Co., Ltd.. All rights reserved.
 *
 * @attention
 * THIS SOFTWARE JUST PROVIDES CUSTOMERS WITH CODING INFORMATION REGARDING
 * THEIR PRODUCTS, WHICH AIMS AT SAVING TIME FOR THEM. SPINTROL SHALL NOT BE
 * LIABLE FOR THE USE OF THE SOFTWARE. SPINTROL DOES NOT GUARANTEE THE
 * CORRECTNESS OF THIS SOFTWARE AND RESERVES THE RIGHT TO MODIFY THE SOFTWARE
 * WITHOUT NOTIFICATION.
 *
 ******************************************************************************/

#include<stdio.h>
#include<stdlib.h>

#if defined(SPC1158)
#include "spc1158.h"
#elif defined(SPD1148)
#include "spd1148.h"
#elif defined(SPD1178)
#include "spd1178.h"
#elif defined(SPD1188)
#include "spd1188.h"
#elif defined(SPD1163)
#include "spd1163.h"
#else
#include "spc1168.h"
#endif

/* Maximum size of buffer frame */
#define UART_RX_BUF_SIZE_MAX 256
/* Minimum size of buffer frame */
#define UART_RX_BUF_SIZE_MIN 2

/* UART Receive FIFO interrupt trigger threshold */
#define UART_RXFIFO_THRESHOLD UART_RXFIFO_32BYTE_OR_MORE

/* UART Transmit FIFO interrupt trigger threshold */
#define UART_TXFIFO_THRESHOLD UART_TXFIFO_EMPTY


typedef struct DeviceUartPack
{
    uint8_t* pu8RxBuf;
    uint16_t u16RxLength;

    /* A frame was received */
    uint8_t u8RxDataEnd; 
} DeviceUartPack_t, *pDeviceUartPack_t;


DeviceUartPack_t MyDeviceUartPackTest;

uint8_t gu8UartRxBuff[UART_RX_BUF_SIZE_MAX];


void UartDataPack_Init(DeviceUartPack_t* myDataPack, uint8_t* pu8Buffer)
{
    myDataPack->pu8RxBuf = pu8Buffer;
    myDataPack->u16RxLength = 0;

    myDataPack->u8RxDataEnd = 0;
}

uint8_t BCCXOR_Calculate(uint8_t* pu8Data, uint16_t u16DataLen)
{
    uint8_t result = 0;
    uint16_t index = 0;

    if(NULL == pu8Data)
    {
        return 0;
    }

    while(u16DataLen > 0)
    {
        result ^= pu8Data[index++];  
        u16DataLen--;
    }

    return result;
}

void UART_TX_Byte(uint8_t u8Data) 
{
    /* Write the datum to UART Transmit Holding Register */
    UART_WriteByte(UART, u8Data);
      
    /* Wait for the TX FIFO empty */
    while(!UART_IsTxDone(UART));
}


/*************************************************************************************************************************
*
* @brief In this case, Serial port tools receive indefinite length of data
*
* @note
*        For detailed procedures, please refer to the UART documentation in the APPNote directory
*
*************************************************************************************************************************/


int main()
{
    FLASH_WALLOW();
#if defined(SPC1158)
    FLASH_SetTiming(100000000);
    /* Disable flash write access after flash operation had done */
    FLASH_WDIS();

    CLOCK_InitWithRCO(100000000UL);
#else
    FLASH_SetTiming(200000000);
    /* Disable flash write access after flash operation had done */
    FLASH_WDIS();

    CLOCK_InitWithRCO(200000000UL);
#endif

    Delay_Init();

    /* Configure GPIO pin as UART function */
    GPIO_SetPinChannel(GPIO_34, GPIO34_UART_TXD);
    GPIO_SetPinChannel(GPIO_35, GPIO35_UART_RXD);

    /* UART Init */
    UART_Init(UART, 38400);

    /* RX FIFO trigger level: 16 */
    /* TX FIFO trigger level:  0 */
    UART_SetFIFOTriggerThreshold(UART, UART_RXFIFO_THRESHOLD, UART_TXFIFO_THRESHOLD);

    /* Enable UART interrupt in MCU side */
    NVIC_EnableIRQ(UART_IRQn);
    
    /* Enable RX interrupt */
    UART_EnableRxDataAvailableInt(UART);

    /* Enable Receiver Time-out Interrupt */
    UART_EnableRxTimeoutInt(UART);

    /* Enable UART interrupt (main switch of UART interrupt) */
    UART_EnableInt(UART);

    /* Init UART data pack struct */
    UartDataPack_Init(&MyDeviceUartPackTest, gu8UartRxBuff);

    while(1)
    {
        if(MyDeviceUartPackTest.u8RxDataEnd)
        {
            uint8_t* pu8Data = MyDeviceUartPackTest.pu8RxBuf;
            uint16_t u16Len = MyDeviceUartPackTest.u16RxLength;

            if((u16Len >= UART_RX_BUF_SIZE_MIN) && (pu8Data[u16Len - 1] == BCCXOR_Calculate(pu8Data, u16Len - 1)))
            {
                /* If the data is correct, we return the value */
                UART_Write(UART, pu8Data, 0, u16Len);
            }
            else
            {
                /* An error occured, Send an error value */
                UART_TX_Byte(0XFF);
            }

            MyDeviceUartPackTest.u16RxLength = 0;
            MyDeviceUartPackTest.u8RxDataEnd = 0;
        }
    }
}


void UART_IRQHandler(void)
{
    uint8_t u8data;
    uint8_t u8error;

    /* RX data more than 32 */
    if(UART_GetRxDataAvailableIntStatus(UART))
    {
        u8error = UART->UARTLSR.all;

        /* Read data until the receive FIFO is empty */
        while(UART_GetRxFIFOLevel(UART) > 1)
        {
            u8data = UART_ReadByte(UART);

            if((!MyDeviceUartPackTest.u8RxDataEnd) && (!(u8error & UARTLSR_ALL_FIFOERR_FIFO_ERROR_OCCUR)))
            {
                gu8UartRxBuff[MyDeviceUartPackTest.u16RxLength] = u8data;
                MyDeviceUartPackTest.u16RxLength = ((MyDeviceUartPackTest.u16RxLength + 1) % UART_RX_BUF_SIZE_MAX);
            }

            u8error = UART->UARTLSR.all;
        }
    }

    if(UART_GetRxTimeoutIntStatus(UART))
    {
        u8error = UART->UARTLSR.all; 
        UART_DisableRxTimeoutInt(UART);

        /* Read data until the receive FIFO is empty */
        while(UART_GetRxFIFOLevel(UART))
        {
            u8data = UART_ReadByte(UART);

            if((!MyDeviceUartPackTest.u8RxDataEnd) && (!(u8error & UARTLSR_ALL_FIFOERR_FIFO_ERROR_OCCUR)))
            {
                gu8UartRxBuff[MyDeviceUartPackTest.u16RxLength] = u8data;
                MyDeviceUartPackTest.u16RxLength = ((MyDeviceUartPackTest.u16RxLength + 1) % UART_RX_BUF_SIZE_MAX);
            }

            u8error = UART->UARTLSR.all;
        }

        MyDeviceUartPackTest.u8RxDataEnd = 1;
        UART_EnableRxTimeoutInt(UART);
    }
}


