⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xymodem.c

📁 vt6528芯片交换机API函数和文档运行程序
💻 C
字号:
/*
 * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc.
 * All rights reserved.
 *
 * This software is copyrighted by and is the sole property of
 * VIA Networking Technologies, Inc. This software may only be used
 * in accordance with the corresponding license agreement. Any unauthorized
 * use, duplication, transmission, distribution, or disclosure of this
 * software is expressly forbidden.
 *
 * This software is provided by VIA Networking Technologies, Inc. "as is"
 * and any express or implied warranties, including, but not limited to, the
 * implied warranties of merchantability and fitness for a particular purpose
 * are disclaimed. In no event shall VIA Networking Technologies, Inc.
 * be liable for any direct, indirect, incidental, special, exemplary, or
 * consequential damages.
 *
 *
 * File:    xymodem.c
 *
 * Purpose: XY-Modem protocol
 *
 * Author:  Tevin Chen
 *
 * Date:    Jan 08, 2002
 *
 * Functions:
 *
 * Revision History:
 *
 */


#if !defined(__KERNEL_H__)
#include "kernel.h"
#endif
#if !defined(__ASCII_H__)
#include "ascii.h"
#endif
#if !defined(__STR_H__)
#include "str.h"
#endif
#if !defined(__CRC_H__)
#include "crc.h"
#endif
#if !defined(__DEVICE_H__)
#include "device.h"
#endif
#if !defined(__UART_H__)
#include "uart.h"
#endif




/*---------------------  Static Definitions  ------------------------*/
#define MAX_RETRY               10

/*---------------------  Static Types  ------------------------------*/

/*---------------------  Static Macros  -----------------------------*/

/*---------------------  Static Classes  ----------------------------*/

/*---------------------  Static Variables  --------------------------*/
UINT8 g_au8ModemBuf[1032];              // 1024 for XModem 1k + 3 head chars
                                        // + 2 crc + 1 nul + 2 padding(dword alignment)

/*---------------------  Static Functions  --------------------------*/
static void s_vFlushInput(void);
static BOOL s_bCheck(BOOL bCrc, const PUINT8 pu8PktBuf, INT16 i16PktLen);
static INT32 s_i32Transmit(PUINT8 pu8TxBuf, UINT32 u32TxBufLen, BOOL bCrc);

/*---------------------  Export Variables  --------------------------*/




static void s_vFlushInput(void)
{
    while (UART_i16GetCharRawTimed(TMR_TICKS_PER_SEC * 3 / 2) >= 0)
        ;
}


static BOOL s_bCheck(BOOL bCrc, const PUINT8 pu8PktBuf, INT16 i16PktLen)
{
    if (bCrc) {
        UINT16  u16Crc = CRC_u16Crc16(pu8PktBuf, i16PktLen);
        UINT16  tcrc = (pu8PktBuf[i16PktLen]<<8) + pu8PktBuf[i16PktLen+1];
        if (u16Crc == tcrc)
            return TRUE;
    }
    else {
        INT16   ii;
        UINT8   cks = 0;
        for (ii = 0; ii < i16PktLen; ii++) {
            cks += pu8PktBuf[ii];
        }
        if (cks == pu8PktBuf[i16PktLen])
            return TRUE;
    }

    return FALSE;
}


INT32 XYMDM_i32Receive(PUINT8 pu8RxBuf, UINT32 u32RxBufLen)
{
    INT16   i16Char;
    UINT16  u16Retry;
    INT16   ii;
    UINT8   u8PacketNo = 1;
    INT16   i16PerPktLen = 128;
    UINT32  u32AlreadyRecv = 0;
    UINT8   u8TryChar = 'C';            // try CRC first
    BOOL    bCrc = FALSE;
    PUINT8  pu8XmodemBuf;
    INT16   i16Retrans = MAX_RETRY;
    BOOL    bInYmodemMode = FALSE;
    UINT8   u8YmodemEot = 0;
    UINT32  u32YmodemLenParam = 0;


    for (;;) {
        // wait for 32 sec to make connection
        for (u16Retry = 0; u16Retry < 16; ++u16Retry) {
            // tell sender to send
            if (u8TryChar != 0)
                UART_vPutCharRaw(u8TryChar);
            // get response from sender
            if ((i16Char = UART_i16GetCharRawTimed(TMR_TICKS_PER_SEC * 2)) >= 0) {
                switch (i16Char) {
                case MC_SOH:
                    i16PerPktLen = 128;
                    goto start_recv;

                case MC_STX:
                    i16PerPktLen = 1024;
                    goto start_recv;

                case MC_EOT:
                    // OK: normal end
                    if (bInYmodemMode)
                        goto ymodem_end;
                    else {
                        s_vFlushInput();
                        UART_vPutCharRaw(MC_ACK);
                        return u32AlreadyRecv;
                    }

                case MC_CAN:
                    // ERR: canceled by remote
                    if ((i16Char = UART_i16GetCharRawTimed(TMR_TICKS_PER_SEC)) == MC_CAN) {
                        s_vFlushInput();
                        UART_vPutCharRaw(MC_ACK);
                        return -1;
                    }
                    break;

                default:
                    // other char, ignore
                    break;
                }
            }
        }

        // if no response for CRC, try NAK
        if (u8TryChar == 'C') {
            u8TryChar = MC_NAK;
            continue;
        }
        // ERR: not sync, abort rx, flush input, send CAN
        s_vFlushInput();
        UART_vPutCharRaw(MC_CAN);
        UART_vPutCharRaw(MC_CAN);
        UART_vPutCharRaw(MC_CAN);
        return -2;

ymodem_end:
        if (u8YmodemEot == 0) {
            // the first eot, send NAK
            s_vFlushInput();
            UART_vPutCharRaw(MC_NAK);
            u8YmodemEot++;
            continue;
        }
        else {
            // the second eot, send ACK
            s_vFlushInput();
            UART_vPutCharRaw(MC_ACK);
            u8TryChar = 'C';
            continue;
        }

start_recv:
        if (u8TryChar == 'C')
            bCrc = TRUE;
        // clear try char for next packet
        u8TryChar = 0;

        pu8XmodemBuf = g_au8ModemBuf;
        *pu8XmodemBuf++ = (UINT8)i16Char;

        // recv a packet
        for (ii = 0;  ii < (i16PerPktLen + 3 + (bCrc ? 1 : 0)); ii++) {
            if ((i16Char = UART_i16GetCharRawTimed(TMR_TICKS_PER_SEC)) < 0) {
                s_vFlushInput();
                UART_vPutCharRaw(MC_NAK);
                continue;
            }
            *pu8XmodemBuf++ = (UINT8)i16Char;
        }

        if (g_au8ModemBuf[1] == 0) {
            // check if ymodem protocol
            UINT8 u8Pos = STR_iStrlen((char *)&g_au8ModemBuf[3]) + 4;

            if (!bInYmodemMode) {
                // start of ymodem
                bInYmodemMode = TRUE;
                u32YmodemLenParam = STR_u32StrDecToU32((char *)&g_au8ModemBuf[u8Pos]);
                UART_vPutCharRaw(MC_ACK);
                u8TryChar = 'C';
                continue;
            }
            else {
                BOOL   bEnd = TRUE;
                UINT16 uu;

                for (uu = 0; uu < i16PerPktLen; uu++) {
                    if (g_au8ModemBuf[3+uu] != 0)
                        bEnd = FALSE;
                }

                if (bEnd) {
                    // end of ymodem
                    UART_vPutCharRaw(MC_ACK);
                    return u32YmodemLenParam;
                }
            }
        }

        // good packet, send ACK
        if ((g_au8ModemBuf[1] == (UINT8)(~g_au8ModemBuf[2]))
                    && ((g_au8ModemBuf[1] == u8PacketNo) || (g_au8ModemBuf[1] == (UINT8)(u8PacketNo - 1)))
                    && s_bCheck(bCrc, &g_au8ModemBuf[3], i16PerPktLen) ) {

            // normal good packet
            if (g_au8ModemBuf[1] == u8PacketNo) {
                register int count = u32RxBufLen - u32AlreadyRecv;
                if (count > i16PerPktLen)
                    count = i16PerPktLen;
                if (count > 0) {
                    STR_pvMemcpy(&pu8RxBuf[u32AlreadyRecv], &g_au8ModemBuf[3], count);
                    u32AlreadyRecv += count;
                }
                ++u8PacketNo;
                i16Retrans = MAX_RETRY;
            }
            // this is a retry good packet, it's ok to receive a repeated packet, just drop it
            else {
                --i16Retrans;
                if (i16Retrans <= 0) {
                    // ERR: too many retry error, abort rx, flush input, send CAN
                    s_vFlushInput();
                    UART_vPutCharRaw(MC_CAN);
                    UART_vPutCharRaw(MC_CAN);
                    UART_vPutCharRaw(MC_CAN);
                    return -3;
                }
            }

            UART_vPutCharRaw(MC_ACK);
        }
        // bad packet, send NAK
        else {
            s_vFlushInput();
            UART_vPutCharRaw(MC_NAK);
        }
    }
}


/*
 *      Each packet looks like this:
 *      +-----+-------+-------+------+-----+
 *      | SOH | Seq1. | Seq2. | data | SUM |
 *      +-----+-------+-------+------+-----+
 *      SOH  = 1 byte, 0x01(SOH) / 0x02(STX)
 *      Seq1 = 1 byte, The sequence number.
 *      Seq2 = 1 byte, The complement of the sequence number.
 *      Data = A 128/1024 bytes of data.
 *      SUM  = 2 bytes, CRC: ccitt 16-bit CRC
 *             1 byte, CheckSum: Add the contents of the 128 bytes and use the low-order
 *             8 bits of the result.
 *
 */
static INT32 s_i32Transmit(PUINT8 pu8TxBuf, UINT32 u32TxBufLen, BOOL bCrc)
{
    INT16   i16Char;
    UINT16  u16Retry;
    INT16   ii;
    UINT8   u8PacketNo = 1;
    INT16   i16PerPktLen;
    UINT32  u32AlreadySend = 0;
    INT32   i32WantToSend;



    for (;;) {

        i32WantToSend = u32TxBufLen - u32AlreadySend;
        if (i32WantToSend <= 128) {
            i16PerPktLen = 128;
            g_au8ModemBuf[0] = MC_SOH;
        }
        else {
            i16PerPktLen = 1024;
            g_au8ModemBuf[0] = MC_STX;
        }

        g_au8ModemBuf[1] = u8PacketNo;
        g_au8ModemBuf[2] = ~u8PacketNo;

        // adjust i32WantToSend not big than i16PerPktLen
        if (i32WantToSend > i16PerPktLen)
            i32WantToSend = i16PerPktLen;

        // send a packet
        if (i32WantToSend >= 0) {
            // clear buffer, for security
            STR_pvMemset(&g_au8ModemBuf[3], 0, i16PerPktLen);
            // append EOF
            if (i32WantToSend == 0) {
                // nothing left to send, put EOF
                g_au8ModemBuf[3] = MC_EOF;
            }
            else {
                STR_pvMemcpy(&g_au8ModemBuf[3], &pu8TxBuf[u32AlreadySend], i32WantToSend);
                // append EOF at the tail
                if (i32WantToSend < i16PerPktLen)
                    g_au8ModemBuf[3+i32WantToSend] = MC_EOF;
            }
            // calculate CRC or CheckSum
            if (bCrc) {
                UINT16 u16Crc = CRC_u16Crc16(&g_au8ModemBuf[3], i16PerPktLen);
                g_au8ModemBuf[i16PerPktLen+3] = (u16Crc>>8) & 0xFF;
                g_au8ModemBuf[i16PerPktLen+4] = u16Crc & 0xFF;
            }
            else {
                UINT8 u8CkSum = 0;
                for (ii = 3; ii < i16PerPktLen+3; ii++)
                    u8CkSum += g_au8ModemBuf[ii];
                g_au8ModemBuf[i16PerPktLen+3] = u8CkSum;
            }

            for (u16Retry = 0; u16Retry < MAX_RETRY; ++u16Retry) {
                // xmit a packet
                for (ii = 0; ii < (i16PerPktLen+4+(bCrc?1:0)); ii++) {
                    UART_vPutCharRaw(g_au8ModemBuf[ii]);
                }

                if ((i16Char = UART_i16GetCharRawTimed(TMR_TICKS_PER_SEC)) >= 0 ) {
                    if (i16Char == MC_ACK) {
                        // OK: send next packet
                        ++u8PacketNo;
                        u32AlreadySend += i16PerPktLen;
                        break;
                    }
                    else if (i16Char == MC_CAN) {
                        // ERR: canceled by remote
                        if ((i16Char = UART_i16GetCharRawTimed(TMR_TICKS_PER_SEC)) == MC_CAN) {
                            UART_vPutCharRaw(MC_ACK);
                            s_vFlushInput();
                            return -1;
                        }
                    }
                    else {
                        // if NAK or other char, then retry
                    }
                }
            }
            if (u16Retry == MAX_RETRY) {
                // ERR: too many xmit error, abort tx, send CAN, flush input
                UART_vPutCharRaw(MC_CAN);
                UART_vPutCharRaw(MC_CAN);
                UART_vPutCharRaw(MC_CAN);
                s_vFlushInput();
                return -4;
            }
        }
        // send completed
        else {
            // OK: wait 20 sec for last ACK to end
            for (u16Retry = 0; u16Retry < 10; ++u16Retry) {
                UART_vPutCharRaw(MC_EOT);
                if ((i16Char = UART_i16GetCharRawTimed(TMR_TICKS_PER_SEC * 2)) == MC_ACK)
                    break;
            }
            if (u16Retry == 10) {
                // ERR: end of xmit, but no ACK
                s_vFlushInput();
                return -5;
            }

            return u32AlreadySend;
        }
    }
}


INT32 XYMDM_i32Transmit(PUINT8 pu8TxBuf, UINT32 u32TxBufLen)
{
    INT16   i16Char;
    UINT16  u16Retry;


    // wait for 32 sec to make connection
    for (u16Retry = 0; u16Retry < 16; ++u16Retry) {
        if ((i16Char = UART_i16GetCharRawTimed(TMR_TICKS_PER_SEC * 2)) >= 0) {
            switch (i16Char) {
            case 'C':
                return s_i32Transmit(pu8TxBuf, u32TxBufLen, TRUE);

            case MC_NAK:
                return s_i32Transmit(pu8TxBuf, u32TxBufLen, FALSE);

            case MC_CAN:
                // ERR: canceled by remote
                if ((i16Char = UART_i16GetCharRawTimed(TMR_TICKS_PER_SEC)) == MC_CAN) {
                    UART_vPutCharRaw(MC_ACK);
                    s_vFlushInput();
                    return -1;
                }
                break;

            default:
                // other char, ignore
                break;
            }
        }
    }

    // ERR: not sync, abort tx, send CAN, flush input
    UART_vPutCharRaw(MC_CAN);
    UART_vPutCharRaw(MC_CAN);
    UART_vPutCharRaw(MC_CAN);
    s_vFlushInput();
    return -2;
}


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -