esp-open-rtos/extras/http_client_ota/http_client_ota.c
2018-03-01 05:03:44 +05:00

259 lines
7.3 KiB
C

#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "arch/cc.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "lwip/netdb.h"
#include "lwip/dns.h"
#include <espressif/spi_flash.h>
#include <espressif/esp_system.h>
#include <espressif/esp_common.h>
#include <espressif/esp_system.h>
#include "mbedtls/sha256.h"
#include "http_client_ota.h"
#include "rboot-api.h"
#include "rboot.h"
#define MODULE "OTA"
#if defined(DEBUG)
# ifndef MODULE
# error "Module not define"
# endif
# define DEBUG_PRINT(fmt, args ...) \
printf("[%s]\t" fmt "\n", MODULE, ## args)
#else
# define DEBUG_PRINT(fmt, args ...) /* Don't do anything in release builds */
#endif
#define MAX_IMAGE_SIZE 0x100000 /*1MB images max at the moment */
#define READ_BUFFER_LEN 512
#define SHA256_SIZE_BIN 32
#define SHA256_SIZE_STR SHA256_SIZE_BIN * 2
#define SHA256_CONV_STEP_SIZE 4
#if SECTOR_SIZE % READ_BUFFER_LEN != 0
# error "Incompatible SECTOR SIZE, with you current READ_BUFFER"
#endif
#define SECTOR_BUFFER_SIZE (SECTOR_SIZE)
#define vTaskDelayMs(ms) vTaskDelay((ms) / portTICK_PERIOD_MS)
static ota_info *ota_inf;
static mbedtls_sha256_context *sha256_ctx;
static uint32_t flash_offset;
static uint32_t flash_limits;
static unsigned char *SHA256_output;
static uint16_t *SHA256_dowload;
static char *SHA256_str;
static char *SHA256_wrt_ptr;
/**
* CallBack called from Http Buffered client, for ota firmaware
*/
static unsigned int ota_firmaware_dowload_callback(char *buf, uint16_t size)
{
if (ota_inf->sha256_path != NULL)
mbedtls_sha256_update(sha256_ctx, (const unsigned char *) buf, size);
if (flash_offset + size > flash_limits) {
DEBUG_PRINT("Flash Limits override");
return -1;
}
// Ready for flash device, the erase NANDFLASH Block
if (flash_offset % SECTOR_SIZE == 0) {
unsigned int sector;
sector = flash_offset / SECTOR_SIZE;
sdk_spi_flash_erase_sector(sector);
}
// Write into Flash
sdk_spi_flash_write(flash_offset, (uint32_t *) buf, size);
flash_offset += size;
return 1;
}
static unsigned int SHA256_check_callback(char *buf, uint16_t size)
{
int Current_SHA_Size;
// Check that str does not contains other streing with SHA256
if (size > SHA256_SIZE_STR)
size = SHA256_SIZE_STR;
Current_SHA_Size = SHA256_wrt_ptr - (char *) SHA256_str;
if (!(Current_SHA_Size > SHA256_SIZE_STR)) {
memcpy(SHA256_wrt_ptr, buf, size);
SHA256_wrt_ptr += size;
}
return 1;
}
static void convert_SHA256_Str_TO_uint32(char *str, uint16_t *final_sha_bin)
{
char tmp[SHA256_CONV_STEP_SIZE + 1];
char *wrt_ptr;
int i;
wrt_ptr = str;
for (i = 0; i < SHA256_SIZE_STR / SHA256_CONV_STEP_SIZE; i++) {
uint16_t val;
memset(tmp, 0, sizeof(tmp));
memcpy(tmp, wrt_ptr, SHA256_CONV_STEP_SIZE);
val = strtol(tmp, NULL, 16);
final_sha_bin[i] = LWIP_PLATFORM_HTONS(val);
wrt_ptr += SHA256_CONV_STEP_SIZE;
}
}
OTA_err ota_update(ota_info *ota_info_par)
{
Http_client_info http_inf;
rboot_config rboot_config;
HTTP_Client_State err;
int slot;
ota_inf = ota_info_par;
// Malloc memory for work
http_inf.buffer = malloc(SECTOR_BUFFER_SIZE);
http_inf.buffer_size = SECTOR_BUFFER_SIZE;
http_inf.server = ota_inf->server;
http_inf.port = ota_inf->port;
// Check memory alignement, must be aligned
if ((unsigned int) http_inf.buffer % sizeof(unsigned int)) {
DEBUG_PRINT("Malloc return Unaligned memory");
free(http_inf.buffer);
}
if (ota_inf->sha256_path != NULL) {
sha256_ctx = malloc(sizeof(mbedtls_sha256_context));
SHA256_output = malloc(SHA256_SIZE_BIN);
SHA256_dowload = malloc(SHA256_SIZE_BIN);
SHA256_str = malloc(SHA256_SIZE_STR + 1);
SHA256_wrt_ptr = SHA256_str;
SHA256_str[SHA256_SIZE_STR] = '\0';
mbedtls_sha256_init(sha256_ctx);
}
DEBUG_PRINT("HTTP client task starting");
rboot_config = rboot_get_config();
slot = (rboot_config.current_rom + 1) % rboot_config.count;
DEBUG_PRINT("Image will be saved in OTA slot %d", slot);
if (slot == rboot_config.current_rom) {
DEBUG_PRINT("Only one OTA slot is configured!");
err = OTA_ONE_SLOT_ONLY;
goto dealloc_all;
}
/* Validate the OTA slot parameter */
if (rboot_config.current_rom == slot || rboot_config.count <= slot)
DEBUG_PRINT("Current rom set to unknow value:%d", rboot_config.current_rom);
// Calculate room limits
flash_offset = rboot_config.roms[slot];
flash_limits = flash_offset + MAX_IMAGE_SIZE;
if (ota_inf->sha256_path != NULL) {
// Setup for dowload sha256
http_inf.path = ota_inf->sha256_path;
http_inf.final_cb = SHA256_check_callback;
http_inf.buffer_full_cb = SHA256_check_callback;
memset(SHA256_dowload, 0, SHA256_SIZE_BIN);
memset(SHA256_str, 0, SHA256_SIZE_STR);
err = HttpClient_dowload(&http_inf);
// Check if dowload success
if (err != HTTP_OK)
goto dealloc_all;
convert_SHA256_Str_TO_uint32(SHA256_str, SHA256_dowload);
}
// Ping Wdog
vTaskDelayMs(250);
// Dowload Firmaware
http_inf.path = ota_inf->binary_path;
http_inf.final_cb = ota_firmaware_dowload_callback;
http_inf.buffer_full_cb = ota_firmaware_dowload_callback;
if (ota_inf->sha256_path != NULL)
mbedtls_sha256_starts(sha256_ctx, 0); // Start SHA256, not SHA224
err = HttpClient_dowload(&http_inf);
if (err != HTTP_OK)
goto dealloc_all;
if (ota_inf->sha256_path != NULL) {
char com_res;
mbedtls_sha256_finish(sha256_ctx, SHA256_output);
mbedtls_sha256_free(sha256_ctx);
com_res = !memcmp((void *) SHA256_output, (void *) SHA256_dowload, SHA256_SIZE_BIN);
if (!com_res) {
DEBUG_PRINT("SHA256 is not equal");
err = HTTP_SHA_DONT_MATCH;
goto dealloc_all;
}
}
// Ping watch DOG
vTaskDelayMs(500);
{
#define MESSAGE_MAX 120
unsigned int Rboot_verified, boot_dimension;
char error_message[MESSAGE_MAX];
memset(error_message, 0, sizeof(error_message));
// Start verify
Rboot_verified = rboot_verify_image(rboot_config.roms[slot], &boot_dimension, (const char **) &error_message);
if (Rboot_verified) {
// Rom OK, call final callback for let inform user that all is ready for switch and reset.
vPortEnterCritical();
if (!rboot_set_current_rom(slot)) {
vPortExitCritical();
err = OTA_FAIL_SET_NEW_SLOT;
goto dealloc_all;
}
vPortExitCritical();
// Update success, software return HTTP_200
err = OTA_UPDATE_DONE;
goto dealloc_all;
} else {
DEBUG_PRINT("%s", error_message);
err = OTA_IMAGE_VERIFY_FALLIED;
goto dealloc_all;
}
}
dealloc_all:
free(http_inf.buffer);
if (ota_inf->sha256_path != NULL) {
free(sha256_ctx);
free(SHA256_str);
free(SHA256_output);
free(SHA256_dowload);
}
return err;
} /* ota_update */