14
14
* See the License for the specific language governing permissions and
15
15
* limitations under the License.
16
16
*/
17
+ #include " lib/support/logging/TextOnlyLogging.h"
17
18
#include < app/codegen-data-model-provider/CodegenDataModelProvider.h>
18
19
19
20
#include < app-common/zap-generated/attribute-type.h>
20
21
#include < app/CommandHandlerInterface.h>
21
22
#include < app/CommandHandlerInterfaceRegistry.h>
23
+ #include < app/ConcreteClusterPath.h>
22
24
#include < app/RequiredPrivilege.h>
23
25
#include < app/data-model-provider/MetadataTypes.h>
24
26
#include < app/util/IMClusterCommandHandler.h>
@@ -45,22 +47,33 @@ namespace {
45
47
class EnumeratorCommandFinder
46
48
{
47
49
public:
50
+ using HandlerCallbackFunction = CHIP_ERROR (CommandHandlerInterface::*)(const ConcreteClusterPath &,
51
+ CommandHandlerInterface::CommandIdCallback, void *);
52
+
48
53
enum class Operation
49
54
{
50
55
FindFirst, // Find the first value in the list
51
56
FindExact, // Find the given value
52
57
FindNext // Find the value AFTER this value
53
58
};
54
59
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
+ {}
56
63
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);
59
71
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);
62
74
63
75
private:
76
+ HandlerCallbackFunction mCallback ;
64
77
Operation mOperation ;
65
78
CommandId mTarget ;
66
79
std::optional<CommandId> mFound = std::nullopt;
@@ -97,6 +110,33 @@ class EnumeratorCommandFinder
97
110
}
98
111
};
99
112
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
+
100
140
// / Load the cluster information into the specified destination
101
141
std::variant<CHIP_ERROR, DataModel::ClusterInfo> LoadClusterInfo (const ConcreteClusterPath & path, const EmberAfCluster & cluster)
102
142
{
@@ -226,6 +266,19 @@ DataModel::CommandEntry CommandEntryFrom(const ConcreteClusterPath & clusterPath
226
266
return entry;
227
267
}
228
268
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
+
229
282
const ConcreteCommandPath kInvalidCommandPath (kInvalidEndpointId , kInvalidClusterId , kInvalidCommandId );
230
283
231
284
} // namespace
@@ -558,25 +611,13 @@ std::optional<DataModel::AttributeInfo> CodegenDataModelProvider::GetAttributeIn
558
611
559
612
DataModel::CommandEntry CodegenDataModelProvider::FirstAcceptedCommand (const ConcreteClusterPath & path)
560
613
{
561
- CommandHandlerInterface * interface =
562
- CommandHandlerInterfaceRegistry::Instance ().GetCommandHandler (path.mEndpointId , path.mClusterId );
614
+ auto handlerInterfaceValue =
615
+ EnumeratorCommandFinder (&CommandHandlerInterface::EnumerateAcceptedCommands, EnumeratorCommandFinder::Operation::FindFirst)
616
+ .FindCommandEntry (path);
563
617
564
- if (interface != nullptr )
618
+ if (handlerInterfaceValue. has_value () )
565
619
{
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;
580
621
}
581
622
582
623
const EmberAfCluster * cluster = FindServerCluster (path);
@@ -591,27 +632,14 @@ DataModel::CommandEntry CodegenDataModelProvider::FirstAcceptedCommand(const Con
591
632
592
633
DataModel::CommandEntry CodegenDataModelProvider::NextAcceptedCommand (const ConcreteCommandPath & before)
593
634
{
594
- CommandHandlerInterface * interface =
595
- CommandHandlerInterfaceRegistry::Instance ().GetCommandHandler (before.mEndpointId , before.mClusterId );
596
-
597
635
// TODO: `Next` redirecting to a callback is slow O(n^2).
598
636
// 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 ())
600
641
{
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;
615
643
}
616
644
617
645
const EmberAfCluster * cluster = FindServerCluster (before);
@@ -626,27 +654,13 @@ DataModel::CommandEntry CodegenDataModelProvider::NextAcceptedCommand(const Conc
626
654
627
655
std::optional<DataModel::CommandInfo> CodegenDataModelProvider::GetAcceptedCommandInfo (const ConcreteCommandPath & path)
628
656
{
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);
632
660
633
- if (interface != nullptr )
661
+ if (handlerInterfaceValue. has_value () )
634
662
{
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;
650
664
}
651
665
652
666
const EmberAfCluster * cluster = FindServerCluster (path);
@@ -659,59 +673,35 @@ std::optional<DataModel::CommandInfo> CodegenDataModelProvider::GetAcceptedComma
659
673
660
674
ConcreteCommandPath CodegenDataModelProvider::FirstGeneratedCommand (const ConcreteClusterPath & path)
661
675
{
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 () )
666
680
{
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);
681
683
}
682
684
683
685
const EmberAfCluster * cluster = FindServerCluster (path);
684
-
685
686
VerifyOrReturnValue (cluster != nullptr , kInvalidCommandPath );
686
687
687
- std::optional<CommandId> commandId = mGeneratedCommandsIterator .First (cluster->generatedCommandList );
688
+ commandId = mGeneratedCommandsIterator .First (cluster->generatedCommandList );
688
689
VerifyOrReturnValue (commandId.has_value (), kInvalidCommandPath );
689
690
return ConcreteCommandPath (path.mEndpointId , path.mClusterId , *commandId);
690
691
}
691
692
692
693
ConcreteCommandPath CodegenDataModelProvider::NextGeneratedCommand (const ConcreteCommandPath & before)
693
694
{
694
- CommandHandlerInterface * interface =
695
- CommandHandlerInterfaceRegistry::Instance ().GetCommandHandler (before.mEndpointId , before.mClusterId );
696
-
697
695
// TODO: `Next` redirecting to a callback is slow O(n^2).
698
696
// 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);
712
700
713
- return kInvalidCommandPath ;
714
- }
701
+ if (nextId.has_value ())
702
+ {
703
+ return (*nextId == kInvalidCommandId ) ? kInvalidCommandPath
704
+ : ConcreteCommandPath (before.mEndpointId , before.mClusterId , *nextId);
715
705
}
716
706
717
707
const EmberAfCluster * cluster = FindServerCluster (before);
0 commit comments