/**************************************************************************
*
* 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;
xmode
评论0