Skip to content

Commit 3219a5f

Browse files
andy31415andreilitvinbzbarsky-apple
authored
Ember compatibility layer - split out GlobalAttributeAccessInterface and the I/O buffer (#33396)
* Split out ember-compatibiltiy-functions with some shareable bits. When looking to implement the ember/codegen data mode, some functionality in ember-compatibility-functions needs sharing to avoid extra copy&paste bloat: - Global attribute handling via AAI split into a separate file - Raw "data I/O" buffer split into a separate file Moved privilege-storage and implemented a few more mock ember methods. * Also update linter * Remove obsolete file * Fix odd include * Add files to Matter.xcodeproject * Update src/app/util/ember-io-storage.h Co-authored-by: Boris Zbarsky <bzbarsky@apple.com> * Update ember-io-storage.h Add additional comments. * Restyle --------- Co-authored-by: Andrei Litvin <andreilitvin@google.com> Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>
1 parent b653e8e commit 3219a5f

15 files changed

+475
-266
lines changed

.github/workflows/lint.yml

+4
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,10 @@ jobs:
119119
--known-failure app/util/DataModelHandler.h \
120120
--known-failure app/util/ember-compatibility-functions.cpp \
121121
--known-failure app/util/ember-compatibility-functions.h \
122+
--known-failure app/util/ember-global-attribute-access-interface.cpp \
123+
--known-failure app/util/ember-global-attribute-access-interface.h \
124+
--known-failure app/util/ember-io-storage.cpp \
125+
--known-failure app/util/ember-io-storage.h \
122126
--known-failure app/util/endpoint-config-api.h \
123127
--known-failure app/util/generic-callbacks.h \
124128
--known-failure app/util/generic-callback-stubs.cpp \

src/app/chip_data_model.cmake

+2
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,8 @@ function(chip_configure_data_model APP_TARGET)
144144
${CHIP_APP_BASE_DIR}/icd/server/ICDConfigurationData.cpp
145145
${CHIP_APP_BASE_DIR}/util/DataModelHandler.cpp
146146
${CHIP_APP_BASE_DIR}/util/ember-compatibility-functions.cpp
147+
${CHIP_APP_BASE_DIR}/util/ember-global-attribute-access-interface.cpp
148+
${CHIP_APP_BASE_DIR}/util/ember-io-storage.cpp
147149
${CHIP_APP_BASE_DIR}/util/generic-callback-stubs.cpp
148150
${CHIP_APP_BASE_DIR}/util/privilege-storage.cpp
149151
${CHIP_APP_BASE_DIR}/util/util.cpp

src/app/chip_data_model.gni

+2
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,8 @@ template("chip_data_model") {
209209
"${_app_root}/util/attribute-storage.cpp",
210210
"${_app_root}/util/attribute-table.cpp",
211211
"${_app_root}/util/ember-compatibility-functions.cpp",
212+
"${_app_root}/util/ember-global-attribute-access-interface.cpp",
213+
"${_app_root}/util/ember-io-storage.cpp",
212214
"${_app_root}/util/util.cpp",
213215
]
214216
}

src/app/tests/BUILD.gn

-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ static_library("helpers") {
2929
"${chip_root}/src/app/reporting/tests/MockReportScheduler.cpp",
3030
"AppTestContext.cpp",
3131
"AppTestContext.h",
32-
"integration/RequiredPrivilegeStubs.cpp",
3332
]
3433

3534
cflags = [ "-Wconversion" ]

src/app/tests/integration/BUILD.gn

-2
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ source_set("common") {
3838
executable("chip-im-initiator") {
3939
sources = [
4040
"${chip_root}/src/app/reporting/tests/MockReportScheduler.cpp",
41-
"RequiredPrivilegeStubs.cpp",
4241
"chip_im_initiator.cpp",
4342
]
4443

@@ -61,7 +60,6 @@ executable("chip-im-responder") {
6160
"${chip_root}/src/app/reporting/tests/MockReportScheduler.cpp",
6261
"MockEvents.cpp",
6362
"MockEvents.h",
64-
"RequiredPrivilegeStubs.cpp",
6563
"chip_im_responder.cpp",
6664
]
6765

src/app/util/ember-compatibility-functions.cpp

+27-259
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
/*
2+
* Copyright (c) 2021-2024 Project CHIP Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
#include <app/util/ember-global-attribute-access-interface.h>
17+
18+
#include <app/GlobalAttributes.h>
19+
#include <app/InteractionModelEngine.h>
20+
21+
namespace chip {
22+
namespace app {
23+
namespace Compatibility {
24+
25+
CHIP_ERROR GlobalAttributeReader::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder)
26+
{
27+
using namespace Clusters::Globals::Attributes;
28+
switch (aPath.mAttributeId)
29+
{
30+
case AttributeList::Id:
31+
return aEncoder.EncodeList([this](const auto & encoder) {
32+
const size_t count = mCluster->attributeCount;
33+
bool addedExtraGlobals = false;
34+
for (size_t i = 0; i < count; ++i)
35+
{
36+
AttributeId id = mCluster->attributes[i].attributeId;
37+
constexpr auto lastGlobalId = GlobalAttributesNotInMetadata[ArraySize(GlobalAttributesNotInMetadata) - 1];
38+
#if CHIP_CONFIG_ENABLE_EVENTLIST_ATTRIBUTE
39+
// The GlobalAttributesNotInMetadata shouldn't have any gaps in their ids here.
40+
static_assert(lastGlobalId - GlobalAttributesNotInMetadata[0] == ArraySize(GlobalAttributesNotInMetadata) - 1,
41+
"Ids in GlobalAttributesNotInMetadata not consecutive");
42+
#else
43+
// If EventList is not supported. The GlobalAttributesNotInMetadata is missing one id here.
44+
static_assert(lastGlobalId - GlobalAttributesNotInMetadata[0] == ArraySize(GlobalAttributesNotInMetadata),
45+
"Ids in GlobalAttributesNotInMetadata not consecutive (except EventList)");
46+
#endif // CHIP_CONFIG_ENABLE_EVENTLIST_ATTRIBUTE
47+
if (!addedExtraGlobals && id > lastGlobalId)
48+
{
49+
for (const auto & globalId : GlobalAttributesNotInMetadata)
50+
{
51+
ReturnErrorOnFailure(encoder.Encode(globalId));
52+
}
53+
addedExtraGlobals = true;
54+
}
55+
ReturnErrorOnFailure(encoder.Encode(id));
56+
}
57+
if (!addedExtraGlobals)
58+
{
59+
for (const auto & globalId : GlobalAttributesNotInMetadata)
60+
{
61+
ReturnErrorOnFailure(encoder.Encode(globalId));
62+
}
63+
}
64+
return CHIP_NO_ERROR;
65+
});
66+
#if CHIP_CONFIG_ENABLE_EVENTLIST_ATTRIBUTE
67+
case EventList::Id:
68+
return aEncoder.EncodeList([this](const auto & encoder) {
69+
for (size_t i = 0; i < mCluster->eventCount; ++i)
70+
{
71+
ReturnErrorOnFailure(encoder.Encode(mCluster->eventList[i]));
72+
}
73+
return CHIP_NO_ERROR;
74+
});
75+
#endif // CHIP_CONFIG_ENABLE_EVENTLIST_ATTRIBUTE
76+
case AcceptedCommandList::Id:
77+
return EncodeCommandList(aPath, aEncoder, &CommandHandlerInterface::EnumerateAcceptedCommands,
78+
mCluster->acceptedCommandList);
79+
case GeneratedCommandList::Id:
80+
return EncodeCommandList(aPath, aEncoder, &CommandHandlerInterface::EnumerateGeneratedCommands,
81+
mCluster->generatedCommandList);
82+
default:
83+
// This function is only called if attributeCluster is non-null in
84+
// ReadSingleClusterData, which only happens for attributes listed in
85+
// GlobalAttributesNotInMetadata. If we reach this code, someone added
86+
// a global attribute to that list but not the above switch.
87+
VerifyOrDieWithMsg(false, DataManagement, "Unexpected global attribute: " ChipLogFormatMEI,
88+
ChipLogValueMEI(aPath.mAttributeId));
89+
return CHIP_NO_ERROR;
90+
}
91+
}
92+
93+
CHIP_ERROR GlobalAttributeReader::EncodeCommandList(const ConcreteClusterPath & aClusterPath, AttributeValueEncoder & aEncoder,
94+
GlobalAttributeReader::CommandListEnumerator aEnumerator,
95+
const CommandId * aClusterCommandList)
96+
{
97+
return aEncoder.EncodeList([&](const auto & encoder) {
98+
auto * commandHandler =
99+
InteractionModelEngine::GetInstance()->FindCommandHandler(aClusterPath.mEndpointId, aClusterPath.mClusterId);
100+
if (commandHandler)
101+
{
102+
struct Context
103+
{
104+
decltype(encoder) & commandIdEncoder;
105+
CHIP_ERROR err;
106+
} context{ encoder, CHIP_NO_ERROR };
107+
CHIP_ERROR err = (commandHandler->*aEnumerator)(
108+
aClusterPath,
109+
[](CommandId command, void * closure) -> Loop {
110+
auto * ctx = static_cast<Context *>(closure);
111+
ctx->err = ctx->commandIdEncoder.Encode(command);
112+
if (ctx->err != CHIP_NO_ERROR)
113+
{
114+
return Loop::Break;
115+
}
116+
return Loop::Continue;
117+
},
118+
&context);
119+
if (err != CHIP_ERROR_NOT_IMPLEMENTED)
120+
{
121+
return context.err;
122+
}
123+
// Else fall through to the list in aClusterCommandList.
124+
}
125+
126+
for (const CommandId * cmd = aClusterCommandList; cmd != nullptr && *cmd != kInvalidCommandId; cmd++)
127+
{
128+
ReturnErrorOnFailure(encoder.Encode(*cmd));
129+
}
130+
return CHIP_NO_ERROR;
131+
});
132+
}
133+
134+
} // namespace Compatibility
135+
} // namespace app
136+
} // namespace chip
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright (c) 2021-2024 Project CHIP Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
#pragma once
17+
18+
#include <app/AttributeAccessInterface.h>
19+
#include <app/CommandHandlerInterface.h>
20+
#include <app/util/af-types.h>
21+
22+
namespace chip {
23+
namespace app {
24+
namespace Compatibility {
25+
26+
// This reader should never actually be registered; we do manual dispatch to it
27+
// for the one attribute it handles.
28+
class MandatoryGlobalAttributeReader : public AttributeAccessInterface
29+
{
30+
public:
31+
MandatoryGlobalAttributeReader(const EmberAfCluster * aCluster) :
32+
AttributeAccessInterface(MakeOptional(kInvalidEndpointId), kInvalidClusterId), mCluster(aCluster)
33+
{}
34+
35+
protected:
36+
const EmberAfCluster * mCluster;
37+
};
38+
39+
class GlobalAttributeReader : public MandatoryGlobalAttributeReader
40+
{
41+
public:
42+
GlobalAttributeReader(const EmberAfCluster * aCluster) : MandatoryGlobalAttributeReader(aCluster) {}
43+
44+
CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override;
45+
46+
private:
47+
typedef CHIP_ERROR (CommandHandlerInterface::*CommandListEnumerator)(const ConcreteClusterPath & cluster,
48+
CommandHandlerInterface::CommandIdCallback callback,
49+
void * context);
50+
static CHIP_ERROR EncodeCommandList(const ConcreteClusterPath & aClusterPath, AttributeValueEncoder & aEncoder,
51+
CommandListEnumerator aEnumerator, const CommandId * aClusterCommandList);
52+
};
53+
54+
} // namespace Compatibility
55+
} // namespace app
56+
} // namespace chip

src/app/util/ember-io-storage.cpp

+126
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/*
2+
* Copyright (c) 2024 Project CHIP Authors
3+
* All rights reserved.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
#include <app/util/ember-io-storage.h>
18+
19+
#include <app-common/zap-generated/attribute-type.h>
20+
#include <zap-generated/endpoint_config.h>
21+
22+
#include <cstddef>
23+
24+
namespace chip {
25+
namespace app {
26+
namespace Compatibility {
27+
namespace Internal {
28+
29+
// On some apps, ATTRIBUTE_LARGEST can as small as 3, making compiler unhappy since data[kAttributeReadBufferSize] cannot hold
30+
// uint64_t. Make kAttributeReadBufferSize at least 8 so it can fit all basic types.
31+
constexpr size_t kAttributeReadBufferSize = (ATTRIBUTE_LARGEST >= 8 ? ATTRIBUTE_LARGEST : 8);
32+
uint8_t attributeIOBuffer[kAttributeReadBufferSize];
33+
34+
MutableByteSpan gEmberAttributeIOBufferSpan(attributeIOBuffer);
35+
36+
EmberAfAttributeType AttributeBaseType(EmberAfAttributeType type)
37+
{
38+
switch (type)
39+
{
40+
case ZCL_ACTION_ID_ATTRIBUTE_TYPE: // Action Id
41+
case ZCL_FABRIC_IDX_ATTRIBUTE_TYPE: // Fabric Index
42+
case ZCL_BITMAP8_ATTRIBUTE_TYPE: // 8-bit bitmap
43+
case ZCL_ENUM8_ATTRIBUTE_TYPE: // 8-bit enumeration
44+
case ZCL_STATUS_ATTRIBUTE_TYPE: // Status Code
45+
case ZCL_PERCENT_ATTRIBUTE_TYPE: // Percentage
46+
static_assert(std::is_same<chip::Percent, uint8_t>::value,
47+
"chip::Percent is expected to be uint8_t, change this when necessary");
48+
return ZCL_INT8U_ATTRIBUTE_TYPE;
49+
50+
case ZCL_ENDPOINT_NO_ATTRIBUTE_TYPE: // Endpoint Number
51+
case ZCL_GROUP_ID_ATTRIBUTE_TYPE: // Group Id
52+
case ZCL_VENDOR_ID_ATTRIBUTE_TYPE: // Vendor Id
53+
case ZCL_ENUM16_ATTRIBUTE_TYPE: // 16-bit enumeration
54+
case ZCL_BITMAP16_ATTRIBUTE_TYPE: // 16-bit bitmap
55+
case ZCL_PERCENT100THS_ATTRIBUTE_TYPE: // 100ths of a percent
56+
static_assert(std::is_same<chip::EndpointId, uint16_t>::value,
57+
"chip::EndpointId is expected to be uint16_t, change this when necessary");
58+
static_assert(std::is_same<chip::GroupId, uint16_t>::value,
59+
"chip::GroupId is expected to be uint16_t, change this when necessary");
60+
static_assert(std::is_same<chip::Percent100ths, uint16_t>::value,
61+
"chip::Percent100ths is expected to be uint16_t, change this when necessary");
62+
return ZCL_INT16U_ATTRIBUTE_TYPE;
63+
64+
case ZCL_CLUSTER_ID_ATTRIBUTE_TYPE: // Cluster Id
65+
case ZCL_ATTRIB_ID_ATTRIBUTE_TYPE: // Attribute Id
66+
case ZCL_FIELD_ID_ATTRIBUTE_TYPE: // Field Id
67+
case ZCL_EVENT_ID_ATTRIBUTE_TYPE: // Event Id
68+
case ZCL_COMMAND_ID_ATTRIBUTE_TYPE: // Command Id
69+
case ZCL_TRANS_ID_ATTRIBUTE_TYPE: // Transaction Id
70+
case ZCL_DEVTYPE_ID_ATTRIBUTE_TYPE: // Device Type Id
71+
case ZCL_DATA_VER_ATTRIBUTE_TYPE: // Data Version
72+
case ZCL_BITMAP32_ATTRIBUTE_TYPE: // 32-bit bitmap
73+
case ZCL_EPOCH_S_ATTRIBUTE_TYPE: // Epoch Seconds
74+
case ZCL_ELAPSED_S_ATTRIBUTE_TYPE: // Elapsed Seconds
75+
static_assert(std::is_same<chip::ClusterId, uint32_t>::value,
76+
"chip::Cluster is expected to be uint32_t, change this when necessary");
77+
static_assert(std::is_same<chip::AttributeId, uint32_t>::value,
78+
"chip::AttributeId is expected to be uint32_t, change this when necessary");
79+
static_assert(std::is_same<chip::AttributeId, uint32_t>::value,
80+
"chip::AttributeId is expected to be uint32_t, change this when necessary");
81+
static_assert(std::is_same<chip::EventId, uint32_t>::value,
82+
"chip::EventId is expected to be uint32_t, change this when necessary");
83+
static_assert(std::is_same<chip::CommandId, uint32_t>::value,
84+
"chip::CommandId is expected to be uint32_t, change this when necessary");
85+
static_assert(std::is_same<chip::TransactionId, uint32_t>::value,
86+
"chip::TransactionId is expected to be uint32_t, change this when necessary");
87+
static_assert(std::is_same<chip::DeviceTypeId, uint32_t>::value,
88+
"chip::DeviceTypeId is expected to be uint32_t, change this when necessary");
89+
static_assert(std::is_same<chip::DataVersion, uint32_t>::value,
90+
"chip::DataVersion is expected to be uint32_t, change this when necessary");
91+
return ZCL_INT32U_ATTRIBUTE_TYPE;
92+
93+
case ZCL_AMPERAGE_MA_ATTRIBUTE_TYPE: // Amperage milliamps
94+
case ZCL_ENERGY_MWH_ATTRIBUTE_TYPE: // Energy milliwatt-hours
95+
case ZCL_POWER_MW_ATTRIBUTE_TYPE: // Power milliwatts
96+
case ZCL_VOLTAGE_MV_ATTRIBUTE_TYPE: // Voltage millivolts
97+
return ZCL_INT64S_ATTRIBUTE_TYPE;
98+
99+
case ZCL_EVENT_NO_ATTRIBUTE_TYPE: // Event Number
100+
case ZCL_FABRIC_ID_ATTRIBUTE_TYPE: // Fabric Id
101+
case ZCL_NODE_ID_ATTRIBUTE_TYPE: // Node Id
102+
case ZCL_BITMAP64_ATTRIBUTE_TYPE: // 64-bit bitmap
103+
case ZCL_EPOCH_US_ATTRIBUTE_TYPE: // Epoch Microseconds
104+
case ZCL_POSIX_MS_ATTRIBUTE_TYPE: // POSIX Milliseconds
105+
case ZCL_SYSTIME_MS_ATTRIBUTE_TYPE: // System time Milliseconds
106+
case ZCL_SYSTIME_US_ATTRIBUTE_TYPE: // System time Microseconds
107+
static_assert(std::is_same<chip::EventNumber, uint64_t>::value,
108+
"chip::EventNumber is expected to be uint64_t, change this when necessary");
109+
static_assert(std::is_same<chip::FabricId, uint64_t>::value,
110+
"chip::FabricId is expected to be uint64_t, change this when necessary");
111+
static_assert(std::is_same<chip::NodeId, uint64_t>::value,
112+
"chip::NodeId is expected to be uint64_t, change this when necessary");
113+
return ZCL_INT64U_ATTRIBUTE_TYPE;
114+
115+
case ZCL_TEMPERATURE_ATTRIBUTE_TYPE: // Temperature
116+
return ZCL_INT16S_ATTRIBUTE_TYPE;
117+
118+
default:
119+
return type;
120+
}
121+
}
122+
123+
} // namespace Internal
124+
} // namespace Compatibility
125+
} // namespace app
126+
} // namespace chip

0 commit comments

Comments
 (0)