blob: a7bbfb78d6ad3a94f3163b0df5313c76b5b1f52f [file] [log] [blame]
/*
*
* 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 "EndpointListLoader.h"
#include "clusters/Clusters.h"
#include "core/BaseCluster.h"
#include "core/CastingPlayer.h"
#include "core/Types.h"
#include "support/CastingStore.h"
#include "app/clusters/bindings/BindingManager.h"
#include <app-common/zap-generated/cluster-objects.h>
namespace matter {
namespace casting {
namespace support {
using namespace matter::casting::core;
EndpointListLoader * EndpointListLoader::_endpointListLoader = nullptr;
EndpointListLoader::EndpointListLoader() {}
EndpointListLoader * EndpointListLoader::GetInstance()
{
if (_endpointListLoader == nullptr)
{
_endpointListLoader = new EndpointListLoader();
}
return _endpointListLoader;
}
void EndpointListLoader::Initialize(chip::Messaging::ExchangeManager * exchangeMgr, const chip::SessionHandle * sessionHandle)
{
mExchangeMgr = exchangeMgr;
mSessionHandle = sessionHandle;
for (const auto & binding : chip::BindingTable::GetInstance())
{
if (binding.type == MATTER_UNICAST_BINDING && CastingPlayer::GetTargetCastingPlayer()->GetNodeId() == binding.nodeId)
{
// check to see if we discovered a new endpoint in the bindings
chip::EndpointId endpointId = binding.remote;
std::vector<memory::Strong<Endpoint>> endpoints = CastingPlayer::GetTargetCastingPlayer()->GetEndpoints();
if (std::find_if(endpoints.begin(), endpoints.end(), [&endpointId](const memory::Strong<Endpoint> & endpoint) {
return endpoint->GetId() == endpointId;
}) == endpoints.end())
{
mNewEndpointsToLoad++;
}
}
}
mPendingAttributeReads = mNewEndpointsToLoad * kTotalDesiredAttributes;
mEndpointAttributesList = new EndpointAttributes[mNewEndpointsToLoad];
mEndpointServerLists = new std::vector<chip::ClusterId>[mNewEndpointsToLoad];
}
CHIP_ERROR EndpointListLoader::Load()
{
ChipLogProgress(AppServer, "EndpointListLoader::Load() called");
VerifyOrReturnError(CastingPlayer::GetTargetCastingPlayer() != nullptr, CHIP_ERROR_INCORRECT_STATE);
int endpointIndex = -1;
bool isLoadingRequired = false;
for (const auto & binding : chip::BindingTable::GetInstance())
{
ChipLogProgress(AppServer,
"Binding type=%d fab=%d nodeId=0x" ChipLogFormatX64
" groupId=%d local endpoint=%d remote endpoint=%d cluster=" ChipLogFormatMEI,
binding.type, binding.fabricIndex, ChipLogValueX64(binding.nodeId), binding.groupId, binding.local,
binding.remote, ChipLogValueMEI(binding.clusterId.value_or(0)));
if (binding.type == MATTER_UNICAST_BINDING && CastingPlayer::GetTargetCastingPlayer()->GetNodeId() == binding.nodeId)
{
// if we discovered a new Endpoint from the bindings, read its EndpointAttributes
chip::EndpointId endpointId = binding.remote;
std::vector<memory::Strong<Endpoint>> endpoints = CastingPlayer::GetTargetCastingPlayer()->GetEndpoints();
if (std::find_if(endpoints.begin(), endpoints.end(), [&endpointId](const memory::Strong<Endpoint> & endpoint) {
return endpoint->GetId() == endpointId;
}) == endpoints.end())
{
// Read attributes and mEndpointAttributesList for (endpointIndex + 1)
ChipLogProgress(AppServer, "EndpointListLoader::Load Reading attributes for endpointId %d", endpointId);
isLoadingRequired = true;
mEndpointAttributesList[++endpointIndex].mId = endpointId;
ReadVendorId(&mEndpointAttributesList[endpointIndex]);
ReadProductId(&mEndpointAttributesList[endpointIndex]);
ReadDeviceTypeList(&mEndpointAttributesList[endpointIndex]);
ReadServerList(&mEndpointServerLists[endpointIndex], endpointId);
}
}
}
if (!isLoadingRequired)
{
ChipLogProgress(AppServer, "EndpointListLoader::Load found no new endpoints to load");
mPendingAttributeReads = 0;
Complete();
}
return CHIP_NO_ERROR;
}
void EndpointListLoader::Complete()
{
ChipLogProgress(AppServer, "EndpointListLoader::Complete called with mPendingAttributeReads %lu", mPendingAttributeReads);
if (mPendingAttributeReads > 0)
{
mPendingAttributeReads--;
}
if (mPendingAttributeReads == 0)
{
ChipLogProgress(AppServer, "EndpointListLoader::Complete Loading %lu endpoint(s)", mNewEndpointsToLoad);
for (unsigned long i = 0; i < mNewEndpointsToLoad; i++)
{
EndpointAttributes endpointAttributes = mEndpointAttributesList[i];
std::shared_ptr<Endpoint> endpoint =
std::make_shared<Endpoint>(CastingPlayer::GetTargetCastingPlayer(), endpointAttributes);
endpoint->RegisterClusters(mEndpointServerLists[i]);
CastingPlayer::GetTargetCastingPlayer()->RegisterEndpoint(endpoint);
}
ChipLogProgress(AppServer, "EndpointListLoader::Complete finished Loading %lu endpoints", mNewEndpointsToLoad);
// TODO cleanup
// delete mEndpointAttributesList;
mEndpointAttributesList = nullptr;
// delete mEndpointServerLists;
mEndpointServerLists = nullptr;
mExchangeMgr = nullptr;
mSessionHandle = nullptr;
mNewEndpointsToLoad = 0;
// done loading endpoints, store TargetCastingPlayer
CHIP_ERROR err = support::CastingStore::GetInstance()->AddOrUpdate(*CastingPlayer::GetTargetCastingPlayer());
if (err != CHIP_NO_ERROR)
{
ChipLogError(AppServer, "CastingStore::AddOrUpdate() failed. Err: %" CHIP_ERROR_FORMAT, err.Format());
}
// callback client OnCompleted
VerifyOrReturn(CastingPlayer::GetTargetCastingPlayer()->mOnCompleted,
ChipLogError(AppServer, "EndpointListLoader::Complete mOnCompleted() not found"));
CastingPlayer::GetTargetCastingPlayer()->mOnCompleted(CHIP_NO_ERROR, CastingPlayer::GetTargetCastingPlayer());
}
}
CHIP_ERROR EndpointListLoader::ReadVendorId(EndpointAttributes * endpointAttributes)
{
core::MediaClusterBase cluster(*mExchangeMgr, *mSessionHandle, endpointAttributes->mId);
return cluster.template ReadAttribute<chip::app::Clusters::ApplicationBasic::Attributes::VendorID::TypeInfo>(
endpointAttributes,
[](void * context,
chip::app::Clusters::ApplicationBasic::Attributes::VendorID::TypeInfo::DecodableArgType decodableVendorId) {
EndpointAttributes * _endpointAttributes = static_cast<EndpointAttributes *>(context);
_endpointAttributes->mVendorId = decodableVendorId;
EndpointListLoader::GetInstance()->Complete();
},
[](void * context, CHIP_ERROR err) {
EndpointAttributes * _endpointAttributes = static_cast<EndpointAttributes *>(context);
ChipLogError(AppServer, "EndpointListLoader ReadAttribute(VendorID) failed for endpointID %d. Err: %" CHIP_ERROR_FORMAT,
_endpointAttributes->mId, err.Format());
EndpointListLoader::GetInstance()->Complete();
});
}
CHIP_ERROR EndpointListLoader::ReadProductId(EndpointAttributes * endpointAttributes)
{
core::MediaClusterBase cluster(*mExchangeMgr, *mSessionHandle, endpointAttributes->mId);
return cluster.template ReadAttribute<chip::app::Clusters::ApplicationBasic::Attributes::ProductID::TypeInfo>(
endpointAttributes,
[](void * context,
chip::app::Clusters::ApplicationBasic::Attributes::ProductID::TypeInfo::DecodableArgType decodableProductId) {
EndpointAttributes * _endpointAttributes = static_cast<EndpointAttributes *>(context);
_endpointAttributes->mProductId = decodableProductId;
EndpointListLoader::GetInstance()->Complete();
},
[](void * context, CHIP_ERROR err) {
EndpointAttributes * _endpointAttributes = static_cast<EndpointAttributes *>(context);
ChipLogError(AppServer,
"EndpointListLoader ReadAttribute(ProductID) failed for endpointID %d. Err: %" CHIP_ERROR_FORMAT,
_endpointAttributes->mId, err.Format());
EndpointListLoader::GetInstance()->Complete();
});
}
CHIP_ERROR EndpointListLoader::ReadDeviceTypeList(EndpointAttributes * endpointAttributes)
{
core::MediaClusterBase cluster(*mExchangeMgr, *mSessionHandle, endpointAttributes->mId);
return cluster.template ReadAttribute<chip::app::Clusters::Descriptor::Attributes::DeviceTypeList::TypeInfo>(
endpointAttributes,
[](void * context,
chip::app::Clusters::Descriptor::Attributes::DeviceTypeList::TypeInfo::DecodableArgType decodableDeviceTypeList) {
EndpointAttributes * _endpointAttributes = static_cast<EndpointAttributes *>(context);
auto iter = decodableDeviceTypeList.begin();
while (iter.Next())
{
auto & deviceType = iter.GetValue();
_endpointAttributes->mDeviceTypeList.push_back(deviceType);
}
EndpointListLoader::GetInstance()->Complete();
},
[](void * context, CHIP_ERROR err) {
EndpointAttributes * _endpointAttributes = static_cast<EndpointAttributes *>(context);
ChipLogError(AppServer,
"EndpointListLoader ReadAttribute(DeviceTypeList) failed for endpointID %d. Err: %" CHIP_ERROR_FORMAT,
_endpointAttributes->mId, err.Format());
EndpointListLoader::GetInstance()->Complete();
});
}
CHIP_ERROR EndpointListLoader::ReadServerList(std::vector<chip::ClusterId> * endpointServerList, chip::EndpointId endpointId)
{
core::MediaClusterBase cluster(*mExchangeMgr, *mSessionHandle, endpointId);
return cluster.template ReadAttribute<chip::app::Clusters::Descriptor::Attributes::ServerList::TypeInfo>(
endpointServerList,
[](void * context,
chip::app::Clusters::Descriptor::Attributes::ServerList::TypeInfo::DecodableArgType decodableServerList) {
std::vector<chip::ClusterId> * _endpointServerList = static_cast<std::vector<chip::ClusterId> *>(context);
auto iter = decodableServerList.begin();
while (iter.Next())
{
auto & clusterId = iter.GetValue();
_endpointServerList->push_back(clusterId);
}
EndpointListLoader::GetInstance()->Complete();
},
[](void * context, CHIP_ERROR err) {
ChipLogError(AppServer, "EndpointListLoader ReadAttribute(ServerList) failed. Err: %" CHIP_ERROR_FORMAT, err.Format());
EndpointListLoader::GetInstance()->Complete();
});
}
}; // namespace support
}; // namespace casting
}; // namespace matter