esp8266-std/fota/local_ota.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;
}