| // Copyright 2017 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_GAP_ADVERTISING_DATA_H_ |
| #define SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_GAP_ADVERTISING_DATA_H_ |
| |
| #include <fuchsia/bluetooth/le/cpp/fidl.h> |
| |
| #include <cstddef> |
| #include <unordered_map> |
| #include <unordered_set> |
| |
| #include "src/connectivity/bluetooth/core/bt-host/common/byte_buffer.h" |
| #include "src/connectivity/bluetooth/core/bt-host/common/uuid.h" |
| #include "src/connectivity/bluetooth/core/bt-host/gap/gap.h" |
| |
| namespace bt { |
| namespace gap { |
| |
| // A helper to build Adversiting Data, Scan Response Data, or Extended Inquiry |
| // Response Data fields. |
| // TODO(jamuraa): Add functionality for ACAD and OOB |
| // |
| // This can be viewed as a complex container type which has a specified byte |
| // view that is valid for: |
| // - Core Spec v5.0 Vol 3, Part C, Section 11 in the case of Advertising or |
| // Scan Response Data |
| // - Core Spec v5.0 Vol 3, Part C, Section 8 for Extended Inquiry Response data |
| // |
| // See those sections, and the Core Specification Supplement v7 for more |
| // information. |
| class AdvertisingData { |
| public: |
| // Creates an empty advertising data. |
| AdvertisingData() = default; |
| ~AdvertisingData() = default; |
| |
| // Move constructor and assignment operator |
| AdvertisingData(AdvertisingData&& other) = default; |
| AdvertisingData& operator=(AdvertisingData&& other) = default; |
| |
| // Fill the AdvertisingData |out_ad| from the raw Bluetooth field block |
| // |data|. Returns false if |data| is not formatted correctly or on a parsing |
| // error, and true otherwise. |out_ad| is not guaranteed to be in any state |
| // unless we return true. Does not clear |out_ad| so this function can be used |
| // to merge multiple field blocks. |
| static bool FromBytes(const ByteBuffer& data, AdvertisingData* out_ad); |
| |
| // Populate AdvertisingData |out_ad| from the corresponding FIDL object |
| // |fidl_ad|. Overwrites existing contents of |out_ad|. Returns false if |
| // |fidl_ad| contains malformed entries. |
| static bool FromFidl(const fuchsia::bluetooth::le::AdvertisingData& fidl_ad, |
| AdvertisingData* out_ad); |
| |
| // Copies all of the data in this object to |out|, including making a copy of |
| // any data in manufacturing data or service data. |
| // Overwrites any data which is already in |out|. |
| void Copy(AdvertisingData* out) const; |
| |
| // Add a UUID to the set of services advertised. |
| // These service UUIDs will automatically be compressed to be represented in |
| // the smallest space possible. |
| void AddServiceUuid(const UUID& uuid); |
| |
| // Get the service UUIDs represented in this advertisement. |
| const std::unordered_set<UUID>& service_uuids() const; |
| |
| // Set some service data for the service specified by |uuid|. |
| void SetServiceData(const UUID& uuid, const ByteBuffer& data); |
| |
| // Get a set of which UUIDs have service data in this advertisement. |
| const std::unordered_set<UUID> service_data_uuids() const; |
| |
| // View the currently set service data for |uuid|. |
| // This view is not stable; it should be used only ephemerally. |
| // Returns an empty BufferView if no service data is set for |uuid| |
| const BufferView service_data(const UUID& uuid) const; |
| |
| // Set some Manufacturer specific data for the company identified by |
| // |company_id| |
| void SetManufacturerData(const uint16_t company_id, const BufferView& data); |
| |
| // Get a set of which IDs have manufacturer data in this advertisement. |
| const std::unordered_set<uint16_t> manufacturer_data_ids() const; |
| |
| // View the currently set manufacturer data for the company |company_id|. |
| // Returns an empty BufferView if no manufacturer data is set for |
| // |company_id|. |
| // NOTE: it is valid to send a manufacturer data with no data. Check that one |
| // exists using manufacturer_data_ids() first. |
| // This view is not stable; it should be used only ephemerally. |
| const BufferView manufacturer_data(const uint16_t company_id) const; |
| |
| // Sets the local TX Power |
| // TODO(jamuraa): add documentation about where to get this number from |
| void SetTxPower(int8_t dbm); |
| |
| // Gets the TX power |
| std::optional<int8_t> tx_power() const; |
| |
| // Sets the local name |
| void SetLocalName(const std::string& name); |
| |
| // Gets the local name |
| std::optional<std::string> local_name() const; |
| |
| // Adds a URI to the set of URIs advertised. |
| // Does nothing if |uri| is empty. |
| void AddURI(const std::string& uri); |
| |
| // Get the URIs in this advertisement |
| const std::unordered_set<std::string>& uris() const; |
| |
| // Sets the appearance |
| void SetAppearance(uint16_t appearance); |
| |
| // Get the appearance |
| std::optional<uint16_t> appearance() const; |
| |
| // Calculates the size of the current set of fields if they were to be written |
| // to a buffer using WriteBlock() |
| size_t CalculateBlockSize() const; |
| |
| // Writes the byte representation of this to |buffer|. |
| // Returns false without modifying |buffer| if there is not enough space |
| // (if the buffer size is less than block_size()) |
| bool WriteBlock(MutableByteBuffer* buffer) const; |
| |
| // Makes a FIDL object that holds the same data |
| fuchsia::bluetooth::le::AdvertisingDataPtr AsLEAdvertisingData() const; |
| |
| // Relation operators |
| bool operator==(const AdvertisingData& other) const; |
| bool operator!=(const AdvertisingData& other) const; |
| |
| private: |
| // TODO(armansito): Consider storing the payload in its serialized form and |
| // have these point into the structure (see NET-209). |
| std::optional<std::string> local_name_; |
| std::optional<int8_t> tx_power_; |
| std::optional<uint16_t> appearance_; |
| std::unordered_set<UUID> service_uuids_; |
| std::unordered_map<uint16_t, DynamicByteBuffer> manufacturer_data_; |
| std::unordered_map<UUID, DynamicByteBuffer> service_data_; |
| |
| std::unordered_set<std::string> uris_; |
| |
| DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(AdvertisingData); |
| }; |
| |
| // Convenience classes for reading and writing the contents |
| // of Advertising Data, Scan Response Data, or Extended Inquiry Response Data |
| // payloads. The format in which data is stored looks like the following: |
| // |
| // [1-octet LENGTH][1-octet TYPE][LENGTH-1 octets DATA] |
| // |
| // Used for parsing data in TLV-format as described at the beginning of the file |
| // above. |
| class AdvertisingDataReader { |
| public: |
| // |data| must point to a valid piece of memory for the duration in which this |
| // object is to remain alive. |
| explicit AdvertisingDataReader(const ByteBuffer& data); |
| |
| // Returns false if the fields of |data| have been formatted incorrectly. For |
| // example, this could happen if the length of an advertising data structure |
| // would exceed the bounds of the buffer. |
| inline bool is_valid() const { return is_valid_; } |
| |
| // Returns the data and type fields of the next advertising data structure in |
| // |out_data| and |out_type|. Returns false if there is no more data to read |
| // or if the data is formatted incorrectly. |
| bool GetNextField(DataType* out_type, BufferView* out_data); |
| |
| // Returns true if there is more data to read. Returns false if the end of |
| // data has been reached or if the current segment is malformed in a way that |
| // would exceed the bounds of the data this reader was initialized with. |
| bool HasMoreData() const; |
| |
| private: |
| bool is_valid_; |
| BufferView remaining_; |
| }; |
| |
| // Used for writing data in TLV-format as described at the beginning of the file |
| // above. |
| class AdvertisingDataWriter { |
| public: |
| // |buffer| is the piece of memory on which this AdvertisingDataWriter should |
| // operate. The buffer must out-live this instance and must point to a valid |
| // piece of memory. |
| explicit AdvertisingDataWriter(MutableByteBuffer* buffer); |
| |
| // Writes the given piece of type/tag and data into the next available segment |
| // in the underlying buffer. Returns false if there isn't enough space left in |
| // the buffer for writing. Returns true on success. |
| bool WriteField(DataType type, const ByteBuffer& data); |
| |
| // The total number of bytes that have been written into the buffer. |
| size_t bytes_written() const { return bytes_written_; } |
| |
| private: |
| MutableByteBuffer* buffer_; |
| size_t bytes_written_; |
| }; |
| |
| } // namespace gap |
| } // namespace bt |
| |
| #endif // SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_GAP_ADVERTISING_DATA_H_ |