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

ESP:Use spiffs in ESP OTA Provider example #12400

Merged
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
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;
}