Skip to content

Commit

Permalink
ESP:Use spiffs in ESP OTA Provider example (#12400)
Browse files Browse the repository at this point in the history
* Use spiffs in ESP OTA Provider Example

* Temporarily fix the compilation errors for ESP OTA Requestor app

* Restyled by prettier-markdown

* Modify the README.md files

Co-authored-by: Restyled.io <commits@restyled.io>
  • Loading branch information
2 people authored and pull[bot] committed Jan 10, 2024
1 parent 480fc64 commit 5789009
Show file tree
Hide file tree
Showing 9 changed files with 80 additions and 69 deletions.
37 changes: 14 additions & 23 deletions examples/ota-provider-app/esp32/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,40 +5,31 @@ A prototype application that demonstrates OTA provider capabilities.
## Supported Devices

- This example supports ESP32 and ESP32C3. For details please check
[here](https://github.com/shubhamdp/connectedhomeip/tree/shubhamdp-patch-1/examples/all-clusters-app/esp32#supported-devices).
[here](https://github.com/project-chip/connectedhomeip/tree/master/examples/all-clusters-app/esp32#supported-devices).

## Building the Example Application

- If you are building for the first time please check
[Building the Example Application](https://github.com/shubhamdp/connectedhomeip/tree/shubhamdp-patch-1/examples/all-clusters-app/esp32#building-the-example-application)
guide.
- Otherwise, `idf.py build` works!
## Copy the OTA image

## Flashing the Example Application
- Copy the binary file which you are going to send to the OTA Requestor to
`./spiffs_image` path and make sure the `OTA_IMAGE_NAME` is the same as the
name of the image file you placed in `./spiffs_image`.

```
idf.py -p <OTAProviderSerialPort> flash
idf.py menuconfig
```

## Flashing the hello-world.bin OTA image

Flash hello-world OTA image on OTA Provider's "ota_data" flash partition. Please
find hello-world.bin
[here](http://shubhamdp.github.io/esp_ota/esp32/hello-world-flash-in-ota-provider-partition.bin).
This OTA image is built for ESP32, it will not work on other devices. This is
the OTA upgrade image and will be sent to OTA requestor.
- Edit the `OTA_IMAGE_NAME` through `Demo`->`OTA image file name`.

```
esptool.py -p <OTAProviderSerialPort> write_flash 0x206400 hello-world-flash-in-ota-provider-partition.bin
```
## Building the Example Application

NOTE: This is a modified binary which contains the size of OTA image at first 4
bytes.
- If you are building for the first time please check
[Building the Example Application](https://github.com/project-chip/connectedhomeip/tree/master/examples/all-clusters-app/esp32#building-the-example-application)
guide.
- Otherwise, `idf.py build` works!

Run the idf monitor
## Flashing the Example Application

```
idf.py -p <OTAProviderSerialPort> monitor
idf.py -p <OTAProviderSerialPort> flash
```

## Commissioning over BLE using chip-tool
Expand Down
3 changes: 2 additions & 1 deletion examples/ota-provider-app/esp32/main/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ idf_component_register(PRIV_INCLUDE_DIRS
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/ota-provider-app/ota-provider-common"
EXCLUDE_SRCS
"${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/ota-provider-app/ota-provider-common/BdxOtaSender.cpp"
PRIV_REQUIRES chip QRCode bt console)
PRIV_REQUIRES chip QRCode bt console spiffs)

spiffs_create_partition_image(img_storage ../spiffs_image FLASH_IN_PROJECT)
set_property(TARGET ${COMPONENT_LIB} PROPERTY CXX_STANDARD 14)
target_compile_options(${COMPONENT_LIB} PRIVATE "-DLWIP_IPV6_SCOPES=0" "-DCHIP_HAVE_CONFIG_H")
6 changes: 6 additions & 0 deletions examples/ota-provider-app/esp32/main/Kconfig.projbuild
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,10 @@ menu "Demo"
default 4 if RENDEZVOUS_MODE_THREAD
default 8 if RENDEZVOUS_MODE_ETHERNET

config OTA_IMAGE_NAME
string "OTA image file name"
default "hello_world.bin"
help
Name of OTA image file which will be added to '/spiffs_image/' and sent to the OTA Requestor.

endmenu
70 changes: 36 additions & 34 deletions examples/ota-provider-app/esp32/main/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "esp_log.h"
#include "esp_netif.h"
#include "esp_spi_flash.h"
#include "esp_spiffs.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "freertos/FreeRTOS.h"
Expand Down Expand Up @@ -60,7 +61,8 @@ void OnTransferComplete(void * context);
void OnTransferFailed(void * context, BdxSenderErrorTypes status);

namespace {
const char * TAG = "ota-provider-app";
const char * TAG = "ota-provider-app";
const uint8_t kMaxImagePathlen = 35;
static DeviceCallbacks EchoCallbacks;
BdxOtaSender bdxServer;

Expand All @@ -69,10 +71,11 @@ constexpr chip::EndpointId kOtaProviderEndpoint = 0;
constexpr uint32_t kMaxBdxBlockSize = 1024;
constexpr chip::System::Clock::Timeout kBdxTimeout = chip::System::Clock::Seconds16(5 * 60); // Specification mandates >= 5 minutes
constexpr chip::System::Clock::Timeout kBdxPollFreq = chip::System::Clock::Milliseconds32(500);
const char * otaFilename = "hello-world.bin";
const esp_partition_t * otaPartition = nullptr;
const char * otaFilename = CONFIG_OTA_IMAGE_NAME;
FILE * otaImageFile = NULL;
uint32_t otaImageLen = 0;
uint32_t otaTransferInProgress = false;
static OTAProviderExample otaProvider;

chip::Callback::Callback<OnBdxBlockQuery> onBlockQueryCallback(OnBlockQuery, nullptr);
chip::Callback::Callback<OnBdxTransferComplete> onTransferCompleteCallback(OnTransferComplete, nullptr);
Expand All @@ -83,22 +86,17 @@ CHIP_ERROR OnBlockQuery(void * context, chip::System::PacketBufferHandle & block
{
if (otaTransferInProgress == false)
{
if (otaPartition == nullptr || otaImageLen == 0)
if (otaImageFile == NULL || otaImageLen == 0)
{
ESP_LOGE(TAG, "OTA partition not found");
ESP_LOGE(TAG, "Failed to open the OTA image file");
return CHIP_ERROR_OPEN_FAILED;
}
otaTransferInProgress = true;
}

uint16_t blockBufAvailableLength = blockBuf->AvailableDataLength();
uint16_t transferBlockSize = bdxServer.GetTransferBlockSize();

size = (blockBufAvailableLength < transferBlockSize) ? blockBufAvailableLength : transferBlockSize;

// There are two types of messages requestor can use to query a block: `BlockQuery` and `BlockQueryWithSkip` so,
// to handle both case in a single callback offset is used which is managed by the `BdxOtaSender`.
// So, offset + size will not overflow and even if it overflows the esp_partition_read API will return an error.
if (offset + size >= otaImageLen)
{
size = otaImageLen - offset;
Expand All @@ -108,17 +106,15 @@ CHIP_ERROR OnBlockQuery(void * context, chip::System::PacketBufferHandle & block
{
isEof = false;
}

esp_err_t err = esp_partition_read(otaPartition, offset + sizeof(otaImageLen), blockBuf->Start(), size);
if (err != ESP_OK)
size_t size_read = fread(blockBuf->Start(), 1, size, otaImageFile);
if (size_read != size)
{
ESP_LOGI(TAG, "Failed to read %d bytes from offset %d", size, offset + sizeof(otaImageLen));
ESP_LOGE(TAG, "Failed to read %d bytes from %s", size, otaFilename);
size = 0;
isEof = false;
return CHIP_ERROR_READ_FAILED;
}

ESP_LOGI(TAG, "Read %d bytes from offset %d", size, offset + sizeof(otaImageLen));
ESP_LOGI(TAG, "Read %d bytes from %s", size, otaFilename);
return CHIP_NO_ERROR;
}

Expand Down Expand Up @@ -157,8 +153,6 @@ extern "C" void app_main()
return;
}

OTAProviderExample otaProvider;

CHIPDeviceManager & deviceMgr = CHIPDeviceManager::GetInstance();

CHIP_ERROR error = deviceMgr.Init(&EchoCallbacks);
Expand Down Expand Up @@ -188,26 +182,34 @@ extern "C" void app_main()
callbacks.onTransferFailed = &onTransferFailedCallback;
bdxServer.SetCallbacks(callbacks);

// If OTA image is available in flash storage then set to update available
otaPartition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, "ota_data");
if (otaPartition != nullptr)
{
ESP_LOGI(TAG, "Partition found %s address:0x%x size:0x%x", otaPartition->label, otaPartition->address, otaPartition->size);
esp_vfs_spiffs_conf_t spiffs_conf = {
.base_path = "/spiffs",
.partition_label = NULL,
.max_files = 3,
.format_if_mount_failed = false,
};

// TODO: Use the OTA image header specified in the specification
// Right now we are using just image length instead of full header
esp_partition_read(otaPartition, 0, &otaImageLen, sizeof(otaImageLen));
if (otaImageLen > otaPartition->size)
{
otaImageLen = 0;
}
ESP_LOGI(TAG, "OTA image length %d bytes", otaImageLen);
err = esp_vfs_spiffs_register(&spiffs_conf);
if (err != ESP_OK)
{
ESP_LOGE(TAG, "Failed to initialize SPIFFS (%s)", esp_err_to_name(err));
return;
}
else
size_t total = 0, used = 0;
err = esp_spiffs_info(NULL, &total, &used);
ESP_LOGI(TAG, "Partition size: total: %d, used: %d", total, used);
char otaImagePath[kMaxImagePathlen];
sprintf(otaImagePath, "/spiffs/%s", otaFilename);
otaImageFile = fopen(otaImagePath, "r");
if (otaImageFile == NULL)
{
ESP_LOGE(TAG, "OTA partition not found");
ESP_LOGE(TAG, "Failed to open %s", otaFilename);
return;
}

fseek(otaImageFile, 0, SEEK_END);
otaImageLen = ftell(otaImageFile);
rewind(otaImageFile);
ESP_LOGI(TAG, "The OTA image size: %d", otaImageLen);
if (otaImageLen > 0)
{
otaProvider.SetQueryImageBehavior(OTAProviderExample::kRespondWithUpdateAvailable);
Expand Down
10 changes: 4 additions & 6 deletions examples/ota-provider-app/esp32/partitions.csv
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
nvs, data, nvs, , 0x6000,
otadata, data, ota, , 0x2000,
phy_init, data, phy, , 0x1000,
# Factory partition size about 1.9MB
factory, app, factory, , 1945K,
# OTA partition of size 1M
ota_data, data, nvs, , 1M,
# ota_1, app, ota_1, , 512K,
# Factory partition size about 1.5MB
factory, app, factory, , 1500K,
# spiffs partition to storage the image file size about 1.5MB
img_storage, data, spiffs, , 1500K,
Binary file not shown.
4 changes: 2 additions & 2 deletions examples/ota-requestor-app/esp32/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ Before moving ahead, make sure you have
## Supported Devices

- This example supports ESP32 and ESP32C3. For details please check
[here](https://github.com/shubhamdp/connectedhomeip/tree/shubhamdp-patch-1/examples/all-clusters-app/esp32#supported-devices).
[here](https://github.com/project-chip/connectedhomeip/tree/master/examples/all-clusters-app/esp32#supported-devices).

## Building the Example Application

- If you are building for the first time please check
[Building the Example Application](https://github.com/shubhamdp/connectedhomeip/tree/shubhamdp-patch-1/examples/all-clusters-app/esp32#building-the-example-application)
[Building the Example Application](https://github.com/project-chip/connectedhomeip/tree/master/examples/all-clusters-app/esp32#building-the-example-application)
guide.
- Otherwise, `idf.py build` works!

Expand Down
6 changes: 3 additions & 3 deletions examples/ota-requestor-app/esp32/main/OTARequesterImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@

using chip::ByteSpan;
using chip::CharSpan;
using chip::DeviceProxy;
using chip::EndpointId;
using chip::FabricIndex;
using chip::NodeId;
using chip::OnDeviceConnected;
using chip::OnDeviceConnectionFailure;
using chip::OperationalDeviceProxy;
using chip::Optional;
using chip::PeerId;
using chip::Server;
Expand All @@ -55,7 +55,7 @@ void OnQueryImageFailure(void * context, EmberAfStatus status);
void OnApplyUpdateResponse(void * context, const ApplyUpdateResponse::DecodableType & response);
void OnApplyUpdateRequestFailure(void * context, EmberAfStatus status);

void OnConnected(void * context, chip::DeviceProxy * deviceProxy);
void OnConnected(void * context, chip::OperationalDeviceProxy * deviceProxy);
void OnConnectionFailure(void * context, NodeId deviceId, CHIP_ERROR error);

void OnBlockReceived(void * context, const chip::bdx::TransferSession::BlockData & blockdata);
Expand Down Expand Up @@ -174,7 +174,7 @@ void OnApplyUpdateRequestFailure(void * context, EmberAfStatus status)
ChipLogDetail(SoftwareUpdate, "ApplyUpdateRequest failure response %" PRIu8, status);
}

void OnConnected(void * context, chip::DeviceProxy * deviceProxy)
void OnConnected(void * context, chip::OperationalDeviceProxy * deviceProxy)
{
ChipLogDetail(SoftwareUpdate, "Callback OnConnected");
uint8_t * command = reinterpret_cast<uint8_t *>(context);
Expand Down
13 changes: 13 additions & 0 deletions examples/ota-requestor-app/esp32/main/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

#include "CHIPDeviceManager.h"
#include "DeviceCallbacks.h"
#include "app/util/af-enums.h"
#include "app/util/af.h"
#include "esp_heap_caps_init.h"
#include "esp_log.h"
#include "esp_netif.h"
Expand Down Expand Up @@ -180,3 +182,14 @@ extern "C" void app_main()

ESPInitConsole();
}

// TODO: We should use the function definition in /src/app/clusters/ota-requestor/ClusterInterface.cpp
// Temporarily add this function.

bool emberAfOtaSoftwareUpdateRequestorClusterAnnounceOtaProviderCallback(
chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
const chip::app::Clusters::OtaSoftwareUpdateRequestor::Commands::AnnounceOtaProvider::DecodableType & commandData)
{
emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_SUCCESS);
return true;
}

0 comments on commit 5789009

Please sign in to comment.