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

Implement the codegen-data-model Write support #34139

Merged
merged 98 commits into from
Jul 5, 2024
Merged
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
98 commits
Select commit Hold shift + click to select a range
ba43ab7
Initial copy/merge of the codegendatamodel::write support
andy31415 Jun 28, 2024
c13f3ce
Restyle
andy31415 Jun 28, 2024
79f9603
Remove the error translation for ACL checks for attribute writes
andy31415 Jun 28, 2024
3648820
Comment correction after special access error code guarantees were re…
andy31415 Jun 28, 2024
f2911ef
Set the namespace for DataModel to resolve nameclash for android builds
andy31415 Jun 28, 2024
fedfc79
Restyle
andy31415 Jun 28, 2024
2a632f3
Some changes to make darwin builds happy
andy31415 Jun 28, 2024
e22cbf9
Merge branch 'master' into imdm/4-ember-write-attribute
andreilitvin Jul 2, 2024
97490f9
Do not clang-tidy on CodegenDataModel_Write
andreilitvin Jul 2, 2024
a0bdfd2
Update src/app/codegen-data-model/CodegenDataModel_Write.cpp
andy31415 Jul 3, 2024
7f30755
Update src/app/codegen-data-model/CodegenDataModel_Write.cpp
andy31415 Jul 3, 2024
8a158ef
Update src/app/codegen-data-model/CodegenDataModel_Write.cpp
andy31415 Jul 3, 2024
6566f31
Merge branch 'master' into imdm/4-ember-write-attribute
andy31415 Jul 3, 2024
55e45d4
Use little endian encoding for pascal long strings, since this is wha…
andy31415 Jul 3, 2024
1b54c1a
Restyle
andy31415 Jul 3, 2024
53458e4
Merge branch 'imdm/4-ember-write-attribute' of github.com:andy31415/c…
andy31415 Jul 3, 2024
2518cba
Fix code to compile and pass tests
andy31415 Jul 3, 2024
4fd538a
Code review comments
andy31415 Jul 3, 2024
77bc4fe
Comment update
andy31415 Jul 3, 2024
929b5f6
Update based on code review feedback
andy31415 Jul 3, 2024
1c15644
Wrong condition. Fixed
andy31415 Jul 3, 2024
b61b3aa
Return invalid value to match ember-compatibility-functions
andy31415 Jul 3, 2024
0992f6d
switch invalid data point to constraint error for return codes
andy31415 Jul 3, 2024
5b7d536
Fix code review comments: comments and return unsupportedaccess
andy31415 Jul 3, 2024
65baf80
Remove useless comment - error check should be clear enough
andy31415 Jul 3, 2024
76b7e7d
Comment update
andy31415 Jul 3, 2024
1f79a52
Re-arrange code for read only and timed
andy31415 Jul 3, 2024
a629992
Re-format the read only checks a bit
andy31415 Jul 3, 2024
3741c61
Use CHIP_ERROR_NOT_FOUND
andy31415 Jul 3, 2024
e252bb0
Separate out variable names
andy31415 Jul 3, 2024
2b0bc7a
Slight updated code layout
andy31415 Jul 3, 2024
3296766
Updated return value for chip error
andy31415 Jul 3, 2024
16cc088
Updated test to verifyordie instead of just logging errors
andy31415 Jul 3, 2024
682b73a
Update src/app/codegen-data-model/tests/TestCodegenModelViaMocks.cpp
andy31415 Jul 3, 2024
37f4298
Update based on review feedback
andy31415 Jul 3, 2024
d50ac27
Merge branch 'imdm/4-ember-write-attribute' of github.com:andy31415/c…
andy31415 Jul 3, 2024
03bb45f
Fix endianess and copying in test code
andy31415 Jul 3, 2024
8b630b0
Restyle
andy31415 Jul 3, 2024
412d681
Updated comment
andy31415 Jul 3, 2024
413b5e7
Update src/app/codegen-data-model/tests/TestCodegenModelViaMocks.cpp
andy31415 Jul 3, 2024
8b1a1b1
Add unit test for "lowest signed value write"
andy31415 Jul 3, 2024
516a1c9
Restyle
andy31415 Jul 3, 2024
2aed85d
A constraint error update and better tests for AAI returning errors
andy31415 Jul 3, 2024
1a48fc9
One more test for invalid ember usage
andy31415 Jul 3, 2024
6fc8d17
Restyle
andy31415 Jul 3, 2024
e93665b
more tests for more coverage
andy31415 Jul 3, 2024
0e4398b
Comment update
andy31415 Jul 3, 2024
41403a4
Fix comment
andy31415 Jul 3, 2024
39da04f
One more test for more coverage
andy31415 Jul 3, 2024
c5feac7
Also cover writing non-null value to nullable attribute
andy31415 Jul 3, 2024
6b05337
Fix the ember string usage
andy31415 Jul 3, 2024
46a5ad2
Update src/app/codegen-data-model/CodegenDataModel_Read.cpp
andy31415 Jul 3, 2024
8631b41
Update src/app/codegen-data-model/CodegenDataModel_Read.cpp
andy31415 Jul 3, 2024
5a4bd3c
Remove duplicate code
andy31415 Jul 3, 2024
6e0d9d1
Update src/app/codegen-data-model/CodegenDataModel_Write.cpp
andy31415 Jul 3, 2024
4bdc2ee
Remove chip::app:: prefix in unit test since we have a top level using
andy31415 Jul 3, 2024
e6e5b19
Merge branch 'imdm/4-ember-write-attribute' of github.com:andy31415/c…
andy31415 Jul 3, 2024
f6e1bb9
Fix copy & paste encode to decode
andy31415 Jul 3, 2024
4bd7e28
Replace decoded with converted
andy31415 Jul 3, 2024
8e2383c
Update src/app/codegen-data-model/CodegenDataModel_Write.cpp
andy31415 Jul 3, 2024
e921ead
Merge branch 'imdm/4-ember-write-attribute' of github.com:andy31415/c…
andy31415 Jul 3, 2024
575b492
Start using Failure for invalid data type instead of unsupported read…
andy31415 Jul 3, 2024
7b5bb9f
Fix comments
andy31415 Jul 3, 2024
da1aae4
Updated encode/decode comment
andy31415 Jul 3, 2024
dc1c658
Use failure instead of constraint error
andy31415 Jul 3, 2024
4dab89b
Update src/app/codegen-data-model/CodegenDataModel_Write.cpp
andy31415 Jul 3, 2024
e39cb80
Update src/app/codegen-data-model/CodegenDataModel_Write.cpp
andy31415 Jul 3, 2024
f58fee8
Update src/app/codegen-data-model/CodegenDataModel_Write.cpp
andy31415 Jul 3, 2024
380ac9f
Merge branch 'imdm/4-ember-write-attribute' of github.com:andy31415/c…
andy31415 Jul 3, 2024
8e87177
Use dataversion mismatch for write without a version
andy31415 Jul 3, 2024
572a7f3
Add extra IsGlobalAttribute check
andy31415 Jul 3, 2024
84fb496
use external writes for the ember write logic, so that we have extra …
andy31415 Jul 3, 2024
db487b4
Updated comments
andy31415 Jul 3, 2024
2d216ab
more comments
andy31415 Jul 3, 2024
865b80a
Restyle
andy31415 Jul 3, 2024
e542231
Use emberAfWriteAttribute
andy31415 Jul 4, 2024
5664e7b
Add comment about ember-string
andy31415 Jul 4, 2024
1df88a2
Restyle
andy31415 Jul 4, 2024
1475193
Add context to unit tests, make write do the marking of dirty paths
andy31415 Jul 4, 2024
b26edf1
Add some unit tests for dirty path handling
andy31415 Jul 4, 2024
faac4fb
Move the change callback around a bit
andy31415 Jul 4, 2024
56fe685
Restyle
andy31415 Jul 4, 2024
94392d6
Fixed unit tests to support size checks
andy31415 Jul 4, 2024
2ab7dd7
Add unit test for invalid data
andy31415 Jul 4, 2024
ecd4fd4
Restyle
andy31415 Jul 4, 2024
73ff5ae
Fix linter errors
andy31415 Jul 4, 2024
c36c64e
Update to make size enforcement and guarantees clearer
andy31415 Jul 4, 2024
9f1b7de
use size_t for getlength sizes
andy31415 Jul 4, 2024
0eb94b5
Review comments and updated code to compile for android
andy31415 Jul 4, 2024
e5fffd6
make datamodel unambiguous
andy31415 Jul 5, 2024
a379908
More fixes for clang compilation for DataModel scoping
andy31415 Jul 5, 2024
b78f27a
Restyle
andy31415 Jul 5, 2024
e10fefc
Try to make darwin compiler happy ... ssize_t vs size_t
andy31415 Jul 5, 2024
40ae352
Fix typo
andy31415 Jul 5, 2024
a6e2ddb
Restyle
andy31415 Jul 5, 2024
9bbe92a
Merge branch 'master' into imdm/4-ember-write-attribute
andy31415 Jul 5, 2024
1c04a69
Code review updates
andy31415 Jul 5, 2024
08c4fbd
Undo submodule update
andy31415 Jul 5, 2024
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
12 changes: 11 additions & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,17 @@ jobs:
type-safe setters
if: always()
run: |
git grep -I -n 'emberAfWriteAttribute' -- './*' ':(exclude).github/workflows/lint.yml' ':(exclude)zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp' ':(exclude)src/app/zap-templates/templates/app/attributes/Accessors-src.zapt' ':(exclude)src/app/util/attribute-table.cpp' ':(exclude)examples/common/pigweed/rpc_services/Attributes.h' ':(exclude)src/app/util/attribute-table.h' ':(exclude)src/app/util/ember-compatibility-functions.cpp' && exit 1 || exit 0
git grep -I -n 'emberAfWriteAttribute' -- './*' \
':(exclude).github/workflows/lint.yml' \
':(exclude)examples/common/pigweed/rpc_services/Attributes.h' \
':(exclude)src/app/codegen-data-model/CodegenDataModel_Write.cpp' \
':(exclude)src/app/codegen-data-model/tests/EmberReadWriteOverride.cpp' \
':(exclude)src/app/util/attribute-table.cpp' \
':(exclude)src/app/util/attribute-table.h' \
':(exclude)src/app/util/ember-compatibility-functions.cpp' \
':(exclude)src/app/zap-templates/templates/app/attributes/Accessors-src.zapt' \
':(exclude)zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp' \
&& exit 1 || exit 0

# Run ruff python linter
- name: Check for errors using ruff Python linter
Expand Down
14 changes: 9 additions & 5 deletions src/app/codegen-data-model/CodegenDataModel_Read.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
#include <app/util/attribute-storage.h>
#include <app/util/ember-global-attribute-access-interface.h>
#include <app/util/ember-io-storage.h>
#include <app/util/ember-strings.h>
#include <app/util/endpoint-config-api.h>
#include <app/util/odd-sized-integers.h>
#include <lib/core/CHIPError.h>
Expand Down Expand Up @@ -90,7 +89,12 @@ struct ShortPascalString
using LengthType = uint8_t;
static constexpr LengthType kNullLength = 0xFF;

static LengthType GetLength(const uint8_t * buffer) { return emberAfStringLength(buffer); }
static LengthType GetLength(const uint8_t * buffer)
{
// NOTE: we do NOT use emberAfLongStringLength because that will result in 0 length
// for null strings
return *buffer;
}
};

/// Metadata of what a ember/pascal LONG string means (prepended by a u16 length)
Expand Down Expand Up @@ -118,7 +122,7 @@ template <class OUT, class ENCODING>
std::optional<OUT> ExtractEmberString(ByteSpan data)
{
VerifyOrDie(sizeof(typename ENCODING::LengthType) <= data.size());
typename ENCODING::LengthType len = ENCODING::GetLength(data.data());
auto len = ENCODING::GetLength(data.data());

if (len == ENCODING::kNullLength)
{
Expand Down Expand Up @@ -238,7 +242,7 @@ CHIP_ERROR EncodeEmberValue(ByteSpan data, const EmberAfAttributeMetadata * meta
return EncodeStringLike<ByteSpan, LongPascalString>(data, isNullable, encoder);
default:
ChipLogError(DataManagement, "Attribute type 0x%x not handled", static_cast<int>(metadata->attributeType));
return CHIP_IM_GLOBAL_STATUS(ConstraintError);
return CHIP_IM_GLOBAL_STATUS(Failure);
}
}

Expand Down Expand Up @@ -270,7 +274,7 @@ CHIP_ERROR CodegenDataModel::ReadAttribute(const InteractionModel::ReadAttribute
ReturnErrorCodeIf(err != CHIP_ERROR_ACCESS_DENIED, err);

// Implementation of 8.4.3.2 of the spec for path expansion
if (request.path.mExpanded && (err == CHIP_ERROR_ACCESS_DENIED))
if (request.path.mExpanded)
{
return CHIP_NO_ERROR;
}
Expand Down
86 changes: 60 additions & 26 deletions src/app/codegen-data-model/CodegenDataModel_Write.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,13 @@
#include <app/RequiredPrivilege.h>
#include <app/codegen-data-model/EmberMetadata.h>
#include <app/data-model/FabricScoped.h>
#include <app/reporting/reporting.h>
#include <app/util/af-types.h>
#include <app/util/attribute-metadata.h>
#include <app/util/attribute-storage-detail.h>
#include <app/util/attribute-storage-null-handling.h>
#include <app/util/attribute-table-detail.h>
#include <app/util/attribute-table.h>
#include <app/util/ember-io-storage.h>
#include <app/util/ember-strings.h>
#include <app/util/odd-sized-integers.h>
Expand Down Expand Up @@ -92,14 +95,14 @@ struct LongPascalString
static_assert(sizeof(ShortPascalString::LengthType) == 1);
static_assert(sizeof(LongPascalString::LengthType) == 2);

/// Encode the value stored in 'decoder' into an ember format string 'out'
/// Convert the value stored in 'decoder' into an ember format span 'out'
///
/// The value encoded will be of type T (e.g. CharSpan or ByteSpan) and it will be encoded
/// The value converted will be of type T (e.g. CharSpan or ByteSpan) and it will be converted
/// via the given ENCODING (i.e. ShortPascalString or LongPascalString)
///
/// isNullable defines if the value of NULL is allowed to be encoded.
/// isNullable defines if the value of NULL is allowed to be converted.
template <typename T, class ENCODING>
CHIP_ERROR DecodeStringLikeIntoEmberBuffer(AttributeValueDecoder decoder, bool isNullable, MutableByteSpan out)
CHIP_ERROR DecodeStringLikeIntoEmberBuffer(AttributeValueDecoder decoder, bool isNullable, MutableByteSpan & out)
{
T workingValue;

Expand All @@ -112,6 +115,7 @@ CHIP_ERROR DecodeStringLikeIntoEmberBuffer(AttributeValueDecoder decoder, bool i
{
VerifyOrReturnError(out.size() >= sizeof(typename ENCODING::LengthType), CHIP_ERROR_BUFFER_TOO_SMALL);
ENCODING::SetLength(out.data(), ENCODING::kNullLength);
out.reduce_size(sizeof(typename ENCODING::LengthType));
return CHIP_NO_ERROR;
}

Expand All @@ -123,7 +127,7 @@ CHIP_ERROR DecodeStringLikeIntoEmberBuffer(AttributeValueDecoder decoder, bool i
ReturnErrorOnFailure(decoder.Decode(workingValue));
}

typename ENCODING::LengthType len = static_cast<typename ENCODING::LengthType>(workingValue.size());
auto len = static_cast<typename ENCODING::LengthType>(workingValue.size());
VerifyOrReturnError(out.size() >= sizeof(len) + len, CHIP_ERROR_BUFFER_TOO_SMALL);

uint8_t * output_buffer = out.data();
Expand All @@ -132,15 +136,17 @@ CHIP_ERROR DecodeStringLikeIntoEmberBuffer(AttributeValueDecoder decoder, bool i
output_buffer += sizeof(len);

memcpy(output_buffer, workingValue.data(), workingValue.size());
output_buffer += workingValue.size();

out.reduce_size(output_buffer - out.data());
return CHIP_NO_ERROR;
}

/// Encodes a numeric data value of type T from the given ember-encoded buffer `data`.
/// Decodes a numeric data value of type T from the `decoder` into a ember-encoded buffer `out`
///
/// isNullable defines if the value of NULL is allowed to be encoded.
/// isNullable defines if the value of NULL is allowed to be decoded.
template <typename T>
CHIP_ERROR DecodeIntoEmberBuffer(AttributeValueDecoder & decoder, bool isNullable, MutableByteSpan out)
CHIP_ERROR DecodeIntoEmberBuffer(AttributeValueDecoder & decoder, bool isNullable, MutableByteSpan & out)
{
using Traits = NumericAttributeTraits<T>;
typename Traits::StorageType storageValue;
Expand All @@ -156,7 +162,7 @@ CHIP_ERROR DecodeIntoEmberBuffer(AttributeValueDecoder & decoder, bool isNullabl
}
else
{
// This guards against trying to encode something that overlaps nullable, for example
// This guards against trying to decode something that overlaps nullable, for example
// Nullable<uint8_t>(0xFF) is not representable because 0xFF is the encoding of NULL in ember
// as well as odd-sized integers (e.g. full 32-bit value like 0x11223344 cannot be written
// to a 3-byte odd-sized integger).
Expand Down Expand Up @@ -185,15 +191,20 @@ CHIP_ERROR DecodeIntoEmberBuffer(AttributeValueDecoder & decoder, bool isNullabl
// The decoding + ToAttributeStoreRepresentation will result in data being
// stored in native format/byteorder, suitable to directly be stored in the data store
memcpy(out.data(), data, sizeof(storageValue));
out.reduce_size(sizeof(storageValue));

return CHIP_NO_ERROR;
}

/// Read the data from "decoder" into an ember-formatted buffer "out"
///
/// `out` is a in/out buffer:
/// - its initial size determines the maximum size of the buffer
/// - its output size reflects the actual data size
///
/// Uses the attribute `metadata` to determine how the data is to be encoded into out.
CHIP_ERROR DecodeValueIntoEmberBuffer(AttributeValueDecoder & decoder, const EmberAfAttributeMetadata * metadata,
MutableByteSpan out)
MutableByteSpan & out)
{
VerifyOrReturnError(metadata != nullptr, CHIP_ERROR_INVALID_ARGUMENT);

Expand Down Expand Up @@ -249,7 +260,7 @@ CHIP_ERROR DecodeValueIntoEmberBuffer(AttributeValueDecoder & decoder, const Emb
return DecodeStringLikeIntoEmberBuffer<ByteSpan, LongPascalString>(decoder, isNullable, out);
default:
ChipLogError(DataManagement, "Attribute type 0x%x not handled", static_cast<int>(metadata->attributeType));
return CHIP_IM_GLOBAL_STATUS(ConstraintError);
return CHIP_IM_GLOBAL_STATUS(Failure);
}
}

Expand All @@ -258,7 +269,7 @@ CHIP_ERROR DecodeValueIntoEmberBuffer(AttributeValueDecoder & decoder, const Emb
CHIP_ERROR CodegenDataModel::WriteAttribute(const InteractionModel::WriteAttributeRequest & request,
AttributeValueDecoder & decoder)
{
ChipLogDetail(DataManagement, "Writing attribute: Cluster=" ChipLogFormatMEI " Endpoint=%x AttributeId=" ChipLogFormatMEI,
ChipLogDetail(DataManagement, "Writing attribute: Cluster=" ChipLogFormatMEI " Endpoint=0x%x AttributeId=" ChipLogFormatMEI,
ChipLogValueMEI(request.path.mClusterId), request.path.mEndpointId, ChipLogValueMEI(request.path.mAttributeId));

// ACL check for non-internal requests
Expand Down Expand Up @@ -293,7 +304,7 @@ CHIP_ERROR CodegenDataModel::WriteAttribute(const InteractionModel::WriteAttribu

// All the global attributes that we do not have metadata for are
// read-only. Specifically only the following list-based attributes match the
// "global attributes not in metadata" (see GlobalAttributes.h :: GlobalAttributesNotInMetadat):
// "global attributes not in metadata" (see GlobalAttributes.h :: GlobalAttributesNotInMetadata):
// - AttributeList
// - EventList
// - AcceptedCommands
Expand Down Expand Up @@ -321,45 +332,68 @@ CHIP_ERROR CodegenDataModel::WriteAttribute(const InteractionModel::WriteAttribu
std::optional<InteractionModel::ClusterInfo> clusterInfo = GetClusterInfo(request.path);
if (!clusterInfo.has_value())
{
ChipLogError(DataManagement, "Unable to get cluster info for Endpoint %x, Cluster " ChipLogFormatMEI,
ChipLogError(DataManagement, "Unable to get cluster info for Endpoint 0x%x, Cluster " ChipLogFormatMEI,
request.path.mEndpointId, ChipLogValueMEI(request.path.mClusterId));
return CHIP_ERROR_NOT_FOUND;
return CHIP_IM_GLOBAL_STATUS(DataVersionMismatch);
}

if (request.path.mDataVersion.Value() != clusterInfo->dataVersion)
{
ChipLogError(DataManagement, "Write Version mismatch for Endpoint %x, Cluster " ChipLogFormatMEI,
ChipLogError(DataManagement, "Write Version mismatch for Endpoint 0x%x, Cluster " ChipLogFormatMEI,
request.path.mEndpointId, ChipLogValueMEI(request.path.mClusterId));
return CHIP_IM_GLOBAL_STATUS(DataVersionMismatch);
}
}

AttributeAccessInterface * aai = GetAttributeAccessOverride(request.path.mEndpointId, request.path.mClusterId);
std::optional<CHIP_ERROR> aai_result = TryWriteViaAccessInterface(request.path, aai, decoder);

if (aai_result.has_value())
{
if (*aai_result == CHIP_NO_ERROR)
{
// TODO: change callbacks should likely be routed through the context `MarkDirty` only
// however for now this is called directly because ember code does this call
// inside emberAfWriteAttribute.
MatterReportingAttributeChangeCallback(request.path);
CurrentContext().dataModelChangeListener->MarkDirty(request.path);
}
return *aai_result;
}

ReturnErrorCodeIf(aai_result.has_value(), *aai_result);
MutableByteSpan dataBuffer = gEmberAttributeIOBufferSpan;
ReturnErrorOnFailure(DecodeValueIntoEmberBuffer(decoder, *attributeMetadata, dataBuffer));

ReturnErrorOnFailure(DecodeValueIntoEmberBuffer(decoder, *attributeMetadata, gEmberAttributeIOBufferSpan));
Protocols::InteractionModel::Status status;

EmberAfAttributeSearchRecord record;
record.endpoint = request.path.mEndpointId;
record.clusterId = request.path.mClusterId;
record.attributeId = request.path.mAttributeId;
if (request.operationFlags.Has(InteractionModel::OperationFlags::kInternal))
{
// Internal requests use the non-External interface that has less enforcement
// than the external version (e.g. does not check/enforce writable settings, does not
// validate atribute types) - see attribute-table.h documentation for details.
status = emberAfWriteAttribute(request.path.mEndpointId, request.path.mClusterId, request.path.mAttributeId,
gEmberAttributeIOBufferSpan.data(), (*attributeMetadata)->attributeType);
}
else
{
if (dataBuffer.size() > (*attributeMetadata)->size)
{
ChipLogDetail(Zcl, "Data to write exceedes the attribute size claimed.");
return CHIP_IM_GLOBAL_STATUS(InvalidValue);
}

Protocols::InteractionModel::Status status = emAfReadOrWriteAttribute(
&record, attributeMetadata, gEmberAttributeIOBufferSpan.data(), static_cast<uint16_t>(gEmberAttributeIOBufferSpan.size()),
/* write = */ true);
status = emAfWriteAttributeExternal(request.path.mEndpointId, request.path.mClusterId, request.path.mAttributeId,
gEmberAttributeIOBufferSpan.data(), (*attributeMetadata)->attributeType);
}

if (status != Protocols::InteractionModel::Status::Success)
{
return CHIP_ERROR_IM_GLOBAL_STATUS_VALUE(status);
}

// TODO: this may need more refinement:
// - should internal requests be able to decide if something is marked dirty or not?
// - changes-omitted paths should not be marked dirty (ember is not aware of these)
CurrentContext().dataModelChangeListener->MarkDirty(request.path);
return CHIP_NO_ERROR;
}

Expand Down
21 changes: 13 additions & 8 deletions src/app/codegen-data-model/EmberMetadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,23 @@ std::variant<const EmberAfCluster *, // global attribute, data from a
>
FindAttributeMetadata(const ConcreteAttributePath & aPath)
{
for (auto & attr : GlobalAttributesNotInMetadata)
if (IsGlobalAttribute(aPath.mAttributeId))
{
if (attr == aPath.mAttributeId)
// Global list attribute check first: during path expansion a lot of attributes
// will actually be global attributes (so not too much of a performance hit)
for (auto & attr : GlobalAttributesNotInMetadata)
{
const EmberAfCluster * cluster = emberAfFindServerCluster(aPath.mEndpointId, aPath.mClusterId);
if (cluster == nullptr)
if (attr == aPath.mAttributeId)
{
return (emberAfFindEndpointType(aPath.mEndpointId) == nullptr) ? CHIP_IM_GLOBAL_STATUS(UnsupportedEndpoint)
: CHIP_IM_GLOBAL_STATUS(UnsupportedCluster);
}
const EmberAfCluster * cluster = emberAfFindServerCluster(aPath.mEndpointId, aPath.mClusterId);
if (cluster == nullptr)
{
return (emberAfFindEndpointType(aPath.mEndpointId) == nullptr) ? CHIP_IM_GLOBAL_STATUS(UnsupportedEndpoint)
: CHIP_IM_GLOBAL_STATUS(UnsupportedCluster);
}

return cluster;
return cluster;
}
}
}
const EmberAfAttributeMetadata * metadata =
Expand Down
29 changes: 29 additions & 0 deletions src/app/codegen-data-model/tests/EmberReadWriteOverride.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "EmberReadWriteOverride.h"

#include <app/util/attribute-storage.h>
#include <app/util/ember-io-storage.h>
#include <lib/support/Span.h>

using chip::Protocols::InteractionModel::Status;
Expand Down Expand Up @@ -98,3 +99,31 @@ Status emAfReadOrWriteAttribute(const EmberAfAttributeSearchRecord * attRecord,

return Status::Success;
}

Status emAfWriteAttributeExternal(chip::EndpointId endpoint, chip::ClusterId cluster, chip::AttributeId attributeID,
uint8_t * dataPtr, EmberAfAttributeType dataType)
{
if (gEmberStatusCode != Status::Success)
{
return gEmberStatusCode;
}

// ember here deduces the size of dataPtr. For testing however, we KNOW we read
// out of the ember IO buffer, so we try to use that
VerifyOrDie(dataPtr == chip::app::Compatibility::Internal::gEmberAttributeIOBufferSpan.data());

// In theory this should do type validation and sizes. This is NOT done for testing.
// copy over as much data as possible
// NOTE: we do NOT use (*metadata)->size since it is unclear if our mocks set that correctly
size_t len = std::min<size_t>(sizeof(gEmberIoBuffer), chip::app::Compatibility::Internal::gEmberAttributeIOBufferSpan.size());
memcpy(gEmberIoBuffer, dataPtr, len);
gEmberIoBufferFill = len;

return Status::Success;
}

Status emberAfWriteAttribute(chip::EndpointId endpoint, chip::ClusterId cluster, chip::AttributeId attributeID, uint8_t * dataPtr,
EmberAfAttributeType dataType)
{
return emAfWriteAttributeExternal(endpoint, cluster, attributeID, dataPtr, dataType);
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,8 @@ void DispatchSingleClusterCommand(const ConcreteCommandPath & aRequestCommandPat

} // namespace app
} // namespace chip

void MatterReportingAttributeChangeCallback(const chip::app::ConcreteAttributePath & aPath)
{
// TODO: should we add logic to track these calls for test purposes?
}
Loading
Loading