Skip to content

Commit 4fa88cd

Browse files
committed
[nrf toup][nrfconnect] Optimize OTA time
Reduced OTA time by 15-20% Signed-off-by: Adam Maciuga <adam.maciuga@nordicsemi.no>
1 parent 64e9bb2 commit 4fa88cd

2 files changed

Lines changed: 68 additions & 35 deletions

File tree

src/platform/nrfconnect/OTAImageProcessorImpl.cpp

Lines changed: 63 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
#include <app/clusters/ota-requestor/OTADownloader.h>
2323
#include <app/clusters/ota-requestor/OTARequestorInterface.h>
24+
#include <cstring>
2425
#include <lib/support/CodeUtils.h>
2526
#include <platform/CHIPDeviceLayer.h>
2627
#include <system/SystemError.h>
@@ -126,20 +127,29 @@ CHIP_ERROR OTAImageProcessorImpl::PrepareDownloadImpl()
126127

127128
CHIP_ERROR OTAImageProcessorImpl::Finalize()
128129
{
129-
PostOTAStateChangeEvent(DeviceLayer::kOtaDownloadComplete);
130-
DFUSync::GetInstance().Free(mDfuSyncMutexId);
131-
return System::MapErrorZephyr(dfu_multi_image_done(true));
130+
return DeviceLayer::SystemLayer().ScheduleLambda([this] {
131+
PostOTAStateChangeEvent(DeviceLayer::kOtaDownloadComplete);
132+
DFUSync::GetInstance().Free(mDfuSyncMutexId);
133+
CHIP_ERROR error = System::MapErrorZephyr(dfu_multi_image_done(true));
134+
if (error != CHIP_NO_ERROR)
135+
{
136+
ChipLogError(SoftwareUpdate, "OTA failed to finalize: %" CHIP_ERROR_FORMAT, error.Format());
137+
}
138+
});
132139
}
133140

134141
CHIP_ERROR OTAImageProcessorImpl::Abort()
135142
{
136-
CHIP_ERROR error = System::MapErrorZephyr(dfu_multi_image_done(false));
137-
138-
DFUSync::GetInstance().Free(mDfuSyncMutexId);
139-
TriggerFlashAction(ExternalFlashManager::Action::SLEEP);
140-
PostOTAStateChangeEvent(DeviceLayer::kOtaDownloadAborted);
141-
142-
return error;
143+
return DeviceLayer::SystemLayer().ScheduleLambda([this] {
144+
CHIP_ERROR error = System::MapErrorZephyr(dfu_multi_image_done(false));
145+
DFUSync::GetInstance().Free(mDfuSyncMutexId);
146+
TriggerFlashAction(ExternalFlashManager::Action::SLEEP);
147+
PostOTAStateChangeEvent(DeviceLayer::kOtaDownloadAborted);
148+
if (error != CHIP_NO_ERROR)
149+
{
150+
ChipLogError(SoftwareUpdate, "Failed to abort OTA: %" CHIP_ERROR_FORMAT, error.Format());
151+
}
152+
});
143153
}
144154

145155
CHIP_ERROR OTAImageProcessorImpl::Apply()
@@ -162,48 +172,66 @@ CHIP_ERROR OTAImageProcessorImpl::Apply()
162172
},
163173
nullptr /* context */);
164174
}
165-
else
166-
{
167-
PostOTAStateChangeEvent(DeviceLayer::kOtaApplyFailed);
168-
return System::MapErrorZephyr(err);
169-
}
175+
PostOTAStateChangeEvent(DeviceLayer::kOtaApplyFailed);
176+
return System::MapErrorZephyr(err);
170177
#else
171178
return System::MapErrorZephyr(err);
172179
#endif
173180
}
174181

182+
CHIP_ERROR OTAImageProcessorImpl::WriteToFlash(size_t offset, const uint8_t * chunk, size_t chunk_size)
183+
{
184+
int err = dfu_multi_image_write(offset, chunk, chunk_size);
185+
if (err != 0)
186+
{
187+
ChipLogError(SoftwareUpdate, "OTA block write failed %d", err);
188+
return CHIP_ERROR_WRITE_FAILED;
189+
}
190+
mParams.downloadedBytes += chunk_size;
191+
ChipLogDetail(SoftwareUpdate, "Downloaded %u/%u bytes", static_cast<unsigned>(mParams.downloadedBytes),
192+
static_cast<unsigned>(mParams.totalFileBytes));
193+
return CHIP_NO_ERROR;
194+
}
195+
175196
CHIP_ERROR OTAImageProcessorImpl::ProcessBlock(ByteSpan & aBlock)
176197
{
177198
VerifyOrReturnError(mDownloader != nullptr, CHIP_ERROR_INCORRECT_STATE);
178199

179200
CHIP_ERROR error = ProcessHeader(aBlock);
180201

181-
if (error == CHIP_NO_ERROR)
202+
const size_t blockOffset = static_cast<size_t>(mParams.downloadedBytes);
203+
const size_t blockSize = aBlock.size();
204+
205+
if (error == CHIP_NO_ERROR && blockSize > kBufferSize)
182206
{
183-
// DFU target library buffers data internally, so do not clone the block data.
184-
if (mParams.downloadedBytes > std::numeric_limits<size_t>::max())
185-
{
186-
error = CHIP_ERROR_BUFFER_TOO_SMALL;
187-
}
188-
else
189-
{
190-
error = System::MapErrorZephyr(
191-
dfu_multi_image_write(static_cast<size_t>(mParams.downloadedBytes), aBlock.data(), aBlock.size()));
192-
mParams.downloadedBytes += aBlock.size();
193-
}
207+
error = CHIP_ERROR_BUFFER_TOO_SMALL;
208+
}
209+
210+
if (error != CHIP_NO_ERROR)
211+
{
212+
return DeviceLayer::SystemLayer().ScheduleLambda([this, error] {
213+
mDownloader->EndDownload(error);
214+
PostOTAStateChangeEvent(DeviceLayer::kOtaDownloadFailed);
215+
});
194216
}
195217

196-
// Report the result back to the downloader asynchronously.
197-
return DeviceLayer::SystemLayer().ScheduleLambda([this, error, aBlock] {
198-
if (error == CHIP_NO_ERROR)
218+
memcpy(mStagingBuffer, aBlock.data(), blockSize);
219+
220+
return DeviceLayer::SystemLayer().ScheduleLambda([this, blockOffset, blockSize] {
221+
CHIP_ERROR err = CHIP_NO_ERROR;
222+
const bool isLastBlock = blockOffset + blockSize >= mParams.totalFileBytes;
223+
if (!isLastBlock)
199224
{
200-
ChipLogDetail(SoftwareUpdate, "Downloaded %u/%u bytes", static_cast<unsigned>(mParams.downloadedBytes),
201-
static_cast<unsigned>(mParams.totalFileBytes));
202-
mDownloader->FetchNextData();
225+
err = mDownloader->FetchNextData();
203226
}
204-
else
227+
if (err == CHIP_NO_ERROR)
205228
{
206-
mDownloader->EndDownload(error);
229+
err = WriteToFlash(blockOffset, mStagingBuffer, blockSize);
230+
}
231+
if (err != CHIP_NO_ERROR)
232+
{
233+
ChipLogError(SoftwareUpdate, "OTA block processing failed: %" CHIP_ERROR_FORMAT, err.Format());
234+
mDownloader->EndDownload(err);
207235
PostOTAStateChangeEvent(DeviceLayer::kOtaDownloadFailed);
208236
}
209237
});

src/platform/nrfconnect/OTAImageProcessorImpl.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,17 @@ class OTAImageProcessorImpl : public OTAImageProcessorInterface
4949
protected:
5050
CHIP_ERROR PrepareDownloadImpl();
5151
CHIP_ERROR ProcessHeader(ByteSpan & aBlock);
52+
CHIP_ERROR WriteToFlash(size_t offset, const uint8_t * chunk, size_t chunk_size);
5253

5354
OTADownloader * mDownloader = nullptr;
5455
OTAImageHeaderParser mHeaderParser;
5556
uint8_t mBuffer[kBufferSize];
5657
ExternalFlashManager * mFlashHandler;
5758

59+
/** When new data is fetched it is copied to the staging buffer,
60+
* this way we can simultaneously receive the next chunk and store the old one to flash */
61+
uint8_t mStagingBuffer[kBufferSize];
62+
5863
private:
5964
bool mImageConfirmed = false;
6065
uint32_t mDfuSyncMutexId;

0 commit comments

Comments
 (0)