Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove lookup tables from ember attribute data buffer #36273

Merged
merged 1 commit into from
Oct 28, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading