blob: 4e03d41e14949c5dc67f14e52117fb4f1d0c7b7a [file] [log] [blame]
/*
*
* Copyright (c) 2020-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 <cstdint>
#include <memory>
#include <ble/Ble.h>
#include <lib/core/CHIPError.h>
#include <lib/support/CodeUtils.h>
#include <platform/CHIPDeviceLayer.h>
#include <platform/Linux/BlePlatformConfig.h>
#include <platform/Linux/bluez/AdapterIterator.h>
#include <platform/Linux/bluez/BluezObjectManager.h>
#include <platform/Linux/bluez/ChipDeviceScanner.h>
#include <platform/Linux/dbus/bluez/DbusBluez.h>
#include <platform/PlatformManager.h>
#include <system/SystemClock.h>
#include <system/SystemLayer.h>
using namespace chip::DeviceLayer::Internal;
/////////// Listing adapters implementation //////////
extern "C" void * pychip_ble_adapter_list_new()
{
return static_cast<void *>(new AdapterIterator());
}
extern "C" void pychip_ble_adapter_list_delete(void * adapterIterator)
{
delete static_cast<AdapterIterator *>(adapterIterator);
}
extern "C" bool pychip_ble_adapter_list_next(void * adapterIterator)
{
return static_cast<AdapterIterator *>(adapterIterator)->Next();
}
extern "C" uint32_t pychip_ble_adapter_list_get_index(void * adapterIterator)
{
return static_cast<AdapterIterator *>(adapterIterator)->GetIndex();
}
extern "C" const char * pychip_ble_adapter_list_get_address(void * adapterIterator)
{
return static_cast<AdapterIterator *>(adapterIterator)->GetAddress();
}
extern "C" const char * pychip_ble_adapter_list_get_alias(void * adapterIterator)
{
return static_cast<AdapterIterator *>(adapterIterator)->GetAlias();
}
extern "C" const char * pychip_ble_adapter_list_get_name(void * adapterIterator)
{
return static_cast<AdapterIterator *>(adapterIterator)->GetName();
}
extern "C" bool pychip_ble_adapter_list_is_powered(void * adapterIterator)
{
return static_cast<AdapterIterator *>(adapterIterator)->IsPowered();
}
extern "C" void * pychip_ble_adapter_list_get_raw_adapter(void * adapterIterator)
{
return static_cast<AdapterIterator *>(adapterIterator)->GetAdapter();
}
/////////// CHIP Device scanner implementation //////////
namespace {
// To avoid python compatibility issues on inc/dec references,
// code assumes an abstract type and leaves it up to python to keep track of
// reference counts
struct PyObject;
class ScannerDelegateImpl : public ChipDeviceScannerDelegate
{
public:
using DeviceScannedCallback = void (*)(PyObject * context, const char * address, uint16_t discriminator, uint16_t vendorId,
uint16_t productId);
using ScanCompleteCallback = void (*)(PyObject * context);
using ScanErrorCallback = void (*)(PyObject * context, CHIP_ERROR::StorageType error);
ScannerDelegateImpl(PyObject * context, DeviceScannedCallback scanCallback, ScanCompleteCallback completeCallback,
ScanErrorCallback errorCallback) :
mContext(context),
mScanCallback(scanCallback), mCompleteCallback(completeCallback), mErrorCallback(errorCallback)
{}
CHIP_ERROR ScannerInit(BluezAdapter1 * adapter)
{
ReturnErrorOnFailure(mBluezObjectManager.Init());
return mScanner.Init(adapter, this);
}
void ScannerShutdown() { mBluezObjectManager.Shutdown(); }
CHIP_ERROR ScannerStartScan(chip::System::Clock::Timeout timeout)
{
CHIP_ERROR err = mScanner.StartScan();
VerifyOrReturnError(err == CHIP_NO_ERROR, err);
err = chip::DeviceLayer::SystemLayer().StartTimer(timeout, HandleScannerTimer, this);
VerifyOrReturnError(err == CHIP_NO_ERROR, err, mScanner.StopScan());
return CHIP_NO_ERROR;
}
CHIP_ERROR ScannerStopScan()
{
chip::DeviceLayer::SystemLayer().CancelTimer(HandleScannerTimer, this);
return mScanner.StopScan();
}
static void HandleScannerTimer(chip::System::Layer *, void * appState)
{
auto * delegate = static_cast<ScannerDelegateImpl *>(appState);
delegate->OnScanError(CHIP_ERROR_TIMEOUT);
delegate->mScanner.StopScan();
}
void OnDeviceScanned(BluezDevice1 & device, const chip::Ble::ChipBLEDeviceIdentificationInfo & info) override
{
if (mScanCallback)
{
mScanCallback(mContext, bluez_device1_get_address(&device), info.GetDeviceDiscriminator(), info.GetProductId(),
info.GetVendorId());
}
}
void OnScanComplete() override
{
if (mCompleteCallback)
{
mCompleteCallback(mContext);
}
}
void OnScanError(CHIP_ERROR error) override
{
if (mErrorCallback)
{
mErrorCallback(mContext, error.AsInteger());
}
}
private:
BluezObjectManager mBluezObjectManager;
ChipDeviceScanner mScanner{ mBluezObjectManager };
PyObject * const mContext;
const DeviceScannedCallback mScanCallback;
const ScanCompleteCallback mCompleteCallback;
const ScanErrorCallback mErrorCallback;
};
} // namespace
extern "C" void * pychip_ble_scanner_start(PyObject * context, void * adapter, uint32_t timeoutMs,
ScannerDelegateImpl::DeviceScannedCallback scanCallback,
ScannerDelegateImpl::ScanCompleteCallback completeCallback,
ScannerDelegateImpl::ScanErrorCallback errorCallback)
{
std::unique_ptr<ScannerDelegateImpl> delegate =
std::make_unique<ScannerDelegateImpl>(context, scanCallback, completeCallback, errorCallback);
CHIP_ERROR err = delegate->ScannerInit(static_cast<BluezAdapter1 *>(adapter));
VerifyOrReturnError(err == CHIP_NO_ERROR, nullptr);
chip::DeviceLayer::PlatformMgr().LockChipStack();
err = delegate->ScannerStartScan(chip::System::Clock::Milliseconds32(timeoutMs));
chip::DeviceLayer::PlatformMgr().UnlockChipStack();
VerifyOrReturnError(err == CHIP_NO_ERROR, nullptr);
return delegate.release();
}
extern "C" void pychip_ble_scanner_delete(void * scanner)
{
auto * delegate = static_cast<ScannerDelegateImpl *>(scanner);
chip::DeviceLayer::StackLock lock;
// Make sure that the scanner is stopped before deleting the delegate.
delegate->ScannerStopScan();
delegate->ScannerShutdown();
delete delegate;
}