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

Commit 917efb1c authored by Zach Johnson's avatar Zach Johnson Committed by Myles Watson
Browse files

Bring multi-channel transport into the glorious new age

Some devices still use MCT as their UART protocol, so
we need to bring it forward to the fresh new HAL.

Also, adding tests for H4 while I'm here.

Test: new unit tests pass and a device using MCT now
boots BT again \o/
Fixes: 34992730
Change-Id: Idb8e536a2779929ad8a0d4bac492c3011995cd79
parent 1143a3fe
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -56,6 +56,9 @@ cc_library_static {
    name: "android.hardware.bluetooth-hci",
    srcs: [
        "hci_packetizer.cc",
        "hci_protocol.cc",
        "h4_protocol.cc",
        "mct_protocol.cc",
    ],
    export_include_dirs: ["."],
    shared_libs: [
@@ -71,16 +74,21 @@ cc_test {
    name: "bluetooth-vendor-interface-unit-tests",
    srcs: [
        "test/async_fd_watcher_unittest.cc",
        "test/h4_protocol_unittest.cc",
        "test/mct_protocol_unittest.cc",
    ],
    local_include_dirs: [
        "test",
    ],
    shared_libs: [
        "libbase",
        "libhidlbase",
        "liblog",
    ],
    static_libs: [
        "android.hardware.bluetooth-async",
        "android.hardware.bluetooth-hci",
        "libgmock",
    ],
}

+8 −15
Original line number Diff line number Diff line
@@ -44,21 +44,14 @@ Return<void> BluetoothHci::initialize(
        event_cb_->initializationComplete(
            status ? Status::SUCCESS : Status::INITIALIZATION_ERROR);
      },
      [this](HciPacketType type, const hidl_vec<uint8_t>& packet) {
        switch (type) {
          case HCI_PACKET_TYPE_EVENT:
      [this](const hidl_vec<uint8_t>& packet) {
        event_cb_->hciEventReceived(packet);
            break;
          case HCI_PACKET_TYPE_ACL_DATA:
      },
      [this](const hidl_vec<uint8_t>& packet) {
        event_cb_->aclDataReceived(packet);
            break;
          case HCI_PACKET_TYPE_SCO_DATA:
      },
      [this](const hidl_vec<uint8_t>& packet) {
        event_cb_->scoDataReceived(packet);
            break;
          default:
            ALOGE("%s Unexpected event type %d", __func__, type);
            break;
        }
      });
  if (!rc) event_cb_->initializationComplete(Status::INITIALIZATION_ERROR);
  return Void();
+71 −0
Original line number Diff line number Diff line
//
// Copyright 2017 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#include "h4_protocol.h"

#define LOG_TAG "android.hardware.bluetooth-hci-h4"
#include <android-base/logging.h>
#include <assert.h>
#include <fcntl.h>

namespace android {
namespace hardware {
namespace bluetooth {
namespace hci {

size_t H4Protocol::Send(uint8_t type, const uint8_t* data, size_t length) {
  int rv = WriteSafely(uart_fd_, &type, sizeof(type));
  if (rv == sizeof(type)) {
    rv = WriteSafely(uart_fd_, data, length);
  }
  return rv;
}

void H4Protocol::OnPacketReady() {
  switch (hci_packet_type_) {
    case HCI_PACKET_TYPE_EVENT:
      event_cb_(hci_packetizer_.GetPacket());
      break;
    case HCI_PACKET_TYPE_ACL_DATA:
      acl_cb_(hci_packetizer_.GetPacket());
      break;
    case HCI_PACKET_TYPE_SCO_DATA:
      sco_cb_(hci_packetizer_.GetPacket());
      break;
    default: {
      bool bad_packet_type = true;
      CHECK(!bad_packet_type);
    }
  }
  // Get ready for the next type byte.
  hci_packet_type_ = HCI_PACKET_TYPE_UNKNOWN;
}

void H4Protocol::OnDataReady(int fd) {
  if (hci_packet_type_ == HCI_PACKET_TYPE_UNKNOWN) {
    uint8_t buffer[1] = {0};
    size_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, 1));
    CHECK(bytes_read == 1);
    hci_packet_type_ = static_cast<HciPacketType>(buffer[0]);
  } else {
    hci_packetizer_.OnDataReady(fd, hci_packet_type_);
  }
}

}  // namespace hci
}  // namespace bluetooth
}  // namespace hardware
}  // namespace android
+61 −0
Original line number Diff line number Diff line
//
// Copyright 2017 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#pragma once

#include <hidl/HidlSupport.h>

#include "async_fd_watcher.h"
#include "bt_vendor_lib.h"
#include "hci_internals.h"
#include "hci_protocol.h"

namespace android {
namespace hardware {
namespace bluetooth {
namespace hci {

class H4Protocol : public HciProtocol {
 public:
  H4Protocol(int fd, PacketReadCallback event_cb, PacketReadCallback acl_cb,
             PacketReadCallback sco_cb)
      : uart_fd_(fd),
        event_cb_(event_cb),
        acl_cb_(acl_cb),
        sco_cb_(sco_cb),
        hci_packetizer_([this]() { OnPacketReady(); }) {}

  size_t Send(uint8_t type, const uint8_t* data, size_t length);

  void OnPacketReady();

  void OnDataReady(int fd);

 private:
  int uart_fd_;

  PacketReadCallback event_cb_;
  PacketReadCallback acl_cb_;
  PacketReadCallback sco_cb_;

  HciPacketType hci_packet_type_{HCI_PACKET_TYPE_UNKNOWN};
  hci::HciPacketizer hci_packetizer_;
};

}  // namespace hci
}  // namespace bluetooth
}  // namespace hardware
}  // namespace android
+24 −48
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@

#define LOG_TAG "android.hardware.bluetooth.hci_packetizer"
#include <android-base/logging.h>
#include <cutils/properties.h>
#include <utils/Log.h>

#include <dlfcn.h>
@@ -46,63 +45,40 @@ namespace hardware {
namespace bluetooth {
namespace hci {

HciPacketType HciPacketizer::GetPacketType() const {
  return hci_packet_type_;
}

const hidl_vec<uint8_t>& HciPacketizer::GetPacket() const {
  return hci_packet_;
}
const hidl_vec<uint8_t>& HciPacketizer::GetPacket() const { return packet_; }

void HciPacketizer::OnDataReady(int fd) {
  switch (hci_parser_state_) {
    case HCI_IDLE: {
      uint8_t buffer[1] = {0};
      size_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, 1));
      CHECK(bytes_read == 1);
      hci_packet_type_ = static_cast<HciPacketType>(buffer[0]);
      CHECK(hci_packet_type_ >= HCI_PACKET_TYPE_ACL_DATA &&
            hci_packet_type_ <= HCI_PACKET_TYPE_EVENT)
          << "buffer[0] = " << static_cast<unsigned int>(buffer[0]);
      hci_parser_state_ = HCI_TYPE_READY;
      hci_packet_bytes_remaining_ = preamble_size_for_type[hci_packet_type_];
      hci_packet_bytes_read_ = 0;
      break;
    }

    case HCI_TYPE_READY: {
void HciPacketizer::OnDataReady(int fd, HciPacketType packet_type) {
  switch (state_) {
    case HCI_PREAMBLE: {
      size_t bytes_read = TEMP_FAILURE_RETRY(
          read(fd, hci_packet_preamble_ + hci_packet_bytes_read_,
               hci_packet_bytes_remaining_));
          read(fd, preamble_ + bytes_read_,
               preamble_size_for_type[packet_type] - bytes_read_));
      CHECK(bytes_read > 0);
      hci_packet_bytes_remaining_ -= bytes_read;
      hci_packet_bytes_read_ += bytes_read;
      if (hci_packet_bytes_remaining_ == 0) {
      bytes_read_ += bytes_read;
      if (bytes_read_ == preamble_size_for_type[packet_type]) {
        size_t packet_length =
            HciGetPacketLengthForType(hci_packet_type_, hci_packet_preamble_);
        hci_packet_.resize(preamble_size_for_type[hci_packet_type_] +
                           packet_length);
        memcpy(hci_packet_.data(), hci_packet_preamble_,
               preamble_size_for_type[hci_packet_type_]);
        hci_packet_bytes_remaining_ = packet_length;
        hci_parser_state_ = HCI_PAYLOAD;
        hci_packet_bytes_read_ = 0;
            HciGetPacketLengthForType(packet_type, preamble_);
        packet_.resize(preamble_size_for_type[packet_type] + packet_length);
        memcpy(packet_.data(), preamble_, preamble_size_for_type[packet_type]);
        bytes_remaining_ = packet_length;
        state_ = HCI_PAYLOAD;
        bytes_read_ = 0;
      }
      break;
    }

    case HCI_PAYLOAD: {
      size_t bytes_read = TEMP_FAILURE_RETRY(
          read(fd,
               hci_packet_.data() + preamble_size_for_type[hci_packet_type_] +
                   hci_packet_bytes_read_,
               hci_packet_bytes_remaining_));
      size_t bytes_read = TEMP_FAILURE_RETRY(read(
          fd,
          packet_.data() + preamble_size_for_type[packet_type] + bytes_read_,
          bytes_remaining_));
      CHECK(bytes_read > 0);
      hci_packet_bytes_remaining_ -= bytes_read;
      hci_packet_bytes_read_ += bytes_read;
      if (hci_packet_bytes_remaining_ == 0) {
        hci_packet_ready_cb_();
        hci_parser_state_ = HCI_IDLE;
      bytes_remaining_ -= bytes_read;
      bytes_read_ += bytes_read;
      if (bytes_remaining_ == 0) {
        packet_ready_cb_();
        state_ = HCI_PREAMBLE;
        bytes_read_ = 0;
      }
      break;
    }
Loading