@@ -26,17 +26,92 @@ namespace {
26
26
using ConcreteAttributePath = app::ConcreteAttributePath;
27
27
using AttributeValuePairType = app::Clusters::ScenesManagement::Structs::AttributeValuePair::Type;
28
28
29
+ // / IsAttributeTypeValid
30
+ // / @brief Check if the attribute type is valid for a scene extension field value according to the spec.
31
+ // / @param type Type of the attribute's metadata
32
+ // / @return
33
+ bool IsSceneValidAttributeType (EmberAfAttributeType type)
34
+ {
35
+ return (type == ZCL_INT8U_ATTRIBUTE_TYPE || type == ZCL_INT16U_ATTRIBUTE_TYPE || type == ZCL_INT32U_ATTRIBUTE_TYPE ||
36
+ type == ZCL_INT64U_ATTRIBUTE_TYPE || type == ZCL_INT8S_ATTRIBUTE_TYPE || type == ZCL_INT16S_ATTRIBUTE_TYPE ||
37
+ type == ZCL_INT32S_ATTRIBUTE_TYPE || type == ZCL_INT64S_ATTRIBUTE_TYPE);
38
+ }
39
+
40
+ // / IsSignedAttribute
41
+ // / @brief Compare the attribute type to the signed attribute types in ZCL and return true if it is signed.
42
+ // / @param attributeType metadata's attribute type
43
+ // / @return
44
+ bool IsSignedAttribute (EmberAfAttributeType attributeType)
45
+ {
46
+ return (attributeType >= ZCL_INT8S_ATTRIBUTE_TYPE && attributeType <= ZCL_INT64S_ATTRIBUTE_TYPE);
47
+ }
48
+
49
+ // / ConvertByteArrayToUInt64
50
+ // / @brief Helper function to convert a byte array to a uint64_t value
51
+ // / @param EmberAfDefaultAttributeValue & defaultValue
52
+ // / @param len Length of the byte array
53
+ // / @return uint64_t Value
54
+ // / @note The attribute table supports 8 bytes only for unsigned integers, 4 bytes is the maximum for signed integers
55
+ uint64_t ConvertByteArrayToUInt64 (const EmberAfDefaultAttributeValue & defaultValue, uint16_t len)
56
+ {
57
+ if (len <= 2 )
58
+ {
59
+ return static_cast <uint64_t >(defaultValue.defaultValue );
60
+ }
61
+ else
62
+ {
63
+ uint64_t result = 0 ;
64
+ const uint8_t * val = defaultValue.ptrToDefaultValue ;
65
+ for (size_t i = 0 ; i < len; i++)
66
+ {
67
+ result = (result << 8 ) | val[(CHIP_CONFIG_BIG_ENDIAN_TARGET ? i : (len - 1 ) - i)];
68
+ }
69
+ return result;
70
+ }
71
+ }
72
+
29
73
// / CapAttributeID
30
- // / Cap the attribute value based on the attribute type size
74
+ // / Cap the attribute value based on the attribute's min and max if they are defined,
75
+ // / or based on the attribute's size if they are not.
31
76
// / @param[in] aVPair AttributeValuePairType
32
77
// / @param[in] metadata EmberAfAttributeMetadata
33
78
// /
34
79
void CapAttributeID (AttributeValuePairType & aVPair, const EmberAfAttributeMetadata * metadata)
35
80
{
36
81
// Calculate the maximum value that can be represented with the given number of bytes
37
- uint64_t maxValue = ( 1ULL << (metadata-> size * 8 )) - 1 ;
82
+ uint64_t maxValue = 0 ;
38
83
39
- // If the attribute ID is greater than the maximum value, cap it
84
+ // Check if the attribute type is signed
85
+ if (IsSignedAttribute (metadata->attributeType ))
86
+ {
87
+ maxValue = (1ULL << ((emberAfAttributeSize (metadata) * 8 ) - 1 )) - 1 ;
88
+ }
89
+ else
90
+ {
91
+ maxValue = (1ULL << (emberAfAttributeSize (metadata) * 8 )) - 1 ;
92
+ }
93
+
94
+ // Check metadata for min and max values
95
+ if ((metadata->mask & ATTRIBUTE_MASK_MIN_MAX) && metadata->defaultValue .ptrToMinMaxValue )
96
+ {
97
+ const EmberAfAttributeMinMaxValue * minMaxValue = metadata->defaultValue .ptrToMinMaxValue ;
98
+ uint64_t minVal = ConvertByteArrayToUInt64 (minMaxValue->minValue , emberAfAttributeSize (metadata));
99
+ uint64_t maxVal = ConvertByteArrayToUInt64 (minMaxValue->maxValue , emberAfAttributeSize (metadata));
100
+
101
+ // Cap based on minValue
102
+ if (minVal > aVPair.attributeValue )
103
+ {
104
+ aVPair.attributeValue = minVal;
105
+ }
106
+
107
+ // Adjust maxValue if greater than the meta data's max value
108
+ if (maxVal < maxValue)
109
+ {
110
+ maxValue = maxVal;
111
+ }
112
+ }
113
+
114
+ // Cap based on maximum value
40
115
if (aVPair.attributeValue > maxValue)
41
116
{
42
117
aVPair.attributeValue = maxValue;
@@ -50,7 +125,6 @@ void CapAttributeID(AttributeValuePairType & aVPair, const EmberAfAttributeMetad
50
125
// / @return CHIP_ERROR_UNSUPPORTED_ATTRIBUTE if the attribute does not exist for a given cluster or is not scenable
51
126
// / @note This will allways fail for global list attributes. If we do want to make them scenable someday, we will need to
52
127
// / use a different validation method.
53
- // TODO: Assess if (and how) we also want to throw an error if the attribute value is out of range
54
128
// TODO: Add check for "S" quality to determine if the attribute is scenable once suported :
55
129
// https://github.com/project-chip/connectedhomeip/issues/24177
56
130
CHIP_ERROR ValidateAttributePath (EndpointId endpoint, ClusterId cluster, AttributeValuePairType & aVPair)
@@ -62,6 +136,11 @@ CHIP_ERROR ValidateAttributePath(EndpointId endpoint, ClusterId cluster, Attribu
62
136
return CHIP_ERROR_UNSUPPORTED_ATTRIBUTE;
63
137
}
64
138
139
+ if (!IsSceneValidAttributeType (metadata->attributeType ))
140
+ {
141
+ return CHIP_ERROR_UNSUPPORTED_ATTRIBUTE;
142
+ }
143
+
65
144
// Cap value based on the attribute type size
66
145
CapAttributeID (aVPair, metadata);
67
146
0 commit comments