最近需要做一个给 STM32F407 做一个 IAP,来进行远程升级,通讯接口是串口,在网上查了一下,看到多是用 ymodem 协议来接收数据包的,其实也可以用自定义协议,不过为了调试方便,还是选择用 ymodem 协议来实现,但是国内网上关于 ymodem 协议的描述文章都是大同小异,而且几乎没有一篇文章完整的描述了 ymodem 协议。所以到现在我也还是有一些没理解的问题(不知道谷歌能找到我没理解的问题不,没去找),不过好在调试都成功了,这里附上的也只是一个雏形,目前仅完成了接收部分,发送部分没做,还有很多没考虑到的,以后有空再更新补充完整吧,建议先看几篇关于 ymodem 协议的文章再来看这里的源码。
这里列出来的通信流程可能和在网上看到的流程有点差异,但事实确确实实是下面列出来的这样,可能和软件(超级终端、secureCRT)和软件版本有关吧。
/*
超级终端通信流程
发送端 接收端
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< C
SOH 00 FF [filename 00] [filesize 00] [NUL..] CRC CRC >>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< C
SOH 00 FF [filename 00] [filesize 00] [NUL..] CRC CRC >>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< C
STX 01 FE data[1024] CRC CRC>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK
STX 02 FD data[1024] CRC CRC>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK
STX 03 FC data[1024] CRC CRC>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK
STX 04 FB data[1024] CRC CRC>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK
SOH 05 FA data[100] 1A[28] CRC CRC>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK
EOT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< NAK
EOT>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< C
SOH 00 FF NUL[128] CRC CRC >>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK
**********************************************************
secureCRT通信过程-128-byte
发送端 接收端
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< C
SOH 00 FF [filename 00] [filesize 00] [NUL..] CRC CRC >>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< C
SOH 01 FE data[128] CRC CRC>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK
SOH 02 FD data[128] CRC CRC>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK
SOH 03 FC data[128] CRC CRC>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK
SOH 04 FB data[128] CRC CRC>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK
SOH 05 FA data[100] 1A[28] CRC CRC>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK
EOT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< NAK
EOT>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< C
SOH 00 FF NUL[128] CRC CRC >>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK
**********************************************************
secureCRT通信过程-1024-byte
发送端 接收端
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< C
STX 00 FF [filename 00] [filesize 00] [NUL..] CRC CRC >>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< C
STX 01 FE data[1024] CRC CRC>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK
STX 02 FD data[1024] CRC CRC>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK
STX 03 FC data[1024] CRC CRC>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK
STX 04 FB data[1024] CRC CRC>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK
STX 05 FA data[24] 1A[1000] CRC CRC>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK
EOT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< NAK
EOT>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< C
SOH 00 FF NUL[128] CRC CRC >>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __YMODEM_H_
#define __YMODEM_H_
#include "stdint.h"
#include "string.h"
#include "app_com.h"
#include "./tim/tim.h"
#include "./uart/uart2.h"
#include "./flash_if/flash_if.h"
/* Includes ------------------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
#define PACKET_SEQNO_INDEX (1)
#define PACKET_SEQNO_COMP_INDEX (2)
#define PACKET_HEADER (3)
#define PACKET_TRAILER (2)
#define PACKET_OVERHEAD (PACKET_HEADER + PACKET_TRAILER)
#define PACKET_SIZE (128)
#define PACKET_1K_SIZE (1024)
#define FILE_NAME_LENGTH (256)
#define FILE_SIZE_LENGTH (16)
#define SOH (0x01) /* start of 128-byte data packet */
#define STX (0x02) /* start of 1024-byte data packet */
#define EOT (0x04) /* end of transmission */
#define ACK (0x06) /* acknowledge */
#define NAK (0x15) /* negative acknowledge */
#define CAN (0x18) /* two of these in succession aborts transfer */
#define C (0x43) /* 'C' == 0x43, request 16-bit CRC */
#define NUL (0X00)
#define SUB (0x1A)
#ifndef COUNTOF
#define COUNTOF(a) (sizeof(a) / sizeof(*a))
#endif
/* Common routines */
#define IS_AF(c) ((c >= 'A') && (c <= 'F'))
#define IS_af(c) ((c >= 'a') && (c <= 'f'))
#define IS_09(c) ((c >= '0') && (c <= '9'))
#define ISVALIDHEX(c) IS_AF(c) || IS_af(c) || IS_09(c)
#define ISVALIDDEC(c) IS_09(c)
#define CONVERTDEC(c) (c - '0')
#define CONVERTHEX_alpha(c) (IS_AF(c) ? (c - 'A'+10) : (c - 'a'+10))
#define CONVERTHEX(c) (IS_09(c) ? (c - '0') : CONVERTHEX_alpha(c))
/*1:超级终端作为接收端
0:超级终端作为发送端
*/
#define DOWNLOAD 0
#if (DOWNLOAD > 0)
/*超级终端作为接收端仅握手一次*/
#define HAND_SHAKE_NUM 1
/*超级终端作为接收端仅发送一次 EOT*/
#define EOT_NUM 1
#else
#define HAND_SHAKE_NUM 2
#define EOT_NUM 2
#endif
/*FLASH 相关操作失败重试次数*/
#define FLASH_OPERATE_FAILED_RETRY 3
#pragma pack(1)/*设置单字节对齐*/
typedef union {
uint8_t packet_full[PACKET_1K_SIZE + PACKET_OVERHEAD];
struct {
uint8_t packet_header[PACKET_HEADER];
uint32_t packet_data[PACKET_1K_SIZE / 4];
uint8_t packet_trailer[PACKET_TRAILER];
}t;
}_packetBuf_u;
#pragma pack()
/* Exported functions ------------------------------------------------------- */
int32_t YmodemReceive(void);
int32_t YmodemTransmit (uint8_t *buf, const char* sendFileName, uint32_t sizeFile);
#endif /* __YMODEM_H_ */
#include "./Ymodem/Ymodem.h"
#define OPT_DBG_INF 1U
static int YmodemReceiveByte(uint8_t *data);
static void YmodemSendByte(uint8_t c);
static void YmodemSendPacket(uint8_t *data, uint16_t length);
static uint16_t UpdateCRC16(uint16_t crcIn, uint8_t byte);
static uint16_t Cal_CRC16(const uint8_t* data, uint32_t size);
static uint8_t CalChecksum(const uint8_t* data, uint32_t size);
static void Int2Str(uint8_t* str, int32_t intnum);
static uint32_t Str2Int(uint8_t *inputstr, int32_t *intnum);
static _packetBuf_u packetBuf;
/*解析最后一个包*/
int32_t YmodemParsingLastPacket(uint8_t *data)
{
if((data[PACKET_SEQNO_INDEX] == 0x00) &&
(data[PACKET_SEQNO_COMP_INDEX] == 0xff))
{
uint16_t crc = Cal_CRC16(&data[PACKET_HEADER],PACKET_SIZE);
if(crc == (uint16_t)((uint16_t)(data[PACKET_SIZE + PACKET_OVERHEAD - 2] << 8) | data[PACKET_SIZE + PACKET_OVERHEAD - 1]))
{
return 0;
}
}
return -1;
}
/*解析第一包*/
int32_t YmodemParsingIntialPacket(uint8_t *data)
{
uint32_t i = 0,j = 0,endAddress = 0;
int32_t size = 0;
uint8_t fileName[FILE_NAME_LENGTH] = {0},filesize[FILE_SIZE_LENGTH] = {0};
if((data[PACKET_SEQNO_INDEX] == 0x00) &&
(data[PACKET_SEQNO_COMP_INDEX] == 0xff))
{
uint16_t crc = Cal_CRC16(&data[PACKET_HEADER],PACKET_SIZE);
if(crc == (uint16_t)((uint16_t)(data[PACKET_SIZE + PACKET_OVERHEAD - 2] << 8) | data[PACKET_SIZE + PACKET_OVERHEAD - 1]))
{
for( ;(packetBuf.packet_full[i + PACKET_HEADER] != '\0') && (i < FILE_NAME_LENGTH);i++)
{
fileName[i] = packetBuf.packet_full[i + PACKET_HEADER];
}
#if(OPT_DBG_INF > 0U)
PRINTF("\n%s:",fileName);
#endif
for(i = i + PACKET_HEADER + 1;(packetBuf.packet_full[i] != '\0') && (j < FILE_SIZE_LENGTH); )
{
filesize[j++] = packetBuf.packet_full[i++];
}
if(0 != Str2Int(filesize,&size))
{
#if(OPT_DBG_INF > 0U)
PRINTF("%dkb,%dbyte\n",size / 1024,size);
#endif
if((size > 0) && (size <= (USER_FLASH_END_ADDRESS - APPLICATION_ADDRESS)))
{
endAddress = APPLICATION_ADDRESS + size;
#if(OPT_DBG_INF > 0U)
PRINTF("endAddress:%08x\n",endAddress);
#endif
if(0 == FLASH_If_Erase(APPLICATION_ADDRESS,endAddress))
{
return 0;
}
else
{
return -2;
}
}
}
}
}
return -1;
}
/*解析数据包*/
int32_t YmodemParsingPacket(uint8_t *data, const uint8_t pktNo, uint32_t packetLen, uint32_t address)
{
if((data[PACKET_SEQNO_INDEX] == pktNo) &&
(((data[PACKET_SEQNO_COMP_INDEX] ^ 0xff) & 0xff) == pktNo))
{
uint16_t crc = Cal_CRC16(&data[PACKET_HEADER],packetLen - PACKET_OVERHEAD);
if(crc == (uint16_t)((uint16_t)(data[packetLen - 2] << 8) | data[packetLen - 1]))
{
if(0 == FLASH_If_Write(address,(uint32_t *)packetBuf.t.packet_data,(packetLen - PACKET_OVERHEAD) / 4))
{
return 0;
}
else
{
return -2;
}
}
}
return -1;
}
/*
* 接收数据包
* 返回值:
* 0:正常接收,>0:超时退出,-1:第一包序号错误,-2:FLASH 多次尝试失败,-3:最后一包错误
*/
int32_t YmodemReceive(void)
{
uint8_t SeqNo = 0x01;
uint8_t ch = 0;
uint32_t err = 0,ackReceived = 0,idx = 0,packetLen = 0,reTryCnt = 0,nakReTryCnt = 0;
int32_t ret = 0;
uint32_t address = APPLICATION_ADDRESS;
do
{
YmodemSendByte(C);
if((YmodemReceiveByte(&ch) < 0) || (ch != SOH))
{
err++;
}
else
{
err = 0;
packetBuf.packet_full[idx++] = ch;
do
{
if(YmodemReceiveByte(&ch) < 0)
{
err++;
}
else
{
packetBuf.packet_full[idx++] = ch;
}
}while((idx < (PACKET_SIZE + PACKET_OVERHEAD)) && (err < 0x0a));
if(err >= 0x0a)
{
return err;
}
err = 0;
idx = 0;
do
{
ret = YmodemParsingIntialPacket(packetBuf.packet_full);
if(ret < -1)
{
reTryCnt++;
}
else
{
break;
}
}while(reTryCnt < FLASH_OPERATE_FAILED_RETRY);
if(reTryCnt >= FLASH_OPERATE_FAILED_RETRY)
{
return -2;
}
reTryCnt = 0;
if(ret < 0)
{
return -1;
}
ret = 0;
ackReceived++;
if(!(ackReceived < HAND_SHAKE_NUM))
{
YmodemSendByte(ACK);
YmodemSendByte(C);
}
}
}while((ackReceived < HAND_SHAKE_NUM) && (err < 0x0a));
if(err >= 0x0a)
{
return err;
}
err = 0;
ackReceived = 0;
do
{
if(YmodemReceiveByte(&ch) < 0)
{
err++;
}
else
{
if((ch == SOH) || (ch == STX))
{
err = 0;
packetBuf.packet_full[idx++] = ch;
packetLen = ((packetBuf.packet_full[0] == STX) ? PACKET_1K_SIZE : PACKET_SIZE) + PACKET_OVERHEAD;
do
{
if(YmodemReceiveByte(&ch) < 0)
{
err++;
}
else
{
packetBuf.packet_full[idx++] = ch;
}
}while((idx < packetLen) && (err < 0x0a));
if(err >= 0x0a)
{
return err;
}
err = 0;
idx = 0;
do
{
ret = YmodemParsingPacket(packetBuf.packet_full,SeqNo,packetLen,address);
if(ret < -1)
{
reTryCnt++;
}
else
{
break;
}
}while(reTryCnt < FLASH_OPERATE_FAILED_RETRY);
if(reTryCnt >= FLASH_OPERATE_FAILED_RETRY)
{
return -2;
}
reTryCnt = 0;
if(ret < 0)
{
nakReTryCnt++;
YmodemSendByte(NAK);
}
else
{
SeqNo++;
address += (packetLen - PACKET_OVERHEAD);
YmodemSendByte(ACK);
}
ret = 0;
}
else if(ch == EOT)
{
break;
}
else
{
err++;
}
}
}while((err < 0x0a) && (nakReTryCnt < 0x0a));
if(err >= 0x0a)
{
return err;
}
err = 0;
if(nakReTryCnt >= 0x0a)
{
return nakReTryCnt;
}
nakReTryCnt = 0;
idx = 0;
YmodemSendByte(NAK);
do
{
if((YmodemReceiveByte(&ch) < 0) || (ch != EOT))
{
err++;
}
else
{
ackReceived++;
}
}while((!ackReceived) && (err < 0x0a));
if(err >= 0x0a)
{
return err;
}
err = 0;
ackReceived = 0;
YmodemSendByte(ACK);
YmodemSendByte(C);
do
{
if((YmodemReceiveByte(&ch) < 0) || (ch != SOH))
{
err++;
}
else
{
err = 0;
packetBuf.packet_full[idx++] = ch;
do
{
if(YmodemReceiveByte(&ch) < 0)
{
err++;
}
else
{
packetBuf.packet_full[idx++] = ch;
}
}while((idx < (PACKET_SIZE + PACKET_OVERHEAD)) && (err < 0x0a));
if(err >= 0x0a)
{
return err;
}
err = 0;
idx = 0;
ackReceived++;
}
}while((!ackReceived) && (err < 0x0a));
if(err >= 0x0a)
{
return err;
}
err = 0;
ackReceived = 0;
if(!(YmodemParsingLastPacket(packetBuf.packet_full) < 0))
{
YmodemSendByte(ACK);
return 0;
}
return -3;
}
/*ymodem receive byte*/
static int YmodemReceiveByte(uint8_t *data)
{
return Usart2ReceiveBytes_polling(data,1);
}
/*ymodem send byte*/
static void YmodemSendByte(uint8_t c)
{
Usart2SendBytes_polling(&c,1);
}
static void YmodemSendPacket(uint8_t *data, uint16_t length)
{
uint16_t i = 0;
while (i < length)
{
YmodemSendByte(data[i]);
i++;
}
}
/**
* @brief Update CRC16 for input byte
* @param CRC input value
* @param input byte
* @retval None
*/
static uint16_t UpdateCRC16(uint16_t crcIn, uint8_t byte)
{
uint32_t crc = crcIn;
uint32_t in = byte | 0x100;
do
{
crc <<= 1;
in <<= 1;
if(in & 0x100)
++crc;
if(crc & 0x10000)
crc ^= 0x1021;
}
while(!(in & 0x10000));
return crc & 0xffffu;
}
/**
* @brief Cal CRC16 for YModem Packet
* @param data
* @param length
* @retval None
*/
static uint16_t Cal_CRC16(const uint8_t* data, uint32_t size)
{
uint32_t crc = 0;
const uint8_t* dataEnd = data+size;
while(data < dataEnd)
crc = UpdateCRC16(crc, *data++);
crc = UpdateCRC16(crc, 0);
crc = UpdateCRC16(crc, 0);
return crc&0xffffu;
}
/**
* @brief Cal Check sum for YModem Packet
* @param data
* @param length
* @retval None
*/
static uint8_t CalChecksum(const uint8_t* data, uint32_t size)
{
uint32_t sum = 0;
const uint8_t* dataEnd = data+size;
while(data < dataEnd )
sum += *data++;
return (sum & 0xffu);
}
/**
* @brief Convert an Integer to a string
* @param str: The string
* @param intnum: The integer to be converted
* @retval None
*/
static void Int2Str(uint8_t* str, int32_t intnum)
{
uint32_t i, Div = 1000000000, j = 0, Status = 0;
for (i = 0; i < 10; i++)
{
str[j++] = (intnum / Div) + 48;
intnum = intnum % Div;
Div /= 10;
if ((str[j-1] == '0') & (Status == 0))
{
j = 0;
}
else
{
Status++;
}
}
}
/**
* @brief Convert a string to an integer
* @param inputstr: The string to be converted
* @param intnum: The integer value
* @retval 1: Correct
* 0: Error
*/
static uint32_t Str2Int(uint8_t *inputstr, int32_t *intnum)
{
uint32_t i = 0, res = 0;
uint32_t val = 0;
if (inputstr[0] == '0' && (inputstr[1] == 'x' || inputstr[1] == 'X'))
{
if (inputstr[2] == '\0')
{
return 0;
}
for (i = 2; i < 11; i++)
{
if (inputstr[i] == '\0')
{
*intnum = val;
/* return 1; */
res = 1;
break;
}
if (ISVALIDHEX(inputstr[i]))
{
val = (val << 4) + CONVERTHEX(inputstr[i]);
}
else
{
/* Return 0, Invalid input */
res = 0;
break;
}
}
/* Over 8 digit hex --invalid */
if (i >= 11)
{
res = 0;
}
}
else /* max 10-digit decimal input */
{
for (i = 0;i < 11;i++)
{
if (inputstr[i] == '\0')
{
*intnum = val;
/* return 1 */
res = 1;
break;
}
else if ((inputstr[i] == 'k' || inputstr[i] == 'K') && (i > 0))
{
val = val << 10;
*intnum = val;
res = 1;
break;
}
else if ((inputstr[i] == 'm' || inputstr[i] == 'M') && (i > 0))
{
val = val << 20;
*intnum = val;
res = 1;
break;
}
else if (ISVALIDDEC(inputstr[i]))
{
val = val * 10 + CONVERTDEC(inputstr[i]);
}
else
{
/* return 0, Invalid input */
res = 0;
break;
}
}
/* Over 10 digit decimal --invalid */
if (i >= 11)
{
res = 0;
}
}
return res;
}
/*打包数据
* SourceBuf:数据源
* data:打包后的数据
* pktNo:包序号
* sizeBlk:数据量
*/
void YmodemPreparePacket(uint8_t *SourceBuf, uint8_t *data, uint8_t pktNo, uint32_t sizeBlk)
{
uint16_t i = 0, size = 0, packetSize = 0;
uint8_t* file_ptr = NULL;
/* 判断需要使用的包大小 */
packetSize = sizeBlk < PACKET_SIZE ? PACKET_SIZE : PACKET_1K_SIZE;
/* 填充到包的数据量 */
size = sizeBlk < packetSize ? sizeBlk :packetSize;
if (packetSize == PACKET_1K_SIZE)
{
data[0] = STX;
}
else
{
data[0] = SOH;
}
data[1] = pktNo;
data[2] = (~pktNo);
file_ptr = SourceBuf;
/* 转移有效数据 */
for (i = PACKET_HEADER; i < size + PACKET_HEADER;i++)
{
data[i] = *file_ptr++;
}
if ( size <= packetSize)
{
for (i = size + PACKET_HEADER; i < packetSize + PACKET_HEADER; i++)
{
data[i] = SUB;
}
}
}
/*准备第一个包
* data:打包后的数据
* fileName:文件名
* length:文件大小(单位:byte)
*/
void YmodemPrepareIntialPacket(uint8_t *data, const char* fileName, uint32_t *length)
{
uint16_t i = 0, j = 0;
uint8_t file_ptr[FILE_SIZE_LENGTH] = {0};
data[0] = SOH;
data[1] = 0x00;
data[2] = 0xff;
/* 转移有效数据 */
for (i = 0; (fileName[i] != '\0') && (i < FILE_NAME_LENGTH);i++)
{
data[i + PACKET_HEADER] = fileName[i];
}
data[i + PACKET_HEADER] = NUL;
Int2Str (file_ptr, *length);
for (j =0, i = i + PACKET_HEADER + 1; (file_ptr[j] != '\0') && (j < FILE_SIZE_LENGTH) ; )
{
data[i++] = file_ptr[j++];
}
for (j = i; j < PACKET_SIZE + PACKET_HEADER; j++)
{
data[j] = NUL;
}
}
/*准备最后一个包
* data:打包后的数据
*/
void YmodemPrepareLastPacket(uint8_t *data)
{
uint16_t i = 0;
data[0] = SOH;
data[1] = 0x00;
data[2] = 0xff;
for ( i = PACKET_HEADER; i < PACKET_SIZE + PACKET_HEADER; i++)
{
data[i] = NUL;
}
}
/*Ymodem 发送
* buf:数据源
* sendFileName:文件名
* sizeFile:文件大小
* 返回值:
* 0:正常发送,>0:超时退出
*/
int32_t YmodemTransmit (uint8_t *buf, const char* sendFileName, uint32_t sizeFile)
{
uint8_t SeqNo = 0x01;
uint16_t tempCRC = 0;
uint8_t tempCheckSum = 0;
uint8_t ch[2] = {0},idx = 0,chk = 0;
uint32_t err = 0,ackReceived = 0,packSize = 0;
do
{
do
{
/* wait for 'C' or 'NAK' */
if(YmodemReceiveByte(&ch[0]) < 0)
{
err++;
}
else
{
if((ch[0] == C) || (ch[0] == NAK))
{
/* received 'C' or 'NAK' */
ackReceived++;
}
else
{
err++;
}
}
}while((!ackReceived) && (err < 0x0a));
if(err >= 0x0a)
{
/* timeout */
return err;
}
err = 0;
chk = ch[0];
/* prepare start packet */
YmodemPrepareIntialPacket(packetBuf.packet_full,sendFileName,&sizeFile);
/* send start packet */
YmodemSendPacket(packetBuf.packet_full, PACKET_SIZE + PACKET_HEADER);
/* cal CRC or check sum */
if (chk == C)
{
tempCRC = Cal_CRC16(&packetBuf.packet_full[PACKET_HEADER], PACKET_SIZE);
YmodemSendByte(tempCRC >> 8);
YmodemSendByte(tempCRC & 0xFF);
}
else
{
tempCheckSum = CalChecksum (&packetBuf.packet_full[PACKET_HEADER], PACKET_SIZE);
YmodemSendByte(tempCheckSum);
}
}while(ackReceived < HAND_SHAKE_NUM);
ackReceived = 0;
do
{
/* wait for 'C' and 'ACK' */
if(YmodemReceiveByte(&ch[idx]) < 0)
{
err++;
}
else
{
if(ch[0] == ACK)
{
if(idx > 0)
{
if(ch[1] == C)
{
/* received 'C' and 'ACK' */
ackReceived++;
}
else
{
err++;
}
}
else
{
idx++;
}
}
else
{
err++;
}
}
}while((!ackReceived) && (err < 0x0a));
if(err >= 0x0a)
{
/* timeout */
return err;
}
err = 0;
ackReceived = 0;
idx = 0;
while(sizeFile)
{
YmodemPreparePacket(buf,packetBuf.packet_full,SeqNo,sizeFile);
packSize = packetBuf.packet_full[0] == STX ? PACKET_1K_SIZE : PACKET_SIZE;
/* send data packet */
YmodemSendPacket(packetBuf.packet_full, packSize + PACKET_HEADER);
if (chk == C)
{
tempCRC = Cal_CRC16(&packetBuf.packet_full[PACKET_HEADER], packSize);
YmodemSendByte(tempCRC >> 8);
YmodemSendByte(tempCRC & 0xFF);
}
else
{
tempCheckSum = CalChecksum (&packetBuf.packet_full[PACKET_HEADER], packSize);
YmodemSendByte(tempCheckSum);
}
do
{
/* wait for 'ACK' or 'NAK' */
if(YmodemReceiveByte(&ch[0]) < 0)
{
err++;
}
else
{
if((ch[0] == ACK) || (ch[0] == NAK))
{
/* received 'ACK' or 'NAK' */
ackReceived++;
}
else
{
err++;
}
}
}while((!ackReceived) && (err < 0x0a));
if(err >= 0x0a)
{
/* timeout */
return err;
}
err = 0;
ackReceived = 0;
if(ch[0] == ACK)
{
buf += packSize;
SeqNo++;
if(sizeFile > packSize)
{
sizeFile -= packSize;
}
else
{
sizeFile = 0;
}
}
}
buf = 0;
SeqNo = 0;
#if (EOT_NUM > 1)
/* send 'EOT' */
YmodemSendByte(EOT);
do
{
/* wait for 'NAK' */
if((YmodemReceiveByte(&ch[0]) < 0) || (ch[0] != NAK))
{
err++;
}
else
{
/* received 'NAK' */
ackReceived++;
}
}while((!ackReceived) && (err < 0x0a));
if(err >= 0x0a)
{
/* timeout */
return err;
}
err = 0;
ackReceived = 0;
#endif/*EOT_NUM*/
/* send 'EOT' */
YmodemSendByte(EOT);
do
{
/* wait for 'C' and 'ACK' */
if(YmodemReceiveByte(&ch[idx]) < 0)
{
err++;
}
else
{
if(ch[0] == ACK)
{
if(idx > 0)
{
if(ch[1] == C)
{
/* received 'C' and 'ACK' */
ackReceived++;
}
else
{
err++;
}
}
else
{
idx++;
}
}
else
{
err++;
}
}
}while((!ackReceived) && (err < 0x0a));
if(err >= 0x0a)
{
/* timeout */
return err;
}
err = 0;
ackReceived = 0;
idx = 0;
YmodemPrepareLastPacket(packetBuf.packet_full);
/* send end packet */
YmodemSendPacket(packetBuf.packet_full, PACKET_SIZE + PACKET_HEADER);
if (chk == C)
{
tempCRC = Cal_CRC16(&packetBuf.packet_full[PACKET_HEADER], PACKET_SIZE);
YmodemSendByte(tempCRC >> 8);
YmodemSendByte(tempCRC & 0xFF);
}
else
{
tempCheckSum = CalChecksum (&packetBuf.packet_full[PACKET_HEADER], PACKET_SIZE);
YmodemSendByte(tempCheckSum);
}
do
{
/* wait for 'ACK' */
if((YmodemReceiveByte(&ch[0]) < 0) || (ch[0] != ACK))
{
err++;
}
else
{
/* received 'ACK' */
ackReceived++;
}
}while((!ackReceived) && (err < 0x0a));
if(err >= 0x0a)
{
/* timeout */
return err;
}
err = 0;
ackReceived = 0;
return 0;
}