Skip to content

Commit a9ac014

Browse files
committed
Update code flow to hopefully make it somewhat easier to read
1 parent 0d30fce commit a9ac014

File tree

2 files changed

+104
-114
lines changed

2 files changed

+104
-114
lines changed

src/app/codegen-data-model-provider/CodegenDataModelProvider.cpp

+87-97
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@
1414
* See the License for the specific language governing permissions and
1515
* limitations under the License.
1616
*/
17+
#include "lib/support/logging/TextOnlyLogging.h"
1718
#include <app/codegen-data-model-provider/CodegenDataModelProvider.h>
1819

1920
#include <app-common/zap-generated/attribute-type.h>
2021
#include <app/CommandHandlerInterface.h>
2122
#include <app/CommandHandlerInterfaceRegistry.h>
23+
#include <app/ConcreteClusterPath.h>
2224
#include <app/RequiredPrivilege.h>
2325
#include <app/data-model-provider/MetadataTypes.h>
2426
#include <app/util/IMClusterCommandHandler.h>
@@ -45,22 +47,33 @@ namespace {
4547
class EnumeratorCommandFinder
4648
{
4749
public:
50+
using HandlerCallbackFunction = CHIP_ERROR (CommandHandlerInterface::*)(const ConcreteClusterPath &,
51+
CommandHandlerInterface::CommandIdCallback, void *);
52+
4853
enum class Operation
4954
{
5055
FindFirst, // Find the first value in the list
5156
FindExact, // Find the given value
5257
FindNext // Find the value AFTER this value
5358
};
5459

55-
EnumeratorCommandFinder(Operation operation, CommandId target) : mOperation(operation), mTarget(target) {}
60+
EnumeratorCommandFinder(HandlerCallbackFunction callback, Operation operation, CommandId target = kInvalidCommandId) :
61+
mCallback(callback), mOperation(operation), mTarget(target)
62+
{}
5663

57-
/// Callback to pass in to `Enumerate*` calls in CommandHandlerInterface
58-
CommandHandlerInterface::CommandIdCallback Callback() { return HandlerCallbackFn; }
64+
/// Find the given command id fo
65+
///
66+
/// Returns:
67+
/// - std::nullopt if no command found using the command handler interface
68+
/// - kInvalidCommandId if the find failed (but command handler interface does provide a list)
69+
/// - valid id if command handler interface usage succeeds
70+
std::optional<CommandId> FindCommandId(ConcreteClusterPath cluster);
5971

60-
/// Get the element found (if any) after the `Callback` is used
61-
std::optional<CommandId> GetFound() const { return mFound; }
72+
/// Uses FindCommandId to find the given command and loads the command entry data
73+
std::optional<DataModel::CommandEntry> FindCommandEntry(ConcreteClusterPath cluster);
6274

6375
private:
76+
HandlerCallbackFunction mCallback;
6477
Operation mOperation;
6578
CommandId mTarget;
6679
std::optional<CommandId> mFound = std::nullopt;
@@ -97,6 +110,33 @@ class EnumeratorCommandFinder
97110
}
98111
};
99112

113+
std::optional<CommandId> EnumeratorCommandFinder::FindCommandId(ConcreteClusterPath cluster)
114+
{
115+
CommandHandlerInterface * interface =
116+
CommandHandlerInterfaceRegistry::Instance().GetCommandHandler(cluster.mEndpointId, cluster.mClusterId);
117+
118+
if (interface == nullptr)
119+
{
120+
return std::nullopt; // no data: no interface
121+
}
122+
123+
CHIP_ERROR err = (interface->*mCallback)(cluster, HandlerCallbackFn, this);
124+
if (err == CHIP_ERROR_NOT_IMPLEMENTED)
125+
{
126+
return std::nullopt; // no data provided by the interface
127+
}
128+
129+
if (err != CHIP_NO_ERROR)
130+
{
131+
// Report the error here since we lose actual error. This generally should NOT be possible as CHI usually returns
132+
// unimplemented or should just work for our use case (our callback never fails)
133+
ChipLogError(DataManagement, "Enumerate error: %" CHIP_ERROR_FORMAT, err.Format());
134+
return kInvalidCommandId;
135+
}
136+
137+
return mFound.value_or(kInvalidCommandId);
138+
}
139+
100140
/// Load the cluster information into the specified destination
101141
std::variant<CHIP_ERROR, DataModel::ClusterInfo> LoadClusterInfo(const ConcreteClusterPath & path, const EmberAfCluster & cluster)
102142
{
@@ -226,6 +266,19 @@ DataModel::CommandEntry CommandEntryFrom(const ConcreteClusterPath & clusterPath
226266
return entry;
227267
}
228268

269+
std::optional<DataModel::CommandEntry> EnumeratorCommandFinder::FindCommandEntry(ConcreteClusterPath cluster)
270+
{
271+
272+
std::optional<CommandId> id = FindCommandId(cluster);
273+
274+
if (!id.has_value())
275+
{
276+
return std::nullopt;
277+
}
278+
279+
return (*id == kInvalidCommandId) ? DataModel::CommandEntry::kInvalid : CommandEntryFrom(cluster, *id);
280+
}
281+
229282
const ConcreteCommandPath kInvalidCommandPath(kInvalidEndpointId, kInvalidClusterId, kInvalidCommandId);
230283

231284
} // namespace
@@ -558,25 +611,13 @@ std::optional<DataModel::AttributeInfo> CodegenDataModelProvider::GetAttributeIn
558611

559612
DataModel::CommandEntry CodegenDataModelProvider::FirstAcceptedCommand(const ConcreteClusterPath & path)
560613
{
561-
CommandHandlerInterface * interface =
562-
CommandHandlerInterfaceRegistry::Instance().GetCommandHandler(path.mEndpointId, path.mClusterId);
614+
auto handlerInterfaceValue =
615+
EnumeratorCommandFinder(&CommandHandlerInterface::EnumerateAcceptedCommands, EnumeratorCommandFinder::Operation::FindFirst)
616+
.FindCommandEntry(path);
563617

564-
if (interface != nullptr)
618+
if (handlerInterfaceValue.has_value())
565619
{
566-
EnumeratorCommandFinder finder(EnumeratorCommandFinder::Operation::FindFirst, kInvalidCommandId);
567-
CHIP_ERROR err = interface->EnumerateAcceptedCommands(path, finder.Callback(), &finder);
568-
569-
if (err != CHIP_ERROR_NOT_IMPLEMENTED)
570-
{
571-
auto firstId = finder.GetFound();
572-
573-
if ((err == CHIP_NO_ERROR) && firstId.has_value())
574-
{
575-
return CommandEntryFrom(path, *firstId);
576-
}
577-
578-
return DataModel::CommandEntry::kInvalid;
579-
}
620+
return *handlerInterfaceValue;
580621
}
581622

582623
const EmberAfCluster * cluster = FindServerCluster(path);
@@ -591,27 +632,14 @@ DataModel::CommandEntry CodegenDataModelProvider::FirstAcceptedCommand(const Con
591632

592633
DataModel::CommandEntry CodegenDataModelProvider::NextAcceptedCommand(const ConcreteCommandPath & before)
593634
{
594-
CommandHandlerInterface * interface =
595-
CommandHandlerInterfaceRegistry::Instance().GetCommandHandler(before.mEndpointId, before.mClusterId);
596-
597635
// TODO: `Next` redirecting to a callback is slow O(n^2).
598636
// see https://github.com/project-chip/connectedhomeip/issues/35790
599-
if (interface != nullptr)
637+
auto handlerInterfaceValue = EnumeratorCommandFinder(&CommandHandlerInterface::EnumerateAcceptedCommands,
638+
EnumeratorCommandFinder::Operation::FindNext, before.mCommandId)
639+
.FindCommandEntry(before);
640+
if (handlerInterfaceValue.has_value())
600641
{
601-
EnumeratorCommandFinder finder(EnumeratorCommandFinder::Operation::FindNext, before.mCommandId);
602-
CHIP_ERROR err = interface->EnumerateAcceptedCommands(before, finder.Callback(), &finder);
603-
604-
if (err != CHIP_ERROR_NOT_IMPLEMENTED)
605-
{
606-
auto nextId = finder.GetFound();
607-
608-
if ((err == CHIP_NO_ERROR) && nextId.has_value())
609-
{
610-
return CommandEntryFrom(before, *nextId);
611-
}
612-
613-
return DataModel::CommandEntry::kInvalid;
614-
}
642+
return *handlerInterfaceValue;
615643
}
616644

617645
const EmberAfCluster * cluster = FindServerCluster(before);
@@ -626,27 +654,13 @@ DataModel::CommandEntry CodegenDataModelProvider::NextAcceptedCommand(const Conc
626654

627655
std::optional<DataModel::CommandInfo> CodegenDataModelProvider::GetAcceptedCommandInfo(const ConcreteCommandPath & path)
628656
{
629-
// Command handler interface MAY override lists of commands
630-
CommandHandlerInterface * interface =
631-
CommandHandlerInterfaceRegistry::Instance().GetCommandHandler(path.mEndpointId, path.mClusterId);
657+
auto handlerInterfaceValue = EnumeratorCommandFinder(&CommandHandlerInterface::EnumerateAcceptedCommands,
658+
EnumeratorCommandFinder::Operation::FindExact, path.mCommandId)
659+
.FindCommandEntry(path);
632660

633-
if (interface != nullptr)
661+
if (handlerInterfaceValue.has_value())
634662
{
635-
EnumeratorCommandFinder finder(EnumeratorCommandFinder::Operation::FindExact, path.mCommandId);
636-
CHIP_ERROR err = interface->EnumerateGeneratedCommands(path, finder.Callback(), &finder);
637-
638-
if (err != CHIP_ERROR_NOT_IMPLEMENTED)
639-
{
640-
auto commandId = finder.GetFound();
641-
642-
if ((err == CHIP_NO_ERROR) && commandId.has_value())
643-
{
644-
// definitive answer: command exists
645-
return CommandEntryFrom(path, *commandId).info;
646-
}
647-
648-
return std::nullopt;
649-
}
663+
return handlerInterfaceValue->IsValid() ? std::make_optional(handlerInterfaceValue->info) : std::nullopt;
650664
}
651665

652666
const EmberAfCluster * cluster = FindServerCluster(path);
@@ -659,59 +673,35 @@ std::optional<DataModel::CommandInfo> CodegenDataModelProvider::GetAcceptedComma
659673

660674
ConcreteCommandPath CodegenDataModelProvider::FirstGeneratedCommand(const ConcreteClusterPath & path)
661675
{
662-
CommandHandlerInterface * interface =
663-
CommandHandlerInterfaceRegistry::Instance().GetCommandHandler(path.mEndpointId, path.mClusterId);
664-
665-
if (interface != nullptr)
676+
std::optional<CommandId> commandId =
677+
EnumeratorCommandFinder(&CommandHandlerInterface::EnumerateGeneratedCommands, EnumeratorCommandFinder::Operation::FindFirst)
678+
.FindCommandId(path);
679+
if (commandId.has_value())
666680
{
667-
EnumeratorCommandFinder finder(EnumeratorCommandFinder::Operation::FindFirst, kInvalidCommandId);
668-
CHIP_ERROR err = interface->EnumerateGeneratedCommands(path, finder.Callback(), &finder);
669-
670-
if (err != CHIP_ERROR_NOT_IMPLEMENTED)
671-
{
672-
auto firstId = finder.GetFound();
673-
674-
if ((err == CHIP_NO_ERROR) && firstId.has_value())
675-
{
676-
return ConcreteCommandPath(path.mEndpointId, path.mClusterId, *firstId);
677-
}
678-
679-
return kInvalidCommandPath;
680-
}
681+
return *commandId == kInvalidCommandId ? kInvalidCommandPath
682+
: ConcreteCommandPath(path.mEndpointId, path.mClusterId, *commandId);
681683
}
682684

683685
const EmberAfCluster * cluster = FindServerCluster(path);
684-
685686
VerifyOrReturnValue(cluster != nullptr, kInvalidCommandPath);
686687

687-
std::optional<CommandId> commandId = mGeneratedCommandsIterator.First(cluster->generatedCommandList);
688+
commandId = mGeneratedCommandsIterator.First(cluster->generatedCommandList);
688689
VerifyOrReturnValue(commandId.has_value(), kInvalidCommandPath);
689690
return ConcreteCommandPath(path.mEndpointId, path.mClusterId, *commandId);
690691
}
691692

692693
ConcreteCommandPath CodegenDataModelProvider::NextGeneratedCommand(const ConcreteCommandPath & before)
693694
{
694-
CommandHandlerInterface * interface =
695-
CommandHandlerInterfaceRegistry::Instance().GetCommandHandler(before.mEndpointId, before.mClusterId);
696-
697695
// TODO: `Next` redirecting to a callback is slow O(n^2).
698696
// see https://github.com/project-chip/connectedhomeip/issues/35790
699-
if (interface != nullptr)
700-
{
701-
EnumeratorCommandFinder finder(EnumeratorCommandFinder::Operation::FindNext, before.mCommandId);
702-
CHIP_ERROR err = interface->EnumerateGeneratedCommands(before, finder.Callback(), &finder);
703-
704-
if (err != CHIP_ERROR_NOT_IMPLEMENTED)
705-
{
706-
auto nextId = finder.GetFound();
707-
708-
if ((err == CHIP_NO_ERROR) && nextId.has_value())
709-
{
710-
return ConcreteCommandPath(before.mEndpointId, before.mClusterId, *nextId);
711-
}
697+
auto nextId = EnumeratorCommandFinder(&CommandHandlerInterface::EnumerateGeneratedCommands,
698+
EnumeratorCommandFinder::Operation::FindNext, before.mCommandId)
699+
.FindCommandId(before);
712700

713-
return kInvalidCommandPath;
714-
}
701+
if (nextId.has_value())
702+
{
703+
return (*nextId == kInvalidCommandId) ? kInvalidCommandPath
704+
: ConcreteCommandPath(before.mEndpointId, before.mClusterId, *nextId);
715705
}
716706

717707
const EmberAfCluster * cluster = FindServerCluster(before);

src/app/codegen-data-model-provider/tests/TestCodegenModelViaMocks.cpp

+17-17
Original file line numberDiff line numberDiff line change
@@ -1382,17 +1382,17 @@ TEST(TestCodegenModelViaMocks, CommandHandlerInterfaceAcceptedCommands)
13821382
CustomListCommandHandler handler(MakeOptional(kMockEndpoint1), MockClusterId(1));
13831383

13841384
// At this point, without overrides, there should be no accepted/generated commands
1385-
ASSERT_FALSE(model.FirstAcceptedCommand(ConcreteClusterPath(kMockEndpoint1, MockClusterId(1))).IsValid());
1386-
ASSERT_FALSE(model.FirstGeneratedCommand(ConcreteClusterPath(kMockEndpoint1, MockClusterId(1))).HasValidIds());
1387-
ASSERT_FALSE(model.GetAcceptedCommandInfo(ConcreteCommandPath(kMockEndpoint1, MockClusterId(1), 1234)).has_value());
1385+
EXPECT_FALSE(model.FirstAcceptedCommand(ConcreteClusterPath(kMockEndpoint1, MockClusterId(1))).IsValid());
1386+
EXPECT_FALSE(model.FirstGeneratedCommand(ConcreteClusterPath(kMockEndpoint1, MockClusterId(1))).HasValidIds());
1387+
EXPECT_FALSE(model.GetAcceptedCommandInfo(ConcreteCommandPath(kMockEndpoint1, MockClusterId(1), 1234)).has_value());
13881388

13891389
handler.SetOverrideAccepted(true);
13901390
handler.SetOverrideGenerated(true);
13911391

13921392
// with overrides, the list is still empty ...
1393-
ASSERT_FALSE(model.FirstAcceptedCommand(ConcreteClusterPath(kMockEndpoint1, MockClusterId(1))).IsValid());
1394-
ASSERT_FALSE(model.FirstGeneratedCommand(ConcreteClusterPath(kMockEndpoint1, MockClusterId(1))).HasValidIds());
1395-
ASSERT_FALSE(model.GetAcceptedCommandInfo(ConcreteCommandPath(kMockEndpoint1, MockClusterId(1), 1234)).has_value());
1393+
EXPECT_FALSE(model.FirstAcceptedCommand(ConcreteClusterPath(kMockEndpoint1, MockClusterId(1))).IsValid());
1394+
EXPECT_FALSE(model.FirstGeneratedCommand(ConcreteClusterPath(kMockEndpoint1, MockClusterId(1))).HasValidIds());
1395+
EXPECT_FALSE(model.GetAcceptedCommandInfo(ConcreteCommandPath(kMockEndpoint1, MockClusterId(1), 1234)).has_value());
13961396

13971397
// set some overrides
13981398
handler.AcceptedVec().push_back(1234);
@@ -1403,26 +1403,26 @@ TEST(TestCodegenModelViaMocks, CommandHandlerInterfaceAcceptedCommands)
14031403
DataModel::CommandEntry entry;
14041404

14051405
entry = model.FirstAcceptedCommand(ConcreteClusterPath(kMockEndpoint1, MockClusterId(1)));
1406-
ASSERT_TRUE(entry.IsValid());
1407-
ASSERT_EQ(entry.path, ConcreteCommandPath(kMockEndpoint1, MockClusterId(1), 1234));
1406+
EXPECT_TRUE(entry.IsValid());
1407+
EXPECT_EQ(entry.path, ConcreteCommandPath(kMockEndpoint1, MockClusterId(1), 1234));
14081408

14091409
entry = model.NextAcceptedCommand(entry.path);
1410-
ASSERT_TRUE(entry.IsValid());
1411-
ASSERT_EQ(entry.path, ConcreteCommandPath(kMockEndpoint1, MockClusterId(1), 999));
1410+
EXPECT_TRUE(entry.IsValid());
1411+
EXPECT_EQ(entry.path, ConcreteCommandPath(kMockEndpoint1, MockClusterId(1), 999));
14121412

14131413
entry = model.NextAcceptedCommand(entry.path);
1414-
ASSERT_FALSE(entry.IsValid());
1414+
EXPECT_FALSE(entry.IsValid());
14151415

14161416
ConcreteCommandPath path = model.FirstGeneratedCommand(ConcreteClusterPath(kMockEndpoint1, MockClusterId(1)));
1417-
ASSERT_TRUE(path.HasValidIds());
1418-
ASSERT_EQ(path, ConcreteCommandPath(kMockEndpoint1, MockClusterId(1), 33));
1417+
EXPECT_TRUE(path.HasValidIds());
1418+
EXPECT_EQ(path, ConcreteCommandPath(kMockEndpoint1, MockClusterId(1), 33));
14191419
path = model.NextGeneratedCommand(path);
1420-
ASSERT_FALSE(path.HasValidIds());
1420+
EXPECT_FALSE(path.HasValidIds());
14211421

14221422
// Command finding should work
1423-
ASSERT_TRUE(model.GetAcceptedCommandInfo(ConcreteCommandPath(kMockEndpoint1, MockClusterId(1), 1234)).has_value());
1424-
ASSERT_FALSE(model.GetAcceptedCommandInfo(ConcreteCommandPath(kMockEndpoint1, MockClusterId(1), 88)).has_value());
1425-
ASSERT_FALSE(model.GetAcceptedCommandInfo(ConcreteCommandPath(kMockEndpoint1, MockClusterId(1), 33)).has_value());
1423+
EXPECT_TRUE(model.GetAcceptedCommandInfo(ConcreteCommandPath(kMockEndpoint1, MockClusterId(1), 1234)).has_value());
1424+
EXPECT_FALSE(model.GetAcceptedCommandInfo(ConcreteCommandPath(kMockEndpoint1, MockClusterId(1), 88)).has_value());
1425+
EXPECT_FALSE(model.GetAcceptedCommandInfo(ConcreteCommandPath(kMockEndpoint1, MockClusterId(1), 33)).has_value());
14261426
}
14271427

14281428
TEST(TestCodegenModelViaMocks, EmberAttributeReadAclDeny)

0 commit comments

Comments
 (0)