Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix OTA binary header download timeout #15

Merged
merged 4 commits into from
Oct 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .github/workflows/compile-examples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ jobs:
libraries: |
- name: Arduino_DebugUtils
sketch-paths: |
- examples/OTA
- examples/OTA_Arduino_Server
- examples/OTA_GitHub_Server
- examples/LOLIN_32_Blink
- board:
type: arduino_esp32
Expand All @@ -58,7 +59,8 @@ jobs:
libraries: |
- name: Arduino_DebugUtils
sketch-paths: |
- examples/OTA
- examples/OTA_Arduino_Server
- examples/OTA_GitHub_Server
- examples/NANO_ESP32_Blink

steps:
Expand Down
Binary file added examples/LOLIN_32_Blink/LOLIN_32_Blink.ino.ota
Binary file not shown.
Binary file not shown.
File renamed without changes.
File renamed without changes.
115 changes: 115 additions & 0 deletions examples/OTA_GitHub_Server/OTA_GitHub_Server.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* This example demonstrates how to use to update the firmware using Arduino_ESP_OTA library
*
* Steps:
* 1) Create a sketch for your ESP board and verify
* that it both compiles and works.
* 2) In the IDE select: Sketch -> Export compiled Binary.
* 3) Create an OTA update file utilising the tools 'lzss.py' and 'bin2ota.py' stored in
* https://github.com/arduino-libraries/ArduinoIoTCloud/tree/master/extras/tools .
* A) ./lzss.py --encode SKETCH.bin SKETCH.lzss
* B) ./bin2ota.py ESP SKETCH.lzss SKETCH.ota
* 4) Upload the OTA file to a network reachable location, e.g. LOLIN_32_Blink.ino.ota
* has been uploaded to: http://downloads.arduino.cc/ota/LOLIN_32_Blink.ino.ota
* 5) Verify if a custom ca_cert is needed by default Amazon root CA are used
* https://www.amazontrust.com/repository/
* 6) Perform an OTA update via steps outlined below.
*/

/******************************************************************************
* INCLUDE
******************************************************************************/

#include <Arduino_ESP32_OTA.h>

#include <WiFi.h>

#include "arduino_secrets.h"

#include "root_ca.h"

/******************************************************************************
* CONSTANT
******************************************************************************/

/* Please enter your sensitive data in the Secret tab/arduino_secrets.h */
static char const SSID[] = SECRET_SSID; /* your network SSID (name) */
static char const PASS[] = SECRET_PASS; /* your network password (use for WPA, or use as key for WEP) */


#if defined(ARDUINO_NANO_ESP32)
static char const OTA_FILE_LOCATION[] = "https://raw.githubusercontent.com/arduino-libraries/Arduino_ESP32_OTA/main/examples/NANO_ESP32_Blink/NANO_ESP32_Blink.ino.ota";
#else
static char const OTA_FILE_LOCATION[] = "https://raw.githubusercontent.com/arduino-libraries/Arduino_ESP32_OTA/main/examples/LOLIN_32_Blink/LOLIN_32_Blink.ino.ota";
#endif

/******************************************************************************
* SETUP/LOOP
******************************************************************************/

void setup()
{
Serial.begin(9600);
while (!Serial) {}

while (WiFi.status() != WL_CONNECTED)
{
Serial.print ("Attempting to connect to '");
Serial.print (SSID);
Serial.println("'");
WiFi.begin(SSID, PASS);
delay(2000);
}
Serial.print ("You're connected to '");
Serial.print (WiFi.SSID());
Serial.println("'");

Arduino_ESP32_OTA ota;
Arduino_ESP32_OTA::Error ota_err = Arduino_ESP32_OTA::Error::None;

/* Configure custom Root CA */
ota.setCACert(root_ca);

Serial.println("Initializing OTA storage");
if ((ota_err = ota.begin()) != Arduino_ESP32_OTA::Error::None)
{
Serial.print ("Arduino_ESP_OTA::begin() failed with error code ");
Serial.println((int)ota_err);
return;
}


Serial.println("Starting download to flash ...");
int const ota_download = ota.download(OTA_FILE_LOCATION);
if (ota_download <= 0)
{
Serial.print ("Arduino_ESP_OTA::download failed with error code ");
Serial.println(ota_download);
return;
}
Serial.print (ota_download);
Serial.println(" bytes stored.");


Serial.println("Verify update integrity and apply ...");
if ((ota_err = ota.update()) != Arduino_ESP32_OTA::Error::None)
{
Serial.print ("ota.update() failed with error code ");
Serial.println((int)ota_err);
return;
}

Serial.println("Performing a reset after which the bootloader will start the new firmware.");
#if defined(ARDUINO_NANO_ESP32)
Serial.println("Hint: Arduino NANO ESP32 will blink Red Green and Blue.");
#else
Serial.println("Hint: LOLIN32 will blink Blue.");
#endif
delay(1000); /* Make sure the serial message gets out before the reset. */
ota.reset();
}

void loop()
{

}
2 changes: 2 additions & 0 deletions examples/OTA_GitHub_Server/arduino_secrets.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#define SECRET_SSID ""
#define SECRET_PASS ""
55 changes: 55 additions & 0 deletions examples/OTA_GitHub_Server/root_ca.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
const char* root_ca = \
/*DigiCert TLS Hybrid ECC SHA384 2020 CA1*/
"-----BEGIN CERTIFICATE-----\n" \
"MIIEFzCCAv+gAwIBAgIQB/LzXIeod6967+lHmTUlvTANBgkqhkiG9w0BAQwFADBh\n" \
"MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" \
"d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD\n" \
"QTAeFw0yMTA0MTQwMDAwMDBaFw0zMTA0MTMyMzU5NTlaMFYxCzAJBgNVBAYTAlVT\n" \
"MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxMDAuBgNVBAMTJ0RpZ2lDZXJ0IFRMUyBI\n" \
"eWJyaWQgRUNDIFNIQTM4NCAyMDIwIENBMTB2MBAGByqGSM49AgEGBSuBBAAiA2IA\n" \
"BMEbxppbmNmkKaDp1AS12+umsmxVwP/tmMZJLwYnUcu/cMEFesOxnYeJuq20ExfJ\n" \
"qLSDyLiQ0cx0NTY8g3KwtdD3ImnI8YDEe0CPz2iHJlw5ifFNkU3aiYvkA8ND5b8v\n" \
"c6OCAYIwggF+MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFAq8CCkXjKU5\n" \
"bXoOzjPHLrPt+8N6MB8GA1UdIwQYMBaAFAPeUDVW0Uy7ZvCj4hsbw5eyPdFVMA4G\n" \
"A1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwdgYI\n" \
"KwYBBQUHAQEEajBoMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5j\n" \
"b20wQAYIKwYBBQUHMAKGNGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdp\n" \
"Q2VydEdsb2JhbFJvb3RDQS5jcnQwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2Ny\n" \
"bDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNybDA9BgNVHSAE\n" \
"NjA0MAsGCWCGSAGG/WwCATAHBgVngQwBATAIBgZngQwBAgEwCAYGZ4EMAQICMAgG\n" \
"BmeBDAECAzANBgkqhkiG9w0BAQwFAAOCAQEAR1mBf9QbH7Bx9phdGLqYR5iwfnYr\n" \
"6v8ai6wms0KNMeZK6BnQ79oU59cUkqGS8qcuLa/7Hfb7U7CKP/zYFgrpsC62pQsY\n" \
"kDUmotr2qLcy/JUjS8ZFucTP5Hzu5sn4kL1y45nDHQsFfGqXbbKrAjbYwrwsAZI/\n" \
"BKOLdRHHuSm8EdCGupK8JvllyDfNJvaGEwwEqonleLHBTnm8dqMLUeTF0J5q/hos\n" \
"Vq4GNiejcxwIfZMy0MJEGdqN9A57HSgDKwmKdsp33Id6rHtSJlWncg+d0ohP/rEh\n" \
"xRqhqjn1VtvChMQ1H3Dau0bwhr9kAMQ+959GG50jBbl9s08PqUU643QwmA==\n" \
"-----END CERTIFICATE-----\n"
/*DigiCert TLS RSA SHA256 2020 CA1*/
"-----BEGIN CERTIFICATE-----\n" \
"MIIEvjCCA6agAwIBAgIQBtjZBNVYQ0b2ii+nVCJ+xDANBgkqhkiG9w0BAQsFADBh\n" \
"MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" \
"d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD\n" \
"QTAeFw0yMTA0MTQwMDAwMDBaFw0zMTA0MTMyMzU5NTlaME8xCzAJBgNVBAYTAlVT\n" \
"MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxKTAnBgNVBAMTIERpZ2lDZXJ0IFRMUyBS\n" \
"U0EgU0hBMjU2IDIwMjAgQ0ExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC\n" \
"AQEAwUuzZUdwvN1PWNvsnO3DZuUfMRNUrUpmRh8sCuxkB+Uu3Ny5CiDt3+PE0J6a\n" \
"qXodgojlEVbbHp9YwlHnLDQNLtKS4VbL8Xlfs7uHyiUDe5pSQWYQYE9XE0nw6Ddn\n" \
"g9/n00tnTCJRpt8OmRDtV1F0JuJ9x8piLhMbfyOIJVNvwTRYAIuE//i+p1hJInuW\n" \
"raKImxW8oHzf6VGo1bDtN+I2tIJLYrVJmuzHZ9bjPvXj1hJeRPG/cUJ9WIQDgLGB\n" \
"Afr5yjK7tI4nhyfFK3TUqNaX3sNk+crOU6JWvHgXjkkDKa77SU+kFbnO8lwZV21r\n" \
"eacroicgE7XQPUDTITAHk+qZ9QIDAQABo4IBgjCCAX4wEgYDVR0TAQH/BAgwBgEB\n" \
"/wIBADAdBgNVHQ4EFgQUt2ui6qiqhIx56rTaD5iyxZV2ufQwHwYDVR0jBBgwFoAU\n" \
"A95QNVbRTLtm8KPiGxvDl7I90VUwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQG\n" \
"CCsGAQUFBwMBBggrBgEFBQcDAjB2BggrBgEFBQcBAQRqMGgwJAYIKwYBBQUHMAGG\n" \
"GGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBABggrBgEFBQcwAoY0aHR0cDovL2Nh\n" \
"Y2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNydDBCBgNV\n" \
"HR8EOzA5MDegNaAzhjFodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRH\n" \
"bG9iYWxSb290Q0EuY3JsMD0GA1UdIAQ2MDQwCwYJYIZIAYb9bAIBMAcGBWeBDAEB\n" \
"MAgGBmeBDAECATAIBgZngQwBAgIwCAYGZ4EMAQIDMA0GCSqGSIb3DQEBCwUAA4IB\n" \
"AQCAMs5eC91uWg0Kr+HWhMvAjvqFcO3aXbMM9yt1QP6FCvrzMXi3cEsaiVi6gL3z\n" \
"ax3pfs8LulicWdSQ0/1s/dCYbbdxglvPbQtaCdB73sRD2Cqk3p5BJl+7j5nL3a7h\n" \
"qG+fh/50tx8bIKuxT8b1Z11dmzzp/2n3YWzW2fP9NsarA4h20ksudYbj/NhVfSbC\n" \
"EXffPgK2fPOre3qGNm+499iTcc+G33Mw+nur7SpZyEKEOxEXGlLzyQ4UfaJbcme6\n" \
"ce1XR2bFuAJKZTRei9AqPCCcUZlM51Ke92sRKw2Sfh3oius2FkOH6ipjv3U/697E\n" \
"A7sKPPcw7+uvTPyLNhBzPvOk\n" \
"-----END CERTIFICATE-----\n";
21 changes: 19 additions & 2 deletions src/Arduino_ESP32_OTA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,13 +182,30 @@ int Arduino_ESP32_OTA::download(const char * ota_url)
DEBUG_VERBOSE("%s: Length of OTA binary according to HTTP header = %d bytes", __FUNCTION__, content_length_val);

/* Read the OTA header ... */
_client->read(_ota_header.buf, sizeof(OtaHeader));
bool is_ota_header_timeout = false;
unsigned long const start = millis();
for (int i = 0; i < sizeof(OtaHeader);)
{
is_ota_header_timeout = (millis() - start) > ARDUINO_ESP32_OTA_BINARY_HEADER_RECEIVE_TIMEOUT_ms;
if (is_ota_header_timeout) break;

if (_client->available())
{
_ota_header.buf[i++] = _client->read();
}
}

/* ... check for header download timeout ... */
if (is_ota_header_timeout) {
return static_cast<int>(Error::OtaHeaderTimeout);
}

/* ... and check first length ... */
/* ... then check if OTA header length field matches HTTP content length... */
if (_ota_header.header.len != (content_length_val - sizeof(_ota_header.header.len) - sizeof(_ota_header.header.crc32))) {
return static_cast<int>(Error::OtaHeaderLength);
}

/* ... and OTA magic number */
if (_ota_header.header.magic_number != ARDUINO_ESP32_OTA_MAGIC)
{
return static_cast<int>(Error::OtaHeaterMagicNumber);
Expand Down
2 changes: 2 additions & 0 deletions src/Arduino_ESP32_OTA.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
******************************************************************************/

static uint32_t const ARDUINO_ESP32_OTA_HTTP_HEADER_RECEIVE_TIMEOUT_ms = 10000;
static uint32_t const ARDUINO_ESP32_OTA_BINARY_HEADER_RECEIVE_TIMEOUT_ms = 10000;
static uint32_t const ARDUINO_ESP32_OTA_BINARY_BYTE_RECEIVE_TIMEOUT_ms = 2000;

/******************************************************************************
Expand Down Expand Up @@ -71,6 +72,7 @@ class Arduino_ESP32_OTA
OtaHeaderCrc = -10,
OtaHeaterMagicNumber = -11,
OtaDownload = -12,
OtaHeaderTimeout = -13
};

Arduino_ESP32_OTA();
Expand Down
Loading