Skip to content

Commit

Permalink
Enable support for varint patch version. Useful for nightly build pat…
Browse files Browse the repository at this point in the history
…ch versions.
  • Loading branch information
slav-at-attachix committed Mar 18, 2021
1 parent bcd4ff8 commit d1fe80c
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 19 deletions.
56 changes: 56 additions & 0 deletions samples/Ota_Mqtt/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ enough resources: memory, space on flash, power and time to complete such an upd
Depending on the size of the new firmware and the speed of the connection an update can take 10 to 20 seconds.
2) The application connects via MQTT to a remote server and subscribes to a special topic. The topic is based on the
application id and its current version. If the current application version is 4.3.1 then the topic that will be used for OTA is "/a/test/u/4.3".
2.1) If there is a need to support both stable and unstable/nightly builds then the topic name can have s or u suffix. For example
all stable versions should be published and downloaded from the topic "/a/test/u/4.3/s". For the unstable ones we can use the topic "/a/test/u/4.3/u".
If an application is interested in both then it can subscribe using the following pattern "/a/test/u/4.3/+".
3) The application is waiting for new firmware. When the application is on battery than it makes sense to wait for a limited time and if there is no
message coming back to disconnect.

Expand All @@ -47,3 +50,56 @@ For additional security a standard SSL/TLS can be used
2) To prove that the server is the correct one: The MQTT clients should pin the public key fingerprint on the server.
OR have a list of public key fingerprints that are allowed.
3) To prove that the clients are allowed to connect: Every MQTT client should also have a client certificate that is signed by the server.


Configuration and Security features
-----------------------------------

.. envvar:: APP_ID

Default: "test"

This variable contains the unique application name.

.. envvar:: APP_VERSION

Default: not set

Contains the application major and minor versions separated by comma. Example "4.2".
If not set will use the current major and minor version from Sming.

.. envvar::APP_VERSION_PATCH
Default: not set
Contains the application patch version as integer. For stable versions you can use 0 until 255.
For unstable versions the current timestamp can be used as a patch version.
.. envvar:: ENABLE_VARINT_PATCH_VERSION

Default: 0 (disabled)

If set to 1 the OTA upgrade mechanism and application will use a `varint <https://developers.google.com/protocol-buffers/docs/encoding#varints>`_`
encoding for the patch version. Thus allowing unlimited number of patch versions. Useful for enumerating unstable/nightly releases.
A bit more difficult to read and write but allows for unlimited versions.

If set to 0 the OTA upgrade mechanism and application will use one byte for the patch version which will limit it to 256 possible patch versions.
Useful for enumarating stable releases. Easier to write and read but limited to 256 versions only.

.. envvar:: ENABLE_SSL

Default: unset (disable)

If set to 1 (highly recommended), OTA upgrade files will be trasnferred securely over TLS/SSL.

.. envvar:: ENABLE_CLIENT_CERTIFICATE

Default: 0 (disabled)

Used in combination with ``ENABLE_SSL``. Set to 1 if the remote server requires the application to authenticate via client certficate.

.. envvar:: MQTT_URL

Default: depends on ``ENABLE_SSL`` and ``ENABLE_CLIENT_CERTIFICATE`` values

Url containing the location of the firmware update MQTT server.
62 changes: 53 additions & 9 deletions samples/Ota_Mqtt/app/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,13 @@ IMPORT_FSTR(certificateData, PROJECT_DIR "/files/certificate.pem.crt.der");
struct UpdateState {
RbootOutputStream* stream{nullptr};
bool started{false};
size_t offset{0}; // The bytes used for encoding the version.
size_t version{0};
};

constexpr const uint8_t VERSION_NOT_READY = -1;
constexpr const uint8_t VERSION_MAX_BYTES_ALLOWED = 24;

Storage::Partition findRomPartition(uint8_t slot)
{
String name = F("rom");
Expand All @@ -53,6 +58,32 @@ void switchRom()
System.restart();
}

#if ENABLE_VARINT_PATCH_VERSION
int getPatchVersion(const char* buffer, int length, size_t& offset, size_t versionStart = 0)
{
size_t version = versionStart;
offset = 0;
int useNextByte = 0;
do {
version += (buffer[offset] & 0x7f);
useNextByte = (buffer[offset++] & 0x80);
} while(useNextByte && (offset < length));

if(useNextByte) {
// all the data is consumed and we still don't have a version number?!
return VERSION_NOT_READY;
}

return version;
}
#else
int getPatchVersion(const char* buffer, int length, size_t& offset, size_t versionStart = 0)
{
offset = 1;
return buffer[0];
}
#endif

void otaUpdate()
{
if(mqtt.isProcessing()) {
Expand Down Expand Up @@ -136,22 +167,35 @@ void otaUpdate()
}

if(!updateState->started) {
updateState->started = true;
if(message->common.length - 1 > part.size()) {
debug_e("The new rom is too big to fit!");
return -2;
size_t offset = 0;
int patchVersion = getPatchVersion(buffer, length, offset, updateState->version);
updateState->offset += offset;
#if ENABLE_VARINT_PATCH_VERSION
if(patchVersion == VERSION_NOT_READY) {

if(updateState->offset > VERSION_MAX_BYTES_ALLOWED) {
debug_e("Invalid patch version.");
return -3; //
}
return 0;
}
#endif

uint8_t patchVersion = buffer[0];
updateState->started = true;
if(patchVersion < APP_VERSION_PATCH) {
// The update is not newer than our patch version
// The update is not newer than our current patch version
return 0;
}

updateState->started = true;
if(message->common.length - updateState->offset > part.size()) {
debug_e("The new rom is too big to fit!");
return -2;
}

length -= offset;
buffer += offset;

updateState->stream = new RbootOutputStream(part.address(), part.size());
buffer++;
length--;
}

auto rbootStream = static_cast<RbootOutputStream*>(updateState->stream);
Expand Down
24 changes: 14 additions & 10 deletions samples/Ota_Mqtt/component.mk
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
## User configurable settings

ENABLE_CLIENT_CERTIFICATE ?= 0
ENABLE_VARINT_PATCH_VERSION ?=0

CONFIG_VARS := ENABLE_SSL ENABLE_CLIENT_CERTIFICATE
CONFIG_VARS := MQTT_URL ENABLE_SSL ENABLE_CLIENT_CERTIFICATE ENABLE_VARINT_PATCH_VERSION

# Application id
APP_ID := "test"
APP_ID ?= "test"

# Application version: string containing only the major and minor version separated by comma
# APP_VERSION := "1.2"
# Application patch version: integer containing only the patch version
# APP_VERSION_PATCH := 3

# Firmware Update Server
MQTT_URL := "mqtt://test.mosquitto.org:1883"
ifneq ($(ENABLE_SSL),)
ifneq ($(ENABLE_CLIENT_CERTIFICATE),0)
MQTT_URL := "mqtts://test.mosquitto.org:8884"
else
MQTT_URL := "mqtts://test.mosquitto.org:8883"
endif
ifeq ($(MQTT_URL),)
MQTT_URL := "mqtt://test.mosquitto.org:1883"
ifneq ($(ENABLE_SSL),)
ifneq ($(ENABLE_CLIENT_CERTIFICATE),0)
MQTT_URL := "mqtts://test.mosquitto.org:8884"
else
MQTT_URL := "mqtts://test.mosquitto.org:8883"
endif
endif
endif

## End of user configurable settings. Don't change anything below this line
Expand All @@ -34,7 +37,8 @@ else
HWCONFIG := basic_rboot
endif

APP_CFLAGS = -DMQTT_URL="\"$(MQTT_URL)"\" -DAPP_ID="\"$(APP_ID)"\" -DENABLE_CLIENT_CERTIFICATE=$(ENABLE_CLIENT_CERTIFICATE)
APP_CFLAGS = -DMQTT_URL="\"$(MQTT_URL)"\" -DAPP_ID="\"$(APP_ID)"\" -DENABLE_CLIENT_CERTIFICATE=$(ENABLE_CLIENT_CERTIFICATE) \
-DENABLE_VARINT_PATCH_VERSION=$(ENABLE_VARINT_PATCH_VERSION)
ifneq ($(APP_VERSION),)
APP_CFLAGS += -DAPP_VERSION="\"$(APP_VERSION)"\" -DAPP_VERSION_PATCH=$(APP_VERSION_PATCH)
endif

0 comments on commit d1fe80c

Please sign in to comment.