int main(void)
{
bool isJumpToApp=true;
YmodemSohPackage *ymodemSohPack = (YmodemSohPackage *)&rs485RecData.recDataBuf;//SOH包结构
YmodemStxPackage *ymodemStxPack = (YmodemStxPackage *)&rs485RecData.recDataBuf;//STX包结构
ProgUpdateProcessE progUpdateProcess=waitStartVerInfo; //程序更新流程
CommitAgree commitProtoco=noAgree; //通信协议
u16 rs485RecCntVal=0; //485接收到的数据
u8 versionStrBuf[10]; //旧版本
u8 sizeStrBuf[10]; //程序大小
u8 md5StrBuf[34]; //MD5值
u32 programTotalSize; //程序大小
u8 failCnt=0; //失败计数
char buf[200]; //临时缓冲器
FRESULT fileRes=FR_OK; //文件操作结果
static FIL file; //文件
bool isAck=true; //是否应答ACK
u8 packNumCnt;
u32 br; //程序移动指针
u32 updatingProgSize;//程序读取字节
u32 progWriteAddr; //写MCU程序地址
u8 readProgBuf[2048];//读取存储BUF
if(get_update_key())//检测是否强制更新程序
{
MSG_OUT("开始更新程序");
isJumpToApp=false;
}
while(1)
{
if(isJumpToApp)//跳转到Application程序
{
if (strcmp((char *)sysParaSave.oldVersion, (char *)sysParaSave.newVersion) == 0)//程序有效
{
//执行跳转
MSG_OUT("程序无需更新,直接跳转");
__disable_irq(); //关闭所有中断
iap_load_app(SAVE_PROGRAM_ADDR);//执行FLASH APP代码
}
else
{
isJumpToApp=false;
}
}
else
{
switch(progUpdateProcess)
{
case waitStartVerInfo: //等待起始校验消息,确定协议
{
rs485RecCntVal = wait_rec_data(1000);
if(rs485RecCntVal!=0)
{
if(strstr(rs485RecData.recDataBuf,"ymodem")!=NULL)//查找协议
{
commitProtoco=ymodem;
}
if(strstr(rs485RecData.recDataBuf,COMMIT_PASSWORD)!=NULL)//验证密码
{
if(commitProtoco!=noAgree)//通信协议和密码都合适
{
MSG_OUT("包头提取成功");
progUpdateProcess=getProgInfoPack;//执行获去信息包
}
}
}
}break;
case getProgInfoPack: //获去信息包
{
switch(commitProtoco)
{
case ymodem:
{
ymodem_answer_c();
rs485RecCntVal = wait_rec_data(1000);
if(rs485RecCntVal!=0) //接收到了数据
{
//校验数据是否合适
if(ymodemSohPack->packHead==ymodem_soh&&\
ymodemSohPack->ymodemPackNum==(u8)(~ymodemSohPack->ymodemPackNumNegation)&&\
ymodem_crc16_cal(ymodemSohPack->ymodemData, sizeof(ymodemSohPack->ymodemData))\
==(ymodemSohPack->ymodemCrcH*256+ymodemSohPack->ymodemCrcL))
{
memset(versionStrBuf,0x00,sizeof(versionStrBuf));
memset(sizeStrBuf,0x00,sizeof(sizeStrBuf));
memset(md5StrBuf,0x00,sizeof(md5StrBuf));
programTotalSize=0;
//获取字符串
if(copy_between_characters((char *)&ymodemSohPack->ymodemData,(char *)&versionStrBuf,"$","@")&&\
copy_between_characters((char *)&ymodemSohPack->ymodemData,(char *)&sizeStrBuf,"@","&")&&\
copy_between_characters((char *)&ymodemSohPack->ymodemData,(char *)&md5StrBuf,"&","#"))//获取版本
{
if(strcmp((char *)&versionStrBuf,(char *)sysParaSave.oldVersion)==0)//版本一样
{
MSG_OUT("运行程序与当前更新程序为同一个文件");
failCnt=0;
ymodem_cancel_transport();//停止ymodem传输
progUpdateProcess=jumpToAppProg;//直接跳转运行
}
else
{
programTotalSize = atol((char *)sizeStrBuf);
MSG_OUT("文件信息获取成功");
failCnt=0;
progUpdateProcess=progFileDeal;//文件处理
}
}
else
{
failCnt++;
if(failCnt>=5)
{
failCnt=0;
MSG_OUT("文件信息获取失败");
ymodem_cancel_transport();//停止ymodem传输
while(1);
}
}
}
else
{
failCnt++;
if(failCnt>=5)
{
failCnt=0;
MSG_OUT("文件信息数据校验失败");
ymodem_cancel_transport();//停止ymodem传输
while(1);
}
}
}
else
{
failCnt++;
if(failCnt>=5)
{
failCnt=0;
MSG_OUT("文件信息数据获取失败");
ymodem_cancel_transport();//停止ymodem传输
while(1);
}
}
}break;
}
}break;
case progFileDeal: //程序处理
{
//删除旧文件
memset(buf,0x00,sizeof(buf));
sprintf(buf,"%s%s%s%s",PROG_PATH,"/",sysParaSave.oldVersion,".bin");
fileRes = f_unlink(buf);
if(fileRes!=FR_OK&&fileRes!=FR_NO_PATH)
{
MSG_OUT("旧文件删除失败");
ymodem_cancel_transport();//停止ymodem传输
while(1);
}
//新建根目录
fileRes=f_mkdir(PROG_PATH); //新建程序根目录
if(fileRes!=FR_OK&&fileRes!=FR_EXIST) //文件打开失败
{
MSG_OUT("程序根目录新建失败");
ymodem_cancel_transport();//停止ymodem传输
while(1);
}
//新建文件并打开
memset(buf,0x00,sizeof(buf));
sprintf(buf,"%s%s%s%s",PROG_PATH,"/",versionStrBuf,".bin");
fileRes=f_open(&file,buf,FA_CREATE_NEW|FA_WRITE); //新建文件并打开
if(fileRes!=FR_OK)
{
MSG_OUT("打开新文件失败");
ymodem_cancel_transport();//停止ymodem传输
while(1);
}
progUpdateProcess=downloadAndSaveProg;//开始下载程序
isAck=true;
packNumCnt=1; //从1开始计数
failCnt=0;
br=0;
}break;
case downloadAndSaveProg: //下载并保存程序
{
switch(commitProtoco)
{
case ymodem:
{
if(isAck)//应答ACK
ymodem_answer_ack();
else
ymodem_answer_nak();
rs485RecCntVal = wait_rec_data(1000);
if(rs485RecCntVal<5)//有可能是结束信号
{
if(ymodemStxPack->packHead==YMODEM_EOT)//结束信号
{
ymodem_answer_nak();
rs485RecCntVal = wait_rec_data(1000);
ymodem_answer_ack();
ymodem_answer_c();
delay_ms(200);
packNumCnt=0;//结束包号是0
isAck=true;
}
}
else if(ymodemStxPack->packHead==ymodem_soh)//128字节包
{
if(ymodemSohPack->ymodemPackNum==(u8)(~ymodemSohPack->ymodemPackNumNegation)&&\
ymodem_crc16_cal(ymodemSohPack->ymodemData, sizeof(ymodemSohPack->ymodemData))\
==(ymodemSohPack->ymodemCrcH*256+ymodemSohPack->ymodemCrcL)&&
ymodemSohPack->ymodemPackNum==packNumCnt)
{
if(ymodemSohPack->ymodemPackNum!=0x00)//不是结束包
{
//读取成功了
fileRes=f_write (&file, ymodemSohPack->ymodemData,sizeof(ymodemSohPack->ymodemData), &br); //写入文件
if(fileRes==FR_OK)
{
MSG_OUT("写入成功");
packNumCnt++;
isAck=true; //应答、发送下一包
failCnt=0;
}
else
{
isAck=false;//非应答、重新发送此包
failCnt++;
if(failCnt>=5)
{
failCnt=0;
MSG_OUT("文件写入失败");
ymodem_cancel_transport();//停止ymodem传输
while(1);
}
}
}
else//是结束包
{
MSG_OUT("成功收到应答包");
f_close (&file);//关闭文件
progUpdateProcess = verifyDownloadProg;
}
}
else
{
isAck=false;//非应答、重新发送此包
failCnt++;
if(failCnt>=5)
{
failCnt=0;
MSG_OUT("文件写入失败");
ymodem_cancel_transport();//停止ymodem传输
while(1);
}
}
}
else//1024 STX包
{
if(ymodemStxPack->ymodemPackNum==(u8)(~ymodemStxPack->ymodemPackNumNegation)&&\
ymodem_crc16_cal(ymodemStxPack->ymodemData, sizeof(ymodemStxPack->ymodemData))\
==(ymodemStxPack->ymodemCrcH*256+ymodemStxPack->ymodemCrcL)&&\
ymodemStxPack->ymodemPackNum==packNumCnt)
{
//读取成功了
fileRes=f_write (&file, ymodemStxPack->ymodemData,sizeof(ymodemStxPack->ymodemData), &br); //写入文件
if(fileRes==FR_OK)
{
MSG_OUT("写入成功");
packNumCnt++;
isAck=true; //应答、发送下一包
failCnt=0;
}
else
{
isAck=false;//非应答、重新发送此包
failCnt++;
if(failCnt>=5)
{
failCnt=0;
MSG_OUT("文件写入失败");
ymodem_cancel_transport();//停止ymodem传输
while(1);
}
}
}
else
{
isAck=false;//非应答、重新发送此包
failCnt++;
if(failCnt>=5)
{
failCnt=0;
MSG_OUT("文件写入失败");
ymodem_cancel_transport();//停止ymodem传输
while(1);
}
}
}
}break;
}
}break;
case verifyDownloadProg: //校验下载下来的程序
{
fileRes=f_open(&file,buf,FA_READ); //打开新文件
if(fileRes!=FR_OK)
{
MSG_OUT("校验文件打开失败");
while(1);
}
MSG_OUT("校验文件打开成功");
if(file.fsize<programTotalSize)
{
MSG_OUT("文件尺寸校验失败");
f_close(&file);
while(1);
}
MSG_OUT("文件尺寸校验成功");
progUpdateProcess=carryProgToMcu;
}break;
case carryProgToMcu: //搬运程序进入MCU
{
MSG_OUT("开始更新程序");
updatingProgSize=programTotalSize;//程序读取字节
progWriteAddr=SAVE_PROGRAM_ADDR; //程序写入MCU地址
__disable_irq(); //关闭所有中断
while(1)//开始读取
{
memset(buf,0x00,sizeof(buf));
sprintf(buf,"程序已更新: %d/%d",(programTotalSize-updatingProgSize),programTotalSize);
MSG_OUT(buf);
if(updatingProgSize==0) //程序复制完成
{
MSG_OUT("程序更新完成");
progUpdateProcess=verifyMcuProg;//执行校验程序
f_close (&file);
break;
}
if(updatingProgSize<2048)
{
if(f_read (&file, &readProgBuf,updatingProgSize, &br)==FR_OK) //读取文件
{
iap_write_appbin(progWriteAddr,readProgBuf,updatingProgSize); //更新FLASH代码
updatingProgSize=0;
}
else
{
MSG_OUT("程序文件读取失败!");
f_close (&file);
while(1);
}
}
else
{
if(f_read (&file, &readProgBuf,2048, &br)==FR_OK) //读取文件
{
iap_write_appbin(progWriteAddr,readProgBuf,2048); //更新FLASH代码
updatingProgSize-=2048;
progWriteAddr+=2048;
}
else
{
MSG_OUT("程序文件读取失败!");
f_close (&file);
while(1);
}
}
}
__enable_irq(); //关闭所有中断
}break;
case verifyMcuProg: //校验搬运进入MCU的程序
{
MSG_OUT("开始MD5校验程序");
memset(buf,0x00,sizeof(buf));
get_bin_md5(SAVE_PROGRAM_ADDR,programTotalSize,buf); //MD5校验程序文件
if(strcmp((char *)md5StrBuf,buf)!=0)
{
MSG_OUT("程序MD5校验失败");
while(1);
}
MSG_OUT("MD5校验程序成功");
progUpdateProcess=recordProgInfo;//记录程序信息
}break;
case recordProgInfo: //记录程序信息
{
MSG_OUT("开始记录数据");
memset(sysParaSave.oldVersion,0x00,sizeof(sysParaSave.oldVersion));
memset(sysParaSave.newVersion,0x00,sizeof(sysParaSave.newVersion));
memset(sysParaSave.md5Val,0x00,sizeof(sysParaSave.md5Val));
memcpy(sysParaSave.oldVersion,versionStrBuf,sizeof(versionStrBuf)); //程序版本
memcpy(sysParaSave.newVersion,versionStrBuf,sizeof(versionStrBuf)); //程序版本
memcpy(sysParaSave.md5Val,md5StrBuf,sizeof(md5StrBuf)); //MD5
sysParaSave.programSize = programTotalSize; //程序大小
if(sys_data_save()!=true)
{
MSG_OUT("数据保存失败");
while(1);
}
MSG_OUT("数据保存成功");
progUpdateProcess=jumpToAppProg;//执行跳转程序
}break;
case jumpToAppProg: //跳转到应用程序
{
MSG_OUT("执行跳转");
__disable_irq(); //关闭所有中断
iap_load_app(SAVE_PROGRAM_ADDR);//执行FLASH APP代码
}break;
}
}
}
}
|