368 lines
6.3 KiB
C
368 lines
6.3 KiB
C
|
||
#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;
|
||
}
|
||
|
||
|