blob: fd6039d5256031f36ea4d9f533b1d21b4aaf901b [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 "ChipDeviceEventHandler.h"
#include "core/CastingPlayer.h"
#include "core/Types.h"
#include "support/CastingStore.h"
#include "support/EndpointListLoader.h"
#include "app/clusters/bindings/BindingManager.h"
namespace matter {
namespace casting {
namespace support {
using namespace matter::casting::core;
bool ChipDeviceEventHandler::sUdcInProgress = false;
void ChipDeviceEventHandler::Handle(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg)
{
ChipLogProgress(AppServer, "ChipDeviceEventHandler::Handle called");
bool runPostCommissioning = false;
chip::NodeId targetNodeId = 0;
chip::FabricIndex targetFabricIndex = 0;
if (event->Type == chip::DeviceLayer::DeviceEventType::kFailSafeTimerExpired &&
CastingPlayer::GetTargetCastingPlayer()->mConnectionState == CASTING_PLAYER_CONNECTING)
{
HandleFailSafeTimerExpired();
}
else if (event->Type == chip::DeviceLayer::DeviceEventType::kBindingsChangedViaCluster &&
CastingPlayer::GetTargetCastingPlayer() != nullptr)
{
HandleBindingsChangedViaCluster(event, arg, runPostCommissioning, targetNodeId, targetFabricIndex);
}
else if (event->Type == chip::DeviceLayer::DeviceEventType::kCommissioningComplete)
{
HandleCommissioningComplete(event, arg, runPostCommissioning, targetNodeId, targetFabricIndex);
}
if (runPostCommissioning)
{
sUdcInProgress = false;
CastingPlayer::GetTargetCastingPlayer()->SetNodeId(targetNodeId);
CastingPlayer::GetTargetCastingPlayer()->SetFabricIndex(targetFabricIndex);
CastingPlayer::GetTargetCastingPlayer()->FindOrEstablishSession(
nullptr,
[](void * context, chip::Messaging::ExchangeManager & exchangeMgr, const chip::SessionHandle & sessionHandle) {
ChipLogProgress(AppServer, "ChipDeviceEventHandler::Handle: Connection to CastingPlayer successful");
CastingPlayer::GetTargetCastingPlayer()->mConnectionState = CASTING_PLAYER_CONNECTED;
// this async call will Load all the endpoints with their respective attributes into the TargetCastingPlayer
// persist the TargetCastingPlayer information into the CastingStore and call mOnCompleted()
EndpointListLoader::GetInstance()->Initialize(&exchangeMgr, &sessionHandle);
EndpointListLoader::GetInstance()->Load();
},
[](void * context, const chip::ScopedNodeId & peerId, CHIP_ERROR error) {
ChipLogError(AppServer, "ChipDeviceEventHandler::Handle: Connection to CastingPlayer failed");
CastingPlayer::GetTargetCastingPlayer()->mConnectionState = CASTING_PLAYER_NOT_CONNECTED;
CHIP_ERROR err = support::CastingStore::GetInstance()->Delete(*CastingPlayer::GetTargetCastingPlayer());
if (err != CHIP_NO_ERROR)
{
ChipLogError(AppServer, "CastingStore::Delete() failed. Err: %" CHIP_ERROR_FORMAT, err.Format());
}
VerifyOrReturn(CastingPlayer::GetTargetCastingPlayer()->mOnCompleted);
CastingPlayer::GetTargetCastingPlayer()->mOnCompleted(error, nullptr);
CastingPlayer::mTargetCastingPlayer = nullptr;
});
}
}
void ChipDeviceEventHandler::HandleFailSafeTimerExpired()
{
// if UDC was in progress (when the Fail-Safe timer expired), reset TargetCastingPlayer commissioning state and return early
if (sUdcInProgress)
{
ChipLogProgress(AppServer, "ChipDeviceEventHandler::HandleFailSafeTimerExpired() when sUdcInProgress: %d, returning early",
sUdcInProgress);
sUdcInProgress = false;
CastingPlayer::GetTargetCastingPlayer()->mConnectionState = CASTING_PLAYER_NOT_CONNECTED;
CastingPlayer::GetTargetCastingPlayer()->mOnCompleted(CHIP_ERROR_TIMEOUT, nullptr);
CastingPlayer::GetTargetCastingPlayer()->mOnCompleted = nullptr;
CastingPlayer::GetTargetCastingPlayer()->mTargetCastingPlayer = nullptr;
return;
}
// if UDC was NOT in progress (when the Fail-Safe timer expired), start UDC
ChipLogProgress(AppServer, "ChipDeviceEventHandler::HandleFailSafeTimerExpired() when sUdcInProgress: %d, starting UDC",
sUdcInProgress);
chip::DeviceLayer::SystemLayer().StartTimer(
chip::System::Clock::Milliseconds32(1),
[](chip::System::Layer * aSystemLayer, void * aAppState) {
ChipLogProgress(AppServer, "ChipDeviceEventHandler::HandleFailSafeTimerExpired() running OpenBasicCommissioningWindow");
CHIP_ERROR err = chip::Server::GetInstance().GetCommissioningWindowManager().OpenBasicCommissioningWindow(
chip::System::Clock::Seconds16(CastingPlayer::GetTargetCastingPlayer()->mCommissioningWindowTimeoutSec));
if (err != CHIP_NO_ERROR)
{
ChipLogError(AppServer,
"ChipDeviceEventHandler::HandleFailSafeTimerExpired() Failed to OpenBasicCommissioningWindow "
"%" CHIP_ERROR_FORMAT,
err.Format());
CastingPlayer::GetTargetCastingPlayer()->mOnCompleted(err, nullptr);
return;
}
#if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT
err = CastingPlayer::GetTargetCastingPlayer()->SendUserDirectedCommissioningRequest();
if (err != CHIP_NO_ERROR)
{
ChipLogError(AppServer,
"ChipDeviceEventHandler::HandleFailSafeTimerExpired() Failed to SendUserDirectedCommissioningRequest "
"%" CHIP_ERROR_FORMAT,
err.Format());
CastingPlayer::GetTargetCastingPlayer()->mOnCompleted(err, nullptr);
return;
}
#endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT
},
nullptr);
}
void ChipDeviceEventHandler::HandleBindingsChangedViaCluster(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg,
bool & runPostCommissioning, chip::NodeId & targetNodeId,
chip::FabricIndex & targetFabricIndex)
{
ChipLogProgress(AppServer, "ChipDeviceEventHandler::HandleBindingsChangedViaCluster called");
if (CastingPlayer::GetTargetCastingPlayer()->IsConnected())
{
// re-use existing nodeId and fabricIndex
ChipLogProgress(AppServer, "ChipDeviceEventHandler::HandleBindingsChangedViaCluster already connected to video player");
runPostCommissioning = true;
targetNodeId = CastingPlayer::GetTargetCastingPlayer()->GetNodeId();
targetFabricIndex = CastingPlayer::GetTargetCastingPlayer()->GetFabricIndex();
}
// handle the "re-commissioning" use case i.e. we received a kBindingsChangedViaCluster event when UDC was in progress (i.e. no
// kCommissioningComplete received)
else if (sUdcInProgress)
{
ChipLogProgress(AppServer,
"ChipDeviceEventHandler::HandleBindingsChangedViaCluster UDC is in progress while handling "
"kBindingsChangedViaCluster with "
"fabricIndex: %d",
event->BindingsChanged.fabricIndex);
sUdcInProgress = false;
// find targetNodeId from binding table by matching the binding's fabricIndex with the accessing fabricIndex
// received in BindingsChanged event
for (const auto & binding : chip::BindingTable::GetInstance())
{
ChipLogProgress(AppServer,
"ChipDeviceEventHandler::HandleBindingsChangedViaCluster Read cached binding type=%d fabrixIndex=%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 && event->BindingsChanged.fabricIndex == binding.fabricIndex)
{
ChipLogProgress(AppServer,
"ChipDeviceEventHandler::HandleBindingsChangedViaCluster Matched accessingFabricIndex with "
"nodeId=0x" ChipLogFormatX64,
ChipLogValueX64(binding.nodeId));
targetNodeId = binding.nodeId;
targetFabricIndex = binding.fabricIndex;
runPostCommissioning = true;
break;
}
}
if (targetNodeId == 0 && runPostCommissioning == false)
{
ChipLogError(AppServer,
"ChipDeviceEventHandler::HandleBindingsChangedViaCluster accessingFabricIndex: %d did not match bindings",
event->BindingsChanged.fabricIndex);
CastingPlayer::GetTargetCastingPlayer()->mOnCompleted(CHIP_ERROR_INCORRECT_STATE,
CastingPlayer::GetTargetCastingPlayer());
return;
}
}
}
void ChipDeviceEventHandler::HandleCommissioningComplete(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg,
bool & runPostCommissioning, chip::NodeId & targetNodeId,
chip::FabricIndex & targetFabricIndex)
{
ChipLogProgress(AppServer, "ChipDeviceEventHandler::HandleCommissioningComplete called");
sUdcInProgress = false;
targetNodeId = event->CommissioningComplete.nodeId;
targetFabricIndex = event->CommissioningComplete.fabricIndex;
runPostCommissioning = true;
}
CHIP_ERROR ChipDeviceEventHandler::SetUdcStatus(bool udcInProgress)
{
ChipLogProgress(AppServer, "ChipDeviceEventHandler::SetUdcStatus() called with udcInProgress: %d", udcInProgress);
if (sUdcInProgress == udcInProgress)
{
ChipLogError(AppServer, "ChipDeviceEventHandler::SetUdcStatus() UDC in progress state is already %d", sUdcInProgress);
return CHIP_ERROR_INCORRECT_STATE;
}
sUdcInProgress = udcInProgress;
return CHIP_NO_ERROR;
}
}; // namespace support
}; // namespace casting
}; // namespace matter