From fb064c32081b689b84b504b99c360f8de252ce43 Mon Sep 17 00:00:00 2001 From: Yufeng Wang Date: Fri, 24 May 2024 14:36:25 -0700 Subject: [PATCH 1/5] Add the RPC support between Fabric_Admin and Fabric_Bridge --- examples/common/pigweed/BUILD.gn | 14 ++ .../pigweed/protos/fabric_admin_service.proto | 20 +++ .../protos/fabric_bridge_service.proto | 15 ++ .../common/pigweed/rpc_console/py/BUILD.gn | 2 + .../rpc_console/py/chip_rpc/console.py | 4 + .../common/pigweed/rpc_services/FabricAdmin.h | 44 +++++ .../pigweed/rpc_services/FabricBridge.h | 44 +++++ examples/fabric-admin/BUILD.gn | 48 ++++- .../commands/fabric-sync/Commands.h | 33 ++++ .../fabric-sync/FabricSyncCommand.cpp | 45 +++++ .../commands/fabric-sync/FabricSyncCommand.h | 40 +++++ examples/fabric-admin/main.cpp | 32 ++++ examples/fabric-admin/rpc/RpcClient.cpp | 168 +++++++++++++++++ examples/fabric-admin/rpc/RpcClient.h | 27 +++ examples/fabric-admin/rpc/RpcServer.cpp | 70 ++++++++ examples/fabric-admin/rpc/RpcServer.h | 23 +++ examples/fabric-admin/with_pw_rpc.gni | 42 +++++ examples/fabric-bridge-app/linux/BUILD.gn | 36 +++- .../fabric-bridge-app/linux/RpcClient.cpp | 169 ++++++++++++++++++ .../fabric-bridge-app/linux/RpcServer.cpp | 68 +++++++ .../linux/include/RpcClient.h | 27 +++ .../linux/include/RpcServer.h | 23 +++ examples/fabric-bridge-app/linux/main.cpp | 100 +++++++++-- .../fabric-bridge-app/linux/with_pw_rpc.gni | 41 +++++ 24 files changed, 1123 insertions(+), 12 deletions(-) create mode 100644 examples/common/pigweed/protos/fabric_admin_service.proto create mode 100644 examples/common/pigweed/protos/fabric_bridge_service.proto create mode 100644 examples/common/pigweed/rpc_services/FabricAdmin.h create mode 100644 examples/common/pigweed/rpc_services/FabricBridge.h create mode 100644 examples/fabric-admin/commands/fabric-sync/Commands.h create mode 100644 examples/fabric-admin/commands/fabric-sync/FabricSyncCommand.cpp create mode 100644 examples/fabric-admin/commands/fabric-sync/FabricSyncCommand.h create mode 100644 examples/fabric-admin/rpc/RpcClient.cpp create mode 100644 examples/fabric-admin/rpc/RpcClient.h create mode 100644 examples/fabric-admin/rpc/RpcServer.cpp create mode 100644 examples/fabric-admin/rpc/RpcServer.h create mode 100644 examples/fabric-admin/with_pw_rpc.gni create mode 100644 examples/fabric-bridge-app/linux/RpcClient.cpp create mode 100644 examples/fabric-bridge-app/linux/RpcServer.cpp create mode 100644 examples/fabric-bridge-app/linux/include/RpcClient.h create mode 100644 examples/fabric-bridge-app/linux/include/RpcServer.h create mode 100644 examples/fabric-bridge-app/linux/with_pw_rpc.gni diff --git a/examples/common/pigweed/BUILD.gn b/examples/common/pigweed/BUILD.gn index c0178e419a1d5d..e523bea380c03f 100644 --- a/examples/common/pigweed/BUILD.gn +++ b/examples/common/pigweed/BUILD.gn @@ -80,6 +80,20 @@ pw_proto_library("button_service") { prefix = "button_service" } +pw_proto_library("fabric_admin_service") { + sources = [ "protos/fabric_admin_service.proto" ] + deps = [ "$dir_pw_protobuf:common_protos" ] + strip_prefix = "protos" + prefix = "fabric_admin_service" +} + +pw_proto_library("fabric_bridge_service") { + sources = [ "protos/fabric_bridge_service.proto" ] + deps = [ "$dir_pw_protobuf:common_protos" ] + strip_prefix = "protos" + prefix = "fabric_bridge_service" +} + pw_proto_library("lighting_service") { sources = [ "protos/lighting_service.proto" ] deps = [ "$dir_pw_protobuf:common_protos" ] diff --git a/examples/common/pigweed/protos/fabric_admin_service.proto b/examples/common/pigweed/protos/fabric_admin_service.proto new file mode 100644 index 00000000000000..e52fd2951ac0d7 --- /dev/null +++ b/examples/common/pigweed/protos/fabric_admin_service.proto @@ -0,0 +1,20 @@ +syntax = "proto3"; + +import 'pw_protobuf_protos/common.proto'; + +package chip.rpc; + +// Define the message for a synchronized end device with necessary fields +message DeviceInfo { + uint64 node_id = 1; +} + +// Define the response message to convey the status of the operation +message OperationStatus { + bool success = 1; +} + +service FabricAdmin { + rpc OpenCommissioningWindow(DeviceInfo) returns (OperationStatus){} +} + diff --git a/examples/common/pigweed/protos/fabric_bridge_service.proto b/examples/common/pigweed/protos/fabric_bridge_service.proto new file mode 100644 index 00000000000000..5bd4f8efd779e7 --- /dev/null +++ b/examples/common/pigweed/protos/fabric_bridge_service.proto @@ -0,0 +1,15 @@ +syntax = "proto3"; + +import 'pw_protobuf_protos/common.proto'; + +package chip.rpc; + +// Define the message for a synchronized end device with necessary fields +message SynchronizedDevice { + uint64 node_id = 1; +} + +service FabricBridge { + rpc AddSynchronizedDevice(SynchronizedDevice) returns (pw.protobuf.Empty){} +} + diff --git a/examples/common/pigweed/rpc_console/py/BUILD.gn b/examples/common/pigweed/rpc_console/py/BUILD.gn index a03dc980872739..db9f22fe45fff9 100644 --- a/examples/common/pigweed/rpc_console/py/BUILD.gn +++ b/examples/common/pigweed/rpc_console/py/BUILD.gn @@ -46,6 +46,8 @@ pw_python_package("chip_rpc") { "${chip_root}/examples/common/pigweed:descriptor_service.python", "${chip_root}/examples/common/pigweed:device_service.python", "${chip_root}/examples/common/pigweed:echo_service.python", + "${chip_root}/examples/common/pigweed:fabric_admin_service.python", + "${chip_root}/examples/common/pigweed:fabric_bridge_service.python", "${chip_root}/examples/common/pigweed:lighting_service.python", "${chip_root}/examples/common/pigweed:locking_service.python", "${chip_root}/examples/common/pigweed:ot_cli_service.python", diff --git a/examples/common/pigweed/rpc_console/py/chip_rpc/console.py b/examples/common/pigweed/rpc_console/py/chip_rpc/console.py index 1591722bfdbeab..7aea568c288b16 100644 --- a/examples/common/pigweed/rpc_console/py/chip_rpc/console.py +++ b/examples/common/pigweed/rpc_console/py/chip_rpc/console.py @@ -53,6 +53,8 @@ from descriptor_service import descriptor_service_pb2 from device_service import device_service_pb2 from echo_service import echo_pb2 +from fabric_admin_service import fabric_admin_service_pb2 +from fabric_bridge_service import fabric_bridge_service_pb2 from lighting_service import lighting_service_pb2 from locking_service import locking_service_pb2 from ot_cli_service import ot_cli_service_pb2 @@ -136,6 +138,8 @@ def show_console(device: str, baudrate: int, descriptor_service_pb2, device_service_pb2, echo_pb2, + fabric_admin_service_pb2, + fabric_bridge_service_pb2, lighting_service_pb2, locking_service_pb2, ot_cli_service_pb2, diff --git a/examples/common/pigweed/rpc_services/FabricAdmin.h b/examples/common/pigweed/rpc_services/FabricAdmin.h new file mode 100644 index 00000000000000..5254b9e9054a0c --- /dev/null +++ b/examples/common/pigweed/rpc_services/FabricAdmin.h @@ -0,0 +1,44 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "app/util/attribute-storage.h" +#include "fabric_admin_service/fabric_admin_service.rpc.pb.h" +#include "pigweed/rpc_services/internal/StatusUtils.h" +#include +#include +#include +#include + +namespace chip { +namespace rpc { + +class FabricAdmin : public pw_rpc::nanopb::FabricAdmin::Service +{ +public: + virtual ~FabricAdmin() = default; + + virtual pw::Status OpenCommissioningWindow(const chip_rpc_DeviceInfo & request, chip_rpc_OperationStatus & response) + { + return pw::Status::Unimplemented(); + } +}; + +} // namespace rpc +} // namespace chip diff --git a/examples/common/pigweed/rpc_services/FabricBridge.h b/examples/common/pigweed/rpc_services/FabricBridge.h new file mode 100644 index 00000000000000..bce32ebd3d99b2 --- /dev/null +++ b/examples/common/pigweed/rpc_services/FabricBridge.h @@ -0,0 +1,44 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "app/util/attribute-storage.h" +#include "fabric_bridge_service/fabric_bridge_service.rpc.pb.h" +#include "pigweed/rpc_services/internal/StatusUtils.h" +#include +#include +#include +#include + +namespace chip { +namespace rpc { + +class FabricBridge : public pw_rpc::nanopb::FabricBridge::Service +{ +public: + virtual ~FabricBridge() = default; + + virtual pw::Status AddSynchronizedDevice(const chip_rpc_SynchronizedDevice & request, pw_protobuf_Empty & response) + { + return pw::Status::Unimplemented(); + } +}; + +} // namespace rpc +} // namespace chip diff --git a/examples/fabric-admin/BUILD.gn b/examples/fabric-admin/BUILD.gn index ddaa33483257b1..c8a95a3c3925be 100644 --- a/examples/fabric-admin/BUILD.gn +++ b/examples/fabric-admin/BUILD.gn @@ -22,6 +22,13 @@ import("${chip_root}/src/lib/core/core.gni") assert(chip_build_tools) +import("${chip_root}/examples/common/pigweed/pigweed_rpcs.gni") + +if (chip_enable_pw_rpc) { + import("//build_overrides/pigweed.gni") + import("$dir_pw_build/target_types.gni") +} + config("config") { include_dirs = [ ".", @@ -38,7 +45,9 @@ config("config") { defines += [ "CONFIG_USE_LOCAL_STORAGE" ] } - cflags = [ "-Wconversion" ] + if (chip_enable_pw_rpc) { + defines += [ "PW_RPC_ENABLED" ] + } } static_library("fabric-admin-utils") { @@ -59,6 +68,7 @@ static_library("fabric-admin-utils") { "commands/common/HexConversion.h", "commands/common/RemoteDataModelLogger.cpp", "commands/common/RemoteDataModelLogger.h", + "commands/fabric-sync/FabricSyncCommand.cpp", "commands/pairing/OpenCommissioningWindowCommand.cpp", "commands/pairing/OpenCommissioningWindowCommand.h", "commands/pairing/PairingCommand.cpp", @@ -95,6 +105,42 @@ static_library("fabric-admin-utils") { public_configs = [ ":config" ] + if (chip_enable_pw_rpc) { + defines = [ + "PW_RPC_FABRIC_ADMIN_SERVICE=1", + "PW_RPC_FABRIC_BRIDGE_SERVICE=1", + ] + + sources += [ + "${chip_root}/examples/platform/linux/system_rpc_server.cc", + "rpc/RpcClient.cpp", + "rpc/RpcClient.h", + "rpc/RpcServer.cpp", + "rpc/RpcServer.h", + ] + + deps += [ + "$dir_pw_hdlc:default_addresses", + "$dir_pw_hdlc:rpc_channel_output", + "$dir_pw_log", + "$dir_pw_rpc:server", + "$dir_pw_rpc/system_server:facade", + "$dir_pw_rpc/system_server:socket", + "$dir_pw_stream:socket_stream", + "$dir_pw_sync:mutex", + "${chip_root}/config/linux/lib/pw_rpc:pw_rpc", + "${chip_root}/examples/common/pigweed:fabric_admin_service.nanopb_rpc", + "${chip_root}/examples/common/pigweed:fabric_bridge_service.nanopb_rpc", + "${chip_root}/examples/common/pigweed:rpc_services", + ] + + deps += pw_build_LINK_DEPS + } else { + # The system_rpc_server.cc file is in pigweed and doesn't compile with + # -Wconversion, remove check for RPC build only. + cflags = [ "-Wconversion" ] + } + if (chip_enable_transport_trace) { public_deps += [ "${chip_root}/examples/common/tracing:trace_handlers_decoder" ] diff --git a/examples/fabric-admin/commands/fabric-sync/Commands.h b/examples/fabric-admin/commands/fabric-sync/Commands.h new file mode 100644 index 00000000000000..7c15416c560e60 --- /dev/null +++ b/examples/fabric-admin/commands/fabric-sync/Commands.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2021 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#pragma once + +#include +#include + +void registerCommandsFabricSync(Commands & commands, CredentialIssuerCommands * credsIssuerConfig) +{ + const char * clusterName = "FabricSync"; + + commands_list clusterCommands = { + make_unique(credsIssuerConfig), + }; + + commands.RegisterCommandSet(clusterName, clusterCommands, "Commands for fabric synchronization."); +} diff --git a/examples/fabric-admin/commands/fabric-sync/FabricSyncCommand.cpp b/examples/fabric-admin/commands/fabric-sync/FabricSyncCommand.cpp new file mode 100644 index 00000000000000..c2a1b5df8fb80e --- /dev/null +++ b/examples/fabric-admin/commands/fabric-sync/FabricSyncCommand.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "FabricSyncCommand.h" +#include +#include +#include + +#if defined(PW_RPC_ENABLED) +#include "pw_assert/check.h" +#include "pw_hdlc/decoder.h" +#include "pw_hdlc/default_addresses.h" +#include "pw_hdlc/rpc_channel.h" +#include "pw_rpc/client.h" +#include "pw_stream/socket_stream.h" + +#include +#endif + +using namespace ::chip; + +CHIP_ERROR FabricSyncAddDeviceCommand::RunCommand(NodeId remoteId) +{ +#if defined(PW_RPC_ENABLED) + AddSynchronizedDevice(remoteId); + return CHIP_NO_ERROR; +#else + return CHIP_ERROR_NOT_IMPLEMENTED; +#endif +} diff --git a/examples/fabric-admin/commands/fabric-sync/FabricSyncCommand.h b/examples/fabric-admin/commands/fabric-sync/FabricSyncCommand.h new file mode 100644 index 00000000000000..3b57e891db7723 --- /dev/null +++ b/examples/fabric-admin/commands/fabric-sync/FabricSyncCommand.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#pragma once + +#include + +class FabricSyncAddDeviceCommand : public CHIPCommand +{ +public: + FabricSyncAddDeviceCommand(CredentialIssuerCommands * credIssuerCommands) : CHIPCommand("add-device", credIssuerCommands) + { + AddArgument("nodeid", 0, UINT64_MAX, &mNodeId); + } + + /////////// CHIPCommand Interface ///////// + CHIP_ERROR RunCommand() override { return RunCommand(mNodeId); } + + chip::System::Clock::Timeout GetWaitDuration() const override { return chip::System::Clock::Seconds16(30); } + +private: + chip::NodeId mNodeId; + + CHIP_ERROR RunCommand(NodeId remoteId); +}; diff --git a/examples/fabric-admin/main.cpp b/examples/fabric-admin/main.cpp index a1002d83170d5b..450586cb5f86db 100644 --- a/examples/fabric-admin/main.cpp +++ b/examples/fabric-admin/main.cpp @@ -18,14 +18,43 @@ #include #include +#include #include #include #include #include #include +#include #include +#if defined(PW_RPC_ENABLED) +#include +#include +#endif + +#define RETRY_INTERVAL_S (3) + +void ApplicationInit() +{ +#if defined(PW_RPC_ENABLED) + InitRpcServer(kFabricAdminServerPort); + ChipLogProgress(NotSpecified, "PW_RPC initialized."); + + while (true) + { + if (InitRpcClient(kFabricBridgeServerPort) == CHIP_NO_ERROR) + { + ChipLogProgress(NotSpecified, "Connected to Fabric-Bridge"); + break; + } + + ChipLogError(NotSpecified, "Failed to connect to Fabric-Bridge, retry in %d seconds....", RETRY_INTERVAL_S); + std::this_thread::sleep_for(std::chrono::seconds(RETRY_INTERVAL_S)); + } +#endif +} + // ================================================================================ // Main Code // ================================================================================ @@ -45,6 +74,7 @@ int main(int argc, char * argv[]) ExampleCredentialIssuerCommands credIssuerCommands; Commands commands; + registerCommandsFabricSync(commands, &credIssuerCommands); registerCommandsInteractive(commands, &credIssuerCommands); registerCommandsPairing(commands, &credIssuerCommands); registerClusters(commands, &credIssuerCommands); @@ -56,5 +86,7 @@ int main(int argc, char * argv[]) c_args.push_back(const_cast(arg.c_str())); } + ApplicationInit(); + return commands.Run(static_cast(c_args.size()), c_args.data()); } diff --git a/examples/fabric-admin/rpc/RpcClient.cpp b/examples/fabric-admin/rpc/RpcClient.cpp new file mode 100644 index 00000000000000..0be1668f2daeac --- /dev/null +++ b/examples/fabric-admin/rpc/RpcClient.cpp @@ -0,0 +1,168 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "RpcClient.h" + +#include +#include +#include + +#include "fabric_bridge_service/fabric_bridge_service.rpc.pb.h" +#include "pw_assert/check.h" +#include "pw_hdlc/decoder.h" +#include "pw_hdlc/default_addresses.h" +#include "pw_hdlc/rpc_channel.h" +#include "pw_rpc/client.h" +#include "pw_stream/socket_stream.h" + +namespace { + +constexpr size_t kMaxTransmissionUnit = 256; +constexpr uint32_t kRpcTimeoutMs = 1000; +const char * rpcServerAddress = "127.0.0.1"; + +pw::stream::SocketStream rpcSocketStream; + +// Set up the output channel for the pw_rpc client to use. +pw::hdlc::RpcChannelOutput hdlc_channel_output(rpcSocketStream, pw::hdlc::kDefaultRpcAddress, "HDLC channel"); + +// An array of RPC channels (channels) is created, each associated with an HDLC channel output. +// This sets up the communication channels for RPC calls. +pw::rpc::Channel channels[] = { pw::rpc::Channel::Create<1>(&hdlc_channel_output) }; + +// Initialize the RPC client with the channels. +pw::rpc::Client client(channels); + +// Generated clients are namespaced with their proto library. +using FabricBridgeClient = chip::rpc::pw_rpc::nanopb::FabricBridge::Client; + +// RPC channel ID on which to make client calls. RPC calls cannot be made on +// channel 0 (Channel::kUnassignedChannelId). +constexpr uint32_t kDefaultChannelId = 1; + +// Function to process incoming packets +void ProcessPackets() +{ + std::array inputBuf; + pw::hdlc::Decoder decoder(inputBuf); + + while (true) + { + std::array data; + auto ret = rpcSocketStream.Read(data); + if (!ret.ok()) + { + if (ret.status() == pw::Status::OutOfRange()) + { + // Handle remote disconnect + rpcSocketStream.Close(); + return; + } + continue; + } + + for (std::byte byte : ret.value()) + { + auto result = decoder.Process(byte); + if (!result.ok()) + { + // Wait for more bytes that form a complete packet + continue; + } + pw::hdlc::Frame & frame = result.value(); + if (frame.address() != pw::hdlc::kDefaultRpcAddress) + { + // Wrong address; ignore the packet + continue; + } + + client.ProcessPacket(frame.data()).IgnoreError(); + } + } +} + +template +CHIP_ERROR WaitForResponse(CallType & call) +{ + if (!call.active()) + { + return CHIP_ERROR_INTERNAL; + } + + // Wait for the response or timeout + uint32_t elapsedTimeMs = 0; + const uint32_t sleepTimeMs = 100; + + while (call.active() && elapsedTimeMs < kRpcTimeoutMs) + { + usleep(sleepTimeMs * 1000); + elapsedTimeMs += sleepTimeMs; + } + + if (elapsedTimeMs >= kRpcTimeoutMs) + { + fprintf(stderr, "RPC Response timed out!"); + return CHIP_ERROR_TIMEOUT; + } + + return CHIP_NO_ERROR; +} + +void AddDeviceResponse(const pw_protobuf_Empty & response, pw::Status status) +{ + if (status.ok()) + { + printf("RPC call succeeded\n"); + } + else + { + printf("RPC call failed with status: %d\n", status.code()); + } +} + +} // namespace + +CHIP_ERROR InitRpcClient(uint16_t rpcServerPort) +{ + if (rpcSocketStream.Connect(rpcServerAddress, rpcServerPort) != PW_STATUS_OK) + { + ChipLogError(NotSpecified, "Failed to connect the Fabric-Admin"); + return CHIP_ERROR_NOT_CONNECTED; + } + + ChipLogProgress(NotSpecified, "Connectted to the Fabric-Admin\n"); + + // Start a thread to process incoming packets + std::thread packet_processor(ProcessPackets); + packet_processor.detach(); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR AddSynchronizedDevice(chip::NodeId nodeId) +{ + ChipLogProgress(NotSpecified, "AddSynchronizedDevice"); + + FabricBridgeClient fabric_bridge_client(client, kDefaultChannelId); + chip_rpc_SynchronizedDevice device; + device.node_id = nodeId; + + // The RPC will remain active as long as `call` is alive. + auto call = fabric_bridge_client.AddSynchronizedDevice(device, AddDeviceResponse); + return WaitForResponse(call); +} diff --git a/examples/fabric-admin/rpc/RpcClient.h b/examples/fabric-admin/rpc/RpcClient.h new file mode 100644 index 00000000000000..46c1e9497c53aa --- /dev/null +++ b/examples/fabric-admin/rpc/RpcClient.h @@ -0,0 +1,27 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +constexpr uint16_t kFabricBridgeServerPort = 33002; + +CHIP_ERROR InitRpcClient(uint16_t rpcServerPort); + +CHIP_ERROR AddSynchronizedDevice(chip::NodeId nodeId); diff --git a/examples/fabric-admin/rpc/RpcServer.cpp b/examples/fabric-admin/rpc/RpcServer.cpp new file mode 100644 index 00000000000000..ed3e6b0d59e077 --- /dev/null +++ b/examples/fabric-admin/rpc/RpcServer.cpp @@ -0,0 +1,70 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "pw_rpc/server.h" +#include "pw_rpc_system_server/rpc_server.h" +#include "pw_rpc_system_server/socket.h" + +#include +#include + +#if defined(PW_RPC_FABRIC_ADMIN_SERVICE) && PW_RPC_FABRIC_ADMIN_SERVICE +#include "pigweed/rpc_services/FabricAdmin.h" +#endif + +namespace { + +#if defined(PW_RPC_FABRIC_ADMIN_SERVICE) && PW_RPC_FABRIC_ADMIN_SERVICE +class FabricAdmin final : public chip::rpc::FabricAdmin +{ +public: + pw::Status OpenCommissioningWindow(const chip_rpc_DeviceInfo & request, chip_rpc_OperationStatus & response) override + { + chip::NodeId nodeId = request.node_id; + printf("Received OpenCommissioningWindow request: 0x%" PRIx64 "\n", nodeId); + response.success = false; + + return pw::OkStatus(); + } +}; + +FabricAdmin fabric_admin_service; +#endif // defined(PW_RPC_FABRIC_ADMIN_SERVICE) && PW_RPC_FABRIC_ADMIN_SERVICE + +void RegisterServices(pw::rpc::Server & server) +{ +#if defined(PW_RPC_FABRIC_ADMIN_SERVICE) && PW_RPC_FABRIC_ADMIN_SERVICE + server.RegisterService(fabric_admin_service); +#endif +} + +} // namespace + +void RunRpcService() +{ + pw::rpc::system_server::Init(); + RegisterServices(pw::rpc::system_server::Server()); + pw::rpc::system_server::Start(); +} + +void InitRpcServer(uint16_t rpcServerPort) +{ + pw::rpc::system_server::set_socket_port(rpcServerPort); + std::thread rpc_service(RunRpcService); + rpc_service.detach(); +} diff --git a/examples/fabric-admin/rpc/RpcServer.h b/examples/fabric-admin/rpc/RpcServer.h new file mode 100644 index 00000000000000..bc03bc0ac4abd3 --- /dev/null +++ b/examples/fabric-admin/rpc/RpcServer.h @@ -0,0 +1,23 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +constexpr uint16_t kFabricAdminServerPort = 33001; + +void InitRpcServer(uint16_t rpcServerPort); diff --git a/examples/fabric-admin/with_pw_rpc.gni b/examples/fabric-admin/with_pw_rpc.gni new file mode 100644 index 00000000000000..abb9ac65f27e78 --- /dev/null +++ b/examples/fabric-admin/with_pw_rpc.gni @@ -0,0 +1,42 @@ +# Copyright (c) 2024 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# add this gni as import in your build args to use pigweed in the example +# 'import("//with_pw_rpc.gni")' + +import("//build_overrides/chip.gni") + +import("${chip_root}/config/standalone/args.gni") + +import("//build_overrides/pigweed.gni") + +pw_log_BACKEND = "$dir_pw_log_basic" +pw_assert_BACKEND = "$dir_pw_assert_log:check_backend" +pw_sys_io_BACKEND = "$dir_pw_sys_io_stdio" +pw_trace_BACKEND = "$dir_pw_trace_tokenized" +pw_unit_test_MAIN = "$dir_pw_unit_test:logging_main" +pw_rpc_system_server_BACKEND = "${chip_root}/config/linux/lib/pw_rpc:pw_rpc" +dir_pw_third_party_nanopb = "${chip_root}/third_party/nanopb/repo" +pw_chrono_SYSTEM_CLOCK_BACKEND = "$dir_pw_chrono_stl:system_clock" +pw_sync_MUTEX_BACKEND = "$dir_pw_sync_stl:mutex_backend" +pw_thread_YIELD_BACKEND = "$dir_pw_thread_stl:yield" +pw_thread_SLEEP_BACKEND = "$dir_pw_thread_stl:sleep" + +pw_build_LINK_DEPS = [ + "$dir_pw_assert:impl", + "$dir_pw_log:impl", +] + +chip_enable_pw_rpc = true +chip_use_pw_logging = true diff --git a/examples/fabric-bridge-app/linux/BUILD.gn b/examples/fabric-bridge-app/linux/BUILD.gn index ea7e6e0b31b331..7a61d957984a49 100644 --- a/examples/fabric-bridge-app/linux/BUILD.gn +++ b/examples/fabric-bridge-app/linux/BUILD.gn @@ -18,13 +18,21 @@ import("${chip_root}/build/chip/tools.gni") assert(chip_build_tools) +import("//build_overrides/pigweed.gni") +import("$dir_pw_build/target_types.gni") +import("${chip_root}/examples/common/pigweed/pigweed_rpcs.gni") + executable("fabric-bridge-app") { sources = [ "${chip_root}/examples/fabric-bridge-app/fabric-bridge-common/include/CHIPProjectAppConfig.h", "Device.cpp", - "DeviceManager.cpp", "include/Device.h", + "DeviceManager.cpp", "include/DeviceManager.h", + "RpcClient.cpp", + "include/RpcClient.h", + "RpcServer.cpp", + "include/RpcServer.h", "main.cpp", ] @@ -38,6 +46,32 @@ executable("fabric-bridge-app") { include_dirs = [ "include" ] + defines = [ + "PW_RPC_FABRIC_ADMIN_SERVICE=1", + "PW_RPC_FABRIC_BRIDGE_SERVICE=1", + ] + + sources += [ "${chip_root}/examples/platform/linux/system_rpc_server.cc" ] + + deps += [ + "$dir_pw_hdlc:default_addresses", + "$dir_pw_hdlc:rpc_channel_output", + "$dir_pw_log", + "$dir_pw_rpc:server", + "$dir_pw_rpc/system_server:facade", + "$dir_pw_rpc/system_server:socket", + "$dir_pw_stream:socket_stream", + "$dir_pw_sync:mutex", + "${chip_root}/config/linux/lib/pw_rpc:pw_rpc", + "${chip_root}/examples/common/pigweed:fabric_admin_service.nanopb_rpc", + "${chip_root}/examples/common/pigweed:fabric_bridge_service.nanopb_rpc", + "${chip_root}/examples/common/pigweed:rpc_services", + ] + + deps += pw_build_LINK_DEPS + + include_dirs += [ "${chip_root}/examples/common" ] + output_dir = root_out_dir } diff --git a/examples/fabric-bridge-app/linux/RpcClient.cpp b/examples/fabric-bridge-app/linux/RpcClient.cpp new file mode 100644 index 00000000000000..57cfcb23a82e9b --- /dev/null +++ b/examples/fabric-bridge-app/linux/RpcClient.cpp @@ -0,0 +1,169 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "RpcClient.h" + +#include +#include +#include + +#include "fabric_admin_service/fabric_admin_service.rpc.pb.h" +#include "pw_assert/check.h" +#include "pw_hdlc/decoder.h" +#include "pw_hdlc/default_addresses.h" +#include "pw_hdlc/rpc_channel.h" +#include "pw_rpc/client.h" +#include "pw_stream/socket_stream.h" + +namespace { + +constexpr size_t kMaxTransmissionUnit = 256; +constexpr uint32_t kRpcTimeoutMs = 1000; +const char * rpcServerAddress = "127.0.0.1"; + +pw::stream::SocketStream rpcSocketStream; + +// Set up the output channel for the pw_rpc client to use. +pw::hdlc::RpcChannelOutput hdlc_channel_output(rpcSocketStream, pw::hdlc::kDefaultRpcAddress, "HDLC channel"); + +// An array of RPC channels (channels) is created, each associated with an HDLC channel output. +// This sets up the communication channels for RPC calls. +pw::rpc::Channel channels[] = { pw::rpc::Channel::Create<1>(&hdlc_channel_output) }; + +// Initialize the RPC client with the channels. +pw::rpc::Client client(channels); + +// Generated clients are namespaced with their proto library. +using FabricAdminClient = chip::rpc::pw_rpc::nanopb::FabricAdmin::Client; + +// RPC channel ID on which to make client calls. RPC calls cannot be made on +// channel 0 (Channel::kUnassignedChannelId). +constexpr uint32_t kDefaultChannelId = 1; + +// Function to process incoming packets +void ProcessPackets() +{ + std::array inputBuf; + pw::hdlc::Decoder decoder(inputBuf); + + while (true) + { + std::array data; + auto ret = rpcSocketStream.Read(data); + if (!ret.ok()) + { + if (ret.status() == pw::Status::OutOfRange()) + { + // Handle remote disconnect + rpcSocketStream.Close(); + return; + } + continue; + } + + for (std::byte byte : ret.value()) + { + auto result = decoder.Process(byte); + if (!result.ok()) + { + // Wait for more bytes that form a complete packet + continue; + } + pw::hdlc::Frame & frame = result.value(); + if (frame.address() != pw::hdlc::kDefaultRpcAddress) + { + // Wrong address; ignore the packet + continue; + } + + client.ProcessPacket(frame.data()).IgnoreError(); + } + } +} + +template +CHIP_ERROR WaitForResponse(CallType & call) +{ + if (!call.active()) + { + return CHIP_ERROR_INTERNAL; + } + + // Wait for the response or timeout + uint32_t elapsedTimeMs = 0; + const uint32_t sleepTimeMs = 100; + + while (call.active() && elapsedTimeMs < kRpcTimeoutMs) + { + usleep(sleepTimeMs * 1000); + elapsedTimeMs += sleepTimeMs; + } + + if (elapsedTimeMs >= kRpcTimeoutMs) + { + ChipLogError(NotSpecified, "RPC Response timed out!"); + return CHIP_ERROR_TIMEOUT; + } + + return CHIP_NO_ERROR; +} + +void OperationStatusResponse(const chip_rpc_OperationStatus & response, pw::Status status) +{ + if (status.ok()) + { + ChipLogProgress(NotSpecified, "Received operation status: %d", response.success); + } + else + { + ChipLogProgress(NotSpecified, "RPC call failed with status: %d\n", status.code()); + } +} + +} // namespace + +CHIP_ERROR InitRpcClient(uint16_t rpcServerPort) +{ + if (rpcSocketStream.Connect(rpcServerAddress, rpcServerPort) != PW_STATUS_OK) + { + ChipLogError(NotSpecified, "Failed to connect the Fabric-Admin"); + return CHIP_ERROR_NOT_CONNECTED; + } + + ChipLogProgress(NotSpecified, "Connectted to the Fabric-Admin\n"); + + // Start a thread to process incoming packets + std::thread packet_processor(ProcessPackets); + packet_processor.detach(); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR OpenCommissioningWindow(chip::NodeId nodeId) +{ + ChipLogProgress(NotSpecified, "OpenCommissioningWindow\n"); + + FabricAdminClient fabric_admin_client(client, kDefaultChannelId); + chip_rpc_DeviceInfo device; + + device.node_id = nodeId; + + // The RPC will remain active as long as `call` is alive. + auto call = fabric_admin_client.OpenCommissioningWindow(device, OperationStatusResponse); + return WaitForResponse(call); +} diff --git a/examples/fabric-bridge-app/linux/RpcServer.cpp b/examples/fabric-bridge-app/linux/RpcServer.cpp new file mode 100644 index 00000000000000..c971811b193016 --- /dev/null +++ b/examples/fabric-bridge-app/linux/RpcServer.cpp @@ -0,0 +1,68 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "pw_rpc/server.h" +#include "pw_rpc_system_server/rpc_server.h" +#include "pw_rpc_system_server/socket.h" + +#include +#include + +#if defined(PW_RPC_FABRIC_BRIDGE_SERVICE) && PW_RPC_FABRIC_BRIDGE_SERVICE +#include "pigweed/rpc_services/FabricBridge.h" +#endif + +namespace { + +#if defined(PW_RPC_FABRIC_BRIDGE_SERVICE) && PW_RPC_FABRIC_BRIDGE_SERVICE +class FabricBridge final : public chip::rpc::FabricBridge +{ +public: + pw::Status AddSynchronizedDevice(const chip_rpc_SynchronizedDevice & request, pw_protobuf_Empty & response) override + { + chip::NodeId nodeId = request.node_id; + ChipLogProgress(NotSpecified, "Received AddSynchronizedDevice: " ChipLogFormatX64, ChipLogValueX64(nodeId)); + return pw::OkStatus(); + } +}; + +FabricBridge fabric_bridge_service; +#endif // defined(PW_RPC_FABRIC_BRIDGE_SERVICE) && PW_RPC_FABRIC_BRIDGE_SERVICE + +void RegisterServices(pw::rpc::Server & server) +{ +#if defined(PW_RPC_FABRIC_BRIDGE_SERVICE) && PW_RPC_FABRIC_BRIDGE_SERVICE + server.RegisterService(fabric_bridge_service); +#endif +} + +} // namespace + +void RunRpcService() +{ + pw::rpc::system_server::Init(); + RegisterServices(pw::rpc::system_server::Server()); + pw::rpc::system_server::Start(); +} + +void InitRpcServer(uint16_t rpcServerPort) +{ + pw::rpc::system_server::set_socket_port(rpcServerPort); + std::thread rpc_service(RunRpcService); + rpc_service.detach(); +} diff --git a/examples/fabric-bridge-app/linux/include/RpcClient.h b/examples/fabric-bridge-app/linux/include/RpcClient.h new file mode 100644 index 00000000000000..8baa8231f63cb4 --- /dev/null +++ b/examples/fabric-bridge-app/linux/include/RpcClient.h @@ -0,0 +1,27 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +constexpr uint16_t kFabricAdminServerPort = 33001; + +CHIP_ERROR InitRpcClient(uint16_t rpcServerPort); + +CHIP_ERROR OpenCommissioningWindow(chip::NodeId nodeId); diff --git a/examples/fabric-bridge-app/linux/include/RpcServer.h b/examples/fabric-bridge-app/linux/include/RpcServer.h new file mode 100644 index 00000000000000..f86858b19bdfe3 --- /dev/null +++ b/examples/fabric-bridge-app/linux/include/RpcServer.h @@ -0,0 +1,23 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +constexpr uint16_t kFabricBridgeServerPort = 33002; + +void InitRpcServer(uint16_t rpcServerPort); diff --git a/examples/fabric-bridge-app/linux/main.cpp b/examples/fabric-bridge-app/linux/main.cpp index 600d4a2a376d55..edd6efdbde3e2e 100644 --- a/examples/fabric-bridge-app/linux/main.cpp +++ b/examples/fabric-bridge-app/linux/main.cpp @@ -17,27 +17,61 @@ */ #include +#include +#include -#include "CommissionableInit.h" -#include "Device.h" -#include "DeviceManager.h" - +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include "CommissionableInit.h" +#include "Device.h" +#include "DeviceManager.h" +#if defined(PW_RPC_FABRIC_BRIDGE_SERVICE) +#include "RpcClient.h" +#include "RpcServer.h" +#endif + +#include +#include +#include #include #include #include using namespace chip; - -#define POLL_INTERVAL_MS (100) -#define ZCL_DESCRIPTOR_CLUSTER_REVISION (1u) -#define ZCL_BRIDGED_DEVICE_BASIC_INFORMATION_CLUSTER_REVISION (2u) -#define ZCL_BRIDGED_DEVICE_BASIC_INFORMATION_FEATURE_MAP (0u) +using namespace chip::app; +using namespace chip::Credentials; +using namespace chip::Inet; +using namespace chip::Transport; +using namespace chip::DeviceLayer; +using namespace chip::app::Clusters; namespace { +constexpr uint16_t kPollIntervalMs = 100; +constexpr uint16_t kRetryIntervalS = 3; + +EndpointId gCurrentEndpointId; +EndpointId gFirstDynamicEndpointId; +Device * gDevices[CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT + 1]; + bool KeyboardHit() { int bytesWaiting; @@ -57,20 +91,66 @@ void BridgePollingThread() ChipLogProgress(NotSpecified, "Exiting....."); exit(0); } +#if defined(PW_RPC_FABRIC_BRIDGE_SERVICE) + else if (ch == 'o') + { + if (OpenCommissioningWindow(0x1234) != CHIP_NO_ERROR) + { + ChipLogError(NotSpecified, "Failed to call OpenCommissioningWindow RPC"); + } + } +#endif continue; } // Sleep to avoid tight loop reading commands - usleep(POLL_INTERVAL_MS * 1000); + usleep(kPollIntervalMs * 1000); } } +#if defined(PW_RPC_FABRIC_BRIDGE_SERVICE) +void AttemptRpcClientConnect(System::Layer * systemLayer, void * appState) +{ + if (InitRpcClient(kFabricAdminServerPort) == CHIP_NO_ERROR) + { + ChipLogProgress(NotSpecified, "Connected to Fabric-Admin"); + } + else + { + ChipLogError(NotSpecified, "Failed to connect to Fabric-Admin, retry in %d seconds....", kRetryIntervalS); + systemLayer->StartTimer(System::Clock::Seconds16(kRetryIntervalS), AttemptRpcClientConnect, nullptr); + } +} +#endif + DeviceManager gDeviceManager; } // namespace +// REVISION DEFINITIONS: +// ================================================================================= + +#define ZCL_DESCRIPTOR_CLUSTER_REVISION (1u) +#define ZCL_BRIDGED_DEVICE_BASIC_INFORMATION_CLUSTER_REVISION (2u) +#define ZCL_BRIDGED_DEVICE_BASIC_INFORMATION_FEATURE_MAP (0u) + void ApplicationInit() { + // Clear out the device database + memset(gDevices, 0, sizeof(gDevices)); + + // Set starting endpoint id where dynamic endpoints will be assigned, which + // will be the next consecutive endpoint id after the last fixed endpoint. + gFirstDynamicEndpointId = static_cast( + static_cast(emberAfEndpointFromIndex(static_cast(emberAfFixedEndpointCount() - 1))) + 1); + gCurrentEndpointId = gFirstDynamicEndpointId; + +#if defined(PW_RPC_FABRIC_BRIDGE_SERVICE) + InitRpcServer(kFabricBridgeServerPort); + + AttemptRpcClientConnect(&DeviceLayer::SystemLayer(), nullptr); +#endif + // Start a thread for bridge polling std::thread pollingThread(BridgePollingThread); pollingThread.detach(); diff --git a/examples/fabric-bridge-app/linux/with_pw_rpc.gni b/examples/fabric-bridge-app/linux/with_pw_rpc.gni new file mode 100644 index 00000000000000..054640f9ddae61 --- /dev/null +++ b/examples/fabric-bridge-app/linux/with_pw_rpc.gni @@ -0,0 +1,41 @@ +# Copyright (c) 2024 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# add this gni as import in your build args to use pigweed in the example +# 'import("//with_pw_rpc.gni")' + +import("//build_overrides/chip.gni") + +import("${chip_root}/config/standalone/args.gni") + +import("//build_overrides/pigweed.gni") + +pw_log_BACKEND = "$dir_pw_log_basic" +pw_assert_BACKEND = "$dir_pw_assert_log:check_backend" +pw_sys_io_BACKEND = "$dir_pw_sys_io_stdio" +pw_trace_BACKEND = "$dir_pw_trace_tokenized" +pw_unit_test_MAIN = "$dir_pw_unit_test:logging_main" +pw_rpc_system_server_BACKEND = "${chip_root}/config/linux/lib/pw_rpc:pw_rpc" +dir_pw_third_party_nanopb = "${chip_root}/third_party/nanopb/repo" +pw_chrono_SYSTEM_CLOCK_BACKEND = "$dir_pw_chrono_stl:system_clock" +pw_sync_MUTEX_BACKEND = "$dir_pw_sync_stl:mutex_backend" +pw_thread_YIELD_BACKEND = "$dir_pw_thread_stl:yield" +pw_thread_SLEEP_BACKEND = "$dir_pw_thread_stl:sleep" + +pw_build_LINK_DEPS = [ + "$dir_pw_assert:impl", + "$dir_pw_log:impl", +] + +chip_use_pw_logging = true From 4c2f79875fa0c19b20a04418de16223fd7fa8736 Mon Sep 17 00:00:00 2001 From: Yufeng Wang Date: Fri, 24 May 2024 21:54:33 -0700 Subject: [PATCH 2/5] Add bridge_enable_pw_rpc build flag --- examples/fabric-admin/BUILD.gn | 6 +- .../commands/fabric-sync/FabricSyncCommand.h | 2 +- examples/fabric-admin/rpc/RpcServer.cpp | 2 +- examples/fabric-bridge-app/linux/BUILD.gn | 72 +++++++++++-------- examples/fabric-bridge-app/linux/main.cpp | 3 + .../fabric-bridge-app/linux/with_pw_rpc.gni | 1 + 6 files changed, 52 insertions(+), 34 deletions(-) diff --git a/examples/fabric-admin/BUILD.gn b/examples/fabric-admin/BUILD.gn index c8a95a3c3925be..ecc218688a7db5 100644 --- a/examples/fabric-admin/BUILD.gn +++ b/examples/fabric-admin/BUILD.gn @@ -45,6 +45,8 @@ config("config") { defines += [ "CONFIG_USE_LOCAL_STORAGE" ] } + cflags = [ "-Wconversion" ] + if (chip_enable_pw_rpc) { defines += [ "PW_RPC_ENABLED" ] } @@ -135,10 +137,6 @@ static_library("fabric-admin-utils") { ] deps += pw_build_LINK_DEPS - } else { - # The system_rpc_server.cc file is in pigweed and doesn't compile with - # -Wconversion, remove check for RPC build only. - cflags = [ "-Wconversion" ] } if (chip_enable_transport_trace) { diff --git a/examples/fabric-admin/commands/fabric-sync/FabricSyncCommand.h b/examples/fabric-admin/commands/fabric-sync/FabricSyncCommand.h index 3b57e891db7723..cf739ccfb3a520 100644 --- a/examples/fabric-admin/commands/fabric-sync/FabricSyncCommand.h +++ b/examples/fabric-admin/commands/fabric-sync/FabricSyncCommand.h @@ -31,7 +31,7 @@ class FabricSyncAddDeviceCommand : public CHIPCommand /////////// CHIPCommand Interface ///////// CHIP_ERROR RunCommand() override { return RunCommand(mNodeId); } - chip::System::Clock::Timeout GetWaitDuration() const override { return chip::System::Clock::Seconds16(30); } + chip::System::Clock::Timeout GetWaitDuration() const override { return chip::System::Clock::Seconds16(1); } private: chip::NodeId mNodeId; diff --git a/examples/fabric-admin/rpc/RpcServer.cpp b/examples/fabric-admin/rpc/RpcServer.cpp index ed3e6b0d59e077..769d430786199a 100644 --- a/examples/fabric-admin/rpc/RpcServer.cpp +++ b/examples/fabric-admin/rpc/RpcServer.cpp @@ -36,7 +36,7 @@ class FabricAdmin final : public chip::rpc::FabricAdmin pw::Status OpenCommissioningWindow(const chip_rpc_DeviceInfo & request, chip_rpc_OperationStatus & response) override { chip::NodeId nodeId = request.node_id; - printf("Received OpenCommissioningWindow request: 0x%" PRIx64 "\n", nodeId); + printf("Received OpenCommissioningWindow request: 0x%llx\n", nodeId); response.success = false; return pw::OkStatus(); diff --git a/examples/fabric-bridge-app/linux/BUILD.gn b/examples/fabric-bridge-app/linux/BUILD.gn index 7a61d957984a49..7661be9cb8dacb 100644 --- a/examples/fabric-bridge-app/linux/BUILD.gn +++ b/examples/fabric-bridge-app/linux/BUILD.gn @@ -16,11 +16,19 @@ import("//build_overrides/chip.gni") import("${chip_root}/build/chip/tools.gni") +import("//with_pw_rpc.gni") + assert(chip_build_tools) -import("//build_overrides/pigweed.gni") -import("$dir_pw_build/target_types.gni") -import("${chip_root}/examples/common/pigweed/pigweed_rpcs.gni") +declare_args() { + bridge_enable_pw_rpc = false +} + +if (bridge_enable_pw_rpc) { + import("//build_overrides/pigweed.gni") + import("$dir_pw_build/target_types.gni") + import("${chip_root}/examples/common/pigweed/pigweed_rpcs.gni") +} executable("fabric-bridge-app") { sources = [ @@ -46,31 +54,39 @@ executable("fabric-bridge-app") { include_dirs = [ "include" ] - defines = [ - "PW_RPC_FABRIC_ADMIN_SERVICE=1", - "PW_RPC_FABRIC_BRIDGE_SERVICE=1", - ] - - sources += [ "${chip_root}/examples/platform/linux/system_rpc_server.cc" ] - - deps += [ - "$dir_pw_hdlc:default_addresses", - "$dir_pw_hdlc:rpc_channel_output", - "$dir_pw_log", - "$dir_pw_rpc:server", - "$dir_pw_rpc/system_server:facade", - "$dir_pw_rpc/system_server:socket", - "$dir_pw_stream:socket_stream", - "$dir_pw_sync:mutex", - "${chip_root}/config/linux/lib/pw_rpc:pw_rpc", - "${chip_root}/examples/common/pigweed:fabric_admin_service.nanopb_rpc", - "${chip_root}/examples/common/pigweed:fabric_bridge_service.nanopb_rpc", - "${chip_root}/examples/common/pigweed:rpc_services", - ] - - deps += pw_build_LINK_DEPS - - include_dirs += [ "${chip_root}/examples/common" ] + if (bridge_enable_pw_rpc) { + defines = [ + "PW_RPC_FABRIC_ADMIN_SERVICE=1", + "PW_RPC_FABRIC_BRIDGE_SERVICE=1", + ] + + sources += [ + "${chip_root}/examples/platform/linux/system_rpc_server.cc", + "RpcClient.cpp", + "RpcServer.cpp", + "include/RpcClient.h", + "include/RpcServer.h", + ] + + deps += [ + "$dir_pw_hdlc:default_addresses", + "$dir_pw_hdlc:rpc_channel_output", + "$dir_pw_log", + "$dir_pw_rpc:server", + "$dir_pw_rpc/system_server:facade", + "$dir_pw_rpc/system_server:socket", + "$dir_pw_stream:socket_stream", + "$dir_pw_sync:mutex", + "${chip_root}/config/linux/lib/pw_rpc:pw_rpc", + "${chip_root}/examples/common/pigweed:fabric_admin_service.nanopb_rpc", + "${chip_root}/examples/common/pigweed:fabric_bridge_service.nanopb_rpc", + "${chip_root}/examples/common/pigweed:rpc_services", + ] + + deps += pw_build_LINK_DEPS + + include_dirs += [ "${chip_root}/examples/common" ] + } output_dir = root_out_dir } diff --git a/examples/fabric-bridge-app/linux/main.cpp b/examples/fabric-bridge-app/linux/main.cpp index edd6efdbde3e2e..341129ef2cacd7 100644 --- a/examples/fabric-bridge-app/linux/main.cpp +++ b/examples/fabric-bridge-app/linux/main.cpp @@ -42,7 +42,10 @@ #include "CommissionableInit.h" #include "Device.h" +<<<<<<< HEAD #include "DeviceManager.h" +======= +>>>>>>> 9631848953 (Add bridge_enable_pw_rpc build flag) #if defined(PW_RPC_FABRIC_BRIDGE_SERVICE) #include "RpcClient.h" #include "RpcServer.h" diff --git a/examples/fabric-bridge-app/linux/with_pw_rpc.gni b/examples/fabric-bridge-app/linux/with_pw_rpc.gni index 054640f9ddae61..e1bd567cf22db2 100644 --- a/examples/fabric-bridge-app/linux/with_pw_rpc.gni +++ b/examples/fabric-bridge-app/linux/with_pw_rpc.gni @@ -39,3 +39,4 @@ pw_build_LINK_DEPS = [ ] chip_use_pw_logging = true +bridge_enable_pw_rpc = true From e38cf147d12ae177a5f3f05c5f9ac302bb7465d2 Mon Sep 17 00:00:00 2001 From: Yufeng Wang Date: Thu, 30 May 2024 10:23:35 -0700 Subject: [PATCH 3/5] Address review comments --- .../interactive/InteractiveCommands.cpp | 41 ++++++++++-- examples/fabric-admin/main.cpp | 16 +---- examples/fabric-admin/rpc/RpcClient.cpp | 3 - examples/fabric-admin/rpc/RpcServer.cpp | 2 +- examples/fabric-bridge-app/linux/BUILD.gn | 4 -- .../fabric-bridge-app/linux/RpcClient.cpp | 4 -- examples/fabric-bridge-app/linux/main.cpp | 62 +++---------------- 7 files changed, 46 insertions(+), 86 deletions(-) diff --git a/examples/fabric-admin/commands/interactive/InteractiveCommands.cpp b/examples/fabric-admin/commands/interactive/InteractiveCommands.cpp index aaf3c36461cffb..c5c844256f5351 100644 --- a/examples/fabric-admin/commands/interactive/InteractiveCommands.cpp +++ b/examples/fabric-admin/commands/interactive/InteractiveCommands.cpp @@ -28,11 +28,18 @@ #include #include +#if defined(PW_RPC_ENABLED) +#include +#endif + +using namespace chip; + +namespace { + constexpr char kInteractiveModePrompt[] = ">>> "; constexpr char kInteractiveModeHistoryFileName[] = "chip_tool_history"; constexpr char kInteractiveModeStopCommand[] = "quit()"; - -namespace { +constexpr uint16_t kRetryIntervalS = 5; // File pointer for the log file FILE * sLogFile = nullptr; @@ -67,7 +74,7 @@ void ENFORCE_FORMAT(3, 0) LoggingCallback(const char * module, uint8_t category, return; } - uint64_t timeMs = chip::System::SystemClock().GetMonotonicMilliseconds64().count(); + uint64_t timeMs = System::SystemClock().GetMonotonicMilliseconds64().count(); uint64_t seconds = timeMs / 1000; uint64_t milliseconds = timeMs % 1000; @@ -82,6 +89,26 @@ void ENFORCE_FORMAT(3, 0) LoggingCallback(const char * module, uint8_t category, funlockfile(sLogFile); } +#if defined(PW_RPC_ENABLED) +void AttemptRpcClientConnect(System::Layer * systemLayer, void * appState) +{ + if (InitRpcClient(kFabricBridgeServerPort) == CHIP_NO_ERROR) + { + ChipLogProgress(NotSpecified, "Connected to Fabric-Bridge"); + } + else + { + ChipLogError(NotSpecified, "Failed to connect to Fabric-Bridge, retry in %d seconds....", kRetryIntervalS); + systemLayer->StartTimer(System::Clock::Seconds16(kRetryIntervalS), AttemptRpcClientConnect, nullptr); + } +} + +void ExecuteDeferredConnect(intptr_t ignored) +{ + AttemptRpcClientConnect(&DeviceLayer::SystemLayer(), nullptr); +} +#endif + } // namespace char * InteractiveStartCommand::GetCommand(char * command) @@ -134,9 +161,13 @@ CHIP_ERROR InteractiveStartCommand::RunCommand() OpenLogFile(mLogFilePath.Value()); // Redirect logs to the custom logging callback - chip::Logging::SetLogRedirectCallback(LoggingCallback); + Logging::SetLogRedirectCallback(LoggingCallback); } +#if defined(PW_RPC_ENABLED) + DeviceLayer::PlatformMgr().ScheduleWork(ExecuteDeferredConnect, 0); +#endif + char * command = nullptr; int status; while (true) @@ -167,7 +198,7 @@ bool InteractiveCommand::ParseCommand(char * command, int * status) // If scheduling the cleanup fails, there is not much we can do. // But if something went wrong while the application is leaving it could be because things have // not been cleaned up properly, so it is still useful to log the failure. - LogErrorOnFailure(chip::DeviceLayer::PlatformMgr().ScheduleWork(ExecuteDeferredCleanups, 0)); + LogErrorOnFailure(DeviceLayer::PlatformMgr().ScheduleWork(ExecuteDeferredCleanups, 0)); return false; } diff --git a/examples/fabric-admin/main.cpp b/examples/fabric-admin/main.cpp index 450586cb5f86db..f5f98cc0d960db 100644 --- a/examples/fabric-admin/main.cpp +++ b/examples/fabric-admin/main.cpp @@ -25,33 +25,19 @@ #include #include -#include #include #if defined(PW_RPC_ENABLED) -#include #include #endif -#define RETRY_INTERVAL_S (3) +using namespace chip; void ApplicationInit() { #if defined(PW_RPC_ENABLED) InitRpcServer(kFabricAdminServerPort); ChipLogProgress(NotSpecified, "PW_RPC initialized."); - - while (true) - { - if (InitRpcClient(kFabricBridgeServerPort) == CHIP_NO_ERROR) - { - ChipLogProgress(NotSpecified, "Connected to Fabric-Bridge"); - break; - } - - ChipLogError(NotSpecified, "Failed to connect to Fabric-Bridge, retry in %d seconds....", RETRY_INTERVAL_S); - std::this_thread::sleep_for(std::chrono::seconds(RETRY_INTERVAL_S)); - } #endif } diff --git a/examples/fabric-admin/rpc/RpcClient.cpp b/examples/fabric-admin/rpc/RpcClient.cpp index 0be1668f2daeac..b9d309e08c5730 100644 --- a/examples/fabric-admin/rpc/RpcClient.cpp +++ b/examples/fabric-admin/rpc/RpcClient.cpp @@ -141,12 +141,9 @@ CHIP_ERROR InitRpcClient(uint16_t rpcServerPort) { if (rpcSocketStream.Connect(rpcServerAddress, rpcServerPort) != PW_STATUS_OK) { - ChipLogError(NotSpecified, "Failed to connect the Fabric-Admin"); return CHIP_ERROR_NOT_CONNECTED; } - ChipLogProgress(NotSpecified, "Connectted to the Fabric-Admin\n"); - // Start a thread to process incoming packets std::thread packet_processor(ProcessPackets); packet_processor.detach(); diff --git a/examples/fabric-admin/rpc/RpcServer.cpp b/examples/fabric-admin/rpc/RpcServer.cpp index 769d430786199a..1fb264bd65c53a 100644 --- a/examples/fabric-admin/rpc/RpcServer.cpp +++ b/examples/fabric-admin/rpc/RpcServer.cpp @@ -36,7 +36,7 @@ class FabricAdmin final : public chip::rpc::FabricAdmin pw::Status OpenCommissioningWindow(const chip_rpc_DeviceInfo & request, chip_rpc_OperationStatus & response) override { chip::NodeId nodeId = request.node_id; - printf("Received OpenCommissioningWindow request: 0x%llx\n", nodeId); + printf("Received OpenCommissioningWindow request: 0x%lx\n", nodeId); response.success = false; return pw::OkStatus(); diff --git a/examples/fabric-bridge-app/linux/BUILD.gn b/examples/fabric-bridge-app/linux/BUILD.gn index 7661be9cb8dacb..155f3fb283fd66 100644 --- a/examples/fabric-bridge-app/linux/BUILD.gn +++ b/examples/fabric-bridge-app/linux/BUILD.gn @@ -37,10 +37,6 @@ executable("fabric-bridge-app") { "include/Device.h", "DeviceManager.cpp", "include/DeviceManager.h", - "RpcClient.cpp", - "include/RpcClient.h", - "RpcServer.cpp", - "include/RpcServer.h", "main.cpp", ] diff --git a/examples/fabric-bridge-app/linux/RpcClient.cpp b/examples/fabric-bridge-app/linux/RpcClient.cpp index 57cfcb23a82e9b..6422ed0cc7892c 100644 --- a/examples/fabric-bridge-app/linux/RpcClient.cpp +++ b/examples/fabric-bridge-app/linux/RpcClient.cpp @@ -141,12 +141,9 @@ CHIP_ERROR InitRpcClient(uint16_t rpcServerPort) { if (rpcSocketStream.Connect(rpcServerAddress, rpcServerPort) != PW_STATUS_OK) { - ChipLogError(NotSpecified, "Failed to connect the Fabric-Admin"); return CHIP_ERROR_NOT_CONNECTED; } - ChipLogProgress(NotSpecified, "Connectted to the Fabric-Admin\n"); - // Start a thread to process incoming packets std::thread packet_processor(ProcessPackets); packet_processor.detach(); @@ -160,7 +157,6 @@ CHIP_ERROR OpenCommissioningWindow(chip::NodeId nodeId) FabricAdminClient fabric_admin_client(client, kDefaultChannelId); chip_rpc_DeviceInfo device; - device.node_id = nodeId; // The RPC will remain active as long as `call` is alive. diff --git a/examples/fabric-bridge-app/linux/main.cpp b/examples/fabric-bridge-app/linux/main.cpp index 341129ef2cacd7..3c27d6a301e9c6 100644 --- a/examples/fabric-bridge-app/linux/main.cpp +++ b/examples/fabric-bridge-app/linux/main.cpp @@ -17,64 +17,34 @@ */ #include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include "CommissionableInit.h" #include "Device.h" -<<<<<<< HEAD #include "DeviceManager.h" -======= ->>>>>>> 9631848953 (Add bridge_enable_pw_rpc build flag) + +#include +#include + #if defined(PW_RPC_FABRIC_BRIDGE_SERVICE) #include "RpcClient.h" #include "RpcServer.h" #endif -#include -#include -#include #include #include #include using namespace chip; -using namespace chip::app; -using namespace chip::Credentials; -using namespace chip::Inet; -using namespace chip::Transport; -using namespace chip::DeviceLayer; -using namespace chip::app::Clusters; + +#define ZCL_DESCRIPTOR_CLUSTER_REVISION (1u) +#define ZCL_BRIDGED_DEVICE_BASIC_INFORMATION_CLUSTER_REVISION (2u) +#define ZCL_BRIDGED_DEVICE_BASIC_INFORMATION_FEATURE_MAP (0u) namespace { constexpr uint16_t kPollIntervalMs = 100; constexpr uint16_t kRetryIntervalS = 3; -EndpointId gCurrentEndpointId; -EndpointId gFirstDynamicEndpointId; -Device * gDevices[CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT + 1]; - bool KeyboardHit() { int bytesWaiting; @@ -130,24 +100,8 @@ DeviceManager gDeviceManager; } // namespace -// REVISION DEFINITIONS: -// ================================================================================= - -#define ZCL_DESCRIPTOR_CLUSTER_REVISION (1u) -#define ZCL_BRIDGED_DEVICE_BASIC_INFORMATION_CLUSTER_REVISION (2u) -#define ZCL_BRIDGED_DEVICE_BASIC_INFORMATION_FEATURE_MAP (0u) - void ApplicationInit() { - // Clear out the device database - memset(gDevices, 0, sizeof(gDevices)); - - // Set starting endpoint id where dynamic endpoints will be assigned, which - // will be the next consecutive endpoint id after the last fixed endpoint. - gFirstDynamicEndpointId = static_cast( - static_cast(emberAfEndpointFromIndex(static_cast(emberAfFixedEndpointCount() - 1))) + 1); - gCurrentEndpointId = gFirstDynamicEndpointId; - #if defined(PW_RPC_FABRIC_BRIDGE_SERVICE) InitRpcServer(kFabricBridgeServerPort); From 40bf9848786c9d9ffd1f94ecbd0007253129a747 Mon Sep 17 00:00:00 2001 From: Yufeng Wang Date: Fri, 31 May 2024 17:16:17 -0700 Subject: [PATCH 4/5] Add RpcClientProcessor --- examples/fabric-admin/BUILD.gn | 3 + examples/fabric-admin/rpc/RpcClient.cpp | 134 ++++------------- examples/fabric-admin/rpc/RpcClient.h | 19 +++ examples/fabric-admin/rpc/RpcServer.cpp | 2 +- examples/fabric-bridge-app/linux/BUILD.gn | 9 +- .../fabric-bridge-app/linux/RpcClient.cpp | 135 ++++-------------- .../linux/include/RpcClient.h | 17 +++ examples/fabric-bridge-app/linux/main.cpp | 18 +-- .../platform/linux/RpcClientProcessor.cpp | 124 ++++++++++++++++ examples/platform/linux/RpcClientProcessor.h | 36 +++++ 10 files changed, 274 insertions(+), 223 deletions(-) create mode 100644 examples/platform/linux/RpcClientProcessor.cpp create mode 100644 examples/platform/linux/RpcClientProcessor.h diff --git a/examples/fabric-admin/BUILD.gn b/examples/fabric-admin/BUILD.gn index ecc218688a7db5..ad7eb217f9914c 100644 --- a/examples/fabric-admin/BUILD.gn +++ b/examples/fabric-admin/BUILD.gn @@ -33,6 +33,7 @@ config("config") { include_dirs = [ ".", "${chip_root}/examples/common", + "${chip_root}/examples/platform/linux", "${chip_root}/zzz_generated/app-common/app-common", "${chip_root}/zzz_generated/chip-tool", "${chip_root}/src/lib", @@ -114,6 +115,8 @@ static_library("fabric-admin-utils") { ] sources += [ + "${chip_root}/examples/platform/linux/RpcClientProcessor.cpp", + "${chip_root}/examples/platform/linux/RpcClientProcessor.h", "${chip_root}/examples/platform/linux/system_rpc_server.cc", "rpc/RpcClient.cpp", "rpc/RpcClient.h", diff --git a/examples/fabric-admin/rpc/RpcClient.cpp b/examples/fabric-admin/rpc/RpcClient.cpp index b9d309e08c5730..a1a34d309ba17a 100644 --- a/examples/fabric-admin/rpc/RpcClient.cpp +++ b/examples/fabric-admin/rpc/RpcClient.cpp @@ -17,6 +17,7 @@ */ #include "RpcClient.h" +#include "RpcClientProcessor.h" #include #include @@ -24,114 +25,34 @@ #include "fabric_bridge_service/fabric_bridge_service.rpc.pb.h" #include "pw_assert/check.h" +#include "pw_function/function.h" #include "pw_hdlc/decoder.h" #include "pw_hdlc/default_addresses.h" #include "pw_hdlc/rpc_channel.h" #include "pw_rpc/client.h" #include "pw_stream/socket_stream.h" -namespace { - -constexpr size_t kMaxTransmissionUnit = 256; -constexpr uint32_t kRpcTimeoutMs = 1000; -const char * rpcServerAddress = "127.0.0.1"; - -pw::stream::SocketStream rpcSocketStream; - -// Set up the output channel for the pw_rpc client to use. -pw::hdlc::RpcChannelOutput hdlc_channel_output(rpcSocketStream, pw::hdlc::kDefaultRpcAddress, "HDLC channel"); - -// An array of RPC channels (channels) is created, each associated with an HDLC channel output. -// This sets up the communication channels for RPC calls. -pw::rpc::Channel channels[] = { pw::rpc::Channel::Create<1>(&hdlc_channel_output) }; - -// Initialize the RPC client with the channels. -pw::rpc::Client client(channels); +using namespace chip; -// Generated clients are namespaced with their proto library. -using FabricBridgeClient = chip::rpc::pw_rpc::nanopb::FabricBridge::Client; +namespace { -// RPC channel ID on which to make client calls. RPC calls cannot be made on -// channel 0 (Channel::kUnassignedChannelId). +// Constants constexpr uint32_t kDefaultChannelId = 1; -// Function to process incoming packets -void ProcessPackets() -{ - std::array inputBuf; - pw::hdlc::Decoder decoder(inputBuf); +// Fabric Bridge Client +rpc::pw_rpc::nanopb::FabricBridge::Client fabricBridgeClient(rpc::client::GetDefaultRpcClient(), kDefaultChannelId); +pw::rpc::NanopbUnaryReceiver<::pw_protobuf_Empty> addSynchronizedDeviceCall; - while (true) - { - std::array data; - auto ret = rpcSocketStream.Read(data); - if (!ret.ok()) - { - if (ret.status() == pw::Status::OutOfRange()) - { - // Handle remote disconnect - rpcSocketStream.Close(); - return; - } - continue; - } - - for (std::byte byte : ret.value()) - { - auto result = decoder.Process(byte); - if (!result.ok()) - { - // Wait for more bytes that form a complete packet - continue; - } - pw::hdlc::Frame & frame = result.value(); - if (frame.address() != pw::hdlc::kDefaultRpcAddress) - { - // Wrong address; ignore the packet - continue; - } - - client.ProcessPacket(frame.data()).IgnoreError(); - } - } -} - -template -CHIP_ERROR WaitForResponse(CallType & call) -{ - if (!call.active()) - { - return CHIP_ERROR_INTERNAL; - } - - // Wait for the response or timeout - uint32_t elapsedTimeMs = 0; - const uint32_t sleepTimeMs = 100; - - while (call.active() && elapsedTimeMs < kRpcTimeoutMs) - { - usleep(sleepTimeMs * 1000); - elapsedTimeMs += sleepTimeMs; - } - - if (elapsedTimeMs >= kRpcTimeoutMs) - { - fprintf(stderr, "RPC Response timed out!"); - return CHIP_ERROR_TIMEOUT; - } - - return CHIP_NO_ERROR; -} - -void AddDeviceResponse(const pw_protobuf_Empty & response, pw::Status status) +// Callback function to be called when the RPC response is received +void OnAddDeviceResponseCompleted(const pw_protobuf_Empty & response, pw::Status status) { if (status.ok()) { - printf("RPC call succeeded\n"); + ChipLogProgress(NotSpecified, "AddSynchronizedDevice RPC call succeeded!"); } else { - printf("RPC call failed with status: %d\n", status.code()); + ChipLogProgress(NotSpecified, "AddSynchronizedDevice RPC call failed with status: %d\n", status.code()); } } @@ -139,27 +60,30 @@ void AddDeviceResponse(const pw_protobuf_Empty & response, pw::Status status) CHIP_ERROR InitRpcClient(uint16_t rpcServerPort) { - if (rpcSocketStream.Connect(rpcServerAddress, rpcServerPort) != PW_STATUS_OK) - { - return CHIP_ERROR_NOT_CONNECTED; - } - - // Start a thread to process incoming packets - std::thread packet_processor(ProcessPackets); - packet_processor.detach(); - - return CHIP_NO_ERROR; + rpc::client::SetRpcServerPort(rpcServerPort); + return rpc::client::StartPacketProcessing(); } CHIP_ERROR AddSynchronizedDevice(chip::NodeId nodeId) { ChipLogProgress(NotSpecified, "AddSynchronizedDevice"); - FabricBridgeClient fabric_bridge_client(client, kDefaultChannelId); + if (addSynchronizedDeviceCall.active()) + { + ChipLogError(NotSpecified, "OpenCommissioningWindow is in progress\n"); + return CHIP_ERROR_BUSY; + } + chip_rpc_SynchronizedDevice device; device.node_id = nodeId; - // The RPC will remain active as long as `call` is alive. - auto call = fabric_bridge_client.AddSynchronizedDevice(device, AddDeviceResponse); - return WaitForResponse(call); + // The RPC will remain active as long as `addSynchronizedDeviceCall` is alive. + addSynchronizedDeviceCall = fabricBridgeClient.AddSynchronizedDevice(device, OnAddDeviceResponseCompleted); + + if (!addSynchronizedDeviceCall.active()) + { + return CHIP_ERROR_INTERNAL; + } + + return CHIP_NO_ERROR; } diff --git a/examples/fabric-admin/rpc/RpcClient.h b/examples/fabric-admin/rpc/RpcClient.h index 46c1e9497c53aa..14d03fc6b6655b 100644 --- a/examples/fabric-admin/rpc/RpcClient.h +++ b/examples/fabric-admin/rpc/RpcClient.h @@ -22,6 +22,25 @@ constexpr uint16_t kFabricBridgeServerPort = 33002; +/** + * @brief Initializes the RPC client with the specified server port. + * + * This function sets the RPC server port and starts packet processing for the RPC client. + * + * @param rpcServerPort The port number on which the RPC server is running. + * @return CHIP_NO_ERROR on successful initialization, or an appropriate CHIP_ERROR on failure. + */ CHIP_ERROR InitRpcClient(uint16_t rpcServerPort); +/** + * @brief Adds a synchronized device to the RPC client. + * + * This function attempts to add a device identified by its `nodeId` to the synchronized device list. + * It logs the progress and checks if an `OpenCommissioningWindow` operation is already in progress. + * If an operation is in progress, it returns `CHIP_ERROR_BUSY`. + * + * @param nodeId The Node ID of the device to be added. + * @return CHIP_NO_ERROR on success, `CHIP_ERROR_BUSY` if an operation is already in progress, + * or `CHIP_ERROR_INTERNAL` if there is an internal error while activating the RPC call. + */ CHIP_ERROR AddSynchronizedDevice(chip::NodeId nodeId); diff --git a/examples/fabric-admin/rpc/RpcServer.cpp b/examples/fabric-admin/rpc/RpcServer.cpp index 1fb264bd65c53a..b3cbdcea05409a 100644 --- a/examples/fabric-admin/rpc/RpcServer.cpp +++ b/examples/fabric-admin/rpc/RpcServer.cpp @@ -36,7 +36,7 @@ class FabricAdmin final : public chip::rpc::FabricAdmin pw::Status OpenCommissioningWindow(const chip_rpc_DeviceInfo & request, chip_rpc_OperationStatus & response) override { chip::NodeId nodeId = request.node_id; - printf("Received OpenCommissioningWindow request: 0x%lx\n", nodeId); + ChipLogProgress(NotSpecified, "Received OpenCommissioningWindow request: 0x%lx", nodeId); response.success = false; return pw::OkStatus(); diff --git a/examples/fabric-bridge-app/linux/BUILD.gn b/examples/fabric-bridge-app/linux/BUILD.gn index 155f3fb283fd66..3e82f044c047f9 100644 --- a/examples/fabric-bridge-app/linux/BUILD.gn +++ b/examples/fabric-bridge-app/linux/BUILD.gn @@ -34,8 +34,8 @@ executable("fabric-bridge-app") { sources = [ "${chip_root}/examples/fabric-bridge-app/fabric-bridge-common/include/CHIPProjectAppConfig.h", "Device.cpp", - "include/Device.h", "DeviceManager.cpp", + "include/Device.h", "include/DeviceManager.h", "main.cpp", ] @@ -57,6 +57,8 @@ executable("fabric-bridge-app") { ] sources += [ + "${chip_root}/examples/platform/linux/RpcClientProcessor.cpp", + "${chip_root}/examples/platform/linux/RpcClientProcessor.h", "${chip_root}/examples/platform/linux/system_rpc_server.cc", "RpcClient.cpp", "RpcServer.cpp", @@ -81,7 +83,10 @@ executable("fabric-bridge-app") { deps += pw_build_LINK_DEPS - include_dirs += [ "${chip_root}/examples/common" ] + include_dirs += [ + "${chip_root}/examples/common", + "${chip_root}/examples/platform/linux", + ] } output_dir = root_out_dir diff --git a/examples/fabric-bridge-app/linux/RpcClient.cpp b/examples/fabric-bridge-app/linux/RpcClient.cpp index 6422ed0cc7892c..c09a447cff28c9 100644 --- a/examples/fabric-bridge-app/linux/RpcClient.cpp +++ b/examples/fabric-bridge-app/linux/RpcClient.cpp @@ -17,6 +17,7 @@ */ #include "RpcClient.h" +#include "RpcClientProcessor.h" #include #include @@ -30,108 +31,27 @@ #include "pw_rpc/client.h" #include "pw_stream/socket_stream.h" -namespace { - -constexpr size_t kMaxTransmissionUnit = 256; -constexpr uint32_t kRpcTimeoutMs = 1000; -const char * rpcServerAddress = "127.0.0.1"; - -pw::stream::SocketStream rpcSocketStream; - -// Set up the output channel for the pw_rpc client to use. -pw::hdlc::RpcChannelOutput hdlc_channel_output(rpcSocketStream, pw::hdlc::kDefaultRpcAddress, "HDLC channel"); - -// An array of RPC channels (channels) is created, each associated with an HDLC channel output. -// This sets up the communication channels for RPC calls. -pw::rpc::Channel channels[] = { pw::rpc::Channel::Create<1>(&hdlc_channel_output) }; - -// Initialize the RPC client with the channels. -pw::rpc::Client client(channels); +using namespace chip; -// Generated clients are namespaced with their proto library. -using FabricAdminClient = chip::rpc::pw_rpc::nanopb::FabricAdmin::Client; +namespace { -// RPC channel ID on which to make client calls. RPC calls cannot be made on -// channel 0 (Channel::kUnassignedChannelId). +// Constants constexpr uint32_t kDefaultChannelId = 1; -// Function to process incoming packets -void ProcessPackets() -{ - std::array inputBuf; - pw::hdlc::Decoder decoder(inputBuf); +// Fabric Admin Client +rpc::pw_rpc::nanopb::FabricAdmin::Client fabricAdminClient(rpc::client::GetDefaultRpcClient(), kDefaultChannelId); +pw::rpc::NanopbUnaryReceiver<::chip_rpc_OperationStatus> openCommissioningWindowCall; - while (true) - { - std::array data; - auto ret = rpcSocketStream.Read(data); - if (!ret.ok()) - { - if (ret.status() == pw::Status::OutOfRange()) - { - // Handle remote disconnect - rpcSocketStream.Close(); - return; - } - continue; - } - - for (std::byte byte : ret.value()) - { - auto result = decoder.Process(byte); - if (!result.ok()) - { - // Wait for more bytes that form a complete packet - continue; - } - pw::hdlc::Frame & frame = result.value(); - if (frame.address() != pw::hdlc::kDefaultRpcAddress) - { - // Wrong address; ignore the packet - continue; - } - - client.ProcessPacket(frame.data()).IgnoreError(); - } - } -} - -template -CHIP_ERROR WaitForResponse(CallType & call) -{ - if (!call.active()) - { - return CHIP_ERROR_INTERNAL; - } - - // Wait for the response or timeout - uint32_t elapsedTimeMs = 0; - const uint32_t sleepTimeMs = 100; - - while (call.active() && elapsedTimeMs < kRpcTimeoutMs) - { - usleep(sleepTimeMs * 1000); - elapsedTimeMs += sleepTimeMs; - } - - if (elapsedTimeMs >= kRpcTimeoutMs) - { - ChipLogError(NotSpecified, "RPC Response timed out!"); - return CHIP_ERROR_TIMEOUT; - } - - return CHIP_NO_ERROR; -} - -void OperationStatusResponse(const chip_rpc_OperationStatus & response, pw::Status status) +// Callback function to be called when the RPC response is received +void OnOpenCommissioningWindowCompleted(const chip_rpc_OperationStatus & response, pw::Status status) { if (status.ok()) { - ChipLogProgress(NotSpecified, "Received operation status: %d", response.success); + ChipLogProgress(NotSpecified, "OpenCommissioningWindow received operation status: %d", response.success); } else { - ChipLogProgress(NotSpecified, "RPC call failed with status: %d\n", status.code()); + ChipLogProgress(NotSpecified, "OpenCommissioningWindow RPC call failed with status: %d\n", status.code()); } } @@ -139,27 +59,30 @@ void OperationStatusResponse(const chip_rpc_OperationStatus & response, pw::Stat CHIP_ERROR InitRpcClient(uint16_t rpcServerPort) { - if (rpcSocketStream.Connect(rpcServerAddress, rpcServerPort) != PW_STATUS_OK) - { - return CHIP_ERROR_NOT_CONNECTED; - } - - // Start a thread to process incoming packets - std::thread packet_processor(ProcessPackets); - packet_processor.detach(); - - return CHIP_NO_ERROR; + rpc::client::SetRpcServerPort(rpcServerPort); + return rpc::client::StartPacketProcessing(); } -CHIP_ERROR OpenCommissioningWindow(chip::NodeId nodeId) +CHIP_ERROR OpenCommissioningWindow(NodeId nodeId) { ChipLogProgress(NotSpecified, "OpenCommissioningWindow\n"); - FabricAdminClient fabric_admin_client(client, kDefaultChannelId); + if (openCommissioningWindowCall.active()) + { + ChipLogError(NotSpecified, "OpenCommissioningWindow is in progress\n"); + return CHIP_ERROR_BUSY; + } + chip_rpc_DeviceInfo device; device.node_id = nodeId; - // The RPC will remain active as long as `call` is alive. - auto call = fabric_admin_client.OpenCommissioningWindow(device, OperationStatusResponse); - return WaitForResponse(call); + // The RPC will remain active as long as `openCommissioningWindowCall` is alive. + openCommissioningWindowCall = fabricAdminClient.OpenCommissioningWindow(device, OnOpenCommissioningWindowCompleted); + + if (!openCommissioningWindowCall.active()) + { + return CHIP_ERROR_INTERNAL; + } + + return CHIP_NO_ERROR; } diff --git a/examples/fabric-bridge-app/linux/include/RpcClient.h b/examples/fabric-bridge-app/linux/include/RpcClient.h index 8baa8231f63cb4..5a485957c9dbae 100644 --- a/examples/fabric-bridge-app/linux/include/RpcClient.h +++ b/examples/fabric-bridge-app/linux/include/RpcClient.h @@ -22,6 +22,23 @@ constexpr uint16_t kFabricAdminServerPort = 33001; +/** + * Initializes the RPC client by setting the server port and starting packet processing. + * + * @param rpcServerPort The port number of the RPC server. + * @return CHIP_ERROR An error code indicating the success or failure of the initialization process. + * - CHIP_NO_ERROR: Initialization was successful. + * - Other error codes indicating specific failure reasons. + */ CHIP_ERROR InitRpcClient(uint16_t rpcServerPort); +/** + * Opens a commissioning window for a specified node. + * + * @param nodeId The identifier of the node for which the commissioning window should be opened. + * @return CHIP_ERROR An error code indicating the success or failure of the operation. + * - CHIP_NO_ERROR: The commissioning window was successfully opened. + * - CHIP_ERROR_BUSY: Another commissioning window is currently in progress. + * - CHIP_ERROR_INTERNAL: An internal error occurred. + */ CHIP_ERROR OpenCommissioningWindow(chip::NodeId nodeId); diff --git a/examples/fabric-bridge-app/linux/main.cpp b/examples/fabric-bridge-app/linux/main.cpp index 3c27d6a301e9c6..47670561430c90 100644 --- a/examples/fabric-bridge-app/linux/main.cpp +++ b/examples/fabric-bridge-app/linux/main.cpp @@ -25,7 +25,7 @@ #include #include -#if defined(PW_RPC_FABRIC_BRIDGE_SERVICE) +#if defined(PW_RPC_FABRIC_BRIDGE_SERVICE) && PW_RPC_FABRIC_BRIDGE_SERVICE #include "RpcClient.h" #include "RpcServer.h" #endif @@ -64,15 +64,16 @@ void BridgePollingThread() ChipLogProgress(NotSpecified, "Exiting....."); exit(0); } -#if defined(PW_RPC_FABRIC_BRIDGE_SERVICE) +#if defined(PW_RPC_FABRIC_BRIDGE_SERVICE) && PW_RPC_FABRIC_BRIDGE_SERVICE else if (ch == 'o') { - if (OpenCommissioningWindow(0x1234) != CHIP_NO_ERROR) + CHIP_ERROR err = OpenCommissioningWindow(0x1234); + if (err != CHIP_NO_ERROR) { - ChipLogError(NotSpecified, "Failed to call OpenCommissioningWindow RPC"); + ChipLogError(NotSpecified, "Failed to call OpenCommissioningWindow RPC: %" CHIP_ERROR_FORMAT, err.Format()); } } -#endif +#endif // defined(PW_RPC_FABRIC_BRIDGE_SERVICE) && PW_RPC_FABRIC_BRIDGE_SERVICE continue; } @@ -81,7 +82,7 @@ void BridgePollingThread() } } -#if defined(PW_RPC_FABRIC_BRIDGE_SERVICE) +#if defined(PW_RPC_FABRIC_BRIDGE_SERVICE) && PW_RPC_FABRIC_BRIDGE_SERVICE void AttemptRpcClientConnect(System::Layer * systemLayer, void * appState) { if (InitRpcClient(kFabricAdminServerPort) == CHIP_NO_ERROR) @@ -94,7 +95,7 @@ void AttemptRpcClientConnect(System::Layer * systemLayer, void * appState) systemLayer->StartTimer(System::Clock::Seconds16(kRetryIntervalS), AttemptRpcClientConnect, nullptr); } } -#endif +#endif // defined(PW_RPC_FABRIC_BRIDGE_SERVICE) && PW_RPC_FABRIC_BRIDGE_SERVICE DeviceManager gDeviceManager; @@ -102,9 +103,8 @@ DeviceManager gDeviceManager; void ApplicationInit() { -#if defined(PW_RPC_FABRIC_BRIDGE_SERVICE) +#if defined(PW_RPC_FABRIC_BRIDGE_SERVICE) && PW_RPC_FABRIC_BRIDGE_SERVICE InitRpcServer(kFabricBridgeServerPort); - AttemptRpcClientConnect(&DeviceLayer::SystemLayer(), nullptr); #endif diff --git a/examples/platform/linux/RpcClientProcessor.cpp b/examples/platform/linux/RpcClientProcessor.cpp new file mode 100644 index 00000000000000..a2cbe5694f531d --- /dev/null +++ b/examples/platform/linux/RpcClientProcessor.cpp @@ -0,0 +1,124 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "RpcClientProcessor.h" + +#include +#include + +#include "pw_hdlc/decoder.h" +#include "pw_hdlc/default_addresses.h" +#include "pw_hdlc/rpc_channel.h" +#include "pw_stream/socket_stream.h" + +namespace chip { +namespace rpc { +namespace client { +namespace { + +// Constants +constexpr size_t kMaxTransmissionUnit = 256; +constexpr uint32_t kDefaultChannelId = 1; +const char * kDefaultRpcServerAddress = "127.0.0.1"; + +// RPC Stream and Channel Setup +pw::stream::SocketStream rpcSocketStream; +pw::hdlc::RpcChannelOutput hdlcChannelOutput(rpcSocketStream, pw::hdlc::kDefaultRpcAddress, "HDLC channel"); +pw::rpc::Channel channels[] = { pw::rpc::Channel::Create<1>(&hdlcChannelOutput) }; +pw::rpc::Client rpcClient(channels); + +// RPC Stream and Channel Setup +uint16_t rpcServerPort = 0; +const char * rpcServerAddress = kDefaultRpcServerAddress; + +// Function to process incoming packets +void ProcessPackets() +{ + std::array inputBuf; + pw::hdlc::Decoder decoder(inputBuf); + + while (true) + { + std::array data; + auto ret = rpcSocketStream.Read(data); + if (!ret.ok()) + { + if (ret.status() == pw::Status::OutOfRange()) + { + // Handle remote disconnect + rpcSocketStream.Close(); + return; + } + continue; + } + + for (std::byte byte : ret.value()) + { + auto result = decoder.Process(byte); + if (!result.ok()) + { + // Wait for more bytes that form a complete packet + continue; + } + pw::hdlc::Frame & frame = result.value(); + if (frame.address() != pw::hdlc::kDefaultRpcAddress) + { + // Wrong address; ignore the packet + continue; + } + + rpcClient.ProcessPacket(frame.data()).IgnoreError(); + } + } +} + +} // namespace + +void SetRpcServerAddress(const char * address) +{ + rpcServerAddress = address; +} + +void SetRpcServerPort(uint16_t port) +{ + rpcServerPort = port; +} + +pw::rpc::Client & GetDefaultRpcClient() +{ + return rpcClient; +} + +CHIP_ERROR StartPacketProcessing() +{ + if (rpcSocketStream.Connect(rpcServerAddress, rpcServerPort) != PW_STATUS_OK) + { + // Handle connection error + return CHIP_ERROR_NOT_CONNECTED; + } + + // Start a thread to process incoming packets + std::thread packet_processor(ProcessPackets); + packet_processor.detach(); + + return CHIP_NO_ERROR; +} + +} // namespace client +} // namespace rpc +} // namespace chip diff --git a/examples/platform/linux/RpcClientProcessor.h b/examples/platform/linux/RpcClientProcessor.h new file mode 100644 index 00000000000000..f2305df7aa046c --- /dev/null +++ b/examples/platform/linux/RpcClientProcessor.h @@ -0,0 +1,36 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "pw_rpc/client.h" +#include +#include + +namespace chip { +namespace rpc { +namespace client { + +void SetRpcServerAddress(const char * address); +void SetRpcServerPort(uint16_t port); +pw::rpc::Client & GetDefaultRpcClient(); +CHIP_ERROR StartPacketProcessing(); + +} // namespace client +} // namespace rpc +} // namespace chip From d08f0ca2d1bcfaf1005fd8a69d4058a6701f7dbb Mon Sep 17 00:00:00 2001 From: Yufeng Wang Date: Mon, 3 Jun 2024 11:31:41 -0700 Subject: [PATCH 5/5] Update API comments --- examples/common/pigweed/rpc_console/py/chip_rpc/console.py | 2 +- examples/fabric-admin/commands/fabric-sync/Commands.h | 2 +- examples/fabric-admin/rpc/RpcClient.h | 6 ++++-- examples/fabric-bridge-app/linux/include/RpcClient.h | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/examples/common/pigweed/rpc_console/py/chip_rpc/console.py b/examples/common/pigweed/rpc_console/py/chip_rpc/console.py index 7aea568c288b16..50f0b030f51725 100644 --- a/examples/common/pigweed/rpc_console/py/chip_rpc/console.py +++ b/examples/common/pigweed/rpc_console/py/chip_rpc/console.py @@ -139,7 +139,7 @@ def show_console(device: str, baudrate: int, device_service_pb2, echo_pb2, fabric_admin_service_pb2, - fabric_bridge_service_pb2, + fabric_bridge_service_pb2, lighting_service_pb2, locking_service_pb2, ot_cli_service_pb2, diff --git a/examples/fabric-admin/commands/fabric-sync/Commands.h b/examples/fabric-admin/commands/fabric-sync/Commands.h index 7c15416c560e60..f2be577065b617 100644 --- a/examples/fabric-admin/commands/fabric-sync/Commands.h +++ b/examples/fabric-admin/commands/fabric-sync/Commands.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2024 Project CHIP Authors * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/examples/fabric-admin/rpc/RpcClient.h b/examples/fabric-admin/rpc/RpcClient.h index 14d03fc6b6655b..efe3c24acc3b23 100644 --- a/examples/fabric-admin/rpc/RpcClient.h +++ b/examples/fabric-admin/rpc/RpcClient.h @@ -40,7 +40,9 @@ CHIP_ERROR InitRpcClient(uint16_t rpcServerPort); * If an operation is in progress, it returns `CHIP_ERROR_BUSY`. * * @param nodeId The Node ID of the device to be added. - * @return CHIP_NO_ERROR on success, `CHIP_ERROR_BUSY` if an operation is already in progress, - * or `CHIP_ERROR_INTERNAL` if there is an internal error while activating the RPC call. + * @return CHIP_ERROR An error code indicating the success or failure of the operation. + * - CHIP_NO_ERROR: The RPC command was successfully sent. + * - CHIP_ERROR_BUSY: Another operation is currently in progress. + * - CHIP_ERROR_INTERNAL: An internal error occurred while activating the RPC call. */ CHIP_ERROR AddSynchronizedDevice(chip::NodeId nodeId); diff --git a/examples/fabric-bridge-app/linux/include/RpcClient.h b/examples/fabric-bridge-app/linux/include/RpcClient.h index 5a485957c9dbae..bd424e9d275910 100644 --- a/examples/fabric-bridge-app/linux/include/RpcClient.h +++ b/examples/fabric-bridge-app/linux/include/RpcClient.h @@ -37,7 +37,7 @@ CHIP_ERROR InitRpcClient(uint16_t rpcServerPort); * * @param nodeId The identifier of the node for which the commissioning window should be opened. * @return CHIP_ERROR An error code indicating the success or failure of the operation. - * - CHIP_NO_ERROR: The commissioning window was successfully opened. + * - CHIP_NO_ERROR: The RPC command was successfully sent. * - CHIP_ERROR_BUSY: Another commissioning window is currently in progress. * - CHIP_ERROR_INTERNAL: An internal error occurred. */