stm32_ota/USER/USERAPP/userapp.c

385 lines
16 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 "userapp.h"
#include <string.h>
#include <stdlib.h>
/********************************************************************************
* @file userapp.c
* @author 晏诚科技 Mr.Wang
* @version V1.0.0
* @date 11-Dec-2018
* @brief 针对SmartGate应用程序对所有驱动进行封装
******************************************************************************
* @attention
* 所有对除USER层的封装都放在gateapp中
*******************************************************************************/
/*********应用层外部调用文件*******************************************************/
#include "usart.h" //printf
#include "watchdog.h"
#include "ec20module.h"
#include "ec20net.h"
#include "ec20tcp.h"
#include "ec20http.h" //RunResult Send_Post( POSTP_s *psHttpP, char* postBody )
#include "user_key.h"
#include "sysport.h"
#include "malloc.h"
#include "cjson.h"
#include "rtc.h"
#include "beep.h"
#include "led.h"
#include "logflash.h"
#include "syslib.h"
#include "user_oled.h"
#include "user_ftp.h"
#include "user_tcp.h"
#include "user_http.h"
#include "gate_timer.h"
#include "usercmd.h"
#include "logflash.h"
#include "io.h"
#include "pvd.h"
#include "oled.h"
#include "stm32Temp.h"
#include "iap.h"
/**********************************************************************************/
/**********************************************************************************
*内部使用的常变量
**********************************************************************************/
/**********************************************************************************
*供外部使用的常变量
***********************************************************************************/
Application gateApp ; //gateApp存放应用参数
DownFileP_s sDownApp ; //sDownApp存放下载文件的相关参数的结构体变量
NETSTATUS_s sNetStatus ; //NETSTATUS_s结构体类型变量反映网络状态
/**************************************************************************************************
* 名 称: void Board_Init(void)
* 功能说明: 驱动及功能块初始化
**************************************************************************************************/
void Board_Init(void)
{
SysTick_Init() ; //系统滴答定时器初始化 1ms中断一次 中断内部进行了喂狗操作
MyMenInit(SRAMIN) ; //动态内存分配初始化
// Watchdog_Init() ; //延时函数可用,即可开启硬件看门狗
// RTC_Init(INT_RANK_15) ; //实时时钟初始化
// PrintfDeviceInfo() ; //UART_DEBUG输出硬件信息
// Watchdog_Feed() ; //看门狗喂狗
Gpio_Init(PC, PIN8, GPIO_Mode_Out_PP) ;
GPIO_WriteBit(GPIOC,PIN8,Bit_SET);
//KeyInit() ; //初始化KEY按键
// Led_Init() ; //初始化LED
//Beep_Init() ; //初始化蜂鸣器
// OLED_Init() ; //OLED初始化
// RS232Init(115200) ; //RS232初始化
// RS485Init(115200) ; //RS485初始化
// Pvd_Init( EXTI_Trigger_Rising_Falling, INT_RANK_14) ;
// PWR_PVD_Init() ;
}
/**************************************************************************************************
* 名 称: RunResult FindAppFile(DownFileP_s *psFileParm)
* 功能说明: 在sFtpBoot.ftpDirectory目录中查找文件名为24位MAC地址+.bin/("CommonApp.bin")的文件函数将修改结构体变量中的fileName和eAppType
* 入口参数:
* @param1 *psFileParm DownFileP_s结构体指针
* 出口参数:
* @param1 RUNOK 在目录中能找到新的固件
* 说 明: ec20AtBuf[EC20_ATBUF_LEN] 320字节 所以当dir中文件名总字节数大于(EC20_ATBUF_LEN-50)时也会出现查找失败。
**************************************************************************************************/
RunResult NetDisconnetc(void)
{
RunResult result = RUNOK ;
if( TCPBIT_2 == true )
{
AppLogPrintf("BOOT断开TCP连接") ;
TcpDisconnetc() ; //断开Socket 去激活TCP链路的PDP
}
if( FTPBIT_4 == true )
{
AppLogPrintf("BOOT注销FTP登陆!") ;
result = AppFtpClose() ; //FTP注销
}
return result ;
}
/**************************************************************************************************
* 名 称: RunResult FindAppFile(DownFileP_s *psFileParm)
* 功能说明: 在sFtpBoot.ftpDirectory目录中查找文件名为24位MAC地址+.bin/("CommonApp.bin")的文件函数将修改结构体变量中的fileName和eAppType
* 入口参数:
* @param1 *psFileParm DownFileP_s结构体指针
* 出口参数:
* @param1 RUNOK 在目录中能找到新的固件
* 说 明: ec20AtBuf[EC20_ATBUF_LEN] 320字节 所以当dir中文件名总字节数大于(EC20_ATBUF_LEN-50)时也会出现查找失败。
**************************************************************************************************/
RunResult FindAppFile(DownFileP_s *psFileParm)
{
RunResult result = RUNERR ;
GetDeviceMacAddress(psFileParm->fileName, STRMACID) ;
strcat((char*)psFileParm->fileName, ".bin") ; //需要获取新固件文件名 文件名为24位MAC地址+.bin
if(RUNOK == Ftp_Find_File( sFtpBoot.ftpDirectory, psFileParm->fileName ) ) //在FTP服务器中查找唯一新固件文件名为24位MAC地址+.bin
{
psFileParm->eAppType = SelfApp ;
result = RUNOK ;
}
else //在FTP服务器中查找通用新固件文件名CommonApp.bin
{
memset(psFileParm->fileName, 0, MAC_BYTES_LEN+4+1) ; //清空下载文件的文件名
strcat((char*)psFileParm->fileName, "App.bin") ; //填充通用升级文件的文件名
//result= Ftp_Find_File( sFtpBoot.ftpDirectory, psFileParm->fileName ) ; //在FTP服务器中查找通用固件包文件名CommonApp.bin
if( kmp(ec20AtBuf, (char*)psFileParm->fileName) >= 0 )
{
psFileParm->eAppType = CommonApp ;
result = RUNOK ;
}
}
return (result) ;
}
/**************************************************************************************************
* 名 称: RunResult DownSubpackVerify(DownFileP_s *psFileParm, int *pHeadPos)
* 功能说明: 下载第一个子包然后进行固件合法性校验,函数将修改结构体变量中的appFlashAddr(校验方法BIN文件的前4个字节存放“栈顶地址”__initial_sp 所对应的就是堆栈的起始地址 这是编译器自动分配的“栈顶地址”)
* 入口参数:
* @param1 *psFileParm DownFileP_s结构体指针
* 出口参数:
* @param1 RUNOK 固件栈顶地址校验成功
* @param2 RUNERR 固件栈顶地址校验失败
* @param3 TIMEOUT 固件下载失败
* @param4 *pHeadPos 下载数据在ec20FtpBuf中的偏移地址
**************************************************************************************************/
RunResult DownSubpackVerify(DownFileP_s *psFileParm, int *pHeadPos)
{
RunResult result = RUNERR ;
*pHeadPos = Ftp_Down_File(psFileParm->fileName, 0, ONCE_DOWN_LEN) ; //下载第一个子包
if( *pHeadPos >= 0 ) /*下载数据成功*/
{
psFileParm->appFlashAddr = Check_AppNum(*(vu32*)((u32)&ec20FtpBuf[*pHeadPos+4])) ; //检查APP中的栈顶地址是否符合APP2\APP3
if( psFileParm->appFlashAddr != 0) // 固件校验合法
{
result = RUNOK ;
}
else //固件校验失败
{
result = RUNERR ;
}
}
else
{
result = TIMEOUT ;
}
return (result) ;
}
/**************************************************************************************************
* 名 称: RunResult DownOtherSubpack(DownFileP_s *psFileParm)
* 功能说明: 下载新固件除第一个subpack的其余sbupack并写入对应的FLASH段
* 入口参数:
* @param1 *psFileParm DownFileP_s结构体指针
* 出口参数:
* @param1 RUNOK 固件下载成功且写入FLASH成功
* @param2 RUNERR 固件下载时存在子包下载失败
* @param3 TIMEOUT 固件下载时存在子包写入FLASH失败
**************************************************************************************************/
RunResult DownOtherSubpack(DownFileP_s *psFileParm)
{
int headPos ;
for( psFileParm->subPackNum = 2; psFileParm->subPackNum <= psFileParm->subPackSum; psFileParm->subPackNum++ ) //从第2个包开始采用循环下载
{
OledPrintf(LINE_LEFT, HIGH_16, LINE4, false, "下载子包:%d", psFileParm->subPackNum ) ;
Data_Led_Reverse() ;
Wait_For_Nms(5) ;
uint16_t downLen = ONCE_DOWN_LEN ; //本次下载数据的长度
if( psFileParm->subPackNum == psFileParm->subPackSum ) /*下载最后一个包,下载数据长度需要重新计算*/
{
downLen = psFileParm->fileSize%ONCE_DOWN_LEN ; //最后一个包的数据长度
}
headPos = Ftp_Down_File(psFileParm->fileName, (psFileParm->subPackNum-1)*ONCE_DOWN_LEN, downLen) ; //下载文件
if( headPos >= 0 ) //子包下载成功
{
TcpUpdata( BOOTTOTCPFRAME, "子包:%d 。下载成功!", psFileParm->subPackNum) ;
if( RUNOK == Write_Flash(psFileParm->appFlashAddr+(psFileParm->subPackNum-1)*ONCE_DOWN_LEN, (uint8_t*)(ec20FtpBuf+headPos), downLen))
{
TcpUpdata( BOOTTOTCPFRAME, "子包:%d 。写入FLASH成功", psFileParm->subPackNum) ;
}
else //子包写FLASH失败
{
TcpUpdata( BOOTTOTCPFRAME, "子包:%d 。写入FLASH失败设备即将跳转到应急程序", psFileParm->subPackNum) ;
return TIMEOUT ;
}
}
else //子包下载失败
{
TcpUpdata( BOOTTOTCPFRAME, "子包:%d 。下载失败!设备即将跳转到应急程序!", psFileParm->subPackNum) ;
return RUNERR ;
}
}
return (RUNOK) ;
}
/**************************************************************************************************
* 名 称: uint32_t Check_AppNum( u32 appNumFlagWord )
* 功能说明: 检查下载的固件是否合法并且记录appNum
* 入口参数:
* @param1 appNum appNum号或者APP存放的FLASH首地址
* 出口参数:
* @param1 flagWord 返回固件应该写入FLASH的开始地址
* @arg APP2_AREA_ADDR: 下载的固件为APP2应该写入FLASH内的APP2_AREA_ADDR位置
* @arg APP3_AREA_ADDR: 下载的固件为APP3应该写入FLASH内的APP3_AREA_ADDR位置
* @arg 0: 固件不合法
**************************************************************************************************/
uint32_t Check_AppNum( u32 appNumFlagWord )
{
uint32_t flagWord = appNumFlagWord & 0xFFFF0000 ;
if(flagWord >= APP3_AREA_ADDR){
return APP3_AREA_ADDR ;
}
if(flagWord >= APP2_AREA_ADDR){
return APP2_AREA_ADDR ;
}
return 0;
/*
switch(flagWord)
{
case(APP2_AREA_ADDR & 0xFFFF0000):
return APP2_AREA_ADDR ;
case(APP3_AREA_ADDR & 0xFFFF0000):
return APP3_AREA_ADDR ;
default:
return 0 ;
}*/
}
/**************************************************************************************************
* 名 称: void Erase_App_Area(uint32_t appNum)
* 功能说明: 擦除APP1\APP2\APP3程序存储的FLASH区域
* 入口参数:
* @param1 appNum appNum号或者APP存放的FLASH首地址
**************************************************************************************************/
void Erase_App_Area(uint32_t appNum)
{
FLASH_Status eraseResult ;
uint8_t pageSum = 0, pageNum = 0 ;
FLASH_Unlock(); //Flash解锁
switch(appNum)
{
case 0x00000031: case APP1_AREA_ADDR:
{
// pageSum = APP1_AREA_SIZE/FLASH_PAGE_SIZE ; //计算出APP1_AREA_SIZE共计占用多少页
// while(pageSum--)
// {
// eraseResult = FLASH_ErasePage(APP1_AREA_ADDR+pageNum*FLASH_PAGE_SIZE) ;
// pageNum++ ;
// }
break ;
}
case 0x00000032: case APP2_AREA_ADDR:
{
pageSum = APP2_AREA_SIZE/FLASH_PAGE_SIZE ; //计算出APP1_AREA_SIZE共计占用多少页
while(pageSum--)
{
eraseResult = FLASH_ErasePage(APP2_AREA_ADDR+pageNum*FLASH_PAGE_SIZE) ;
pageNum++ ;
}
break ;
}
case 0x00000033: case APP3_AREA_ADDR:
{
pageSum = APP3_AREA_SIZE/FLASH_PAGE_SIZE ; //计算出APP1_AREA_SIZE共计占用多少页
while(pageSum--)
{
eraseResult = FLASH_ErasePage(APP3_AREA_ADDR+pageNum*FLASH_PAGE_SIZE) ;
pageNum++ ;
}
break ;
}
default:
{
break ;
}
}
FLASH_Lock(); //Flash上锁
}
/**************************************************************************************************
* 名 称: void PrintfDeviceInfo(void)
* 功能说明: DEBUG口输出信息
**************************************************************************************************/
void PrintfDeviceInfo(void)
{
printf("\r\n**************************************************************" ) ;
printf("\r\n版权归属 : 晏诚科技 2017/8-2027/8 .\
\r\n技术支持 : Mr. Wang 13635513618 .") ;
Query_AppVersion((char*)gateApp.bootVers) ;
//SetAppVersion(&gateApp, (char*)gateApp.bootVers) ;
printf("\r\nBoot版本 : %.*s",VERSION_LEN, gateApp.bootVers) ;
memset(uIapFlash.sIapFlash.BootVers, 0, VERSION_LEN+1) ;
strncpy((char*)uIapFlash.sIapFlash.BootVers, (const char*)gateApp.bootVers, VERSION_LEN ) ; //清除Boot版本并写入新的boot版本号
Set_uIapFlash(&uIapFlash) ; //保存版本号到FLASH中
GetDeviceMacAddress((uint8_t*)gateApp.macId, STRMACID) ;
printf("\r\n设备编号 : %.*s", MAC_BYTES_LEN, gateApp.macId) ;
DeviceRstReason((uint8_t*)gateApp.rstReason, VERSION_LEN) ;
printf("\r\n重启原因 : %.*s", VERSION_LEN, gateApp.rstReason) ;
printf("\r\n**************************************************************" ) ;
}
/**************************************************************************************************
* 名 称: void DeviceRstReason(uint8_t *reason, uint8_t maxLen)
* 功能说明: 判断硬件重启原因
**************************************************************************************************/
void DeviceRstReason(uint8_t *reason, uint8_t maxLen)
{
if( SET == RCC_GetFlagStatus( RCC_FLAG_PORRST) )
{
strncpy((char*)reason, "重上电启动", maxLen) ;
}
if( SET == RCC_GetFlagStatus(RCC_FLAG_SFTRST) )
{
strncpy((char*)reason, "软复位启动", maxLen) ;
}
if( SET == RCC_GetFlagStatus(RCC_FLAG_IWDGRST) )
{
strncpy((char*)reason, "独立看门狗启动", maxLen) ;
}
if( SET == RCC_GetFlagStatus(RCC_FLAG_WWDGRST) )
{
strncpy((char*)reason, "窗口看门狗启动", maxLen) ;
}
if( (RESET == RCC_GetFlagStatus(RCC_FLAG_SFTRST)) &&
(RESET == RCC_GetFlagStatus(RCC_FLAG_IWDGRST)) &&
(RESET == RCC_GetFlagStatus(RCC_FLAG_WWDGRST)) &&
(SET == RCC_GetFlagStatus(RCC_FLAG_PINRST))
)
{
strncpy((char*)reason, "硬复位启动", maxLen) ;
}
RCC_ClearFlag() ;
}
/**************************************************************************************************
* 名 称: void InitApplictationState(Application *appPointer)
* 功能说明: 对Application类型数据进行初始化
* 入口参数: @param *appPointer Application结构指针
*************************************************************************************************/
void InitApplictationState(Application *appPointer)
{
memset(appPointer->appVers, 0, VERSION_LEN+1) ;
memset(appPointer->bootVers, 0, VERSION_LEN+1) ;
memset(appPointer->macId, 0, MAC_BYTES_LEN+1) ;
}
void SetAppVersion(Application *appPointer, char *version)
{
strncpy((char*)appPointer->appVers, version, VERSION_LEN) ;
*(appPointer->appVers+VERSION_LEN+1) = 0 ;
}
void SetBootVersion(Application *appPointer, char *version)
{
strncpy((char*)appPointer->bootVers, version, VERSION_LEN) ;
*(appPointer->bootVers+VERSION_LEN+1) = 0 ;
}