/* * 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 "iot_import.h" #include "iot_export.h" #include "esp_common.h" #include "cfg.h" #include "esp_mqtt.h" #include "esp_MSG_ctrl.h" #include "lwip/mem.h" #include "lwip/sockets.h" #include "utils_httpc.h" #include "ota.h" #include "log.h" #include "user_main.h" #include "ne_monitor.h" extern bool http_200_check; extern bool resp_body_start; extern uint32 download_length; extern int got_ip_flag; extern int ota_report_latest_version; extern int ota_process; #define OTA_HTTP_GET_MAX_LEN 1024 #define OTA_HTTP_RECEIVE_MAX_LEN 1460 #define REMOTE_OTA_HEALTH_TIME 120*1000 //ms #define REMOTE_OTA_INTERVAL_TIME 1 //sec static uint32 remote_ota_health_value; os_timer_t upgrade_timer; uint32_t ota_MCU_upgrade_flag; uint32_t ota_MCU_Segment_length; extern const char *iotx_ca_get(void); extern int httpclient_recv(httpclient_t *client, char *buf, int min_len, int max_len, int *p_read_len, uint32_t timeout_ms); uint8_t remote_ota_MCU_upgrade_flag_check(void); void remote_ota_MCU_upgrade_flag_set(uint8_t flag); void remote_ota_restart(void); void remote_ota_WIFI_end(void); void remote_ota_MCU_end(void); /* * system thread monitor check. */ static int32 remote_ota_thread_check(uint32 cur_msec) { // OTA_LOG_EX(LOG_Info, "check.......!\r\n"); if (cur_msec > remote_ota_health_value + REMOTE_OTA_HEALTH_TIME) { OTA_LOG_EX(LOG_Error, "remote OTA thread is sick! and system restart!\r\n"); system_restart(); return -ERR_FAIL; } return ERR_OK; } /* * system set msec. */ static void remote_ota_set_last_msec(uint32 msec) { // OTA_LOG_EX(LOG_Info, "feed ... ...\r\n"); remote_ota_health_value = msec; } /* * system register thread monitor. */ static int32 remote_ota_thread_monitor_init(void *handle_name) { remote_ota_health_value = ne_os_ticks_ms(xTaskGetTickCount()); return ne_thread_monitor_register(handle_name, REMOTE_OTA_INTERVAL_TIME, remote_ota_set_last_msec); } #if (OTA_SERVER_TYPE == OTA_HTTP) /****************************************************************************** * FunctionName : remote_ota_WIFI_process * Description : ota_task function * Parameters : task param * Returns : none *******************************************************************************/ static void remote_ota_download(ota_info_t *ota_info, uint32_t sector, uint8_t type) { sint32 read_bytes; sint32 sin_size, sectorDigi, i, orgin_ota_len; uint8_t *recv_buf; sint32 sta_socket; struct sockaddr_in remote_ip; uint8_t *http_request = NULL; sint32 get_len = 0; uint8_t digtal[5]; OTA_LOG_EX(LOG_Info, "Remote OTA Download, Free Heap %d!\r\n", system_get_free_heap_size()); /* upgrade download initial */ system_upgrade_init(type); if (type == OTA_DEVICE_WIFI) { system_upgrade_flag_set(UPGRADE_FLAG_START); } if (type == OTA_DEVICE_MCU) { remote_ota_MCU_upgrade_flag_set(UPGRADE_FLAG_START); } recv_buf = HAL_Malloc(OTA_HTTP_RECEIVE_MAX_LEN); orgin_ota_len = strlen(ota_info->ota_path); do { sta_socket = socket(PF_INET, SOCK_STREAM, 0); if (-1 == sta_socket) { OTA_LOG_EX(LOG_Error, "socket fail %x!\r\n", errno); break; } bzero(&remote_ip, sizeof(struct sockaddr_in)); remote_ip.sin_family = AF_INET; remote_ip.sin_addr.s_addr = (ota_info->target_ip).addr; remote_ip.sin_port = htons(REMOTE_OTA_SERVER_PORT); if (0 != connect(sta_socket, (struct sockaddr *)(&remote_ip), sizeof(struct sockaddr))) { OTA_LOG_EX(LOG_Info, "connect fail!\r\n"); break; } OTA_LOG_EX(LOG_Info, "connect ok!\r\n"); remote_ota_set_last_msec(ne_os_ticks_ms(xTaskGetTickCount())); /* Add sector number to ota_path */ sectorDigi = sector+1; get_len = 0; do { digtal[get_len] = 0x30+(sectorDigi%10); get_len++; sectorDigi /= 10; } while (sectorDigi) ; i = get_len-1; get_len = orgin_ota_len; for ( ; i >= 0 ; i--) { ota_info->ota_path[get_len++] = digtal[i]; } ota_info->ota_path[get_len] = 0; /* generate GET request to http server */ http_request = HAL_Malloc(OTA_HTTP_GET_MAX_LEN); if (http_request == 0) { OTA_LOG_EX(LOG_Error, "malloc memory failed.\n"); break; } memset(http_request, 0, OTA_HTTP_GET_MAX_LEN); OTA_LOG_EX(LOG_Info, "OTA path %s, host name %s \r\n", ota_info->ota_path, ota_info->hostname); get_len = HAL_Snprintf(http_request, 2048, OTA_REMOTE_GET_FORMAT, (const char *)ota_info->ota_path, ota_info->hostname); // OTA_LOG_EX(LOG_Info, "OTA request %s\r\n", http_request); /* send http request */ if (write(sta_socket, http_request, strlen(http_request) + 1) < 0) { OTA_LOG_EX(LOG_Error, "send request fail\n"); HAL_Free(http_request); break; } HAL_Free(http_request); /* read http response */ while ((read_bytes = read(sta_socket , recv_buf, OTA_HTTP_RECEIVE_MAX_LEN)) >= 0) { int rc; remote_ota_set_last_msec(ne_os_ticks_ms(xTaskGetTickCount())); // OTA_LOG_EX(LOG_Info, "Read Data Leng %x\r\n", read_bytes); /* parse and store */ if (read_bytes > 0) { rc = upgrade_download(sta_socket, recv_buf, read_bytes, type); if (rc < 0) { OTA_LOG_EX(LOG_Error, "OTA download error\n"); break; } if (upgrade_getContentLen() && (ota_info->bin_size != upgrade_getContentLen())) ota_info->bin_size = upgrade_getContentLen(); } else { OTA_LOG_EX(LOG_Error, "peer close socket\n"); break; } /* WIFI OTA end */ if (type == OTA_DEVICE_WIFI) { /* default bin size equals to ota_info->bin_size */ if (download_length == ota_info->bin_size && download_length != 0) { OTA_LOG_EX(LOG_Info, "upgrade download finished, bin size:%d\n", download_length); if (upgrade_crc_check(system_get_fw_start_sec(), download_length) != true) { OTA_LOG_EX(LOG_Info, "upgrade crc failed !\n"); system_upgrade_flag_set(UPGRADE_FLAG_IDLE); } else { OTA_LOG_EX(LOG_Info, "upgrade crc ok\n"); system_upgrade_flag_set(UPGRADE_FLAG_FINISH); } break; } } /* MCU OTA end */ if (type == OTA_DEVICE_MCU) { /* default bin size equals to ota_info->bin_size */ if (download_length == ota_info->bin_size && download_length != 0) { OTA_LOG_EX(LOG_Info, "upgrade download finished, bin size:%d\n", download_length); system_upgrade_finish(); ota_MCU_Segment_length = download_length; remote_ota_MCU_upgrade_flag_set(UPGRADE_FLAG_FINISH); break; } } } if (read_bytes < 0) { OTA_LOG_EX(LOG_Error, "read data fail!\r\n"); } break; } while (0); if (sta_socket >= 0) close(sta_socket); if (type == OTA_DEVICE_WIFI) { if (system_upgrade_flag_check() != UPGRADE_FLAG_FINISH) system_upgrade_flag_set(UPGRADE_FLAG_IDLE); } if (type == OTA_DEVICE_MCU){ if (remote_ota_MCU_upgrade_flag_check() != UPGRADE_FLAG_FINISH) remote_ota_MCU_upgrade_flag_set(UPGRADE_FLAG_IDLE); } upgrade_recycle(); HAL_Free(recv_buf); ota_info->ota_path[orgin_ota_len] = 0; } #else /****************************************************************************** * FunctionName : ota_WIFI_process * Description : ota_task function * Parameters : task param * Returns : none *******************************************************************************/ static void remote_ota_download(ota_info_t *ota_info, uint32_t sector, uint8_t type) { sint32 read_bytes; sint32 ret, get_len, sectorDigi, orgin_ota_len, i; uint8_t *recv_buf; httpclient_t httpc; httpclient_data_t httpc_data; uint8_t *http_request = 0; uint8_t digtal[5]; recv_buf = HAL_Malloc(OTA_HTTP_RECEIVE_MAX_LEN); orgin_ota_len = strlen(ota_info->ota_path); OTA_LOG_EX(LOG_Info, "Hello, welcome to remote ota!\r\n"); while (1) { memset(&httpc, 0, sizeof(httpclient_t)); memset(&httpc_data, 0, sizeof(httpclient_data_t)); /* build http header */ http_request = HAL_Malloc(OTA_HTTP_GET_MAX_LEN); if (NULL == http_request) { OTA_LOG_EX(LOG_Error, "req payload error\r\n"); break; } memset(http_request, 0, OTA_HTTP_GET_MAX_LEN); get_len = strlen(ota_info->ota_path); /* Add sector number to ota_path */ sectorDigi = sector+1; get_len = 0; do { digtal[get_len] = 0x30+(sectorDigi%10); get_len++; sectorDigi /= 10; } while (sectorDigi) ; i = get_len-1; get_len = orgin_ota_len; for ( ; i >= 0 ; i--) { ota_info->ota_path[get_len++] = digtal[i]; } ota_info->ota_path[get_len] = 0; get_len = HAL_Snprintf(http_request, OTA_HTTP_GET_MAX_LEN, OTA_REMOTE_GET_FORMAT); httpc.header = http_request; OTA_LOG_EX(LOG_Info, "http req header %s\r\n", http_request); /* http connect and send get requset */ httpc_data.post_buf = NULL; httpc_data.post_buf_len = 0; if (0 == httpc.net.handle) { char url[128]; get_len = HAL_Snprintf(url, 128, "https://%s%s", ota_info->hostname, ota_info->ota_path); OTA_LOG_EX(LOG_Info, "http URL is %s\r\n", url); ret = iotx_net_init(&(httpc.net), ota_info->hostname, REMOTE_OTA_SERVER_PORT, iotx_ca_get(), NULL); if (0 != ret) { break; } OTA_LOG_EX(LOG_Error, "httpclient_connect\r\n"); ret = httpclient_connect(&httpc); if (0 != ret) { OTA_LOG_EX(LOG_Error, "httpclient_connect is error, ret = %d\r\n", ret); httpclient_close(&httpc); break; } OTA_LOG_EX(LOG_Error, "httpclient_get req\r\n"); ret = httpclient_send_request(&httpc, url, HTTPCLIENT_GET, &httpc_data); if (0 != ret) { OTA_LOG_EX(LOG_Error, "httpclient_send_request is error, ret = %d\r\n", ret); httpclient_close(&httpc); break; } } /* http receive and parse response */ while (httpclient_recv(&httpc, recv_buf, 128, 128, &read_bytes, 3000) == 0) { #if 1 OTA_LOG_EX(LOG_Info, "Read Data Length %x\r\n", read_bytes); #else if (read_bytes > 0) { upgrade_download(0, recv_buf, read_bytes, type); } else { OTA_LOG_EX(LOG_Error, "peer close socket\n"); break; } // default bin size equals to ota_info->bin_size if (download_length >= ota_info->bin_size && download_length != 0) { OTA_LOG_EX(LOG_Info, "upgrade file download finished, bin size:%d\n", download_length); if (upgrade_crc_check(system_get_fw_start_sec(), ota_info->bin_size) != true) { OTA_LOG_EX(LOG_Info, "upgrade crc check failed !\n"); system_upgrade_flag_set(UPGRADE_FLAG_IDLE); } else { OTA_LOG_EX(LOG_Info, "bin check crc ok\n"); system_upgrade_flag_set(UPGRADE_FLAG_FINISH); } break; } #endif } OTA_LOG_EX(LOG_Info, "read_bytes = %d\n", read_bytes); if (read_bytes < 0) { OTA_LOG_EX(LOG_Error, "read data fail!\r\n"); system_upgrade_flag_set(UPGRADE_FLAG_IDLE); } break; } if (http_request) HAL_Free(http_request); HAL_Free(recv_buf); ota_info->ota_path[orgin_ota_len] = 0; } #endif /****************************************************************************** * FunctionName : ota_wifi_timeout * Description : ota_task function * Parameters : task param * Returns : none *******************************************************************************/ void remote_ota_WIFI_timeout(void) { /* OTA timeout */ remote_ota_WIFI_end(); } /****************************************************************************** * FunctionName : remote_ota_WIFI_start * Description : ota_task function * Parameters : task param * Returns : none *******************************************************************************/ void remote_ota_WIFI_start(void) { /* OTA timeout setup */ os_timer_disarm(&upgrade_timer); os_timer_setfn(&upgrade_timer, (os_timer_func_t *)remote_ota_WIFI_timeout, NULL); os_timer_arm(&upgrade_timer, OTA_TIMEOUT_WIFI, 0); /* inform MCU if needed */ #if (OTA_CONTROL_DEV == OTA_DEVICE_MCU) /* UNDO */ #endif } /****************************************************************************** * FunctionName : remote_ota_WIFI_download * Description : ota_task function * Parameters : task param * Returns : none *******************************************************************************/ void remote_ota_WIFI_download(ota_info_t *ota_info, uint32_t sector) { remote_ota_download(ota_info, sector, OTA_DEVICE_WIFI); } /****************************************************************************** * FunctionName : remote_ota_WIFI_end * Description : ota_task function * Parameters : task param * Returns : none *******************************************************************************/ void remote_ota_WIFI_end(void) { /* inform MCU if needed */ #if (OTA_CONTROL_DEV == OTA_DEVICE_MCU) /* UNDO */ #endif upgrade_recycle(); } /****************************************************************************** * FunctionName : ota_MCU_timeout * Description : ota_task function * Parameters : task param * Returns : none *******************************************************************************/ void remote_ota_MCU_timeout(void) { /* OTA timeout */ remote_ota_MCU_end(); } /****************************************************************************** * FunctionName : remote_ota_MCU_start * Description : ota_task function * Parameters : task param * Returns : none *******************************************************************************/ void remote_ota_MCU_start(void) { /* OTA timeout setup */ os_timer_disarm(&upgrade_timer); os_timer_setfn(&upgrade_timer, (os_timer_func_t *)remote_ota_MCU_timeout, NULL); os_timer_arm(&upgrade_timer, OTA_TIMEOUT_MCU, 0); MSG_ctrl_rsp_start(OTA_DEVICE_MCU, MSG_CONTROL_RESULT_SUCCESS); } /****************************************************************************** * FunctionName : remote_ota_MCU_download * Description : ota_task function * Parameters : task param * Returns : none *******************************************************************************/ void remote_ota_MCU_download(ota_info_t *ota_info, uint32_t sector) { remote_ota_download(ota_info, sector, OTA_DEVICE_MCU); if (remote_ota_MCU_upgrade_flag_check() == UPGRADE_FLAG_FINISH) { MSG_ctrl_rsp_download(OTA_DEVICE_MCU, MSG_CONTROL_RESULT_SUCCESS, ota_MCU_Segment_length); } else { MSG_ctrl_rsp_download(OTA_DEVICE_MCU, MSG_CONTROL_RESULT_FAILED, 0); } } /****************************************************************************** * FunctionName : remote_ota_MCU_read * Description : ota_task function * Parameters : task param * Returns : none *******************************************************************************/ void remote_ota_MCU_read(ota_info_t *ota_info, int offset, int size) { uint8_t *data; data = HAL_Malloc(size); if (data) { if (system_upgrade_read(offset, data, size) == true) { MSG_ctrl_rsp_read(OTA_DEVICE_MCU, MSG_CONTROL_RESULT_SUCCESS, data, size); return; } HAL_Free(data); } MSG_ctrl_rsp_read(OTA_DEVICE_MCU, MSG_CONTROL_RESULT_FAILED, 0, 0); } /****************************************************************************** * FunctionName : remote_ota_MCU_end * Description : ota_task function * Parameters : task param * Returns : none *******************************************************************************/ void remote_ota_MCU_end_callback(void *pArgs) { if (pArgs) HAL_Free(pArgs); remote_ota_restart(); } /****************************************************************************** * FunctionName : remote_ota_MCU_end * Description : ota_task function * Parameters : task param * Returns : none *******************************************************************************/ void remote_ota_MCU_end(void) { MSG_ctrl_rsp_quit(OTA_DEVICE_MCU, MSG_CONTROL_RESULT_SUCCESS); HAL_TimerCreate(3000, remote_ota_MCU_end_callback, NULL); } /****************************************************************************** * FunctionName : remote_ota_MCU_upgrade_flag_set * Description : ota_task function * Parameters : task param * Returns : none *******************************************************************************/ uint8_t remote_ota_MCU_upgrade_flag_check(void) { return ota_MCU_upgrade_flag; } /****************************************************************************** * FunctionName : remote_ota_MCU_upgrade_flag_set * Description : ota_task function * Parameters : task param * Returns : none *******************************************************************************/ void remote_ota_MCU_upgrade_flag_set(uint8_t flag) { ota_MCU_upgrade_flag = flag; } /****************************************************************************** * FunctionName : remote_ota_restart * Description : ota_task function * Parameters : task param * Returns : none *******************************************************************************/ void remote_ota_restart(void) { system_restart(); } /****************************************************************************** * FunctionName : remote_ota_get_info * Description : ota_task function * Parameters : task param * Returns : none *******************************************************************************/ uint32_t remote_ota_get_info(uint8_t type, ota_info_t *ota_info) { uint32_t flash_sector = PARAM_SAVE_OTAINFO_WIFI; if (type == OTA_DEVICE_MCU) { flash_sector = PARAM_SAVE_OTAINFO_MCU; } if (spi_flash_read(flash_sector*SECTOR_SIZE, (uint32 *)ota_info, sizeof(ota_info_t)) != SPI_FLASH_RESULT_OK) { OTA_LOG_EX(LOG_Error, "get info\r\n"); } OTA_LOG_EX(LOG_Info,"OTA flag:%u, sect %x\n", ota_info->ota_flag, flash_sector); OTA_LOG_EX(LOG_Info,"bin size:%u\n", ota_info->bin_size); OTA_LOG_EX(LOG_Info,"seg size:%u\n", ota_info->seg_size); OTA_LOG_EX(LOG_Info,"device :%u\n", ota_info->ota_device); OTA_LOG_EX(LOG_Info,"latest version:%s\n", ota_info->latest_version); OTA_LOG_EX(LOG_Info,"hostname:%s\n", ota_info->hostname); OTA_LOG_EX(LOG_Info,"ota path:%s\n", ota_info->ota_path); if (ota_info->ota_flag == 1) { ota_info->ota_flag = 0; if (spi_flash_erase_sector(flash_sector) != SPI_FLASH_RESULT_OK) { OTA_LOG_EX(LOG_Error, "flash erase\r\n"); } if (spi_flash_write(flash_sector*SECTOR_SIZE, (uint32 *)ota_info, sizeof(ota_info_t)) != SPI_FLASH_RESULT_OK) { OTA_LOG_EX(LOG_Error, "flash write\r\n"); } return TRUE; } else { return FALSE; } } /****************************************************************************** * FunctionName : remote_ota_store_info * Description : ota_task function * Parameters : task param * Returns : none *******************************************************************************/ uint32_t remote_ota_store_info(uint8_t type, ota_info_t *ota_info) { uint32_t flash_sector = PARAM_SAVE_OTAINFO_WIFI; if (type == OTA_DEVICE_MCU) { flash_sector = PARAM_SAVE_OTAINFO_MCU; } OTA_LOG_EX(LOG_Info,"Store OTA type:%u, sect %x\n", type, flash_sector); /* write information to flash */ if (spi_flash_erase_sector(flash_sector) != SPI_FLASH_RESULT_OK) { OTA_LOG_EX(LOG_Error, "flash erase\n"); } else { if (spi_flash_write(flash_sector*SECTOR_SIZE, (uint32 *)ota_info, sizeof(ota_info_t)) != SPI_FLASH_RESULT_OK) { OTA_LOG_EX(LOG_Error, "flash write\r\n"); } } return TRUE; } /****************************************************************************** * FunctionName : ota_upgrade task * Description : ota_task function * Parameters : task param * Returns : none *******************************************************************************/ void remote_ota_upgrade_process(uint8_t type) { ota_info_t *ota_info; uint32_t rc; remote_ota_thread_monitor_init("remote_ota_thread"); while ( wifi_station_get_connect_status() != STATION_GOT_IP) { remote_ota_set_last_msec(ne_os_ticks_ms(xTaskGetTickCount())); vTaskDelay(1000 / portTICK_RATE_MS); } OTA_LOG_EX(LOG_Info, "OTA process started, type %x, free heap size %x\r\n", type, system_get_free_heap_size()); /* control command initial */ MSG_ctrl_cmd_initial(); /* ota info get */ ota_info = HAL_Malloc(sizeof(ota_info_t)); memset(ota_info, 0, sizeof(ota_info_t)); rc = remote_ota_get_info(type, ota_info); if (rc == FALSE) { OTA_LOG_EX(LOG_Error, "OTA get info failed\n"); HAL_Free(ota_info); return; } if (type == OTA_DEVICE_WIFI) { remote_ota_WIFI_start(); remote_ota_WIFI_download(ota_info, 0); remote_ota_WIFI_end(); } else { remote_ota_MCU_start(); do { uint32_t cmd, rc; void *param; remote_ota_set_last_msec(ne_os_ticks_ms(xTaskGetTickCount())); rc = MSG_ctrl_cmd_get(&cmd, ¶m); if (rc == FALSE) { continue; } OTA_LOG_EX(LOG_Info, "OTA Process cmd %x\r\n", cmd); switch (cmd) { case MSG_CONTROL_CMD_OTA_START: break; case MSG_CONTROL_CMD_OTA_SEGDOWNLOAD: { struct OTA_SegDownload_Cmd *cmd = param; remote_ota_MCU_download(ota_info, cmd->seg_num); } break; case MSG_CONTROL_CMD_OTA_SEGREAD: { struct OTA_SegRead_Cmd *cmd = param; remote_ota_MCU_read(ota_info, cmd->offset, cmd->length); } break; case MSG_CONTROL_CMD_OTA_QUIT: { remote_ota_MCU_end(); } break; } if (param) HAL_Free(param); } while (1); remote_ota_MCU_end(); } HAL_Free(ota_info); } /****************************************************************************** * FunctionName : ota_upgrade task * Description : ota_task function * Parameters : task param * Returns : none *******************************************************************************/ void remote_ota_upgrade_task_MCU(void *pvParameter) { remote_ota_upgrade_process(OTA_DEVICE_MCU); remote_ota_restart(); vTaskDelete(NULL); } /****************************************************************************** * FunctionName : ota_upgrade task * Description : ota_task function * Parameters : task param * Returns : none *******************************************************************************/ void remote_ota_upgrade_task_WIFI(void *pvParameter) { remote_ota_upgrade_process(OTA_DEVICE_WIFI); remote_ota_restart(); vTaskDelete(NULL); }