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

Linux sample implementation for Messages cluster #32043

Merged
merged 25 commits into from
Feb 16, 2024
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
e33eff5
Linux sample implementation for Messages cluster
chrisdecenzo Feb 9, 2024
326644f
cleanup the chip:: and chip::app prefixes
chrisdecenzo Feb 9, 2024
0dabc8c
Merge branch 'master' into tv2-6
lazarkov Feb 9, 2024
caea32b
CI fixes
chrisdecenzo Feb 9, 2024
0e94261
Merge branch 'tv2-6' of github.com:project-chip/connectedhomeip into …
chrisdecenzo Feb 9, 2024
222019f
Merge branch 'master' into tv2-6
lazarkov Feb 12, 2024
18fe638
Address comments
chrisdecenzo Feb 13, 2024
e716867
Merge branch 'tv2-6' of github.com:project-chip/connectedhomeip into …
chrisdecenzo Feb 13, 2024
784b9a2
Make memory management less error prone
chrisdecenzo Feb 14, 2024
3681d6d
Fix CI
chrisdecenzo Feb 14, 2024
66a31cb
more feedback
chrisdecenzo Feb 14, 2024
47809aa
fix CI
chrisdecenzo Feb 14, 2024
6183338
Restyled by clang-format (#32123)
restyled-io[bot] Feb 14, 2024
d976b01
address comments
chrisdecenzo Feb 15, 2024
4b08069
address comments
chrisdecenzo Feb 15, 2024
4e3b2d8
Restyled by clang-format (#32136)
restyled-io[bot] Feb 15, 2024
d759a6f
fix CI
chrisdecenzo Feb 15, 2024
9fb2f0b
address comments
chrisdecenzo Feb 15, 2024
760d0c5
address comments
chrisdecenzo Feb 15, 2024
8e8bcff
Restyled by clang-format (#32144)
restyled-io[bot] Feb 15, 2024
0c2fa27
address comments
chrisdecenzo Feb 15, 2024
01ebed8
address comments
chrisdecenzo Feb 15, 2024
ccac074
address comments
chrisdecenzo Feb 15, 2024
98b39ee
Restyled by clang-format (#32148)
restyled-io[bot] Feb 15, 2024
9c71610
Merge branch 'master' into tv2-6
lazarkov Feb 15, 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
96 changes: 71 additions & 25 deletions examples/tv-app/tv-common/clusters/messages/MessagesManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,64 +18,110 @@
#include "MessagesManager.h"

#include <app-common/zap-generated/attributes/Accessors.h>
#include <vector>

using namespace std;
using namespace chip;
using namespace chip::app;
using namespace chip::app::Clusters::Messages;
using Message = chip::app::Clusters::Messages::Structs::MessageStruct::Type;

// Commands
void MessagesManager::HandlePresentMessagesRequest(
const chip::ByteSpan & messageId, const MessagePriorityEnum & priority,
const chip::BitMask<MessageControlBitmap> & messageControl, const chip::app::DataModel::Nullable<uint32_t> & startTime,
const chip::app::DataModel::Nullable<uint16_t> & duration, const chip::CharSpan & messageText,
const chip::Optional<chip::app::DataModel::DecodableList<MessageResponseOption>> & responses)
void MessagesManager::HandlePresentMessagesRequest(const ByteSpan & messageId, const MessagePriorityEnum & priority,
const BitMask<MessageControlBitmap> & messageControl,
const DataModel::Nullable<uint32_t> & startTime,
const DataModel::Nullable<uint16_t> & duration, const CharSpan & messageText,
const Optional<DataModel::DecodableList<MessageResponseOption>> & responses)
{
Message message{
// TODO: Enable id
chip::ByteSpan(), priority, messageControl, startTime, duration,
// TODO: Enable text
chip::CharSpan()
// TODO: Convert responses to Optional<chip::app::DataModel::List<const
// chip::app::Clusters::Messages::Structs::MessageResponseOptionStruct::Type>> message.responses = responses;
};

mMessages.push_back(message);
ChipLogProgress(Zcl, "HandlePresentMessagesRequest message:%s", std::string(messageText.data(), messageText.size()).c_str());

VerifyOrReturn(messageId.size() == CachedMessage::kMessageIdLength,
ChipLogProgress(Zcl, "HandlePresentMessagesRequest invalid message id length"));
bzbarsky-apple marked this conversation as resolved.
Show resolved Hide resolved

auto cachedMessage = CachedMessage(messageId, priority, messageControl, startTime, duration,
std::string(messageText.data(), messageText.size()));
if (responses.HasValue())
{
size_t size = 0;
CHIP_ERROR err = responses.Value().ComputeSize(&size);
VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogProgress(Zcl, "HandlePresentMessagesRequest size check failed"));

VerifyOrReturn(size <= CachedMessage::kMaxOptionCount,
ChipLogProgress(Zcl, "HandlePresentMessagesRequest too many options"));
bzbarsky-apple marked this conversation as resolved.
Show resolved Hide resolved

auto iter = responses.Value().begin();
while (iter.Next())
{
auto & response = iter.GetValue();

VerifyOrReturn(response.messageResponseID.HasValue() && response.label.HasValue(),
ChipLogProgress(Zcl, "HandlePresentMessagesRequest missing response id or label"));
bzbarsky-apple marked this conversation as resolved.
Show resolved Hide resolved

VerifyOrReturn(response.messageResponseID.Value() >= CachedMessageOption::kResponseIdMin,
ChipLogProgress(Zcl, "HandlePresentMessagesRequest responseID value check failed"));

VerifyOrReturn(response.label.Value().size() <= CachedMessageOption::kLabelMaxLength,
ChipLogProgress(Zcl, "HandlePresentMessagesRequest label length check failed"));

CachedMessageOption option(response.messageResponseID.Value(),
std::string(response.label.Value().data(), response.label.Value().size()));

cachedMessage.AddOption(option);
}
bzbarsky-apple marked this conversation as resolved.
Show resolved Hide resolved
VerifyOrReturn(iter.GetStatus() == CHIP_NO_ERROR, ChipLogProgress(Zcl, "HandlePresentMessagesRequest TLV parsing error"));
}

mCachedMessages.push_back(cachedMessage);

// Add your code to present Message
ChipLogProgress(Zcl, "HandlePresentMessagesRequest complete");
}

void MessagesManager::HandleCancelMessagesRequest(const chip::app::DataModel::DecodableList<chip::ByteSpan> & messageIds)
void MessagesManager::HandleCancelMessagesRequest(const DataModel::DecodableList<ByteSpan> & messageIds)
{
// TODO: Cancel Message
auto iter = messageIds.begin();
while (iter.Next())
{
auto & id = iter.GetValue();

mCachedMessages.remove_if([id](CachedMessage & entry) {
if (entry.mMessageId.data_equal(id))
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
{
return true;
}
return false;
});
// per spec, the command succeeds even when the message id does not match an existing message
bzbarsky-apple marked this conversation as resolved.
Show resolved Hide resolved
}
bzbarsky-apple marked this conversation as resolved.
Show resolved Hide resolved
bzbarsky-apple marked this conversation as resolved.
Show resolved Hide resolved
}

// Attributes
CHIP_ERROR MessagesManager::HandleGetMessages(chip::app::AttributeValueEncoder & aEncoder)
CHIP_ERROR MessagesManager::HandleGetMessages(AttributeValueEncoder & aEncoder)
{
return aEncoder.EncodeList([this](const auto & encoder) -> CHIP_ERROR {
for (Message & entry : mMessages)
for (CachedMessage & entry : mCachedMessages)
{
ReturnErrorOnFailure(encoder.Encode(entry));
ReturnErrorOnFailure(encoder.Encode(entry.GetMessage()));
}
return CHIP_NO_ERROR;
});
}

CHIP_ERROR MessagesManager::HandleGetActiveMessageIds(chip::app::AttributeValueEncoder & aEncoder)
CHIP_ERROR MessagesManager::HandleGetActiveMessageIds(AttributeValueEncoder & aEncoder)
{
return aEncoder.EncodeList([this](const auto & encoder) -> CHIP_ERROR {
for (Message & entry : mMessages)
for (CachedMessage & entry : mCachedMessages)
{
ReturnErrorOnFailure(encoder.Encode(entry.messageID));
ReturnErrorOnFailure(encoder.Encode(entry.GetMessage().messageID));
}
return CHIP_NO_ERROR;
});
}

// Global Attributes
uint32_t MessagesManager::GetFeatureMap(chip::EndpointId endpoint)
uint32_t MessagesManager::GetFeatureMap(EndpointId endpoint)
{
uint32_t featureMap = 0;
uint32_t featureMap = 15; // all features enabled by default
chrisdecenzo marked this conversation as resolved.
Show resolved Hide resolved
Attributes::FeatureMap::Get(endpoint, &featureMap);
return featureMap;
}
111 changes: 110 additions & 1 deletion examples/tv-app/tv-common/clusters/messages/MessagesManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,115 @@

#include <iostream>
#include <list>
#include <vector>

struct CachedMessageOption
{
constexpr static size_t kResponseIdMin = 1;
constexpr static size_t kLabelMaxLength = 32;

CachedMessageOption(uint32_t id, std::string label) :
mLabel(label), mOption{ chip::MakeOptional(id), chip::MakeOptional(chip::CharSpan::fromCharString(mLabel.c_str())) }
{}

CachedMessageOption(const CachedMessageOption & option) :
mLabel(option.mLabel),
mOption{ option.mOption.messageResponseID, chip::MakeOptional(chip::CharSpan::fromCharString(mLabel.c_str())) } {};
chrisdecenzo marked this conversation as resolved.
Show resolved Hide resolved

CachedMessageOption & operator=(const CachedMessageOption & option) { return *this; };
andy31415 marked this conversation as resolved.
Show resolved Hide resolved

chip::app::Clusters::Messages::MessageResponseOption GetMessageOption() { return mOption; }

~CachedMessageOption() {}

protected:
std::string mLabel;
chip::app::Clusters::Messages::MessageResponseOption mOption;
};

struct CachedMessage
{
constexpr static size_t kMessageIdLength = 16;
constexpr static size_t kMaxOptionCount = 4;

chip::ByteSpan mMessageId;
bzbarsky-apple marked this conversation as resolved.
Show resolved Hide resolved

CachedMessage(const CachedMessage & message) :
mPriority(message.mPriority), mMessageControl(message.mMessageControl), mStartTime(message.mStartTime),
mDuration(message.mDuration), mMessageText(message.mMessageText), mOptions(message.mOptions)
{
memcpy(mMessageIdBuffer, message.mMessageIdBuffer, kMessageIdLength);
mMessageId = chip::ByteSpan(mMessageIdBuffer, kMessageIdLength);
bzbarsky-apple marked this conversation as resolved.
Show resolved Hide resolved

for (CachedMessageOption & entry : mOptions)
{
mResponseOptions.push_back(entry.GetMessageOption());
}
};
chrisdecenzo marked this conversation as resolved.
Show resolved Hide resolved

CachedMessage & operator=(const CachedMessage & message) { return *this; };
andy31415 marked this conversation as resolved.
Show resolved Hide resolved

CachedMessage(const chip::ByteSpan & messageId, const chip::app::Clusters::Messages::MessagePriorityEnum & priority,
const chip::BitMask<chip::app::Clusters::Messages::MessageControlBitmap> & messageControl,
const chip::app::DataModel::Nullable<uint32_t> & startTime,
const chip::app::DataModel::Nullable<uint16_t> & duration, std::string messageText) :
mPriority(priority),
mMessageControl(messageControl), mStartTime(startTime), mDuration(duration), mMessageText(messageText)
{
if (messageId.size() != kMessageIdLength)
{
ChipLogProgress(Zcl, "CachedMessage bad message id size, ignoring");
bzbarsky-apple marked this conversation as resolved.
Show resolved Hide resolved
return;
}
memcpy(mMessageIdBuffer, messageId.data(), kMessageIdLength);
mMessageId = chip::ByteSpan(mMessageIdBuffer, kMessageIdLength);
bzbarsky-apple marked this conversation as resolved.
Show resolved Hide resolved
}

void AddOption(CachedMessageOption option)
{
mOptions.push_back(option);
mResponseOptions.push_back(option.GetMessageOption());
}

chip::app::Clusters::Messages::Structs::MessageStruct::Type GetMessage()
{
if (mResponseOptions.size() > 0)
{
chip::app::DataModel::List<chip::app::Clusters::Messages::MessageResponseOption> options(mResponseOptions.data(),
bzbarsky-apple marked this conversation as resolved.
Show resolved Hide resolved
mResponseOptions.size());
chip::app::Clusters::Messages::Structs::MessageStruct::Type message{ mMessageId,
mPriority,
mMessageControl,
mStartTime,
mDuration,
chip::CharSpan::fromCharString(
mMessageText.c_str()),
chip::MakeOptional(options) };
return message;
}
else
chrisdecenzo marked this conversation as resolved.
Show resolved Hide resolved
{
chip::app::Clusters::Messages::Structs::MessageStruct::Type message{
mMessageId, mPriority, mMessageControl, mStartTime, mDuration, chip::CharSpan::fromCharString(mMessageText.c_str())
};
return message;
}
}

~CachedMessage() {}

protected:
const chip::app::Clusters::Messages::MessagePriorityEnum mPriority;
const chip::BitMask<chip::app::Clusters::Messages::MessageControlBitmap> mMessageControl;
const chip::app::DataModel::Nullable<uint32_t> mStartTime;
const chip::app::DataModel::Nullable<uint16_t> mDuration;

std::string mMessageText;
uint8_t mMessageIdBuffer[kMessageIdLength];

std::vector<chip::app::Clusters::Messages::MessageResponseOption> mResponseOptions;
std::list<CachedMessageOption> mOptions;
};

class MessagesManager : public chip::app::Clusters::Messages::Delegate
{
Expand All @@ -44,5 +153,5 @@ class MessagesManager : public chip::app::Clusters::Messages::Delegate
uint32_t GetFeatureMap(chip::EndpointId endpoint) override;

protected:
std::list<chip::app::Clusters::Messages::Structs::MessageStruct::Type> mMessages;
std::list<CachedMessage> mCachedMessages;
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
};
Loading