/******************************************************************************
 * @file     ymodem.c
 * @brief    Y-Modem protocol functions.
 * @version  V4.0.3
 * @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 "ymodem.h"
#include "common.h"
#include <string.h>
#include <stdio.h>


/* Array for file name string */
uint8_t au8FileName[FILE_NAME_LENGTH];
/* Array for file size string */
uint8_t au8FileSize[FILE_SIZE_LENGTH];
/* Array for Packet frame data */
uint8_t au8PacketData[PACKET_1K_SIZE + PACKET_OVERHEAD];




/******************************************************************************
 * @brief      Receive byte from sender
 *
 * @param[in]  u32Timeout:  Timeout
 * @param[out] pu8Data   :  Received byte data
 *
 * @return      0 - Byte received
 *             -1 - Timeout
 *
 ******************************************************************************/
static int32_t Receive_Byte(uint8_t *pu8Data, uint32_t u32Timeout)
{
    while (u32Timeout-- > 0)
    {
        /* Byte data received */
        if (UART_IsRxNotEmpty(UART))
        {
            *pu8Data = UART_ReadByte(UART);

            return 0;
        }
    }

    /* Timeout */
    return -1;
}




/******************************************************************************
 * @brief      Send a byte
 *
 * @param[in]  pu8Data:  Byte data to be sent
 * @param[in]  u32Size:  Byte data count
 *
 * @return      0 - Bytes have been sent
 *
 ******************************************************************************/
static uint32_t Send_Bytes(uint8_t *pu8Data, uint32_t u32Size)
{
    uint32_t i = 0;

#if RS485_INTERFACE_ENABLED > 0
    /* RS485 Tx Enable */
    GPIO_WritePin(RS485_CONTROL_PIN, GPIO_LEVEL_LOW);
#endif

    while (i < u32Size)
    {
        UART_WriteByte(UART, pu8Data[i++]);

        /* Wait until transmit finished */
        while (UART_IsTxDone(UART) == 0)
        {
        }
    }

#if RS485_INTERFACE_ENABLED > 0
    /* RS485 Rx Enable */
    GPIO_WritePin(RS485_CONTROL_PIN, GPIO_LEVEL_HIGH);
#endif

    return 0;
}




/******************************************************************************
 * @brief      Update CRC16 for input byte
 *
 * @param[in]  u16CRCIn:  CRC input value
 * @param[in]  u8Data  :  Input byte
 *
 * @return     CRC value
 *
 ******************************************************************************/
static uint16_t UpdateCRC16(uint16_t u16CRCIn, uint8_t u8Data)
{
    uint32_t u32CRCVal = u16CRCIn;
    uint32_t u32DataIn = u8Data | 0x100;

    do
    {
        u32CRCVal <<= 1;
        u32DataIn <<= 1;

        if (u32DataIn & 0x100)
        {
            ++u32CRCVal;
        }

        if (u32CRCVal & 0x10000)
        {
            u32CRCVal ^= 0x1021;
        }
    }
    while (!(u32DataIn & 0x10000));

    return (u32CRCVal & 0xFFFFU);
}




/******************************************************************************
 * @brief      Calculate CRC16 for YModem packet
 *
 * @param[in]  pu8Data:  Packet data
 * @param[in]  u32Size:  Packet length
 *
 * @return     CRC value of packet data
 *
 ******************************************************************************/
static uint16_t YModem_CalCRC16(const uint8_t *pu8Data, uint32_t u32Size)
{
    uint32_t u32CRCVal = 0x0000;
    const uint8_t *pu8DataEnd = pu8Data + u32Size;

    while (pu8Data < pu8DataEnd)
    {
        u32CRCVal = UpdateCRC16(u32CRCVal, *pu8Data++);
    }

    u32CRCVal = UpdateCRC16(u32CRCVal, 0);
    u32CRCVal = UpdateCRC16(u32CRCVal, 0);

    return (u32CRCVal & 0xFFFFU);
}




/******************************************************************************
 * @brief      Receive a packet from sender
 *
 * @param[in]  pu8Data   :  Received data
 * @param[in]  u32Timeout:  Timeout
 * @param[out] pi32Len   :  Data length
 *                           0 - End of transmission
 *                          -1 - Abort by sender
 *                          >0 - Packet data length
 *
 * @return      0 - Normally return
 *             -1 - Timeout or packet error
 *              1 - Abort by user
 *
 ******************************************************************************/
static int32_t YModem_ReceivePacket(uint8_t *pu8Data, int32_t *pi32Len, uint32_t u32Timeout)
{
    uint32_t i, u32PacketSize;
    uint8_t u8ByteData;

    *pi32Len = 0;

    /* Try to receive a byte from sender */
    if (Receive_Byte(&u8ByteData, u32Timeout) != 0)
    {
        /* Timeout */
        return -1;
    }

    switch (u8ByteData)
    {
        case MODEM_SOH:     /* Start of 128-byte data packet */
            u32PacketSize = PACKET_SIZE;
            break;

        case MODEM_STX:     /* Start of 1024-byte data packet */
            u32PacketSize = PACKET_1K_SIZE;
            break;

        case MODEM_EOT:     /* End of transmission */
            return 0;

        case MODEM_CAN:      /* Abort by sender */
            if ((Receive_Byte(&u8ByteData, u32Timeout) == 0) && (u8ByteData == MODEM_CAN))
            {
                *pi32Len = -1;
                return 0;
            }
            else
            {
                /* Packet error */
                return -1;
            }

        case ABORT1:  /* Abort by user */
        case ABORT2:
            return 1;

        default:      /* Packet error */
            return -1;
    }


    /* Save the first byte of the packet */
    *pu8Data = u8ByteData;

    /* Receive the following byte of the packet */
    for (i = 1; i < (u32PacketSize + PACKET_OVERHEAD); i++)
    {
        if (Receive_Byte(pu8Data + i, u32Timeout) != 0)
        {
            /* Timeout */
            return -1;
        }
    }

    /* Check packet number */
    if (pu8Data[PACKET_SEQNUM_INDEX] != (pu8Data[PACKET_SEQNUM_COMP_INDEX] ^ 0xFF))
    {
        /* Packet error */
        return -1;
    }

    /* Packet data length */
    *pi32Len = u32PacketSize;

    return 0;
}




/******************************************************************************
 * @brief      Receive a file using the Y-modem protocol
 *
 * @param[in]  none
 *
 * @return     >0 - Success, the size of the file
 *             -1 - Image size is higher than the allowed space memory
 *             -2 - Validation failed
 *             -3 - Abort by user
 *             Others - Failed to receive the file
 *
 ******************************************************************************/
int32_t YModem_Receive(void)
{
    uint8_t *file_ptr;
    uint8_t au8RespData[2];
    uint32_t i, j;
    uint32_t u32SessionDoneFlag, u32TransEndFlag, u32SessionBeginFlag, u32ErrorCnt;
    uint32_t u32PacketNumOfReceived;
    uint32_t u32FileSize = 0;
    ErrorStatus es;
    uint32_t u32FlashAddr;
    uint32_t u32SrcAddr;
    uint32_t u32NumOfPage = 0;

    int32_t i32PacketSize;


    /* Initialize variables */
    u32FlashAddr = APPLICATION_ADDR;

    for (u32SessionDoneFlag = 0, u32ErrorCnt = 0, u32SessionBeginFlag = 0; ;)
    {
        for (u32PacketNumOfReceived = 0, u32TransEndFlag = 0; ;)
        {
            /* Receive a packet */
            switch (YModem_ReceivePacket(au8PacketData, &i32PacketSize, NAK_TIMEOUT))
            {
                case 0:   /* Normally return */
                    u32ErrorCnt = 0;
                    switch (i32PacketSize)
                    {
                        case -1:    /* Abort by sender     */
                            au8RespData[0] = MODEM_ACK;
                            Send_Bytes(au8RespData, 1);
                            return 0;

                        case 0:     /* End of transmission */
                            au8RespData[0] = MODEM_ACK;
                            Send_Bytes(au8RespData, 1);

                            u32TransEndFlag = 1;
                            break;

                        default:    /* Normal packet */
                            /* Check packet number */
                            if (au8PacketData[PACKET_SEQNUM_INDEX] != u32PacketNumOfReceived)
                            {
                                au8RespData[0] = MODEM_NAK;
                                Send_Bytes(au8RespData, 1);
                                break;
                            }

                            /* Check CRC of received packet data */
                            i = YModem_CalCRC16(au8PacketData + PACKET_HEADER, i32PacketSize);
                            if ((au8PacketData[i32PacketSize + PACKET_HEADER] != ((i >> 8) & 0xFF)) ||
                                    (au8PacketData[i32PacketSize + PACKET_HEADER + 1] != (i & 0xFF)))
                            {
                                au8RespData[0] = MODEM_NAK;
                                Send_Bytes(au8RespData, 1);
                                break;
                            }

                            /* First packet or the last packet */
                            if (u32PacketNumOfReceived == 0)
                            {
                                /* Filename packet has valid data, start frame */
                                if (au8PacketData[PACKET_HEADER] != 0)
                                {
                                    /* File name */
                                    for (i = 0, file_ptr = au8PacketData + PACKET_HEADER; (*file_ptr != 0) && (i < FILE_NAME_LENGTH);)
                                    {
                                        au8FileName[i++] = *file_ptr++;
                                    }
                                    au8FileName[i++] = '\0';

                                    /* File size */
                                    for (i = 0, file_ptr++; (*file_ptr != 0) && (i < FILE_SIZE_LENGTH);)
                                    {
                                        au8FileSize[i++] = *file_ptr++;
                                    }
                                    au8FileSize[i++] = '\0';

                                    Str2Int(au8FileSize, &u32FileSize);

                                    /* Test the size of the image to be sent */
                                    /* Image size is greater than Flash size */
                                    if (u32FileSize > (FLASH_CHIP_SIZE - 1))
                                    {
                                        /* End session */
                                        au8RespData[0] = MODEM_CAN;
                                        au8RespData[1] = MODEM_CAN;

                                        Send_Bytes(au8RespData, 2);
                                        return -1;
                                    }

                                    /* Erase the needed pages where the user application will be loaded */
                                    /* Define the number of page to be erased */
                                    if ((u32FileSize % PAGE_SIZE) != 0)
                                    {
                                        u32NumOfPage = (u32FileSize / PAGE_SIZE) + 1;
                                    }
                                    else
                                    {
                                        u32NumOfPage = (u32FileSize / PAGE_SIZE);
                                    }

                                    /* Erase the FLASH pages */
                                    for (i = 0; i < u32NumOfPage; i++)
                                    {
                                        es = FLASH_EraseSector(u32FlashAddr + (PAGE_SIZE * i));
                                        if (es == ERROR)
                                        {
                                            printf("flash erase fail\n");
                                            return -1;
                                        }
                                    }

                                    au8RespData[0] = MODEM_ACK;
                                    au8RespData[1] = MODEM_C;

                                    Send_Bytes(au8RespData, 2);
                                }
                                else
                                {
                                    /* Filename packet is empty, end session */
                                    au8RespData[0] = MODEM_ACK;
                                    Send_Bytes(au8RespData, 1);

                                    u32TransEndFlag    = 1;
                                    u32SessionDoneFlag = 1;
                                    break;
                                }
                            }
                            /* Data packet */
                            else
                            {
                                /* Source address not 32-bit aligned */
                                u32SrcAddr = (uint32_t)au8PacketData + PACKET_HEADER;

                                /* Program packet data */
                                for (j = 0; (j < i32PacketSize) && (u32FlashAddr < (APPLICATION_ADDR + u32FileSize)); j += 4)
                                {
                                    /* Program the data received into the Flash */
                                    FLASH_ProgramWord(*(__IO uint32_t *)u32SrcAddr, u32FlashAddr);

                                    /* Readback and check */
                                    if (*(__IO uint32_t *)u32FlashAddr != *(__IO uint32_t *)u32SrcAddr)
                                    {
                                        /* End session */
                                        au8RespData[0] = MODEM_CAN;
                                        au8RespData[1] = MODEM_CAN;

                                        Send_Bytes(au8RespData, 2);

                                        return -2;
                                    }

                                    u32FlashAddr += 4;
                                    u32SrcAddr   += 4;
                                }

                                au8RespData[0] = MODEM_ACK;

                                Send_Bytes(au8RespData, 1);
                            }

                            u32PacketNumOfReceived++;

                            u32SessionBeginFlag = 1;

                            break;
                    }
                    break;

                case 1:   /* Abort by user */
                    au8RespData[0] = MODEM_CAN;
                    au8RespData[1] = MODEM_CAN;

                    Send_Bytes(au8RespData, 2);
                    return -3;

                default:  /* Timout or packet error  */
                    if (u32SessionBeginFlag > 0)
                    {
                        u32ErrorCnt++;
                    }

                    if (u32ErrorCnt > MAX_ERRORS)
                    {
                        au8RespData[0] = MODEM_CAN;
                        au8RespData[1] = MODEM_CAN;

                        Send_Bytes(au8RespData, 2);
                        return 0;
                    }

                    au8RespData[0] = MODEM_C;

                    Send_Bytes(au8RespData, 1);
                    break;
            }

            /* End Transmission  */
            if (u32TransEndFlag != 0)
            {
                break;
            }
        }

        /* End File download session */
        if (u32SessionDoneFlag != 0)
        {
            break;
        }
    }

    return (int32_t)u32FileSize;
}




/******************************************************************************
 * @brief      Prepare the first block
 *
 * @param[in]  pu8Packet   :  Packet data
 * @param[in]  pu8FileName :  File name string
 * @param[in]  pu32FileSize:  File data size
 *
 * @return     none
 *
 ******************************************************************************/
static void YModem_PrepareInitPacket(uint8_t *pu8Packet, const uint8_t *pu8FileName, uint32_t *pu32FileSize)
{
    uint16_t i, j;
    uint8_t  au8FileSize[10];

    /* Make first three packet */
    pu8Packet[0] = MODEM_SOH;
    pu8Packet[1] = 0x00;
    pu8Packet[2] = 0xFF;

    /* File name packet has valid data */
    for (i = 0; (pu8FileName[i] != '\0') && (i < FILE_NAME_LENGTH); i++)
    {
        pu8Packet[i + PACKET_HEADER] = pu8FileName[i];
    }

    pu8Packet[i + PACKET_HEADER] = 0x00;

    /* File size */
    Int2Str(au8FileSize, *pu32FileSize);

    for (j = 0, i = i + PACKET_HEADER + 1; au8FileSize[j] != '\0';)
    {
        pu8Packet[i++] = au8FileSize[j++];
    }

    /* Pad data */
    for (j = i; j < PACKET_SIZE + PACKET_HEADER; j++)
    {
        pu8Packet[j] = 0x00;
    }
}




/******************************************************************************
 * @brief      Prepare the data block
 *
 * @param[in]  pu8FileData :  File data to be sent
 * @param[in]  pu8Packet   :  Packet data
 * @param[in]  u8PacketNum :  Packet sequence number
 * @param[in]  u32BlockSize:  Data size
 *
 * @return     Packet size
 *
 ******************************************************************************/
static uint32_t YModem_PreparePacket(uint8_t *pu8FileData, uint8_t *pu8Packet, uint8_t u8PacketNum, uint32_t u32BlockSize)
{
    uint32_t i;
    uint32_t u32Size;
    uint32_t u32PacketSize;

    uint8_t *pu8FilePtr;


    /* Make first three packet */
    u32PacketSize = (u32BlockSize >= PACKET_1K_SIZE) ? PACKET_1K_SIZE : PACKET_SIZE;
    u32Size       = (u32BlockSize < u32PacketSize) ? u32BlockSize : u32PacketSize;

    if (u32PacketSize == PACKET_1K_SIZE)
    {
        pu8Packet[0] = MODEM_STX;
    }
    else
    {
        pu8Packet[0] = MODEM_SOH;
    }

    pu8Packet[1] = u8PacketNum;
    pu8Packet[2] = (~u8PacketNum);


    /* File data */
    pu8FilePtr = pu8FileData;
    for (i = PACKET_HEADER; i < u32Size + PACKET_HEADER; i++)
    {
        pu8Packet[i] = *pu8FilePtr++;
    }

    /* Pad data */
    if (u32Size <= u32PacketSize)
    {
        for (i = u32Size + PACKET_HEADER; i < u32PacketSize + PACKET_HEADER; i++)
        {
            pu8Packet[i] = 0x1A;    /* EOF (0x1A) or 0x00 */
        }
    }

    return u32PacketSize;
}




/******************************************************************************
 * @brief      Transmit a data packet using the YModem protocol
 *
 * @param[in]  pu8Packet:  Packet data
 * @param[in]  u32Size  :  Data size
 *
 * @return     none
 *
 ******************************************************************************/
void YModem_SendPacket(uint8_t *pu8Packet, uint32_t u32Size)
{
    Send_Bytes(pu8Packet, u32Size);
}




/******************************************************************************
 * @brief      Transmit a file using the YModem protocol
 *
 * @param[in]  pu8File    :  File data in the Flash
 * @param[in]  pu8FileName:  File name
 * @param[in]  u32FileSize:  File size
 *
 * @return     0      - Success
 *             Others - Error
 *
 ******************************************************************************/
int32_t YModem_Transmit(uint8_t *pu8File, const uint8_t *pu8FileName, uint32_t u32FileSize)
{
    uint8_t *pu8TempFile;

    uint8_t i;
    uint8_t au8RespData[2];
    uint8_t au8ReceivedC[2];
    uint8_t u8AckReceived;

    uint32_t u32ErrorCnt;
    uint32_t u32Size;
    uint32_t u32PacketSize;
    uint16_t u16PacketNum;
    uint16_t u16TempCRC;


    /* Init variables */
    u32ErrorCnt   = 0;
    u8AckReceived = 0;

    for (i = 0; i < (FILE_NAME_LENGTH - 1); i++)
    {
        au8FileName[i] = pu8FileName[i];

        /* File name string end flag */
        if (pu8FileName[i] == '\0')
        {
            break;
        }
    }


    /* Prepare first block */
    YModem_PrepareInitPacket(au8PacketData, au8FileName, &u32FileSize);

    do
    {
        /* Send Packet */
        YModem_SendPacket(au8PacketData, PACKET_SIZE + PACKET_HEADER);

        /* Send CRC */
        u16TempCRC = YModem_CalCRC16(au8PacketData + PACKET_HEADER, PACKET_SIZE);

        au8RespData[0] = (uint8_t)(u16TempCRC >> 8);
        au8RespData[1] = (uint8_t)(u16TempCRC & 0xFF);
        Send_Bytes(au8RespData, 2);

        /* Wait for Ack */
        if (Receive_Byte(&au8ReceivedC[0], NAK_TIMEOUT) == 0)
        {
            if (au8ReceivedC[0] == MODEM_ACK)
            {
                /* Packet transfered correctly */
                u8AckReceived = 1;
            }
        }
        else
        {
            u32ErrorCnt++;
        }
    }
    while (!u8AckReceived && (u32ErrorCnt < MAX_ERRORS));

    if (u32ErrorCnt >= MAX_ERRORS)
    {
        return u32ErrorCnt;
    }

    /* Wait for 'C' */
    do
    {
        if (Receive_Byte(&au8ReceivedC[0], NAK_TIMEOUT) == 0)
        {
            if (au8ReceivedC[0] != MODEM_C)
            {
                return -1;
            }
            else
            {
                break;
            }
        }
        else
        {
            u32ErrorCnt++;
        }
    }
    while (u32ErrorCnt < MAX_ERRORS);

    if (u32ErrorCnt >= MAX_ERRORS)
    {
        return u32ErrorCnt;
    }



    /* Data packet */
    pu8TempFile  = pu8File;
    u32Size      = u32FileSize;
    u16PacketNum = 0x01;

    while (u32Size)
    {
        /* Prepare packet */
        u32PacketSize = YModem_PreparePacket(pu8TempFile, au8PacketData, u16PacketNum, u32Size);

        u8AckReceived   = 0;
        au8ReceivedC[0] = 0;
        u32ErrorCnt     = 0;

        do
        {
            /* Send packet */
            YModem_SendPacket(au8PacketData, u32PacketSize + PACKET_HEADER);

            /* Send CRC */
            u16TempCRC = YModem_CalCRC16(au8PacketData + PACKET_HEADER, u32PacketSize);

            au8RespData[0] = (uint8_t)(u16TempCRC >> 8);
            au8RespData[1] = (uint8_t)(u16TempCRC & 0xFF);
            Send_Bytes(au8RespData, 2);

            /* Wait for Ack */
            if ((Receive_Byte(&au8ReceivedC[0], NAK_TIMEOUT) == 0)  && (au8ReceivedC[0] == MODEM_ACK))
            {
                u8AckReceived = 1;

                /* Update file data address and size for next packet */
                if (u32Size > u32PacketSize)
                {
                    pu8TempFile += u32PacketSize;
                    u32Size -= u32PacketSize;

                    if (u16PacketNum == (FLASH_IMAGE_SIZE / PACKET_1K_SIZE))
                    {
                        return 0xFF; /*  error */
                    }
                    else
                    {
                        u16PacketNum++;
                    }
                }
                else
                {
                    pu8TempFile += u32PacketSize;
                    u32Size = 0;
                }
            }
            else
            {
                u32ErrorCnt++;
            }
        }
        while (!u8AckReceived && (u32ErrorCnt < MAX_ERRORS));
        /* Resend packet if NAK  for a count of MAX_ERRORS else end of commuincation */

        if (u32ErrorCnt >=  MAX_ERRORS)
        {
            return u32ErrorCnt;
        }
    }



    /* Send EOT */
    u8AckReceived   = 0;
    au8ReceivedC[0] = 0x00;
    u32ErrorCnt     = 0;

    do
    {
        au8RespData[0] = MODEM_EOT;
        Send_Bytes(au8RespData, 1);

        /* Wait for Ack */
        if ((Receive_Byte(&au8ReceivedC[0], NAK_TIMEOUT) == 0) && (au8ReceivedC[0] == MODEM_ACK))
        {
            u8AckReceived = 1;
        }
        else
        {
            u32ErrorCnt++;
        }
    }
    while (!u8AckReceived && (u32ErrorCnt < MAX_ERRORS));

    if (u32ErrorCnt >= MAX_ERRORS)
    {
        return u32ErrorCnt;
    }

    /* Wait for 'C' */
    u32ErrorCnt = 0;
    do
    {
        if (Receive_Byte(&au8ReceivedC[0], NAK_TIMEOUT) == 0)
        {
            if (au8ReceivedC[0] != MODEM_C)
            {
                return -1;
            }
            else
            {
                break;
            }
        }
        else
        {
            u32ErrorCnt++;
        }
    }
    while (u32ErrorCnt < MAX_ERRORS);

    if (u32ErrorCnt >= MAX_ERRORS)
    {
        return u32ErrorCnt;
    }



    /* Last packet preparation */
    u8AckReceived   = 0;
    au8ReceivedC[0] = 0x00;
    u32ErrorCnt     = 0;

    au8PacketData[0] = MODEM_SOH;
    au8PacketData[1] = 0;
    au8PacketData[2] = 0xFF;

    for (i = PACKET_HEADER; i < (PACKET_SIZE + PACKET_HEADER); i++)
    {
        au8PacketData[i] = 0x00;
    }

    do
    {
        /* Send Packet */
        YModem_SendPacket(au8PacketData, PACKET_SIZE + PACKET_HEADER);

        /* Send CRC */
        u16TempCRC = YModem_CalCRC16(au8PacketData + PACKET_HEADER, PACKET_SIZE);

        au8RespData[0] = (uint8_t)(u16TempCRC >> 8);
        au8RespData[1] = (uint8_t)(u16TempCRC & 0xFF);
        Send_Bytes(au8RespData, 2);

        /* Wait for Ack */
        if (Receive_Byte(&au8ReceivedC[0], NAK_TIMEOUT) == 0)
        {
            if (au8ReceivedC[0] == MODEM_ACK)
            {
                /* Packet transferred correctly */
                u8AckReceived = 1;
            }
        }
        else
        {
            u32ErrorCnt++;
        }
    }
    while (!u8AckReceived && (u32ErrorCnt < MAX_ERRORS));

    /* Re-send packet if NAK  for a count of MAX_ERRORS  else end of communication */
    if (u32ErrorCnt >= MAX_ERRORS)
    {
        return u32ErrorCnt;
    }

    return 0;   /* File transmitted successfully */
}


/******************* Copyright (C) 2022 Spintrol Electronic Technology (Shanghai) Co., Ltd. ***** END OF FILE ****/
