#include "userapp.h" #include #include /******************************************************************************** * @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); Gpio_Init(PB, PIN1, GPIO_Mode_Out_PP) ; GPIO_WriteBit(GPIOC,PIN1,Bit_SET); Gpio_Init(PD, PIN10, GPIO_Mode_Out_PP) ; GPIO_WriteBit(GPIOD,PIN10,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个包开始,采用循环下载 { Wait_For_Nms(50) ; 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 ; }