diff --git a/src/httpserver/rest_interface.c b/src/httpserver/rest_interface.c index 4ede510f9..43e28db14 100644 --- a/src/httpserver/rest_interface.c +++ b/src/httpserver/rest_interface.c @@ -241,8 +241,11 @@ static int http_rest_post(http_request_t* request) { return http_rest_post_flash(request, -1, -1); #elif PLATFORM_BL602 return http_rest_post_flash(request, -1, -1); +#elif PLATFORM_LN882H + return http_rest_post_flash(request, -1, -1); #else // TODO + ADDLOG_DEBUG(LOG_FEATURE_API, "No OTA"); #endif } if (!strncmp(request->url, "api/flash/", 10)) { @@ -1133,6 +1136,225 @@ static int _check_ota_header(ota_header_t *ota_header, uint32_t *ota_len, int *u return 0; } #endif + +#if PLATFORM_LN882H +#include "ota_port.h" +#include "ota_image.h" +#include "ota_types.h" +#include "hal/hal_flash.h" +#include "netif/ethernetif.h" +#include "flash_partition_table.h" + + +#define KV_OTA_UPG_STATE ("kv_ota_upg_state") +#define HTTP_OTA_DEMO_STACK_SIZE (1024 * 16) + +#define SECTOR_SIZE_4KB (1024 * 4) + +static char g_http_uri_buff[512] = "http://192.168.122.48:9090/ota-images/otaimage-v1.3.bin"; + +// a block to save http data. +static char *temp4K_buf = NULL; +static int temp4k_offset = 0; + +// where to save OTA data in flash. +static int32_t flash_ota_start_addr = OTA_SPACE_OFFSET; +static int32_t flash_ota_offset = 0; +static uint8_t is_persistent_started = LN_FALSE; +static uint8_t is_ready_to_verify = LN_FALSE; +static uint8_t is_precheck_ok = LN_FALSE; +static uint8_t httpc_ota_started = 0; + +/** + * @brief Pre-check the image file to be downloaded. + * + * @attention None + * + * @param[in] app_offset The offset of the APP partition in Flash. + * @param[in] ota_hdr pointer to ota partition info struct. + * + * @return whether the check is successful. + * @retval #LN_TRUE successful. + * @retval #LN_FALSE failed. + */ +static int ota_download_precheck(uint32_t app_offset, image_hdr_t * ota_hdr) +{ + + image_hdr_t *app_hdr = NULL; + if (NULL == (app_hdr = OS_Malloc(sizeof(image_hdr_t)))) { + ADDLOG_DEBUG(LOG_FEATURE_OTA, "[%s:%d] malloc failed.\r\n", __func__, __LINE__); + return LN_FALSE; + } + + if (OTA_ERR_NONE != image_header_fast_read(app_offset, app_hdr)) { + ADDLOG_DEBUG(LOG_FEATURE_OTA, "failed to read app header.\r\n"); + goto ret_err; + } + + if ((ota_hdr->image_type == IMAGE_TYPE_ORIGINAL) || \ + (ota_hdr->image_type == IMAGE_TYPE_ORIGINAL_XZ)) + { + // check version + if (((ota_hdr->ver.ver_major << 8) + ota_hdr->ver.ver_minor) == \ + ((app_hdr->ver.ver_major << 8) + app_hdr->ver.ver_minor)) { + ADDLOG_DEBUG(LOG_FEATURE_OTA, "[%s:%d] same version, do not upgrade!\r\n", + __func__, __LINE__); + } + + // check file size + if (((ota_hdr->img_size_orig + sizeof(image_hdr_t)) > APP_SPACE_SIZE) || \ + ((ota_hdr->img_size_orig_xz + sizeof(image_hdr_t)) > OTA_SPACE_SIZE)) { + ADDLOG_DEBUG(LOG_FEATURE_OTA, "[%s:%d] size check failed.\r\n", __func__, __LINE__); + goto ret_err; + } + } + else { + //image type not support! + goto ret_err; + } + + OS_Free(app_hdr); + return LN_TRUE; + +ret_err: + OS_Free(app_hdr); + return LN_FALSE; +} + +static int ota_persistent_start(void) +{ + if (NULL == temp4K_buf) { + temp4K_buf = OS_Malloc(SECTOR_SIZE_4KB); + if (NULL == temp4K_buf) { + LOG(LOG_LVL_INFO,"failed to alloc 4KB!!!\r\n"); + return LN_FALSE; + } + memset(temp4K_buf, 0, SECTOR_SIZE_4KB); + } + + temp4k_offset = 0; + flash_ota_start_addr = OTA_SPACE_OFFSET; + flash_ota_offset = 0; + is_persistent_started = LN_TRUE; + return LN_TRUE; +} + +/** + * @brief Save block to flash. + * + * @param buf + * @param buf_len + * @return return LN_TRUE on success, LN_FALSE on failure. + */ +static int ota_persistent_write(const char *buf, const int32_t buf_len) +{ + int part_len = 0; // [0, 1, 2, ..., 4K-1], 0, 1, 2, ..., (part_len-1) + + if (!is_persistent_started) { + return LN_TRUE; + } + + if (temp4k_offset + buf_len < SECTOR_SIZE_4KB) { + // just copy all buf data to temp4K_buf + memcpy(temp4K_buf + temp4k_offset, buf, buf_len); + temp4k_offset += buf_len; + part_len = 0; + } + else { + // just copy part of buf to temp4K_buf + part_len = temp4k_offset + buf_len - SECTOR_SIZE_4KB; + memcpy(temp4K_buf + temp4k_offset, buf, buf_len - part_len); + temp4k_offset += buf_len - part_len; + } + if (temp4k_offset >= (SECTOR_SIZE_4KB - 1)) { + // write to flash + ADDLOG_DEBUG(LOG_FEATURE_OTA, "write at flash: 0x%08x\r\n", flash_ota_start_addr + flash_ota_offset); + + if (flash_ota_offset == 0) { + if (LN_TRUE != ota_download_precheck(APP_SPACE_OFFSET, (image_hdr_t *)temp4K_buf)) + { + ADDLOG_DEBUG(LOG_FEATURE_OTA, "ota download precheck failed!\r\n"); + is_precheck_ok = LN_FALSE; + return LN_FALSE; + } + is_precheck_ok = LN_TRUE; + } + + hal_flash_erase(flash_ota_start_addr + flash_ota_offset, SECTOR_SIZE_4KB); + hal_flash_program(flash_ota_start_addr + flash_ota_offset, SECTOR_SIZE_4KB, (uint8_t *)temp4K_buf); + + flash_ota_offset += SECTOR_SIZE_4KB; + memset(temp4K_buf, 0, SECTOR_SIZE_4KB); + temp4k_offset = 0; + } + + if (part_len > 0) { + memcpy(temp4K_buf + temp4k_offset, buf + (buf_len - part_len), part_len); + temp4k_offset += part_len; + } + + return LN_TRUE; +} + +/** + * @brief save last block and clear flags. + * @return return LN_TRUE on success, LN_FALSE on failure. + */ +static int ota_persistent_finish(void) +{ + if (!is_persistent_started) { + return LN_FALSE; + } + + // write to flash + ADDLOG_DEBUG(LOG_FEATURE_OTA, "write at flash: 0x%08x\r\n", flash_ota_start_addr + flash_ota_offset); + hal_flash_erase(flash_ota_start_addr + flash_ota_offset, SECTOR_SIZE_4KB); + hal_flash_program(flash_ota_start_addr + flash_ota_offset, SECTOR_SIZE_4KB, (uint8_t *)temp4K_buf); + + OS_Free(temp4K_buf); + temp4K_buf = NULL; + temp4k_offset = 0; + + flash_ota_offset = 0; + is_persistent_started = LN_FALSE; + return LN_TRUE; +} + +static int update_ota_state(void) +{ + upg_state_t state = UPG_STATE_DOWNLOAD_OK; + ln_nvds_set_ota_upg_state(state); + return LN_TRUE; +} +/** + * @brief check ota image header, body. + * @return return LN_TRUE on success, LN_FALSE on failure. + */ +static int ota_verify_download(void) +{ + image_hdr_t ota_header; + + ADDLOG_DEBUG(LOG_FEATURE_OTA, "Succeed to verify OTA image content.\r\n"); + if (OTA_ERR_NONE != image_header_fast_read(OTA_SPACE_OFFSET, &ota_header)) { + ADDLOG_DEBUG(LOG_FEATURE_OTA, "failed to read ota header.\r\n"); + return LN_FALSE; + } + + if (OTA_ERR_NONE != image_header_verify(&ota_header)) { + ADDLOG_DEBUG(LOG_FEATURE_OTA, "failed to verify ota header.\r\n"); + return LN_FALSE; + } + + if (OTA_ERR_NONE != image_body_verify(OTA_SPACE_OFFSET, &ota_header)) { + ADDLOG_DEBUG(LOG_FEATURE_OTA, "failed to verify ota body.\r\n"); + return LN_FALSE; + } + + ADDLOG_DEBUG(LOG_FEATURE_OTA, "Succeed to verify OTA image content.\r\n"); + return LN_TRUE; +} +#endif + static int http_rest_post_flash(http_request_t* request, int startaddr, int maxaddr) { #if PLATFORM_XR809 || PLATFORM_W800 @@ -1254,8 +1476,7 @@ static int http_rest_post_flash(http_request_t* request, int startaddr, int maxa socket_fwup_err(0, nRetCode); return http_rest_error(request, nRetCode, error_message); } -#elif PLATFORM_LN882H - + #elif PLATFORM_BL602 int sockfd, i; @@ -1360,7 +1581,7 @@ static int http_rest_post_flash(http_request_t* request, int startaddr, int maxa // clamp to available len if (take_len > useLen) take_len = useLen; - printf("Header takes %i. ",take_len); + printf("Header takes %i. ", take_len); memcpy(recv_buffer + buffer_offset, writebuf, take_len); buffer_offset += take_len; useBuf = writebuf + take_len; @@ -1429,6 +1650,60 @@ static int http_rest_post_flash(http_request_t* request, int startaddr, int maxa vPortFree(recv_buffer); utils_sha256_free(&ctx); bl_mtd_close(handle); + +#elif PLATFORM_LN882H + ADDLOG_DEBUG(LOG_FEATURE_OTA, "Ota start!\r\n"); + if (LN_TRUE != ota_persistent_start()) { + ADDLOG_DEBUG(LOG_FEATURE_OTA, "Ota start error, exit...\r\n"); + return 0; + } + + if (request->contentLength >= 0) { + towrite = request->contentLength; + } + + do { + //ADDLOG_DEBUG(LOG_FEATURE_OTA, "%d bytes to write", writelen); + + if (LN_TRUE != ota_persistent_write(writebuf, writelen)) { + // ADDLOG_DEBUG(LOG_FEATURE_OTA, "ota write err.\r\n"); + return -1; + } + + rtos_delay_milliseconds(10); + ADDLOG_DEBUG(LOG_FEATURE_OTA, "Writelen %i at %i", writelen, total); + total += writelen; + startaddr += writelen; + towrite -= writelen; + if (towrite > 0) { + writebuf = request->received; + writelen = recv(request->fd, writebuf, request->receivedLenmax, 0); + if (writelen < 0) { + ADDLOG_DEBUG(LOG_FEATURE_OTA, "recv returned %d - end of data - remaining %d", writelen, towrite); + } + } + } while ((towrite > 0) && (writelen >= 0)); + + ota_persistent_finish(); + is_ready_to_verify = LN_TRUE; + ADDLOG_DEBUG(LOG_FEATURE_OTA, "cb info: recv %d finished, no more data to deal with.\r\n", towrite); + + + ADDLOG_DEBUG(LOG_FEATURE_OTA, "http client job done, exit...\r\n"); + if (LN_TRUE == is_precheck_ok) + { + if ((LN_TRUE == is_ready_to_verify) && (LN_TRUE == ota_verify_download())) { + update_ota_state(); + //ln_chip_reboot(); + } + else { + ADDLOG_DEBUG(LOG_FEATURE_OTA, "Veri bad\r\n"); + } + } + else { + ADDLOG_DEBUG(LOG_FEATURE_OTA, "Precheck bad\r\n"); + } + #else init_ota(startaddr);