From 6183d8a4e401c1fe8960b4ed930e3fe8eefe9173 Mon Sep 17 00:00:00 2001 From: Sergei Lissianoi <54454955+selissia@users.noreply.github.com> Date: Thu, 13 Jan 2022 10:47:49 -0500 Subject: [PATCH] [EFR32 OTA] Invoke Silabs API for writing, verifying and applying the image (#13499) * Code for testing bootloader integration * Add bootloader API calls * Add the rest of booloader calls to EFR32 OTA Requestor * Call the OTARequestor Init() method * Use correct booloader API * Close exchange when session is released (#13448) * Close exchange when session is released * Add clearRetransTable parameter to DoClose call Co-authored-by: Andrei Litvin * Clean up comments and debug code * Restyled by whitespace * Restyled by clang-format Co-authored-by: Zang MingJie Co-authored-by: Andrei Litvin Co-authored-by: Restyled.io --- examples/ota-requestor-app/efr32/src/main.cpp | 44 +++++++++++ src/platform/EFR32/OTAImageProcessorImpl.cpp | 77 +++++++++++++------ src/platform/EFR32/OTAImageProcessorImpl.h | 3 +- 3 files changed, 101 insertions(+), 23 deletions(-) diff --git a/examples/ota-requestor-app/efr32/src/main.cpp b/examples/ota-requestor-app/efr32/src/main.cpp index e3254635ec7610..3f5a5bca94c47d 100644 --- a/examples/ota-requestor-app/efr32/src/main.cpp +++ b/examples/ota-requestor-app/efr32/src/main.cpp @@ -88,6 +88,48 @@ BDXDownloader gDownloader; OTAImageProcessorImpl gImageProcessor; volatile int apperror_cnt; + +#include "platform/bootloader/api/application_properties.h" + +// Header used for building the image GBL file +#define APP_PROPERTIES_VERSION 1 +#define APP_PROPERTIES_ID \ + { \ + 0 \ + } + +__attribute__((used)) ApplicationProperties_t sl_app_properties = { + /// @brief Magic value indicating that this is an ApplicationProperties_t + /// Must equal @ref APPLICATION_PROPERTIES_MAGIC + .magic = APPLICATION_PROPERTIES_MAGIC, + + /// Version number of this struct + .structVersion = APPLICATION_PROPERTIES_VERSION, + + /// Type of signature this application is signed with + .signatureType = APPLICATION_SIGNATURE_NONE, + + /// Location of the signature. Typically a pointer to the end of application + .signatureLocation = 0, + + /// Information about the application + .app = { + + /// Bitfield representing type of application + /// e.g. @ref APPLICATION_TYPE_BLUETOOTH_APP + .type = APPLICATION_TYPE_ZIGBEE, + + /// Version number for this application + .version = APP_PROPERTIES_VERSION, + + /// Capabilities of this application + .capabilities = 0, + + /// Unique ID (e.g. UUID/GUID) for the product this application is built for + .productId = APP_PROPERTIES_ID, + }, +}; + // ================================================================================ // App Error //================================================================================= @@ -174,6 +216,8 @@ int main(void) gRequestorCore.Init(&(chip::Server::GetInstance()), &gRequestorUser, &gDownloader); + gRequestorUser.Init(&gRequestorCore, &gImageProcessor); + OTAImageProcessorParams ipParams; ipParams.imageFile = CharSpan("test.txt"); gImageProcessor.SetOTAImageProcessorParams(ipParams); diff --git a/src/platform/EFR32/OTAImageProcessorImpl.cpp b/src/platform/EFR32/OTAImageProcessorImpl.cpp index 14a061484b680e..165ccb8b8f3390 100644 --- a/src/platform/EFR32/OTAImageProcessorImpl.cpp +++ b/src/platform/EFR32/OTAImageProcessorImpl.cpp @@ -16,12 +16,22 @@ * limitations under the License. */ +#include "OTAImageProcessorImpl.h" #include -#include "OTAImageProcessorImpl.h" +extern "C" { +#include "platform/bootloader/api/btl_interface.h" +} + +/// No error, operation OK +#define SL_BOOTLOADER_OK 0L namespace chip { +// Define static memebers +uint8_t OTAImageProcessorImpl::mSlotId; +uint16_t OTAImageProcessorImpl::mWriteOffset; + CHIP_ERROR OTAImageProcessorImpl::PrepareDownload() { if (mParams.imageFile.empty()) @@ -42,6 +52,29 @@ CHIP_ERROR OTAImageProcessorImpl::Finalize() CHIP_ERROR OTAImageProcessorImpl::Apply() { + uint32_t err = SL_BOOTLOADER_OK; + + ChipLogError(SoftwareUpdate, "OTAImageProcessorImpl::Apply()"); + + // Assuming that bootloader_verifyImage() call is not too expensive and + // doesn't need to be offloaded to a different task. Revisit if necessary. + err = bootloader_verifyImage(mSlotId, NULL); + if (err != SL_BOOTLOADER_OK) + { + ChipLogError(SoftwareUpdate, "bootloader_verifyImage error %ld", err); + return CHIP_ERROR_INTERNAL; + } + + err = bootloader_setImageToBootload(mSlotId); + if (err != SL_BOOTLOADER_OK) + { + ChipLogError(SoftwareUpdate, "setImageToBootload error %ld", err); + return CHIP_ERROR_INTERNAL; + } + + // This reboots the device + bootloader_rebootAndInstall(); + return CHIP_NO_ERROR; } @@ -59,11 +92,6 @@ CHIP_ERROR OTAImageProcessorImpl::Abort() CHIP_ERROR OTAImageProcessorImpl::ProcessBlock(ByteSpan & block) { - if (!mOfs.is_open() || !mOfs.good()) - { - return CHIP_ERROR_INTERNAL; - } - if ((block.data() == nullptr) || block.empty()) { return CHIP_ERROR_INVALID_ARGUMENT; @@ -82,7 +110,9 @@ CHIP_ERROR OTAImageProcessorImpl::ProcessBlock(ByteSpan & block) void OTAImageProcessorImpl::HandlePrepareDownload(intptr_t context) { + int32_t err = SL_BOOTLOADER_OK; auto * imageProcessor = reinterpret_cast(context); + if (imageProcessor == nullptr) { ChipLogError(SoftwareUpdate, "ImageProcessor context is null"); @@ -94,17 +124,13 @@ void OTAImageProcessorImpl::HandlePrepareDownload(intptr_t context) return; } - imageProcessor->mOfs.open(imageProcessor->mParams.imageFile.data(), - std::ofstream::out | std::ofstream::ate | std::ofstream::app); - if (!imageProcessor->mOfs.good()) - { - imageProcessor->mDownloader->OnPreparedForDownload(CHIP_ERROR_OPEN_FAILED); - return; - } + bootloader_init(); + mSlotId = 0; // Single slot until we support multiple images + mWriteOffset = 0; - // TODO: if file already exists and is not empty, erase previous contents + // Not calling bootloader_eraseStorageSlot(mSlotId) here because we erase during each write - imageProcessor->mDownloader->OnPreparedForDownload(CHIP_NO_ERROR); + imageProcessor->mDownloader->OnPreparedForDownload(err == SL_BOOTLOADER_OK ? CHIP_NO_ERROR : CHIP_ERROR_INTERNAL); } void OTAImageProcessorImpl::HandleFinalize(intptr_t context) @@ -115,7 +141,6 @@ void OTAImageProcessorImpl::HandleFinalize(intptr_t context) return; } - imageProcessor->mOfs.close(); imageProcessor->ReleaseBlock(); ChipLogProgress(SoftwareUpdate, "OTA image downloaded to %s", imageProcessor->mParams.imageFile.data()); @@ -129,13 +154,13 @@ void OTAImageProcessorImpl::HandleAbort(intptr_t context) return; } - imageProcessor->mOfs.close(); - remove(imageProcessor->mParams.imageFile.data()); + // Not clearing the image storage area as it is done during each write imageProcessor->ReleaseBlock(); } void OTAImageProcessorImpl::HandleProcessBlock(intptr_t context) { + uint32_t err = SL_BOOTLOADER_OK; auto * imageProcessor = reinterpret_cast(context); if (imageProcessor == nullptr) { @@ -150,17 +175,23 @@ void OTAImageProcessorImpl::HandleProcessBlock(intptr_t context) // TODO: Process block header if any - if (!imageProcessor->mOfs.write(reinterpret_cast(imageProcessor->mBlock.data()), - static_cast(imageProcessor->mBlock.size()))) + err = bootloader_eraseWriteStorage(mSlotId, mWriteOffset, reinterpret_cast(imageProcessor->mBlock.data()), + imageProcessor->mBlock.size()); + + if (err) { + ChipLogError(SoftwareUpdate, "bootloader_eraseWriteStorage err %ld", err); + imageProcessor->mDownloader->EndDownload(CHIP_ERROR_WRITE_FAILED); return; } + mWriteOffset += imageProcessor->mBlock.size(); // Keep our own track of how far we've written imageProcessor->mParams.downloadedBytes += imageProcessor->mBlock.size(); imageProcessor->mDownloader->FetchNextData(); } +// Store block data for HandleProcessBlock to access CHIP_ERROR OTAImageProcessorImpl::SetBlock(ByteSpan & block) { if ((block.data() == nullptr) || block.empty()) @@ -168,9 +199,11 @@ CHIP_ERROR OTAImageProcessorImpl::SetBlock(ByteSpan & block) return CHIP_NO_ERROR; } - // Allocate memory for block data if it has not been done yet - if (mBlock.empty()) + // Allocate memory for block data if we don't have enough already + if (mBlock.size() < block.size()) { + ReleaseBlock(); + mBlock = MutableByteSpan(static_cast(chip::Platform::MemoryAlloc(block.size())), block.size()); if (mBlock.data() == nullptr) { diff --git a/src/platform/EFR32/OTAImageProcessorImpl.h b/src/platform/EFR32/OTAImageProcessorImpl.h index 77a13ca36e890c..6f60ea0001d8ec 100644 --- a/src/platform/EFR32/OTAImageProcessorImpl.h +++ b/src/platform/EFR32/OTAImageProcessorImpl.h @@ -55,7 +55,8 @@ class OTAImageProcessorImpl : public OTAImageProcessorInterface */ CHIP_ERROR ReleaseBlock(); - std::ofstream mOfs; + static uint16_t mWriteOffset; // End of last written block + static uint8_t mSlotId; // Bootloader storage slot MutableByteSpan mBlock; OTADownloader * mDownloader; };