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

Add commands support for dynamically generated clusters in dynamic-bridge-app #23840

Merged
merged 34 commits into from
Jan 18, 2023
Merged
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
7d75e69
Add commands for bridge-generated dynamic clusters
mukifera Nov 15, 2022
ccb4bb9
Allow reads and writes to externally stored OnOff cluster attribute
mukifera Nov 18, 2022
7311e55
dynamic-bridge-app: implement generic read and write callbacks for ex…
mukifera Nov 25, 2022
aa05bd7
Merge branch 'master' into dba-clusters-gen
mukifera Nov 30, 2022
e0ac5a3
Update bridge idl tests to include external storage flags
mukifera Dec 1, 2022
fc487ee
Merge branch 'master' into dba-clusters-gen
mukifera Dec 1, 2022
046d372
Restyled by clang-format
restyled-commits Dec 1, 2022
fa663b1
Merge branch 'master' into dba-clusters-gen
mukifera Dec 12, 2022
c67e2a5
Document the data buffer padding size used when reading/writing exter…
mukifera Dec 12, 2022
37ff981
Add better error handling for attribute read/write overrides in dynam…
mukifera Dec 12, 2022
ca68227
Allow bitmap32 attribute reads for dynamic clusters in dynamic-bridge…
mukifera Dec 13, 2022
fd91c1f
Adjust indentation in BridgeClustersCpp.jinja
mukifera Dec 19, 2022
7ea7e8b
Change the incoming command list for generated clusters to static
mukifera Dec 19, 2022
c8cc3c9
Change the incoming command list for generated clusters to const
mukifera Dec 19, 2022
f34dd3f
Rename incomingCommandList to mIncomingCommandList for generated clus…
mukifera Dec 19, 2022
b13861c
add a test for bridge generated cluster headers
mukifera Dec 19, 2022
52d72b1
Restyle one line if statements in dynamic-bridge-app main.cpp
mukifera Dec 19, 2022
42661f6
dynamic-bridge-app: change buffer read logic to assume byte arrays
mukifera Jan 5, 2023
739b4ec
Merge branch 'master' into dba-clusters-gen
mukifera Jan 9, 2023
0941696
Restyled by clang-format
restyled-commits Jan 9, 2023
8c22ed0
dynamic-bridge-app: move tests to the proper location
mukifera Jan 11, 2023
bc0238e
dynamic-bridge-app: undo formatting done to matter_idl tests restyled…
mukifera Jan 11, 2023
98ea329
dynamic-bridge-app: change read and write functions to use AnonymousT…
mukifera Jan 12, 2023
b91b1f8
dynamic-bridge-app: document unclear code and refactor function and v…
mukifera Jan 12, 2023
f5f2d64
dynamic-bridge-app: mark OnListWriteBegin and OnListWriteEnd as overr…
mukifera Jan 13, 2023
1872a7c
dynamic-bridge-app: fix error handling in WriteValueToBuffer
mukifera Jan 13, 2023
a21b528
dynamic-bridge-app: simplify the include path in BridgeClustersCpp ji…
mukifera Jan 13, 2023
f2692f9
dynamic-bridge-app: change CHIP_ERROR_BUFFER_TOO_SMALL errors to CHIP…
mukifera Jan 13, 2023
ec0b498
dynamic-bridge-app: allow read operations on externally stored list a…
mukifera Jan 16, 2023
8dc0893
Restyled by whitespace
restyled-commits Jan 16, 2023
6069841
Restyled by clang-format
restyled-commits Jan 16, 2023
be231e4
dynamic-bridge-app: formatting - add whitespace between function defi…
mukifera Jan 16, 2023
ff809c5
Merge branch 'master' into dba-clusters-gen
mukifera Jan 16, 2023
4496927
dynamic-bridge-app: fix typo in GeneratedClusters.h
mukifera Jan 16, 2023
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
17 changes: 9 additions & 8 deletions examples/dynamic-bridge-app/linux/UserInputBackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ void AddCluster(const std::vector<std::string> & tokens)
auto c = CreateCluster(cluster_name.c_str());
if (c)
{
g_pending->AddCluster(std::make_unique<DynamicCluster>(std::move(c)));
g_pending->AddCluster(
std::make_unique<DynamicCluster>(std::move(c), c->GetIncomingCommandList(), c->GetOutgoingCommandList()));
}
else
{
Expand Down Expand Up @@ -285,20 +286,20 @@ void ParseValue(std::vector<uint8_t> * data, uint16_t size, const std::string &
{
case ZCL_OCTET_STRING_ATTRIBUTE_TYPE:
case ZCL_CHAR_STRING_ATTRIBUTE_TYPE:
wr.PutString(chip::TLV::Tag(), str.data(), (uint32_t) str.size());
wr.PutString(chip::TLV::AnonymousTag(), str.data(), (uint32_t) str.size());
break;
case ZCL_LONG_OCTET_STRING_ATTRIBUTE_TYPE:
case ZCL_LONG_CHAR_STRING_ATTRIBUTE_TYPE:
wr.PutBytes(chip::TLV::Tag(), (const uint8_t *) str.data(), (uint32_t) str.size());
wr.PutBytes(chip::TLV::AnonymousTag(), (const uint8_t *) str.data(), (uint32_t) str.size());
break;
case ZCL_STRUCT_ATTRIBUTE_TYPE:
// Writing structs not supported yet
break;
case ZCL_SINGLE_ATTRIBUTE_TYPE:
wr.Put(chip::TLV::Tag(), (float) atof(str.c_str()));
wr.Put(chip::TLV::AnonymousTag(), (float) atof(str.c_str()));
break;
case ZCL_DOUBLE_ATTRIBUTE_TYPE:
wr.Put(chip::TLV::Tag(), atof(str.c_str()));
wr.Put(chip::TLV::AnonymousTag(), atof(str.c_str()));
break;
case ZCL_INT8S_ATTRIBUTE_TYPE:
case ZCL_INT16S_ATTRIBUTE_TYPE:
Expand All @@ -308,7 +309,7 @@ void ParseValue(std::vector<uint8_t> * data, uint16_t size, const std::string &
case ZCL_INT48S_ATTRIBUTE_TYPE:
case ZCL_INT56S_ATTRIBUTE_TYPE:
case ZCL_INT64S_ATTRIBUTE_TYPE:
wr.Put(chip::TLV::Tag(), (int64_t) strtoll(str.c_str(), nullptr, 10));
wr.Put(chip::TLV::AnonymousTag(), (int64_t) strtoll(str.c_str(), nullptr, 10));
break;

case ZCL_INT8U_ATTRIBUTE_TYPE:
Expand All @@ -319,12 +320,12 @@ void ParseValue(std::vector<uint8_t> * data, uint16_t size, const std::string &
case ZCL_INT48U_ATTRIBUTE_TYPE:
case ZCL_INT56U_ATTRIBUTE_TYPE:
case ZCL_INT64U_ATTRIBUTE_TYPE:
wr.Put(chip::TLV::Tag(), (uint64_t) strtoll(str.c_str(), nullptr, 10));
wr.Put(chip::TLV::AnonymousTag(), (uint64_t) strtoll(str.c_str(), nullptr, 10));
break;

default:
// Assume integer
wr.Put(chip::TLV::Tag(), (int64_t) strtoll(str.c_str(), nullptr, 10));
wr.Put(chip::TLV::AnonymousTag(), (int64_t) strtoll(str.c_str(), nullptr, 10));
break;
}
wr.Finalize();
Expand Down
12 changes: 12 additions & 0 deletions examples/dynamic-bridge-app/linux/include/GeneratedClusters.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,16 @@ class GeneratedCluster
virtual chip::ClusterId GetClusterId() = 0;
// Gets the list of available attributes for this cluster.
virtual std::vector<AttributeInterface *> GetAttributes() = 0;

// Returns a list of client to server commands. Can be nulttptr or terminated by 0xFFFF_FFFF.
mukifera marked this conversation as resolved.
Show resolved Hide resolved
// The returned list mirrors the `acceptedCommandList` field in `EmberAfCluster`
// This function is used to pass a command list when creating a `DynamicCluster` and its underlying `EmberAfCluster`. See
// `AddCluster` in `UserInputBackend`.
virtual const chip::CommandId * GetIncomingCommandList() { return nullptr; }
andy31415 marked this conversation as resolved.
Show resolved Hide resolved

// Returns a list of server generated commands (responses to client commands). Can be nulttptr or terminated by 0xFFFF_FFFF.
// The returned list mirrors the `generatedCommandList` field in `EmberAfCluster`
// This function is used to pass a command list when creating a `DynamicCluster` and its underlying `EmberAfCluster`. See
// `AddCluster` in `UserInputBackend`.
virtual const chip::CommandId * GetOutgoingCommandList() { return nullptr; }
};
19 changes: 19 additions & 0 deletions examples/dynamic-bridge-app/linux/include/data-model/Attribute.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ class AttributeInterface

// Read the contents of the attribute.
virtual CHIP_ERROR Read(const chip::app::ConcreteReadAttributePath & aPath, chip::app::AttributeValueEncoder & aEncoder) = 0;

virtual CHIP_ERROR Read(const chip::app::ConcreteReadAttributePath & aPath, chip::TLV::TLVWriter & writer) = 0;
};

// This is the base type for implementing an attribute
Expand All @@ -52,6 +54,23 @@ struct Attribute : public AttributeInterface
return chip::app::DataModel::Encode(aPath, aEncoder, mData);
}

template <typename T = Type, std::enable_if_t<chip::app::DataModel::IsList<std::decay_t<T>>::value, bool> = true>
CHIP_ERROR ReadValue(const chip::app::ConcreteReadAttributePath & aPath, chip::TLV::TLVWriter & writer, Type & value)
{
return chip::app::DataModel::Encode(aPath, writer, chip::TLV::AnonymousTag(), value);
}

template <typename T = Type, std::enable_if_t<!chip::app::DataModel::IsList<std::decay_t<T>>::value, bool> = true>
CHIP_ERROR ReadValue(const chip::app::ConcreteReadAttributePath & aPath, chip::TLV::TLVWriter & writer, Type & value)
{
return chip::app::DataModel::Encode(writer, chip::TLV::AnonymousTag(), value);
}

CHIP_ERROR Read(const chip::app::ConcreteReadAttributePath & aPath, chip::TLV::TLVWriter & writer) override
{
return ReadValue(aPath, writer, mData);
}

void operator=(const Type & value) { mData = value; }
const Type & Peek() const { return mData; }

Expand Down
56 changes: 56 additions & 0 deletions examples/dynamic-bridge-app/linux/include/data-model/DataModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ CHIP_ERROR Encode(const ConcreteReadAttributePath &, AttributeValueEncoder & aEn
/*
* @brief
* Lists that are string-like should be encoded as char/byte spans.
* Encode using a given AttributeValueEncoder.
*/
template <
typename X,
Expand All @@ -74,11 +75,26 @@ CHIP_ERROR Encode(const ConcreteReadAttributePath & aPath, AttributeValueEncoder
return aEncoder.Encode(Span<std::decay_t<typename X::pointer>>(x.data(), x.size()));
}

/*
* @brief
* Lists that are string-like should be encoded as char/byte spans.
* Encode using a given TLVWriter.
*/
template <
typename X,
std::enable_if_t<IsList<std::decay_t<X>>::value && sizeof(std::decay_t<typename X::pointer>) == sizeof(char), bool> = true>
CHIP_ERROR Encode(const ConcreteReadAttributePath & aPath, TLV::TLVWriter & writer, TLV::Tag tag, const X & x)
{
return writer.Put(tag, Span<std::decay_t<typename X::pointer>>(x.data(), x.size()));
}

/*
* @brief
*
* If an item is requested from a list, encode just that single item, or the entire list otherwise.
*
* Encodes items using a given AttributeValueEncoder.
*
* The object must satisfy the following constraints
* size() must return an integer
* begin() must return a type conforming to LegacyRandomAccessIterator
Expand Down Expand Up @@ -113,6 +129,46 @@ CHIP_ERROR Encode(const ConcreteReadAttributePath & aPath, AttributeValueEncoder
});
}

/*
* @brief
*
* If an item is requested from a list, encode just that single item, or the entire list otherwise.
*
* Encodes items using a given TLVWriter.
*
* The object must satisfy the following constraints
* size() must return an integer
* begin() must return a type conforming to LegacyRandomAccessIterator
*
* This is const X& instead of X&& because it is "more specialized" and so this overload will
* be chosen if possible.
*/
template <
typename X,
std::enable_if_t<IsList<std::decay_t<X>>::value && (sizeof(std::decay_t<typename X::pointer>) > sizeof(char)), bool> = true>
CHIP_ERROR Encode(const ConcreteReadAttributePath & aPath, TLV::TLVWriter & writer, TLV::Tag tag, const X & x)
{
if (aPath.mListIndex.HasValue())
{
uint16_t index = aPath.mListIndex.Value();
if (index >= x.size())
return CHIP_ERROR_INVALID_ARGUMENT;

auto it = x.begin();
std::advance(it, index);
return Encode(writer, tag, *it);
}
TLV::TLVType type;

ReturnErrorOnFailure(writer.StartContainer(tag, TLV::kTLVType_Array, type));
for (auto & item : x)
{
ReturnErrorOnFailure(Encode(writer, tag, item));
}
ReturnErrorOnFailure(writer.EndContainer(type));
return CHIP_NO_ERROR;
}

/*
* @brief
* Set of overloaded encode methods that can be called from AttributeAccessInterface::Read
Expand Down
2 changes: 2 additions & 0 deletions examples/dynamic-bridge-app/linux/include/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,5 @@ chip::Span<Action *> GetActionListInfo(chip::EndpointId parentId);
chip::Optional<chip::ClusterId> LookupClusterByName(const char * name);
std::unique_ptr<GeneratedCluster> CreateCluster(const char * name);
std::unique_ptr<GeneratedCluster> CreateCluster(chip::ClusterId id);
EmberAfStatus HandleReadOnOffAttribute(Attribute<bool> * attribute, uint8_t * buffer, uint16_t maxReadLength);
EmberAfStatus HandleWriteOnOffAttribute(Attribute<bool> * attribute, uint8_t * buffer);
Loading