475 lines
15 KiB
C
475 lines
15 KiB
C
/*
|
|
* ESPRESSIF MIT License
|
|
*
|
|
* Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
|
|
*
|
|
* Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
|
|
* it is free of charge, to any person obtaining a copy of this software and associated
|
|
* documentation files (the "Software"), to deal in the Software without restriction, including
|
|
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
|
|
* to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all copies or
|
|
* substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*
|
|
*/
|
|
#include "iot_export_ota.h"
|
|
#include "esp_common.h"
|
|
#include "cfg.h"
|
|
#include "lwip/mem.h"
|
|
#include "lwip/sockets.h"
|
|
#include "ota.h"
|
|
#include "log.h"
|
|
|
|
|
|
uint32 download_length = 0;
|
|
|
|
bool http_200_check = false;
|
|
char *resp_body_start = 0;
|
|
int content_len = 0;
|
|
|
|
extern int got_ip_flag;
|
|
struct upgrade_param *upgrade;
|
|
|
|
struct upgrade_param {
|
|
uint32 fw_bin_addr;
|
|
uint16 fw_bin_sec;
|
|
uint16 fw_bin_sec_num;
|
|
uint16 fw_bin_sec_earse;
|
|
uint8 extra;
|
|
uint8 save[4];
|
|
uint8 *buffer;
|
|
};
|
|
|
|
/******************************************************************************
|
|
* FunctionName : OUT_OF_RANGE
|
|
* Description : a
|
|
* Parameters :
|
|
* Returns :
|
|
*******************************************************************************/
|
|
LOCAL bool OUT_OF_RANGE(uint16 erase_sec)
|
|
{
|
|
uint8 spi_size_map = system_get_flash_size_map();
|
|
uint16 sec_num = 0;
|
|
uint16 start_sec = 0;
|
|
|
|
#if 1
|
|
start_sec = upgrade->fw_bin_sec;
|
|
sec_num = upgrade->fw_bin_sec_num;
|
|
#else
|
|
if (spi_size_map == FLASH_SIZE_8M_MAP_512_512 ||
|
|
spi_size_map == FLASH_SIZE_16M_MAP_512_512 ||
|
|
spi_size_map == FLASH_SIZE_32M_MAP_512_512) {
|
|
start_sec = (system_upgrade_userbin_check() == USER_BIN2) ? 1 : 129;
|
|
sec_num = 123;
|
|
} else if (spi_size_map == FLASH_SIZE_16M_MAP_1024_1024 ||
|
|
spi_size_map == FLASH_SIZE_32M_MAP_1024_1024) {
|
|
start_sec = (system_upgrade_userbin_check() == USER_BIN2) ? 1 : 257;
|
|
sec_num = 251;
|
|
} else {
|
|
start_sec = (system_upgrade_userbin_check() == USER_BIN2) ? 1 : 65;
|
|
sec_num = 59;
|
|
}
|
|
#endif
|
|
if ((erase_sec >= start_sec) && (erase_sec <= (start_sec + sec_num))) {
|
|
return false;
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
* FunctionName : user_upgrade_internal
|
|
* Description : a
|
|
* Parameters :
|
|
* Returns :
|
|
*******************************************************************************/
|
|
LOCAL bool system_upgrade_internal(struct upgrade_param *upgrade, uint8 *data, u32 len)
|
|
{
|
|
bool ret = false;
|
|
uint16 secnm = 0;
|
|
|
|
if (data == NULL || len == 0) {
|
|
return true;
|
|
}
|
|
|
|
/*got the sumlngth,erase all upgrade sector*/
|
|
if (len > SPI_FLASH_SEC_SIZE) {
|
|
upgrade->fw_bin_sec_earse = upgrade->fw_bin_sec;
|
|
|
|
secnm = ((upgrade->fw_bin_addr + len) >> 12) + (len & 0xfff ? 1 : 0);
|
|
|
|
while (upgrade->fw_bin_sec_earse != secnm) {
|
|
taskENTER_CRITICAL();
|
|
|
|
if (OUT_OF_RANGE(upgrade->fw_bin_sec_earse)) {
|
|
OTA_LOG_EX(LOG_Error, "fw_bin_sec_earse:%d, Out of range\n", upgrade->fw_bin_sec_earse);
|
|
taskEXIT_CRITICAL();
|
|
return FALSE;
|
|
} else {
|
|
spi_flash_erase_sector(upgrade->fw_bin_sec_earse);
|
|
upgrade->fw_bin_sec_earse++;
|
|
}
|
|
|
|
taskEXIT_CRITICAL();
|
|
vTaskDelay(10 / portTICK_RATE_MS);
|
|
}
|
|
|
|
OTA_LOG_EX(LOG_Info, "flash erase over\n");
|
|
return true;
|
|
}
|
|
|
|
upgrade->buffer = (uint8 *)zalloc(len + upgrade->extra);
|
|
|
|
memcpy(upgrade->buffer, upgrade->save, upgrade->extra);
|
|
memcpy(upgrade->buffer + upgrade->extra, data, len);
|
|
|
|
len += upgrade->extra;
|
|
upgrade->extra = len & 0x03;
|
|
len -= upgrade->extra;
|
|
|
|
if (upgrade->extra <= 4) {
|
|
memcpy(upgrade->save, upgrade->buffer + len, upgrade->extra);
|
|
} else {
|
|
OTA_LOG_EX(LOG_Error, "ERR3:arr_overflow,%u,%d\n", __LINE__, upgrade->extra);
|
|
}
|
|
|
|
do {
|
|
if (upgrade->fw_bin_addr + len >= (upgrade->fw_bin_sec + upgrade->fw_bin_sec_num) * SPI_FLASH_SEC_SIZE) {
|
|
OTA_LOG_EX(LOG_Error, "spi_flash_write exceed\n");
|
|
break;
|
|
}
|
|
|
|
if (spi_flash_write(upgrade->fw_bin_addr, (uint32 *)upgrade->buffer, len) != SPI_FLASH_RESULT_OK) {
|
|
OTA_LOG_EX(LOG_Error, "spi_flash_write failed\n");
|
|
break;
|
|
}
|
|
|
|
ret = true;
|
|
upgrade->fw_bin_addr += len;
|
|
} while (0);
|
|
|
|
free(upgrade->buffer);
|
|
upgrade->buffer = NULL;
|
|
return ret;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* FunctionName : system_upgrade_read
|
|
* Description : a
|
|
* Parameters :
|
|
* Returns :
|
|
*******************************************************************************/
|
|
void system_upgrade_finish(void)
|
|
{
|
|
uint32_t buffer[1];
|
|
|
|
/* check if any extra data not stored */
|
|
if ((upgrade->extra) == 0 || (upgrade->extra >= 4))
|
|
return;
|
|
|
|
memcpy(buffer, upgrade->save, upgrade->extra);
|
|
do {
|
|
if (upgrade->fw_bin_addr + upgrade->extra >= (upgrade->fw_bin_sec + upgrade->fw_bin_sec_num) * SPI_FLASH_SEC_SIZE) {
|
|
OTA_LOG_EX(LOG_Error, "spi_flash_write exceed\n");
|
|
break;
|
|
}
|
|
|
|
if (spi_flash_write(upgrade->fw_bin_addr, (uint32 *)buffer, upgrade->extra) != SPI_FLASH_RESULT_OK) {
|
|
OTA_LOG_EX(LOG_Error, "spi_flash_write failed\n");
|
|
break;
|
|
}
|
|
upgrade->fw_bin_addr += upgrade->extra;
|
|
} while (0);
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
* FunctionName : system_upgrade_read
|
|
* Description : a
|
|
* Parameters :
|
|
* Returns :
|
|
*******************************************************************************/
|
|
bool system_upgrade_read(uint32 offset, uint8 *data, uint32 len)
|
|
{
|
|
int start_sec;
|
|
start_sec = 0x100 - OTA_DEVICE_MAX_SECTORS;
|
|
|
|
if ((uint32)data&0x03)
|
|
return false;
|
|
|
|
if (spi_flash_read(start_sec*SPI_FLASH_SEC_SIZE+offset, (uint32 *)data, len) != SPI_FLASH_RESULT_OK) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* FunctionName : system_get_fw_start_sec
|
|
* Description : a
|
|
* Parameters :
|
|
* Returns :
|
|
*******************************************************************************/
|
|
uint16 system_get_fw_start_sec()
|
|
{
|
|
if (upgrade != NULL) {
|
|
return upgrade->fw_bin_sec;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/******************************************************************************
|
|
* FunctionName : system_upgrade
|
|
* Description : a
|
|
* Parameters :
|
|
* Returns :
|
|
*******************************************************************************/
|
|
bool system_upgrade(uint8 *data, uint32 len)
|
|
{
|
|
bool ret;
|
|
ret = system_upgrade_internal(upgrade, data, len);
|
|
return ret;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* FunctionName : upgrade_recycle
|
|
* Description : a
|
|
* Parameters :
|
|
* Returns :
|
|
*******************************************************************************/
|
|
void upgrade_recycle(void)
|
|
{
|
|
OTA_LOG_EX(LOG_Info, "upgrade recycle\n");
|
|
download_length = 0;
|
|
http_200_check = false;
|
|
resp_body_start = 0;
|
|
content_len = 0;
|
|
|
|
system_upgrade_deinit();
|
|
|
|
if (system_upgrade_flag_check() == UPGRADE_FLAG_FINISH) {
|
|
system_upgrade_reboot(); // if need
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* FunctionName : upgrade_getContentLen
|
|
* Description : a
|
|
* Parameters :
|
|
* Returns :
|
|
*******************************************************************************/
|
|
int upgrade_getContentLen(void)
|
|
{
|
|
return content_len;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* FunctionName : system_upgrade_init
|
|
* Description : a
|
|
* Parameters :
|
|
* Returns :
|
|
*******************************************************************************/
|
|
void system_upgrade_init(int type)
|
|
{
|
|
uint32 user_bin2_start, user_bin1_start;
|
|
uint8 spi_size_map = system_get_flash_size_map();
|
|
|
|
OTA_LOG_EX(LOG_Info, "upgrade init\n");
|
|
if (upgrade == NULL) {
|
|
upgrade = (struct upgrade_param *)zalloc(sizeof(struct upgrade_param));
|
|
}
|
|
|
|
/* WIFI mode, should check flash map */
|
|
if (type == OTA_DEVICE_WIFI) {
|
|
user_bin1_start = 1;
|
|
if (spi_size_map == FLASH_SIZE_8M_MAP_512_512 ||
|
|
spi_size_map == FLASH_SIZE_16M_MAP_512_512 ||
|
|
spi_size_map == FLASH_SIZE_32M_MAP_512_512) {
|
|
user_bin2_start = 129;
|
|
upgrade->fw_bin_sec_num = 123;
|
|
} else if (spi_size_map == FLASH_SIZE_16M_MAP_1024_1024 ||
|
|
spi_size_map == FLASH_SIZE_32M_MAP_1024_1024) {
|
|
user_bin2_start = 257;
|
|
upgrade->fw_bin_sec_num = 251;
|
|
} else {
|
|
user_bin2_start = 65;
|
|
upgrade->fw_bin_sec_num = 59;
|
|
}
|
|
|
|
upgrade->fw_bin_sec = (system_upgrade_userbin_check() == USER_BIN1) ? user_bin2_start : user_bin1_start;
|
|
}
|
|
|
|
/* MCU mode, from (0x100000-OTA_DEVICE_MAX_SECTORS*SECTOR_SIZE) to 0x100000, and MAYBE around 64 is better */
|
|
if (type == OTA_DEVICE_MCU) {
|
|
upgrade->fw_bin_sec = 0x100 - OTA_DEVICE_MAX_SECTORS;
|
|
upgrade->fw_bin_sec_num = OTA_DEVICE_MAX_SECTORS;
|
|
}
|
|
|
|
upgrade->fw_bin_addr = upgrade->fw_bin_sec * SPI_FLASH_SEC_SIZE;
|
|
|
|
upgrade->fw_bin_sec_earse = upgrade->fw_bin_sec;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* FunctionName : system_upgrade_deinit
|
|
* Description : a
|
|
* Parameters :
|
|
* Returns :
|
|
*******************************************************************************/
|
|
void system_upgrade_deinit(void)
|
|
{
|
|
if (upgrade != NULL) {
|
|
free(upgrade);
|
|
upgrade = NULL;
|
|
}
|
|
|
|
OTA_LOG_EX(LOG_Info, "upgrade deinit\n");
|
|
return;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* FunctionName : read_until
|
|
* Description : a
|
|
* Parameters :
|
|
* Returns :
|
|
*******************************************************************************/
|
|
static int read_until(char *buffer, char delim, int len)
|
|
{
|
|
// /*TODO: delim check,buffer check,further: do an buffer length limited*/
|
|
int i = 0;
|
|
|
|
while (buffer[i] != delim && i < len) {
|
|
++i;
|
|
}
|
|
|
|
return i + 1;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* FunctionName : read_past_http_header
|
|
* Description : a
|
|
* Parameters :
|
|
* Returns :
|
|
*******************************************************************************/
|
|
int read_past_http_header(char text[], int total_len, char **content_body, int *content_len)
|
|
{
|
|
/* i means current position */
|
|
int i = 0, i_read_len = 0;
|
|
char *ptr = NULL, *ptr2 = NULL;
|
|
char length_str[32] = {0};
|
|
int erase_length;
|
|
|
|
while (text[i] != 0 && i < total_len) {
|
|
if ((*content_len == 0) && (ptr = (char *)strstr(text, "Content-Length")) != NULL) {
|
|
ptr += 16;
|
|
ptr2 = (char *)strstr(ptr, "\r\n");
|
|
memset(length_str, 0, sizeof(length_str));
|
|
memcpy(length_str, ptr, ptr2 - ptr);
|
|
*content_len = atoi(length_str);
|
|
OTA_LOG_EX(LOG_Info, "parse Content-Length:%d\n", *content_len);
|
|
}
|
|
|
|
i_read_len = read_until(&text[i], '\n', total_len);
|
|
|
|
/* if resolve \r\n line, http header is finished */
|
|
if (i_read_len == 2) {
|
|
if (*content_len == 0) {
|
|
OTA_LOG_EX(LOG_Error, "did not parse Content-Length item\n");
|
|
return -1;
|
|
}
|
|
|
|
/* erase flash when first flash, for save new bin */
|
|
#if 1 //bug in flash erase, walk around.
|
|
erase_length = *content_len;
|
|
if (erase_length < 8192)
|
|
erase_length = 8192;
|
|
#endif
|
|
if (false == system_upgrade(text, erase_length)) {
|
|
return -1;
|
|
}
|
|
|
|
/* the valid left http body length */
|
|
*content_body = text + i + 2;
|
|
return 1 ;
|
|
}
|
|
|
|
i += i_read_len;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define STR_HTTP_RSP_200 "HTTP/1.1 200"
|
|
/******************************************************************************
|
|
* FunctionName : upgrade_download
|
|
* Description : parse http response ,and download remote data and write in flash
|
|
* Parameters : int sta_socket : ota client socket fd
|
|
* char *pusrdata : remote data
|
|
* length : data length
|
|
* Returns : none
|
|
*******************************************************************************/
|
|
int upgrade_download(int sta_socket, char *pusrdata, unsigned short length, int type)
|
|
{
|
|
char *ptr = NULL;
|
|
char *ptmp2 = NULL;
|
|
char lengthbuffer[32];
|
|
|
|
// first response should include state code:200
|
|
if (!http_200_check && strstr(pusrdata, STR_HTTP_RSP_200) == NULL) {
|
|
OTA_LOG_EX(LOG_Error, "ota url is invalid or bin is not exist\n");
|
|
return -1;
|
|
}
|
|
|
|
http_200_check = true;
|
|
|
|
if (resp_body_start == 0) {
|
|
int rc;
|
|
|
|
/* deal with http header */
|
|
OTA_LOG_EX(LOG_Info, "HTTP Header %s\n", pusrdata);
|
|
rc = read_past_http_header(pusrdata, length, &resp_body_start, &content_len);
|
|
if (rc > 0) {
|
|
length = length-(resp_body_start-pusrdata);
|
|
pusrdata = resp_body_start;
|
|
} else if (rc < 0) {
|
|
return -1;
|
|
} else {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// deal with http body
|
|
// http transmit body more than content-length occasionally
|
|
// default bin size = content-length, throw up the other http body
|
|
if (download_length + length > content_len) {
|
|
length = content_len - download_length;
|
|
download_length = content_len;
|
|
} else {
|
|
download_length += length;
|
|
}
|
|
|
|
OTA_LOG_EX(LOG_Info, "downloaded len:%d\n", download_length);
|
|
|
|
/* save http body(bin) to flash */
|
|
if (false == system_upgrade(pusrdata, length)) {
|
|
return -1;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|