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

[EFR32 OTA] Invoke Silabs API for writing, verifying and applying the image #13499

Merged
merged 13 commits into from
Jan 13, 2022
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
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 @@ -179,6 +221,8 @@ int main(void)
// Connect the Requestor and Requestor Driver objects
gRequestorCore.SetOtaRequestorDriver(&gRequestorUser);

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