blob: 6077fd3d20b6f0d3caff77186bea60c602f61c8e [file] [log] [blame]
/**
*
* 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 (totalMatchedChannels == 0)
{
// "index" is only used when we end up with totalMatchedChannels == 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 (totalMatchedChannels > 1)
{
response.status = chip::app::Clusters::Channel::ChannelStatusEnum::kMultipleMatches;
helper.Success(response);
}
else if (totalMatchedChannels == 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 */