/* * ESPRESSIF MIT License * * Copyright (c) 2015 * * 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; }