/*
*********************************************************************************************************
*
* 模块名称 : XYZmodem协议
* 文件名称 : xyzmodem.c
* 版 本 : V1.0
* 说 明 : xyzmodem协议
*
* 修改记录
* 版本号 日期 作者 说明
* V1.0 2022-08-08 Eric2013 首发
*
* Copyright (C), 2022-2030, 安富莱电子 www.armbbs.cn
*
*********************************************************************************************************
*/
#include <stdio.h>
#include <stdlib.h>
#include "stdint.h"
#include <windows.h>
#include "uart.c"
/*
*********************************************************************************************************
* Ymodem文件传输协议介绍
*********************************************************************************************************
*/
/*
第1阶段: 同步
从机给数据发送同步字符 C
第2阶段:发送第1帧数据,包含文件名和文件大小
主机发送:
---------------------------------------------------------------------------------------
| SOH | 序号 - 0x00 | 序号取反 - 0xff | 128字节数据,含文件名和文件大小字符串|CRC0 CRC1|
|-------------------------------------------------------------------------------------|
从机接收:
接收成功回复ACK和CRC16,接收失败(校验错误,序号有误)继续回复字符C,超过一定错误次数,回复两个CA,终止传输。
第3阶段:数据传输
主机发送:
---------------------------------------------------------------------------------------
| SOH/STX | 从0x01开始序号 | 序号取反 | 128字节或者1024字节 |CRC0 CRC1|
|-------------------------------------------------------------------------------------|
从机接收:
接收成功回复ACK,接收失败(校验错误,序号有误)或者用户处理失败继续回复字符C,超过一定错误次数,回复两个CA,终止传输。
第4阶段:结束帧
主机发送:发送EOT结束传输。
从机接收:回复ACK。
第5阶段:空帧,结束通话
主机发送:一帧空数据。
从机接收:回复ACK。
*/
#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 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 NAK_TIMEOUT (0x100000)
#define MAX_ERRORS (5)
/*
*********************************************************************************************************
* 函 数 名: Int2Str
* 功能说明: 将整数转换成字符
* 形 参: str 字符 intnum 整数
* 返 回 值: 无
*********************************************************************************************************
*/
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++;
}
}
}
/*
*********************************************************************************************************
* 函 数 名: Ymodem_PrepareIntialPacket
* 功能说明: 准备第一包要发送的数据
* 形 参: data 数据
* fileName 文件名
* length 文件大小
* 返 回 值: 0
*********************************************************************************************************
*/
void Ymodem_PrepareIntialPacket(uint8_t *data, const uint8_t* fileName, uint32_t *length)
{
uint16_t i, j;
uint8_t file_ptr[10];
/* 第一包数据的前三个字符 */
data[0] = SOH; /* soh表示数据包是128字节 */
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] = 0x00;
/* 文件大小转换成字符 */
Int2Str (file_ptr, *length);
for (j =0, i = i + PACKET_HEADER + 1; file_ptr[j] != '\0' ; )
{
data[i++] = file_ptr[j++];
}
/* 其余补0 */
for (j = i; j < PACKET_SIZE + PACKET_HEADER; j++)
{
data[j] = 0;
}
}
/*
*********************************************************************************************************
* 函 数 名: Ymodem_PreparePacket
* 功能说明: 准备发送数据包
* 形 参: SourceBuf 要发送的原数据
* data 最终要发送的数据包,已经包含的头文件和原数据
* pktNo 数据包序号
* sizeBlk 要发送数据数
* 返 回 值: 无
*********************************************************************************************************
*/
int sendsize = 0;
void Ymodem_PreparePacket(uint8_t *SourceBuf, uint8_t *data, uint8_t pktNo, uint32_t sizeBlk)
{
uint16_t i, size, packetSize;
uint8_t* file_ptr;
/* 设置好要发送数据包的前三个字符data[0],data[1],data[2] */
/* 根据sizeBlk的大小设置数据区数据个数是取1024字节还是取128字节*/
packetSize = sizeBlk >= PACKET_1K_SIZE ? PACKET_1K_SIZE : PACKET_SIZE;
/* 数据大小进一步确定 */
size = sizeBlk < packetSize ? sizeBlk :packetSize;
/* 首字节:确定是1024字节还是用128字节 */
if (packetSize == PACKET_1K_SIZE)
{
data[0] = STX;
}
else
{
data[0] = SOH;
}
/* 第2个字节:数据序号 */
data[1] = pktNo;
/* 第3个字节:数据序号取反 */
data[2] = (~pktNo);
file_ptr = SourceBuf;
/* 填充要发送的原始数据 */
for (i = PACKET_HEADER; i < size + PACKET_HEADER;i++)
{
data[i] = *file_ptr++;
}
/* 不足的补 EOF (0x1A) 或 0x00 */
if ( size <= packetSize)
{
for (i = size + PACKET_HEADER; i < packetSize + PACKET_HEADER; i++)
{
data[i] = 0x1A; /* EOF (0x1A) or 0x00 */
}
}
sendsize += size;
printf("SendSize = %d\r\n", sendsize);
}
/*
*********************************************************************************************************
* 函 数 名: UpdateCRC16
* 功能说明: 上次计算的CRC结果 crcIn 再加上一个字节数据计算CRC
* 形 参: crcIn 上一次CRC计算结果
* byte 新添加字节
* 返 回 值: 无
*********************************************************************************************************
*/
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;
}
/*
*********************************************************************************************************
* 函 数 名: Cal_CRC16
* 功能说明: 计算一串数据的CRC
* 形 参: data 数据
* size 数据长度
* 返 回 值: CRC计算结果
*********************************************************************************************************
*/
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;
}
/*
*********************************************************************************************************
* 函 数 名: CalChecksum
* 功能说明: 计算一串数据总和
* 形 参: data 数据
* size 数据长度
* �