optical/NxFuncs/comm/xmodem.c
2025-09-04 09:45:08 +08:00

368 lines
6.3 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "xmodem.h"
#include "serial.h"
#include "trigger.h"
#include "shell.h"
#include "delay.h"
//---------------------------------------------------------
#define DEBUG_OK 0
#if (DEBUG_OK == 1)
#define DEBUG_OUT(...) do \
{\
printf(__VA_ARGS__); \
}while(0)
void OutDebugBufInfo(void){};
#elif (DEBUG_OK == 2)
char g_debugbuf[200][50];
int g_debugidx = 0;
#define DEBUG_OUT(...) do \
{\
if (g_debugidx < 200) \
{ \
sprintf((char*)&(g_debugbuf[g_debugidx][0]), __VA_ARGS__); \
g_debugidx++; \
} \
}while(0)
#if (DEBUG_OK == 2)
void OutDebugBufInfo(void)
{
printf("\r\nDebug buff info (%d):\r\n", g_debugidx);
for (int i = 0; i < g_debugidx; i++)
{
printf("%s", (char*)(&g_debugbuf[i][0]));
DelayMs(10);
}
printf("\r\nDebug buff info end\r\n");
g_debugidx = 0;
}
#endif
#else
#define DEBUG_OUT(...) do {}while(0)
void OutDebugBufInfo(void){};
#endif
//---------------------------------------------------------
// 计算xmodem的crc值
u16 CalcXModemCrc(u8 * pDat, int count)
{
u16 crc;
int i;
crc = 0;
while (--count >= 0)
{
crc = crc ^ (u16) (*pDat++ << 8);
i = 8;
do
{
if (crc & 0x8000)
{
crc = crc << 1 ^ 0x1021; // X16+X12+X5+X0
}
else
{
crc = crc << 1;
}
} while (--i);
}
return (crc);
}
// 检验xmodem数据包的正确性
int CheckXModemDat(int crcflag, u8 * pBuf, int size)
{
if(crcflag != 0)
{
u16 crc = CalcXModemCrc(pBuf, size);
u16 tcrc = ((u16)(pBuf[size])<<8) + pBuf[size+1];
if (crc == tcrc)
{
return 1;
}
}
else
{
int i = 0;
u8 cks = 0;
for(i = 0; i < size; i++)
{
cks += pBuf[i];
}
if (cks == pBuf[size])
{
return 1;
}
}
return 0;
}
// 接收xmodem数据
int XmodemReceive(XmodemCtrl * pCtrl)
{
int rslt, err, retry, recvsize, exsize;
int timer;
u8 packid, tmpid, temp;
u8 trychar, svchar;
u8 xbuff[XMODEM1K_FRAME_C];
u8 ch;
int crcflag;
int datidx;
trychar = 'C'; // 先用crc校验方式
svchar = trychar;
recvsize = 0;
packid = 1;
err = 0;
datidx = 0;
pCtrl->InitSave();
DEBUG_OUT("Start XmodemReceive\r\n");
#define MAX_RETRY 32
// 启动传输
for (retry = 0; retry < MAX_RETRY; retry++) // 尝试启动发送
{
// 1. 向发送方发送同步字节
if(trychar != 0)
{
xbuff[0] = trychar;
pCtrl->XmodemOutBuff(xbuff, 1);
}
// 2. 等待回复数据包
timer = GetMsSoftTimer(); // 记录时间
recvsize = 0;
do
{
rslt = pCtrl->XmodemInBuff(xbuff, 1);
if (rslt != 1) // 等到字符
{
if (GetMsSoftTimer() - timer > 1000) // 判断是否超时
{
break;
}
continue;
}
ch = xbuff[0];
switch(ch)
{
case XMODEM_SOH: // Xmodem数据包头
{
DEBUG_OUT("get soh\r\n");
recvsize = XMODEM_F_SIZE;
break;
}
case XMODEM_STX: // 1K-Xmodem数据包头
{
DEBUG_OUT("get stx\r\n");
recvsize = XMODEM1K_F_SIZE;
break;
}
case XMODEM_EOT: // 传输结束
{
DEBUG_OUT("get eot\r\n");
pCtrl->XmodemCleanBuff(); // 清除已经接收数据
xbuff[0] = XMODEM_ACK; // 确认回复
pCtrl->XmodemOutBuff(xbuff, 1);
err = 1;
break;
}
case XMODEM_CAN: // 取消传输
{
DEBUG_OUT("get can\r\n");
pCtrl->XmodemCleanBuff(); // 清除已经接收数据
xbuff[0] = XMODEM_ACK; // 确认回复
pCtrl->XmodemOutBuff(xbuff, 1);
err = -2;
break;
}
default:
{
DEBUG_OUT("get others\r\n");
break;
}
}
break;
}while(1);
if (err == 0)
{
// 3. 判断回复是否正确
if (recvsize == 0) // 同步字超时
{
if (trychar == 'C')
{
if (retry >= MAX_RETRY-1)
{
trychar = XMODEM_NAK; // 改为使用和校验方式
retry = 0;
}
continue; // 重新开始
}
else
{
if (retry >= MAX_RETRY-1)
{
err = -1; // 真超时,退出
}
else
{
continue;
}
}
}
if (trychar != 0)
{
DEBUG_OUT("save trychar\r\n");
svchar = trychar;
}
trychar = 0; // 已经启动了传输
}
// 传输文件内容
if (err == 0 && recvsize != 0)
{
if (svchar == 'C')
{
DEBUG_OUT("exsize = 4\r\n");
exsize = XMODEM_HEAD_SIZE+XMODEM_CRC_SIZE-1;
crcflag = 1;
}
else
{
DEBUG_OUT("exsize = 3\r\n");
exsize = XMODEM_HEAD_SIZE+XMODEM_CHECK_SIZE-1;
crcflag = 0;
}
// 接收数据包
timer = GetMsSoftTimer(); // 记录时间
DEBUG_OUT("timer=%d\r\n", timer);
do
{
rslt = pCtrl->XmodemInBuff(&(xbuff[1]), recvsize+exsize);
if (rslt == recvsize+exsize) // 等到字符
{
DEBUG_OUT("get exsize+recvsize=%d+%d\r\n", exsize, recvsize);
tmpid = xbuff[1];
temp = ~(xbuff[2]);
if ((tmpid == temp) &&
(CheckXModemDat(crcflag, &(xbuff[3]), recvsize) != 0))
{
xbuff[0] = XMODEM_ACK; // 回复ACK确认接收到请求发送下一个数据包
pCtrl->XmodemOutBuff(xbuff, 1);
DEBUG_OUT("check ok, send ack\r\n");
if (tmpid == packid) // 保存数据
{
int svlen;
int svflag = (datidx == 0 ? 0:1);
svlen = pCtrl->SaveData(svflag, &(xbuff[3]), recvsize, pCtrl->savedsize); // 保存数据
if (svlen > 0)
{
pCtrl->savedsize += svlen;
}
datidx++;
packid++;
}
retry = 0;
}
else
{
xbuff[0] = XMODEM_NAK; // 回复 NAK需要重新传输该数据包
pCtrl->XmodemOutBuff(xbuff, 1);
DEBUG_OUT("crc err, send NAK\r\n");
}
break;
}
else
{
int tptimer;
// 接收
tptimer = GetMsSoftTimer();
if (tptimer - timer > recvsize*1) // 判断是否超时
{
DEBUG_OUT("tptimer=%d, timer=%d, gap=%d\r\n", tptimer, timer, tptimer - timer);
rslt = pCtrl->XmodemGetInBuffLen();
if (rslt > 0)
{
pCtrl->XmodemCleanBuff(); // 清除已经接收数据
xbuff[0] = XMODEM_NAK; // 回复 NAK需要重新传输该数据包
pCtrl->XmodemOutBuff(xbuff, 1);
DEBUG_OUT("resvlen = %d, send NAK\r\n", rslt);
}
else
{
DEBUG_OUT("not data, error\r\n");
err = -1; // 接收超时,退出
}
DEBUG_OUT("wait timeout\r\n");
break;
}
else
{
// 继续等待
}
}
}while(1);
}
else
{
DEBUG_OUT("err != 0 || recvsize == 0\r\n");
break;
}
if (err < 0)
{
DEBUG_OUT("err < 0 sanc cancel\r\n");
xbuff[0] = XMODEM_CAN; // 取消发送
pCtrl->XmodemOutBuff(xbuff, 1);
pCtrl->XmodemOutBuff(xbuff, 1);
pCtrl->XmodemOutBuff(xbuff, 1);
break;
}
} // end of for
return err;
}