From 87a3f58b6bee5e602f676ff9d66dae94379c0211 Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Mon, 28 Oct 2024 14:31:01 -0400 Subject: [PATCH] Remove lookup tables from ember attribute data buffer --- .../EmberAttributeDataBuffer.cpp | 150 +++++++----------- 1 file changed, 58 insertions(+), 92 deletions(-) diff --git a/src/app/codegen-data-model-provider/EmberAttributeDataBuffer.cpp b/src/app/codegen-data-model-provider/EmberAttributeDataBuffer.cpp index 7eb2e9d2b1d2ea..1296e7190833fd 100644 --- a/src/app/codegen-data-model-provider/EmberAttributeDataBuffer.cpp +++ b/src/app/codegen-data-model-provider/EmberAttributeDataBuffer.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -51,74 +52,47 @@ constexpr uint32_t MaxLength(EmberAttributeDataBuffer::PascalStringType s) return std::numeric_limits::max() - 1; } -struct UnsignedDecodeInfo +constexpr unsigned GetByteCountOfIntegerType(EmberAfAttributeType type) { - unsigned byteCount; - uint64_t maxValue; - - constexpr UnsignedDecodeInfo(unsigned bytes) : byteCount(bytes), maxValue(NumericLimits::MaxUnsignedValue(bytes)) {} -}; - -constexpr UnsignedDecodeInfo GetUnsignedDecodeInfo(EmberAfAttributeType type) -{ - - switch (type) - { - case ZCL_INT8U_ATTRIBUTE_TYPE: // Unsigned 8-bit integer - return UnsignedDecodeInfo(1); - case ZCL_INT16U_ATTRIBUTE_TYPE: // Unsigned 16-bit integer - return UnsignedDecodeInfo(2); - case ZCL_INT24U_ATTRIBUTE_TYPE: // Unsigned 24-bit integer - return UnsignedDecodeInfo(3); - case ZCL_INT32U_ATTRIBUTE_TYPE: // Unsigned 32-bit integer - return UnsignedDecodeInfo(4); - case ZCL_INT40U_ATTRIBUTE_TYPE: // Unsigned 40-bit integer - return UnsignedDecodeInfo(5); - case ZCL_INT48U_ATTRIBUTE_TYPE: // Unsigned 48-bit integer - return UnsignedDecodeInfo(6); - case ZCL_INT56U_ATTRIBUTE_TYPE: // Unsigned 56-bit integer - return UnsignedDecodeInfo(7); - case ZCL_INT64U_ATTRIBUTE_TYPE: // Unsigned 64-bit integer - return UnsignedDecodeInfo(8); - } - chipDie(); -} - -struct SignedDecodeInfo -{ - unsigned byteCount; - int64_t minValue; - int64_t maxValue; - - constexpr SignedDecodeInfo(unsigned bytes) : - byteCount(bytes), minValue(NumericLimits::MinSignedValue(bytes)), maxValue(NumericLimits::MaxSignedValue(bytes)) - {} -}; - -constexpr SignedDecodeInfo GetSignedDecodeInfo(EmberAfAttributeType type) -{ - - switch (type) - { - case ZCL_INT8S_ATTRIBUTE_TYPE: // Signed 8-bit integer - return SignedDecodeInfo(1); - case ZCL_INT16S_ATTRIBUTE_TYPE: // Signed 16-bit integer - return SignedDecodeInfo(2); - case ZCL_INT24S_ATTRIBUTE_TYPE: // Signed 24-bit integer - return SignedDecodeInfo(3); - case ZCL_INT32S_ATTRIBUTE_TYPE: // Signed 32-bit integer - return SignedDecodeInfo(4); - case ZCL_INT40S_ATTRIBUTE_TYPE: // Signed 40-bit integer - return SignedDecodeInfo(5); - case ZCL_INT48S_ATTRIBUTE_TYPE: // Signed 48-bit integer - return SignedDecodeInfo(6); - case ZCL_INT56S_ATTRIBUTE_TYPE: // Signed 56-bit integer - return SignedDecodeInfo(7); - case ZCL_INT64S_ATTRIBUTE_TYPE: // Signed 64-bit integer - return SignedDecodeInfo(8); - } - chipDie(); + // This TERRIBLE bit fiddling, however it is small in flash + // and we assert statically the actual values we care about + + // ZCL_INT8U_ATTRIBUTE_TYPE = 0x20, // Unsigned 8-bit integer + // ZCL_INT16U_ATTRIBUTE_TYPE = 0x21, // Unsigned 16-bit integer + // ZCL_INT24U_ATTRIBUTE_TYPE = 0x22, // Unsigned 24-bit integer + // ZCL_INT32U_ATTRIBUTE_TYPE = 0x23, // Unsigned 32-bit integer + // ZCL_INT40U_ATTRIBUTE_TYPE = 0x24, // Unsigned 40-bit integer + // ZCL_INT48U_ATTRIBUTE_TYPE = 0x25, // Unsigned 48-bit integer + // ZCL_INT56U_ATTRIBUTE_TYPE = 0x26, // Unsigned 56-bit integer + // ZCL_INT64U_ATTRIBUTE_TYPE = 0x27, // Unsigned 64-bit integer + // + // ZCL_INT8S_ATTRIBUTE_TYPE = 0x28, // Signed 8-bit integer + // ZCL_INT16S_ATTRIBUTE_TYPE = 0x29, // Signed 16-bit integer + // ZCL_INT24S_ATTRIBUTE_TYPE = 0x2A, // Signed 24-bit integer + // ZCL_INT32S_ATTRIBUTE_TYPE = 0x2B, // Signed 32-bit integer + // ZCL_INT40S_ATTRIBUTE_TYPE = 0x2C, // Signed 40-bit integer + // ZCL_INT48S_ATTRIBUTE_TYPE = 0x2D, // Signed 48-bit integer + // ZCL_INT56S_ATTRIBUTE_TYPE = 0x2E, // Signed 56-bit integer + // ZCL_INT64S_ATTRIBUTE_TYPE = 0x2F, // Signed 64-bit integer + + return (static_cast(type) % 8) + 1; } +static_assert(GetByteCountOfIntegerType(ZCL_INT8U_ATTRIBUTE_TYPE) == 1); +static_assert(GetByteCountOfIntegerType(ZCL_INT8S_ATTRIBUTE_TYPE) == 1); +static_assert(GetByteCountOfIntegerType(ZCL_INT16U_ATTRIBUTE_TYPE) == 2); +static_assert(GetByteCountOfIntegerType(ZCL_INT16S_ATTRIBUTE_TYPE) == 2); +static_assert(GetByteCountOfIntegerType(ZCL_INT24U_ATTRIBUTE_TYPE) == 3); +static_assert(GetByteCountOfIntegerType(ZCL_INT24S_ATTRIBUTE_TYPE) == 3); +static_assert(GetByteCountOfIntegerType(ZCL_INT32U_ATTRIBUTE_TYPE) == 4); +static_assert(GetByteCountOfIntegerType(ZCL_INT32S_ATTRIBUTE_TYPE) == 4); +static_assert(GetByteCountOfIntegerType(ZCL_INT40U_ATTRIBUTE_TYPE) == 5); +static_assert(GetByteCountOfIntegerType(ZCL_INT40S_ATTRIBUTE_TYPE) == 5); +static_assert(GetByteCountOfIntegerType(ZCL_INT48U_ATTRIBUTE_TYPE) == 6); +static_assert(GetByteCountOfIntegerType(ZCL_INT48S_ATTRIBUTE_TYPE) == 6); +static_assert(GetByteCountOfIntegerType(ZCL_INT56U_ATTRIBUTE_TYPE) == 7); +static_assert(GetByteCountOfIntegerType(ZCL_INT56S_ATTRIBUTE_TYPE) == 7); +static_assert(GetByteCountOfIntegerType(ZCL_INT64U_ATTRIBUTE_TYPE) == 8); +static_assert(GetByteCountOfIntegerType(ZCL_INT64S_ATTRIBUTE_TYPE) == 8); /// Encodes the string of type stringType pointed to by `reader` into the TLV `writer`. /// Then encoded string will be at tag `tag` and of type `tlvType` @@ -173,7 +147,8 @@ CHIP_ERROR EncodeString(EmberAttributeDataBuffer::PascalStringType stringType, T CHIP_ERROR EmberAttributeDataBuffer::DecodeUnsignedInteger(chip::TLV::TLVReader & reader, EndianWriter & writer) { - UnsignedDecodeInfo info = GetUnsignedDecodeInfo(mAttributeType); + const unsigned byteCount = GetByteCountOfIntegerType(mAttributeType); + const uint64_t maxValue = NumericLimits::MaxUnsignedValue(byteCount); // Any size of integer can be read by TLV getting 64-bit integers uint64_t value; @@ -181,7 +156,7 @@ CHIP_ERROR EmberAttributeDataBuffer::DecodeUnsignedInteger(chip::TLV::TLVReader if (reader.GetType() == TLV::kTLVType_Null) { // we know mIsNullable due to the check at the top of ::Decode - value = NumericLimits::UnsignedMaxValueToNullValue(info.maxValue); + value = NumericLimits::UnsignedMaxValueToNullValue(maxValue); } else { @@ -189,20 +164,22 @@ CHIP_ERROR EmberAttributeDataBuffer::DecodeUnsignedInteger(chip::TLV::TLVReader bool valid = // Value is in [0, max] RANGE - (value <= info.maxValue) + (value <= maxValue) // Nullable values reserve a specific value to mean NULL - && !(mIsNullable && (value == NumericLimits::UnsignedMaxValueToNullValue(info.maxValue))); + && !(mIsNullable && (value == NumericLimits::UnsignedMaxValueToNullValue(maxValue))); VerifyOrReturnError(valid, CHIP_IM_GLOBAL_STATUS(ConstraintError)); } - writer.EndianPut(value, info.byteCount); + writer.EndianPut(value, byteCount); return CHIP_NO_ERROR; } CHIP_ERROR EmberAttributeDataBuffer::DecodeSignedInteger(chip::TLV::TLVReader & reader, EndianWriter & writer) { - SignedDecodeInfo info = GetSignedDecodeInfo(mAttributeType); + const unsigned byteCount = GetByteCountOfIntegerType(mAttributeType); + const int64_t minValue = NumericLimits::MinSignedValue(byteCount); + const int64_t maxValue = NumericLimits::MaxSignedValue(byteCount); // Any size of integer can be read by TLV getting 64-bit integers int64_t value; @@ -210,7 +187,7 @@ CHIP_ERROR EmberAttributeDataBuffer::DecodeSignedInteger(chip::TLV::TLVReader & if (reader.GetType() == TLV::kTLVType_Null) { // we know mIsNullable due to the check at the top of ::Decode - value = NumericLimits::SignedMinValueToNullValue(info.minValue); + value = NumericLimits::SignedMinValueToNullValue(minValue); } else { @@ -218,13 +195,13 @@ CHIP_ERROR EmberAttributeDataBuffer::DecodeSignedInteger(chip::TLV::TLVReader & bool valid = // Value is in [min, max] RANGE - ((value >= info.minValue) && (value <= info.maxValue)) + ((value >= minValue) && (value <= maxValue)) // Nullable values reserve a specific value to mean NULL - && !(mIsNullable && (value == NumericLimits::SignedMinValueToNullValue(info.minValue))); + && !(mIsNullable && (value == NumericLimits::SignedMinValueToNullValue(minValue))); VerifyOrReturnError(valid, CHIP_IM_GLOBAL_STATUS(ConstraintError)); } - writer.EndianPutSigned(value, info.byteCount); + writer.EndianPutSigned(value, byteCount); return CHIP_NO_ERROR; } @@ -384,23 +361,12 @@ CHIP_ERROR EmberAttributeDataBuffer::EncodeInteger(chip::TLV::TLVWriter & writer uint8_t raw_bytes[8]; - const bool isSigned = IsSignedAttributeType(mAttributeType); - - unsigned byteCount; - uint64_t nullValueAsU64; + const bool isSigned = IsSignedAttributeType(mAttributeType); + const unsigned byteCount = GetByteCountOfIntegerType(mAttributeType); - if (isSigned) - { - const SignedDecodeInfo info = GetSignedDecodeInfo(mAttributeType); - byteCount = info.byteCount; - nullValueAsU64 = static_cast(info.minValue); - } - else - { - const UnsignedDecodeInfo info = GetUnsignedDecodeInfo(mAttributeType); - byteCount = info.byteCount; - nullValueAsU64 = info.maxValue; - } + const uint64_t nullValueAsU64 = isSigned + ? static_cast(NumericLimits::SignedMinValueToNullValue(NumericLimits::MinSignedValue(byteCount))) + : NumericLimits::UnsignedMaxValueToNullValue(NumericLimits::MaxUnsignedValue(byteCount)); VerifyOrDie(sizeof(raw_bytes) >= byteCount); if (!reader.ReadBytes(raw_bytes, byteCount).IsSuccess())