diff --git a/examples/tv-casting-app/tv-casting-common/BUILD.gn b/examples/tv-casting-app/tv-casting-common/BUILD.gn index b6e3cf06688da0..4f323aaebfd92a 100644 --- a/examples/tv-casting-app/tv-casting-common/BUILD.gn +++ b/examples/tv-casting-app/tv-casting-common/BUILD.gn @@ -95,7 +95,8 @@ chip_data_model("tv-casting-common") { "core/CastingPlayerDiscovery.h", "core/Types.h", "support/AppParameters.h", - "support/AppParameters.h", + "support/CastingStore.cpp", + "support/CastingStore.h", "support/ChipDeviceEventHandler.cpp", "support/ChipDeviceEventHandler.h", "support/DataProvider.h", diff --git a/examples/tv-casting-app/tv-casting-common/core/CastingPlayer.h b/examples/tv-casting-app/tv-casting-common/core/CastingPlayer.h index a804d5c802c672..ba88799560f152 100644 --- a/examples/tv-casting-app/tv-casting-common/core/CastingPlayer.h +++ b/examples/tv-casting-app/tv-casting-common/core/CastingPlayer.h @@ -39,10 +39,10 @@ inline constexpr chip::System::Clock::Seconds16 kCommissioningWindowTimeout = ch class CastingPlayerAttributes { public: - char id[kIdMaxLength + 1] = {}; - char deviceName[chip::Dnssd::kMaxDeviceNameLen + 1] = {}; - char hostName[chip::Dnssd::kHostNameMaxLength + 1] = {}; - char instanceName[chip::Dnssd::kHostNameMaxLength + 1] = {}; + char id[kIdMaxLength + 1] = {}; + char deviceName[chip::Dnssd::kMaxDeviceNameLen + 1] = {}; + char hostName[chip::Dnssd::kHostNameMaxLength + 1] = {}; + char instanceName[chip::Dnssd::Commission::kInstanceNameMaxLength + 1] = {}; unsigned int numIPs; // number of valid IP addresses chip::Inet::IPAddress ipAddresses[chip::Dnssd::CommonResolutionData::kMaxIPAddresses]; chip::Inet::InterfaceId interfaceId; diff --git a/examples/tv-casting-app/tv-casting-common/core/CastingPlayerDiscovery.cpp b/examples/tv-casting-app/tv-casting-common/core/CastingPlayerDiscovery.cpp index b4419e995eaeac..27bbe9bc14204b 100644 --- a/examples/tv-casting-app/tv-casting-common/core/CastingPlayerDiscovery.cpp +++ b/examples/tv-casting-app/tv-casting-common/core/CastingPlayerDiscovery.cpp @@ -79,15 +79,13 @@ void DeviceDiscoveryDelegateImpl::OnDiscoveredDevice(const chip::Dnssd::Discover // convert nodeData to CastingPlayer CastingPlayerAttributes attributes; - strcpy(attributes.id, nodeData.resolutionData.hostName); + snprintf(attributes.id, kIdMaxLength + 1, "%s%u", nodeData.resolutionData.hostName, nodeData.resolutionData.port); - char port[kPortMaxLength + 1] = {}; - snprintf(port, sizeof(port), "%u", nodeData.resolutionData.port); - strcat(attributes.id, port); + chip::Platform::CopyString(attributes.deviceName, chip::Dnssd::kMaxDeviceNameLen + 1, nodeData.commissionData.deviceName); + chip::Platform::CopyString(attributes.hostName, chip::Dnssd::kHostNameMaxLength + 1, nodeData.resolutionData.hostName); + chip::Platform::CopyString(attributes.instanceName, chip::Dnssd::Commission::kInstanceNameMaxLength + 1, + nodeData.commissionData.instanceName); - strcpy(attributes.deviceName, nodeData.commissionData.deviceName); - strcpy(attributes.hostName, nodeData.resolutionData.hostName); - strcpy(attributes.instanceName, nodeData.commissionData.instanceName); attributes.numIPs = (unsigned int) nodeData.resolutionData.numIPs; for (unsigned j = 0; j < attributes.numIPs; j++) { diff --git a/examples/tv-casting-app/tv-casting-common/support/CastingStore.cpp b/examples/tv-casting-app/tv-casting-common/support/CastingStore.cpp new file mode 100644 index 00000000000000..01790669bb54dd --- /dev/null +++ b/examples/tv-casting-app/tv-casting-common/support/CastingStore.cpp @@ -0,0 +1,270 @@ +/* + * + * Copyright (c) 2023 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 "CastingStore.h" + +#include +#include + +namespace matter { +namespace casting { +namespace support { + +CastingStore * CastingStore::_CastingStore = nullptr; + +CastingStore::CastingStore() {} + +CastingStore * CastingStore::GetInstance() +{ + if (_CastingStore == nullptr) + { + _CastingStore = new CastingStore(); + } + return _CastingStore; +} + +CHIP_ERROR CastingStore::AddOrUpdate(core::CastingPlayer * CastingPlayer) +{ + return CHIP_NO_ERROR; +} + +std::vector CastingStore::ReadAll() +{ + ChipLogProgress(AppServer, "CastingStore::ReadAll called"); + CHIP_ERROR err = CHIP_NO_ERROR; + + std::vector castingPlayers; + uint8_t castingStoreData[kCastingStoreDataMaxBytes]; + size_t castingStoreDataSize = 0; + err = chip::DeviceLayer::PersistedStorage::KeyValueStoreMgr().Get(kCastingStoreDataKey, castingStoreData, kCastingStoreDataMaxBytes, &castingStoreDataSize); + VerifyOrReturnValue(err == CHIP_NO_ERROR, std::vector(), + ChipLogError(AppServer, "KeyValueStoreMgr.Get failed %" CHIP_ERROR_FORMAT, err.Format())); + ChipLogProgress(AppServer, "CastingStore::ReadAll Read TLV(CastingStoreData) from KVS store with size: %lu bytes", + static_cast(castingStoreDataSize)); + + chip::TLV::TLVReader reader; + reader.Init(castingStoreData); + + // read the envelope (and version) + err = reader.Next(chip::TLV::kTLVType_Structure, chip::TLV::AnonymousTag()); + VerifyOrReturnValue(err == CHIP_NO_ERROR, std::vector(), + ChipLogError(AppServer, "TLVReader.Next failed %" CHIP_ERROR_FORMAT, err.Format())); + + chip::TLV::TLVType outerContainerType = chip::TLV::kTLVType_Structure; + err = reader.EnterContainer(outerContainerType); + VerifyOrReturnValue(err == CHIP_NO_ERROR, std::vector(), + ChipLogError(AppServer, "TLVReader.EnterContainer failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = reader.Next(); + VerifyOrReturnValue(err == CHIP_NO_ERROR, std::vector(), + ChipLogError(AppServer, "TLVReader.Next failed %" CHIP_ERROR_FORMAT, err.Format())); + chip::TLV::Tag outerContainerTag = reader.GetTag(); + uint8_t outerContainerTagTagNum = static_cast(chip::TLV::TagNumFromTag(outerContainerTag)); + VerifyOrReturnValue(outerContainerTagTagNum == kCastingStoreDataVersionTag, castingPlayers, + ChipLogError(AppServer, "CastingStoreDataVersionTag not found")); + uint32_t version; + err = reader.Get(version); + VerifyOrReturnValue(err == CHIP_NO_ERROR, std::vector(), + ChipLogError(AppServer, "TLVReader.Get failed %" CHIP_ERROR_FORMAT, err.Format())); + ChipLogProgress(AppServer, "CastingStore::ReadAll TLV(CastingStoreData) version: %d", version); + + // Entering CastingPlayers container + chip::TLV::TLVType castingPlayersContainerType = chip::TLV::kTLVType_Array; + err = reader.Next(); + VerifyOrReturnValue(err == CHIP_NO_ERROR, std::vector(), + ChipLogError(AppServer, "TLVReader.Next failed %" CHIP_ERROR_FORMAT, err.Format())); + err = reader.EnterContainer(castingPlayersContainerType); + VerifyOrReturnValue(err == CHIP_NO_ERROR, std::vector(), + ChipLogError(AppServer, "TLVReader.EnterContainer failed %" CHIP_ERROR_FORMAT, err.Format())); + while ((err = reader.Next()) == CHIP_NO_ERROR) + { + // Entering CastingPlayer container + chip::TLV::TLVType castingPlayerContainerType = chip::TLV::kTLVType_Structure; + err = reader.EnterContainer(castingPlayerContainerType); + VerifyOrReturnValue(err == CHIP_NO_ERROR, std::vector(), + ChipLogError(AppServer, "TLVReader.EnterContainer failed %" CHIP_ERROR_FORMAT, err.Format())); + + core::CastingPlayerAttributes attributes; + while ((err = reader.Next()) == CHIP_NO_ERROR) + { + chip::TLV::Tag castingPlayerContainerTag = reader.GetTag(); + VerifyOrReturnValue(chip::TLV::IsContextTag(castingPlayerContainerTag), std::vector(), + ChipLogError(AppServer, "Unexpected non-context TLV tag")); + + uint8_t castingPlayerContainerTagNum = static_cast(chip::TLV::TagNumFromTag(castingPlayerContainerTag)); + if (castingPlayerContainerTagNum == kCastingPlayerIdTag) + { + err = reader.GetBytes(reinterpret_cast(attributes.id), core::kIdMaxLength + 1); + VerifyOrReturnValue(err == CHIP_NO_ERROR, std::vector(), + ChipLogError(AppServer, "TLVReader.GetBytes failed %" CHIP_ERROR_FORMAT, err.Format())); + continue; + } + + if (castingPlayerContainerTagNum == kCastingPlayerNodeIdTag) + { + err = reader.Get(attributes.nodeId); + VerifyOrReturnValue(err == CHIP_NO_ERROR, std::vector(), + ChipLogError(AppServer, "TLVReader.Get failed %" CHIP_ERROR_FORMAT, err.Format())); + continue; + } + + if (castingPlayerContainerTagNum == kCastingPlayerFabricIndexTag) + { + err = reader.Get(attributes.fabricIndex); + VerifyOrReturnValue(err == CHIP_NO_ERROR, std::vector(), + ChipLogError(AppServer, "TLVReader.Get failed %" CHIP_ERROR_FORMAT, err.Format())); + continue; + } + + if (castingPlayerContainerTagNum == kCastingPlayerVendorIdTag) + { + err = reader.Get(attributes.vendorId); + VerifyOrReturnValue(err == CHIP_NO_ERROR, std::vector(), + ChipLogError(AppServer, "TLVReader.Get failed %" CHIP_ERROR_FORMAT, err.Format())); + continue; + } + + if (castingPlayerContainerTagNum == kCastingPlayerProductIdTag) + { + err = reader.Get(attributes.productId); + VerifyOrReturnValue(err == CHIP_NO_ERROR, std::vector(), + ChipLogError(AppServer, "TLVReader.Get failed %" CHIP_ERROR_FORMAT, err.Format())); + continue; + } + + if (castingPlayerContainerTagNum == kCastingPlayerDeviceTypeIdTag) + { + err = reader.Get(attributes.deviceType); + VerifyOrReturnValue(err == CHIP_NO_ERROR, std::vector(), + ChipLogError(AppServer, "TLVReader.Get failed %" CHIP_ERROR_FORMAT, err.Format())); + continue; + } + + if (castingPlayerContainerTagNum == kCastingPlayerDeviceNameTag) + { + err = reader.GetBytes(reinterpret_cast(attributes.deviceName), chip::Dnssd::kMaxDeviceNameLen + 1); + VerifyOrReturnValue(err == CHIP_NO_ERROR, std::vector(), + ChipLogError(AppServer, "TLVReader.GetBytes failed %" CHIP_ERROR_FORMAT, err.Format())); + continue; + } + + if (castingPlayerContainerTagNum == kCastingPlayerHostNameTag) + { + err = reader.GetBytes(reinterpret_cast(attributes.hostName), chip::Dnssd::kHostNameMaxLength + 1); + VerifyOrReturnValue(err == CHIP_NO_ERROR, std::vector(), + ChipLogError(AppServer, "TLVReader.GetBytes failed %" CHIP_ERROR_FORMAT, err.Format())); + continue; + } + + if (err == CHIP_END_OF_TLV) + { + // Exiting CastingPlayer container + err = reader.ExitContainer(castingPlayerContainerType); + VerifyOrReturnValue(err == CHIP_NO_ERROR, std::vector(), + ChipLogError(AppServer, "TLVReader.ExitContainer failed %" CHIP_ERROR_FORMAT, err.Format())); + core::CastingPlayer castingPlayer(attributes); + castingPlayers.push_back(castingPlayer); + break; + } + } + } + + VerifyOrReturnValue(err == CHIP_END_OF_TLV, std::vector(), + ChipLogError(AppServer, "TLV parsing failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = reader.ExitContainer(castingPlayersContainerType); + VerifyOrReturnValue(err == CHIP_NO_ERROR, std::vector(), + ChipLogError(AppServer, "TLVReader.ExitContainer failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = reader.ExitContainer(outerContainerType); + VerifyOrReturnValue(err == CHIP_NO_ERROR, std::vector(), + ChipLogError(AppServer, "TLVReader.ExitContainer failed %" CHIP_ERROR_FORMAT, err.Format())); + + ChipLogProgress(AppServer, "CastingStore::ReadAll CastingPlayers size: %lu", static_cast(castingPlayers.size())); + return castingPlayers; +} + +CHIP_ERROR CastingStore::DeleteAll() +{ + return CHIP_NO_ERROR; +} + +CHIP_ERROR CastingStore::Delete(core::CastingPlayer * castingPlayer) +{ + return CHIP_NO_ERROR; +} + +void CastingStore::OnFabricRemoved(const chip::FabricTable & fabricTable, chip::FabricIndex fabricIndex) +{ + +} + +CHIP_ERROR CastingStore::WriteAll(std::vector castingPlayers) +{ + ChipLogProgress(AppServer, "CastingStore::WriteAll called"); + + chip::TLV::TLVWriter tlvWriter; + uint8_t castingStoreData[kCastingStoreDataMaxBytes]; + tlvWriter.Init(castingStoreData, kCastingStoreDataMaxBytes); + + chip::TLV::TLVType outerContainerType = chip::TLV::kTLVType_Structure; + ReturnErrorOnFailure(tlvWriter.StartContainer(chip::TLV::AnonymousTag(), chip::TLV::kTLVType_Structure, outerContainerType)); + ReturnErrorOnFailure(tlvWriter.Put(chip::TLV::ContextTag(kCastingStoreDataVersionTag), kCurrentCastingStoreDataVersion)); + + chip::TLV::TLVType castingPlayersContainerType = chip::TLV::kTLVType_Array; + // CastingPlayers container starts + ReturnErrorOnFailure( + tlvWriter.StartContainer(chip::TLV::ContextTag(kCastingPlayersContainerTag), chip::TLV::kTLVType_Array, castingPlayersContainerType)); + + for(auto & castingPlayer : castingPlayers) + { + chip::TLV::TLVType castingPlayerContainerType = chip::TLV::kTLVType_Structure; + // CastingPlayer container starts + ReturnErrorOnFailure(tlvWriter.StartContainer(chip::TLV::ContextTag(kCastingPlayerContainerTag), chip::TLV::kTLVType_Structure, castingPlayerContainerType)); + + ReturnErrorOnFailure(tlvWriter.Put(chip::TLV::ContextTag(kCastingPlayerIdTag), castingPlayer.GetId())); + ReturnErrorOnFailure(tlvWriter.Put(chip::TLV::ContextTag(kCastingPlayerNodeIdTag), castingPlayer.GetNodeId())); + ReturnErrorOnFailure(tlvWriter.Put(chip::TLV::ContextTag(kCastingPlayerFabricIndexTag), castingPlayer.GetFabricIndex())); + ReturnErrorOnFailure(tlvWriter.Put(chip::TLV::ContextTag(kCastingPlayerVendorIdTag), castingPlayer.GetVendorId())); + ReturnErrorOnFailure(tlvWriter.Put(chip::TLV::ContextTag(kCastingPlayerProductIdTag), castingPlayer.GetProductId())); + ReturnErrorOnFailure(tlvWriter.Put(chip::TLV::ContextTag(kCastingPlayerDeviceTypeIdTag), castingPlayer.GetDeviceType())); + ReturnErrorOnFailure(tlvWriter.PutBytes(chip::TLV::ContextTag(kCastingPlayerDeviceNameTag), + (const uint8_t *) castingPlayer.GetDeviceName(), + static_cast(strlen(castingPlayer.GetDeviceName()) + 1))); + ReturnErrorOnFailure(tlvWriter.PutBytes(chip::TLV::ContextTag(kCastingPlayerHostNameTag), + (const uint8_t *) castingPlayer.GetHostName(), + static_cast(strlen(castingPlayer.GetHostName()) + 1))); + // CastingPlayer container ends + ReturnErrorOnFailure(tlvWriter.EndContainer(castingPlayerContainerType)); + } + + // CastingPlayers container ends + ReturnErrorOnFailure(tlvWriter.EndContainer(castingPlayersContainerType)); + ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType)); + + ReturnErrorOnFailure(tlvWriter.Finalize()); + ChipLogProgress(AppServer, + "CastingStore::WriteAll TLV(CastingStoreData).LengthWritten: %d bytes, CastingPlayers size: %lu " + "and version: %d", + tlvWriter.GetLengthWritten(), castingPlayers.size(), kCurrentCastingStoreDataVersion); + return chip::DeviceLayer::PersistedStorage::KeyValueStoreMgr().Put(kCastingStoreDataKey, castingStoreData, tlvWriter.GetLengthWritten()); +} + +}; // namespace support +}; // namespace casting +}; // namespace matter \ No newline at end of file diff --git a/examples/tv-casting-app/tv-casting-common/support/CastingStore.h b/examples/tv-casting-app/tv-casting-common/support/CastingStore.h new file mode 100644 index 00000000000000..2f91e41b1255e1 --- /dev/null +++ b/examples/tv-casting-app/tv-casting-common/support/CastingStore.h @@ -0,0 +1,73 @@ +/* + * + * Copyright (c) 2023 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 "core/CastingPlayer.h" + +namespace matter { +namespace casting { +namespace support { + +class CastingStore : public chip::FabricTable::Delegate +{ +public: + static CastingStore * GetInstance(); + + CHIP_ERROR AddOrUpdate(core::CastingPlayer * castingPlayer); + + std::vector ReadAll(); + + CHIP_ERROR Delete(core::CastingPlayer * castingPlayer); + + CHIP_ERROR DeleteAll(); + + void OnFabricRemoved(const chip::FabricTable & fabricTable, chip::FabricIndex fabricIndex) override; + +private: + CastingStore(); + static CastingStore * _CastingStore; + + CHIP_ERROR WriteAll(std::vector castingPlayers); + + enum CastingStoreTLVTag + { + kCastingStoreDataVersionTag = 1, + kCastingPlayersContainerTag, + kCastingPlayerContainerTag, + kCastingPlayerIdTag, + kCastingPlayerNodeIdTag, + kCastingPlayerFabricIndexTag, + kCastingPlayerVendorIdTag, + kCastingPlayerProductIdTag, + kCastingPlayerDeviceTypeIdTag, + kCastingPlayerDeviceNameTag, + kCastingPlayerHostNameTag, + + kContextTagMaxNum = UINT8_MAX + }; + + constexpr static size_t kCastingStoreDataMaxBytes = 1024 * 100; // 100 KBs + constexpr static char * kCastingStoreDataKey = (char *) "com.matter.casting.CastingStore"; + constexpr static uint32_t kCurrentCastingStoreDataVersion = 1; + constexpr static uint32_t kSupportedCastingStoreDataVersions[1] = { 1 }; +}; + +}; // namespace support +}; // namespace casting +}; // namespace matter \ No newline at end of file