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