Skip to content

Commit 5345c52

Browse files
Added support for bool and odd sized integer types
Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>
1 parent 9df2ffa commit 5345c52

File tree

4 files changed

+67
-29
lines changed

4 files changed

+67
-29
lines changed

src/app/clusters/scenes-server/SceneHandlerImpl.cpp

+56-24
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,26 @@
1717

1818
#include <app/clusters/scenes-server/SceneHandlerImpl.h>
1919
#include <app/util/endpoint-config-api.h>
20+
#include <app/util/odd-sized-integers.h>
2021

2122
namespace chip {
2223
namespace scenes {
2324

2425
namespace {
2526

27+
template <int ByteSize, bool IsSigned>
28+
using OddSizedInteger = app::OddSizedInteger<ByteSize, IsSigned>;
2629
using ConcreteAttributePath = app::ConcreteAttributePath;
2730
using AttributeValuePairType = app::Clusters::ScenesManagement::Structs::AttributeValuePair::Type;
2831

29-
/// ConvertByteArrayToUInt64
30-
/// @brief Helper function to convert a byte array to a uint64_t value
32+
/// ConvertDefaultValueToWorkingValue
33+
/// @brief Helper function to convert a byte array to a value of the given type.
3134
/// @param EmberAfDefaultAttributeValue & defaultValue
32-
/// @param len Length of the byte array
33-
/// @return uint64_t or int64_t Value
34-
/// @note The attribute table supports 8 bytes only for unsigned integers, 4 bytes is the maximum for signed integers
35+
/// @return Value converted to the given working type
3536
template <typename Type>
36-
Type ConvertByteArrayToType(const EmberAfDefaultAttributeValue & defaultValue, uint16_t len)
37+
Type ConvertDefaultValueToWorkingValue(const EmberAfDefaultAttributeValue & defaultValue)
3738
{
38-
if (len <= 2)
39+
if (sizeof(Type) <= 2)
3940
{
4041
return static_cast<Type>(defaultValue.defaultValue);
4142
}
@@ -56,32 +57,38 @@ Type ConvertByteArrayToType(const EmberAfDefaultAttributeValue & defaultValue, u
5657
template <typename Type>
5758
void CapAttributeID(AttributeValuePairType & aVPair, const EmberAfAttributeMetadata * metadata)
5859
{
59-
// Calculate the maximum value that can be represented with the given number of bytes
60-
Type maxValue = 0;
60+
using IntType = app::NumericAttributeTraits<Type, CHIP_CONFIG_BIG_ENDIAN_TARGET>;
61+
using WorkingType = typename IntType::WorkingType;
62+
63+
WorkingType maxValue;
64+
65+
if (metadata->IsBoolean())
66+
{
67+
aVPair.attributeValue = aVPair.attributeValue ? 1 : 0;
68+
return;
69+
}
6170

6271
// Check if the attribute type is signed
6372
if (metadata->IsSignedIntegerAttribute())
6473
{
65-
maxValue = static_cast<Type>((1ULL << (emberAfAttributeSize(metadata) * 8 - 1)) - 1);
74+
maxValue = static_cast<WorkingType>((1ULL << (emberAfAttributeSize(metadata) * 8 - 1)) - 1);
6675
}
6776
else
6877
{
69-
maxValue = static_cast<Type>((1ULL << (emberAfAttributeSize(metadata) * 8)) - 1);
78+
maxValue = static_cast<WorkingType>((1ULL << (emberAfAttributeSize(metadata) * 8)) - 1);
7079
}
7180

7281
// Check metadata for min and max values
7382
if (metadata->HasMinMax())
7483
{
7584
const EmberAfAttributeMinMaxValue * minMaxValue = metadata->defaultValue.ptrToMinMaxValue;
76-
Type minVal = ConvertByteArrayToType<Type>(minMaxValue->minValue, emberAfAttributeSize(metadata));
77-
Type maxVal = ConvertByteArrayToType<Type>(minMaxValue->maxValue, emberAfAttributeSize(metadata));
85+
WorkingType minVal = ConvertDefaultValueToWorkingValue<WorkingType>(minMaxValue->minValue);
86+
WorkingType maxVal = ConvertDefaultValueToWorkingValue<WorkingType>(minMaxValue->maxValue);
7887

7988
// Cap based on minimum value
80-
if (minVal > static_cast<Type>(aVPair.attributeValue))
89+
if (minVal > static_cast<WorkingType>(aVPair.attributeValue))
8190
{
82-
uint64_t sValue = 0;
83-
memcpy(&sValue, &minVal, sizeof(Type));
84-
aVPair.attributeValue = app::NumericAttributeTraits<uint64_t>::StorageToWorking(sValue);
91+
aVPair.attributeValue = static_cast<std::make_unsigned_t<WorkingType>>(minVal);
8592
// We assume the max is >= min therefore we can return
8693
return;
8794
}
@@ -98,18 +105,14 @@ void CapAttributeID(AttributeValuePairType & aVPair, const EmberAfAttributeMetad
98105
{
99106
if (static_cast<int64_t>(aVPair.attributeValue) > static_cast<int64_t>(maxValue))
100107
{
101-
uint64_t sValue = 0;
102-
memcpy(&sValue, &maxValue, sizeof(Type));
103-
aVPair.attributeValue = app::NumericAttributeTraits<uint64_t>::StorageToWorking(sValue);
108+
aVPair.attributeValue = static_cast<std::make_unsigned_t<WorkingType>>(maxValue);
104109
}
105110
}
106111
else
107112
{
108-
if (static_cast<uint64_t>(aVPair.attributeValue) > static_cast<uint64_t>(maxValue))
113+
if (aVPair.attributeValue > static_cast<uint64_t>(maxValue))
109114
{
110-
uint64_t sValue = 0;
111-
memcpy(&sValue, &maxValue, sizeof(Type));
112-
aVPair.attributeValue = app::NumericAttributeTraits<uint64_t>::StorageToWorking(sValue);
115+
aVPair.attributeValue = static_cast<std::make_unsigned_t<WorkingType>>(maxValue);
113116
}
114117
}
115118
}
@@ -134,15 +137,32 @@ CHIP_ERROR ValidateAttributePath(EndpointId endpoint, ClusterId cluster, Attribu
134137

135138
switch (metadata->attributeType)
136139
{
140+
case ZCL_BOOLEAN_ATTRIBUTE_TYPE:
141+
case ZCL_BITMAP8_ATTRIBUTE_TYPE:
137142
case ZCL_INT8U_ATTRIBUTE_TYPE:
138143
CapAttributeID<uint8_t>(aVPair, metadata);
139144
break;
145+
case ZCL_BITMAP16_ATTRIBUTE_TYPE:
140146
case ZCL_INT16U_ATTRIBUTE_TYPE:
141147
CapAttributeID<uint16_t>(aVPair, metadata);
142148
break;
149+
case ZCL_INT24U_ATTRIBUTE_TYPE:
150+
CapAttributeID<OddSizedInteger<3, false>>(aVPair, metadata);
151+
break;
152+
case ZCL_BITMAP32_ATTRIBUTE_TYPE:
143153
case ZCL_INT32U_ATTRIBUTE_TYPE:
144154
CapAttributeID<uint32_t>(aVPair, metadata);
145155
break;
156+
case ZCL_INT40U_ATTRIBUTE_TYPE:
157+
CapAttributeID<OddSizedInteger<5, false>>(aVPair, metadata);
158+
break;
159+
case ZCL_INT48U_ATTRIBUTE_TYPE:
160+
CapAttributeID<OddSizedInteger<6, false>>(aVPair, metadata);
161+
break;
162+
case ZCL_INT56U_ATTRIBUTE_TYPE:
163+
CapAttributeID<OddSizedInteger<7, false>>(aVPair, metadata);
164+
break;
165+
case ZCL_BITMAP64_ATTRIBUTE_TYPE:
146166
case ZCL_INT64U_ATTRIBUTE_TYPE:
147167
CapAttributeID<uint64_t>(aVPair, metadata);
148168
break;
@@ -152,9 +172,21 @@ CHIP_ERROR ValidateAttributePath(EndpointId endpoint, ClusterId cluster, Attribu
152172
case ZCL_INT16S_ATTRIBUTE_TYPE: // fallthrough
153173
CapAttributeID<int16_t>(aVPair, metadata);
154174
break;
175+
case ZCL_INT24S_ATTRIBUTE_TYPE:
176+
CapAttributeID<OddSizedInteger<3, true>>(aVPair, metadata);
177+
break;
155178
case ZCL_INT32S_ATTRIBUTE_TYPE:
156179
CapAttributeID<int32_t>(aVPair, metadata);
157180
break;
181+
case ZCL_INT40S_ATTRIBUTE_TYPE:
182+
CapAttributeID<OddSizedInteger<5, true>>(aVPair, metadata);
183+
break;
184+
case ZCL_INT48S_ATTRIBUTE_TYPE:
185+
CapAttributeID<OddSizedInteger<6, true>>(aVPair, metadata);
186+
break;
187+
case ZCL_INT56S_ATTRIBUTE_TYPE:
188+
CapAttributeID<OddSizedInteger<7, true>>(aVPair, metadata);
189+
break;
158190
case ZCL_INT64S_ATTRIBUTE_TYPE:
159191
CapAttributeID<int64_t>(aVPair, metadata);
160192
break;

src/app/tests/TestSceneTable.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -755,7 +755,7 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext)
755755
CHIP_NO_ERROR == sHandler.Deserialize(kTestEndpoint1, kOnOffClusterId, buff_span, extensionFieldValueCapOut));
756756

757757
// Verify that the output value is capped
758-
NL_TEST_ASSERT(aSuite, extensionFieldValueCapOut.attributeValueList[0].attributeValue == 0x00FFFFFF);
758+
NL_TEST_ASSERT(aSuite, extensionFieldValueCapOut.attributeValueList[0].attributeValue == 0x007FFFFF);
759759

760760
// Clear buffer
761761
memset(buffer, 0, buff_span.size());

src/app/util/attribute-metadata.h

+5
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,11 @@ struct EmberAfAttributeMetadata
158158
*/
159159
EmberAfAttributeMask mask;
160160

161+
/**
162+
* Check wether this attribute is a boolean based on its type according to the spec.
163+
*/
164+
bool IsBoolean() const { return attributeType == ZCL_BOOLEAN_ATTRIBUTE_TYPE; }
165+
161166
/**
162167
* Check wether this attribute is signed based on its type according to the spec.
163168
*/

src/app/util/mock/attribute-storage.cpp

+5-4
Original file line numberDiff line numberDiff line change
@@ -82,17 +82,18 @@ uint8_t mockAttribute4[256] = {
8282
const uint8_t defaultValueData[] = { 0x01, 0x02, 0x03, 0x04 };
8383
const uint8_t minValueData[] = { 0xFF, 0xFF, 0xFF, 0xFF };
8484
#if CHIP_CONFIG_BIG_ENDIAN_TARGET
85-
const uint8_t maxValueData[] = { 0x00, 0xFF, 0xFF, 0xFF }; // Equivalent, in big-endian, to 0x00FFFFFF
85+
const uint8_t maxValueData[] = { 0x00, 0x7F, 0xFF, 0xFF };
86+
7
8687
#else
87-
const uint8_t maxValueData[] = { 0xFF, 0xFF, 0xFF, 0x00 }; // Equivalent, in little-endian, to 0x00FFFFFF
88+
const uint8_t maxValueData[] = { 0xFF, 0xFF, 0x7F, 0x00 }; // Equivalent, in little-endian, to 0x007FFFFF
8889
#endif
8990

90-
EmberAfAttributeMinMaxValue minMaxValue = { defaultValueData, minValueData, maxValueData };
91+
EmberAfAttributeMinMaxValue minMaxValue = { defaultValueData, minValueData, maxValueData };
9192

9293
EmberAfAttributeMetadata mockmetadata = { .defaultValue = EmberAfDefaultOrMinMaxAttributeValue(&minMaxValue),
9394
.attributeId = 0,
9495
.size = sizeof(int32_t),
95-
.attributeType = ZCL_INT32S_ATTRIBUTE_TYPE,
96+
.attributeType = ZCL_INT24S_ATTRIBUTE_TYPE,
9697
.mask = ATTRIBUTE_MASK_MIN_MAX }; // namespace
9798

9899
} // namespace

0 commit comments

Comments
 (0)