Skip to content

Commit

Permalink
[QPG] OTA updates + Move to secure bootloader (#20224)
Browse files Browse the repository at this point in the history
* [QPG] * OTA updates + Move to secure bootloader
      * SDK submodule update for changes

* Restyled by clang-format

* [QPG] * Update persistent-storage app to SDK API change

Co-authored-by: Restyled.io <commits@restyled.io>
  • Loading branch information
2 people authored and pull[bot] committed Feb 13, 2024
1 parent 1a51b63 commit 2369476
Show file tree
Hide file tree
Showing 10 changed files with 153 additions and 51 deletions.
9 changes: 9 additions & 0 deletions examples/lighting-app/qpg/include/CHIPProjectConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@
*/
#define CHIP_DEVICE_CONFIG_DEVICE_HARDWARE_VERSION 1

/**
* CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION
*
* A uint32_t identifying the software version running on the device.
*/
#ifndef CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION
#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION 0x0001
#endif

/**
* CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING
*
Expand Down
20 changes: 12 additions & 8 deletions examples/persistent-storage/qpg/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,25 +47,29 @@ void TestTask(void * pvParameter)
}
}

void Application_Init(void)
{
/* Launch application task */
qvCHIP_Printf(LOG_MODULE_ID, "============================");
qvCHIP_Printf(LOG_MODULE_ID, "Qorvo " APP_NAME " Launching");
qvCHIP_Printf(LOG_MODULE_ID, "============================");

// Run tests
xTaskCreateStatic(TestTask, APP_NAME, 2048, NULL, 1, appStack, &appTaskStruct);
}

int main(void)
{

int result;

/* Initialize Qorvo stack */
result = qvCHIP_init();
result = qvCHIP_init(Application_Init);
if (result < 0)
{
goto exit;
}

/* Launch application task */
qvCHIP_Printf(LOG_MODULE_ID, "============================");
qvCHIP_Printf(LOG_MODULE_ID, "Qorvo " APP_NAME " Launching");
qvCHIP_Printf(LOG_MODULE_ID, "============================");

// Run tests
xTaskCreateStatic(TestTask, APP_NAME, 2048, NULL, 1, appStack, &appTaskStruct);
qvCHIP_Printf(LOG_MODULE_ID, "Starting FreeRTOS scheduler");
vTaskStartScheduler();

Expand Down
38 changes: 15 additions & 23 deletions examples/platform/qpg/app/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,20 @@ constexpr int extDiscTimeoutSecs = 20;
/*****************************************************************************
* Application Function Definitions
*****************************************************************************/
CHIP_ERROR CHIP_Init(void);

int Application_Init(void)
void Application_Init(void)
{
CHIP_ERROR error;

/* Initialize CHIP stack */
error = CHIP_Init();
if (error != CHIP_NO_ERROR)
{
ChipLogError(NotSpecified, "CHIP_Init failed");
return;
}

/* Launch application task */
ChipLogProgress(NotSpecified, "============================");
ChipLogProgress(NotSpecified, "Qorvo " APP_NAME " Launching");
Expand All @@ -81,10 +92,8 @@ int Application_Init(void)
if (ret != CHIP_NO_ERROR)
{
ChipLogError(NotSpecified, "GetAppTask().Init() failed");
return -1;
return;
}

return 0;
}

CHIP_ERROR CHIP_Init(void)
Expand Down Expand Up @@ -172,32 +181,15 @@ CHIP_ERROR CHIP_Init(void)
int main(void)
{
int result;
CHIP_ERROR error;

/* Initialize Qorvo stack */
result = qvCHIP_init();
if (result < 0)
{
goto exit;
}

/* Initialize CHIP stack */
error = CHIP_Init();
if (error != CHIP_NO_ERROR)
{
goto exit;
}

/* Application task */
result = Application_Init();
result = qvCHIP_init(Application_Init);
if (result < 0)
{
goto exit;
return 0;
}

/* Start FreeRTOS */
vTaskStartScheduler();

exit:
return 0;
}
16 changes: 16 additions & 0 deletions examples/platform/qpg/ota/ota.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,19 @@ OTAImageProcessorImpl gImageProcessor;
* Application Function Definitions
*****************************************************************************/

bool OtaHeaderValidationCb(qvCHIP_Ota_ImageHeader_t imageHeader)
{
// Check that the image matches vendor and product ID and that the version is higher than what we currently have
if (imageHeader.vendorId != CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID ||
imageHeader.productId != CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID ||
imageHeader.softwareVersion <= CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION)
{
return false;
}

return true;
}

void InitializeOTARequestor(void)
{
// Initialize and interconnect the Requestor and Image Processor objects
Expand All @@ -60,6 +73,9 @@ void InitializeOTARequestor(void)
gImageProcessor.SetOTADownloader(&gDownloader);
gDownloader.SetImageProcessorDelegate(&gImageProcessor);
gRequestorUser.Init(&gRequestorCore, &gImageProcessor);

// Initialize OTA image validation callback
qvCHIP_OtaSetHeaderValidationCb(OtaHeaderValidationCb);
}

void TriggerOTAQuery(void)
Expand Down
2 changes: 1 addition & 1 deletion src/platform/qpg/CHIPDevicePlatformConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
// ========== Platform-specific Configuration Overrides =========

#ifndef CHIP_DEVICE_CONFIG_CHIP_TASK_STACK_SIZE
#define CHIP_DEVICE_CONFIG_CHIP_TASK_STACK_SIZE (5 * 1024)
#define CHIP_DEVICE_CONFIG_CHIP_TASK_STACK_SIZE (6 * 1024)
#endif // CHIP_DEVICE_CONFIG_CHIP_TASK_STACK_SIZE

#ifndef CHIP_DEVICE_CONFIG_THREAD_TASK_STACK_SIZE
Expand Down
90 changes: 82 additions & 8 deletions src/platform/qpg/OTAImageProcessorImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,87 @@
*/

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

#include "OTAImageProcessorImpl.h"

namespace chip {

bool OTAImageProcessorImpl::IsFirstImageRun()
{
OTARequestorInterface * requestor = chip::GetRequestorInstance();
if (requestor == nullptr)
{
return false;
}

return requestor->GetCurrentUpdateState() == OTARequestorInterface::OTAUpdateStateEnum::kApplying;
}

CHIP_ERROR OTAImageProcessorImpl::ConfirmCurrentImage()
{
OTARequestorInterface * requestor = chip::GetRequestorInstance();
if (requestor == nullptr)
{
return CHIP_ERROR_INTERNAL;
}

uint32_t currentVersion;
ReturnErrorOnFailure(DeviceLayer::ConfigurationMgr().GetSoftwareVersion(currentVersion));

if (currentVersion != requestor->GetTargetVersion())
{
return CHIP_ERROR_INCORRECT_STATE;
}

return CHIP_NO_ERROR;
}

CHIP_ERROR OTAImageProcessorImpl::PrepareDownload()
{

// Get OTA status - under what circumstances does prepared break?
// what happens if a prepare is pending and another one is invoked
// Should we store the state here and wait til we receive notification
// Should we store the state here and wait until we receive notification

mHeaderParser.Init();

DeviceLayer::PlatformMgr().ScheduleWork(HandlePrepareDownload, reinterpret_cast<intptr_t>(this));
return CHIP_NO_ERROR;
}

CHIP_ERROR OTAImageProcessorImpl::ProcessHeader(ByteSpan & block)
{
if (mHeaderParser.IsInitialized())
{
OTAImageHeader header;
CHIP_ERROR error = mHeaderParser.AccumulateAndDecode(block, header);

// Needs more data to decode the header
ReturnErrorCodeIf(error == CHIP_ERROR_BUFFER_TOO_SMALL, CHIP_NO_ERROR);
ReturnErrorOnFailure(error);

mParams.totalFileBytes = header.mPayloadSize;
mHeaderParser.Clear();

// Load qvCHIP_Ota header structure and call application callback to validate image header
qvCHIP_Ota_ImageHeader_t qvCHIP_OtaImgHeader;
this->mSwVer = header.mSoftwareVersion; // Store software version in imageProcessor as well
qvCHIP_OtaImgHeader.vendorId = header.mVendorId;
qvCHIP_OtaImgHeader.productId = header.mProductId;
qvCHIP_OtaImgHeader.softwareVersion = header.mSoftwareVersion;
qvCHIP_OtaImgHeader.minApplicableVersion = header.mMinApplicableVersion.ValueOr(0);
qvCHIP_OtaImgHeader.maxApplicableVersion = header.mMaxApplicableVersion.ValueOr(0);

if (true != qvCHIP_OtaValidateImage(qvCHIP_OtaImgHeader))
{
return CHIP_ERROR_UNSUPPORTED_EXCHANGE_VERSION;
}
}

return CHIP_NO_ERROR;
}

CHIP_ERROR OTAImageProcessorImpl::Finalize()
{
DeviceLayer::PlatformMgr().ScheduleWork(HandleFinalize, reinterpret_cast<intptr_t>(this));
Expand All @@ -57,16 +122,27 @@ CHIP_ERROR OTAImageProcessorImpl::Abort()

CHIP_ERROR OTAImageProcessorImpl::ProcessBlock(ByteSpan & block)
{
CHIP_ERROR err;

if ((block.data() == nullptr) || block.empty())
{
return CHIP_ERROR_INVALID_ARGUMENT;
}

// Process block header info
err = ProcessHeader(block);
if (err != CHIP_NO_ERROR)
{
ChipLogError(SoftwareUpdate, "Cannot process block header: %" CHIP_ERROR_FORMAT, err.Format());
return err;
}

// Store block data for HandleProcessBlock to access
CHIP_ERROR err = SetBlock(block);
err = SetBlock(block);
if (err != CHIP_NO_ERROR)
{
ChipLogError(SoftwareUpdate, "Cannot set block data: %" CHIP_ERROR_FORMAT, err.Format());
return err;
}

DeviceLayer::PlatformMgr().ScheduleWork(HandleProcessBlock, reinterpret_cast<intptr_t>(this));
Expand Down Expand Up @@ -109,8 +185,7 @@ void OTAImageProcessorImpl::HandleFinalize(intptr_t context)

ChipLogProgress(SoftwareUpdate, "Q: HandleFinalize");

// FIXME - Versions need to be filled in
qvCHIP_OtaSetPendingImage(imageProcessor->mSwVer /*swVer*/, imageProcessor->mHwVer /*hwVer*/, qvCHIP_OtaGetAreaStartAddress(),
qvCHIP_OtaSetPendingImage(imageProcessor->mSwVer /*swVer*/, CHIP_DEVICE_CONFIG_DEVICE_HARDWARE_VERSION /*hwVer*/, 0,
static_cast<std::uint32_t>(imageProcessor->mParams.downloadedBytes) /*imgSz*/);

imageProcessor->ReleaseBlock();
Expand Down Expand Up @@ -149,11 +224,10 @@ void OTAImageProcessorImpl::HandleProcessBlock(intptr_t context)
}

ChipLogProgress(SoftwareUpdate, "Q: HandleProcessBlock");
// TODO: Process block header if any

status = qvCHIP_OtaWriteChunk(qvCHIP_OtaGetAreaStartAddress() + imageProcessor->mParams.downloadedBytes,
static_cast<std::uint16_t>(imageProcessor->mBlock.size()),
reinterpret_cast<std::uint8_t *>(imageProcessor->mBlock.data()));
status =
qvCHIP_OtaWriteChunk(imageProcessor->mParams.downloadedBytes, static_cast<std::uint16_t>(imageProcessor->mBlock.size()),
reinterpret_cast<std::uint8_t *>(imageProcessor->mBlock.data()));

if (status != qvCHIP_OtaStatusSuccess)
{
Expand Down
9 changes: 6 additions & 3 deletions src/platform/qpg/OTAImageProcessorImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#pragma once

#include <app/clusters/ota-requestor/OTADownloader.h>
#include <lib/core/OTAImageHeader.h>
#include <platform/CHIPDeviceLayer.h>
#include <platform/OTAImageProcessor.h>

Expand All @@ -29,12 +30,13 @@ class OTAImageProcessorImpl : public OTAImageProcessorInterface
public:
//////////// OTAImageProcessorInterface Implementation ///////////////
CHIP_ERROR PrepareDownload() override;
CHIP_ERROR ProcessHeader(ByteSpan & block);
CHIP_ERROR Finalize() override;
CHIP_ERROR Apply() override;
CHIP_ERROR Abort() override;
CHIP_ERROR ProcessBlock(ByteSpan & block) override;
bool IsFirstImageRun() override { return false; }
CHIP_ERROR ConfirmCurrentImage() override { return CHIP_NO_ERROR; }
bool IsFirstImageRun() override;
CHIP_ERROR ConfirmCurrentImage() override;

void SetOTADownloader(OTADownloader * downloader) { mDownloader = downloader; }

Expand All @@ -59,7 +61,8 @@ class OTAImageProcessorImpl : public OTAImageProcessorInterface
std::uint32_t mHwVer;

MutableByteSpan mBlock;
OTADownloader * mDownloader;
OTADownloader * mDownloader = nullptr;
OTAImageHeaderParser mHeaderParser;
};

} // namespace chip
16 changes: 10 additions & 6 deletions third_party/qpg_sdk/qpg_executable.gni
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,9 @@

import("//build_overrides/build.gni")
import("//build_overrides/chip.gni")
import("//build_overrides/pigweed.gni")

import("${build_root}/toolchain/flashable_executable.gni")
import("${chip_root}/src/platform/device.gni")
import("${dir_pw_build}/python_action.gni")
import("qpg_sdk.gni")

# Run the generator script that takes a .HEX file and adds the OTA header to it.
Expand All @@ -43,7 +41,7 @@ template("gen_ota_header") {
"data_deps",
])

pw_python_action(target_name) {
action(target_name) {
outputs = [ ota_header_script_name ]

args = ota_header_options
Expand Down Expand Up @@ -96,10 +94,8 @@ template("qpg_executable") {

# If OTA requestor is enabled, generate OTA image from HEX
if (chip_enable_ota_requestor) {
ota_image_name = invoker.output_name + ".ota"

gen_ota_header("$executable_target_name.ota") {
ota_header_script_name = "${root_out_dir}/${ota_image_name}"
ota_header_script_name = "${root_out_dir}/${executable_target_name}.ota"
out_dir = rebase_path(root_out_dir, root_build_dir)
ota_header_generator = "${qpg_sdk_root}/Tools/ota/generate_ota_img.py"

Expand All @@ -119,6 +115,14 @@ template("qpg_executable") {
"--out_file",
"${out_dir}/${invoker.output_name}.ota",
]),
string_join("=",
[
"--pem_file_path",
rebase_path(qpg_sdk_root, root_build_dir) +
"/Tools/ota/example_private_key.pem.example",
]),
"--pem_password=test1234",
"--sign",
]
deps = [ ":$executable_target_name" ]
}
Expand Down
2 changes: 1 addition & 1 deletion third_party/qpg_sdk/qpg_sdk.gni
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ template("qpg_sdk") {
"${qpg_sdk_root}/${qpg_sdk_lib_dir}/MatterQorvoGlue_${qpg_target_ic}_libbuild/libMatterQorvoGlue_${qpg_target_ic}_libbuild.a",
"${qpg_sdk_root}/${qpg_sdk_lib_dir}/QorvoStack_${qpg_target_ic}/libQorvoStack_${qpg_target_ic}.a",
"${qpg_sdk_root}/${qpg_sdk_lib_dir}/mbedtls_alt_${qpg_target_ic}/libmbedtls_alt_${qpg_target_ic}.a",
"${qpg_sdk_root}/${qpg_sdk_lib_dir}/Bootloader_${qpg_target_ic}/libBootloader_${qpg_target_ic}.a",
"${qpg_sdk_root}/${qpg_sdk_lib_dir}/Bootloader_${qpg_target_ic}_compr_secure/libBootloader_${qpg_target_ic}_compr_secure.a",
]
}

Expand Down
2 changes: 1 addition & 1 deletion third_party/qpg_sdk/repo
Submodule repo updated from a29b99 to fa660d

0 comments on commit 2369476

Please sign in to comment.