chef-channel-manager.cpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. /**
  2. *
  3. * Copyright (c) 2021 Project CHIP Authors
  4. * All rights reserved.
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the "License");
  7. * you may not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. #include <app-common/zap-generated/attributes/Accessors.h>
  19. #include <app-common/zap-generated/callback.h>
  20. #include <app/util/config.h>
  21. using ChangeChannelResponseType = chip::app::Clusters::Channel::Commands::ChangeChannelResponse::Type;
  22. using ChannelInfoType = chip::app::Clusters::Channel::Structs::ChannelInfoStruct::Type;
  23. using LineupInfoType = chip::app::Clusters::Channel::Structs::LineupInfoStruct::Type;
  24. // Include Channel Cluster Server callbacks only when the server is enabled
  25. #ifdef EMBER_AF_PLUGIN_CHANNEL_SERVER
  26. #include <chef-channel-manager.h>
  27. using namespace chip;
  28. using namespace chip::app;
  29. using namespace chip::app::Clusters::Channel;
  30. using namespace chip::Uint8;
  31. ChefChannelManager::ChefChannelManager()
  32. {
  33. ChannelInfoType abc;
  34. abc.affiliateCallSign = MakeOptional(chip::CharSpan::fromCharString("KAAL"));
  35. abc.callSign = MakeOptional(chip::CharSpan::fromCharString("KAAL-TV"));
  36. abc.name = MakeOptional(chip::CharSpan::fromCharString("ABC"));
  37. abc.majorNumber = static_cast<uint8_t>(6);
  38. abc.minorNumber = static_cast<uint16_t>(0);
  39. mChannels[mTotalChannels++] = abc;
  40. ChannelInfoType pbs;
  41. pbs.affiliateCallSign = MakeOptional(chip::CharSpan::fromCharString("KCTS"));
  42. pbs.callSign = MakeOptional(chip::CharSpan::fromCharString("KCTS-TV"));
  43. pbs.name = MakeOptional(chip::CharSpan::fromCharString("PBS"));
  44. pbs.majorNumber = static_cast<uint8_t>(9);
  45. pbs.minorNumber = static_cast<uint16_t>(1);
  46. mChannels[mTotalChannels++] = pbs;
  47. ChannelInfoType pbsKids;
  48. pbsKids.affiliateCallSign = MakeOptional(chip::CharSpan::fromCharString("KCTS"));
  49. pbsKids.callSign = MakeOptional(chip::CharSpan::fromCharString("KCTS-TV"));
  50. pbsKids.name = MakeOptional(chip::CharSpan::fromCharString("PBS Kids"));
  51. pbsKids.majorNumber = static_cast<uint8_t>(9);
  52. pbsKids.minorNumber = static_cast<uint16_t>(2);
  53. mChannels[mTotalChannels++] = pbsKids;
  54. ChannelInfoType worldChannel;
  55. worldChannel.affiliateCallSign = MakeOptional(chip::CharSpan::fromCharString("KCTS"));
  56. worldChannel.callSign = MakeOptional(chip::CharSpan::fromCharString("KCTS-TV"));
  57. worldChannel.name = MakeOptional(chip::CharSpan::fromCharString("World Channel"));
  58. worldChannel.majorNumber = static_cast<uint8_t>(9);
  59. worldChannel.minorNumber = static_cast<uint16_t>(3);
  60. mChannels[mTotalChannels++] = worldChannel;
  61. }
  62. static bool isChannelMatched(const ChannelInfoType & channel, const CharSpan & match)
  63. {
  64. if (channel.name.HasValue() && channel.name.Value().data_equal(match))
  65. {
  66. return true;
  67. }
  68. if (channel.affiliateCallSign.HasValue() && channel.affiliateCallSign.Value().data_equal(match))
  69. {
  70. return true;
  71. }
  72. if (channel.callSign.HasValue() && channel.callSign.Value().data_equal(match))
  73. {
  74. return true;
  75. }
  76. StringBuilder<32> nr;
  77. nr.AddFormat("%d.%d", channel.majorNumber, channel.minorNumber);
  78. return match.data_equal(CharSpan::fromCharString(nr.c_str()));
  79. }
  80. CHIP_ERROR ChefChannelManager::HandleGetChannelList(app::AttributeValueEncoder & aEncoder)
  81. {
  82. return aEncoder.EncodeList([](const auto & encoder) -> CHIP_ERROR {
  83. int index = 0;
  84. for (auto const & channel : ChefChannelManager().mChannels)
  85. {
  86. ReturnErrorOnFailure(encoder.Encode(channel));
  87. index++;
  88. if (index >= ChefChannelManager().mTotalChannels)
  89. break;
  90. }
  91. return CHIP_NO_ERROR;
  92. });
  93. }
  94. CHIP_ERROR ChefChannelManager::HandleGetLineup(app::AttributeValueEncoder & aEncoder)
  95. {
  96. LineupInfoType lineup;
  97. lineup.operatorName = chip::CharSpan::fromCharString("Comcast");
  98. lineup.lineupName = MakeOptional(chip::CharSpan::fromCharString("Comcast King County"));
  99. lineup.postalCode = MakeOptional(chip::CharSpan::fromCharString("98052"));
  100. lineup.lineupInfoType = chip::app::Clusters::Channel::LineupInfoTypeEnum::kMso;
  101. return aEncoder.Encode(lineup);
  102. }
  103. CHIP_ERROR ChefChannelManager::HandleGetCurrentChannel(app::AttributeValueEncoder & aEncoder)
  104. {
  105. return aEncoder.Encode(mChannels[mCurrentChannelIndex]);
  106. }
  107. void ChefChannelManager::HandleChangeChannel(CommandResponseHelper<ChangeChannelResponseType> & helper,
  108. const chip::CharSpan & match)
  109. {
  110. std::array<ChannelInfoType, kMaxChannels> matchedChannels;
  111. uint16_t index = 0;
  112. uint16_t totalMatchedChannels = 0;
  113. for (auto const & channel : mChannels)
  114. {
  115. // verify if CharSpan matches channel name
  116. // or callSign or affiliateCallSign or majorNumber.minorNumber
  117. if (isChannelMatched(channel, match))
  118. {
  119. matchedChannels[totalMatchedChannels++] = (channel);
  120. }
  121. else if (totalMatchedChannels == 0)
  122. {
  123. // "index" is only used when we end up with totalMatchedChannels == 1.
  124. // In that case, we want it to be the number of non-matching channels we saw before
  125. // the matching one.
  126. index++;
  127. }
  128. }
  129. ChangeChannelResponseType response;
  130. // Error: Found multiple matches
  131. if (totalMatchedChannels > 1)
  132. {
  133. response.status = chip::app::Clusters::Channel::ChannelStatusEnum::kMultipleMatches;
  134. helper.Success(response);
  135. }
  136. else if (totalMatchedChannels == 0)
  137. {
  138. // Error: Found no match
  139. response.status = chip::app::Clusters::Channel::ChannelStatusEnum::kNoMatches;
  140. helper.Success(response);
  141. }
  142. else
  143. {
  144. response.status = chip::app::Clusters::Channel::ChannelStatusEnum::kSuccess;
  145. response.data = chip::MakeOptional(CharSpan::fromCharString("data response"));
  146. mCurrentChannelIndex = index;
  147. helper.Success(response);
  148. }
  149. }
  150. bool ChefChannelManager::HandleChangeChannelByNumber(const uint16_t & majorNumber, const uint16_t & minorNumber)
  151. {
  152. bool channelChanged = false;
  153. uint16_t index = 0;
  154. for (auto const & channel : mChannels)
  155. {
  156. // verify if major & minor matches one of the channel from the list
  157. if (channel.minorNumber == minorNumber && channel.majorNumber == majorNumber)
  158. {
  159. // verify if channel changed by comparing values of current channel with the requested channel
  160. if (channel.minorNumber != mChannels[mCurrentChannelIndex].minorNumber ||
  161. channel.majorNumber != mChannels[mCurrentChannelIndex].majorNumber)
  162. {
  163. channelChanged = true;
  164. mCurrentChannelIndex = index;
  165. }
  166. // return since we've already found the unique matched channel
  167. return channelChanged;
  168. }
  169. index++;
  170. if (index >= mTotalChannels)
  171. break;
  172. }
  173. return channelChanged;
  174. }
  175. bool ChefChannelManager::HandleSkipChannel(const int16_t & count)
  176. {
  177. int32_t newChannelIndex = static_cast<int32_t>(count) + static_cast<int32_t>(mCurrentChannelIndex);
  178. uint16_t channelsSize = static_cast<uint16_t>(mChannels.size());
  179. // handle newChannelIndex out of range.
  180. newChannelIndex = newChannelIndex % channelsSize;
  181. if (newChannelIndex < 0)
  182. {
  183. newChannelIndex = newChannelIndex + channelsSize;
  184. }
  185. mCurrentChannelIndex = static_cast<uint16_t>(newChannelIndex);
  186. return true;
  187. }
  188. uint32_t ChefChannelManager::GetFeatureMap(chip::EndpointId endpoint)
  189. {
  190. if (endpoint > EMBER_AF_CHANNEL_CLUSTER_SERVER_ENDPOINT_COUNT)
  191. {
  192. return 0;
  193. }
  194. uint32_t featureMap = 0;
  195. Attributes::FeatureMap::Get(endpoint, &featureMap);
  196. return featureMap;
  197. }
  198. #endif /* EMBER_AF_PLUGIN_CHANNEL_SERVER */