/******************************************************************************* * File Name : OTA.c * Description : * Created on : 2020Äê9ÔÂ13ÈÕ * Author : www.hido-studio.com *******************************************************************************/ /******************************************************************************* * Include Files * *******************************************************************************/ #include "string.h" #include "HIDO_TypeDef.h" #include "HIDO_Timer.h" #include "OTA.h" #include "HIDO_Debug.h" #include "HIDO_Timer.h" #include "HIDO_Util.h" #include "HTTPClient.h" #include "SPIFlash.h" #include "APPConfig.h" #include "Flash.h" #include "Internet.h" /******************************************************************************* * Macro * *******************************************************************************/ #define MAX_REQUEST_SIZE (30 * 1024) /******************************************************************************* * Type Definition * *******************************************************************************/ typedef enum { OTA_STATE_IDLE, OTA_STATE_HTTP_REQUEST_FILE_LEN, OTA_STATE_HTTP_REQUEST_DATA, OTA_STATE_WAIT_HTTP_RESPONSE, }E_OTAState; /******************************************************************************* * Local Variable * *******************************************************************************/ static HIDO_CHAR l_acOTAUrl[128]; static HIDO_UINT32 l_u32OTATimerID = 0; static E_OTAState l_eOTAState = OTA_STATE_IDLE; static HIDO_UINT32 l_u32OTARetryCnt = 0; static HIDO_UINT32 l_u32OTAFileRecvLen = 0; static HIDO_UINT32 l_u32OTAFileSize = 0; /******************************************************************************* * Local Function Declaration * *******************************************************************************/ static HIDO_VOID OTA_TimerCallBack(HIDO_VOID *_pArg); static HIDO_INT32 OTA_HTTPGetFileCallBack(HIDO_UINT32 _u32RespCode, ST_HTTPGetFileResponse *_pstResponse, HIDO_UINT8 *_pu8Data, HIDO_UINT32 _u32Len, HIDO_VOID *_pArg); /******************************************************************************* * Local Function * *******************************************************************************/ /******************************************************************************* * Function Name : OTA_RequestFileLen * Description : * Input : * Output : * Return : * Author : www.hido-studio.com * Modified Date: : 2020Äê9ÔÂ13ÈÕ *******************************************************************************/ static HIDO_INT32 OTA_RequestFileLen(HIDO_VOID) { ST_HTTPGetFileOpt stFileOpt; memset(&stFileOpt, 0, sizeof(stFileOpt)); stFileOpt.m_u32RangeBegin = 0; stFileOpt.m_u32RangeEnd = 0; if (HTTPClient_GetFile(l_acOTAUrl, OTA_HTTPGetFileCallBack, &stFileOpt, HIDO_NULL) != HIDO_OK) { return HIDO_ERR; } return HIDO_OK; } /******************************************************************************* * Function Name : OTA_RequestFileData * Description : * Input : * Output : * Return : * Author : www.hido-studio.com * Modified Date: : 2020Äê9ÔÂ13ÈÕ *******************************************************************************/ static HIDO_INT32 OTA_RequestFileData(HIDO_UINT32 _u32Offset) { ST_HTTPGetFileOpt stFileOpt; memset(&stFileOpt, 0, sizeof(stFileOpt)); stFileOpt.m_u32RangeBegin = _u32Offset; if ((l_u32OTAFileSize - l_u32OTAFileRecvLen) < MAX_REQUEST_SIZE) { stFileOpt.m_u32RangeEnd = _u32Offset + l_u32OTAFileSize - l_u32OTAFileRecvLen - 1; } else { stFileOpt.m_u32RangeEnd = _u32Offset + MAX_REQUEST_SIZE - 1; } if(HTTPClient_GetFile(l_acOTAUrl, OTA_HTTPGetFileCallBack, &stFileOpt, HIDO_NULL) != HIDO_OK) { return HIDO_ERR; } return HIDO_OK; } /******************************************************************************* * Function Name : OTA_HTTPGetFileCallBack * Description : * Input : * Output : * Return : * Author : www.hido-studio.com * Modified Date: : 2020Äê9ÔÂ13ÈÕ *******************************************************************************/ static HIDO_INT32 OTA_HTTPGetFileCallBack(HIDO_UINT32 _u32RespCode, ST_HTTPGetFileResponse *_pstResponse, HIDO_UINT8 *_pu8Data, HIDO_UINT32 _u32Len, HIDO_VOID *_pArg) { if (200 == _u32RespCode) { HIDO_Debug("HTTPGetFileCallBack:200\r\n"); } else if (206 == _u32RespCode) { switch (l_eOTAState) { case OTA_STATE_HTTP_REQUEST_FILE_LEN: { l_u32OTAFileRecvLen = 0; l_u32OTAFileSize = _pstResponse->m_u32RangeTotal; if(0 == l_u32OTAFileSize) { HIDO_Debug("OTAFileSize error\r\n"); } HIDO_Debug("OTAFileSize %u\r\n", l_u32OTAFileSize); l_eOTAState = OTA_STATE_HTTP_REQUEST_DATA; OTA_RequestFileData(l_u32OTAFileRecvLen); HIDO_TimerStart(l_u32OTATimerID, HIDO_TIMER_TYPE_ONCE, HIDO_TIMER_TICK_S(30), OTA_TimerCallBack, HIDO_NULL); break; } case OTA_STATE_HTTP_REQUEST_DATA: { if(_pstResponse->m_u32RangeBegin != l_u32OTAFileRecvLen) { break; } /* дÈëÎļþ */ SPIFlash_Write(SPI_FLASH_ID_0, APP_CONFIG_APP_DOWN_LOAD_SPIFLASH_ADDRESS + l_u32OTAFileRecvLen, _pu8Data, _u32Len); l_u32OTAFileRecvLen += _u32Len; HIDO_Debug("OTAFileDownload %u/%u\r\n", l_u32OTAFileRecvLen, l_u32OTAFileSize); /* Îļþ½ÓÊÕÍê³É */ if (l_u32OTAFileRecvLen == l_u32OTAFileSize) { l_eOTAState = OTA_STATE_IDLE; HIDO_TimerCancel(l_u32OTATimerID); HIDO_UINT16 tmp = 0xBBBB,result; SPIFlash_Erase(SPI_FLASH_ID_0, APP_CONFIG_IAPFLAG_MAP,2, SPI_FLASH_SECTOR_ERASE_MODE_4K); SPIFlash_Write(SPI_FLASH_ID_0, APP_CONFIG_IAPFLAG_MAP, (HIDO_UINT8*)&tmp, sizeof(tmp)); HAL_Delay(10); Reboot(0); break; } OTA_RequestFileData(l_u32OTAFileRecvLen); HIDO_TimerStart(l_u32OTATimerID, HIDO_TIMER_TYPE_ONCE, HIDO_TIMER_TICK_S(30), OTA_TimerCallBack, HIDO_NULL); break; } default: { break; } } } else { // l_eOTAState = OTA_STATE_IDLE; /* ÇëÇóʧ°Ü */ } return HIDO_OK; } /******************************************************************************* * Function Name : OTA_Failed * Description : * Input : * Output : * Return : * Author : www.hido-studio.com * Modified Date: : 2020Äê9ÔÂ13ÈÕ *******************************************************************************/ static HIDO_INT32 OTA_Failed(void) { /* Éý¼¶²ÎÊýÓÐÎó£¬È¡ÏûÉý¼¶ */ HIDO_UINT16 tmp = 0xFFFF; HIDO_Debug("goto app application\r\n"); SPIFlash_Erase(SPI_FLASH_ID_0, APP_CONFIG_IAPFLAG_MAP, 2, SPI_FLASH_SECTOR_ERASE_MODE_4K); SPIFlash_Write(SPI_FLASH_ID_0, APP_CONFIG_IAPFLAG_MAP, (HIDO_UINT8*)&tmp, sizeof(tmp)); SPIFlash_Erase(SPI_FLASH_ID_0, APP_CONFIG_IAP_PARAM_MAP, 256, SPI_FLASH_SECTOR_ERASE_MODE_4K); delay_ms(10); Reboot(0); return HIDO_OK; } /******************************************************************************* * Function Name : OTA_TimerCallBack * Description : OTA¶¨Ê±Æ÷³¬Ê±»Øµ÷ * Input : ¶¨Ê±Æ÷²ÎÊý * Output : * Return : * Author : www.hido-studio.com * Modified Date: : 2020Äê9ÔÂ13ÈÕ *******************************************************************************/ static HIDO_VOID OTA_TimerCallBack(HIDO_VOID *_pArg) { HIDO_Debug("l_eOTAState = %u @%s\r\n", l_eOTAState, __FUNCTION__); switch (l_eOTAState) { case OTA_STATE_HTTP_REQUEST_FILE_LEN: { l_u32OTARetryCnt++; if(l_u32OTARetryCnt >= 3) { OTA_Failed(); } OTA_RequestFileLen(); HIDO_TimerStart(l_u32OTATimerID, HIDO_TIMER_TYPE_ONCE, HIDO_TIMER_TICK_S(30), OTA_TimerCallBack, HIDO_NULL); break; } case OTA_STATE_HTTP_REQUEST_DATA: { l_u32OTARetryCnt++; if(l_u32OTARetryCnt >= 3) { OTA_Failed(); } OTA_RequestFileData(l_u32OTAFileRecvLen); HIDO_TimerStart(l_u32OTATimerID, HIDO_TIMER_TYPE_ONCE, HIDO_TIMER_TICK_S(30), OTA_TimerCallBack, HIDO_NULL); break; } default: { break; } } } /******************************************************************************* * Global Function * *******************************************************************************/ /******************************************************************************* * Function Name : OTA_SetUp * Description : OTAÆô¶¯ * Input : _pcUrl OTAÉý¼¶Îļþ·¾¶ * Output : None * Return : HIDO_OK ³É¹¦,HIDO_ERR ʧ°Ü * Author : www.hido-studio.com * Modified Date: : 2020Äê9ÔÂ13ÈÕ *******************************************************************************/ HIDO_INT32 OTA_SetUp(HIDO_CHAR *_pcUrl) { if(HIDO_NULL == _pcUrl) { return HIDO_ERR; } if(l_eOTAState != OTA_STATE_IDLE) { return HIDO_ERR; } /* ³õʼ»¯²ÎÊý */ l_u32OTARetryCnt = 0; l_u32OTAFileSize = 0; l_u32OTAFileRecvLen = 0; HIDO_UtilSnprintf(l_acOTAUrl, sizeof(l_acOTAUrl), _pcUrl); /* ²Á³ýOTAÎļþ»º´æ´æ´¢¿Õ¼ä */ SPIFlash_Erase(SPI_FLASH_ID_0, APP_CONFIG_APP_DOWN_LOAD_SPIFLASH_ADDRESS, APP_CONFIG_APP_DOWN_LOAD_SPIFLASH_SIZE, SPI_FLASH_SECTOR_ERASE_MODE_64K); /* ÇëÇóÉý¼¶Îļþ³¤¶È */ if(OTA_RequestFileLen() != HIDO_OK) { return HIDO_ERR; } l_eOTAState = OTA_STATE_HTTP_REQUEST_FILE_LEN; HIDO_TimerStart(l_u32OTATimerID, HIDO_TIMER_TYPE_ONCE, HIDO_TIMER_TICK_S(30), OTA_TimerCallBack, HIDO_NULL); return HIDO_OK; } /******************************************************************************* * Function Name : OTA_Cancel * Description : * Input : * Output : * Return : * Author : www.hido-studio.com * Modified Date: : 2020Äê9ÔÂ13ÈÕ *******************************************************************************/ HIDO_INT32 OTA_Cancel(HIDO_VOID) { HIDO_TimerCancel(l_u32OTATimerID); l_eOTAState = OTA_STATE_IDLE; return HIDO_OK; } static HIDO_CHAR url[256 + 1]; /******************************************************************************* * Function Name : OTA_Poll * Description : * Input : * Output : * Return : * Author : www.hido-studio.com * Modified Date: : 2020Äê9ÔÂ13ÈÕ *******************************************************************************/ HIDO_INT32 OTA_Poll(void) { if(Internet_IsIPReady() != HIDO_TRUE) { return HIDO_ERR; } if(l_eOTAState == OTA_STATE_IDLE) { OTA_SetUp(url); } return HIDO_OK; } /******************************************************************************* * Function Name : OTA_Init * Description : * Input : * Output : * Return : * Author : www.hido-studio.com * Modified Date: : 2020Äê9ÔÂ13ÈÕ *******************************************************************************/ HIDO_INT32 OTA_Init(void) { l_eOTAState = OTA_STATE_IDLE; HIDO_TimerCreate(&l_u32OTATimerID); HIDO_DataStruct stHost; HIDO_DataStruct stPath; HIDO_UINT32 u32Port = 0; SPIFlash_Read(SPI_FLASH_ID_0, url, APP_CONFIG_IAP_PARAM_MAP, sizeof(url) - 1); url[256] = '\0'; if(HIDO_UtilParseFormat((HIDO_UINT8 *)url, sizeof(url), "http://%p:%d/%p", &stHost, &u32Port, &stPath) != 3) { u32Port = 80; if (HIDO_UtilParseFormat((HIDO_UINT8 *) url, sizeof(url), "http://%p/%p", &stHost, &stPath) != 2) { OTA_Failed(); } } return HIDO_OK; }