ASSERT(reset_complete.GetStatus() == ErrorCode::SUCCESS);
}
-static void on_hci_timeout(OpCode op_code) {
- ASSERT_LOG(false, "Timed out waiting for 0x%02hx (%s)", op_code, OpCodeText(op_code).c_str());
+static void abort_after_time_out(OpCode op_code) {
+ ASSERT_LOG(false, "Done waiting for debug information after HCI timeout (%s)", OpCodeText(op_code).c_str());
}
class CommandQueueEntry {
struct HciLayer::impl {
impl(hal::HciHal* hal, HciLayer& module) : hal_(hal), module_(module) {
hci_timeout_alarm_ = new Alarm(module.GetHandler());
+ hci_abort_alarm_ = new Alarm(module.GetHandler());
}
~impl() {
incoming_acl_buffer_.Clear();
incoming_iso_buffer_.Clear();
delete hci_timeout_alarm_;
+ delete hci_abort_alarm_;
command_queue_.clear();
}
send_next_command();
}
+ void on_hci_timeout(OpCode op_code) {
+ LOG_ERROR("Timed out waiting for 0x%02hx (%s)", op_code, OpCodeText(op_code).c_str());
+
+ LOG_ERROR("Flushing %zd waiting commands", command_queue_.size());
+ // Clear any waiting commands (there is an abort coming anyway)
+ command_queue_.clear();
+ command_credits_ = 1;
+ waiting_command_ = OpCode::NONE;
+ enqueue_command(
+ ControllerDebugInfoBuilder::Create(), module_.GetHandler()->BindOnce(&fail_if_reset_complete_not_success));
+ // Don't time out for this one;
+ hci_timeout_alarm_->Cancel();
+ hci_abort_alarm_->Schedule(BindOnce(&abort_after_time_out, op_code), kHciTimeoutRestartMs);
+ }
+
void send_next_command() {
if (command_credits_ == 0) {
return;
OpCode op_code = cmd_view.GetOpCode();
waiting_command_ = op_code;
command_credits_ = 0; // Only allow one outstanding command
- hci_timeout_alarm_->Schedule(BindOnce(&on_hci_timeout, op_code), kHciTimeoutMs);
+ hci_timeout_alarm_->Schedule(BindOnce(&impl::on_hci_timeout, common::Unretained(this), op_code), kHciTimeoutMs);
}
void register_event(EventCode event, ContextualCallback<void(EventView)> handler) {
OpCode waiting_command_{OpCode::NONE};
uint8_t command_credits_{1}; // Send reset first
Alarm* hci_timeout_alarm_{nullptr};
+ Alarm* hci_abort_alarm_{nullptr};
// Acl packets
BidiQueue<AclView, AclBuilder> acl_queue_{3 /* TODO: Set queue depth */};
ASSERT_NE(event_status, std::future_status::ready);
}
+TEST_F(HciTest, hciTimeOut) {
+ auto event_future = upper->GetReceivedEventFuture();
+ auto reset_command_future = hal->GetSentCommandFuture();
+ upper->SendHciCommandExpectingComplete(ResetBuilder::Create());
+ auto reset_command_sent_status = reset_command_future.wait_for(kTimeout);
+ ASSERT_EQ(reset_command_sent_status, std::future_status::ready);
+ auto reset = hal->GetSentCommand();
+ ASSERT_TRUE(reset.IsValid());
+ ASSERT_EQ(reset.GetOpCode(), OpCode::RESET);
+
+ auto debug_command_future = hal->GetSentCommandFuture();
+ auto event_status = event_future.wait_for(HciLayer::kHciTimeoutMs);
+ ASSERT_NE(event_status, std::future_status::ready);
+ auto debug_command_sent_status = debug_command_future.wait_for(kTimeout);
+ ASSERT_EQ(debug_command_sent_status, std::future_status::ready);
+ auto debug = hal->GetSentCommand();
+ ASSERT_TRUE(debug.IsValid());
+ ASSERT_EQ(debug.GetOpCode(), OpCode::CONTROLLER_DEBUG_INFO);
+}
+
TEST_F(HciTest, noOpCredits) {
ASSERT_EQ(0, hal->GetNumSentCommands());