Skip to content

Commit

Permalink
[Chef] Add BasicVideoPlayer device type (project-chip#28152)
Browse files Browse the repository at this point in the history
* [Chef] Add Basic Video Player sample device

* [Chef] Implement ChefChannelManager

Implement ChefChannelManager and enable ChannelList, Lineup, ...

* [Chef]Use emberAfChannelClusterInitC..k to init

* [Chef] Support BasicVideoPlayer for esp32,nrfconnect

* Restyled by whitespace

* Restyled by clang-format

* [Chef] upgrade zap to level 20230721

* Avoid doing "using namespace" in chef-channel-manager.h

* return since we've alreay find the matched channel

* Remove todo in common/chef-channel-manager.cpp

* Fine tune chef-channel-manager logic

1. Remove mCurrentChannel which can be gotten from mCurrentChannelIndex
2. Return channel early when matched
3. use std::array instead if std::vector to optimize memory usage in MCU

* Restyled by clang-format

* Remove vector in chef-channel-manage.[cp]

And avoid using "using" in header file

* Restyled by clang-format

---------

Co-authored-by: Restyled.io <[email protected]>
  • Loading branch information
erwinpan1 and restyled-commits authored Jul 28, 2023
1 parent 013e3ce commit 6e9b15c
Show file tree
Hide file tree
Showing 9 changed files with 9,680 additions and 7 deletions.
226 changes: 226 additions & 0 deletions examples/chef/common/chef-channel-manager.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
/**
*
* Copyright (c) 2021 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <app-common/zap-generated/attributes/Accessors.h>
#include <app-common/zap-generated/callback.h>
#include <app/util/config.h>

using ChangeChannelResponseType = chip::app::Clusters::Channel::Commands::ChangeChannelResponse::Type;
using ChannelInfoType = chip::app::Clusters::Channel::Structs::ChannelInfoStruct::Type;
using LineupInfoType = chip::app::Clusters::Channel::Structs::LineupInfoStruct::Type;
// Include Channel Cluster Server callbacks only when the server is enabled
#ifdef EMBER_AF_PLUGIN_CHANNEL_SERVER
#include <chef-channel-manager.h>

using namespace chip;
using namespace chip::app;
using namespace chip::app::Clusters::Channel;
using namespace chip::Uint8;

ChefChannelManager::ChefChannelManager()
{
ChannelInfoType abc;
abc.affiliateCallSign = MakeOptional(chip::CharSpan::fromCharString("KAAL"));
abc.callSign = MakeOptional(chip::CharSpan::fromCharString("KAAL-TV"));
abc.name = MakeOptional(chip::CharSpan::fromCharString("ABC"));
abc.majorNumber = static_cast<uint8_t>(6);
abc.minorNumber = static_cast<uint16_t>(0);
mChannels[mTotalChannels++] = abc;

ChannelInfoType pbs;
pbs.affiliateCallSign = MakeOptional(chip::CharSpan::fromCharString("KCTS"));
pbs.callSign = MakeOptional(chip::CharSpan::fromCharString("KCTS-TV"));
pbs.name = MakeOptional(chip::CharSpan::fromCharString("PBS"));
pbs.majorNumber = static_cast<uint8_t>(9);
pbs.minorNumber = static_cast<uint16_t>(1);
mChannels[mTotalChannels++] = pbs;

ChannelInfoType pbsKids;
pbsKids.affiliateCallSign = MakeOptional(chip::CharSpan::fromCharString("KCTS"));
pbsKids.callSign = MakeOptional(chip::CharSpan::fromCharString("KCTS-TV"));
pbsKids.name = MakeOptional(chip::CharSpan::fromCharString("PBS Kids"));
pbsKids.majorNumber = static_cast<uint8_t>(9);
pbsKids.minorNumber = static_cast<uint16_t>(2);
mChannels[mTotalChannels++] = pbsKids;

ChannelInfoType worldChannel;
worldChannel.affiliateCallSign = MakeOptional(chip::CharSpan::fromCharString("KCTS"));
worldChannel.callSign = MakeOptional(chip::CharSpan::fromCharString("KCTS-TV"));
worldChannel.name = MakeOptional(chip::CharSpan::fromCharString("World Channel"));
worldChannel.majorNumber = static_cast<uint8_t>(9);
worldChannel.minorNumber = static_cast<uint16_t>(3);
mChannels[mTotalChannels++] = worldChannel;
}

static bool isChannelMatched(const ChannelInfoType & channel, const CharSpan & match)
{
if (channel.name.HasValue() && channel.name.Value().data_equal(match))
{
return true;
}

if (channel.affiliateCallSign.HasValue() && channel.affiliateCallSign.Value().data_equal(match))
{
return true;
}

if (channel.callSign.HasValue() && channel.callSign.Value().data_equal(match))
{
return true;
}

StringBuilder<32> nr;
nr.AddFormat("%d.%d", channel.majorNumber, channel.minorNumber);
return match.data_equal(CharSpan::fromCharString(nr.c_str()));
}

CHIP_ERROR ChefChannelManager::HandleGetChannelList(app::AttributeValueEncoder & aEncoder)
{
return aEncoder.EncodeList([](const auto & encoder) -> CHIP_ERROR {
int index = 0;
for (auto const & channel : ChefChannelManager().mChannels)
{
ReturnErrorOnFailure(encoder.Encode(channel));
index++;
if (index >= ChefChannelManager().mTotalChannels)
break;
}
return CHIP_NO_ERROR;
});
}

CHIP_ERROR ChefChannelManager::HandleGetLineup(app::AttributeValueEncoder & aEncoder)
{
LineupInfoType lineup;
lineup.operatorName = chip::CharSpan::fromCharString("Comcast");
lineup.lineupName = MakeOptional(chip::CharSpan::fromCharString("Comcast King County"));
lineup.postalCode = MakeOptional(chip::CharSpan::fromCharString("98052"));
lineup.lineupInfoType = chip::app::Clusters::Channel::LineupInfoTypeEnum::kMso;

return aEncoder.Encode(lineup);
}

CHIP_ERROR ChefChannelManager::HandleGetCurrentChannel(app::AttributeValueEncoder & aEncoder)
{
return aEncoder.Encode(mChannels[mCurrentChannelIndex]);
}

void ChefChannelManager::HandleChangeChannel(CommandResponseHelper<ChangeChannelResponseType> & helper,
const chip::CharSpan & match)
{
std::array<ChannelInfoType, kMaxChannels> matchedChannels;

uint16_t index = 0;
uint16_t totalMatchedChannels = 0;
for (auto const & channel : mChannels)
{
// verify if CharSpan matches channel name
// or callSign or affiliateCallSign or majorNumber.minorNumber
if (isChannelMatched(channel, match))
{
matchedChannels[totalMatchedChannels++] = (channel);
}
else if (matchedChannels.size() == 0)
{
// "index" is only used when we end up with matchedChannels.size() == 1.
// In that case, we want it to be the number of non-matching channels we saw before
// the matching one.
index++;
}
}

ChangeChannelResponseType response;

// Error: Found multiple matches
if (matchedChannels.size() > 1)
{
response.status = chip::app::Clusters::Channel::ChannelStatusEnum::kMultipleMatches;
helper.Success(response);
}
else if (matchedChannels.size() == 0)
{
// Error: Found no match
response.status = chip::app::Clusters::Channel::ChannelStatusEnum::kNoMatches;
helper.Success(response);
}
else
{
response.status = chip::app::Clusters::Channel::ChannelStatusEnum::kSuccess;
response.data = chip::MakeOptional(CharSpan::fromCharString("data response"));
mCurrentChannelIndex = index;
helper.Success(response);
}
}

bool ChefChannelManager::HandleChangeChannelByNumber(const uint16_t & majorNumber, const uint16_t & minorNumber)
{
bool channelChanged = false;
uint16_t index = 0;
for (auto const & channel : mChannels)
{

// verify if major & minor matches one of the channel from the list
if (channel.minorNumber == minorNumber && channel.majorNumber == majorNumber)
{
// verify if channel changed by comparing values of current channel with the requested channel
if (channel.minorNumber != mChannels[mCurrentChannelIndex].minorNumber ||
channel.majorNumber != mChannels[mCurrentChannelIndex].majorNumber)
{
channelChanged = true;
mCurrentChannelIndex = index;
}

// return since we've already found the unique matched channel
return channelChanged;
}
index++;
if (index >= mTotalChannels)
break;
}
return channelChanged;
}

bool ChefChannelManager::HandleSkipChannel(const int16_t & count)
{
int32_t newChannelIndex = static_cast<int32_t>(count) + static_cast<int32_t>(mCurrentChannelIndex);
uint16_t channelsSize = static_cast<uint16_t>(mChannels.size());

// handle newChannelIndex out of range.
newChannelIndex = newChannelIndex % channelsSize;

if (newChannelIndex < 0)
{
newChannelIndex = newChannelIndex + channelsSize;
}

mCurrentChannelIndex = static_cast<uint16_t>(newChannelIndex);
return true;
}

uint32_t ChefChannelManager::GetFeatureMap(chip::EndpointId endpoint)
{
if (endpoint > EMBER_AF_CHANNEL_CLUSTER_SERVER_ENDPOINT_COUNT)
{
return 0;
}

uint32_t featureMap = 0;
Attributes::FeatureMap::Get(endpoint, &featureMap);
return featureMap;
}

#endif /* EMBER_AF_PLUGIN_CHANNEL_SERVER */
55 changes: 55 additions & 0 deletions examples/chef/common/chef-channel-manager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
*
* Copyright (c) 2021 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#pragma once

#include <app/clusters/channel-server/channel-server.h>

class ChefChannelManager : public chip::app::Clusters::Channel::Delegate
{

public:
ChefChannelManager();

CHIP_ERROR HandleGetChannelList(chip::app::AttributeValueEncoder & aEncoder);
CHIP_ERROR HandleGetLineup(chip::app::AttributeValueEncoder & aEncoder);
CHIP_ERROR HandleGetCurrentChannel(chip::app::AttributeValueEncoder & aEncoder);

void HandleChangeChannel(
chip::app::CommandResponseHelper<chip::app::Clusters::Channel::Commands::ChangeChannelResponse::Type> & helper,
const chip::CharSpan & match);
bool HandleChangeChannelByNumber(const uint16_t & majorNumber, const uint16_t & minorNumber);
bool HandleSkipChannel(const int16_t & count);

static ChefChannelManager & Instance()
{
static ChefChannelManager instance;
return instance;
}

// bool HasFeature(chip::EndpointId endpoint, Feature feature);
uint32_t GetFeatureMap(chip::EndpointId endpoint);

~ChefChannelManager() = default;

protected:
static constexpr size_t kMaxChannels = 10;
uint16_t mCurrentChannelIndex{ 0 };
uint16_t mTotalChannels{ 0 };
std::array<chip::app::Clusters::Channel::Structs::ChannelInfoStruct::Type, kMaxChannels> mChannels;
};
12 changes: 12 additions & 0 deletions examples/chef/common/stubs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

using chip::app::DataModel::Nullable;

using namespace chip;

// Include door lock callbacks only when the server is enabled
#ifdef EMBER_AF_PLUGIN_DOOR_LOCK_SERVER
#include <app/clusters/door-lock-server/door-lock-server.h>
Expand Down Expand Up @@ -237,3 +239,13 @@ bool emberAfPluginDoorLockSetCredential(chip::EndpointId endpointId, uint16_t cr
}

#endif /* EMBER_AF_PLUGIN_DOOR_LOCK_SERVER */

#ifdef EMBER_AF_PLUGIN_CHANNEL_SERVER
#include <chef-channel-manager.h>

void emberAfChannelClusterInitCallback(EndpointId endpoint)
{
app::Clusters::Channel::SetDefaultDelegate(endpoint,
static_cast<app::Clusters::Channel::Delegate *>(&(ChefChannelManager::Instance())));
}
#endif // EMBER_AF_PLUGIN_CHANNEL_SERVER
Loading

0 comments on commit 6e9b15c

Please sign in to comment.