Skip to content

Commit 5044317

Browse files
authored
Allow fabric sync example to accept KeepActive Command (project-chip#34636)
1 parent fd1421c commit 5044317

File tree

14 files changed

+256
-6
lines changed

14 files changed

+256
-6
lines changed

examples/common/pigweed/protos/fabric_admin_service.proto

+6
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,17 @@ message DeviceCommissioningWindowInfo {
1414
bytes verifier = 6;
1515
}
1616

17+
message KeepActiveParameters {
18+
uint64 node_id = 1;
19+
uint32 stay_active_duration_ms = 2;
20+
}
21+
1722
// Define the response message to convey the status of the operation
1823
message OperationStatus {
1924
bool success = 1;
2025
}
2126

2227
service FabricAdmin {
2328
rpc OpenCommissioningWindow(DeviceCommissioningWindowInfo) returns (OperationStatus){}
29+
rpc KeepActive(KeepActiveParameters) returns (pw.protobuf.Empty){}
2430
}

examples/common/pigweed/protos/fabric_bridge_service.proto

+7-2
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,13 @@ message SynchronizedDevice {
2121
optional bool is_icd = 12;
2222
}
2323

24+
message KeepActiveChanged {
25+
uint64 node_id = 1;
26+
uint32 promised_active_duration_ms = 2;
27+
}
28+
2429
service FabricBridge {
2530
rpc AddSynchronizedDevice(SynchronizedDevice) returns (pw.protobuf.Empty){}
26-
rpc RemoveSynchronizedDevice(SynchronizedDevice) returns (pw.protobuf.Empty){}
31+
rpc RemoveSynchronizedDevice(SynchronizedDevice) returns (pw.protobuf.Empty){}
32+
rpc ActiveChanged(KeepActiveChanged) returns (pw.protobuf.Empty){}
2733
}
28-

examples/common/pigweed/rpc_services/FabricAdmin.h

+5
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ class FabricAdmin : public pw_rpc::nanopb::FabricAdmin::Service<FabricAdmin>
3939
{
4040
return pw::Status::Unimplemented();
4141
}
42+
43+
virtual pw::Status KeepActive(const chip_rpc_KeepActiveParameters & request, pw_protobuf_Empty & response)
44+
{
45+
return pw::Status::Unimplemented();
46+
}
4247
};
4348

4449
} // namespace rpc

examples/common/pigweed/rpc_services/FabricBridge.h

+5
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ class FabricBridge : public pw_rpc::nanopb::FabricBridge::Service<FabricBridge>
4343
{
4444
return pw::Status::Unimplemented();
4545
}
46+
47+
virtual pw::Status ActiveChanged(const chip_rpc_KeepActiveChanged & request, pw_protobuf_Empty & response)
48+
{
49+
return pw::Status::Unimplemented();
50+
}
4651
};
4752

4853
} // namespace rpc

examples/fabric-admin/rpc/RpcClient.cpp

+38
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,23 @@ void OnRemoveDeviceResponseCompleted(const pw_protobuf_Empty & response, pw::Sta
9898
}
9999
}
100100

101+
void RpcCompletedWithEmptyResponse(const pw_protobuf_Empty & response, pw::Status status)
102+
{
103+
std::lock_guard<std::mutex> lock(responseMutex);
104+
responseReceived = true;
105+
responseError = status.ok() ? CHIP_NO_ERROR : CHIP_ERROR_INTERNAL;
106+
responseCv.notify_one();
107+
108+
if (status.ok())
109+
{
110+
ChipLogProgress(NotSpecified, "RPC call succeeded!");
111+
}
112+
else
113+
{
114+
ChipLogProgress(NotSpecified, "RPC call failed with status: %d", status.code());
115+
}
116+
}
117+
101118
} // namespace
102119

103120
CHIP_ERROR InitRpcClient(uint16_t rpcServerPort)
@@ -142,3 +159,24 @@ CHIP_ERROR RemoveSynchronizedDevice(chip::NodeId nodeId)
142159

143160
return WaitForResponse(call);
144161
}
162+
163+
CHIP_ERROR ActiveChanged(chip::NodeId nodeId, uint32_t promisedActiveDurationMs)
164+
{
165+
ChipLogProgress(NotSpecified, "ActiveChanged");
166+
167+
chip_rpc_KeepActiveChanged parameters;
168+
parameters.node_id = nodeId;
169+
parameters.promised_active_duration_ms = promisedActiveDurationMs;
170+
171+
// The RPC call is kept alive until it completes. When a response is received, it will be logged by the handler
172+
// function and the call will complete.
173+
auto call = fabricBridgeClient.ActiveChanged(parameters, RpcCompletedWithEmptyResponse);
174+
175+
if (!call.active())
176+
{
177+
// The RPC call was not sent. This could occur due to, for example, an invalid channel ID. Handle if necessary.
178+
return CHIP_ERROR_INTERNAL;
179+
}
180+
181+
return WaitForResponse(call);
182+
}

examples/fabric-admin/rpc/RpcClient.h

+12
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,15 @@ CHIP_ERROR AddSynchronizedDevice(const chip_rpc_SynchronizedDevice & data);
6262
* - CHIP_ERROR_INTERNAL: An internal error occurred while activating the RPC call.
6363
*/
6464
CHIP_ERROR RemoveSynchronizedDevice(chip::NodeId nodeId);
65+
66+
/**
67+
* @brief Received StayActiveResponse on behalf of client that previously called KeepActive
68+
*
69+
* @param nodeId The Node ID of the device we recieved a StayActiveResponse.
70+
* @param promisedActiveDurationMs the computed duration (in milliseconds) that the ICD intends to stay active for.
71+
* @return CHIP_ERROR An error code indicating the success or failure of the operation.
72+
* - CHIP_NO_ERROR: The RPC command was successfully processed.
73+
* - CHIP_ERROR_BUSY: Another operation is currently in progress.
74+
* - CHIP_ERROR_INTERNAL: An internal error occurred while activating the RPC call.
75+
*/
76+
CHIP_ERROR ActiveChanged(chip::NodeId nodeId, uint32_t promisedActiveDurationMs);

examples/fabric-admin/rpc/RpcServer.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,18 @@ class FabricAdmin final : public rpc::FabricAdmin
6565

6666
return pw::OkStatus();
6767
}
68+
69+
pw::Status KeepActive(const chip_rpc_KeepActiveParameters & request, pw_protobuf_Empty & response) override
70+
{
71+
ChipLogProgress(NotSpecified, "Received KeepActive request: 0x%lx, %u", request.node_id, request.stay_active_duration_ms);
72+
// TODO(#33221): When we get this command hopefully we are already registered with an ICD device to be
73+
// notified when it wakes up. We will need to add in hooks there to make sure we send the StayActiveRequest
74+
// Important thing to note:
75+
// * If we get this call multiple times before we get a wakeup from ICD, we only send out one StayActiveRequest command
76+
// * After 60 mins from last exipry we no longer will send out a StayActiveRequest.
77+
78+
return pw::OkStatus();
79+
}
6880
};
6981

7082
FabricAdmin fabric_admin_service;

examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h

+4
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,10 @@ class BridgedDevice
4343
BridgedDevice(chip::NodeId nodeId);
4444
virtual ~BridgedDevice() = default;
4545

46+
void LogActiveChangeEvent(uint32_t promisedActiveDurationMs);
47+
4648
bool IsReachable();
49+
bool IsIcd();
4750
void SetReachable(bool reachable);
4851

4952
inline void SetEndpointId(chip::EndpointId id) { mEndpointId = id; };
@@ -61,6 +64,7 @@ class BridgedDevice
6164

6265
protected:
6366
bool mReachable;
67+
bool mIsIcd = false;
6468
chip::NodeId mNodeId;
6569
chip::EndpointId mEndpointId;
6670
chip::EndpointId mParentEndpointId;

examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDevice.cpp

+42-1
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,36 @@
1919
#include "BridgedDevice.h"
2020

2121
#include <cstdio>
22+
#include <string>
23+
24+
#include <app/EventLogging.h>
2225
#include <platform/CHIPDeviceLayer.h>
2326

24-
#include <string>
27+
namespace {
28+
29+
struct ActiveChangeEventWorkData
30+
{
31+
chip::EndpointId mEndpointId;
32+
uint32_t mPromisedActiveDuration;
33+
};
34+
35+
static void ActiveChangeEventWork(intptr_t arg)
36+
{
37+
ActiveChangeEventWorkData * data = reinterpret_cast<ActiveChangeEventWorkData *>(arg);
38+
39+
chip::app::Clusters::BridgedDeviceBasicInformation::Events::ActiveChanged::Type event{};
40+
event.promisedActiveDuration = data->mPromisedActiveDuration;
41+
chip::EventNumber eventNumber = 0;
42+
43+
CHIP_ERROR err = chip::app::LogEvent(event, data->mEndpointId, eventNumber);
44+
if (err != CHIP_NO_ERROR)
45+
{
46+
ChipLogProgress(NotSpecified, "LogEvent for ActiveChanged failed %s", err.AsString());
47+
}
48+
chip::Platform::Delete(data);
49+
}
50+
51+
} // namespace
2552

2653
using namespace chip::app::Clusters::Actions;
2754

@@ -32,11 +59,25 @@ BridgedDevice::BridgedDevice(chip::NodeId nodeId)
3259
mEndpointId = chip::kInvalidEndpointId;
3360
}
3461

62+
void BridgedDevice::LogActiveChangeEvent(uint32_t promisedActiveDurationMs)
63+
{
64+
ActiveChangeEventWorkData * workdata = chip::Platform::New<ActiveChangeEventWorkData>();
65+
workdata->mEndpointId = mEndpointId;
66+
workdata->mPromisedActiveDuration = promisedActiveDurationMs;
67+
68+
chip::DeviceLayer::PlatformMgr().ScheduleWork(ActiveChangeEventWork, reinterpret_cast<intptr_t>(workdata));
69+
}
70+
3571
bool BridgedDevice::IsReachable()
3672
{
3773
return mReachable;
3874
}
3975

76+
bool BridgedDevice::IsIcd()
77+
{
78+
return mIsIcd;
79+
}
80+
4081
void BridgedDevice::SetReachable(bool reachable)
4182
{
4283
mReachable = reachable;

examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp

+7-1
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,11 @@ DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(AdministratorCommissioningAttrs)
129129
DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
130130
// clang-format on
131131

132+
constexpr CommandId bridgedDeviceBasicInformationCommands[] = {
133+
app::Clusters::BridgedDeviceBasicInformation::Commands::KeepActive::Id,
134+
kInvalidCommandId,
135+
};
136+
132137
constexpr CommandId administratorCommissioningCommands[] = {
133138
app::Clusters::AdministratorCommissioning::Commands::OpenCommissioningWindow::Id,
134139
app::Clusters::AdministratorCommissioning::Commands::OpenBasicCommissioningWindow::Id,
@@ -139,7 +144,8 @@ constexpr CommandId administratorCommissioningCommands[] = {
139144
// Declare Cluster List for Bridged Node endpoint
140145
DECLARE_DYNAMIC_CLUSTER_LIST_BEGIN(bridgedNodeClusters)
141146
DECLARE_DYNAMIC_CLUSTER(Descriptor::Id, descriptorAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr),
142-
DECLARE_DYNAMIC_CLUSTER(BridgedDeviceBasicInformation::Id, bridgedDeviceBasicAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr),
147+
DECLARE_DYNAMIC_CLUSTER(BridgedDeviceBasicInformation::Id, bridgedDeviceBasicAttrs, ZAP_CLUSTER_MASK(SERVER),
148+
bridgedDeviceBasicInformationCommands, nullptr),
143149
DECLARE_DYNAMIC_CLUSTER(EcosystemInformation::Id, ecosystemInformationBasicAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr),
144150
DECLARE_DYNAMIC_CLUSTER(AdministratorCommissioning::Id, AdministratorCommissioningAttrs, ZAP_CLUSTER_MASK(SERVER),
145151
administratorCommissioningCommands, nullptr) DECLARE_DYNAMIC_CLUSTER_LIST_END;

examples/fabric-bridge-app/linux/RpcClient.cpp

+37
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,24 @@ void OnOpenCommissioningWindowCompleted(const chip_rpc_OperationStatus & respons
8787
}
8888
}
8989

90+
// Callback function to be called when the RPC response is received for generic empty response.
91+
void RpcCompletedWithEmptyResponse(const pw_protobuf_Empty & response, pw::Status status)
92+
{
93+
std::lock_guard<std::mutex> lock(responseMutex);
94+
responseReceived = true;
95+
responseError = status.ok() ? CHIP_NO_ERROR : CHIP_ERROR_INTERNAL;
96+
responseCv.notify_one();
97+
98+
if (status.ok())
99+
{
100+
ChipLogProgress(NotSpecified, "RPC call succeeded!");
101+
}
102+
else
103+
{
104+
ChipLogProgress(NotSpecified, "RPC call failed with status: %d", status.code());
105+
}
106+
}
107+
90108
} // namespace
91109

92110
CHIP_ERROR InitRpcClient(uint16_t rpcServerPort)
@@ -143,3 +161,22 @@ OpenCommissioningWindow(chip::Controller::CommissioningWindowVerifierParams para
143161

144162
return OpenCommissioningWindow(device);
145163
}
164+
165+
CHIP_ERROR KeepActive(chip::NodeId nodeId, uint32_t stayActiveDurationMs)
166+
{
167+
chip_rpc_KeepActiveParameters params;
168+
params.node_id = nodeId;
169+
params.stay_active_duration_ms = stayActiveDurationMs;
170+
171+
// The RPC call is kept alive until it completes. When a response is received, it will be logged by the handler
172+
// function and the call will complete.
173+
auto call = fabricAdminClient.KeepActive(params, RpcCompletedWithEmptyResponse);
174+
175+
if (!call.active())
176+
{
177+
// The RPC call was not sent. This could occur due to, for example, an invalid channel ID. Handle if necessary.
178+
return CHIP_ERROR_INTERNAL;
179+
}
180+
181+
return WaitForResponse(call);
182+
}

examples/fabric-bridge-app/linux/RpcServer.cpp

+18
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class FabricBridge final : public chip::rpc::FabricBridge
4545
public:
4646
pw::Status AddSynchronizedDevice(const chip_rpc_SynchronizedDevice & request, pw_protobuf_Empty & response) override;
4747
pw::Status RemoveSynchronizedDevice(const chip_rpc_SynchronizedDevice & request, pw_protobuf_Empty & response) override;
48+
pw::Status ActiveChanged(const chip_rpc_KeepActiveChanged & request, pw_protobuf_Empty & response) override;
4849
};
4950

5051
pw::Status FabricBridge::AddSynchronizedDevice(const chip_rpc_SynchronizedDevice & request, pw_protobuf_Empty & response)
@@ -138,6 +139,23 @@ pw::Status FabricBridge::RemoveSynchronizedDevice(const chip_rpc_SynchronizedDev
138139
return pw::OkStatus();
139140
}
140141

142+
pw::Status FabricBridge::ActiveChanged(const chip_rpc_KeepActiveChanged & request, pw_protobuf_Empty & response)
143+
{
144+
NodeId nodeId = request.node_id;
145+
ChipLogProgress(NotSpecified, "Received ActiveChanged: " ChipLogFormatX64, ChipLogValueX64(nodeId));
146+
147+
auto * device = BridgeDeviceMgr().GetDeviceByNodeId(nodeId);
148+
if (device == nullptr)
149+
{
150+
ChipLogError(NotSpecified, "Could not find bridged device associated with nodeId=0x" ChipLogFormatX64,
151+
ChipLogValueX64(nodeId));
152+
return pw::Status::NotFound();
153+
}
154+
155+
device->LogActiveChangeEvent(request.promised_active_duration_ms);
156+
return pw::OkStatus();
157+
}
158+
141159
FabricBridge fabric_bridge_service;
142160
#endif // defined(PW_RPC_FABRIC_BRIDGE_SERVICE) && PW_RPC_FABRIC_BRIDGE_SERVICE
143161

examples/fabric-bridge-app/linux/include/RpcClient.h

+2
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,5 @@ OpenCommissioningWindow(chip::Controller::CommissioningWindowPasscodeParams para
5656
*/
5757
CHIP_ERROR
5858
OpenCommissioningWindow(chip::Controller::CommissioningWindowVerifierParams params);
59+
60+
CHIP_ERROR KeepActive(chip::NodeId nodeId, uint32_t stayActiveDurationMs);

0 commit comments

Comments
 (0)