Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5281d5a0 authored by Rahul Arya's avatar Rahul Arya
Browse files

Use common TestHciLayer

Bug: 261828174
Test: gd unit
Change-Id: I27080b52de9e35c6efb354185fea55ce2fa05c66
parent 9b1e5f58
Loading
Loading
Loading
Loading
+144 −436

File changed.

Preview size limit exceeded, changes collapsed.

+68 −1
Original line number Diff line number Diff line
@@ -25,6 +25,8 @@
namespace bluetooth {
namespace hci {

using common::BidiQueue;
using common::BidiQueueEnd;
using packet::kLittleEndian;
using packet::PacketView;
using packet::RawBuilder;
@@ -37,6 +39,22 @@ PacketView<packet::kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePack
  return packet::PacketView<packet::kLittleEndian>(bytes);
}

std::unique_ptr<BasePacketBuilder> NextPayload(uint16_t handle) {
  static uint32_t packet_number = 1;
  auto payload = std::make_unique<RawBuilder>();
  payload->AddOctets2(6);  // L2CAP PDU size
  payload->AddOctets2(2);  // L2CAP CID
  payload->AddOctets2(handle);
  payload->AddOctets4(packet_number++);
  return std::move(payload);
}

static std::unique_ptr<AclBuilder> NextAclPacket(uint16_t handle) {
  PacketBoundaryFlag packet_boundary_flag = PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE;
  BroadcastFlag broadcast_flag = BroadcastFlag::POINT_TO_POINT;
  return AclBuilder::Create(handle, packet_boundary_flag, broadcast_flag, NextPayload(handle));
}

void TestHciLayer::EnqueueCommand(
    std::unique_ptr<CommandBuilder> command, common::ContextualOnceCallback<void(CommandStatusView)> on_status) {
  std::lock_guard<std::mutex> lock(mutex_);
@@ -150,10 +168,59 @@ void TestHciLayer::InitEmptyCommand() {
  ASSERT_TRUE(empty_command_view_.IsValid());
}

void TestHciLayer::IncomingAclData(uint16_t handle) {
  os::Handler* hci_handler = GetHandler();
  auto* queue_end = acl_queue_.GetDownEnd();
  std::promise<void> promise;
  auto future = promise.get_future();
  queue_end->RegisterEnqueue(
      hci_handler,
      common::Bind(
          [](decltype(queue_end) queue_end, uint16_t handle, std::promise<void> promise) {
            auto packet = GetPacketView(NextAclPacket(handle));
            AclView acl2 = AclView::Create(packet);
            queue_end->UnregisterEnqueue();
            promise.set_value();
            return std::make_unique<AclView>(acl2);
          },
          queue_end,
          handle,
          common::Passed(std::move(promise))));
  auto status = future.wait_for(std::chrono::milliseconds(1000));
  ASSERT_EQ(status, std::future_status::ready);
}

void TestHciLayer::AssertNoOutgoingAclData() {
  auto queue_end = acl_queue_.GetDownEnd();
  EXPECT_EQ(queue_end->TryDequeue(), nullptr);
}

PacketView<kLittleEndian> TestHciLayer::OutgoingAclData() {
  auto queue_end = acl_queue_.GetDownEnd();
  std::unique_ptr<AclBuilder> received;
  do {
    received = queue_end->TryDequeue();
  } while (received == nullptr);

  return GetPacketView(std::move(received));
}

BidiQueueEnd<AclBuilder, AclView>* TestHciLayer::GetAclQueueEnd() {
  return acl_queue_.GetUpEnd();
}

void TestHciLayer::Disconnect(uint16_t handle, ErrorCode reason) {
  GetHandler()->Post(
      common::BindOnce(&TestHciLayer::do_disconnect, common::Unretained(this), handle, reason));
}

void TestHciLayer::do_disconnect(uint16_t handle, ErrorCode reason) {
  HciLayer::Disconnect(handle, reason);
}

void TestHciLayer::ListDependencies(ModuleList* list) const {}
void TestHciLayer::Start() {
  std::lock_guard<std::mutex> lock(mutex_);

  InitEmptyCommand();
}
void TestHciLayer::Stop() {}
+28 −13
Original line number Diff line number Diff line
@@ -25,10 +25,10 @@
namespace bluetooth {
namespace hci {

using packet::kLittleEndian;
using packet::PacketView;
packet::PacketView<packet::kLittleEndian> GetPacketView(
    std::unique_ptr<packet::BasePacketBuilder> packet);

PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet);
std::unique_ptr<BasePacketBuilder> NextPayload(uint16_t handle);

class TestHciLayer : public HciLayer {
 public:
@@ -59,6 +59,16 @@ class TestHciLayer : public HciLayer {

  void CommandStatusCallback(EventView event);

  void IncomingAclData(uint16_t handle);

  void AssertNoOutgoingAclData();

  packet::PacketView<packet::kLittleEndian> OutgoingAclData();

  common::BidiQueueEnd<AclBuilder, AclView>* GetAclQueueEnd() override;

  void Disconnect(uint16_t handle, ErrorCode reason) override;

 protected:
  void ListDependencies(ModuleList* list) const override;
  void Start() override;
@@ -66,6 +76,7 @@ class TestHciLayer : public HciLayer {

 private:
  void InitEmptyCommand();
  void do_disconnect(uint16_t handle, ErrorCode reason);

  // Handler-only state. Mutexes are not needed when accessing these fields.
  std::list<common::ContextualOnceCallback<void(CommandCompleteView)>> command_complete_callbacks;
@@ -73,9 +84,12 @@ class TestHciLayer : public HciLayer {
  std::map<EventCode, common::ContextualCallback<void(EventView)>> registered_events_;
  std::map<SubeventCode, common::ContextualCallback<void(LeMetaEventView)>> registered_le_events_;

  // Most operations must acquire this mutex before manipulating shared state. The ONLY exception is blocking on a
  // promise, IF your thread is the only one mutating it. Note that SETTING a promise REQUIRES a lock, since another
  // thread may replace the promise while you are doing so.
  // thread-safe
  common::BidiQueue<AclView, AclBuilder> acl_queue_{3 /* TODO: Set queue depth */};

  // Most operations must acquire this mutex before manipulating shared state. The ONLY exception
  // is blocking on a promise, IF your thread is the only one mutating it. Note that SETTING a
  // promise REQUIRES a lock, since another thread may replace the promise while you are doing so.
  mutable std::mutex mutex_{};

  // Shared state between the test and stack threads
@@ -83,13 +97,14 @@ class TestHciLayer : public HciLayer {

  // We start with Consumed=Set, Command=Unset.
  // When a command is enqueued, we set Command=set
  // When a command is popped, we block until Command=Set, then (if the queue is now empty) we reset Command=Unset and
  // set Consumed=Set. This way we emulate a blocking queue.
  // When a command is popped, we block until Command=Set, then (if the queue is now empty) we
  // reset Command=Unset and set Consumed=Set. This way we emulate a blocking queue.
  std::promise<void> command_promise_{};  // Set when at least one command is in the queue
  std::future<void> command_future_ = command_promise_.get_future();  // GetCommand() blocks until this is fulfilled
  std::future<void> command_future_ =
      command_promise_.get_future();  // GetCommand() blocks until this is fulfilled

  CommandView empty_command_view_ =
      CommandView::Create(PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>()));
  CommandView empty_command_view_ = CommandView::Create(
      PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>()));
};

}  // namespace hci