Skip to content

Commit

Permalink
[ota-requestor] Added API to get update state and progress. (#13581)
Browse files Browse the repository at this point in the history
* [ota-requestor] Added API to get update state and progress.

Current OTARequestor API doesn't allow to get update state
or progress.

* Added ota state and ota progress shell commands
* Added OTARequestor GetState and GetUpdateProgress methods
* Moved GetPercentComplete method from OTAImageProcessor
to OTADownloader, as it has all necessary data to calculate
progress, while OTAImageProcessor does not.

* Addressed review comments
  • Loading branch information
kkasperczyk-no authored and pull[bot] committed Nov 23, 2023
1 parent e01c0dd commit 1018865
Show file tree
Hide file tree
Showing 7 changed files with 140 additions and 2 deletions.
13 changes: 13 additions & 0 deletions src/app/clusters/ota-requestor/OTARequestor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,19 @@ void OTARequestor::ConnectToProvider(OnConnectedAction onConnectedAction)
ChipLogError(SoftwareUpdate, "Cannot establish connection to provider: %" CHIP_ERROR_FORMAT, err.Format()));
}

CHIP_ERROR OTARequestor::GetUpdateProgress(EndpointId endpointId, app::DataModel::Nullable<uint8_t> & progress)
{
VerifyOrReturnError(OtaRequestorServerGetUpdateStateProgress(endpointId, progress) == EMBER_ZCL_STATUS_SUCCESS,
CHIP_ERROR_BAD_REQUEST);
return CHIP_NO_ERROR;
}

CHIP_ERROR OTARequestor::GetState(EndpointId endpointId, OTAUpdateStateEnum & state)
{
VerifyOrReturnError(OtaRequestorServerGetUpdateState(endpointId, state) == EMBER_ZCL_STATUS_SUCCESS, CHIP_ERROR_BAD_REQUEST);
return CHIP_NO_ERROR;
}

// Called whenever FindOrEstablishSession is successful
void OTARequestor::OnConnected(void * context, OperationalDeviceProxy * deviceProxy)
{
Expand Down
6 changes: 6 additions & 0 deletions src/app/clusters/ota-requestor/OTARequestor.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,12 @@ class OTARequestor : public OTARequestorInterface, public BDXDownloader::StateDe
*/
void ConnectToProvider(OnConnectedAction onConnectedAction);

// Get image update progress in percents unit
CHIP_ERROR GetUpdateProgress(EndpointId endpointId, app::DataModel::Nullable<uint8_t> & progress) override;

// Get requestor state
CHIP_ERROR GetState(EndpointId endpointId, app::Clusters::OtaSoftwareUpdateRequestor::OTAUpdateStateEnum & state) override;

/**
* Called to indicate test mode. This is when the Requestor is used as a test tool and the the provider parameters are supplied
* explicitly.
Expand Down
10 changes: 10 additions & 0 deletions src/app/clusters/ota-requestor/ota-requestor-server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ EmberAfStatus OtaRequestorServerSetUpdateState(OTAUpdateStateEnum value)
return status;
}

EmberAfStatus OtaRequestorServerGetUpdateState(chip::EndpointId endpointId, OTAUpdateStateEnum & value)
{
return Attributes::UpdateState::Get(endpointId, &value);
}

EmberAfStatus OtaRequestorServerSetUpdateStateProgress(app::DataModel::Nullable<uint8_t> value)
{
EmberAfStatus status = EMBER_ZCL_STATUS_SUCCESS;
Expand All @@ -124,6 +129,11 @@ EmberAfStatus OtaRequestorServerSetUpdateStateProgress(app::DataModel::Nullable<
return status;
}

EmberAfStatus OtaRequestorServerGetUpdateStateProgress(chip::EndpointId endpointId, DataModel::Nullable<uint8_t> & value)
{
return Attributes::UpdateStateProgress::Get(endpointId, value);
}

void OtaRequestorServerOnStateTransition(DataModel::Nullable<OTAUpdateStateEnum> previousState, OTAUpdateStateEnum newState,
OTAChangeReasonEnum reason, DataModel::Nullable<uint32_t> const & targetSoftwareVersion)
{
Expand Down
4 changes: 4 additions & 0 deletions src/app/clusters/ota-requestor/ota-requestor-server.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@
#include <app-common/zap-generated/attributes/Accessors.h>

EmberAfStatus OtaRequestorServerSetUpdateState(chip::app::Clusters::OtaSoftwareUpdateRequestor::OTAUpdateStateEnum value);
EmberAfStatus OtaRequestorServerGetUpdateState(chip::EndpointId endpointId,
chip::app::Clusters::OtaSoftwareUpdateRequestor::OTAUpdateStateEnum & value);
EmberAfStatus OtaRequestorServerSetUpdateStateProgress(chip::app::DataModel::Nullable<uint8_t> value);
EmberAfStatus OtaRequestorServerGetUpdateStateProgress(chip::EndpointId endpointId,
chip::app::DataModel::Nullable<uint8_t> & value);

void OtaRequestorServerOnStateTransition(
chip::app::DataModel::Nullable<chip::app::Clusters::OtaSoftwareUpdateRequestor::OTAUpdateStateEnum> previousState,
Expand Down
7 changes: 7 additions & 0 deletions src/include/platform/OTARequestorInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ class OTARequestorInterface
// Send NotifyUpdateApplied command
virtual void NotifyUpdateApplied(uint32_t version) = 0;

// Get image update progress in percents unit
virtual CHIP_ERROR GetUpdateProgress(EndpointId endpointId, chip::app::DataModel::Nullable<uint8_t> & progress) = 0;

// Get requestor state
virtual CHIP_ERROR GetState(EndpointId endpointId,
chip::app::Clusters::OtaSoftwareUpdateRequestor::OTAUpdateStateEnum & state) = 0;

// Manually set OTA Provider parameters
virtual void TestModeSetProviderParameters(NodeId nodeId, FabricIndex fabIndex, EndpointId endpointId) = 0;
};
Expand Down
95 changes: 94 additions & 1 deletion src/lib/shell/commands/Ota.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,97 @@ CHIP_ERROR NotifyImageHandler(int argc, char ** argv)
return CHIP_NO_ERROR;
}

static void HandleState(intptr_t context)
{
app::Clusters::OtaSoftwareUpdateRequestor::OTAUpdateStateEnum state;
CHIP_ERROR err = GetRequestorInstance()->GetState(0, state);

if (err == CHIP_NO_ERROR)
{
streamer_printf(streamer_get(), "Update state: ");
switch (state)
{
case app::Clusters::OtaSoftwareUpdateRequestor::OTAUpdateStateEnum::kUnknown:
streamer_printf(streamer_get(), "unknown");
break;
case app::Clusters::OtaSoftwareUpdateRequestor::OTAUpdateStateEnum::kIdle:
streamer_printf(streamer_get(), "idle");
break;
case app::Clusters::OtaSoftwareUpdateRequestor::OTAUpdateStateEnum::kQuerying:
streamer_printf(streamer_get(), "querying");
break;
case app::Clusters::OtaSoftwareUpdateRequestor::OTAUpdateStateEnum::kDelayedOnQuery:
streamer_printf(streamer_get(), "delayed on query");
break;
case app::Clusters::OtaSoftwareUpdateRequestor::OTAUpdateStateEnum::kDownloading:
streamer_printf(streamer_get(), "downloading");
break;
case app::Clusters::OtaSoftwareUpdateRequestor::OTAUpdateStateEnum::kApplying:
streamer_printf(streamer_get(), "applying");
break;
case app::Clusters::OtaSoftwareUpdateRequestor::OTAUpdateStateEnum::kDelayedOnApply:
streamer_printf(streamer_get(), "delayed on apply");
break;
case app::Clusters::OtaSoftwareUpdateRequestor::OTAUpdateStateEnum::kRollingBack:
streamer_printf(streamer_get(), "rolling back");
break;
case app::Clusters::OtaSoftwareUpdateRequestor::OTAUpdateStateEnum::kDelayedOnUserConsent:
streamer_printf(streamer_get(), "delayed on user consent");
break;
default:
streamer_printf(streamer_get(), "invalid");
break;
}
streamer_printf(streamer_get(), "\r\n");
}
else
{
streamer_printf(streamer_get(), "Error: %" CHIP_ERROR_FORMAT "\r\n", err.Format());
}
}

static void HandleProgress(intptr_t context)
{
chip::app::DataModel::Nullable<uint8_t> progress;
CHIP_ERROR err = GetRequestorInstance()->GetUpdateProgress(0, progress);

if (err == CHIP_NO_ERROR)
{
if (progress.IsNull())
{
streamer_printf(streamer_get(), "Update progress: NULL\r\n");
}
else
{
streamer_printf(streamer_get(), "Update progress: %d %%\r\n", progress);
}
}
else
{
streamer_printf(streamer_get(), "Error: %" CHIP_ERROR_FORMAT "\r\n", err.Format());
}
}

CHIP_ERROR StateHandler(int argc, char ** argv)
{
VerifyOrReturnError(GetRequestorInstance() != nullptr, CHIP_ERROR_INCORRECT_STATE);
VerifyOrReturnError(argc == 0, CHIP_ERROR_INVALID_ARGUMENT);

PlatformMgr().ScheduleWork(HandleState, reinterpret_cast<intptr_t>(nullptr));

return CHIP_NO_ERROR;
}

CHIP_ERROR ProgressHandler(int argc, char ** argv)
{
VerifyOrReturnError(GetRequestorInstance() != nullptr, CHIP_ERROR_INCORRECT_STATE);
VerifyOrReturnError(argc == 0, CHIP_ERROR_INVALID_ARGUMENT);

PlatformMgr().ScheduleWork(HandleProgress, reinterpret_cast<intptr_t>(nullptr));

return CHIP_NO_ERROR;
}

CHIP_ERROR OtaHandler(int argc, char ** argv)
{
if (argc == 0)
Expand All @@ -100,9 +191,11 @@ void RegisterOtaCommands()
static const shell_command_t subCommands[] = {
{ &QueryImageHandler, "query", "Query for a new image. Usage: ota query <fabric-index> <provider-node-id> <endpoint-id>" },
{ &ApplyImageHandler, "apply",
"Apply the current update. Usage ota apply <fabric-index> <provider-node-id> <endpoint-id>" },
"Apply the current update. Usage: ota apply <fabric-index> <provider-node-id> <endpoint-id>" },
{ &NotifyImageHandler, "notify",
"Notify the new image has been applied. Usage: ota notify <fabric-index> <provider-node-id> <endpoint-id>" },
{ &StateHandler, "state", "Gets state of a current image update process. Usage: ota state" },
{ &ProgressHandler, "progress", "Gets progress of a current image update process. Usage: ota progress" }
};

sSubShell.RegisterCommands(subCommands, ArraySize(subCommands));
Expand Down
7 changes: 6 additions & 1 deletion src/platform/nrfconnect/OTAImageProcessorImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,16 @@ CHIP_ERROR OTAImageProcessorImpl::ProcessBlock(ByteSpan & block)
CHIP_ERROR error = System::MapErrorZephyr(dfu_target_write(block.data(), block.size()));

// Report the result back to the downloader asynchronously.
return DeviceLayer::SystemLayer().ScheduleLambda([this, error] {
return DeviceLayer::SystemLayer().ScheduleLambda([this, error, block] {
if (error == CHIP_NO_ERROR)
{
mParams.downloadedBytes += block.size();
mDownloader->FetchNextData();
}
else
{
mDownloader->EndDownload(error);
}
});
}

Expand Down

0 comments on commit 1018865

Please sign in to comment.