// Copyright 2020 Google LLC // // 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 // // https://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. #ifndef PLATFORM_API_BLE_V2_H_ #define PLATFORM_API_BLE_V2_H_ #include #include #include #include #include #include #include "absl/strings/string_view.h" #include "absl/types/optional.h" #include "platform/base/byte_array.h" #include "platform/base/exception.h" namespace location { namespace nearby { namespace api { namespace ble_v2 { // https://developer.android.com/reference/android/bluetooth/le/AdvertiseData // // Bundle of data found in a BLE advertisement. // // All service UUIDs will conform to the 16-bit Bluetooth base UUID, // 0000xxxx-0000-1000-8000-00805F9B34FB. This makes it possible to store two // byte service UUIDs in the advertisement. struct BleAdvertisementData { using TxPowerLevel = int8_t; static const TxPowerLevel kUnspecifiedTxPowerLevel = std::numeric_limits::min(); bool is_connectable; // When set to kUnspecifiedTxPowerLevel, TX power should not be included in // the advertisement data. TxPowerLevel tx_power_level; // When set to an empty string, local name should not be included in the // advertisement data. std::string local_name; // When set to an empty vector, the set of 16-bit service class UUIDs should // not be included in the advertisement data. std::set service_uuids; // Maps service UUIDs to their service data. std::map service_data; }; // Opaque wrapper over a BLE peripheral. Must be able to uniquely identify a // peripheral so that we can connect to its GATT server. class BlePeripheral { public: virtual ~BlePeripheral() {} // https://developer.android.com/reference/android/bluetooth/BluetoothDevice#getAddress() // // This should be the MAC address when possible. If the implementation is // unable to retrieve that, any unique identifier should suffice. virtual std::string GetId() const = 0; }; // https://developer.android.com/reference/android/bluetooth/BluetoothGattCharacteristic // // Representation of a GATT characteristic. class GattCharacteristic { public: virtual ~GattCharacteristic() {} // Possible permissions of a GATT characteristic. enum class Permission { kUnknown = 0, kRead = 1, kWrite = 2, kLast, }; // Possible properties of a GATT characteristic. enum class Property { kUnknown = 0, kRead = 1, kWrite = 2, kIndicate = 3, kLast, }; // Returns the UUID of this characteristic. virtual std::string GetUuid() = 0; // Returns the UUID of the containing GATT service. virtual std::string GetServiceUuid() = 0; }; // https://developer.android.com/reference/android/bluetooth/BluetoothGatt // // Representation of a client GATT connection to a remote GATT server. class ClientGattConnection { public: virtual ~ClientGattConnection() {} // https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#getDevice() // // Retrieves the BLE peripheral that this connection is tied to. virtual BlePeripheral& GetPeripheral() = 0; // https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#discoverServices() // // Discovers all available services and characteristics on this connection. // Returns whether or not discovery finished successfully. // // This function should block until discovery has finished. virtual bool DiscoverServices() = 0; // https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#getService(java.util.UUID) // https://developer.android.com/reference/android/bluetooth/BluetoothGattService.html#getCharacteristic(java.util.UUID) // // Retrieves a GATT characteristic. On error, does not return a value. // // DiscoverServices() should be called before this method to fetch all // available services and characteristics first. // // It is okay for duplicate services to exist, as long as the specified // characteristic UUID is unique among all services of the same UUID. virtual absl::optional GetCharacteristic( absl::string_view service_uuid, absl::string_view characteristic_uuid) = 0; // https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#readCharacteristic(android.bluetooth.BluetoothGattCharacteristic) // https://developer.android.com/reference/android/bluetooth/BluetoothGattCharacteristic.html#getValue() // // Reads a GATT characteristic. No value is returned upon error. virtual absl::optional ReadCharacteristic( const GattCharacteristic& characteristic) = 0; // https://developer.android.com/reference/android/bluetooth/BluetoothGattCharacteristic.html#setValue(byte[]) // https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#writeCharacteristic(android.bluetooth.BluetoothGattCharacteristic) // // Sends a remote characteristic write request to the server and returns // whether or not it was successful. virtual bool WriteCharacteristic(const GattCharacteristic& characteristic, const ByteArray& value) = 0; // https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#disconnect() // // Disconnects a GATT connection. virtual void Disconnect() = 0; }; // https://developer.android.com/reference/android/bluetooth/BluetoothGattServer // // Representation of a server GATT connection to a remote GATT client. class ServerGattConnection { public: virtual ~ServerGattConnection() {} // https://developer.android.com/reference/android/bluetooth/BluetoothGattCharacteristic.html#setValue(byte[]) // https://developer.android.com/reference/android/bluetooth/BluetoothGattServer.html#notifyCharacteristicChanged(android.bluetooth.BluetoothDevice,%20android.bluetooth.BluetoothGattCharacteristic,%20boolean) // // Sends a notification (via indication) to the client that a characteristic // has changed with the given value. Returns whether or not it was successful. // // The value sent does not have to reflect the locally stored characteristic // value. To update the local value, call GattServer::UpdateCharacteristic. virtual bool SendCharacteristic(const GattCharacteristic& characteristic, const ByteArray& value) = 0; }; // Callback for asynchronous events on the client side of a GATT connection. class ClientGattConnectionLifeCycleCallback { public: virtual ~ClientGattConnectionLifeCycleCallback() {} // Called when the client is disconnected from the GATT server. virtual void OnDisconnected(ClientGattConnection* connection) = 0; }; // Callback for asynchronous events on the server side of a GATT connection. class ServerGattConnectionLifeCycleCallback { public: virtual ~ServerGattConnectionLifeCycleCallback() {} // Called when a remote peripheral connected to us and subscribed to one of // our characteristics. virtual void OnCharacteristicSubscription( ServerGattConnection* connection, const GattCharacteristic& characteristic) = 0; // Called when a remote peripheral unsubscribed from one of our // characteristics. virtual void OnCharacteristicUnsubscription( ServerGattConnection* connection, const GattCharacteristic& characteristic) = 0; }; // https://developer.android.com/reference/android/bluetooth/BluetoothGattServer // // Representation of a BLE GATT server. class GattServer { public: virtual ~GattServer() {} // Creates a characteristic and adds it to the GATT server under the given // characteristic and service UUIDs. Returns no value upon error. // // Characteristics of the same service UUID should be put under one // service rather than many services with the same UUID. // // If the INDICATE property is included, the characteristic should include the // official Bluetooth Client Characteristic Configuration descriptor with UUID // 0x2902 and a WRITE permission. This allows remote clients to write to this // descriptor and subscribe for characteristic changes. For more information // about this descriptor, please go to: // https://www.bluetooth.com/specifications/Gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.Gatt.client_characteristic_configuration.xml virtual absl::optional CreateCharacteristic( absl::string_view service_uuid, absl::string_view characteristic_uuid, const std::set& permissions, const std::set& properties) = 0; // https://developer.android.com/reference/android/bluetooth/BluetoothGattCharacteristic.html#setValue(byte[]) // // Locally updates the value of a characteristic and returns whether or not it // was successful. // Takes ownership of (and is responsible for destroying) the passed-in // 'value'. virtual bool UpdateCharacteristic(const GattCharacteristic& characteristic, const ByteArray& value) = 0; // Stops a GATT server. virtual void Stop() = 0; }; // A BLE socket representation. class BleSocket { public: virtual ~BleSocket() {} // Returns the remote BLE peripheral tied to this socket. virtual BlePeripheral& GetRemotePeripheral() = 0; // Writes a message on the socket and blocks until finished. Returns // Exception::kIo upon error, and Exception::kSuccess otherwise. virtual Exception Write(const ByteArray& message) = 0; // Closes the socket and blocks until finished. Returns Exception::kIo upon // error, and Exception::kSuccess otherwise. virtual Exception Close() = 0; }; // Callback for asynchronous events on a BleSocket object. class BleSocketLifeCycleCallback { public: virtual ~BleSocketLifeCycleCallback() {} // Called when a message arrives on a socket. virtual void OnMessageReceived(BleSocket* socket, const ByteArray& message) = 0; // Called when a socket gets disconnected. virtual void OnDisconnected(BleSocket* socket) = 0; }; // Callback for asynchronous events on the server side of a BleSocket object. class ServerBleSocketLifeCycleCallback : public BleSocketLifeCycleCallback { public: ~ServerBleSocketLifeCycleCallback() override {} // Called when a new incoming socket has been established. virtual void OnSocketEstablished(BleSocket* socket) = 0; }; // The main BLE medium used inside of Nearby. This serves as the entry point for // all BLE and GATT related operations. class BleMedium { public: using Mtu = uint32_t; virtual ~BleMedium() {} // Coarse representation of power settings throughout all BLE operations. enum class PowerMode { kUnknown = 0, kLow = 1, kHigh = 2, kLast, }; // https://developer.android.com/reference/android/bluetooth/le/BluetoothLeAdvertiser.html#startAdvertising(android.bluetooth.le.AdvertiseSettings,%20android.bluetooth.le.AdvertiseData,%20android.bluetooth.le.AdvertiseData,%20android.bluetooth.le.AdvertiseCallback) // // Starts BLE advertising and returns whether or not it was successful. // // Power mode should be interpreted in the following way: // LOW: // - Advertising interval = ~1000ms // - TX power = low // HIGH: // - Advertising interval = ~100ms // - TX power = high virtual bool StartAdvertising(const BleAdvertisementData& advertisement_data, const BleAdvertisementData& scan_response, PowerMode power_mode) = 0; // https://developer.android.com/reference/android/bluetooth/le/BluetoothLeAdvertiser.html#stopAdvertising(android.bluetooth.le.AdvertiseCallback) // // Stops advertising. virtual void StopAdvertising() = 0; // https://developer.android.com/reference/android/bluetooth/le/ScanCallback // // Callback for BLE scan results. class ScanCallback { public: virtual ~ScanCallback() {} // https://developer.android.com/reference/android/bluetooth/le/ScanCallback.html#onScanResult(int,%20android.bluetooth.le.ScanResult) // // Called when a BLE advertisement is discovered. // // The passed in advertisement_data is the merged combination of both // advertisement data and scan response. // // Every discovery of an advertisement should be reported, even if the // advertisement was discovered before. // // Ownership of the BleAdvertisementData transfers to the caller at this // point. virtual void OnAdvertisementFound( BlePeripheral* peripheral, const BleAdvertisementData& advertisement_data) = 0; }; // https://developer.android.com/reference/android/bluetooth/le/BluetoothLeScanner.html#startScan(java.util.List%3Candroid.bluetooth.le.ScanFilter%3E,%20android.bluetooth.le.ScanSettings,%20android.bluetooth.le.ScanCallback) // // Starts scanning and returns whether or not it was successful. // // Power mode should be interpreted in the following way: // LOW: // - Scan window = ~512ms // - Scan interval = ~5120ms // HIGH: // - Scan window = ~4096ms // - Scan interval = ~4096ms virtual bool StartScanning(const std::set& service_uuids, PowerMode power_mode, const ScanCallback& scan_callback) = 0; // https://developer.android.com/reference/android/bluetooth/le/BluetoothLeScanner.html#stopScan(android.bluetooth.le.ScanCallback) // // Stops scanning. virtual void StopScanning() = 0; // https://developer.android.com/reference/android/bluetooth/BluetoothManager#openGattServer(android.content.Context,%20android.bluetooth.BluetoothGattServerCallback) // // Starts a GATT server. Returns a nullptr upon error. virtual std::unique_ptr StartGattServer( const ServerGattConnectionLifeCycleCallback& callback) = 0; // Starts listening for incoming BLE sockets and returns false upon error. virtual bool StartListeningForIncomingBleSockets( const ServerBleSocketLifeCycleCallback& callback) = 0; // Stops listening for incoming BLE sockets. virtual void StopListeningForIncomingBleSockets() = 0; // https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#connectGatt(android.content.Context,%20boolean,%20android.bluetooth.BluetoothGattCallback) // https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#requestConnectionPriority(int) // https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#requestMtu(int) // // Connects to a GATT server and negotiates the specified connection // parameters. Returns nullptr upon error. // // Both connection interval and MTU can be negotiated on a best-effort basis. // // Power mode should be interpreted in the following way: // LOW: // - Connection interval = ~11.25ms - 15ms // HIGH: // - Connection interval = ~100ms - 125ms virtual std::unique_ptr ConnectToGattServer( BlePeripheral* peripheral, Mtu mtu, PowerMode power_mode, const ClientGattConnectionLifeCycleCallback& callback) = 0; // Establishes a BLE socket to the specified remote peripheral. Returns // nullptr on error. virtual std::unique_ptr EstablishBleSocket( BlePeripheral* peripheral, const BleSocketLifeCycleCallback& callback) = 0; }; } // namespace ble_v2 } // namespace api } // namespace nearby } // namespace location #endif // PLATFORM_API_BLE_V2_H_