Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions examples/jf-admin-app/linux/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@ config("includes") {

executable("jfa-app") {
sources = [
"JFADatastoreSync.cpp",
"JFAManager.cpp",
"include/CHIPProjectAppConfig.h",
"include/JFADatastoreSync.h",
"include/JFAManager.h",
"include/JFARpc.h",
"main.cpp",
Expand Down
232 changes: 232 additions & 0 deletions examples/jf-admin-app/linux/JFADatastoreSync.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
/*
*
* Copyright (c) 2025 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 "JFADatastoreSync.h"

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

#include <controller/CHIPCluster.h>
#include <lib/support/logging/CHIPLogging.h>

#include <controller/CHIPDeviceController.h>
#include <controller/CommissionerDiscoveryController.h>

using namespace chip;
using namespace chip::app;
using namespace chip::app::Clusters;
using namespace chip::Controller;
using namespace chip::app::Clusters::JointFabricDatastore;

extern DeviceCommissioner * GetDeviceCommissioner();

constexpr uint8_t kJFAvailableShift = 0;
constexpr uint8_t kJFAdminShift = 1;
constexpr uint8_t kJFAnchorShift = 2;
constexpr uint8_t kJFDatastoreShift = 3;

static constexpr EndpointId kJFDatastoreClusterEndpointId = 1;

JFADatastoreSync JFADatastoreSync::sJFDS;

template <typename T>
class DevicePairedCommand
{
public:
struct CallbackContext
{
chip::NodeId nodeId;
T objectToWrite;
std::function<void()> onComplete;

CallbackContext(chip::NodeId nId, T object, std::function<void()> onComp) :
nodeId(nId), objectToWrite(object), onComplete(onComp)
{}
};
DevicePairedCommand(
chip::NodeId nodeId, T object, std::function<void()> onComplete = []() {}) :
mOnDeviceConnectedCallback(OnDeviceConnectedFn, this), mOnDeviceConnectionFailureCallback(OnDeviceConnectionFailureFn, this)
{
mContext = std::make_shared<CallbackContext>(nodeId, object, onComplete);
}

static void OnDeviceConnectedFn(void * context, chip::Messaging::ExchangeManager & exchangeMgr,
const chip::SessionHandle & sessionHandle)
{
auto * pairingCommand = static_cast<DevicePairedCommand *>(context);
auto cbContext = pairingCommand->mContext;

if (pairingCommand)
{
ChipLogProgress(DeviceLayer, "OnDeviceConnectedFn - Syncing device with node id: " ChipLogFormatX64,
ChipLogValueX64(cbContext->nodeId));

chip::Controller::ClusterBase cluster(exchangeMgr, sessionHandle, kJFDatastoreClusterEndpointId);

// Static LUT for mapping type T to attribute ID
AttributeId attributeId = 0;

if constexpr (std::is_same_v<T,
app::Clusters::JointFabricDatastore::Structs::DatastoreEndpointGroupIDEntryStruct::Type>)
{
attributeId = Attributes::EndpointGroupIDList::Id;
}
Comment on lines +86 to +90
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sync is being done with a regular Matter device (not another Datastore) and so in the case of a DatastoreEndpointGroupIDEntryStruct, the operation to send is:

IM Type: Command
EndpointId=newGroupEntry.endpointID
ClusterId=0x0004 (groups)
CommandId=0x00 (add group)
Arg0=newGroupEntry.groupID
Arg1=GroupName

else if constexpr (std::is_same_v<T,
app::Clusters::JointFabricDatastore::Structs::DatastoreNodeKeySetEntryStruct::Type>)
{
attributeId = Attributes::NodeKeySetList::Id;
}
Comment on lines +91 to +95
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the case of DatastoreNodeKeySetEntryStruct, the operation to send is:

IM Type: Command
EndpointId=0 (root endpoint)
ClusterId=0x003F (group key management)
CommandId=0x00 (key set write)
Arg0=groupKeySet

else if constexpr (std::is_same_v<
T, app::Clusters::JointFabricDatastore::Structs::DatastoreEndpointBindingEntryStruct::Type>)
{
attributeId = Attributes::EndpointBindingList::Id;
}
Comment on lines +98 to +100
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the case of DatastoreEndpointBindingEntryStruct, the operation to send is:

IM Type: AttributeWrite
EndpointId=0 (root endpoint)
ClusterId=0x001E (bindings cluster)
AttributeId=0x00 (binding)
Arg0=list of all bindings for this node from datastore

else if constexpr (std::is_same_v<T, app::Clusters::JointFabricDatastore::Structs::DatastoreACLEntryStruct::Type>)
{
attributeId = Attributes::NodeACLList::Id;
}
Comment on lines +102 to +104
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the case of DatastoreACLEntryStruct, the operation to send is:

IM Type: AttributeWrite
EndpointId=0 (root endpoint)
ClusterId=0x001F (ACL cluster)
AttributeId=0x00 (ACL)
Arg0=list of all ACLs for this node from datastore

else
{
ChipLogError(Controller, "Unknown type for attribute mapping");
return;
}

CHIP_ERROR err = cluster.WriteAttribute(cbContext->objectToWrite, pairingCommand, Clusters::JointFabricDatastore::Id,
attributeId, OnWriteSuccessResponse, OnWriteFailureResponse, NullOptional);
Comment on lines +111 to +112
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be moved above since some are using WriteAttribute while others will use SendCommand


if (err != CHIP_NO_ERROR)
{
ChipLogProgress(Controller, "Failed in cluster.WriteAttribute: %s", ErrorStr(err));
}
}
}

static void OnDeviceConnectionFailureFn(void * context, const ScopedNodeId & peerId, CHIP_ERROR error)
{
auto * pairingCommand = static_cast<DevicePairedCommand *>(context);
auto cbContext = pairingCommand->mContext;

if (pairingCommand)
{
ChipLogProgress(DeviceLayer, "OnDeviceConnectionFailureFn - Not syncing device with node id: " ChipLogFormatX64,
ChipLogValueX64(cbContext->nodeId));
}
}

/* Callback when command results in success */
static void OnWriteSuccessResponse(void * context)
{
ChipLogProgress(Controller, "OnWriteSuccessResponse - Data written Successfully");

auto * pairingCommand = static_cast<DevicePairedCommand *>(context);
auto cbContext = pairingCommand->mContext;
if (cbContext && cbContext->onComplete)
{
cbContext->onComplete();
}
}

/* Callback when command results in failure */
static void OnWriteFailureResponse(void * context, CHIP_ERROR error)
{
ChipLogProgress(Controller, "OnWriteFailureResponse - Failed to write Data: %s", ErrorStr(error));
}

chip::Callback::Callback<chip::OnDeviceConnected> mOnDeviceConnectedCallback;
chip::Callback::Callback<chip::OnDeviceConnectionFailure> mOnDeviceConnectionFailureCallback;
std::shared_ptr<CallbackContext> mContext;
};

CHIP_ERROR JFADatastoreSync::Init(Server & server)
{
mServer = &server;

return CHIP_NO_ERROR;
}

CHIP_ERROR JFADatastoreSync::SyncNode(
NodeId nodeId,
const app::Clusters::JointFabricDatastore::Structs::DatastoreEndpointGroupIDEntryStruct::Type & endpointGroupIDEntry,
std::function<void()> onComplete)
{
ChipLogProgress(DeviceLayer, "Creating Pairing Command with node id: " ChipLogFormatX64, ChipLogValueX64(nodeId));

std::shared_ptr<DevicePairedCommand<app::Clusters::JointFabricDatastore::Structs::DatastoreEndpointGroupIDEntryStruct::Type>>
pairingCommand = std::make_shared<
DevicePairedCommand<app::Clusters::JointFabricDatastore::Structs::DatastoreEndpointGroupIDEntryStruct::Type>>(
nodeId, endpointGroupIDEntry, onComplete);

GetDeviceCommissioner()->GetConnectedDevice(nodeId, &pairingCommand->mOnDeviceConnectedCallback,
&pairingCommand->mOnDeviceConnectionFailureCallback);

return CHIP_NO_ERROR;
}

CHIP_ERROR JFADatastoreSync::SyncNode(
NodeId nodeId, const app::Clusters::JointFabricDatastore::Structs::DatastoreNodeKeySetEntryStruct::Type & nodeKeySetEntry,
std::function<void()> onComplete)
{
ChipLogProgress(DeviceLayer, "Creating Pairing Command with node id: " ChipLogFormatX64, ChipLogValueX64(nodeId));

std::shared_ptr<DevicePairedCommand<app::Clusters::JointFabricDatastore::Structs::DatastoreNodeKeySetEntryStruct::Type>>
pairingCommand = std::make_shared<
DevicePairedCommand<app::Clusters::JointFabricDatastore::Structs::DatastoreNodeKeySetEntryStruct::Type>>(
nodeId, nodeKeySetEntry, onComplete);

GetDeviceCommissioner()->GetConnectedDevice(nodeId, &pairingCommand->mOnDeviceConnectedCallback,
&pairingCommand->mOnDeviceConnectionFailureCallback);

return CHIP_NO_ERROR;
}

CHIP_ERROR JFADatastoreSync::SyncNode(
NodeId nodeId, const app::Clusters::JointFabricDatastore::Structs::DatastoreEndpointBindingEntryStruct::Type & bindingEntry,
std::function<void()> onComplete)
{
ChipLogProgress(DeviceLayer, "Creating Pairing Command with node id: " ChipLogFormatX64, ChipLogValueX64(nodeId));

std::shared_ptr<DevicePairedCommand<app::Clusters::JointFabricDatastore::Structs::DatastoreEndpointBindingEntryStruct::Type>>
pairingCommand = std::make_shared<
DevicePairedCommand<app::Clusters::JointFabricDatastore::Structs::DatastoreEndpointBindingEntryStruct::Type>>(
nodeId, bindingEntry, onComplete);

GetDeviceCommissioner()->GetConnectedDevice(nodeId, &pairingCommand->mOnDeviceConnectedCallback,
&pairingCommand->mOnDeviceConnectionFailureCallback);

return CHIP_NO_ERROR;
}

CHIP_ERROR
JFADatastoreSync::SyncNode(NodeId nodeId,
const app::Clusters::JointFabricDatastore::Structs::DatastoreACLEntryStruct::Type & aclEntry,
std::function<void()> onComplete)
{
ChipLogProgress(DeviceLayer, "Creating Pairing Command with node id: " ChipLogFormatX64, ChipLogValueX64(nodeId));

std::shared_ptr<DevicePairedCommand<app::Clusters::JointFabricDatastore::Structs::DatastoreACLEntryStruct::Type>>
pairingCommand =
std::make_shared<DevicePairedCommand<app::Clusters::JointFabricDatastore::Structs::DatastoreACLEntryStruct::Type>>(
nodeId, aclEntry, onComplete);

GetDeviceCommissioner()->GetConnectedDevice(nodeId, &pairingCommand->mOnDeviceConnectedCallback,
&pairingCommand->mOnDeviceConnectionFailureCallback);

return CHIP_NO_ERROR;
}
4 changes: 3 additions & 1 deletion examples/jf-admin-app/linux/args.gni
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ matter_enable_tracing_support = true
chip_enable_additional_data_advertising = true
chip_enable_rotating_device_id = true

chip_enable_read_client = false
chip_enable_read_client = true
chip_build_controller = true
chip_support_commissioning_in_controller = true

chip_device_config_enable_joint_fabric = true
7 changes: 6 additions & 1 deletion examples/jf-admin-app/linux/include/CHIPProjectAppConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
// include the CHIPProjectConfig from config/standalone
#include <CHIPProjectConfig.h>

#define CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY 0
#define CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY 1

#define CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT 0

Expand All @@ -45,3 +45,8 @@
#define CHIP_DEVICE_ENABLE_PORT_PARAMS 1

#define CHIP_DEVICE_CONFIG_DEVICE_NAME "JF Admin"

#define CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE 1

// Enable app platform
#define CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED 1
63 changes: 63 additions & 0 deletions examples/jf-admin-app/linux/include/JFADatastoreSync.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
*
* Copyright (c) 2025 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/server/JointFabricDatastore.h>
#include <app/server/Server.h>
#include <lib/core/CHIPError.h>

namespace chip {

class JFADatastoreSync : public app::JointFabricDatastore::Delegate
{
public:
JFADatastoreSync() {}

CHIP_ERROR Init(Server & server);

/* app::JointFabricDatastore::Delegate */
CHIP_ERROR
SyncNode(NodeId nodeId,
const app::Clusters::JointFabricDatastore::Structs::DatastoreEndpointGroupIDEntryStruct::Type & endpointGroupIDEntry,
std::function<void()> onComplete) override;
CHIP_ERROR
SyncNode(NodeId nodeId,
const app::Clusters::JointFabricDatastore::Structs::DatastoreNodeKeySetEntryStruct::Type & nodeKeySetEntry,
std::function<void()> onComplete) override;
CHIP_ERROR
SyncNode(NodeId nodeId,
const app::Clusters::JointFabricDatastore::Structs::DatastoreEndpointBindingEntryStruct::Type & bindingEntry,
std::function<void()> onComplete) override;
CHIP_ERROR SyncNode(NodeId nodeId, const app::Clusters::JointFabricDatastore::Structs::DatastoreACLEntryStruct::Type & aclEntry,
std::function<void()> onComplete) override;

private:
friend JFADatastoreSync & JFADSync(void);

static JFADatastoreSync sJFDS;

Server * mServer = nullptr;
};

inline JFADatastoreSync & JFADSync(void)
{
return JFADatastoreSync::sJFDS;
}

} // namespace chip
3 changes: 3 additions & 0 deletions examples/jf-admin-app/linux/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* limitations under the License.
*/

#include "JFADatastoreSync.h"
#include "JFAManager.h"
#include "rpc/RpcServer.h"
#include <AppMain.h>
Expand Down Expand Up @@ -99,7 +100,9 @@ void ApplicationInit()
}

JFAMgr().Init(Server::GetInstance());
JFADSync().Init(Server::GetInstance());
Server::GetInstance().GetJointFabricAdministrator().SetDelegate(&JFAMgr());
Server::GetInstance().GetJointFabricDatastore().SetDelegate(&JFADSync());

PlatformMgrImpl().AddEventHandler(EventHandler, 0);
}
Expand Down
Loading
Loading