Skip to content

Commit

Permalink
[ESP32] Delta OTA Feature
Browse files Browse the repository at this point in the history
  • Loading branch information
PSONALl committed Sep 1, 2023
1 parent ea3970a commit 71c2ac4
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 2 deletions.
5 changes: 5 additions & 0 deletions config/esp32/components/chip/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,11 @@ if (CONFIG_ENABLE_ENCRYPTED_OTA)
list(APPEND chip_libraries $<TARGET_FILE:${esp_encrypted_img_lib}>)
endif()

if (CONFIG_ENABLE_DELTA_OTA)
idf_component_get_property(esp_delta_ota_lib espressif__esp_delta_ota COMPONENT_LIB)
list(APPEND chip_libraries $<TARGET_FILE:${esp_delta_ota_lib}>)
endif()

idf_component_get_property(main_lib main COMPONENT_LIB)
list(APPEND chip_libraries $<TARGET_FILE:${main_lib}>)

Expand Down
7 changes: 7 additions & 0 deletions config/esp32/components/chip/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,13 @@ menu "CHIP Core"
help
Enable this option to use the pre encrypted OTA image

config ENABLE_DELTA_OTA
bool "Enable delta OTA"
depends on ENABLE_OTA_REQUESTOR
default n
help
Enable this option for delta OTA image

config OTA_AUTO_REBOOT_ON_APPLY
bool "Reboot the device after applying the OTA image"
depends on ENABLE_OTA_REQUESTOR
Expand Down
5 changes: 5 additions & 0 deletions config/esp32/components/chip/idf_component.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,8 @@ dependencies:
espressif/esp_insights:
version: "1.0.1"
require: public

espressif/esp_delta_ota:
version: "1.0.1"
service_url: "https://components-staging.espressif.com/api"
require: public
31 changes: 31 additions & 0 deletions docs/guides/esp32/ota.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,34 @@ Please follow the steps below to generate an application image for OTA upgrades:
```

3. Use the `lighting-app-encrypted-ota.bin` file with the OTA Provider app.

## Delta OTA

Delta OTA Updates is a feature that enables Over-the-Air (OTA) firmware update with compressed delta binaries. Patch files have smaller size than the original firmware file, which reduces the time and network usage to download the file from the server. Also, no additional storage partition is required for the "patch".

### Firmware Changes

- Enable configuration options for OTA requestor and Delta OTA:

```
CONFIG_ENABLE_OTA_REQUESTOR=y
CONFIG_ENABLE_DELTA_OTA=y
```

- Delta binary needs to be generated using binary delta encoding in Python 3.6+. You can install detools using the following command.

```
pip install -r examples/https_delta_ota/tools/requirements.txt
```

- Generate delta binary and compress it using Heatshrink algorithm.
```
detools create_patch -c heatshrink <base-binary> <new-binary> delta-ota.bin
```

- Append the Matter OTA header:
```
src/app/ota_image_tool.py create --vendor-id 0xFFF1 --product-id 0x8000 --version 2 --version-str "v2.0" -da sha256 delta-ota.bin lighting-app-delta-ota.bin
```

3. Use the `lighting-app-delta-ota.bin` file with the OTA Provider app.
87 changes: 86 additions & 1 deletion src/platform/ESP32/OTAImageProcessorImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@
#include <esp_encrypted_img.h>
#endif // CONFIG_ENABLE_ENCRYPTED_OTA

#if CONFIG_ENABLE_DELTA_OTA
#include <esp_delta_ota.h>
#define IMG_HEADER_LEN sizeof(esp_image_header_t)
#endif // CONFIG_ENABLE_DELTA_OTA

#define TAG "OTAImageProcessor"
using namespace chip::System;
using namespace ::chip::DeviceLayer::Internal;
Expand Down Expand Up @@ -123,6 +128,50 @@ CHIP_ERROR OTAImageProcessorImpl::ProcessBlock(ByteSpan & block)
return CHIP_NO_ERROR;
}

#if CONFIG_ENABLE_DELTA_OTA
esp_err_t OTAImageProcessorImpl::DeltaOTAReadCallback(uint8_t *buf_p, size_t size, int src_offset)
{
if (size <= 0) {
return ESP_ERR_INVALID_ARG;
}
const esp_partition_t *current_partition = esp_ota_get_running_partition();
return esp_partition_read(current_partition, src_offset, buf_p, size);
}

esp_err_t OTAImageProcessorImpl::DeltaOTAWriteCallback(const uint8_t *buf_p, size_t size, void *arg)
{
auto * imageProcessor = reinterpret_cast<OTAImageProcessorImpl *>(arg);
if (size <= 0) {
return ESP_ERR_INVALID_ARG;
}

static char header_data[IMG_HEADER_LEN];
static bool chip_id_verified = false;
static int header_data_read = 0;
int index = 0;

if (!chip_id_verified) {
if (header_data_read + size <= IMG_HEADER_LEN) {
memcpy(header_data + header_data_read, buf_p, size);
header_data_read += size;
return ESP_OK;
} else {
index = IMG_HEADER_LEN - header_data_read;
memcpy(header_data + header_data_read, buf_p, index);

chip_id_verified = true;

// Write data in header_data buffer.
esp_err_t err = esp_ota_write(imageProcessor->mOTAUpdateHandle, header_data, IMG_HEADER_LEN);
if (err != ESP_OK) {
return err;
}
}
}
return esp_ota_write(imageProcessor->mOTAUpdateHandle, buf_p + index, size - index);
}
#endif // CONFIG_ENABLE_DELTA_OTA

void OTAImageProcessorImpl::HandlePrepareDownload(intptr_t context)
{
auto * imageProcessor = reinterpret_cast<OTAImageProcessorImpl *>(context);
Expand All @@ -142,13 +191,31 @@ void OTAImageProcessorImpl::HandlePrepareDownload(intptr_t context)
ChipLogError(SoftwareUpdate, "OTA partition not found");
return;
}
#if CONFIG_ENABLE_DELTA_OTA
esp_err_t err =
esp_ota_begin(imageProcessor->mOTAUpdatePartition, OTA_SIZE_UNKNOWN, &(imageProcessor->mOTAUpdateHandle));
#else
esp_err_t err =
esp_ota_begin(imageProcessor->mOTAUpdatePartition, OTA_WITH_SEQUENTIAL_WRITES, &(imageProcessor->mOTAUpdateHandle));
esp_ota_begin(imageProcessor->mOTAUpdatePartition, OTA_WITH_SEQUENTIAL_WRITES, &(imageProcessor->mOTAUpdateHandle));
#endif // CONFIG_ENABLE_DELTA_OTA

if (err != ESP_OK)
{
imageProcessor->mDownloader->OnPreparedForDownload(ESP32Utils::MapError(err));
return;
}
#if CONFIG_ENABLE_DELTA_OTA
esp_delta_ota_cfg_t cfg = {
.user_data = imageProcessor,
.read_cb = &(imageProcessor->DeltaOTAReadCallback),
.write_cb = &(imageProcessor->DeltaOTAWriteCallback),
};

imageProcessor->mDeltaOTAUpdateHandle = esp_delta_ota_init(&cfg);
if (imageProcessor->mDeltaOTAUpdateHandle == NULL) {
ESP_LOGE(TAG, "delta_ota_set_cfg failed");
}
#endif // CONFIG_ENABLE_DELTA_OTA

#if CONFIG_ENABLE_ENCRYPTED_OTA
CHIP_ERROR chipError = imageProcessor->DecryptStart();
Expand Down Expand Up @@ -182,7 +249,21 @@ void OTAImageProcessorImpl::HandleFinalize(intptr_t context)
}
#endif // CONFIG_ENABLE_ENCRYPTED_OTA

#if CONFIG_ENABLE_DELTA_OTA
esp_err_t err = esp_delta_ota_finalize(imageProcessor->mDeltaOTAUpdateHandle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_delta_ota_finalize() failed : %s", esp_err_to_name(err));
}

err = esp_delta_ota_deinit(imageProcessor->mDeltaOTAUpdateHandle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_delta_ota_deinit() failed : %s", esp_err_to_name(err));
}

err = esp_ota_end(imageProcessor->mOTAUpdateHandle);
#else
esp_err_t err = esp_ota_end(imageProcessor->mOTAUpdateHandle);
#endif // CONFIG_ENABLE_DELTA_OTA
if (err != ESP_OK)
{
if (err == ESP_ERR_OTA_VALIDATE_FAILED)
Expand Down Expand Up @@ -264,7 +345,11 @@ void OTAImageProcessorImpl::HandleProcessBlock(intptr_t context)
}
#endif // CONFIG_ENABLE_ENCRYPTED_OTA

#if CONFIG_ENABLE_DELTA_OTA
err = esp_delta_ota_feed_patch(imageProcessor->mDeltaOTAUpdateHandle, blockToWrite.data(), blockToWrite.size());
#else
err = esp_ota_write(imageProcessor->mOTAUpdateHandle, blockToWrite.data(), blockToWrite.size());
#endif // CONFIG_ENABLE_DELTA_OTA

#if CONFIG_ENABLE_ENCRYPTED_OTA
free((void *) (blockToWrite.data()));
Expand Down
12 changes: 11 additions & 1 deletion src/platform/ESP32/OTAImageProcessorImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@
#include <esp_encrypted_img.h>
#endif // CONFIG_ENABLE_ENCRYPTED_OTA

#if CONFIG_ENABLE_DELTA_OTA
#include <esp_delta_ota.h>
#endif // CONFIG_ENABLE_DELTA_OTA

namespace chip {

class OTAImageProcessorImpl : public OTAImageProcessorInterface
Expand All @@ -48,7 +52,10 @@ class OTAImageProcessorImpl : public OTAImageProcessorInterface
// @return CHIP_NO_ERROR on success, appropriate error code otherwise
CHIP_ERROR InitEncryptedOTA(const CharSpan & key);
#endif // CONFIG_ENABLE_ENCRYPTED_OTA

#if CONFIG_ENABLE_DELTA_OTA
static esp_err_t DeltaOTAReadCallback(uint8_t *buf_p, size_t size, int src_offset);
static esp_err_t DeltaOTAWriteCallback(const uint8_t *buf_p, size_t size, void *arg);
#endif // CONFIG_ENABLE_DELTA_OTA
private:
static void HandlePrepareDownload(intptr_t context);
static void HandleFinalize(intptr_t context);
Expand All @@ -64,6 +71,9 @@ class OTAImageProcessorImpl : public OTAImageProcessorInterface
MutableByteSpan mBlock;
const esp_partition_t * mOTAUpdatePartition = nullptr;
esp_ota_handle_t mOTAUpdateHandle;
#if CONFIG_ENABLE_DELTA_OTA
esp_delta_ota_handle_t mDeltaOTAUpdateHandle;
#endif // CONFIG_ENABLE_DELTA_OTA
OTAImageHeaderParser mHeaderParser;

#if CONFIG_ENABLE_ENCRYPTED_OTA
Expand Down

0 comments on commit 71c2ac4

Please sign in to comment.