/******************************************************************************
 * @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<string.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


char                sCRCTestStr[100]         = "CRC calculate access done!";
uint8_t             au8CRCTestStr[100]         = {0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 
0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE};
uint32_t            u32Result;
static ErrorStatus         Status;




/******************************************************************************
 * @brief      For output data, the entire data is reversed by bit
 *
 * @param[in]  u32Value           :  Output Data
 * @param[in]  u32ValueActualWidth:  Output Data Actual Width
 *                                   For CRC8, u32ValueActualWidth is 8;
 *                                   For CRC16, u32ValueActualWidth is 16;
 *                                   For CRC24, u32ValueActualWidth is 24;
 *                                   For CRC32, u32ValueActualWidth is 32
 *
 * @return     u32Number          :  Reversed Output Data
 *
 ******************************************************************************/
uint32_t ReverseOutputData(uint32_t u32Value, uint32_t u32ValueActualWidth)
{
    uint32_t u32Number = 0;
    uint32_t i = 0;

    for (i = 1; i < u32ValueActualWidth; i++)
    {
        u32Number |= u32Value & 1;
        u32Number <<= 1;
        u32Value >>= 1;
    }
    
    u32Number |= u32Value;

    return u32Number;
}




/******************************************************************************
 * @brief      For input data, the byte sequence remains unchanged
 *             only bit sequence in each byte is reversed.
 *
 * @param[in]  pu8DataStr:  Pointer to the input data stream
 * @param[in]  u32DataLen:  Data length in byte
 *
 * @return     None
 *
 ******************************************************************************/
void ReverseInputData(uint8_t *pu8DataStr, uint32_t u32DataLen)
{
    uint32_t i, j, u32Number, u32Value;
    for (i = 0; i < u32DataLen; i++)
    {
        u32Number = 0;
        j = 0;
        u32Value = pu8DataStr[i];
        
        for (j = 1; j < 8; j++)
        {
            u32Number |= u32Value & 1;
            u32Number <<= 1;
            u32Value >>= 1;
        }

        u32Number |= u32Value;
        
        pu8DataStr[i] = u32Number;
    }
}




/**************************************************************************
 *
 * @brief      "CRC calculate access done!" is calculated by mcu firstly, 
 *             then compare the mcu result with online result, if equal,
 *             test pass.
 *
 * @note       There is no need to use interrupts to get CRC results, because 
 *             CRC results are obtained immediately. If you must use interrupts,
 *             NVIC_EnableIRQ(CRC_IRQn) must be placed after CRC calculation, 
 *             otherwise, an interrupt will occur before CRC result is obtained.
 *
 **************************************************************************/




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();

    /*
     * Init the UART
     *
     * 1.Set the GPIO34/35 as UART FUNC
     *
     * 2.Enable the UART CLK
     *
     * 3.Set the rest para
     */
    GPIO_SetPinChannel(GPIO_34, GPIO34_UART_TXD);
    GPIO_SetPinChannel(GPIO_35, GPIO35_UART_RXD);
    CLOCK_EnableModule(UART_MODULE);
    UART_Init(UART, 38400);

    /*
     *  Algorithm             Poly          Init Value    RefIn    RefOut   XorOut 
     *  CRC-16/CCITT          0x1021        0x0000        true     true     0x0000
     */
    CRC_Disable(CRC);
    CRC_SetMode(CRC, CRC_MODE_16_CCITT);
    CRC_Enable(CRC);
    u32Result = CRC_Calculate(CRC, (uint8_t *)sCRCTestStr, strlen(sCRCTestStr));
    if (u32Result != 0x0A77)
    {
        return 0;
    }  
  
    /*
     *  Algorithm             Poly          Init Value    RefIn    RefOut   XorOut 
     *  CRC-16/IBM            0x8005        0x0000        true     true     0x0000
     */
    CRC_Disable(CRC);
    CRC_SetMode(CRC, CRC_MODE_16_IBM);
    CRC_Enable(CRC);
    u32Result = CRC_Calculate(CRC, (uint8_t *)sCRCTestStr, strlen(sCRCTestStr));
    if (u32Result != 0x73F8)
    {
        return 0;
    }  

    /*
     *  Algorithm             Poly          Init Value    RefIn    RefOut   XorOut 
     *  CRC-16/DNP            0x3D65        0x0000        true     true     0xFFFF
     */
    CRC_Disable(CRC);
    CRC_SetMode(CRC, CRC_MODE_16_DNP);
    CRC_Enable(CRC);
    u32Result = CRC_Calculate(CRC, (uint8_t *)sCRCTestStr, strlen(sCRCTestStr));
    u32Result ^= 0xFFFF;
    if (u32Result != 0x8111)
    {
        return 0;
    }  
    
    /*
     *  Algorithm             Poly          Init Value    RefIn    RefOut   XorOut 
     *  CRC-32/IEEE802P3      0x04C11DB7    0xFFFFFFFF    true     true     0xFFFFFFFF
     */
    CRC_Disable(CRC);
    CRC_SetMode(CRC, CRC_MODE_32_IEEE802P3);
    CRC_Enable(CRC);
    /*
     * When Init Value is not all 0, need to feed special stream(FrameHead)
     * to generate Init Value.
     * for CRC8, stream format is 0xXX000000(low 3 bytes are always 0x00)
     * for CRC16, stream format is 0xXXXX0000(low 2 bytes are always 0x00)
     * for CRC32, stream format is 0xXXXXXXXX
     *
     * At first use, FrameHead must be caculated, step is:
     * 1, Use online CRC web to get target result, for "CRC calculate access done!"
     * , RC-32/IEEE802P3 result is 0xF985B955;
     *
     * 2, Change FrameHead from 0x00000000 to 0xFFFFFFFF, each time judge 
     * if CRC result is equal to RC-32/IEEE802P3 online result(0xF985B955);
     *
     * 3, When CRC result is equal to online result(0xF985B955), caculation
     * finished and current FrameHead(0x9226f562) is what we need
     */
    Status = CRC_CalculateWithInitValueIsNotZero(CRC, (uint8_t *)sCRCTestStr, 
    strlen(sCRCTestStr), 0x9226f562, &u32Result);
    u32Result ^= 0xFFFFFFFF;
    if (u32Result != 0xF985B955)
    {
        return 0;
    }

    if (Status != SUCCESS)
    {
        return 0;
    }
    
    CRC_Disable(CRC);
    CRC_SetMode(CRC, CRC_MODE_32_IEEE802P3);
    CRC_Enable(CRC);
    Status = CRC_CalculateWithInitValueIsNotZero(CRC, au8CRCTestStr, 4, 0x9226f562, &u32Result);
    u32Result ^= 0xFFFFFFFF;
    if (u32Result != 0x677BDD77)
    {
        return 0;
    }

    if (Status != SUCCESS)
    {
        return 0;
    }
    
    CRC_Disable(CRC);
    CRC_SetMode(CRC, CRC_MODE_32_IEEE802P3);
    CRC_Enable(CRC);
    Status = CRC_CalculateWithInitValueIsNotZero(CRC, au8CRCTestStr, 5, 0x9226f562, &u32Result);
    u32Result ^= 0xFFFFFFFF;
    if (u32Result != 0xCDBF173E)
    {
        return 0;
    }

    if (Status != SUCCESS)
    {
        return 0;
    }

    CRC_Disable(CRC);
    CRC_SetMode(CRC, CRC_MODE_32_IEEE802P3);
    CRC_Enable(CRC);
    Status = CRC_CalculateWithInitValueIsNotZero(CRC, au8CRCTestStr, 6, 0x9226f562, &u32Result);
    u32Result ^= 0xFFFFFFFF;
    if (u32Result != 0xB5121A56)
    {
        return 0;
    }

    if (Status != SUCCESS)
    {
        return 0;
    }
    
    CRC_Disable(CRC);
    CRC_SetMode(CRC, CRC_MODE_32_IEEE802P3);
    CRC_Enable(CRC);
    Status = CRC_CalculateWithInitValueIsNotZero(CRC, au8CRCTestStr, 7, 0x9226f562, &u32Result);
    u32Result ^= 0xFFFFFFFF;
    if (u32Result != 0x6F0A0F8B)
    {
        return 0;
    }

    if (Status != SUCCESS)
    {
        return 0;
    }
    
    /*
     *  Algorithm             Poly          Init Value    RefIn    RefOut   XorOut 
     *  CRC-16/T10-DIF        0x8BB7        0x0000        false    false    0x0000
     */
    CRC_Disable(CRC);
    CRC_SetMode(CRC, CRC_MODE_16_T10_DIF);
    CRC_Enable(CRC);
    ReverseInputData((uint8_t *)sCRCTestStr, strlen(sCRCTestStr));
    u32Result = CRC_Calculate(CRC, (uint8_t *)sCRCTestStr, strlen(sCRCTestStr));
    u32Result = ReverseOutputData(u32Result, 16);
    if (u32Result != 0x69A9)
    {
        return 0;
    }

    printf("Test Pass\n");

    while (1)
    {

    }
}


