Skip to content

Commit

Permalink
Allow fabric sync example to accept KeepActive Command (#34636)
Browse files Browse the repository at this point in the history
  • Loading branch information
tehampson authored Aug 8, 2024
1 parent fd1421c commit 5044317
Show file tree
Hide file tree
Showing 14 changed files with 256 additions and 6 deletions.
6 changes: 6 additions & 0 deletions examples/common/pigweed/protos/fabric_admin_service.proto
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,17 @@ message DeviceCommissioningWindowInfo {
bytes verifier = 6;
}

message KeepActiveParameters {
uint64 node_id = 1;
uint32 stay_active_duration_ms = 2;
}

// Define the response message to convey the status of the operation
message OperationStatus {
bool success = 1;
}

service FabricAdmin {
rpc OpenCommissioningWindow(DeviceCommissioningWindowInfo) returns (OperationStatus){}
rpc KeepActive(KeepActiveParameters) returns (pw.protobuf.Empty){}
}
9 changes: 7 additions & 2 deletions examples/common/pigweed/protos/fabric_bridge_service.proto
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,13 @@ message SynchronizedDevice {
optional bool is_icd = 12;
}

message KeepActiveChanged {
uint64 node_id = 1;
uint32 promised_active_duration_ms = 2;
}

service FabricBridge {
rpc AddSynchronizedDevice(SynchronizedDevice) returns (pw.protobuf.Empty){}
rpc RemoveSynchronizedDevice(SynchronizedDevice) returns (pw.protobuf.Empty){}
rpc RemoveSynchronizedDevice(SynchronizedDevice) returns (pw.protobuf.Empty){}
rpc ActiveChanged(KeepActiveChanged) returns (pw.protobuf.Empty){}
}

5 changes: 5 additions & 0 deletions examples/common/pigweed/rpc_services/FabricAdmin.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ class FabricAdmin : public pw_rpc::nanopb::FabricAdmin::Service<FabricAdmin>
{
return pw::Status::Unimplemented();
}

virtual pw::Status KeepActive(const chip_rpc_KeepActiveParameters & request, pw_protobuf_Empty & response)
{
return pw::Status::Unimplemented();
}
};

} // namespace rpc
Expand Down
5 changes: 5 additions & 0 deletions examples/common/pigweed/rpc_services/FabricBridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ class FabricBridge : public pw_rpc::nanopb::FabricBridge::Service<FabricBridge>
{
return pw::Status::Unimplemented();
}

virtual pw::Status ActiveChanged(const chip_rpc_KeepActiveChanged & request, pw_protobuf_Empty & response)
{
return pw::Status::Unimplemented();
}
};

} // namespace rpc
Expand Down
38 changes: 38 additions & 0 deletions examples/fabric-admin/rpc/RpcClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,23 @@ void OnRemoveDeviceResponseCompleted(const pw_protobuf_Empty & response, pw::Sta
}
}

void RpcCompletedWithEmptyResponse(const pw_protobuf_Empty & response, pw::Status status)
{
std::lock_guard<std::mutex> lock(responseMutex);
responseReceived = true;
responseError = status.ok() ? CHIP_NO_ERROR : CHIP_ERROR_INTERNAL;
responseCv.notify_one();

if (status.ok())
{
ChipLogProgress(NotSpecified, "RPC call succeeded!");
}
else
{
ChipLogProgress(NotSpecified, "RPC call failed with status: %d", status.code());
}
}

} // namespace

CHIP_ERROR InitRpcClient(uint16_t rpcServerPort)
Expand Down Expand Up @@ -142,3 +159,24 @@ CHIP_ERROR RemoveSynchronizedDevice(chip::NodeId nodeId)

return WaitForResponse(call);
}

CHIP_ERROR ActiveChanged(chip::NodeId nodeId, uint32_t promisedActiveDurationMs)
{
ChipLogProgress(NotSpecified, "ActiveChanged");

chip_rpc_KeepActiveChanged parameters;
parameters.node_id = nodeId;
parameters.promised_active_duration_ms = promisedActiveDurationMs;

// The RPC call is kept alive until it completes. When a response is received, it will be logged by the handler
// function and the call will complete.
auto call = fabricBridgeClient.ActiveChanged(parameters, RpcCompletedWithEmptyResponse);

if (!call.active())
{
// The RPC call was not sent. This could occur due to, for example, an invalid channel ID. Handle if necessary.
return CHIP_ERROR_INTERNAL;
}

return WaitForResponse(call);
}
12 changes: 12 additions & 0 deletions examples/fabric-admin/rpc/RpcClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,15 @@ CHIP_ERROR AddSynchronizedDevice(const chip_rpc_SynchronizedDevice & data);
* - CHIP_ERROR_INTERNAL: An internal error occurred while activating the RPC call.
*/
CHIP_ERROR RemoveSynchronizedDevice(chip::NodeId nodeId);

/**
* @brief Received StayActiveResponse on behalf of client that previously called KeepActive
*
* @param nodeId The Node ID of the device we recieved a StayActiveResponse.
* @param promisedActiveDurationMs the computed duration (in milliseconds) that the ICD intends to stay active for.
* @return CHIP_ERROR An error code indicating the success or failure of the operation.
* - CHIP_NO_ERROR: The RPC command was successfully processed.
* - CHIP_ERROR_BUSY: Another operation is currently in progress.
* - CHIP_ERROR_INTERNAL: An internal error occurred while activating the RPC call.
*/
CHIP_ERROR ActiveChanged(chip::NodeId nodeId, uint32_t promisedActiveDurationMs);
12 changes: 12 additions & 0 deletions examples/fabric-admin/rpc/RpcServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,18 @@ class FabricAdmin final : public rpc::FabricAdmin

return pw::OkStatus();
}

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

return pw::OkStatus();
}
};

FabricAdmin fabric_admin_service;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@ class BridgedDevice
BridgedDevice(chip::NodeId nodeId);
virtual ~BridgedDevice() = default;

void LogActiveChangeEvent(uint32_t promisedActiveDurationMs);

bool IsReachable();
bool IsIcd();
void SetReachable(bool reachable);

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

protected:
bool mReachable;
bool mIsIcd = false;
chip::NodeId mNodeId;
chip::EndpointId mEndpointId;
chip::EndpointId mParentEndpointId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,36 @@
#include "BridgedDevice.h"

#include <cstdio>
#include <string>

#include <app/EventLogging.h>
#include <platform/CHIPDeviceLayer.h>

#include <string>
namespace {

struct ActiveChangeEventWorkData
{
chip::EndpointId mEndpointId;
uint32_t mPromisedActiveDuration;
};

static void ActiveChangeEventWork(intptr_t arg)
{
ActiveChangeEventWorkData * data = reinterpret_cast<ActiveChangeEventWorkData *>(arg);

chip::app::Clusters::BridgedDeviceBasicInformation::Events::ActiveChanged::Type event{};
event.promisedActiveDuration = data->mPromisedActiveDuration;
chip::EventNumber eventNumber = 0;

CHIP_ERROR err = chip::app::LogEvent(event, data->mEndpointId, eventNumber);
if (err != CHIP_NO_ERROR)
{
ChipLogProgress(NotSpecified, "LogEvent for ActiveChanged failed %s", err.AsString());
}
chip::Platform::Delete(data);
}

} // namespace

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

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

void BridgedDevice::LogActiveChangeEvent(uint32_t promisedActiveDurationMs)
{
ActiveChangeEventWorkData * workdata = chip::Platform::New<ActiveChangeEventWorkData>();
workdata->mEndpointId = mEndpointId;
workdata->mPromisedActiveDuration = promisedActiveDurationMs;

chip::DeviceLayer::PlatformMgr().ScheduleWork(ActiveChangeEventWork, reinterpret_cast<intptr_t>(workdata));
}

bool BridgedDevice::IsReachable()
{
return mReachable;
}

bool BridgedDevice::IsIcd()
{
return mIsIcd;
}

void BridgedDevice::SetReachable(bool reachable)
{
mReachable = reachable;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,11 @@ DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(AdministratorCommissioningAttrs)
DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
// clang-format on

constexpr CommandId bridgedDeviceBasicInformationCommands[] = {
app::Clusters::BridgedDeviceBasicInformation::Commands::KeepActive::Id,
kInvalidCommandId,
};

constexpr CommandId administratorCommissioningCommands[] = {
app::Clusters::AdministratorCommissioning::Commands::OpenCommissioningWindow::Id,
app::Clusters::AdministratorCommissioning::Commands::OpenBasicCommissioningWindow::Id,
Expand All @@ -139,7 +144,8 @@ constexpr CommandId administratorCommissioningCommands[] = {
// Declare Cluster List for Bridged Node endpoint
DECLARE_DYNAMIC_CLUSTER_LIST_BEGIN(bridgedNodeClusters)
DECLARE_DYNAMIC_CLUSTER(Descriptor::Id, descriptorAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr),
DECLARE_DYNAMIC_CLUSTER(BridgedDeviceBasicInformation::Id, bridgedDeviceBasicAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr),
DECLARE_DYNAMIC_CLUSTER(BridgedDeviceBasicInformation::Id, bridgedDeviceBasicAttrs, ZAP_CLUSTER_MASK(SERVER),
bridgedDeviceBasicInformationCommands, nullptr),
DECLARE_DYNAMIC_CLUSTER(EcosystemInformation::Id, ecosystemInformationBasicAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr),
DECLARE_DYNAMIC_CLUSTER(AdministratorCommissioning::Id, AdministratorCommissioningAttrs, ZAP_CLUSTER_MASK(SERVER),
administratorCommissioningCommands, nullptr) DECLARE_DYNAMIC_CLUSTER_LIST_END;
Expand Down
37 changes: 37 additions & 0 deletions examples/fabric-bridge-app/linux/RpcClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,24 @@ void OnOpenCommissioningWindowCompleted(const chip_rpc_OperationStatus & respons
}
}

// Callback function to be called when the RPC response is received for generic empty response.
void RpcCompletedWithEmptyResponse(const pw_protobuf_Empty & response, pw::Status status)
{
std::lock_guard<std::mutex> lock(responseMutex);
responseReceived = true;
responseError = status.ok() ? CHIP_NO_ERROR : CHIP_ERROR_INTERNAL;
responseCv.notify_one();

if (status.ok())
{
ChipLogProgress(NotSpecified, "RPC call succeeded!");
}
else
{
ChipLogProgress(NotSpecified, "RPC call failed with status: %d", status.code());
}
}

} // namespace

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

return OpenCommissioningWindow(device);
}

CHIP_ERROR KeepActive(chip::NodeId nodeId, uint32_t stayActiveDurationMs)
{
chip_rpc_KeepActiveParameters params;
params.node_id = nodeId;
params.stay_active_duration_ms = stayActiveDurationMs;

// The RPC call is kept alive until it completes. When a response is received, it will be logged by the handler
// function and the call will complete.
auto call = fabricAdminClient.KeepActive(params, RpcCompletedWithEmptyResponse);

if (!call.active())
{
// The RPC call was not sent. This could occur due to, for example, an invalid channel ID. Handle if necessary.
return CHIP_ERROR_INTERNAL;
}

return WaitForResponse(call);
}
18 changes: 18 additions & 0 deletions examples/fabric-bridge-app/linux/RpcServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class FabricBridge final : public chip::rpc::FabricBridge
public:
pw::Status AddSynchronizedDevice(const chip_rpc_SynchronizedDevice & request, pw_protobuf_Empty & response) override;
pw::Status RemoveSynchronizedDevice(const chip_rpc_SynchronizedDevice & request, pw_protobuf_Empty & response) override;
pw::Status ActiveChanged(const chip_rpc_KeepActiveChanged & request, pw_protobuf_Empty & response) override;
};

pw::Status FabricBridge::AddSynchronizedDevice(const chip_rpc_SynchronizedDevice & request, pw_protobuf_Empty & response)
Expand Down Expand Up @@ -138,6 +139,23 @@ pw::Status FabricBridge::RemoveSynchronizedDevice(const chip_rpc_SynchronizedDev
return pw::OkStatus();
}

pw::Status FabricBridge::ActiveChanged(const chip_rpc_KeepActiveChanged & request, pw_protobuf_Empty & response)
{
NodeId nodeId = request.node_id;
ChipLogProgress(NotSpecified, "Received ActiveChanged: " ChipLogFormatX64, ChipLogValueX64(nodeId));

auto * device = BridgeDeviceMgr().GetDeviceByNodeId(nodeId);
if (device == nullptr)
{
ChipLogError(NotSpecified, "Could not find bridged device associated with nodeId=0x" ChipLogFormatX64,
ChipLogValueX64(nodeId));
return pw::Status::NotFound();
}

device->LogActiveChangeEvent(request.promised_active_duration_ms);
return pw::OkStatus();
}

FabricBridge fabric_bridge_service;
#endif // defined(PW_RPC_FABRIC_BRIDGE_SERVICE) && PW_RPC_FABRIC_BRIDGE_SERVICE

Expand Down
2 changes: 2 additions & 0 deletions examples/fabric-bridge-app/linux/include/RpcClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,5 @@ OpenCommissioningWindow(chip::Controller::CommissioningWindowPasscodeParams para
*/
CHIP_ERROR
OpenCommissioningWindow(chip::Controller::CommissioningWindowVerifierParams params);

CHIP_ERROR KeepActive(chip::NodeId nodeId, uint32_t stayActiveDurationMs);
Loading

0 comments on commit 5044317

Please sign in to comment.