From 00c268fc9aed9d685bd26238aec39f5b911e3ea0 Mon Sep 17 00:00:00 2001 From: Adam Maciuga Date: Mon, 2 Mar 2026 16:00:28 +0100 Subject: [PATCH] [nrf toup][nrfconnect] Optimize OTA time Reduced OTA time by 15-20% Signed-off-by: Adam Maciuga --- .../nrfconnect/OTAImageProcessorImpl.cpp | 99 ++++++++++++------- .../nrfconnect/OTAImageProcessorImpl.h | 5 + 2 files changed, 69 insertions(+), 35 deletions(-) diff --git a/src/platform/nrfconnect/OTAImageProcessorImpl.cpp b/src/platform/nrfconnect/OTAImageProcessorImpl.cpp index 1cd3f051d13..e47956be3df 100644 --- a/src/platform/nrfconnect/OTAImageProcessorImpl.cpp +++ b/src/platform/nrfconnect/OTAImageProcessorImpl.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -126,20 +127,29 @@ CHIP_ERROR OTAImageProcessorImpl::PrepareDownloadImpl() CHIP_ERROR OTAImageProcessorImpl::Finalize() { - PostOTAStateChangeEvent(DeviceLayer::kOtaDownloadComplete); - DFUSync::GetInstance().Free(mDfuSyncMutexId); - return System::MapErrorZephyr(dfu_multi_image_done(true)); + return DeviceLayer::SystemLayer().ScheduleLambda([this] { + PostOTAStateChangeEvent(DeviceLayer::kOtaDownloadComplete); + DFUSync::GetInstance().Free(mDfuSyncMutexId); + CHIP_ERROR error = System::MapErrorZephyr(dfu_multi_image_done(true)); + if (error != CHIP_NO_ERROR) + { + ChipLogError(SoftwareUpdate, "OTA failed to finalize: %" CHIP_ERROR_FORMAT, error.Format()); + } + }); } CHIP_ERROR OTAImageProcessorImpl::Abort() { - CHIP_ERROR error = System::MapErrorZephyr(dfu_multi_image_done(false)); - - DFUSync::GetInstance().Free(mDfuSyncMutexId); - TriggerFlashAction(ExternalFlashManager::Action::SLEEP); - PostOTAStateChangeEvent(DeviceLayer::kOtaDownloadAborted); - - return error; + return DeviceLayer::SystemLayer().ScheduleLambda([this] { + CHIP_ERROR error = System::MapErrorZephyr(dfu_multi_image_done(false)); + DFUSync::GetInstance().Free(mDfuSyncMutexId); + TriggerFlashAction(ExternalFlashManager::Action::SLEEP); + PostOTAStateChangeEvent(DeviceLayer::kOtaDownloadAborted); + if (error != CHIP_NO_ERROR) + { + ChipLogError(SoftwareUpdate, "Failed to abort OTA: %" CHIP_ERROR_FORMAT, error.Format()); + } + }); } CHIP_ERROR OTAImageProcessorImpl::Apply() @@ -162,48 +172,67 @@ CHIP_ERROR OTAImageProcessorImpl::Apply() }, nullptr /* context */); } - else - { - PostOTAStateChangeEvent(DeviceLayer::kOtaApplyFailed); - return System::MapErrorZephyr(err); - } + PostOTAStateChangeEvent(DeviceLayer::kOtaApplyFailed); + return System::MapErrorZephyr(err); #else return System::MapErrorZephyr(err); #endif } +CHIP_ERROR OTAImageProcessorImpl::WriteToFlash(size_t offset, const uint8_t * chunk, size_t chunk_size) +{ + int err = dfu_multi_image_write(offset, chunk, chunk_size); + if (err != 0) + { + ChipLogError(SoftwareUpdate, "OTA block write failed %d", err); + return CHIP_ERROR_WRITE_FAILED; + } + mParams.downloadedBytes += chunk_size; + ChipLogDetail(SoftwareUpdate, "Downloaded %u/%u bytes", static_cast(mParams.downloadedBytes), + static_cast(mParams.totalFileBytes)); + return CHIP_NO_ERROR; +} + CHIP_ERROR OTAImageProcessorImpl::ProcessBlock(ByteSpan & aBlock) { VerifyOrReturnError(mDownloader != nullptr, CHIP_ERROR_INCORRECT_STATE); CHIP_ERROR error = ProcessHeader(aBlock); - if (error == CHIP_NO_ERROR) + const size_t blockOffset = static_cast(mParams.downloadedBytes); + const size_t blockSize = aBlock.size(); + + if (error == CHIP_NO_ERROR && blockSize > kBufferSize) { - // DFU target library buffers data internally, so do not clone the block data. - if (mParams.downloadedBytes > std::numeric_limits::max()) - { - error = CHIP_ERROR_BUFFER_TOO_SMALL; - } - else - { - error = System::MapErrorZephyr( - dfu_multi_image_write(static_cast(mParams.downloadedBytes), aBlock.data(), aBlock.size())); - mParams.downloadedBytes += aBlock.size(); - } + error = CHIP_ERROR_BUFFER_TOO_SMALL; + } + + if (error != CHIP_NO_ERROR) + { + DeviceLayer::SystemLayer().ScheduleLambda([this, error] { + mDownloader->EndDownload(error); + PostOTAStateChangeEvent(DeviceLayer::kOtaDownloadFailed); + }); + return error; } - // Report the result back to the downloader asynchronously. - return DeviceLayer::SystemLayer().ScheduleLambda([this, error, aBlock] { - if (error == CHIP_NO_ERROR) + memcpy(mStagingBuffer, aBlock.data(), blockSize); + + return DeviceLayer::SystemLayer().ScheduleLambda([this, blockOffset, blockSize] { + CHIP_ERROR err = CHIP_NO_ERROR; + const bool isLastBlock = blockOffset + blockSize >= mParams.totalFileBytes; + if (!isLastBlock) { - ChipLogDetail(SoftwareUpdate, "Downloaded %u/%u bytes", static_cast(mParams.downloadedBytes), - static_cast(mParams.totalFileBytes)); - mDownloader->FetchNextData(); + err = mDownloader->FetchNextData(); } - else + if (err == CHIP_NO_ERROR) { - mDownloader->EndDownload(error); + err = WriteToFlash(blockOffset, mStagingBuffer, blockSize); + } + if (err != CHIP_NO_ERROR) + { + ChipLogError(SoftwareUpdate, "OTA block processing failed: %" CHIP_ERROR_FORMAT, err.Format()); + mDownloader->EndDownload(err); PostOTAStateChangeEvent(DeviceLayer::kOtaDownloadFailed); } }); diff --git a/src/platform/nrfconnect/OTAImageProcessorImpl.h b/src/platform/nrfconnect/OTAImageProcessorImpl.h index 9209aeaf712..2592c2e80a2 100644 --- a/src/platform/nrfconnect/OTAImageProcessorImpl.h +++ b/src/platform/nrfconnect/OTAImageProcessorImpl.h @@ -49,12 +49,17 @@ class OTAImageProcessorImpl : public OTAImageProcessorInterface protected: CHIP_ERROR PrepareDownloadImpl(); CHIP_ERROR ProcessHeader(ByteSpan & aBlock); + CHIP_ERROR WriteToFlash(size_t offset, const uint8_t * chunk, size_t chunk_size); OTADownloader * mDownloader = nullptr; OTAImageHeaderParser mHeaderParser; uint8_t mBuffer[kBufferSize]; ExternalFlashManager * mFlashHandler; + /** When new data is fetched it is copied to the staging buffer, + * this way we can simultaneously receive the next chunk and store the old one to flash */ + uint8_t mStagingBuffer[kBufferSize]; + private: bool mImageConfirmed = false; uint32_t mDfuSyncMutexId;