Skip to content

Commit

Permalink
Introduce a way to loop over endpoints that have a given server clust…
Browse files Browse the repository at this point in the history
…er. (#12542)

We have several places that are doing this, all of them in
not-so-great ways (e.g. mapping indices to endpoint ids and then back
to indices, which is O(N^2) in number of endpoints).  Better to have a
utility that does it right.
  • Loading branch information
bzbarsky-apple authored Dec 3, 2021
1 parent 21757de commit 0315b48
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 92 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -170,49 +170,31 @@ CHIP_ERROR GeneralDiagosticsAttrAccess::Read(const ConcreteReadAttributePath & a

class GeneralDiagnosticsDelegate : public DeviceLayer::ConnectivityManagerDelegate, public DeviceLayer::GeneralDiagnosticsDelegate
{
static void ReportAttributeOnAllEndpoints(AttributeId attribute)
{
ForAllEndpointsWithServerCluster(
GeneralDiagnostics::Id,
[](EndpointId endpoint, intptr_t context) -> Loop {
MatterReportingAttributeChangeCallback(endpoint, GeneralDiagnostics::Id, static_cast<AttributeId>(context));
return Loop::Continue;
},
attribute);
}

// Gets called when any network interface on the Node is updated.
void OnNetworkInfoChanged() override
{
ChipLogProgress(Zcl, "GeneralDiagnosticsDelegate: OnNetworkInfoChanged");

for (uint16_t index = 0; index < emberAfEndpointCount(); index++)
{
if (emberAfEndpointIndexIsEnabled(index))
{
EndpointId endpointId = emberAfEndpointFromIndex(index);

if (emberAfContainsServer(endpointId, GeneralDiagnostics::Id))
{
// If General Diagnostics cluster is implemented on this endpoint
MatterReportingAttributeChangeCallback(endpointId, GeneralDiagnostics::Id,
GeneralDiagnostics::Attributes::NetworkInterfaces::Id);
}
}
}
ReportAttributeOnAllEndpoints(GeneralDiagnostics::Attributes::NetworkInterfaces::Id);
}

// Gets called when the device has been rebooted.
void OnDeviceRebooted() override
{
ChipLogProgress(Zcl, "GeneralDiagnosticsDelegate: OnDeviceRebooted");

for (uint16_t index = 0; index < emberAfEndpointCount(); index++)
{
if (emberAfEndpointIndexIsEnabled(index))
{
EndpointId endpointId = emberAfEndpointFromIndex(index);

if (emberAfContainsServer(endpointId, GeneralDiagnostics::Id))
{
// If General Diagnostics cluster is implemented on this endpoint
MatterReportingAttributeChangeCallback(endpointId, GeneralDiagnostics::Id,
GeneralDiagnostics::Attributes::RebootCount::Id);
MatterReportingAttributeChangeCallback(endpointId, GeneralDiagnostics::Id,
GeneralDiagnostics::Attributes::BootReasons::Id);
}
}
}
ReportAttributeOnAllEndpoints(GeneralDiagnostics::Attributes::BootReasons::Id);
}

// Get called when the Node detects a hardware fault has been raised.
Expand All @@ -221,62 +203,23 @@ class GeneralDiagnosticsDelegate : public DeviceLayer::ConnectivityManagerDelega
{
ChipLogProgress(Zcl, "GeneralDiagnosticsDelegate: OnHardwareFaultsDetected");

for (uint16_t index = 0; index < emberAfEndpointCount(); index++)
{
if (emberAfEndpointIndexIsEnabled(index))
{
EndpointId endpointId = emberAfEndpointFromIndex(index);

if (emberAfContainsServer(endpointId, GeneralDiagnostics::Id))
{
// If General Diagnostics cluster is implemented on this endpoint
MatterReportingAttributeChangeCallback(endpointId, GeneralDiagnostics::Id,
GeneralDiagnostics::Attributes::ActiveHardwareFaults::Id);
}
}
}
ReportAttributeOnAllEndpoints(GeneralDiagnostics::Attributes::ActiveHardwareFaults::Id);
}

// Get called when the Node detects a radio fault has been raised.
void OnRadioFaultsDetected(GeneralFaults<kMaxRadioFaults> & previous, GeneralFaults<kMaxRadioFaults> & current) override
{
ChipLogProgress(Zcl, "GeneralDiagnosticsDelegate: OnHardwareFaultsDetected");

for (uint16_t index = 0; index < emberAfEndpointCount(); index++)
{
if (emberAfEndpointIndexIsEnabled(index))
{
EndpointId endpointId = emberAfEndpointFromIndex(index);

if (emberAfContainsServer(endpointId, GeneralDiagnostics::Id))
{
// If General Diagnostics cluster is implemented on this endpoint
MatterReportingAttributeChangeCallback(endpointId, GeneralDiagnostics::Id,
GeneralDiagnostics::Attributes::ActiveRadioFaults::Id);
}
}
}
ReportAttributeOnAllEndpoints(GeneralDiagnostics::Attributes::ActiveRadioFaults::Id);
}

// Get called when the Node detects a network fault has been raised.
void OnNetworkFaultsDetected(GeneralFaults<kMaxNetworkFaults> & previous, GeneralFaults<kMaxNetworkFaults> & current) override
{
ChipLogProgress(Zcl, "GeneralDiagnosticsDelegate: OnHardwareFaultsDetected");

for (uint16_t index = 0; index < emberAfEndpointCount(); index++)
{
if (emberAfEndpointIndexIsEnabled(index))
{
EndpointId endpointId = emberAfEndpointFromIndex(index);

if (emberAfContainsServer(endpointId, GeneralDiagnostics::Id))
{
// If General Diagnostics cluster is implemented on this endpoint
MatterReportingAttributeChangeCallback(endpointId, GeneralDiagnostics::Id,
GeneralDiagnostics::Attributes::ActiveNetworkFaults::Id);
}
}
}
ReportAttributeOnAllEndpoints(GeneralDiagnostics::Attributes::ActiveNetworkFaults::Id);
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,19 +131,10 @@ class SoftwareDiagnosticsDelegate : public DeviceLayer::SoftwareDiagnosticsDeleg
{
ChipLogProgress(Zcl, "SoftwareDiagnosticsDelegate: OnSoftwareFaultDetected");

for (uint16_t index = 0; index < emberAfEndpointCount(); index++)
{
if (emberAfEndpointIndexIsEnabled(index))
{
EndpointId endpointId = emberAfEndpointFromIndex(index);

if (emberAfContainsServer(endpointId, SoftwareDiagnostics::Id))
{
// If Software Diagnostics cluster is implemented on this endpoint
// TODO: Log SoftwareFault event
}
}
}
ForAllEndpointsWithServerCluster(GeneralDiagnostics::Id, [](EndpointId endpoint, intptr_t) -> Loop {
// TODO: Log SoftwareFault event and walk them all.
return Loop::Break;
});
}
};

Expand Down
19 changes: 19 additions & 0 deletions src/app/util/af.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
#include <app/util/debug-printing.h>
#include <app/util/ember-print.h>

#include <lib/support/Iterators.h>
#include <lib/support/SafeInt.h>

/** @name Attribute Storage */
Expand Down Expand Up @@ -158,6 +159,24 @@ bool emberAfContainsServer(chip::EndpointId endpoint, chip::ClusterId clusterId)
*/
bool emberAfContainsServerFromIndex(uint16_t index, chip::ClusterId clusterId);

namespace chip {
namespace app {

using EndpointCallback = Loop (*)(EndpointId endpoint, intptr_t context);

/**
* @brief calls user-supplied function for every endpoint that has the given
* server cluster, until either the function returns Loop::Break or we run out
* of endpoints.
*
* Returns Loop::Break if the callee did, or Loop::Finished if we ran out of
* endpoints.
*/
Loop ForAllEndpointsWithServerCluster(ClusterId clusterId, EndpointCallback callback, intptr_t context = 0);

} // namespace app
} // namespace chip

/**
* @brief Returns true if endpoint contains cluster client.
*
Expand Down
30 changes: 30 additions & 0 deletions src/app/util/attribute-storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,36 @@ bool emberAfContainsServerFromIndex(uint16_t index, ClusterId clusterId)
}
}

namespace chip {
namespace app {

Loop ForAllEndpointsWithServerCluster(ClusterId clusterId, EndpointCallback callback, intptr_t context)
{
uint16_t count = emberAfEndpointCount();
for (uint16_t index = 0; index < count; ++index)
{
if (!emberAfEndpointIndexIsEnabled(index))
{
continue;
}

if (!emberAfContainsServerFromIndex(index, clusterId))
{
continue;
}

if (callback(emberAfEndpointFromIndex(index), context) == Loop::Break)
{
return Loop::Break;
}
}

return Loop::Finish;
}

} // namespace app
} // namespace chip

// Finds the cluster that matches endpoint, clusterId, direction, and manufacturerCode.
EmberAfCluster * emberAfFindClusterWithMfgCode(EndpointId endpoint, ClusterId clusterId, EmberAfClusterMask mask,
uint16_t manufacturerCode)
Expand Down
1 change: 1 addition & 0 deletions src/lib/support/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ static_library("support") {
"FibonacciUtils.h",
"FixedBufferAllocator.cpp",
"FixedBufferAllocator.h",
"Iterators.h",
"LifetimePersistedCounter.cpp",
"LifetimePersistedCounter.h",
"ObjectLifeCycle.h",
Expand Down
43 changes: 43 additions & 0 deletions src/lib/support/Iterators.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* 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 <cstdint>

namespace chip {

/**
* Enum used to control iteration (e.g. via a callback function that is called
* for each of a set of elements).
*
* When used as the callback return type:
* Continue: Continue the iteration.
* Break: Stop the iteration.
*
* When used as the return type of the entire iteration procedure:
* Break: Some callback returned Break.
* Finish: All callbacks returned Continue.
*/
enum class Loop : uint8_t
{
Continue,
Break,
Finish,
};

} // namespace chip
9 changes: 2 additions & 7 deletions src/lib/support/Pool.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@

#include <system/SystemConfig.h>

#include <lib/support/Iterators.h>

#include <atomic>
#include <limits>
#include <new>
Expand All @@ -32,13 +34,6 @@

namespace chip {

enum class Loop : uint8_t
{
Continue,
Break,
Finish,
};

namespace internal {

class Statistics
Expand Down

0 comments on commit 0315b48

Please sign in to comment.