Skip to content

Commit

Permalink
[bindings] Use TLV format for saving in storage
Browse files Browse the repository at this point in the history
  • Loading branch information
gjc13 committed Feb 25, 2022
1 parent 7dcdc90 commit a90cd1e
Show file tree
Hide file tree
Showing 14 changed files with 459 additions and 240 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -105,15 +105,20 @@ static void BoundDeviceChangedHandler(const EmberBindingTableEntry & binding, ch

static void InitBindingHandlerInternal(intptr_t arg)
{
chip::BindingManager::GetInstance().SetAppServer(&chip::Server::GetInstance());
auto & server = chip::Server::GetInstance();
chip::BindingManager::GetInstance().Init(
{ &server.GetFabricTable(), server.GetCASESessionManager(), &server.GetPersistentStorage() });
chip::BindingManager::GetInstance().RegisterBoundDeviceChangedHandler(BoundDeviceChangedHandler);
#if defined(ENABLE_CHIP_SHELL)
RegisterSwitchCommands();
#endif
}

CHIP_ERROR InitBindingHandlers()
{
// The initialization of binding manager will try establishing connection with unicast peers
// so it requires the Server instance to be correctly initialized. Post the init function to
// the event queue so that everything is ready when initialization is conducted.
chip::DeviceLayer::PlatformMgr().ScheduleWork(InitBindingHandlerInternal);
#if defined(ENABLE_CHIP_SHELL)
RegisterSwitchCommands();
#endif
return CHIP_NO_ERROR;
}
13 changes: 9 additions & 4 deletions examples/light-switch-app/efr32/src/binding-handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,10 @@ static void RegisterSwitchCommands()

void InitBindingHandlerInternal(intptr_t arg)
{
chip::BindingManager::GetInstance().SetAppServer(&chip::Server::GetInstance());
auto & server = chip::Server::GetInstance();
chip::BindingManager::GetInstance().Init(
{ &server.GetFabricTable(), server.GetCASESessionManager(), &server.GetPersistentStorage() });
chip::BindingManager::GetInstance().RegisterBoundDeviceChangedHandler(BoundDeviceChangedHandler);
#if defined(ENABLE_CHIP_SHELL)
RegisterSwitchCommands();
#endif
}

} // namespace
Expand Down Expand Up @@ -180,6 +179,12 @@ void SwitchOnOffOff(intptr_t context)

CHIP_ERROR InitBindingHandler()
{
// The initialization of binding manager will try establishing connection with unicast peers
// so it requires the Server instance to be correctly initialized. Post the init function to
// the event queue so that everything is ready when initialization is conducted.
chip::DeviceLayer::PlatformMgr().ScheduleWork(InitBindingHandlerInternal);
#if defined(ENABLE_CHIP_SHELL)
RegisterSwitchCommands();
#endif
return CHIP_NO_ERROR;
}
1 change: 0 additions & 1 deletion src/app/chip_data_model.gni
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,6 @@ template("chip_data_model") {
} else if (cluster == "bindings") {
sources += [
"${_app_root}/clusters/${cluster}/${cluster}.cpp",
"${_app_root}/clusters/${cluster}/${cluster}.h",
"${_app_root}/clusters/${cluster}/BindingManager.cpp",
"${_app_root}/clusters/${cluster}/BindingManager.h",
"${_app_root}/clusters/${cluster}/PendingNotificationMap.cpp",
Expand Down
106 changes: 42 additions & 64 deletions src/app/clusters/bindings/BindingManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
*/

#include <app/clusters/bindings/BindingManager.h>
#include <app/clusters/bindings/bindings.h>
#include <app/util/binding-table.h>
#include <credentials/FabricTable.h>
#include <lib/support/CHIPMem.h>
Expand All @@ -33,34 +32,14 @@ class BindingFabricTableDelegate : public chip::FabricTableDelegate
{
if (iter->fabricIndex == fabricIndex)
{
iter = bindingTable.RemoveAt(iter);
bindingTable.RemoveAt(iter);
}
else
{
++iter;
}
}
chip::BindingManager::GetInstance().FabricRemoved(compressedFabricId, fabricIndex);

EmberBindingTableEntry * table = static_cast<EmberBindingTableEntry *>(
chip::Platform::MemoryAlloc(bindingTable.Size() * sizeof(EmberBindingTableEntry)));
uint8_t idx = 0;
if (table == nullptr)
{
return;
}
for (const EmberBindingTableEntry & entry : chip::BindingTable::GetInstance())
{
table[idx++] = entry;
}
CHIP_ERROR error = chip::Server::GetInstance().GetPersistentStorage().SyncSetKeyValue(
chip::kBindingStoargeKey, table, static_cast<uint16_t>(bindingTable.Size() * sizeof(EmberBindingTableEntry)));
// Error recovery is not possible here, the fabricIndex will be filtered upon next reboot.
if (error != CHIP_NO_ERROR)
{
ChipLogError(AppServer, "Failed to save binding table after fabric removed %" CHIP_ERROR_FORMAT, error.Format());
}
chip::Platform::MemoryFree(table);
}

// Intentionally left blank
Expand All @@ -72,35 +51,13 @@ class BindingFabricTableDelegate : public chip::FabricTableDelegate

BindingFabricTableDelegate gFabricTableDelegate;

void LoadBindingTableFromStorage(chip::Server * appServer)
{
EmberBindingTableEntry * table = static_cast<EmberBindingTableEntry *>(
chip::Platform::MemoryAlloc(EMBER_BINDING_TABLE_SIZE * sizeof(EmberBindingTableEntry)));
uint16_t readSize = EMBER_BINDING_TABLE_SIZE * sizeof(EmberBindingTableEntry);

if (appServer->GetPersistentStorage().SyncGetKeyValue(chip::kBindingStoargeKey, table, readSize) == CHIP_NO_ERROR &&
readSize % sizeof(EmberBindingTableEntry) == 0)
{
size_t numEntries = readSize / sizeof(EmberBindingTableEntry);
for (size_t i = 0; i < numEntries; i++)
{
// In case the binding table storage failed when fabric removed
if (appServer->GetFabricTable().FindFabricWithIndex(table[i].fabricIndex) != nullptr)
{
chip::AddBindingEntry(table[i]);
}
}
}
chip::Platform::MemoryFree(table);
}

} // namespace

namespace {

chip::PeerId PeerIdForNode(chip::FabricTable & fabricTable, chip::FabricIndex fabric, chip::NodeId node)
chip::PeerId PeerIdForNode(chip::FabricTable * fabricTable, chip::FabricIndex fabric, chip::NodeId node)
{
chip::FabricInfo * fabricInfo = fabricTable.FindFabricWithIndex(fabric);
chip::FabricInfo * fabricInfo = fabricTable->FindFabricWithIndex(fabric);
if (fabricInfo == nullptr)
{
return chip::PeerId();
Expand All @@ -125,21 +82,42 @@ CHIP_ERROR BindingManager::UnicastBindingRemoved(uint8_t bindingEntryId)
return CHIP_NO_ERROR;
}

void BindingManager::SetAppServer(Server * appServer)
CHIP_ERROR BindingManager::Init(const BindingManagerInitParams & params)
{
mAppServer = appServer;
mAppServer->GetFabricTable().AddFabricDelegate(&gFabricTableDelegate);
LoadBindingTableFromStorage(appServer);
VerifyOrReturnError(params.mCASESessionManager != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(params.mFabricTable != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(params.mStorage != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
mInitParams = params;
params.mFabricTable->AddFabricDelegate(&gFabricTableDelegate);
BindingTable::GetInstance().SetPersistentStorage(params.mStorage);
CHIP_ERROR error = BindingTable::GetInstance().LoadFromStorage();
if (error != CHIP_NO_ERROR)
{
// This can happen during first boot of the device.
ChipLogProgress(AppServer, "Cannot load binding table: %" CHIP_ERROR_FORMAT, error.Format());
}
else
{
for (const EmberBindingTableEntry & entry : BindingTable::GetInstance())
{
if (entry.type == EMBER_UNICAST_BINDING)
{
// The CASE connection can also fail if the unicast peer is offline.
// There is recovery mechanism to retry connection on-demand so ignore error.
(void) UnicastBindingCreated(entry.fabricIndex, entry.nodeId);
}
}
}
return CHIP_NO_ERROR;
}

CHIP_ERROR BindingManager::EstablishConnection(FabricIndex fabric, NodeId node)
{
VerifyOrReturnError(mAppServer != nullptr, CHIP_ERROR_INCORRECT_STATE);

PeerId peer = PeerIdForNode(mAppServer->GetFabricTable(), fabric, node);
VerifyOrReturnError(mInitParams.mCASESessionManager != nullptr, CHIP_ERROR_INCORRECT_STATE);
PeerId peer = PeerIdForNode(mInitParams.mFabricTable, fabric, node);
VerifyOrReturnError(peer.GetNodeId() != kUndefinedNodeId, CHIP_ERROR_NOT_FOUND);
CHIP_ERROR error =
mAppServer->GetCASESessionManager()->FindOrEstablishSession(peer, &mOnConnectedCallback, &mOnConnectionFailureCallback);
mInitParams.mCASESessionManager->FindOrEstablishSession(peer, &mOnConnectedCallback, &mOnConnectionFailureCallback);
if (error == CHIP_ERROR_NO_MEMORY)
{
// Release the least recently used entry
Expand All @@ -150,11 +128,11 @@ CHIP_ERROR BindingManager::EstablishConnection(FabricIndex fabric, NodeId node)
if (mPendingNotificationMap.FindLRUConnectPeer(&fabricToRemove, &nodeToRemove) == CHIP_NO_ERROR)
{
mPendingNotificationMap.RemoveAllEntriesForNode(fabricToRemove, nodeToRemove);
PeerId lruPeer = PeerIdForNode(mAppServer->GetFabricTable(), fabricToRemove, nodeToRemove);
mAppServer->GetCASESessionManager()->ReleaseSession(lruPeer);
PeerId lruPeer = PeerIdForNode(mInitParams.mFabricTable, fabricToRemove, nodeToRemove);
mInitParams.mCASESessionManager->ReleaseSession(lruPeer);
// Now retry
error = mAppServer->GetCASESessionManager()->FindOrEstablishSession(peer, &mOnConnectedCallback,
&mOnConnectionFailureCallback);
error =
mInitParams.mCASESessionManager->FindOrEstablishSession(peer, &mOnConnectedCallback, &mOnConnectionFailureCallback);
}
}
return error;
Expand All @@ -177,7 +155,7 @@ void BindingManager::HandleDeviceConnected(OperationalDeviceProxy * device)
{
EmberBindingTableEntry entry = BindingTable::GetInstance().GetAt(pendingNotification.mBindingEntryId);

PeerId peer = PeerIdForNode(mAppServer->GetFabricTable(), entry.fabricIndex, entry.nodeId);
PeerId peer = PeerIdForNode(mInitParams.mFabricTable, entry.fabricIndex, entry.nodeId);
if (device->GetPeerId() == peer)
{
fabricToRemove = entry.fabricIndex;
Expand All @@ -198,29 +176,29 @@ void BindingManager::HandleDeviceConnectionFailure(PeerId peerId, CHIP_ERROR err
{
// Simply release the entry, the connection will be re-established as needed.
ChipLogError(AppServer, "Failed to establish connection to node 0x" ChipLogFormatX64, ChipLogValueX64(peerId.GetNodeId()));
mAppServer->GetCASESessionManager()->ReleaseSession(peerId);
mInitParams.mCASESessionManager->ReleaseSession(peerId);
}

void BindingManager::FabricRemoved(CompressedFabricId compressedFabricId, FabricIndex fabricIndex)
{
mPendingNotificationMap.RemoveAllEntriesForFabric(fabricIndex);
mAppServer->GetCASESessionManager()->ReleaseSessionForFabric(compressedFabricId);
mInitParams.mCASESessionManager->ReleaseSessionForFabric(compressedFabricId);
}

CHIP_ERROR BindingManager::NotifyBoundClusterChanged(EndpointId endpoint, ClusterId cluster, void * context)
{
VerifyOrReturnError(mAppServer != nullptr, CHIP_ERROR_INCORRECT_STATE);
VerifyOrReturnError(mInitParams.mFabricTable != nullptr, CHIP_ERROR_INCORRECT_STATE);

for (auto iter = BindingTable::GetInstance().begin(); iter != BindingTable::GetInstance().end(); ++iter)
{
if (iter->local == endpoint && (!iter->clusterId.HasValue() || iter->clusterId.Value() == cluster))
{
if (iter->type == EMBER_UNICAST_BINDING)
{
FabricInfo * fabricInfo = mAppServer->GetFabricTable().FindFabricWithIndex(iter->fabricIndex);
FabricInfo * fabricInfo = mInitParams.mFabricTable->FindFabricWithIndex(iter->fabricIndex);
VerifyOrReturnError(fabricInfo != nullptr, CHIP_ERROR_NOT_FOUND);
PeerId peer = fabricInfo->GetPeerIdForNode(iter->nodeId);
OperationalDeviceProxy * peerDevice = mAppServer->GetCASESessionManager()->FindExistingSession(peer);
OperationalDeviceProxy * peerDevice = mInitParams.mCASESessionManager->FindExistingSession(peer);
if (peerDevice != nullptr && peerDevice->IsConnected() && mBoundDeviceChangedHandler)
{
// We already have an active connection
Expand Down
13 changes: 11 additions & 2 deletions src/app/clusters/bindings/BindingManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#include <app/clusters/bindings/PendingNotificationMap.h>
#include <app/server/Server.h>
#include <app/util/binding-table.h>
#include <credentials/FabricTable.h>
#include <lib/core/CHIPPersistentStorageDelegate.h>

namespace chip {

Expand All @@ -38,6 +40,13 @@ namespace chip {
*/
using BoundDeviceChangedHandler = void (*)(const EmberBindingTableEntry & binding, DeviceProxy * peer_device, void * context);

struct BindingManagerInitParams
{
FabricTable * mFabricTable = nullptr;
CASESessionManager * mCASESessionManager = nullptr;
PersistentStorageDelegate * mStorage = nullptr;
};

/**
*
* The BindingManager class manages the connections for unicast bindings and notifies the application
Expand All @@ -61,7 +70,7 @@ class BindingManager

void RegisterBoundDeviceChangedHandler(BoundDeviceChangedHandler handler) { mBoundDeviceChangedHandler = handler; }

void SetAppServer(Server * appServer);
CHIP_ERROR Init(const BindingManagerInitParams & params);

/*
* Notifies the BindingManager that a new unicast binding is created.
Expand Down Expand Up @@ -108,7 +117,7 @@ class BindingManager

PendingNotificationMap mPendingNotificationMap;
BoundDeviceChangedHandler mBoundDeviceChangedHandler;
Server * mAppServer = nullptr;
BindingManagerInitParams mInitParams;

Callback::Callback<OnDeviceConnected> mOnConnectedCallback;
Callback::Callback<OnDeviceConnectionFailure> mOnConnectionFailureCallback;
Expand Down
Loading

0 comments on commit a90cd1e

Please sign in to comment.