Skip to content

Commit

Permalink
[EFR32 OTA] Invoke Silabs API for writing, verifying and applying the…
Browse files Browse the repository at this point in the history
… 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 <andy314@gmail.com>

* Clean up comments and debug code

* Restyled by whitespace

* Restyled by clang-format

Co-authored-by: Zang MingJie <mingjiez@google.com>
Co-authored-by: Andrei Litvin <andy314@gmail.com>
Co-authored-by: Restyled.io <commits@restyled.io>
  • Loading branch information
4 people authored and pull[bot] committed Jun 22, 2023
1 parent e46893b commit 4495542
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 23 deletions.
44 changes: 44 additions & 0 deletions examples/ota-requestor-app/efr32/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
//=================================================================================
Expand Down Expand Up @@ -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);
Expand Down
77 changes: 55 additions & 22 deletions src/platform/EFR32/OTAImageProcessorImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,22 @@
* limitations under the License.
*/

#include "OTAImageProcessorImpl.h"
#include <app/clusters/ota-requestor/OTADownloader.h>

#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())
Expand All @@ -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;
}

Expand All @@ -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;
Expand All @@ -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<OTAImageProcessorImpl *>(context);

if (imageProcessor == nullptr)
{
ChipLogError(SoftwareUpdate, "ImageProcessor context is null");
Expand All @@ -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)
Expand All @@ -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());
Expand All @@ -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<OTAImageProcessorImpl *>(context);
if (imageProcessor == nullptr)
{
Expand All @@ -150,27 +175,35 @@ void OTAImageProcessorImpl::HandleProcessBlock(intptr_t context)

// TODO: Process block header if any

if (!imageProcessor->mOfs.write(reinterpret_cast<const char *>(imageProcessor->mBlock.data()),
static_cast<std::streamsize>(imageProcessor->mBlock.size())))
err = bootloader_eraseWriteStorage(mSlotId, mWriteOffset, reinterpret_cast<uint8_t *>(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())
{
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<uint8_t *>(chip::Platform::MemoryAlloc(block.size())), block.size());
if (mBlock.data() == nullptr)
{
Expand Down
3 changes: 2 additions & 1 deletion src/platform/EFR32/OTAImageProcessorImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand Down

0 comments on commit 4495542

Please sign in to comment.