return;
}
if (!fragments_to_send_.empty()) {
+ auto connection_type = fragments_to_send_.front().first;
+ bool classic_buffer_full = acl_packet_credits_ == 0 && connection_type == ConnectionType::CLASSIC;
+ bool le_buffer_full = le_acl_packet_credits_ == 0 && connection_type == ConnectionType::LE;
+ if (classic_buffer_full || le_buffer_full) {
+ LOG_WARN("Buffer of connection_type %d is full", connection_type);
+ return;
+ }
send_next_fragment();
return;
}
acl_queue_handler->second.number_of_sent_packets_ = 0;
}
+ bool credit_was_zero = false;
if (acl_queue_handler->second.connection_type_ == ConnectionType::CLASSIC) {
+ if (acl_packet_credits_ == 0) {
+ credit_was_zero = true;
+ }
acl_packet_credits_ += credits;
if (acl_packet_credits_ > max_acl_packet_credits_) {
acl_packet_credits_ = max_acl_packet_credits_;
LOG_WARN("acl packet credits overflow due to receive %hx credits", credits);
}
} else {
+ if (le_acl_packet_credits_ == 0) {
+ credit_was_zero = true;
+ }
le_acl_packet_credits_ += credits;
if (le_acl_packet_credits_ > le_max_acl_packet_credits_) {
le_acl_packet_credits_ = le_max_acl_packet_credits_;
LOG_WARN("le acl packet credits overflow due to receive %hx credits", credits);
}
}
- if (acl_packet_credits_ == credits || le_acl_packet_credits_ == credits) {
+ if (credit_was_zero) {
start_round_robin();
}
}
round_robin_scheduler_->Unregister(le_handle);
}
+TEST_F(RoundRobinSchedulerTest, receive_le_credit_when_next_fragment_is_classic) {
+ uint16_t handle = 0x01;
+ uint16_t le_handle = 0x02;
+ auto connection_queue = std::make_shared<AclConnection::Queue>(20);
+ auto le_connection_queue = std::make_shared<AclConnection::Queue>(20);
+
+ round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle, connection_queue);
+ round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::LE, le_handle, le_connection_queue);
+
+ SetPacketFuture(controller_->le_max_acl_packet_credits_ + controller_->max_acl_packet_credits_);
+ AclConnection::QueueUpEnd* queue_up_end = connection_queue->GetUpEnd();
+ AclConnection::QueueUpEnd* le_queue_up_end = le_connection_queue->GetUpEnd();
+ std::vector<uint8_t> huge_packet(2000);
+ std::vector<uint8_t> packet = {0x01, 0x02, 0x03};
+ std::vector<uint8_t> le_packet = {0x04, 0x05, 0x06};
+
+ // Make le_acl_packet_credits_ = 0;
+ for (uint16_t i = 0; i < controller_->le_max_acl_packet_credits_; i++) {
+ EnqueueAclUpEnd(le_queue_up_end, le_packet);
+ }
+
+ // Make acl_packet_credits_ = 0 and remain 1 acl fragment in fragments_to_send_
+ for (uint16_t i = 0; i < controller_->max_acl_packet_credits_ - 1; i++) {
+ EnqueueAclUpEnd(queue_up_end, packet);
+ }
+ EnqueueAclUpEnd(queue_up_end, huge_packet);
+
+ packet_future_->wait();
+
+ // Trigger start_round_robin
+ controller_->SendCompletedAclPacketsCallback(0x02, 1);
+ std::this_thread::sleep_for(std::chrono::milliseconds(20));
+
+ ASSERT_EQ(round_robin_scheduler_->GetCredits(), 0);
+ ASSERT_EQ(round_robin_scheduler_->GetLeCredits(), 1);
+
+ round_robin_scheduler_->Unregister(handle);
+ round_robin_scheduler_->Unregister(le_handle);
+}
+
} // namespace acl_manager
} // namespace hci
} // namespace bluetooth