Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow fabric sync example to accept KeepActive Command #34636

Merged
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 = 2;
tehampson marked this conversation as resolved.
Show resolved Hide resolved
}

// 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 @@ -20,8 +20,13 @@ message SynchronizedDevice {
optional string software_version_string = 11;
}

message KeepActiveChanged {
uint64 node_id = 1;
uint32 promised_active_duration = 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 @@ -105,6 +105,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 @@ -180,3 +197,24 @@ CHIP_ERROR RemoveSynchronizedDevice(chip::NodeId nodeId)

return WaitForResponse(call);
}

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

chip_rpc_KeepActiveChanged parameters;
parameters.node_id = nodeId;
parameters.promised_active_duration = promisedActiveDuration;

// 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 @@ -61,3 +61,15 @@ CHIP_ERROR AddSynchronizedDevice(chip::NodeId nodeId);
* - 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 promisedActiveDuration the computed duration (in milliseconds) that the ICD intends to stay active for.
tehampson marked this conversation as resolved.
Show resolved Hide resolved
* @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 promisedActiveDuration);
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);
// TODO(#33221): When we get this command hopefully we are already registers with an ICD device to be
tehampson marked this conversation as resolved.
Show resolved Hide resolved
// 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 promisedActiveDuration);

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 promisedActiveDuration)
{
ActiveChangeEventWorkData * workdata = chip::Platform::New<ActiveChangeEventWorkData>();
workdata->mEndpointId = mEndpointId;
workdata->mPromisedActiveDuration = promisedActiveDuration;

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 stayActiveDuration)
{
chip_rpc_KeepActiveParameters params;
params.node_id = nodeId;
params.stay_active_duration = stayActiveDuration;

// 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);
tehampson marked this conversation as resolved.
Show resolved Hide resolved
}
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);
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 stayActiveDuration);
Loading
Loading