stm32_ota/USER/main.c

292 lines
17 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include <string.h>
#include <stdio.h>
#include "usb.h"
#include "iap.h"
#include "sys.h"
#include "systick.h"
#include "usart.h"
#include "led.h"
#include "timer.h"
#include "sysport.h"
#include "mac.h"
#include "stm32Temp.h"
#include "watchdog.h"
#include "rtc.h"
#include "user_tcp.h"
#include "user_key.h"
#include "logflash.h"
#include "user_ftp.h"
#include "user_http.h"
#include "ec20module.h"
#include "ec20tcp.h"
#include "ec20http.h"
#include "userapp.h"
#include "user_flash.h"
#include "user_ftp.h"
#include "usercmd.h"
#include "user_oled.h"
/**********************************************************************************
*内部函数声明
**********************************************************************************/
RunResult NetTask(void) ; //网络初始化网络
int main(void)
{
RunResult result = RUNERR ; //函数运行状态变量
uint32_t appAddr = 0 ; //最终跳转的APP FLASH段首地址
InitIapFlashConfig(&uIapFlash) ; //读出FLASH中的Iap配置初始化共用体变量uIapFlash最后重新写入FLASH中
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4) ; //设置系统中断优先级分组4 无子优先级、0~15共计16个抢占优先级
InitApplictationState(&gateApp); //初始化结构体变量gateApp
UsbInit(9600) ; //调试串口、串口转USB口初始化
Board_Init() ; //硬件驱动初始化和功能块初始化
Watchdog_Feed() ; //看门狗喂狗
/*强制升级检测、开始变砖检测修复 ▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼*/
if( (uIapFlash.sIapFlash.JumpResult == 0x30) ) // 跳转失败或者按键操作进入恢复模式,则运行应急程序
{
DisplayInfo("执行应急程序") ;
goto SAVEAPPOUT ; //跳转到应急程序运行
}
else //跳转APP未出现失败设置标志位jumpResult为暂未跳转成功状
{
uIapFlash.sIapFlash.JumpResult = 0x30 ; //复位JumpResult标志位
Set_uIapFlash(&uIapFlash) ; //保存JumpResult
}
/*结束变砖检测修复、强制升级检测*/
/*开始检测是否需要升级APP(即判断IapFlag标志位)▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼*/
if(true == IS_IapFlag_ALL_PERIPH(uIapFlash.sIapFlash.IapFlag)) /*IapFlag合法*/ //IapFlag标志位合法性校验
{
if(uIapFlash.sIapFlash.IapFlag == 0x30 ) /*升级标志位为0, 说明不需要升级,直接跳转即可*/
{
AppLogPrintf("无需升级,即将执行APP%c .", uIapFlash.sIapFlash.RunAppNum) ;
goto APPNUMOUT ; //跳转到RunAppNum执行原先的程序
}
}
else /*IapFlag不合法*/
{
AppLogPrintf("IapFlag=%c,不合法,即将执行APP%c .", uIapFlash.sIapFlash.IapFlag, uIapFlash.sIapFlash.RunAppNum) ;
uIapFlash.sIapFlash.IapFlag = 0x30 ; //清除升级标志位
Set_uIapFlash(&uIapFlash) ; //保存升级标志位
goto APPNUMOUT ; //跳转到RunAppNum执行原先的程序
}
/*检测是否需要升级APP结束▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲*/
/*升级APP(连接TCP\FTP下载写入固件最后跳转APPP)开始▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼*/
//保存升级标志位
Watchdog_Feed() ; //看门狗喂狗
/*∧∧网络连接开始∧∧∧∧∧∧∧∧∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨*/
result = NetTask() ; //网络初始化
if(RUNERR == result) /*TCP\FTP初始化、连接失败 */
{
DisplayInfo("FTP连接失败") ;
TcpUpdata( BOOTTOTCPFRAME, "FTP初始化失败即将跳转RunAppNum: APP%c", uIapFlash.sIapFlash.RunAppNum) ;
Wait_For_Nms(20) ; //延时2S用于显示屏显示实际项目可以屏蔽延时
goto APPNUMOUT ; //跳转到RunAppNum执行原先的程序
}
/*∧∧网络连接结束∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧*/
/*∨∨查找新固件开始∨∨∨∨∨∨∨∧∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨*/
TcpUpdata( BOOTTOTCPFRAME, "FTP初始化成功即将开始升级") ;
Watchdog_Feed() ; //看门狗喂狗
result = FindAppFile(&sDownApp) ; //查找新固件
if(RUNERR == result) /*未找到新固件*/
{
TcpUpdata( BOOTTOTCPFRAME, "未搜索到新固件即将跳转RunAppNum: APP%c", uIapFlash.sIapFlash.RunAppNum) ;
Wait_For_Nms(200) ; //延时2S用于显示屏显示实际项目可以屏蔽延时
goto APPNUMOUT ; //跳转到RunAppNum执行原先的程序
}
/*∧∧查找新固件结束∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧*/
/*∨∨获取新固件文件大小开始∨∨∨∨∨∨∨∧∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨*/
sDownApp.fileSize = Ftp_Get_FileSize( sDownApp.fileName ) ; //获取新固件文件的大小
if(sDownApp.fileSize <= 0) /*获取文件大小失败*/
{
TcpUpdata( BOOTTOTCPFRAME, "获取新固件大小失败即将跳转RunAppNum: APP%c", uIapFlash.sIapFlash.RunAppNum) ;
goto APPNUMOUT ; //跳转到RunAppNum执行原先的程序
}
sDownApp.subPackSum = sDownApp.fileSize/ONCE_DOWN_LEN ;
if(sDownApp.fileSize%ONCE_DOWN_LEN > 0)
sDownApp.subPackSum = sDownApp.subPackSum + 1 ; //计算固件subPackSum
TcpUpdata( BOOTTOTCPFRAME, "新固件包大小 %d bytes ; 拆分子包数目: %d 。",sDownApp.fileSize, sDownApp.subPackSum) ;
/*∧∧获取新固件文件大小结束∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧*/
/*∨∨新固件合法性校验开始∨∨∨∨∨∨∨∧∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨*/
int headPos = -1 ;
result = DownSubpackVerify(&sDownApp, &headPos) ; //下载第一个subpack并进行固件合法性校验
if(RUNERR == result) /*固件校验不合法”*/
{
TcpUpdata( BOOTTOTCPFRAME, "新固件栈顶地址校验失败!") ;
// char *newName = (char*)portMalloc(MAC_BYTES_LEN*2) ;
// strncat( (char*)newName, (const char*)sDownApp.fileName, 2) ;
// strncat( (char*)newName, "(BinErr)", 8) ;
// strncat( (char*)newName, (const char*)&sDownApp.fileName[2], 26) ;
// Wait_For_Nms(2000) ; //延时2S用于修改文件名实测发现在下载完数据后立即更名会返回+CME ERROR: 603错误
// Ftp_File_Rename( sDownApp.fileName , (uint8_t *)newName ) ; //对不合法的固件进行重名了, 防止二次升级
// portFree(newName) ;
goto APPNUMOUT ; // 跳转到RunAppNum执行原先的程序
}
else if(TIMEOUT == result) /*固件校验失败*/
{
TcpUpdata( BOOTTOTCPFRAME, "新固件栈顶地址校验超时!") ;
Wait_For_Nms(50) ; //延时2S用于显示屏显示实际项目可以屏蔽延时
goto APPNUMOUT ; // 跳转到RunAppNum执行原先的程序
}
/*∧∧新固件合法性校验结束∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧*/
Erase_App_Area(sDownApp.appFlashAddr) ; //擦除相应代码段准备将新的代码写入FLASH此时该APP段已经不可用了如果后续出现下载/写入FLASH错误需要跳转到应急程序
TcpUpdata( BOOTTOTCPFRAME, "子包1 。下载成功!") ;
if( RUNOK == Write_Flash(sDownApp.appFlashAddr, (uint8_t*)(ec20FtpBuf+headPos), ONCE_DOWN_LEN)) /*写FLASH成功*///将上一步下载的subpack1写入falsh中
{
TcpUpdata( BOOTTOTCPFRAME, "子包1 。写入FLASH成功") ;
}
else /*subpack1写入FLASH失败*/
{
TcpUpdata( BOOTTOTCPFRAME, "子包1 。写入FLASH失败设备即将跳转到应急程序") ;
goto SAVEAPPOUT ; //跳转到应急程序
}
result = DownOtherSubpack(&sDownApp) ; //下载其余的subpack
if( RUNOK != result ) //余下subpack下载失败
{
Erase_App_Area(sDownApp.appFlashAddr) ; //固件写入FLSHA失败此APP段已经作废防止程序异常需要清除FLASH段
Wait_For_Nms(50) ; //延时2S用于显示屏显示实际项目可以屏蔽延时
goto SAVEAPPOUT ; //跳转应急程序
}
else /*余下所有subpack固件下载成功且写入flash成功*/
{
// if( sDownApp.eAppType == SelfApp) /*硬件独有的APP文件升级成功修改文件名*/
// {
// char *newName = (char*)portMalloc(MAC_BYTES_LEN*2) ;
// strncat( (char*)newName, (const char*)sDownApp.fileName, 2) ;
// strncat( (char*)newName, "(BinOk)", 8) ;
// strncat( (char*)newName, (const char*)&sDownApp.fileName[2], 26) ;
// Wait_For_Nms(2000) ; //延时2S用于显示屏显示实际项目可以屏蔽延时
// Ftp_File_Rename( sDownApp.fileName , (uint8_t *)newName ) ;//对已经升级成功的固件进行重名了, 防止二次升级
// portFree(newName) ;
// }
goto NEWAPPOUT ; //跳转到最新下载的固件的栈顶地址运行APP
}
/*∧∧下载新固件并写FLASH 结束∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧*/
APPNUMOUT:
appAddr = QueryNewAppArea(0x32); //校验固件合法性、获取跳转的FLASH存放区域首地址
// appAddr = QueryNewAppArea((u32)uIapFlash.sIapFlash.RunAppNum); //校验固件合法性、获取跳转的FLASH存放区域首地址
NetDisconnetc() ; //断开网络连接注销FTP登陆
Iap_Load_App(appAddr) ; //执行APP不会再往下执行了
NEWAPPOUT:
uIapFlash.sIapFlash.IapFlag = 0x32 ; //清除升级标志位
Set_uIapFlash(&uIapFlash) ;
appAddr = QueryNewAppArea(sDownApp.appFlashAddr); //校验固件合法性、获取跳转的FLASH存放区域首地址
NetDisconnetc() ; //断开网络连接注销FTP登陆
Iap_Load_App(appAddr) ; //执行APP不会再往下执行了
SAVEAPPOUT:
appAddr = QueryNewAppArea(SAVEAPP_AREA_ADDR); //校验固件合法性、获取跳转的FLASH存放区域首地址
NetDisconnetc() ; //断开网络连接注销FTP登陆
Iap_Load_App(SAVEAPP_AREA_ADDR) ; //执行APP不会再往下执行了
DisplayTitle("设备故障:") ;
DisplayInfo("请联系厂家") ;
Wait_For_Nms(50) ; //理论上程序不可能执行到此处
SystemSoftReset() ; //软重启
}
RunResult NetTask(void)
{
RunResult runResult = TIMEOUT ; //RunResult类型变量存储函数执行结果
int tryTimes = 2 ; //网络连接重试次数
while( tryTimes >= 0 ) //重试条件成立
{
tryTimes-- ;
if( MODULEBIT_0 == false ) /*EC20没有module初始化成功则执行*/
{
runResult = EC20_Module_Init() ; //需要保证串口通信正常且关闭模块串口ECHO成功
if( RUNOK == runResult) /*模块UART \gpio\POW\ECHO\RELESE皆无异常*/
{
MODULEBIT_0 = true ; //修改MODULEBIT_0状态标志位
AppLogPrintf("握手成功") ;
}
else /*EC20_Module_Init初始化失败不做异常处理该任务会一直运行EC20_Module_Init()*/
{
AppLogPrintf("握手失败") ;
}
}
if( (MODULEBIT_0 == true) &&
(NETREGBIT_1 == false) ) //EC20module初始化完成且CSPS初始化未完成则进行CS、PS初始化
{
char *errInfo = portMalloc(30) ;
runResult = EC20_Net_Reg(errInfo, 30) ; //连接运营商核心网即CS SERVER、PS SERVER
if( RUNOK == runResult) /*EC20_Net_RegSIM/CS/PS皆无异常*/
{
NETREGBIT_1 = true ; //修改NETREGBIT_1状态标志位
}
else /*1、EC20_Net_Reg异常需要重新进行EC20_Module_Init; 2、模块关机*/
{
MODULEBIT_0 = false ; //设置MODULEBIT_0状态位为失败
EC20_CLOSE() ; //EC20关机
}
AppLogPrintf(errInfo) ; //提示错误请插入SIM卡、SIM欠费、CSQ
portFree(errInfo) ;
}
if( (MODULEBIT_0 == true) &&
(NETREGBIT_1 == true) &&
(TCPBIT_2 == false) ) /*EC20module、EC20_Net_Reg初始化都完成则进行AppTcpInit初始化*/
{
runResult = AppTcpInit() ; //TCP PDP初始化 SOCKET连接
if( RUNOK == runResult) /*TCP连接成功*/
{
TCPBIT_2 =true ; //设置TCP网络状态标志位TCPBIT_2 STATE_OK
TcpUpdata( BOOTTOTCPFRAME, "Device tcp connetced!") ; //上传TCP数据更新服务器硬件客户端列表
AppLogPrintf("TCP连接成功") ;
}
else /*TCP连接失败不影响主业务逻辑所以TCP异常只做重新初始化不做异常处理*/
{
TCPBIT_2 = false ; //设置TCP网络状态标志位 STATE_ERR
AppLogPrintf("TCP连接失败") ;
}
}
if( (MODULEBIT_0 == true) &&
(NETREGBIT_1 == true) &&
(FTPBIT_4 == false) ) /*EC20module、EC20_Net_Reg初始化都完成则进行AppFtpInit初始化*/
{
DisplayTitle("连接FTP服务器:") ;
runResult = AppFtpInit() ; //FTP初始化
if( RUNOK == runResult) //FTP连接成功
{
FTPBIT_4 =true ; //设置FTP网络状态标志位FTPBIT_4 STATE_OK
AppLogPrintf("FTP连接成功") ;
break ;
}
else
{
FTPBIT_4 = false ; //设置FTP网络状态标志位 STATE_ERR
AppLogPrintf("FTP连接失败") ;
}
}
}
if( (MODULEBIT_0 == true) &&
(NETREGBIT_1 == true) &&
(FTPBIT_4 == true ) ) /*EC20module、EC20_Net_Reg、AppFtpInit全部初始化成功TCP只用于上传日志AppTcpInit初始化失败不影响升级*/
{
runResult = RUNOK ;
EC20_Query_CSQ(sEc20Param.csq) ; //获取CSQ的值
EC20_Query_Voltage(sEc20Param.ec20Voltage) ; //获取EC20电压值
// DisplayStatusBar() ; //状态栏显示信号质量和电压
}
else /*网络初始化存在异常*/
{
runResult = RUNERR ;
}
return (runResult) ;
}