Http client OTA (#553)
This commit is contained in:
parent
33082ba2c9
commit
b77380bad1
9 changed files with 712 additions and 0 deletions
4
examples/http_client_ota/Makefile
Normal file
4
examples/http_client_ota/Makefile
Normal file
|
@ -0,0 +1,4 @@
|
|||
PROGRAM=http_ota
|
||||
EXTRA_COMPONENTS=extras/rboot-ota extras/mbedtls extras/http_client_ota
|
||||
|
||||
include ../../common.mk
|
134
examples/http_client_ota/http_get.c
Normal file
134
examples/http_client_ota/http_get.c
Normal file
|
@ -0,0 +1,134 @@
|
|||
#include "espressif/esp_common.h"
|
||||
#include "esp/uart.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
#include "http_client_ota.h"
|
||||
#include "ssid_config.h"
|
||||
|
||||
#define vTaskDelayMs(ms) vTaskDelay((ms) / portTICK_PERIOD_MS)
|
||||
|
||||
/*
|
||||
* How to test
|
||||
* cd test_file
|
||||
* python -m SimpleHTTPServer 8080
|
||||
* fill missing define SERVER and PORT, in your private_ssid_config.h
|
||||
* Ready for test.
|
||||
*/
|
||||
|
||||
|
||||
#define BINARY_PATH "/blink.bin"
|
||||
#define SHA256_PATH "/blink.sha256"
|
||||
|
||||
// Default
|
||||
#define SERVER "192.168.1.30"
|
||||
#define PORT "8080"
|
||||
|
||||
#ifndef SERVER
|
||||
#error "Server address is not defined define it:`192.168.X.X`"
|
||||
#endif
|
||||
|
||||
#ifndef PORT
|
||||
#error "Port is not defined example:`8080`"
|
||||
#endif
|
||||
|
||||
static inline void ota_error_handling(OTA_err err) {
|
||||
printf("Error:");
|
||||
|
||||
switch(err) {
|
||||
case OTA_DNS_LOOKUP_FALLIED:
|
||||
printf("DNS lookup has fallied\n");
|
||||
break;
|
||||
case OTA_SOCKET_ALLOCATION_FALLIED:
|
||||
printf("Impossible allocate required socket\n");
|
||||
break;
|
||||
case OTA_SOCKET_CONNECTION_FALLIED:
|
||||
printf("Server unreachable, impossible connect\n");
|
||||
break;
|
||||
case OTA_SHA_DONT_MATCH:
|
||||
printf("Sha256 sum does not fit downloaded sha256\n");
|
||||
break;
|
||||
case OTA_REQUEST_SEND_FALLIED:
|
||||
printf("Impossible send HTTP request\n");
|
||||
break;
|
||||
case OTA_DOWLOAD_SIZE_NOT_MATCH:
|
||||
printf("Dowload size don't match with server declared size\n");
|
||||
break;
|
||||
case OTA_ONE_SLOT_ONLY:
|
||||
printf("rboot has only one slot configured, impossible switch it\n");
|
||||
break;
|
||||
case OTA_FAIL_SET_NEW_SLOT:
|
||||
printf("rboot cannot switch between rom\n");
|
||||
break;
|
||||
case OTA_IMAGE_VERIFY_FALLIED:
|
||||
printf("Dowloaded image binary checsum is fallied\n");
|
||||
break;
|
||||
case OTA_UPDATE_DONE:
|
||||
printf("Ota has completed upgrade process, all ready for system software reset\n");
|
||||
break;
|
||||
case OTA_HTTP_OK:
|
||||
printf("HTTP server has response 200, Ok\n");
|
||||
break;
|
||||
case OTA_HTTP_NOTFOUND:
|
||||
printf("HTTP server has response 404, file not found\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void ota_task(void *PvParameter)
|
||||
{
|
||||
// Wait until we have joined AP and are assigned an IP *
|
||||
while (sdk_wifi_station_get_connect_status() != STATION_GOT_IP)
|
||||
vTaskDelayMs(100);
|
||||
|
||||
while (1) {
|
||||
OTA_err err;
|
||||
// Remake this task until ota work
|
||||
err = ota_update((ota_info *) PvParameter);
|
||||
|
||||
ota_error_handling(err);
|
||||
|
||||
if(err != OTA_UPDATE_DONE) {
|
||||
vTaskDelayMs(1000);
|
||||
printf("\n\n\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
vTaskDelayMs(1000);
|
||||
printf("Delay 1\n");
|
||||
vTaskDelayMs(1000);
|
||||
printf("Delay 2\n");
|
||||
vTaskDelayMs(1000);
|
||||
printf("Delay 3\n");
|
||||
|
||||
printf("Reset\n");
|
||||
sdk_system_restart();
|
||||
}
|
||||
}
|
||||
|
||||
static ota_info info = {
|
||||
.server = SERVER,
|
||||
.port = PORT,
|
||||
.binary_path = BINARY_PATH,
|
||||
.sha256_path = SHA256_PATH,
|
||||
};
|
||||
|
||||
void user_init(void)
|
||||
{
|
||||
uart_set_baud(0, 115200);
|
||||
printf("SDK version:%s\n", sdk_system_get_sdk_version());
|
||||
|
||||
struct sdk_station_config config = {
|
||||
.ssid = WIFI_SSID,
|
||||
.password = WIFI_PASS,
|
||||
};
|
||||
|
||||
/* required to call wifi_set_opmode before station_set_config */
|
||||
sdk_wifi_set_opmode(STATION_MODE);
|
||||
sdk_wifi_station_set_config(&config);
|
||||
|
||||
xTaskCreate(ota_task, "get_task", 4096, &info, 2, NULL);
|
||||
}
|
BIN
examples/http_client_ota/test_file/blink.bin
Normal file
BIN
examples/http_client_ota/test_file/blink.bin
Normal file
Binary file not shown.
1
examples/http_client_ota/test_file/blink.sha256
Normal file
1
examples/http_client_ota/test_file/blink.sha256
Normal file
|
@ -0,0 +1 @@
|
|||
57dda900027355de85f0de9e6c966e3c4c16741d8eed134d209c0fb6304cf852
|
10
extras/http_client_ota/component.mk
Normal file
10
extras/http_client_ota/component.mk
Normal file
|
@ -0,0 +1,10 @@
|
|||
# Component makefile for extras/http_client_ota
|
||||
|
||||
# Expected anyone using http_client_ota includes it as 'http_client_ota/ota'
|
||||
INC_DIRS += $(http_client_ota_ROOT)
|
||||
|
||||
# args for passing into compile rule generation
|
||||
http_client_ota_INC_DIR = $(http_client_ota_ROOT)
|
||||
http_client_ota_SRC_DIR = $(http_client_ota_ROOT)
|
||||
|
||||
$(eval $(call component_compile_rules,http_client_ota))
|
219
extras/http_client_ota/http_buffered_client.c
Normal file
219
extras/http_client_ota/http_buffered_client.c
Normal file
|
@ -0,0 +1,219 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/sockets.h"
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/netdb.h"
|
||||
#include "lwip/dns.h"
|
||||
|
||||
#include "http_buffered_client.h"
|
||||
|
||||
#define MAX_REQUEST_SIZE (152 / sizeof(uint32_t))
|
||||
#define vTaskDelayMs(ms) vTaskDelay((ms) / portTICK_PERIOD_MS)
|
||||
|
||||
typedef void (*handle_http_token)(char *);
|
||||
|
||||
struct http_token_table {
|
||||
char * token;
|
||||
handle_http_token http_tock_cb;
|
||||
};
|
||||
|
||||
// Response struct
|
||||
struct HTTP_response {
|
||||
unsigned int response_code;
|
||||
unsigned int length;
|
||||
};
|
||||
|
||||
/**
|
||||
* \addtogroup http_buffer_client_internal
|
||||
* Http Request
|
||||
*/
|
||||
const char *req =
|
||||
"GET %s HTTP/1.1\r\n"
|
||||
"Host: %s \r\n"
|
||||
"User-Agent: esp-open-rtos/0.1 esp8266\r\n"
|
||||
"Connection: close\r\n"
|
||||
"\r\n";
|
||||
|
||||
static uint32_t request[MAX_REQUEST_SIZE];
|
||||
|
||||
static const struct addrinfo hints = {
|
||||
.ai_family = AF_UNSPEC,
|
||||
.ai_socktype = SOCK_STREAM,
|
||||
};
|
||||
|
||||
static struct HTTP_response http_reponse;
|
||||
|
||||
// HTTP Header Token, add here function and then register it in HTTP Table callback
|
||||
static void http_handle_cb_ContentLength(char *token)
|
||||
{
|
||||
token += 16; // strlen("Content-Length:"), skip useless part
|
||||
while (*token) {
|
||||
if (isdigit((int) *token))
|
||||
http_reponse.length = (unsigned int) strtol(token, &token, 10);
|
||||
else
|
||||
token++;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void parse_http_header_HTTP_STATUS(char *token)
|
||||
{
|
||||
token += 8; // Skip HTTP/1.0
|
||||
|
||||
while (*token) {
|
||||
if (isdigit((int) *token))
|
||||
http_reponse.response_code = (unsigned int) strtol(token, &token, 10);
|
||||
else
|
||||
token++;
|
||||
}
|
||||
}
|
||||
|
||||
// HTTP Token Hanling callback
|
||||
struct http_token_table HTTP_HEADER_TOKEN[] = {
|
||||
{ .token = "Content-Length", .http_tock_cb = http_handle_cb_ContentLength },
|
||||
};
|
||||
|
||||
static inline void parse_http_header(char *header)
|
||||
{
|
||||
char *str1, *str2, *token, *subtoken, *saveptr1, *saveptr2;
|
||||
const char line_split[] = "\r\n", sub_chart[] = ":";
|
||||
unsigned int j, i;
|
||||
|
||||
for (j = 1, str1 = header;; j++, str1 = NULL) {
|
||||
token = strtok_r(str1, line_split, &saveptr1);
|
||||
if (token == NULL)
|
||||
break;
|
||||
|
||||
str2 = token;
|
||||
subtoken = strtok_r(str2, sub_chart, &saveptr2);
|
||||
if (subtoken == NULL)
|
||||
break;
|
||||
|
||||
if (j == 1) {
|
||||
// Is HTTP Header, response, HTTP Version and status
|
||||
parse_http_header_HTTP_STATUS(token);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i = 0; i < sizeof(HTTP_HEADER_TOKEN) / sizeof(struct http_token_table); i++)
|
||||
if (!strcmp(subtoken, HTTP_HEADER_TOKEN[i].token))
|
||||
HTTP_HEADER_TOKEN[i].http_tock_cb(token);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
HTTP_Client_State HttpClient_dowload(Http_client_info *info)
|
||||
{
|
||||
struct addrinfo *res;
|
||||
unsigned int tot_http_pdu_rd, read_byte, full;
|
||||
int err, sock;
|
||||
char *wrt_ptr;
|
||||
|
||||
err = getaddrinfo(info->server, info->port, &hints, &res);
|
||||
|
||||
if (err != 0 || res == NULL) {
|
||||
if (res)
|
||||
freeaddrinfo(res);
|
||||
return HTTP_DNS_LOOKUP_FALLIED;
|
||||
}
|
||||
|
||||
sock = socket(res->ai_family, res->ai_socktype, 0);
|
||||
if (sock < 0) {
|
||||
freeaddrinfo(res);
|
||||
return HTTP_SOCKET_ALLOCATION_FALLIED;
|
||||
}
|
||||
|
||||
if (connect(sock, res->ai_addr, res->ai_addrlen) != 0) {
|
||||
close(sock);
|
||||
freeaddrinfo(res);
|
||||
return HTTP_SOCKET_CONNECTION_FALLIED;
|
||||
}
|
||||
|
||||
// Release address memory
|
||||
freeaddrinfo(res);
|
||||
|
||||
// Alloc memory for request
|
||||
sprintf((char *) request, req, info->path, info->server);
|
||||
if (write(sock, (char *) request, strlen((char *) request)) < 0) {
|
||||
close(sock);
|
||||
return HTTP_REQUEST_SEND_FALLIED;
|
||||
}
|
||||
|
||||
tot_http_pdu_rd = 0;
|
||||
wrt_ptr = info->buffer;
|
||||
full = 0;
|
||||
|
||||
// Ping wdog
|
||||
vTaskDelayMs(250);
|
||||
do {
|
||||
int free_buff_space;
|
||||
|
||||
free_buff_space = info->buffer_size - full;
|
||||
read_byte = read(sock, wrt_ptr, free_buff_space);
|
||||
|
||||
// Update buffer property
|
||||
wrt_ptr += read_byte;
|
||||
full += read_byte;
|
||||
|
||||
if (tot_http_pdu_rd == 0) {
|
||||
// Is fist chunk, then it contains http header, parse it.
|
||||
unsigned int header_len, pdu_size;
|
||||
char *header, *pdu;
|
||||
|
||||
pdu = strstr(info->buffer, "\r\n\r\n");
|
||||
|
||||
if (pdu != NULL)
|
||||
pdu += 4; // Offset by 4 bytes to start of content
|
||||
else // Not all HTTP Header has been read, then continue read
|
||||
continue;
|
||||
|
||||
header_len = pdu - info->buffer + 4;
|
||||
|
||||
header = malloc(header_len + 1); // NULL string terminator
|
||||
|
||||
memset(header, 0, header_len + 1);
|
||||
memcpy(header, info->buffer, header_len);
|
||||
|
||||
parse_http_header(header);
|
||||
// Release useless memory
|
||||
free(header);
|
||||
|
||||
// Move memory
|
||||
pdu_size = wrt_ptr - pdu;
|
||||
|
||||
memmove(info->buffer, pdu, pdu_size);
|
||||
wrt_ptr = (info->buffer + pdu_size);
|
||||
|
||||
full = pdu_size;
|
||||
tot_http_pdu_rd = pdu_size;
|
||||
|
||||
if (http_reponse.response_code != HTTP_OK)
|
||||
goto err_label;
|
||||
|
||||
continue;
|
||||
}
|
||||
tot_http_pdu_rd += read_byte;
|
||||
|
||||
if (full == info->buffer_size) {
|
||||
info->buffer_full_cb(info->buffer, full);
|
||||
|
||||
memset(info->buffer, 0, info->buffer_size);
|
||||
wrt_ptr = info->buffer;
|
||||
full = 0;
|
||||
vTaskDelayMs(50);
|
||||
}
|
||||
} while (read_byte > 0);
|
||||
|
||||
info->final_cb(info->buffer, full);
|
||||
if (tot_http_pdu_rd != http_reponse.length)
|
||||
http_reponse.response_code = HTTP_DOWLOAD_SIZE_NOT_MATCH;
|
||||
|
||||
err_label:
|
||||
close(sock);
|
||||
return http_reponse.response_code;
|
||||
} /* HttpClient_dowload */
|
29
extras/http_client_ota/http_buffered_client.h
Normal file
29
extras/http_client_ota/http_buffered_client.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#ifndef HTTP_BUFFERED_CLIENT
|
||||
#define HTTP_BUFFERED_CLIENT
|
||||
|
||||
typedef unsigned int (*http_final_cb)(char *buff, uint16_t size);
|
||||
|
||||
typedef enum {
|
||||
HTTP_DNS_LOOKUP_FALLIED = 1,
|
||||
HTTP_SOCKET_ALLOCATION_FALLIED = 2,
|
||||
HTTP_SOCKET_CONNECTION_FALLIED = 3,
|
||||
HTTP_SHA_DONT_MATCH = 4,
|
||||
HTTP_REQUEST_SEND_FALLIED = 5,
|
||||
HTTP_DOWLOAD_SIZE_NOT_MATCH = 6,
|
||||
HTTP_OK = 200,
|
||||
HTTP_NOTFOUND = 404,
|
||||
} HTTP_Client_State;
|
||||
|
||||
typedef struct {
|
||||
char * server;
|
||||
char * port;
|
||||
char * path;
|
||||
char * buffer;
|
||||
uint16_t buffer_size;
|
||||
http_final_cb buffer_full_cb;
|
||||
http_final_cb final_cb;
|
||||
} Http_client_info;
|
||||
|
||||
HTTP_Client_State HttpClient_dowload(Http_client_info *info);
|
||||
|
||||
#endif // ifndef HTTP_BUFFERED_CLIENT
|
259
extras/http_client_ota/http_client_ota.c
Normal file
259
extras/http_client_ota/http_client_ota.c
Normal file
|
@ -0,0 +1,259 @@
|
|||
#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 */
|
56
extras/http_client_ota/http_client_ota.h
Normal file
56
extras/http_client_ota/http_client_ota.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
#ifndef HTTP_OTA_H
|
||||
#define HTTP_OTA_H
|
||||
|
||||
/**
|
||||
* @file ota_update.h
|
||||
* @author Andrea Greco <a.greco@4sigma.it>
|
||||
* @brief File containing struct and function ota update
|
||||
* File containing struct and function ota update.
|
||||
* Ota use remote HTTP server in internet, for dowload Firmaware and sha256 file.
|
||||
* Firmaware is compiled file stripped, contained in folder firmaware.
|
||||
* Sha256 is a file that contains a sha256, of Firmaware.
|
||||
* If enabled 256 is checked during firmaware download.
|
||||
*/
|
||||
#include "http_buffered_client.h"
|
||||
|
||||
typedef enum {
|
||||
// Keep this aligned with \ref HTTP_Client_State
|
||||
OTA_DNS_LOOKUP_FALLIED = HTTP_DNS_LOOKUP_FALLIED,/**< DNS lookup has fallied */
|
||||
OTA_SOCKET_ALLOCATION_FALLIED = HTTP_SOCKET_ALLOCATION_FALLIED,/**< Impossible allocate required socket */
|
||||
OTA_SOCKET_CONNECTION_FALLIED = HTTP_SOCKET_CONNECTION_FALLIED,/**< Server unreachable, impossible connect */
|
||||
OTA_SHA_DONT_MATCH = HTTP_SHA_DONT_MATCH,/** Sha256 sum does not fit downloaded sha256 */
|
||||
OTA_REQUEST_SEND_FALLIED = HTTP_REQUEST_SEND_FALLIED,/**< Impossible send HTTP request */
|
||||
OTA_DOWLOAD_SIZE_NOT_MATCH = HTTP_DOWLOAD_SIZE_NOT_MATCH, /**< Dowload size don't match with server declared size */
|
||||
|
||||
// Ota error
|
||||
OTA_ONE_SLOT_ONLY = 20,/**< rboot has only one slot configured, impossible switch it */
|
||||
OTA_FAIL_SET_NEW_SLOT = 21,/**< rboot cannot switch between rom */
|
||||
OTA_IMAGE_VERIFY_FALLIED = 22,/**< Dowloaded image binary checsum is fallied */
|
||||
OTA_UPDATE_DONE = 23, /**< Ota has completed upgrade process, all ready for system software reset */
|
||||
|
||||
OTA_HTTP_OK = 200,/** HTTP server has response 200, Ok */
|
||||
OTA_HTTP_NOTFOUND = 404,/** HTTP server has response 404, file not found */
|
||||
} OTA_err;
|
||||
|
||||
|
||||
/**
|
||||
* \brief Create ota info.
|
||||
* Struct that contains all info for start ota.
|
||||
*/
|
||||
typedef struct {
|
||||
char *server; /**< Server domain */
|
||||
char *port; /**< Server port */
|
||||
char *binary_path; /**< Server Path dowload new update binary */
|
||||
char *sha256_path; /**< Server Path of SHA256 sum for check binary, could be NULL, check will be skipped */
|
||||
} ota_info;
|
||||
|
||||
/**
|
||||
* \brief Start ota update.
|
||||
* Start Ota update.
|
||||
* Ota_info contains all information about file to download, port, server.
|
||||
* \param ota_info_par ptr to ota info.
|
||||
* In case of success, and ota update is right done, \ref finish_cb is called before ESP8266 reset.
|
||||
* \return http server return Code, check out \ref HTTP_Client_State for all code.
|
||||
*/
|
||||
OTA_err ota_update(ota_info *ota_info_par);
|
||||
#endif // ifndef HTTP_OTA_H
|
Loading…
Reference in a new issue