Skip to content

Commit 6738434

Browse files
carol-applepull[bot]
authored andcommitted
[OTA] Add NotifyUpdateApplied API to OTA Requestor (#13555)
- This API should be called after an image has been successfully applied
1 parent 6e668e8 commit 6738434

File tree

10 files changed

+143
-34
lines changed

10 files changed

+143
-34
lines changed

src/app/clusters/ota-provider/ota-provider.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ bool emberAfOtaSoftwareUpdateProviderClusterNotifyUpdateAppliedCallback(
121121
EmberAfStatus status = EMBER_ZCL_STATUS_SUCCESS;
122122
OTAProviderDelegate * delegate = GetDelegate(endpoint);
123123

124-
ChipLogDetail(Zcl, "OTA Provider received NotifyUpdateUpplied");
124+
ChipLogDetail(Zcl, "OTA Provider received NotifyUpdateApplied");
125125

126126
if (SendStatusIfDelegateNull(endpoint))
127127
{

src/app/clusters/ota-requestor/OTARequestor.cpp

+74-24
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ void OTARequestor::OnQueryImageResponse(void * context, const QueryImageResponse
129129

130130
if (err != CHIP_NO_ERROR)
131131
{
132-
requestorCore->mOtaRequestorDriver->HandleError(OTAUpdateStateEnum::kQuerying, err);
132+
requestorCore->mOtaRequestorDriver->HandleError(UpdateFailureState::kQuerying, err);
133133
return;
134134
}
135135

@@ -153,7 +153,7 @@ void OTARequestor::OnQueryImageResponse(void * context, const QueryImageResponse
153153
SetUpdateStateAttribute(OTAUpdateStateEnum::kIdle);
154154
break;
155155
default:
156-
requestorCore->mOtaRequestorDriver->HandleError(OTAUpdateStateEnum::kQuerying, CHIP_ERROR_BAD_REQUEST);
156+
requestorCore->mOtaRequestorDriver->HandleError(UpdateFailureState::kQuerying, CHIP_ERROR_BAD_REQUEST);
157157
SetUpdateStateAttribute(OTAUpdateStateEnum::kIdle);
158158
break;
159159
}
@@ -165,7 +165,7 @@ void OTARequestor::OnQueryImageFailure(void * context, EmberAfStatus status)
165165
VerifyOrDie(requestorCore != nullptr);
166166

167167
ChipLogDetail(SoftwareUpdate, "QueryImage failure response %" PRIu8, status);
168-
requestorCore->mOtaRequestorDriver->HandleError(OTAUpdateStateEnum::kQuerying, CHIP_ERROR_BAD_REQUEST);
168+
requestorCore->mOtaRequestorDriver->HandleError(UpdateFailureState::kQuerying, CHIP_ERROR_BAD_REQUEST);
169169
SetUpdateStateAttribute(OTAUpdateStateEnum::kIdle);
170170
}
171171

@@ -198,7 +198,19 @@ void OTARequestor::OnApplyUpdateFailure(void * context, EmberAfStatus status)
198198
VerifyOrDie(requestorCore != nullptr);
199199

200200
ChipLogDetail(SoftwareUpdate, "ApplyUpdate failure response %" PRIu8, status);
201-
requestorCore->mOtaRequestorDriver->HandleError(OTAUpdateStateEnum::kApplying, CHIP_ERROR_BAD_REQUEST);
201+
requestorCore->mOtaRequestorDriver->HandleError(UpdateFailureState::kApplying, CHIP_ERROR_BAD_REQUEST);
202+
SetUpdateStateAttribute(OTAUpdateStateEnum::kIdle);
203+
}
204+
205+
void OTARequestor::OnNotifyUpdateAppliedResponse(void * context, const app::DataModel::NullObjectType & response) {}
206+
207+
void OTARequestor::OnNotifyUpdateAppliedFailure(void * context, EmberAfStatus status)
208+
{
209+
OTARequestor * requestorCore = static_cast<OTARequestor *>(context);
210+
VerifyOrDie(requestorCore != nullptr);
211+
212+
ChipLogDetail(SoftwareUpdate, "NotifyUpdateApplied failure response %" PRIu8, status);
213+
requestorCore->mOtaRequestorDriver->HandleError(UpdateFailureState::kNotifying, CHIP_ERROR_BAD_REQUEST);
202214
SetUpdateStateAttribute(OTAUpdateStateEnum::kIdle);
203215
}
204216

@@ -287,7 +299,7 @@ void OTARequestor::OnConnected(void * context, OperationalDeviceProxy * devicePr
287299
if (err != CHIP_NO_ERROR)
288300
{
289301
ChipLogError(SoftwareUpdate, "Failed to send QueryImage command: %" CHIP_ERROR_FORMAT, err.Format());
290-
requestorCore->mOtaRequestorDriver->HandleError(OTAUpdateStateEnum::kQuerying, err);
302+
requestorCore->mOtaRequestorDriver->HandleError(UpdateFailureState::kQuerying, err);
291303
return;
292304
}
293305

@@ -300,7 +312,7 @@ void OTARequestor::OnConnected(void * context, OperationalDeviceProxy * devicePr
300312
if (err != CHIP_NO_ERROR)
301313
{
302314
ChipLogError(SoftwareUpdate, "Failed to start download: %" CHIP_ERROR_FORMAT, err.Format());
303-
requestorCore->mOtaRequestorDriver->HandleError(OTAUpdateStateEnum::kDownloading, err);
315+
requestorCore->mOtaRequestorDriver->HandleError(UpdateFailureState::kDownloading, err);
304316
SetUpdateStateAttribute(OTAUpdateStateEnum::kIdle);
305317
return;
306318
}
@@ -314,14 +326,28 @@ void OTARequestor::OnConnected(void * context, OperationalDeviceProxy * devicePr
314326
if (err != CHIP_NO_ERROR)
315327
{
316328
ChipLogError(SoftwareUpdate, "Failed to send ApplyUpdate command: %" CHIP_ERROR_FORMAT, err.Format());
317-
requestorCore->mOtaRequestorDriver->HandleError(OTAUpdateStateEnum::kApplying, err);
329+
requestorCore->mOtaRequestorDriver->HandleError(UpdateFailureState::kApplying, err);
318330
SetUpdateStateAttribute(OTAUpdateStateEnum::kIdle);
319331
return;
320332
}
321333

322334
SetUpdateStateAttribute(OTAUpdateStateEnum::kApplying);
323335
break;
324336
}
337+
case kNotifyUpdateApplied: {
338+
CHIP_ERROR err = requestorCore->SendNotifyUpdateAppliedRequest(*deviceProxy);
339+
340+
if (err != CHIP_NO_ERROR)
341+
{
342+
ChipLogError(SoftwareUpdate, "Failed to send NotifyUpdateApplied command: %" CHIP_ERROR_FORMAT, err.Format());
343+
requestorCore->mOtaRequestorDriver->HandleError(UpdateFailureState::kNotifying, err);
344+
SetUpdateStateAttribute(OTAUpdateStateEnum::kIdle);
345+
return;
346+
}
347+
348+
SetUpdateStateAttribute(OTAUpdateStateEnum::kIdle);
349+
break;
350+
}
325351
default:
326352
break;
327353
}
@@ -339,13 +365,13 @@ void OTARequestor::OnConnectionFailure(void * context, PeerId peerId, CHIP_ERROR
339365
switch (requestorCore->mOnConnectedAction)
340366
{
341367
case kQueryImage:
342-
requestorCore->mOtaRequestorDriver->HandleError(OTAUpdateStateEnum::kQuerying, error);
368+
requestorCore->mOtaRequestorDriver->HandleError(UpdateFailureState::kQuerying, error);
343369
break;
344370
case kStartBDX:
345-
requestorCore->mOtaRequestorDriver->HandleError(OTAUpdateStateEnum::kDownloading, error);
371+
requestorCore->mOtaRequestorDriver->HandleError(UpdateFailureState::kDownloading, error);
346372
break;
347373
case kApplyUpdate:
348-
requestorCore->mOtaRequestorDriver->HandleError(OTAUpdateStateEnum::kApplying, error);
374+
requestorCore->mOtaRequestorDriver->HandleError(UpdateFailureState::kApplying, error);
349375
break;
350376
default:
351377
break;
@@ -376,6 +402,11 @@ void OTARequestor::ApplyUpdate()
376402
ConnectToProvider(kApplyUpdate);
377403
}
378404

405+
void OTARequestor::NotifyUpdateApplied()
406+
{
407+
ConnectToProvider(kNotifyUpdateApplied);
408+
}
409+
379410
void OTARequestor::OnDownloadStateChanged(OTADownloader::State state)
380411
{
381412
VerifyOrReturn(mOtaRequestorDriver != nullptr);
@@ -386,7 +417,7 @@ void OTARequestor::OnDownloadStateChanged(OTADownloader::State state)
386417
mOtaRequestorDriver->UpdateDownloaded();
387418
break;
388419
case OTADownloader::State::kIdle:
389-
mOtaRequestorDriver->HandleError(OTAUpdateStateEnum::kDownloading, CHIP_ERROR_CONNECTION_ABORTED);
420+
mOtaRequestorDriver->HandleError(UpdateFailureState::kDownloading, CHIP_ERROR_CONNECTION_ABORTED);
390421
break;
391422
default:
392423
break;
@@ -398,6 +429,23 @@ void OTARequestor::OnUpdateProgressChanged(uint8_t percent)
398429
OtaRequestorServerSetUpdateStateProgress(percent);
399430
}
400431

432+
CHIP_ERROR OTARequestor::GenerateUpdateToken()
433+
{
434+
if (mUpdateToken.empty())
435+
{
436+
VerifyOrReturnError(mServer != nullptr, CHIP_ERROR_INCORRECT_STATE);
437+
438+
FabricInfo * fabricInfo = mServer->GetFabricTable().FindFabricWithIndex(mProviderFabricIndex);
439+
VerifyOrReturnError(fabricInfo != nullptr, CHIP_ERROR_INCORRECT_STATE);
440+
441+
static_assert(sizeof(NodeId) == sizeof(uint64_t), "Unexpected NodeId size");
442+
Encoding::BigEndian::Put64(mUpdateTokenBuffer, fabricInfo->GetPeerId().GetNodeId());
443+
mUpdateToken = ByteSpan(mUpdateTokenBuffer, sizeof(NodeId));
444+
}
445+
446+
return CHIP_NO_ERROR;
447+
}
448+
401449
CHIP_ERROR OTARequestor::SendQueryImageRequest(OperationalDeviceProxy & deviceProxy)
402450
{
403451
constexpr OTADownloadProtocol kProtocolsSupported[] = { OTADownloadProtocol::kBDXSynchronous };
@@ -488,19 +536,7 @@ CHIP_ERROR OTARequestor::StartDownload(OperationalDeviceProxy & deviceProxy)
488536

489537
CHIP_ERROR OTARequestor::SendApplyUpdateRequest(OperationalDeviceProxy & deviceProxy)
490538
{
491-
if (mUpdateToken.empty())
492-
{
493-
// OTA Requestor shall use its node ID as the update token in case the original update
494-
// token, received in QueryImageResponse, got lost.
495-
VerifyOrReturnError(mServer != nullptr, CHIP_ERROR_INCORRECT_STATE);
496-
497-
FabricInfo * fabricInfo = mServer->GetFabricTable().FindFabricWithIndex(mProviderFabricIndex);
498-
VerifyOrReturnError(fabricInfo != nullptr, CHIP_ERROR_INCORRECT_STATE);
499-
500-
static_assert(sizeof(NodeId) == sizeof(uint64_t), "Unexpected NodeId size");
501-
Encoding::BigEndian::Put64(mUpdateTokenBuffer, fabricInfo->GetPeerId().GetNodeId());
502-
mUpdateToken = ByteSpan(mUpdateTokenBuffer, sizeof(NodeId));
503-
}
539+
ReturnErrorOnFailure(GenerateUpdateToken());
504540

505541
ApplyUpdateRequest::Type args;
506542
args.updateToken = mUpdateToken;
@@ -512,4 +548,18 @@ CHIP_ERROR OTARequestor::SendApplyUpdateRequest(OperationalDeviceProxy & deviceP
512548
return cluster.InvokeCommand(args, this, OnApplyUpdateResponse, OnApplyUpdateFailure);
513549
}
514550

551+
CHIP_ERROR OTARequestor::SendNotifyUpdateAppliedRequest(OperationalDeviceProxy & deviceProxy)
552+
{
553+
ReturnErrorOnFailure(GenerateUpdateToken());
554+
555+
NotifyUpdateApplied::Type args;
556+
args.updateToken = mUpdateToken;
557+
args.softwareVersion = mUpdateVersion;
558+
559+
Controller::OtaSoftwareUpdateProviderCluster cluster;
560+
cluster.Associate(&deviceProxy, mProviderEndpointId);
561+
562+
return cluster.InvokeCommand(args, this, OnNotifyUpdateAppliedResponse, OnNotifyUpdateAppliedFailure);
563+
}
564+
515565
} // namespace chip

src/app/clusters/ota-requestor/OTARequestor.h

+20
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class OTARequestor : public OTARequestorInterface, public BDXDownloader::StateDe
4343
kQueryImage = 0,
4444
kStartBDX,
4545
kApplyUpdate,
46+
kNotifyUpdateApplied,
4647
};
4748

4849
OTARequestor() : mOnConnectedCallback(OnConnected, this), mOnConnectionFailureCallback(OnConnectionFailure, this) {}
@@ -62,6 +63,9 @@ class OTARequestor : public OTARequestorInterface, public BDXDownloader::StateDe
6263
// Send ApplyImage
6364
void ApplyUpdate() override;
6465

66+
// Send NotifyUpdateApplied
67+
void NotifyUpdateApplied() override;
68+
6569
//////////// BDXDownloader::StateDelegate Implementation ///////////////
6670
void OnDownloadStateChanged(OTADownloader::State state) override;
6771
void OnUpdateProgressChanged(uint8_t percent) override;
@@ -188,6 +192,11 @@ class OTARequestor : public OTARequestorInterface, public BDXDownloader::StateDe
188192
chip::BDXDownloader * mDownloader;
189193
};
190194

195+
/**
196+
* Generate an update token using the operational node ID in case of token lost, received in QueryImageResponse
197+
*/
198+
CHIP_ERROR GenerateUpdateToken();
199+
191200
/**
192201
* Send QueryImage request using values matching Basic cluster
193202
*/
@@ -208,6 +217,11 @@ class OTARequestor : public OTARequestorInterface, public BDXDownloader::StateDe
208217
*/
209218
CHIP_ERROR SendApplyUpdateRequest(OperationalDeviceProxy & deviceProxy);
210219

220+
/**
221+
* Send NotifyUpdateApplied request
222+
*/
223+
CHIP_ERROR SendNotifyUpdateAppliedRequest(OperationalDeviceProxy & deviceProxy);
224+
211225
/**
212226
* Session connection callbacks
213227
*/
@@ -228,6 +242,12 @@ class OTARequestor : public OTARequestorInterface, public BDXDownloader::StateDe
228242
static void OnApplyUpdateResponse(void * context, const ApplyUpdateResponseDecodableType & response);
229243
static void OnApplyUpdateFailure(void * context, EmberAfStatus);
230244

245+
/**
246+
* NotifyUpdateApplied callbacks
247+
*/
248+
static void OnNotifyUpdateAppliedResponse(void * context, const app::DataModel::NullObjectType & response);
249+
static void OnNotifyUpdateAppliedFailure(void * context, EmberAfStatus);
250+
231251
OTARequestorDriver * mOtaRequestorDriver = nullptr;
232252
NodeId mProviderNodeId = kUndefinedNodeId;
233253
FabricIndex mProviderFabricIndex = kUndefinedFabricIndex;

src/include/platform/OTARequestorDriver.h

+10-1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,15 @@ struct UpdateDescription
4040
ByteSpan metadataForRequestor;
4141
};
4242

43+
enum class UpdateFailureState
44+
{
45+
kQuerying,
46+
kDownloading,
47+
kApplying,
48+
kNotifying,
49+
kAwaitingNextAction,
50+
};
51+
4352
enum class UpdateNotFoundReason
4453
{
4554
Busy,
@@ -61,7 +70,7 @@ class OTARequestorDriver
6170
virtual uint16_t GetMaxDownloadBlockSize() { return 1024; }
6271

6372
/// Called when an error occurs at any OTA requestor operation
64-
virtual void HandleError(app::Clusters::OtaSoftwareUpdateRequestor::OTAUpdateStateEnum state, CHIP_ERROR error) = 0;
73+
virtual void HandleError(UpdateFailureState state, CHIP_ERROR error) = 0;
6574

6675
/// Called when the latest query found a software update
6776
virtual void UpdateAvailable(const UpdateDescription & update, System::Clock::Seconds32 delay) = 0;

src/include/platform/OTARequestorInterface.h

+3
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ class OTARequestorInterface
6464
// Send ApplyImage command
6565
virtual void ApplyUpdate() = 0;
6666

67+
// Send NotifyUpdateApplied command
68+
virtual void NotifyUpdateApplied() = 0;
69+
6770
// Manually set OTA Provider parameters
6871
virtual void TestModeSetProviderParameters(NodeId nodeId, FabricIndex fabIndex, EndpointId endpointId) = 0;
6972
};

src/lib/shell/commands/Ota.cpp

+16
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,20 @@ CHIP_ERROR ApplyImageHandler(int argc, char ** argv)
5959
return CHIP_NO_ERROR;
6060
}
6161

62+
CHIP_ERROR NotifyImageHandler(int argc, char ** argv)
63+
{
64+
VerifyOrReturnError(GetRequestorInstance() != nullptr, CHIP_ERROR_INCORRECT_STATE);
65+
VerifyOrReturnError(argc == 3, CHIP_ERROR_INVALID_ARGUMENT);
66+
67+
const FabricIndex fabricIndex = static_cast<FabricIndex>(strtoul(argv[0], nullptr, 10));
68+
const NodeId providerNodeId = static_cast<NodeId>(strtoull(argv[1], nullptr, 10));
69+
const EndpointId providerEndpointId = static_cast<EndpointId>(strtoul(argv[2], nullptr, 10));
70+
71+
GetRequestorInstance()->TestModeSetProviderParameters(providerNodeId, fabricIndex, providerEndpointId);
72+
PlatformMgr().ScheduleWork([](intptr_t) { GetRequestorInstance()->NotifyUpdateApplied(); });
73+
return CHIP_NO_ERROR;
74+
}
75+
6276
CHIP_ERROR OtaHandler(int argc, char ** argv)
6377
{
6478
if (argc == 0)
@@ -85,6 +99,8 @@ void RegisterOtaCommands()
8599
{ &QueryImageHandler, "query", "Query for a new image. Usage: ota query <fabric-index> <provider-node-id> <endpoint-id>" },
86100
{ &ApplyImageHandler, "apply",
87101
"Apply the current update. Usage ota apply <fabric-index> <provider-node-id> <endpoint-id>" },
102+
{ &NotifyImageHandler, "notify",
103+
"Notify the new image has been applied. Usage: ota notify <fabric-index> <provider-node-id> <endpoint-id>" },
88104
};
89105

90106
sSubShell.RegisterCommands(subCommands, ArraySize(subCommands));

src/platform/GenericOTARequestorDriver.cpp

+5-5
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,15 @@ uint16_t GenericOTARequestorDriver::GetMaxDownloadBlockSize()
4444
return 1024;
4545
}
4646

47-
void GenericOTARequestorDriver::HandleError(OTAUpdateStateEnum state, CHIP_ERROR error)
47+
void GenericOTARequestorDriver::HandleError(UpdateFailureState state, CHIP_ERROR error)
4848
{
4949
// TODO: Schedule the next QueryImage
5050
}
5151

5252
void GenericOTARequestorDriver::UpdateAvailable(const UpdateDescription & update, System::Clock::Seconds32 delay)
5353
{
5454
VerifyOrDie(mRequestor != nullptr);
55-
ScheduleDelayedAction(OTAUpdateStateEnum::kDelayedOnQuery, delay,
55+
ScheduleDelayedAction(UpdateFailureState::kDownloading, delay,
5656
[](System::Layer *, void * context) { ToDriver(context)->mRequestor->DownloadUpdate(); });
5757
}
5858

@@ -70,14 +70,14 @@ void GenericOTARequestorDriver::UpdateDownloaded()
7070
void GenericOTARequestorDriver::UpdateConfirmed(System::Clock::Seconds32 delay)
7171
{
7272
VerifyOrDie(mImageProcessor != nullptr);
73-
ScheduleDelayedAction(OTAUpdateStateEnum::kDelayedOnApply, delay,
73+
ScheduleDelayedAction(UpdateFailureState::kApplying, delay,
7474
[](System::Layer *, void * context) { ToDriver(context)->mImageProcessor->Apply(); });
7575
}
7676

7777
void GenericOTARequestorDriver::UpdateSuspended(System::Clock::Seconds32 delay)
7878
{
7979
VerifyOrDie(mRequestor != nullptr);
80-
ScheduleDelayedAction(OTAUpdateStateEnum::kDelayedOnApply, delay,
80+
ScheduleDelayedAction(UpdateFailureState::kAwaitingNextAction, delay,
8181
[](System::Layer *, void * context) { ToDriver(context)->mRequestor->ApplyUpdate(); });
8282
}
8383

@@ -87,7 +87,7 @@ void GenericOTARequestorDriver::UpdateDiscontinued()
8787
mImageProcessor->Abort();
8888
}
8989

90-
void GenericOTARequestorDriver::ScheduleDelayedAction(OTAUpdateStateEnum state, System::Clock::Seconds32 delay,
90+
void GenericOTARequestorDriver::ScheduleDelayedAction(UpdateFailureState state, System::Clock::Seconds32 delay,
9191
System::TimerCompleteCallback action)
9292
{
9393
CHIP_ERROR error = SystemLayer().StartTimer(std::chrono::duration_cast<System::Clock::Timeout>(delay), action, this);

src/platform/GenericOTARequestorDriver.h

+2-3
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class GenericOTARequestorDriver : public OTARequestorDriver
4545
bool CanConsent() override;
4646
uint16_t GetMaxDownloadBlockSize() override;
4747

48-
void HandleError(app::Clusters::OtaSoftwareUpdateRequestor::OTAUpdateStateEnum state, CHIP_ERROR error) override;
48+
void HandleError(UpdateFailureState state, CHIP_ERROR error) override;
4949
void UpdateAvailable(const UpdateDescription & update, System::Clock::Seconds32 delay) override;
5050
void UpdateNotFound(UpdateNotFoundReason reason, System::Clock::Seconds32 delay) override;
5151
void UpdateDownloaded() override;
@@ -54,8 +54,7 @@ class GenericOTARequestorDriver : public OTARequestorDriver
5454
void UpdateDiscontinued() override;
5555

5656
private:
57-
void ScheduleDelayedAction(app::Clusters::OtaSoftwareUpdateRequestor::OTAUpdateStateEnum state, System::Clock::Seconds32 delay,
58-
System::TimerCompleteCallback action);
57+
void ScheduleDelayedAction(UpdateFailureState state, System::Clock::Seconds32 delay, System::TimerCompleteCallback action);
5958

6059
OTARequestorInterface * mRequestor = nullptr;
6160
OTAImageProcessorInterface * mImageProcessor = nullptr;

0 commit comments

Comments
 (0)