一.对ymodem协议的基础通信结构解读:
(1)Ymodem 有两种帧格式,主要区别是信息块长度不一样。
(2)帧头表示两种数据帧长度,主要是信息块长度不同。
(3)数据包序号只有1字节,因此计算范围是0~255;对于数据包大于255的,序号归零重复计算。
(4)【1】以SOH(0x01)开始的数据包,信息块是128字节,该类型帧总长度为133字节。
【2】以STX(0x02)开始的数据包,信息块是1024字节,该类型帧总长度为1029字节。
(5)Ymodem采用的是CRC16校验算法,校验值为2字节,传输时CRC高八位在前,低八位在后;CRC计算数据为信息块数据,不包含帧头、包号、包号反码。
(6)握手信号由接收方发起,在发送方开始传输文件前,接收方需发送YMODEM_C (字符C,ASII码为0x43)命令,发送方收到后,开始传输起始帧。
(7)Ymodem起始帧并不直接传输文件内容,而是先将文件名和文件大小置于数据帧中传输;起始帧是以SOH 133字节长度帧传输,格式如下。
其中包号为固定为0;Filename为文件名称,文件名称后必须加0x00作为结束;Filesize为文件大小值,文件大小值后必须加0x00作为结束;余下未满128字节数据区域,则以0x00填充。
(8)Ymodem数据帧传输,在信息块填充有效数据。
传输有效数据时主要考虑的是最后一包数据的是处理,SOH帧和STR帧有不同的处理。
【1】对于SOH帧,若余下数据小于128字节,则以0x1A填充,该帧长度仍为133字节。
【2】对于STX帧需考虑几种情况:
●余下数据等于1024字节,以1029长度帧发送;
●余下数据小于1024字节,但大于128字节,以1029字节帧长度发送,无效数据以0x1A填充。
●余下数据等于128字节,以133字节帧长度发送。
●余下数据小于128字节,以133字节帧长度发送,无效数据以0x1A填充。
(9)Ymodem的结束帧采用SOH 133字节长度帧传输,该帧不携带数据(空包),即数据区、校验都以0x00填充。
(10)通信中的命令
二.文件内容。
//ymodem的命令的定义
#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 CA (0x18) /* two of these in succession aborts transfer */
#define CRC16 (0x43) /* 'C' == 0x43, request 16-bit CRC */
#define ABORT1 (0x41) /* 'A' == 0x41, abort by user */
#define ABORT2 (0x61) /* 'a' == 0x61, abort by user */
#define ENTER (0xd) /* enter , do not jump to app , done in 2S*/
#define NAK_TIMEOUT (0x400000)
#define MAX_ERRORS (3)
//传输的数据包的大小
#define PACKET_SIZE (128)
#define PACKET_1K_SIZE (1024)
//包的数据序号,以及比较缓存序号,用于确保数据包的序号
#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 Size_512KByte 524288 //存储字节格式
typedef struct
{
uint8_t begin; //1:正在传输,0:不在传输 2:传输完成
uint32_t file_exist; //0:传输的文件不存在, 1:传输的文件存在
UART_HandleTypeDef YmodemUart_Handler; //对应ymodem的串口通信的结构体初始化句柄 等效huart_x
}Ymodem_TypeDef;
uint32_t file_verison,file_crc;//定义文件版本号以及文件32CRC,
uint32_t file_exist;//STM32中是否有文件标志 0:文件不存在, 1:文件存在
//用于将str》》》int转换的宏定义
#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')
程序:ymodem初始化,配置
//首先是初始化ymodem用到串口传输的初始化
void Ymodem_Init(void)
{
huart2.Instance=USART2;
huart2.Init.BaudRate=115200;
huart2.Init.WordLength=UART_WORDLENGTH_8B;
huart2.Init.StopBits=UART_STOPBITS_1;
huart2.Init.Parity=UART_PARITY_NONE;
huart2.Init.HwFlowCtl=UART_HWCONTROL_NONE;
huart2.Init.Mode=UART_MODE_TX_RX;
HAL_UART_Init(&huart2);
HAL_NVIC_DisableIRQ(USART2_IRQn); //在NVIC中断控制器中禁用该设备的中断。
}
/**
* @brief 将字符串转换成数字
* @param inputstr: 待转换的字符串
* @param intnum: 转换得到的数字
* @retval 1: 正确
* 0: 错误
*/
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