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

Commit a2adef9c authored by David Duarte's avatar David Duarte Committed by Gerrit Code Review
Browse files

Merge "Use common TestHciLayer"

parents 9296968f 5281d5a0
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