blob: f5d8f2f5f4da34cbab5bb95cbe809805e196aad6 [file]
/*
*
* Copyright (c) 2026 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 <devices/Types.h>
#include <devices/proximity-ranger/ProximityRangerDevice.h>
using namespace chip::app::Clusters;
namespace {
// Global controller shared across all ProximityRangerDevice instances.
ProximityRanging::RangingTechnologyController & GetRangingController()
{
static ProximityRanging::RangingTechnologyController sRangingController;
return sRangingController;
}
} // namespace
namespace chip {
namespace app {
size_t ProximityRangerDevice::sActiveCount = 0;
ProximityRangerDevice::ProximityRangerDevice(TimerDelegate & timerDelegate,
Span<ProximityRanging::RangingAdapter * const> adapters) :
SingleEndpointDevice(Span<const DataModel::DeviceTypeEntry>(&Device::Type::kProximityRanger, 1)),
mRangingDriver(GetRangingController()), mTimerDelegate(timerDelegate), mAdapters(adapters)
{}
CHIP_ERROR ProximityRangerDevice::Register(chip::EndpointId endpoint, CodeDrivenDataModelProvider & provider, EndpointId parentId)
{
VerifyOrReturnError(!mRegistered, CHIP_ERROR_INCORRECT_STATE);
// Register adapters with the shared controller, skipping any already registered.
for (auto * adapter : mAdapters)
{
VerifyOrReturnError(adapter != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
ReturnErrorOnFailure(GetRangingController().RegisterAdapter(*adapter).NoErrorIf(CHIP_ERROR_DUPLICATE_KEY_ID));
}
ReturnErrorOnFailure(SingleEndpointRegistration(endpoint, provider, parentId));
mIdentifyCluster.Create(IdentifyCluster::Config(endpoint, mTimerDelegate));
ReturnErrorOnFailure(provider.AddCluster(mIdentifyCluster.Registration()));
// Configure cluster features based on registered adapters' technologies.
BitMask<ProximityRanging::Feature> features;
for (auto * adapter : mAdapters)
{
switch (adapter->GetTechnology())
{
case ProximityRanging::RangingTechEnum::kBluetoothChannelSounding:
features.Set(ProximityRanging::Feature::kBluetoothChannelSounding);
break;
case ProximityRanging::RangingTechEnum::kWiFiRoundTripTimeRanging:
case ProximityRanging::RangingTechEnum::kWiFiNextGenerationRanging:
features.Set(ProximityRanging::Feature::kWiFiUsdProximityDetection);
break;
case ProximityRanging::RangingTechEnum::kBLEBeaconRSSIRanging:
features.Set(ProximityRanging::Feature::kBleBeaconRssi);
break;
default:
break;
}
}
mProximityRangingCluster.Create(endpoint, ProximityRanging::ProximityRangingCluster::Config().WithFeatures(features));
mProximityRangingCluster.Cluster().SetDriver(&mRangingDriver);
ReturnErrorOnFailure(provider.AddCluster(mProximityRangingCluster.Registration()));
ReturnErrorOnFailure(provider.AddEndpoint(mEndpointRegistration));
mRegistered = true;
sActiveCount++;
return CHIP_NO_ERROR;
}
void ProximityRangerDevice::Unregister(CodeDrivenDataModelProvider & provider)
{
SingleEndpointUnregistration(provider);
if (mProximityRangingCluster.IsConstructed())
{
LogErrorOnFailure(provider.RemoveCluster(&mProximityRangingCluster.Cluster()));
mProximityRangingCluster.Destroy();
}
if (mIdentifyCluster.IsConstructed())
{
LogErrorOnFailure(provider.RemoveCluster(&mIdentifyCluster.Cluster()));
mIdentifyCluster.Destroy();
}
if (!mRegistered)
{
return;
}
mRegistered = false;
if (--sActiveCount != 0)
{
return;
}
for (auto * adapter : mAdapters)
{
if (adapter != nullptr)
{
LogErrorOnFailure(GetRangingController().UnregisterAdapter(*adapter));
}
}
}
} // namespace app
} // namespace chip