blob: 8630150949cf662927204eb7a2efd3250d38f6cb [file] [log] [blame]
// 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_HCI_LEGACY_LOW_ENERGY_SCANNER_H_
#define SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_HCI_LEGACY_LOW_ENERGY_SCANNER_H_
#include <lib/async/cpp/task.h>
#include <lib/async/dispatcher.h>
#include <lib/fit/thread_checker.h>
#include <memory>
#include <unordered_map>
#include "src/connectivity/bluetooth/core/bt-host/common/byte_buffer.h"
#include "src/connectivity/bluetooth/core/bt-host/hci-spec/protocol.h"
#include "src/connectivity/bluetooth/core/bt-host/hci/command_channel.h"
#include "src/connectivity/bluetooth/core/bt-host/hci/low_energy_scanner.h"
#include "src/lib/fxl/memory/ref_counted.h"
namespace bt::hci {
class LocalAddressDelegate;
// LegacyLowEnergyScanner implements the LowEnergyScanner interface for
// controllers that do not support the 5.0 Extended Advertising feature. This
// uses the legacy HCI LE scan commands and events:
// - HCI_LE_Set_Scan_Parameters
// - HCI_LE_Set_Scan_Enable
// - HCI_LE_Advertising_Report event
class LegacyLowEnergyScanner : public LowEnergyScanner {
public:
LegacyLowEnergyScanner(LocalAddressDelegate* local_addr_delegate, fxl::WeakPtr<Transport> hci,
async_dispatcher_t* dispatcher);
~LegacyLowEnergyScanner() override;
// LowEnergyScanner overrides:
bool StartScan(const ScanOptions& options, ScanStatusCallback callback) override;
bool StopScan() override;
private:
// This represents the data obtained for a scannable advertisement for which a scan response has
// not yet been received. Clients are notified for scannable advertisement either when the
// corresponding scan response is received or, otherwise, a timeout expires.
class PendingScanResult {
public:
// |adv|: Initial advertising data payload.
PendingScanResult(LowEnergyScanResult result, const ByteBuffer& adv, zx::duration timeout,
fit::closure timeout_handler);
// Return the contents of the data.
BufferView data() const { return buffer_.view(0, data_size_); }
const LowEnergyScanResult& result() const { return result_; }
void set_rssi(int8_t rssi) { result_.rssi = rssi; }
void set_resolved(bool resolved) { result_.resolved = resolved; }
// Appends |data| to the end of the current contents.
void Append(const ByteBuffer& data);
private:
LowEnergyScanResult result_;
// The size of the data so far accumulated in |buffer_|.
size_t data_size_ = 0u;
// Buffer large enough to store both advertising and scan response payloads.
StaticByteBuffer<kMaxLEAdvertisingDataLength * 2> buffer_;
// Since not all scannable advertisements are always followed by a scan response, we report a
// pending result if a scan response is not received within a timeout.
async::TaskClosure timeout_task_;
};
// Called by StartScan() after the local peer address has been obtained.
void StartScanInternal(const DeviceAddress& local_address, const ScanOptions& options,
ScanStatusCallback callback);
// Called by StopScan() and by the scan timeout handler set up by StartScan().
void StopScanInternal(bool stopped);
// Event handler for HCI LE Advertising Report event.
CommandChannel::EventCallbackResult OnAdvertisingReportEvent(const EventPacket& event);
// Called when a Scan Response is received during an active scan.
void HandleScanResponse(const LEAdvertisingReportData& report, int8_t rssi);
// Notifies observers of a peer that was found.
void NotifyPeerFound(const LowEnergyScanResult& result, const ByteBuffer& data);
// Called when the scan timeout task executes.
void OnScanPeriodComplete();
// Called when the scan response timeout expires for the given device address.
void OnScanResponseTimeout(const DeviceAddress& address);
// Used to obtain the local peer address type to use during scanning.
LocalAddressDelegate* local_addr_delegate_; // weak
// Callback passed in to the most recently accepted call to StartScan();
ScanStatusCallback scan_cb_;
// The scan period timeout handler for the currently active scan session.
async::TaskClosure scan_timeout_task_;
// Maximum time duration for which a scannable advertisement will be stored and not reported to
// clients until a corresponding scan response is received.
zx::duration scan_response_timeout_;
// Our event handler ID for the LE Advertising Report event.
CommandChannel::EventHandlerId event_handler_id_;
// Scannable advertising events for which a Scan Response PDU has not been
// received. This is accumulated during a discovery procedure and always
// cleared at the end of the scan period.
std::unordered_map<DeviceAddress, std::unique_ptr<PendingScanResult>> pending_results_;
fit::thread_checker thread_checker_;
DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(LegacyLowEnergyScanner);
};
} // namespace bt::hci
#endif // SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_HCI_LEGACY_LOW_ENERGY_SCANNER_H_