| /** |
| * |
| * Copyright (c) 2021 Project CHIP Authors |
| * |
| * 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 "ChannelManager.h" |
| #include <app-common/zap-generated/attributes/Accessors.h> |
| #include <app/util/config.h> |
| |
| #include <vector> |
| |
| using namespace chip; |
| using namespace chip::app; |
| using namespace chip::app::Clusters::Channel; |
| using namespace chip::Uint8; |
| |
| ChannelManager::ChannelManager() |
| { |
| 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.push_back(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.push_back(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.push_back(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.push_back(worldChannel); |
| |
| mCurrentChannelIndex = 0; |
| mCurrentChannel = mChannels[mCurrentChannelIndex]; |
| } |
| |
| CHIP_ERROR ChannelManager::HandleGetChannelList(AttributeValueEncoder & aEncoder) |
| { |
| // TODO: Insert code here |
| return aEncoder.EncodeList([](const auto & encoder) -> CHIP_ERROR { |
| for (auto const & channel : ChannelManager().mChannels) |
| { |
| ReturnErrorOnFailure(encoder.Encode(channel)); |
| } |
| return CHIP_NO_ERROR; |
| }); |
| } |
| |
| CHIP_ERROR ChannelManager::HandleGetLineup(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 ChannelManager::HandleGetCurrentChannel(AttributeValueEncoder & aEncoder) |
| { |
| return aEncoder.Encode(mCurrentChannel); |
| } |
| |
| bool isChannelMatched(const ChannelInfoType & channel, const CharSpan & match) |
| { |
| char number[32]; |
| sprintf(number, "%d.%d", channel.majorNumber, channel.minorNumber); |
| bool nameMatch = channel.name.HasValue() ? channel.name.Value().data_equal(match) : false; |
| bool affiliateCallSignMatch = |
| channel.affiliateCallSign.HasValue() ? channel.affiliateCallSign.Value().data_equal(match) : false; |
| bool callSignMatch = channel.callSign.HasValue() ? channel.callSign.Value().data_equal(match) : false; |
| bool numberMatch = match.data_equal(chip::CharSpan::fromCharString(number)); |
| |
| return affiliateCallSignMatch || callSignMatch || nameMatch || numberMatch; |
| } |
| |
| void ChannelManager::HandleChangeChannel(CommandResponseHelper<ChangeChannelResponseType> & helper, const CharSpan & match) |
| { |
| std::vector<ChannelInfoType> matchedChannels; |
| uint16_t index = 0; |
| for (auto const & channel : mChannels) |
| { |
| // verify if CharSpan matches channel name |
| // or callSign or affiliateCallSign or majorNumber.minorNumber |
| if (isChannelMatched(channel, match)) |
| { |
| matchedChannels.push_back(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")); |
| mCurrentChannel = matchedChannels[0]; |
| mCurrentChannelIndex = index; |
| helper.Success(response); |
| } |
| } |
| |
| bool ChannelManager::HandleChangeChannelByNumber(const uint16_t & majorNumber, const uint16_t & minorNumber) |
| { |
| // TODO: Insert code here |
| 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 != mCurrentChannel.minorNumber || channel.majorNumber != mCurrentChannel.majorNumber) |
| { |
| channelChanged = true; |
| mCurrentChannelIndex = index; |
| mCurrentChannel = channel; |
| } |
| } |
| index++; |
| } |
| return channelChanged; |
| } |
| |
| bool ChannelManager::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); |
| mCurrentChannel = mChannels[mCurrentChannelIndex]; |
| return true; |
| } |
| |
| uint32_t ChannelManager::GetFeatureMap(chip::EndpointId endpoint) |
| { |
| if (endpoint >= EMBER_AF_CONTENT_LAUNCHER_CLUSTER_SERVER_ENDPOINT_COUNT) |
| { |
| return mDynamicEndpointFeatureMap; |
| } |
| |
| uint32_t featureMap = 0; |
| Attributes::FeatureMap::Get(endpoint, &featureMap); |
| return featureMap; |
| } |