Loading tools/rootcanal/model/controller/dual_mode_controller.cc +12 −17 Original line number Diff line number Diff line Loading @@ -1717,24 +1717,19 @@ void DualModeController::SetEventFilter(CommandView command) { 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) { Loading @@ -1743,9 +1738,9 @@ void DualModeController::InquiryCancel(CommandView command) { 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) { Loading tools/rootcanal/model/controller/link_layer_controller.cc +59 −48 Original line number Diff line number Diff line Loading @@ -60,6 +60,7 @@ namespace rootcanal { constexpr milliseconds kNoDelayMs(0); constexpr milliseconds kPageInterval(1000); constexpr milliseconds kInquiryInterval(500); const Address& LinkLayerController::GetAddress() const { return address_; } Loading Loading @@ -267,6 +268,43 @@ LinkLayerController::GenerateResolvablePrivateAddress(AddressWithType address, // 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) { Loading Loading @@ -5155,10 +5193,7 @@ void LinkLayerController::IncomingPageResponsePacket( void LinkLayerController::Tick() { RunPendingTasks(); Paging(); if (inquiry_timer_task_id_ != kInvalidTaskId) { Inquiry(); } Inquiring(); LeAdvertising(); LeScanning(); link_manager_tick(lm_.get()); Loading Loading @@ -5386,7 +5421,7 @@ ErrorCode LinkLayerController::CreateConnection(const Address& bd_addr, } 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, Loading Loading @@ -6043,10 +6078,7 @@ void LinkLayerController::Reset() { 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(); Loading @@ -6056,11 +6088,7 @@ void LinkLayerController::Reset() { 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_)); Loading @@ -6071,7 +6099,7 @@ void LinkLayerController::Paging() { 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( Loading @@ -6094,47 +6122,30 @@ void LinkLayerController::Paging() { } } 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)); } } } void LinkLayerController::SetInquiryMode(uint8_t mode) { inquiry_mode_ = static_cast<model::packets::InquiryType>(mode); inquiry_ = {}; return; } void LinkLayerController::SetInquiryLAP(uint64_t lap) { inquiry_lap_ = lap; } void LinkLayerController::SetInquiryMaxResponses(uint8_t max) { inquiry_max_responses_ = max; // 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; } 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::SetInquiryMode(uint8_t mode) { inquiry_mode_ = static_cast<model::packets::InquiryType>(mode); } void LinkLayerController::SetInquiryScanEnable(bool enable) { Loading tools/rootcanal/model/controller/link_layer_controller.h +21 −13 Original line number Diff line number Diff line Loading @@ -185,6 +185,7 @@ class LinkLayerController { void Reset(); void Paging(); void Inquiring(); void LeAdvertising(); void LeScanning(); void LeSynchronization(); Loading Loading @@ -267,13 +268,7 @@ class LinkLayerController { 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); Loading Loading @@ -334,6 +329,12 @@ class LinkLayerController { // 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); Loading Loading @@ -939,6 +940,9 @@ class LinkLayerController { // 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). Loading Loading @@ -1161,23 +1165,27 @@ class LinkLayerController { 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. 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{}; }; // Page and inquiry substates. // RootCanal will allow only one page request running at the same time. std::optional<Page> page_; std::optional<PageState> page_; std::optional<InquiryState> inquiry_; std::chrono::steady_clock::time_point last_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. Loading Loading
tools/rootcanal/model/controller/dual_mode_controller.cc +12 −17 Original line number Diff line number Diff line Loading @@ -1717,24 +1717,19 @@ void DualModeController::SetEventFilter(CommandView command) { 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) { Loading @@ -1743,9 +1738,9 @@ void DualModeController::InquiryCancel(CommandView command) { 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) { Loading
tools/rootcanal/model/controller/link_layer_controller.cc +59 −48 Original line number Diff line number Diff line Loading @@ -60,6 +60,7 @@ namespace rootcanal { constexpr milliseconds kNoDelayMs(0); constexpr milliseconds kPageInterval(1000); constexpr milliseconds kInquiryInterval(500); const Address& LinkLayerController::GetAddress() const { return address_; } Loading Loading @@ -267,6 +268,43 @@ LinkLayerController::GenerateResolvablePrivateAddress(AddressWithType address, // 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) { Loading Loading @@ -5155,10 +5193,7 @@ void LinkLayerController::IncomingPageResponsePacket( void LinkLayerController::Tick() { RunPendingTasks(); Paging(); if (inquiry_timer_task_id_ != kInvalidTaskId) { Inquiry(); } Inquiring(); LeAdvertising(); LeScanning(); link_manager_tick(lm_.get()); Loading Loading @@ -5386,7 +5421,7 @@ ErrorCode LinkLayerController::CreateConnection(const Address& bd_addr, } 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, Loading Loading @@ -6043,10 +6078,7 @@ void LinkLayerController::Reset() { 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(); Loading @@ -6056,11 +6088,7 @@ void LinkLayerController::Reset() { 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_)); Loading @@ -6071,7 +6099,7 @@ void LinkLayerController::Paging() { 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( Loading @@ -6094,47 +6122,30 @@ void LinkLayerController::Paging() { } } 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)); } } } void LinkLayerController::SetInquiryMode(uint8_t mode) { inquiry_mode_ = static_cast<model::packets::InquiryType>(mode); inquiry_ = {}; return; } void LinkLayerController::SetInquiryLAP(uint64_t lap) { inquiry_lap_ = lap; } void LinkLayerController::SetInquiryMaxResponses(uint8_t max) { inquiry_max_responses_ = max; // 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; } 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::SetInquiryMode(uint8_t mode) { inquiry_mode_ = static_cast<model::packets::InquiryType>(mode); } void LinkLayerController::SetInquiryScanEnable(bool enable) { Loading
tools/rootcanal/model/controller/link_layer_controller.h +21 −13 Original line number Diff line number Diff line Loading @@ -185,6 +185,7 @@ class LinkLayerController { void Reset(); void Paging(); void Inquiring(); void LeAdvertising(); void LeScanning(); void LeSynchronization(); Loading Loading @@ -267,13 +268,7 @@ class LinkLayerController { 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); Loading Loading @@ -334,6 +329,12 @@ class LinkLayerController { // 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); Loading Loading @@ -939,6 +940,9 @@ class LinkLayerController { // 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). Loading Loading @@ -1161,23 +1165,27 @@ class LinkLayerController { 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. 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{}; }; // Page and inquiry substates. // RootCanal will allow only one page request running at the same time. std::optional<Page> page_; std::optional<PageState> page_; std::optional<InquiryState> inquiry_; std::chrono::steady_clock::time_point last_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. Loading