Add OTA update support (#711)

Adds a 12K OTA stub 3rd stage bootloader, which reads new firmware
from the LittleFS filesystem and flashes on reboot.

By storing the OTA commands in a file in flash, it is possible to
recover from a power failure during OTA programming.  On power
resume, the OTA block will simply re-program from the beginning.

Support cryptographic signed OTA updates, if desired.  Includes
host-side signing logic via openssl.

Add PicoOTA library which encapsulates the file format for
the updater, including CRC32 checking.

Add LEAmDNS support to allow Arduino IDE discovery

Add ArduinoOTA class for IDE uploads

Add MD5Builder class

Add Updater class which supports writing and validating
cryptographically signed binaries from any source (http,
Ethernet, WiFi, Serial, etc.)

Add documentation and readmes.
This commit was merged in pull request #711.
This commit is contained in:
Earle F. Philhower, III
2022-08-12 00:26:51 -07:00
committed by GitHub
parent 71be07e69f
commit da86a8942b
87 changed files with 23806 additions and 313 deletions
+103
View File
@@ -0,0 +1,103 @@
#pragma once
#include <WiFi.h>
#include <functional>
#include <LittleFS.h>
#include <Updater.h>
class UdpContext;
typedef enum {
OTA_IDLE,
OTA_WAITAUTH,
OTA_RUNUPDATE
} ota_state_t;
typedef enum {
OTA_AUTH_ERROR,
OTA_BEGIN_ERROR,
OTA_CONNECT_ERROR,
OTA_RECEIVE_ERROR,
OTA_END_ERROR
} ota_error_t;
class ArduinoOTAClass {
public:
typedef std::function<void(void)> THandlerFunction;
typedef std::function<void(ota_error_t)> THandlerFunction_Error;
typedef std::function<void(unsigned int, unsigned int)> THandlerFunction_Progress;
ArduinoOTAClass();
~ArduinoOTAClass();
//Sets the service port. Default 2040
void setPort(uint16_t port);
//Sets the device hostname. Default pico-xxxxxx
void setHostname(const char *hostname);
String getHostname();
//Sets the password that will be required for OTA. Default NULL
void setPassword(const char *password);
//Sets the password as above but in the form MD5(password). Default NULL
void setPasswordHash(const char *password);
//Sets if the device should be rebooted after successful update. Default true
void setRebootOnSuccess(bool reboot);
//This callback will be called when OTA connection has begun
void onStart(THandlerFunction fn);
//This callback will be called when OTA has finished
void onEnd(THandlerFunction fn);
//This callback will be called when OTA encountered Error
void onError(THandlerFunction_Error fn);
//This callback will be called when OTA is receiving data
void onProgress(THandlerFunction_Progress fn);
//Starts the ArduinoOTA service
void begin(bool useMDNS = true);
//Ends the ArduinoOTA service
void end();
//Call this in loop() to run the service. Also calls MDNS.update() when begin() or begin(true) is used.
void handle();
//Gets update command type after OTA has started. Either U_FLASH or U_FS
int getCommand();
private:
void _runUpdate(void);
void _onRx(void);
int parseInt(void);
String readStringUntil(char end);
int _port = 0;
String _password;
String _hostname;
String _nonce;
UdpContext *_udp_ota = nullptr;
bool _initialized = false;
bool _rebootOnSuccess = true;
bool _useMDNS = true;
ota_state_t _state = OTA_IDLE;
int _size = 0;
int _cmd = 0;
uint16_t _ota_port = 0;
uint16_t _ota_udp_port = 0;
IPAddress _ota_ip;
String _md5;
THandlerFunction _start_callback = nullptr;
THandlerFunction _end_callback = nullptr;
THandlerFunction_Error _error_callback = nullptr;
THandlerFunction_Progress _progress_callback = nullptr;
};
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_ARDUINOOTA)
extern ArduinoOTAClass ArduinoOTA;
#endif