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

Marshal the data from BasicInformationCluster to FabricBridge #34854

Merged
merged 43 commits into from
Aug 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
48a0363
Add extra attributes to the bridged device basic info structures, rem…
andy31415 Aug 6, 2024
c37cd56
Make use of AAI for BridgedDeviceBasicInformation cluster
andy31415 Aug 7, 2024
530691d
Restyled by gn
restyled-commits Aug 7, 2024
a7240c8
Fix sizes for software version
andy31415 Aug 7, 2024
eb95854
Update the synchronized device proto to have more data in it
andy31415 Aug 7, 2024
1356b1f
Switch to unique ptr in the registry, making sure memory management w…
andy31415 Aug 7, 2024
3d06305
Use more std::optional
andy31415 Aug 7, 2024
ece219b
Bump revision to 4
andy31415 Aug 7, 2024
651f092
Merge branch 'fabric_admin_info' into fabric_admin_add_rpc
andy31415 Aug 7, 2024
9f20d0f
Forward attributes from the create call into the bridged device
andy31415 Aug 7, 2024
5a1cb33
Make attribute mapping actually work
andy31415 Aug 7, 2024
4475143
Restyle
andy31415 Aug 7, 2024
152d225
Ensure unique IDs are generated
andy31415 Aug 7, 2024
c6877c8
Restyle
andy31415 Aug 7, 2024
28c8bb3
Increase size to 33 to allow for a null terminator
andy31415 Aug 7, 2024
23d61eb
make sure that the rpc structures are initialized
andy31415 Aug 7, 2024
6628f5c
Restyle
andy31415 Aug 7, 2024
33f2517
Add some fake data to test moving the data around
andy31415 Aug 7, 2024
68b58ef
Merge branch 'master' into fabric_admin_info
andy31415 Aug 7, 2024
d72e4cf
Merge branch 'fabric_admin_info' into fabric_admin_add_rpc
andy31415 Aug 7, 2024
fbb42ac
Remove unused members that were likely just copied over
andy31415 Aug 7, 2024
4abba22
make the attributes optional
andy31415 Aug 7, 2024
fab3b06
Prepare some device sync data - reading the basic info cluster
andy31415 Aug 7, 2024
f2d353e
Prepare some device sync data - reading the basic info cluster
andy31415 Aug 7, 2024
0d0ddae
Full implementation of forwarding data
andy31415 Aug 7, 2024
a4bc1b8
Restyle
andy31415 Aug 7, 2024
ff84027
Add missing file
andy31415 Aug 7, 2024
c60afe6
Restyle
andy31415 Aug 7, 2024
348030a
reset readclient, since this may reset the exchange manager ... seems…
andy31415 Aug 7, 2024
471941c
Add the verifyOrDie
andy31415 Aug 7, 2024
bcb6a11
Merge branch 'master' into fabric_admin_info
andy31415 Aug 7, 2024
b1d878d
Merge branch 'fabric_admin_info' into fabric_admin_add_rpc
andy31415 Aug 7, 2024
f9465eb
Restyled by clang-format
restyled-commits Aug 7, 2024
b0c3ffd
Merge branch 'fabric_admin_add_rpc' into fabric_admin_populate
andy31415 Aug 7, 2024
c256b3b
Fix string size for HW and software versions
andy31415 Aug 7, 2024
e965259
Merge branch 'master' into fabric_admin_add_rpc
andy31415 Aug 7, 2024
61d43f1
Merge branch 'fabric_admin_add_rpc' into fabric_admin_populate
andy31415 Aug 7, 2024
f2841eb
Remove some of the spammier logs
andy31415 Aug 7, 2024
dc75ac5
Enfore RPC enabling for synchronized device addition
andy31415 Aug 7, 2024
2501d42
Add device sync in progress tracking
andreilitvin Aug 8, 2024
9ff1c0d
Undo submodule update
andreilitvin Aug 8, 2024
46b75f2
Fix up device sync progress tracking to better handle errors
andreilitvin Aug 8, 2024
4ae53d0
Restyled by clang-format
restyled-commits Aug 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/common/pigweed/protos/fabric_bridge_service.proto
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ message SynchronizedDevice {
optional string hardware_version_string = 9;
optional uint32 software_version = 10;
optional string software_version_string = 11;
optional bool is_icd = 12;
}

service FabricBridge {
Expand Down
2 changes: 2 additions & 0 deletions examples/fabric-admin/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ static_library("fabric-admin-utils") {
"commands/common/RemoteDataModelLogger.cpp",
"commands/common/RemoteDataModelLogger.h",
"commands/fabric-sync/FabricSyncCommand.cpp",
"commands/pairing/DeviceSynchronization.cpp",
"commands/pairing/DeviceSynchronization.h",
"commands/pairing/OpenCommissioningWindowCommand.cpp",
"commands/pairing/OpenCommissioningWindowCommand.h",
"commands/pairing/PairingCommand.cpp",
Expand Down
187 changes: 187 additions & 0 deletions examples/fabric-admin/commands/pairing/DeviceSynchronization.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
/*
* 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 "DeviceSynchronization.h"
#include "rpc/RpcClient.h"

#include <app/InteractionModelEngine.h>
#include <app/server/Server.h>

#include <app-common/zap-generated/ids/Attributes.h>
#include <app-common/zap-generated/ids/Clusters.h>

using namespace ::chip;
using namespace ::chip::app;
using chip::app::ReadClient;

namespace {

void OnDeviceConnectedWrapper(void * context, Messaging::ExchangeManager & exchangeMgr, const SessionHandle & sessionHandle)
{
reinterpret_cast<DeviceSynchronizer *>(context)->OnDeviceConnected(exchangeMgr, sessionHandle);
}

void OnDeviceConnectionFailureWrapper(void * context, const ScopedNodeId & peerId, CHIP_ERROR error)
{
reinterpret_cast<DeviceSynchronizer *>(context)->OnDeviceConnectionFailure(peerId, error);
}

bool SuccessOrLog(CHIP_ERROR err, const char * name)
{
if (err == CHIP_NO_ERROR)
{
return true;
}

ChipLogError(NotSpecified, "Failed to read %s: %" CHIP_ERROR_FORMAT, name, err.Format());

return false;
}

} // namespace

DeviceSynchronizer & DeviceSynchronizer::Instance()
{
static DeviceSynchronizer instance;
return instance;
}

DeviceSynchronizer::DeviceSynchronizer() :
mOnDeviceConnectedCallback(OnDeviceConnectedWrapper, this),
mOnDeviceConnectionFailureCallback(OnDeviceConnectionFailureWrapper, this)
{}

void DeviceSynchronizer::OnAttributeData(const ConcreteDataAttributePath & path, TLV::TLVReader * data, const StatusIB & status)
{
VerifyOrDie(path.mEndpointId == kRootEndpointId);
VerifyOrDie(path.mClusterId == Clusters::BasicInformation::Id);

switch (path.mAttributeId)
{
case Clusters::BasicInformation::Attributes::UniqueID::Id:
mCurrentDeviceData.has_unique_id =
SuccessOrLog(data->GetString(mCurrentDeviceData.unique_id, sizeof(mCurrentDeviceData.unique_id)), "UniqueId");
break;
case Clusters::BasicInformation::Attributes::VendorName::Id:
mCurrentDeviceData.has_vendor_name =
SuccessOrLog(data->GetString(mCurrentDeviceData.vendor_name, sizeof(mCurrentDeviceData.vendor_name)), "VendorName");
break;
case Clusters::BasicInformation::Attributes::VendorID::Id:
mCurrentDeviceData.has_vendor_id = SuccessOrLog(data->Get(mCurrentDeviceData.vendor_id), "VendorID");
break;
case Clusters::BasicInformation::Attributes::ProductName::Id:
mCurrentDeviceData.has_product_name =
SuccessOrLog(data->GetString(mCurrentDeviceData.product_name, sizeof(mCurrentDeviceData.product_name)), "ProductName");
break;
case Clusters::BasicInformation::Attributes::ProductID::Id:
mCurrentDeviceData.has_product_id = SuccessOrLog(data->Get(mCurrentDeviceData.product_id), "ProductID");
break;
case Clusters::BasicInformation::Attributes::NodeLabel::Id:
mCurrentDeviceData.has_node_label =
SuccessOrLog(data->GetString(mCurrentDeviceData.node_label, sizeof(mCurrentDeviceData.node_label)), "NodeLabel");
break;
case Clusters::BasicInformation::Attributes::HardwareVersion::Id:
mCurrentDeviceData.has_hardware_version = SuccessOrLog(data->Get(mCurrentDeviceData.hardware_version), "HardwareVersion");
break;
case Clusters::BasicInformation::Attributes::HardwareVersionString::Id:
mCurrentDeviceData.has_hardware_version_string = SuccessOrLog(
data->GetString(mCurrentDeviceData.hardware_version_string, sizeof(mCurrentDeviceData.hardware_version_string)),
"HardwareVersionString");
break;
case Clusters::BasicInformation::Attributes::SoftwareVersion::Id:
mCurrentDeviceData.has_software_version = SuccessOrLog(data->Get(mCurrentDeviceData.software_version), "HardwareVersion");
break;
case Clusters::BasicInformation::Attributes::SoftwareVersionString::Id:
mCurrentDeviceData.has_software_version_string = SuccessOrLog(
data->GetString(mCurrentDeviceData.software_version_string, sizeof(mCurrentDeviceData.software_version_string)),
"SoftwareVersionString");
break;
default:
break;
}
}

void DeviceSynchronizer::OnReportEnd()
{
// Report end is at the end of all attributes (success)
#if defined(PW_RPC_ENABLED)
AddSynchronizedDevice(mCurrentDeviceData);
#else
ChipLogError(NotSpecified, "Cannot synchronize device with fabric bridge: RPC not enabled");
#endif
}

void DeviceSynchronizer::OnDone(chip::app::ReadClient * apReadClient)
{
// Nothing to do: error reported on OnError or report ended called.
mDeviceSyncInProcess = false;
}

void DeviceSynchronizer::OnError(CHIP_ERROR error)
{
ChipLogProgress(NotSpecified, "Error fetching device data: %" CHIP_ERROR_FORMAT, error.Format());
}

void DeviceSynchronizer::OnDeviceConnected(chip::Messaging::ExchangeManager & exchangeMgr,
const chip::SessionHandle & sessionHandle)
{
mClient = std::make_unique<ReadClient>(app::InteractionModelEngine::GetInstance(), &exchangeMgr /* echangeMgr */,
*this /* callback */, ReadClient::InteractionType::Read);
VerifyOrDie(mClient);

AttributePathParams readPaths[1];
readPaths[0] = AttributePathParams(kRootEndpointId, Clusters::BasicInformation::Id);

ReadPrepareParams readParams(sessionHandle);

readParams.mpAttributePathParamsList = readPaths;
readParams.mAttributePathParamsListSize = 1;

CHIP_ERROR err = mClient->SendRequest(readParams);

if (err != CHIP_NO_ERROR)
{
ChipLogError(NotSpecified, "Failed to issue read for BasicInformation data");
mDeviceSyncInProcess = false;
}
}

void DeviceSynchronizer::OnDeviceConnectionFailure(const chip::ScopedNodeId & peerId, CHIP_ERROR error)
{
ChipLogError(NotSpecified, "Device Sync failed to connect to " ChipLogFormatX64, ChipLogValueX64(peerId.GetNodeId()));
mDeviceSyncInProcess = false;
}

void DeviceSynchronizer::StartDeviceSynchronization(chip::Controller::DeviceController & controller, chip::NodeId nodeId,
bool deviceIsIcd)
{
if (mDeviceSyncInProcess)
{
ChipLogError(NotSpecified, "Device Sync NOT POSSIBLE: another sync is in progress");
return;
}

mCurrentDeviceData = chip_rpc_SynchronizedDevice_init_default;
mCurrentDeviceData.node_id = nodeId;
mCurrentDeviceData.has_is_icd = true;
mCurrentDeviceData.is_icd = deviceIsIcd;

mDeviceSyncInProcess = true;

controller.GetConnectedDevice(nodeId, &mOnDeviceConnectedCallback, &mOnDeviceConnectionFailureCallback);
}
70 changes: 70 additions & 0 deletions examples/fabric-admin/commands/pairing/DeviceSynchronization.h
Original file line number Diff line number Diff line change
@@ -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.
*
*/
#pragma once

#include <app/ReadClient.h>
#include <controller/CHIPDeviceController.h>
#include <lib/core/DataModelTypes.h>

#include <memory>

#include "fabric_bridge_service/fabric_bridge_service.pb.h"
#include "fabric_bridge_service/fabric_bridge_service.rpc.pb.h"

/// Ensures that device data is synchronized to the remove fabric bridge.
///
/// Includes a state machine that:
/// - initiates a "read basic information data" command to fetch basic information
/// - upon receiving such information, ensures that synchronized device data is sent
/// to the remote end.
class DeviceSynchronizer : public chip::app::ReadClient::Callback
{
public:
DeviceSynchronizer();

/// Usually called after commissioning is complete, initiates a
/// read of required data from the remote node ID and then will synchronize
/// the device towards the fabric bridge
void StartDeviceSynchronization(chip::Controller::DeviceController & controller, chip::NodeId nodeId, bool deviceIsIcd);

///////////////////////////////////////////////////////////////
// ReadClient::Callback implementation
///////////////////////////////////////////////////////////////
void OnAttributeData(const chip::app::ConcreteDataAttributePath & path, chip::TLV::TLVReader * data,
const chip::app::StatusIB & status) override;
void OnReportEnd() override;
void OnError(CHIP_ERROR error) override;
void OnDone(chip::app::ReadClient * apReadClient) override;

///////////////////////////////////////////////////////////////
// callbacks for CASE session establishment
///////////////////////////////////////////////////////////////
void OnDeviceConnected(chip::Messaging::ExchangeManager & exchangeMgr, const chip::SessionHandle & sessionHandle);
void OnDeviceConnectionFailure(const chip::ScopedNodeId & peerId, CHIP_ERROR error);

static DeviceSynchronizer & Instance();

private:
std::unique_ptr<chip::app::ReadClient> mClient;

chip::Callback::Callback<chip::OnDeviceConnected> mOnDeviceConnectedCallback;
chip::Callback::Callback<chip::OnDeviceConnectionFailure> mOnDeviceConnectionFailureCallback;

bool mDeviceSyncInProcess = false;
chip_rpc_SynchronizedDevice mCurrentDeviceData = chip_rpc_SynchronizedDevice_init_default;
};
8 changes: 4 additions & 4 deletions examples/fabric-admin/commands/pairing/PairingCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@

#include "PairingCommand.h"

#include <app-common/zap-generated/ids/Clusters.h>
#include <commands/common/DeviceScanner.h>
#include <commands/interactive/InteractiveCommands.h>
#include <commands/pairing/DeviceSynchronization.h>
#include <controller/ExampleOperationalCredentialsIssuer.h>
#include <crypto/CHIPCryptoPAL.h>
#include <lib/core/CHIPSafeCasts.h>
Expand Down Expand Up @@ -400,10 +403,7 @@ void PairingCommand::OnCommissioningComplete(NodeId nodeId, CHIP_ERROR err)
{
// print to console
fprintf(stderr, "New device with Node ID: 0x%lx has been successfully added.\n", nodeId);

#if defined(PW_RPC_ENABLED)
AddSynchronizedDevice(nodeId);
#endif
DeviceSynchronizer::Instance().StartDeviceSynchronization(CurrentCommissioner(), mNodeId, mDeviceIsICD);
}
else
{
Expand Down
44 changes: 3 additions & 41 deletions examples/fabric-admin/rpc/RpcClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,9 @@
#include <chrono>
#include <condition_variable>
#include <mutex>
#include <string>
#include <thread>

#include "fabric_bridge_service/fabric_bridge_service.pb.h"
#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"

using namespace chip;

Expand Down Expand Up @@ -113,44 +106,13 @@ CHIP_ERROR InitRpcClient(uint16_t rpcServerPort)
return rpc::client::StartPacketProcessing();
}

CHIP_ERROR AddSynchronizedDevice(chip::NodeId nodeId)
CHIP_ERROR AddSynchronizedDevice(const chip_rpc_SynchronizedDevice & data)
{
ChipLogProgress(NotSpecified, "AddSynchronizedDevice");

chip_rpc_SynchronizedDevice device = chip_rpc_SynchronizedDevice_init_default;
device.node_id = nodeId;

// TODO: fill this with real data. For now we just add things for testing
strcpy(device.vendor_name, "Test Vendor");
device.has_vendor_name = true;

device.vendor_id = 123;
device.has_vendor_id = true;

strcpy(device.product_name, "Test Product");
device.has_product_name = true;

device.product_id = 234;
device.has_product_id = true;

strcpy(device.node_label, "Device Label");
device.has_node_label = true;

device.hardware_version = 11;
device.has_hardware_version = true;

strcpy(device.hardware_version_string, "Hardware");
device.has_hardware_version_string = true;

device.software_version = 22;
device.has_software_version = true;

strcpy(device.software_version_string, "Test 1.4.22");
device.has_software_version_string = true;

// 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.AddSynchronizedDevice(device, OnAddDeviceResponseCompleted);
auto call = fabricBridgeClient.AddSynchronizedDevice(data, OnAddDeviceResponseCompleted);

if (!call.active())
{
Expand Down
5 changes: 3 additions & 2 deletions examples/fabric-admin/rpc/RpcClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

#include <platform/CHIPDeviceLayer.h>

#include "fabric_bridge_service/fabric_bridge_service.rpc.pb.h"

constexpr uint16_t kFabricBridgeServerPort = 33002;

/**
Expand All @@ -39,13 +41,12 @@ CHIP_ERROR InitRpcClient(uint16_t rpcServerPort);
* It logs the progress and checks if an `AddSynchronizedDevice` 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_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 AddSynchronizedDevice(chip::NodeId nodeId);
CHIP_ERROR AddSynchronizedDevice(const chip_rpc_SynchronizedDevice & data);

/**
* @brief Removes a synchronized device from the RPC client.
Expand Down
Loading