From 10188652fa6bba992a8e65df4f22ce0a14758bee Mon Sep 17 00:00:00 2001 From: Kamil Kasperczyk <66371704+kkasperczyk-no@users.noreply.github.com> Date: Wed, 26 Jan 2022 09:03:51 +0100 Subject: [PATCH] [ota-requestor] Added API to get update state and progress. (#13581) * [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 --- .../clusters/ota-requestor/OTARequestor.cpp | 13 +++ src/app/clusters/ota-requestor/OTARequestor.h | 6 ++ .../ota-requestor/ota-requestor-server.cpp | 10 ++ .../ota-requestor/ota-requestor-server.h | 4 + src/include/platform/OTARequestorInterface.h | 7 ++ src/lib/shell/commands/Ota.cpp | 95 ++++++++++++++++++- .../nrfconnect/OTAImageProcessorImpl.cpp | 7 +- 7 files changed, 140 insertions(+), 2 deletions(-) diff --git a/src/app/clusters/ota-requestor/OTARequestor.cpp b/src/app/clusters/ota-requestor/OTARequestor.cpp index a00b0a50fb63c6..c5c24314493d95 100644 --- a/src/app/clusters/ota-requestor/OTARequestor.cpp +++ b/src/app/clusters/ota-requestor/OTARequestor.cpp @@ -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 & 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) { diff --git a/src/app/clusters/ota-requestor/OTARequestor.h b/src/app/clusters/ota-requestor/OTARequestor.h index b8ce786c9056f8..482d626a6d6526 100644 --- a/src/app/clusters/ota-requestor/OTARequestor.h +++ b/src/app/clusters/ota-requestor/OTARequestor.h @@ -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 & 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. diff --git a/src/app/clusters/ota-requestor/ota-requestor-server.cpp b/src/app/clusters/ota-requestor/ota-requestor-server.cpp index e87339bfe040ed..b7916b643a6e04 100644 --- a/src/app/clusters/ota-requestor/ota-requestor-server.cpp +++ b/src/app/clusters/ota-requestor/ota-requestor-server.cpp @@ -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 value) { EmberAfStatus status = EMBER_ZCL_STATUS_SUCCESS; @@ -124,6 +129,11 @@ EmberAfStatus OtaRequestorServerSetUpdateStateProgress(app::DataModel::Nullable< return status; } +EmberAfStatus OtaRequestorServerGetUpdateStateProgress(chip::EndpointId endpointId, DataModel::Nullable & value) +{ + return Attributes::UpdateStateProgress::Get(endpointId, value); +} + void OtaRequestorServerOnStateTransition(DataModel::Nullable previousState, OTAUpdateStateEnum newState, OTAChangeReasonEnum reason, DataModel::Nullable const & targetSoftwareVersion) { diff --git a/src/app/clusters/ota-requestor/ota-requestor-server.h b/src/app/clusters/ota-requestor/ota-requestor-server.h index ad0ecdd94e41b9..8493d9a81993d2 100644 --- a/src/app/clusters/ota-requestor/ota-requestor-server.h +++ b/src/app/clusters/ota-requestor/ota-requestor-server.h @@ -21,7 +21,11 @@ #include 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 value); +EmberAfStatus OtaRequestorServerGetUpdateStateProgress(chip::EndpointId endpointId, + chip::app::DataModel::Nullable & value); void OtaRequestorServerOnStateTransition( chip::app::DataModel::Nullable previousState, diff --git a/src/include/platform/OTARequestorInterface.h b/src/include/platform/OTARequestorInterface.h index 28febbfac64afe..1751e9de152739 100644 --- a/src/include/platform/OTARequestorInterface.h +++ b/src/include/platform/OTARequestorInterface.h @@ -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 & 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; }; diff --git a/src/lib/shell/commands/Ota.cpp b/src/lib/shell/commands/Ota.cpp index a483ce33fa181b..f0569d2c68bb24 100644 --- a/src/lib/shell/commands/Ota.cpp +++ b/src/lib/shell/commands/Ota.cpp @@ -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 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(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(nullptr)); + + return CHIP_NO_ERROR; +} + CHIP_ERROR OtaHandler(int argc, char ** argv) { if (argc == 0) @@ -100,9 +191,11 @@ void RegisterOtaCommands() static const shell_command_t subCommands[] = { { &QueryImageHandler, "query", "Query for a new image. Usage: ota query " }, { &ApplyImageHandler, "apply", - "Apply the current update. Usage ota apply " }, + "Apply the current update. Usage: ota apply " }, { &NotifyImageHandler, "notify", "Notify the new image has been applied. Usage: ota notify " }, + { &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)); diff --git a/src/platform/nrfconnect/OTAImageProcessorImpl.cpp b/src/platform/nrfconnect/OTAImageProcessorImpl.cpp index c31f321a70872b..4e3949fdae7dea 100644 --- a/src/platform/nrfconnect/OTAImageProcessorImpl.cpp +++ b/src/platform/nrfconnect/OTAImageProcessorImpl.cpp @@ -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); + } }); }