| /* |
| * |
| * 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; |
| } |