Skip to content

Commit

Permalink
Remove lookup tables from ember attribute data buffer
Browse files Browse the repository at this point in the history
  • Loading branch information
andy31415 committed Oct 28, 2024
1 parent c50c591 commit 87a3f58
Showing 1 changed file with 58 additions and 92 deletions.
150 changes: 58 additions & 92 deletions src/app/codegen-data-model-provider/EmberAttributeDataBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <app/codegen-data-model-provider/EmberAttributeDataBuffer.h>

#include <app-common/zap-generated/attribute-type.h>
#include <app/AttributeValueEncoder.h>
#include <app/util/attribute-metadata.h>
#include <app/util/attribute-storage-null-handling.h>
#include <app/util/odd-sized-integers.h>
Expand Down Expand Up @@ -51,74 +52,47 @@ constexpr uint32_t MaxLength(EmberAttributeDataBuffer::PascalStringType s)
return std::numeric_limits<uint16_t>::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<unsigned>(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`
Expand Down Expand Up @@ -173,58 +147,61 @@ 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;

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
{
ReturnErrorOnFailure(reader.Get(value));

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;

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
{
ReturnErrorOnFailure(reader.Get(value));

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;
}

Expand Down Expand Up @@ -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<uint64_t>(info.minValue);
}
else
{
const UnsignedDecodeInfo info = GetUnsignedDecodeInfo(mAttributeType);
byteCount = info.byteCount;
nullValueAsU64 = info.maxValue;
}
const uint64_t nullValueAsU64 = isSigned
? static_cast<uint64_t>(NumericLimits::SignedMinValueToNullValue(NumericLimits::MinSignedValue(byteCount)))
: NumericLimits::UnsignedMaxValueToNullValue(NumericLimits::MaxUnsignedValue(byteCount));

VerifyOrDie(sizeof(raw_bytes) >= byteCount);
if (!reader.ReadBytes(raw_bytes, byteCount).IsSuccess())
Expand Down

0 comments on commit 87a3f58

Please sign in to comment.