Skip to content

Commit

Permalink
Merge pull request #53 from arduino/nina-download-ota
Browse files Browse the repository at this point in the history
Add 'downloadOTA' command to download OTA file and verify length/CRC
  • Loading branch information
aentinger committed Aug 6, 2020
2 parents 83b0d10 + ec7c1c8 commit d4a2118
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 27 deletions.
157 changes: 155 additions & 2 deletions main/CommandHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@

#include "CommandHandler.h"

#include "esp_log.h"

const char FIRMWARE_VERSION[6] = "1.4.0";

/*IPAddress*/uint32_t resolvedHostname;
Expand Down Expand Up @@ -1315,12 +1317,163 @@ int downloadFile(const uint8_t command[], uint8_t response[]) {
memcpy(&filename[strlen("/fs/")], &command[5 + command[3]], command[4 + command[3]]);

FILE* f = fopen(filename, "w");
downloadAndSaveFile(url, filename, f);
downloadAndSaveFile(url, f, 0);
fclose(f);

return 0;
}

/**
* Static table used for the table_driven implementation.
*/
static const uint32_t crc_table[256] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};

uint32_t crc_update(uint32_t crc, const void * data, size_t data_len)
{
const unsigned char *d = (const unsigned char *)data;
unsigned int tbl_idx;

while (data_len--) {
tbl_idx = (crc ^ *d) & 0xff;
crc = (crc_table[tbl_idx] ^ (crc >> 8)) & 0xffffffff;
d++;
}

return crc & 0xffffffff;
}

int downloadOTA(const uint8_t command[], uint8_t response[])
{
static const char * OTA_TAG = "OTA";
static const char * OTA_FILE = "/fs/UPDATE.BIN.LZSS";
static const char * OTA_TEMP_FILE = "/fs/UPDATE.BIN.LZSS.TMP";

typedef enum OTA_Error {
ERR_NO_ERROR = 0,
ERR_OPEN = 1,
ERR_LENGTH = 2,
ERR_CRC = 3,
ERR_RENAME = 4,
};

union {
struct __attribute__((packed)) {
uint32_t len;
uint32_t crc32;
} header;
uint8_t buf[sizeof(header)];
} ota_header;

int ota_size, c;
uint32_t crc32;

/* Retrieve the URL parameter. */
char url[128 + 1];
memset(url, 0, sizeof(url));
memcpy(url, &command[4], command[3]);
ESP_LOGI(OTA_TAG, "url: %s", url);

/* Set up the response packet. */
response[2] = 1; /* Number of parameters */
response[3] = 1; /* Length of parameter 1 */
response[4] = ERR_NO_ERROR; /* The actual payload */

/* Download the OTA file */
FILE * f = fopen(OTA_TEMP_FILE, "w+");
if (!f) {
ESP_LOGE(OTA_TAG, "fopen(..., \"w+\") error: %d", ferror(f));
response[4] = ERR_OPEN;
goto ota_cleanup;
}
downloadAndSaveFile(url, f, 0);

/* Determine size of downloaded file. */
ota_size = ftell(f) - sizeof(ota_header.buf);
/* Reposition file pointer at start of file. */
rewind(f);
/* Read the OTA header. */
fread(ota_header.buf, sizeof(ota_header.buf), 1, f);
ESP_LOGI(OTA_TAG, "ota image length = %d", ota_header.header.len);
ESP_LOGI(OTA_TAG, "ota image crc32 = %X", ota_header.header.crc32);

/* Check length. */
if (ota_header.header.len != ota_size) {
ESP_LOGE(OTA_TAG, "error ota length: expected %d, actual %d", ota_header.header.len, ota_size);
response[4] = ERR_LENGTH;
goto ota_cleanup;
}

/* Init CRC */
crc32 = 0xFFFFFFFF;
/* Calculate CRC */
c = fgetc(f);
while (c != EOF) {
crc32 = crc_update(crc32, &c, 1);
c = fgetc(f);
}
/* Finalise CRC */
crc32 ^= 0xFFFFFFFF;

/* Check CRC. */
if (ota_header.header.crc32 != crc32) {
ESP_LOGE(OTA_TAG, "error ota crc: expected %X, actual %X", ota_header.header.crc32, crc32);
response[4] = ERR_CRC;
goto ota_cleanup;
}

/* Close the file. */
fclose(f);

/* Rename in case of success. */
errno = 0;
rename(OTA_TEMP_FILE, OTA_FILE);
if (errno) {
ESP_LOGE(OTA_TAG, "rename(...) error: %d", errno);
response[4] = ERR_RENAME;
goto ota_cleanup;
}

return 6;

ota_cleanup:
fclose(f);
unlink(OTA_TEMP_FILE);
return 6;
}

typedef int (*CommandHandlerType)(const uint8_t command[], uint8_t response[]);

const CommandHandlerType commandHandlers[] = {
Expand All @@ -1343,7 +1496,7 @@ const CommandHandlerType commandHandlers[] = {
setPinMode, setDigitalWrite, setAnalogWrite, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,

// 0x60 -> 0x6f
writeFile, readFile, deleteFile, existsFile, downloadFile, applyOTA, renameFile, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
writeFile, readFile, deleteFile, existsFile, downloadFile, applyOTA, renameFile, downloadOTA, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
};

#define NUM_COMMAND_HANDLERS (sizeof(commandHandlers) / sizeof(commandHandlers[0]))
Expand Down
2 changes: 1 addition & 1 deletion main/CommandHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,6 @@ class CommandHandlerClass {

extern CommandHandlerClass CommandHandler;

extern "C" int downloadAndSaveFile(char* url, char* filename, FILE* f);
extern "C" int downloadAndSaveFile(char * url, FILE * f, const char * cert_pem);

#endif
32 changes: 8 additions & 24 deletions main/http_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,46 +8,28 @@

#define MAX_HTTP_RECV_BUFFER 128

static const char* TAG = "HTTP_HANDLER";
static const char* TAG = "HTTP_CLIENT";

static esp_err_t _http_event_handler(esp_http_client_event_t *evt)
int downloadAndSaveFile(char * url, FILE * f, const char * cert_pem)
{
switch(evt->event_id) {
case HTTP_EVENT_ERROR:
case HTTP_EVENT_ON_CONNECTED:
case HTTP_EVENT_HEADER_SENT:
case HTTP_EVENT_ON_FINISH:
case HTTP_EVENT_DISCONNECTED:
case HTTP_EVENT_ON_HEADER:
break;
case HTTP_EVENT_ON_DATA:
if (!esp_http_client_is_chunked_response(evt->client)) {
//fwrite((char*)evt->data, sizeof(uint8_t), evt->data_len, (FILE*)evt->user_data);
}
break;
}
return ESP_OK;
}

int downloadAndSaveFile(char* url, char* filename, FILE* f) {

char *buffer = (char*)malloc(MAX_HTTP_RECV_BUFFER);
if (buffer == NULL) {
return -1;
}
esp_http_client_config_t config = {
.url = url,
.event_handler = _http_event_handler,
.user_data = f,
.cert_pem = cert_pem,
.timeout_ms = 20000,
};

esp_http_client_handle_t client = esp_http_client_init(&config);
esp_err_t err;
if ((err = esp_http_client_open(client, 0)) != ESP_OK) {
ESP_LOGE(TAG, "esp_http_client_open failed: %d", err);
free(buffer);
return -1;
}
int content_length = esp_http_client_fetch_headers(client);
int content_length = esp_http_client_fetch_headers(client);
int total_read_len = 0, read_len;
while (total_read_len < content_length) {
read_len = esp_http_client_read(client, buffer, MAX_HTTP_RECV_BUFFER);
Expand All @@ -56,7 +38,9 @@ int downloadAndSaveFile(char* url, char* filename, FILE* f) {
break;
}
total_read_len += read_len;
ESP_LOGV(TAG, "esp_http_client_read data received: %d, total %d", read_len, total_read_len);
}
ESP_LOGV(TAG, "connection closed, cleaning up, total %d bytes received", total_read_len);
esp_http_client_close(client);
esp_http_client_cleanup(client);
free(buffer);
Expand Down

0 comments on commit d4a2118

Please sign in to comment.