// // Copyright (C) 2015 Google, Inc. // // 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. // #pragma once #include #include #include #include #include #include "service/bluetooth_instance.h" #include "service/common/bluetooth/advertise_data.h" #include "service/common/bluetooth/advertise_settings.h" #include "service/common/bluetooth/low_energy_constants.h" #include "service/common/bluetooth/scan_filter.h" #include "service/common/bluetooth/scan_result.h" #include "service/common/bluetooth/scan_settings.h" #include "service/common/bluetooth/uuid.h" #include "service/hal/bluetooth_gatt_interface.h" namespace bluetooth { struct ConnComparator { bool operator()(const bt_bdaddr_t& a, const bt_bdaddr_t& b) const { return memcmp(&a, &b, sizeof(bt_bdaddr_t)) < 0; } }; class Adapter; // A LowEnergyClient represents an application's handle to perform various // Bluetooth Low Energy GAP operations. Instances cannot be created directly and // should be obtained through the factory. class LowEnergyClient : private hal::BluetoothGattInterface::ClientObserver, public BluetoothInstance { public: // The Delegate interface is used to notify asynchronous events related to BLE // GAP operations. class Delegate { public: Delegate() = default; virtual ~Delegate() = default; // Called asynchronously to notify the delegate of nearby BLE advertisers // found during a device scan. virtual void OnScanResult(LowEnergyClient* client, const ScanResult& scan_result) = 0; // Called asynchronously to notify the delegate of connection state change virtual void OnConnectionState(LowEnergyClient* client, int status, const char* address, bool connected) = 0; // Called asynchronously to notify the delegate of mtu change virtual void OnMtuChanged(LowEnergyClient* client, int status, const char* address, int mtu) = 0; private: DISALLOW_COPY_AND_ASSIGN(Delegate); }; // The destructor automatically unregisters this client instance from the // stack. ~LowEnergyClient() override; // Assigns a delegate to this instance. |delegate| must out-live this // LowEnergyClient instance. void SetDelegate(Delegate* delegate); // Callback type used to return the result of asynchronous operations below. using StatusCallback = std::function; // Initiates a BLE connection do device with address |address|. If // |is_direct| is set, use direct connect procedure. Return true on success //, false otherwise. bool Connect(std::string address, bool is_direct); // Disconnect from previously connected BLE device with address |address|. // Return true on success, false otherwise. bool Disconnect(std::string address); // Sends request to set MTU to |mtu| for device with address |address|. // Return true on success, false otherwise. bool SetMtu(std::string address, int mtu); // Initiates a BLE device scan for this client using the given |settings| and // |filters|. See the documentation for ScanSettings and ScanFilter for how // these parameters can be configured. Return true on success, false // otherwise. Please see logs for details in case of error. bool StartScan(const ScanSettings& settings, const std::vector& filters); // Stops an ongoing BLE device scan for this client. bool StopScan(); // Starts advertising based on the given advertising and scan response // data and the provided |settings|. Reports the result of the operation in // |callback|. Return true on success, false otherwise. Please see logs for // details in case of error. bool StartAdvertising(const AdvertiseSettings& settings, const AdvertiseData& advertise_data, const AdvertiseData& scan_response, const StatusCallback& callback); // Stops advertising if it was already started. Reports the result of the // operation in |callback|. bool StopAdvertising(const StatusCallback& callback); // Returns true if advertising has been started. bool IsAdvertisingStarted() const; // Returns the state of pending advertising operations. bool IsStartingAdvertising() const; bool IsStoppingAdvertising() const; // Returns the current advertising settings. const AdvertiseSettings& advertise_settings() const { return advertise_settings_; } // Returns the current scan settings. const ScanSettings& scan_settings() const { return scan_settings_; } // BluetoothClientInstace overrides: const UUID& GetAppIdentifier() const override; int GetInstanceId() const override; private: friend class LowEnergyClientFactory; // Constructor shouldn't be called directly as instances are meant to be // obtained from the factory. LowEnergyClient(Adapter& adapter, const UUID& uuid, int client_id); // BluetoothGattInterface::ClientObserver overrides: void ScanResultCallback( hal::BluetoothGattInterface* gatt_iface, const bt_bdaddr_t& bda, int rssi, uint8_t* adv_data) override; void ConnectCallback( hal::BluetoothGattInterface* gatt_iface, int conn_id, int status, int client_id, const bt_bdaddr_t& bda) override; void DisconnectCallback( hal::BluetoothGattInterface* gatt_iface, int conn_id, int status, int client_id, const bt_bdaddr_t& bda) override; void MtuChangedCallback( hal::BluetoothGattInterface* gatt_iface, int conn_id, int status, int mtu) override; void MultiAdvEnableCallback( hal::BluetoothGattInterface* gatt_iface, int client_id, int status) override; void MultiAdvDataCallback( hal::BluetoothGattInterface* gatt_iface, int client_id, int status) override; void MultiAdvDisableCallback( hal::BluetoothGattInterface* gatt_iface, int client_id, int status) override; // Helper method called from SetAdvertiseData/SetScanResponse. bt_status_t SetAdvertiseData( hal::BluetoothGattInterface* gatt_iface, const AdvertiseData& data, bool set_scan_rsp); // Handles deferred advertise/scan-response data updates. We set the data if // there's data to be set, otherwise we either defer it if advertisements // aren't enabled or do nothing. void HandleDeferredAdvertiseData(hal::BluetoothGattInterface* gatt_iface); // Calls and clears the pending callbacks. void InvokeAndClearStartCallback(BLEStatus status); void InvokeAndClearStopCallback(BLEStatus status); // Raw pointer to the Bluetooth Adapter. Adapter& adapter_; // See getters above for documentation. UUID app_identifier_; int client_id_; // Protects advertising-related members below. std::mutex adv_fields_lock_; // The advertising and scan response data fields that will be sent to the // controller. AdvertiseData adv_data_; AdvertiseData scan_response_; std::atomic_bool adv_data_needs_update_; std::atomic_bool scan_rsp_needs_update_; // Latest advertising settings. AdvertiseSettings advertise_settings_; // Whether or not there is a pending call to update advertising or scan // response data. std::atomic_bool is_setting_adv_data_; std::atomic_bool adv_started_; std::unique_ptr adv_start_callback_; std::unique_ptr adv_stop_callback_; // Protects device scan related members below. std::mutex scan_fields_lock_; // Current scan settings. ScanSettings scan_settings_; // If true, then this client have a BLE device scan in progress. std::atomic_bool scan_started_; // Raw handle to the Delegate, which must outlive this LowEnergyClient // instance. std::mutex delegate_mutex_; Delegate* delegate_; // Protects device connection related members below. std::mutex connection_fields_lock_; // Maps bluetooth address to connection id //TODO(jpawlowski): change type to bimap std::map connection_ids_; DISALLOW_COPY_AND_ASSIGN(LowEnergyClient); }; // LowEnergyClientFactory is used to register and obtain a per-application // LowEnergyClient instance. Users should call RegisterInstance to obtain their // own unique LowEnergyClient instance that has been registered with the // Bluetooth stack. class LowEnergyClientFactory : private hal::BluetoothGattInterface::ClientObserver, public BluetoothInstanceFactory { public: // Don't construct/destruct directly except in tests. Instead, obtain a handle // from an Adapter instance. LowEnergyClientFactory(Adapter& adapter); ~LowEnergyClientFactory() override; // BluetoothInstanceFactory override: bool RegisterInstance(const UUID& uuid, const RegisterCallback& callback) override; private: friend class LowEnergyClient; // BluetoothGattInterface::ClientObserver overrides: void RegisterClientCallback( hal::BluetoothGattInterface* gatt_iface, int status, int client_id, const bt_uuid_t& app_uuid) override; // Map of pending calls to register. std::mutex pending_calls_lock_; std::map pending_calls_; // Raw pointer to the Adapter that owns this factory. Adapter& adapter_; DISALLOW_COPY_AND_ASSIGN(LowEnergyClientFactory); }; } // namespace bluetooth