RootCanal: Refactor implementation of Inquiry and InquiryCancel
Test: atest rootcanal_ll_test
Bug: 286588829
Flag: EXEMPT, tool change
Change-Id: I546b90e15be1547044d62ceaf5f5991be912a47f
diff --git a/tools/rootcanal/model/controller/dual_mode_controller.cc b/tools/rootcanal/model/controller/dual_mode_controller.cc
index 20d8ccf..b5913d7 100644
--- a/tools/rootcanal/model/controller/dual_mode_controller.cc
+++ b/tools/rootcanal/model/controller/dual_mode_controller.cc
@@ -1717,24 +1717,19 @@
void DualModeController::Inquiry(CommandView command) {
auto command_view = bluetooth::hci::InquiryView::Create(command);
ASSERT(command_view.IsValid());
- auto max_responses = command_view.GetNumResponses();
- auto length = command_view.GetInquiryLength();
+ auto lap = command_view.GetLap().lap_;
+ auto inquiry_length = command_view.GetInquiryLength();
+ auto num_responses = command_view.GetNumResponses();
DEBUG(id_, "<< Inquiry");
- DEBUG(id_, " num_responses={}", max_responses);
- DEBUG(id_, " inquiry_length={}", length);
+ DEBUG(id_, " lap={}", lap);
+ DEBUG(id_, " inquiry_length={}", inquiry_length);
+ DEBUG(id_, " num_responses={}", num_responses);
- if (max_responses > 0xff || length < 1 || length > 0x30) {
- send_event_(bluetooth::hci::InquiryStatusBuilder::Create(
- ErrorCode::INVALID_HCI_COMMAND_PARAMETERS, kNumCommandPackets));
- return;
- }
- link_layer_controller_.SetInquiryLAP(command_view.GetLap().lap_);
- link_layer_controller_.SetInquiryMaxResponses(max_responses);
- link_layer_controller_.StartInquiry(std::chrono::milliseconds(length * 1280));
-
- send_event_(bluetooth::hci::InquiryStatusBuilder::Create(ErrorCode::SUCCESS,
- kNumCommandPackets));
+ auto status =
+ link_layer_controller_.Inquiry(lap, inquiry_length, num_responses);
+ send_event_(
+ bluetooth::hci::InquiryStatusBuilder::Create(status, kNumCommandPackets));
}
void DualModeController::InquiryCancel(CommandView command) {
@@ -1743,9 +1738,9 @@
DEBUG(id_, "<< Inquiry Cancel");
- link_layer_controller_.InquiryCancel();
+ auto status = link_layer_controller_.InquiryCancel();
send_event_(bluetooth::hci::InquiryCancelCompleteBuilder::Create(
- kNumCommandPackets, ErrorCode::SUCCESS));
+ kNumCommandPackets, status));
}
void DualModeController::AcceptConnectionRequest(CommandView command) {
diff --git a/tools/rootcanal/model/controller/link_layer_controller.cc b/tools/rootcanal/model/controller/link_layer_controller.cc
index 845f108..15feb1a 100644
--- a/tools/rootcanal/model/controller/link_layer_controller.cc
+++ b/tools/rootcanal/model/controller/link_layer_controller.cc
@@ -60,6 +60,7 @@
constexpr milliseconds kNoDelayMs(0);
constexpr milliseconds kPageInterval(1000);
+constexpr milliseconds kInquiryInterval(500);
const Address& LinkLayerController::GetAddress() const { return address_; }
@@ -267,6 +268,43 @@
// BR/EDR Commands
// =============================================================================
+// HCI Inquiry command (Vol 4, Part E § 7.1.1).
+ErrorCode LinkLayerController::Inquiry(uint8_t lap, uint8_t inquiry_length,
+ uint8_t num_responses) {
+ if (inquiry_.has_value()) {
+ INFO(id_, "inquiry is already started");
+ return ErrorCode::COMMAND_DISALLOWED;
+ }
+
+ if (inquiry_length < 0x1 || inquiry_length > 0x30) {
+ INFO(id_, "invalid inquiry length ({})", inquiry_length);
+ return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS;
+ }
+
+ // The Inquiry_Length parameter, added to Extended_Inquiry_Length
+ // (see Section 6.42), specifies the total duration of the Inquiry Mode and,
+ // when this time expires, Inquiry will be halted.
+ std::chrono::microseconds inquiry_timeout =
+ 1280ms * inquiry_length +
+ std::chrono::duration_cast<milliseconds>(extended_inquiry_length_);
+
+ auto now = std::chrono::steady_clock::now();
+ inquiry_ = InquiryState{
+ .lap = lap,
+ .num_responses = num_responses,
+ .next_inquiry_event = now + kInquiryInterval,
+ .inquiry_timeout = now + inquiry_timeout,
+ };
+
+ return ErrorCode::SUCCESS;
+}
+
+// HCI Inquiry Cancel command (Vol 4, Part E § 7.1.2).
+ErrorCode LinkLayerController::InquiryCancel() {
+ inquiry_ = {};
+ return ErrorCode::SUCCESS;
+}
+
// HCI Read Rssi command (Vol 4, Part E § 7.5.4).
ErrorCode LinkLayerController::ReadRssi(uint16_t connection_handle,
int8_t* rssi) {
@@ -5155,10 +5193,7 @@
void LinkLayerController::Tick() {
RunPendingTasks();
Paging();
-
- if (inquiry_timer_task_id_ != kInvalidTaskId) {
- Inquiry();
- }
+ Inquiring();
LeAdvertising();
LeScanning();
link_manager_tick(lm_.get());
@@ -5386,7 +5421,7 @@
}
auto now = std::chrono::steady_clock::now();
- page_ = Page{
+ page_ = PageState{
.bd_addr = bd_addr,
.allow_role_switch = allow_role_switch,
.next_page_event = now + kPageInterval,
@@ -6043,10 +6078,7 @@
initiator_ = Initiator{};
synchronizing_ = {};
synchronized_ = {};
- last_inquiry_ = steady_clock::now();
inquiry_mode_ = InquiryType::STANDARD;
- inquiry_lap_ = 0;
- inquiry_max_responses_ = 0;
default_tx_phys_ = properties_.LeSupportedPhys();
default_rx_phys_ = properties_.LeSupportedPhys();
@@ -6056,11 +6088,7 @@
current_iac_lap_list_.emplace_back(general_iac);
page_ = {};
-
- if (inquiry_timer_task_id_ != kInvalidTaskId) {
- CancelScheduledTask(inquiry_timer_task_id_);
- inquiry_timer_task_id_ = kInvalidTaskId;
- }
+ inquiry_ = {};
lm_.reset(link_manager_create(controller_ops_));
ll_.reset(link_layer_create(controller_ops_));
@@ -6071,7 +6099,7 @@
auto now = std::chrono::steady_clock::now();
if (page_.has_value() && now >= page_->page_timeout) {
- INFO("page timeout triggered for connection with {}",
+ INFO(id_, "page timeout triggered for connection with {}",
page_->bd_addr.ToString());
send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create(
@@ -6094,25 +6122,25 @@
}
}
-void LinkLayerController::StartInquiry(milliseconds timeout) {
- inquiry_timer_task_id_ = ScheduleTask(milliseconds(timeout), [this]() {
- LinkLayerController::InquiryTimeout();
- });
-}
+/// Drive the logic for the Inquiry controller substate.
+void LinkLayerController::Inquiring() {
+ auto now = std::chrono::steady_clock::now();
-void LinkLayerController::InquiryCancel() {
- ASSERT(inquiry_timer_task_id_ != kInvalidTaskId);
- CancelScheduledTask(inquiry_timer_task_id_);
- inquiry_timer_task_id_ = kInvalidTaskId;
-}
+ if (inquiry_.has_value() && now >= inquiry_->inquiry_timeout) {
+ INFO(id_, "inquiry timeout triggered");
-void LinkLayerController::InquiryTimeout() {
- if (inquiry_timer_task_id_ != kInvalidTaskId) {
- inquiry_timer_task_id_ = kInvalidTaskId;
- if (IsEventUnmasked(EventCode::INQUIRY_COMPLETE)) {
- send_event_(
- bluetooth::hci::InquiryCompleteBuilder::Create(ErrorCode::SUCCESS));
- }
+ send_event_(
+ bluetooth::hci::InquiryCompleteBuilder::Create(ErrorCode::SUCCESS));
+
+ inquiry_ = {};
+ return;
+ }
+
+ // Send a Inquiry packet when the inquiry interval has passed.
+ if (inquiry_.has_value() && now >= inquiry_->next_inquiry_event) {
+ SendLinkLayerPacket(model::packets::InquiryBuilder::Create(
+ GetAddress(), Address::kEmpty, inquiry_mode_, inquiry_->lap));
+ inquiry_->next_inquiry_event = now + kInquiryInterval;
}
}
@@ -6120,23 +6148,6 @@
inquiry_mode_ = static_cast<model::packets::InquiryType>(mode);
}
-void LinkLayerController::SetInquiryLAP(uint64_t lap) { inquiry_lap_ = lap; }
-
-void LinkLayerController::SetInquiryMaxResponses(uint8_t max) {
- inquiry_max_responses_ = max;
-}
-
-void LinkLayerController::Inquiry() {
- steady_clock::time_point now = steady_clock::now();
- if (duration_cast<milliseconds>(now - last_inquiry_) < milliseconds(2000)) {
- return;
- }
-
- SendLinkLayerPacket(model::packets::InquiryBuilder::Create(
- GetAddress(), Address::kEmpty, inquiry_mode_, inquiry_lap_));
- last_inquiry_ = now;
-}
-
void LinkLayerController::SetInquiryScanEnable(bool enable) {
inquiry_scan_enable_ = enable;
}
diff --git a/tools/rootcanal/model/controller/link_layer_controller.h b/tools/rootcanal/model/controller/link_layer_controller.h
index ce50d91..35a72ef 100644
--- a/tools/rootcanal/model/controller/link_layer_controller.h
+++ b/tools/rootcanal/model/controller/link_layer_controller.h
@@ -185,6 +185,7 @@
void Reset();
void Paging();
+ void Inquiring();
void LeAdvertising();
void LeScanning();
void LeSynchronization();
@@ -267,13 +268,7 @@
uint8_t LeReadNumberOfSupportedAdvertisingSets();
// Classic
- void StartInquiry(std::chrono::milliseconds timeout);
- void InquiryCancel();
- void InquiryTimeout();
void SetInquiryMode(uint8_t mode);
- void SetInquiryLAP(uint64_t lap);
- void SetInquiryMaxResponses(uint8_t max);
- void Inquiry();
bool GetInquiryScanEnable() const { return inquiry_scan_enable_; }
void SetInquiryScanEnable(bool enable);
@@ -334,6 +329,12 @@
// BR/EDR Commands
+ // HCI Inquiry command (Vol 4, Part E § 7.1.1).
+ ErrorCode Inquiry(uint8_t lap, uint8_t inquiry_length, uint8_t num_responses);
+
+ // HCI Inquiry Cancel command (Vol 4, Part E § 7.1.2).
+ ErrorCode InquiryCancel();
+
// HCI Read Rssi command (Vol 4, Part E § 7.5.4).
ErrorCode ReadRssi(uint16_t connection_handle, int8_t* rssi);
@@ -939,6 +940,9 @@
// Class of Device (Vol 4, Part E § 6.26).
uint32_t class_of_device_{0};
+ // Extended Inquiry Length (Vol 4, Part E § 6.42).
+ slots extended_inquiry_length_{0};
+
// Other configuration parameters.
// Current IAC LAP (Vol 4, Part E § 7.3.44).
@@ -1161,23 +1165,27 @@
struct ControllerOps controller_ops_;
// Classic state.
- struct Page {
+ struct PageState {
Address bd_addr;
uint8_t allow_role_switch;
std::chrono::steady_clock::time_point next_page_event{};
std::chrono::steady_clock::time_point page_timeout{};
};
- // Page substate.
- // RootCanal will allow only one page request running at the same time.
- std::optional<Page> page_;
+ struct InquiryState {
+ uint64_t lap;
+ uint8_t num_responses;
+ std::chrono::steady_clock::time_point next_inquiry_event{};
+ std::chrono::steady_clock::time_point inquiry_timeout{};
+ };
- std::chrono::steady_clock::time_point last_inquiry_;
+ // Page and inquiry substates.
+ // RootCanal will allow only one page request running at the same time.
+ std::optional<PageState> page_;
+ std::optional<InquiryState> inquiry_;
+
model::packets::InquiryType inquiry_mode_{
model::packets::InquiryType::STANDARD};
- TaskId inquiry_timer_task_id_ = kInvalidTaskId;
- uint64_t inquiry_lap_{};
- uint8_t inquiry_max_responses_{};
public:
// Type of scheduled tasks.