xmodem源码
单片机源程序如下:
- /**************************************************************************
- *
- * Written by Cencong Su (cencong.su@gmail.com)
- *
- ***************************************************************************
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above author notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above author notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- **********************************************************************//*!
- *
- * @file xmodem.c
- *
- * @author Cencong Su
- *
- * @brief Implement xmodem protocol
- *
- * @details This module needs the following libray functions:
- * 1> memcpy
- * 2> memset
- * 3> malloc and free
- * Target dependent code is marked with special comment "Target Dependent :"
- *
- *
- ***************************************************************************/
- #include <common.h>
- #include <stdlib.h>
- #include "xmodem.h"
- #include "crc16.h"
- /** Target dependent : header files */
- #include "fnet_serial.h"
- /*-----------------------------------------------------------------------------------*/
- /* -----------------------------Target Dependent : code ---------------------------*/
- /**
- * Initiate the xmodem module, serial port etc.
- * Leave empty here
- *
- * @param NONE
- * @return NONE
- */
- void xmodem_init()
- {
- }
- /**
- * Get one byte from xmodem serial port
- *
- * @param[in] timeout timeout value for getting one byte from
- * serial port unit:ms
- *
- * @retval >0 data from xmodem serial port, other receive wrong
- */
- int getbyte_timeout(uint16_t timeout)
- {
- int c = 0, len;
- uint32_t time_cnt = fnet_timer_ms();
- while ((fnet_timer_ms() - time_cnt) < timeout)
- {
- c = fnet_getchar();
- if (c >= 0)
- {
- return c;
- }
- }
- return -1;
- }
- /**
- * Send one byte to xmodem serial port
- *
- * @param[in] ch data sent out
- *
- * @return None
- */
- void sendbyte(int ch)
- {
- fnet_putchar(ch);
- }
- /**
- * flush serial port buffer
- *
- * @param NONE
- * @return NONE
- */
- void flush_input()
- {
- while(getbyte_timeout(DLY_1S/3) >= 0);
- }
- /**
- * Send out a group of data
- * Implement this function here is because some platform will provide
- * similar function to send continuous serial data
- *
- * @param data data address
- * @param len data length
- *
- * @return NONE
- */
- void xmodem_send_data(uint8_t * data, uint16_t len)
- {
- uint16_t i;
- for (i = 0; i < len; i++)
- {
- sendbyte(data[i]);
- }
- }
- /* -------------------Target dependent code END --------------------*/
- /*-----------------------------------------------------------------------------------*/
- /**
- * Cancel xmodem transmission
- *
- * @param NONE
- * @return NONE
- */
- void xmodem_cancel()
- {
- sendbyte(CAN);
- sendbyte(CAN);
- sendbyte(CAN);
- }
- /**
- * Receive one xmodem packet with timeout
- *
- * @param[out] dest address of memory to place received data
- * @param[in] timeout keep trying to get data until timeout
- * @param[in] crc_flag mechanism to check data integrity, 1:CRC, 0:Check sum
- *
- * @return Received data length
- */
- uint16_t xmodem_recv_pkt(uint8_t *dest, uint32_t timeout, uint8_t crc_flag)
- {
- int ch;
- uint16_t cnt = 0;
- ch = getbyte_timeout(timeout);
-
- if(ch >= 0)
- {
- dest[cnt++] = ch;
-
-
- while(cnt < ((crc_flag) ? sizeof(XMODEM_PACKET) : (sizeof(XMODEM_PACKET) - 1)))
- {
- //Try to receive one byte
- ch = getbyte_timeout(DLY_1S);
-
- if (ch >= 0)
- {
- dest[cnt++] = ch;
- }
- else
- {
- /*If the no data receive then keep trying to get data until timeout,
- If data already arrives, then received char<0 means end of packet,
- return received number*/
- return cnt;
- }
- }
-
- return cnt;
- }
- else
- {
- return 0;
- }
- }
- /**
- * Check xmodem packet integrity
- *
- * @param[in] crc_flag Check mechanism, 1:CRC, 0:Check sum
- * @param[in] pkt xmodem packet
- *
- * @return TRUE: data is OK, FALSE: data wrong
- */
- bool xmodem_check(uint8_t crc_flag, XMODEM_PACKET_PTR pkt)
- {
- uint16 i, crc;
- uint8_t cks = 0;
- if (crc_flag)
- {
- crc = crc16_ccitt(pkt->data, PACKET_LEN);
- hsb2lsb(crc);
- if (crc == pkt->chk_code.crc)
- {
- return TRUE;
- }
- }
- else
- {
- for (i = 0; i < PACKET_LEN; ++i)
- {
- cks += pkt->data[i];
- }
- if (cks == pkt->chk_code.chksum)
- {
- return TRUE;
- }
- }
- return FALSE;
- }
- /**
- * Parse one xmodem packet
- *
- * @param[in] data xmodem packet address
- * @param[in] len packet length
- * @param[in] crc_flag Data check mechanism, 1: CRC, 0: Check sum
- *
- * @ret PARS_OK Data is ok
- * @ret PARS_NAK Need to response with "NAK"
- * @ret PARS_EOT Receive "EOT"
- * @ret PARS_CAN Receive "CAN"
- *
- * @see xmodem_parse_pkt_ret
- */
- xmodem_parse_pkt_ret xmodem_parse_pkt(uint8_t * data, uint32_t len,
- uint8_t crc_flag, uint8_t recv_pkt_no)
- {
- XMODEM_PACKET_PTR pkt = (XMODEM_PACKET_PTR) data;
- switch (data[0])
- {
- case SOH:
- if ((pkt->packet_num == recv_pkt_no)
- && (pkt->pkt_num_cmplemt == (uint8_t) ~recv_pkt_no)
- && (len == ((crc_flag) ?sizeof(XMODEM_PACKET) : (sizeof(XMODEM_PACKET) - 1)))
- && (xmodem_check(crc_flag, pkt) == 1))
- {
- return PARS_OK;
- }
- else
- {
- return PARS_ERR;
- }
- break;
- case EOT:
- return PARS_EOT;
- case CAN:
- return PARS_CAN;
- default:
- return PARS_ERR;
- }
- }
- /**
- * xmodem receive entry
- *
- * @param[in] dest destination address to store received data
- * @param[in] destsz destination area size
- *
- * @return actual data size copied to destination
- */
- uint32_t xmodem_recv(uint8_t *dest, uint32_t destsz)
- {
- XMODEM_PACKET_PTR xdm_pkt;
- uint8_t crc_flag = 1, i, recv_pkt_no = 1;
- uint32_t recv_len, dest_index = 0, destsz_left = 0;
- xmodem_parse_pkt_ret xdmParsRet;
- flush_input();
- xdm_pkt = (XMODEM_PACKET_PTR) malloc(sizeof(XMODEM_PACKET));
- if (xdm_pkt == NULL)
- {
- printf("Can't allocate memory for new xmodem packet in %s!\n",
- __FUNCTION__);
- goto RETURN;
- }
- //Send out first byte and try to receive the acknowledge packet
- for (i = 0; i < MAX_RETRANS; i++)
- {
- //Try to communicate with remote: send 'C' -> NAK -> 'C' -> NAK...
- sendbyte((crc_flag) ? USE_CRC : NAK);
- recv_len = xmodem_recv_pkt((uint8_t *) xdm_pkt, (2 * DLY_1S), crc_flag);
- if (recv_len > 0)
- {
- //Tera term first xmodem packet will contain wrong data
- //flush serial port buffer to be compatible with teara term
- flush_input();
- break;
- }
- else
- {
- if( i == (MAX_RETRANS/2))
- {
- crc_flag = !crc_flag;
- }
- //Already try the maximum times to communicate with remote, cancel link
- if (i == (MAX_RETRANS - 1))
- {
- xmodem_cancel();
- goto RETURN;
- }
- }
- }
-
- while (1)
- {
- xdmParsRet = xmodem_parse_pkt((uint8_t *) xdm_pkt, recv_len, crc_flag,
- recv_pkt_no);
- switch (xdmParsRet)
- {
- case PARS_OK:
- recv_pkt_no++;
- destsz_left = destsz - dest_index;
- if (destsz_left < PACKET_LEN)
- {
- memcpy(dest + dest_index, xdm_pkt->data, destsz_left);
- dest_index += destsz_left;
- xmodem_cancel();
- goto RETURN;
- }
- else
- {
- memcpy(dest + dest_index, xdm_pkt->data, PACKET_LEN);
- dest_index += PACKET_LEN;
- sendbyte(ACK);
- }
- break;
- case PARS_CAN:
- sendbyte(ACK);
- goto RETURN;
- case PARS_EOT:
- sendbyte(ACK);
- goto RETURN;
- case PARS_ERR:
- default:
- flush_input();
- sendbyte(NAK);
- break;
- }
- recv_len = xmodem_recv_pkt((uint8_t *) xdm_pkt, (10 * DLY_1S),
- crc_flag);
-
- if (recv_len <= 0)
- {
- xmodem_cancel();
- goto RETURN;
- }
- }
- RETURN:
- free(xdm_pkt);
- return dest_index;
- }
- /**
- * Start xmodem transmit
- *
- * @param[in] crc_flag check data integrity method: 1 - crc, 0 - checksum
- * @param[in] data_src address of data be sent
- * @param[in] data_sz size of data be sent
- *
- * @ret >0 actual sent data length
- * @ret -1 remote cancel
- * @ret -2 communication timeout
- *
- * @see REMOTE_CANCEL,COM_TIMEOUT
- */
- int xmodem_start_trans(uint8_t crc_flag, uint8_t *dat_src, int data_sz)
- {
- XMODEM_PACKET xmodem_pkt;
- uint8_t packetno = 1, i;
- int sent_len = 0, left_num;
- int ch;
- START_TRANS:
- memset(&xmodem_pkt, 0, sizeof(xmodem_pkt));
- left_num = data_sz - sent_len;
- xmodem_pkt.soh = SOH;
- xmodem_pkt.packet_num = packetno;
- xmodem_pkt.pkt_num_cmplemt = ~packetno;
- //Still have left bytes to send
- if (left_num > 0)
- {
- if (left_num >= PACKET_LEN)
- {
- memcpy(xmodem_pkt.data, &dat_src[sent_len], PACKET_LEN);
- }
- else if (left_num < PACKET_LEN)
- {
- //The remain data can't fill one packet, so fill it with "CTRL-Z(0x1a)"
- memcpy(xmodem_pkt.data, &dat_src[sent_len], left_num);
- memset(xmodem_pkt.data + left_num, CTRLZ, PACKET_LEN - left_num);
- }
- //Calculate check code, checksum/CRC
- if (crc_flag)
- {
- xmodem_pkt.chk_code.crc = crc16_ccitt(xmodem_pkt.data, PACKET_LEN);
- //Exchange the lsb and hsb byte, hsb output first
- hsb2lsb(xmodem_pkt.chk_code.crc);
- }
- else
- {
- for (i = 0; i < PACKET_LEN; i++)
- {
- xmodem_pkt.chk_code.chksum += xmodem_pkt.data[i];
- }
- }
- //Transmit the packet
- for (i = 0; i < MAX_RETRANS; i++)
- {
- xmodem_send_data((uint8_t *) &xmodem_pkt,
- sizeof(xmodem_pkt) - (crc_flag ? 0 : 1));
- //Read response byte from remote
- if ((ch = getbyte_timeout(DLY_1S * 10)) >= 0)
- {
- switch (ch)
- {
- case ACK:
- packetno++;
- sent_len += PACKET_LEN;
- goto START_TRANS;
- case CAN:
- if ((ch = getbyte_timeout(DLY_1S)) == CAN)
- {
- sendbyte(ACK);
- return REMOTE_CANCEL; /* canceled by remote */
- }
- break;
- case NAK:
- default:
- break;
- }
- }
-
- if(i == MAX_RETRANS -1)
- {
- //Has retransmit the maximum times without response from remote
- xmodem_cancel();
- return COM_TIMEOUT;
- }
- }
- }
- else
- {
- for (i = 0; i < MAX_RETRANS; i++)
- {
- sendbyte(EOT);
- if ((ch = getbyte_timeout((DLY_1S) << 1)) == ACK)
- break;
- }
- return (ch == ACK) ? sent_len : COM_TIMEOUT;
- }
- }
- /**
- * Transmit entry
- *
- * @param[in] src address of data be sent
- * @param[in] srcsz size of data be sent
- *
- * @ret >0 actual sent data length
- * @ret -1 remote cancel
- * @ret -2 communication timeout
- *
- * @see REMOTE_CANCEL,COM_TIMEOUT
- */
- int xmodemTransmit(unsigned char *src, int srcsz)
- {
- int ch = 0;
- flush_input();
-
- //Try to receive the first byte from remote
- ch = getbyte_timeout(DLY_1S * 30);
- if (ch >= 0)
- {
- switch (ch)
- {
- case USE_CRC:
- return xmodem_start_trans(1, src, srcsz);
- case NAK:
- return xmodem_start_trans(0, src, srcsz);
- case CAN:
- if ((ch = getbyte_timeout(DLY_1S)) == CAN)
- {
- //Canceled by remote
- sendbyte(ACK);
- return REMOTE_CANCEL;
- }
- break;
- default:
- printf("Unrecognized xmodem command byte: %d\n", ch);
- break;
- }
- }
- xmodem_cancel();
- return COM_TIMEOUT; /* no sync */
- }
- /**
- * Xmodem module test sample
- *
- * @param NONE
- *
- * @return NONE
- */
- void xmodem_test()
- {
- int st;
- uint8_t buf[128];
- st = xmodem_recv(buf, 128);
- xmodemTransmit(buf, st);
- }
复制代码
所有资料51hei提供下载:
xmodem.zip
(8.66 KB, 下载次数: 32)
|