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

Commit c4c2793b authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Bluetooth: Make HciPacketizer reusable"

parents 09e49b08 274a381d
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ cc_library_shared {
    ],
    static_libs: [
        "android.hardware.bluetooth-async",
        "android.hardware.bluetooth-hci",
    ],
}

@@ -51,6 +52,21 @@ cc_library_static {
    ],
}

cc_library_static {
    name: "android.hardware.bluetooth-hci",
    srcs: [
        "hci_packetizer.cc",
    ],
    export_include_dirs: ["."],
    shared_libs: [
        "libbase",
        "libcutils",
        "libhidlbase",
        "liblog",
        "libutils",
    ],
}

cc_test {
    name: "bluetooth-vendor-interface-unit-tests",
    srcs: [
+2 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

#pragma once

#include <stdlib.h>

// HCI UART transport packet types (Volume 4, Part A, 2)
enum HciPacketType {
  HCI_PACKET_TYPE_UNKNOWN = 0,
+115 −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 "hci_packetizer.h"

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

#include <dlfcn.h>
#include <fcntl.h>

namespace {

const size_t preamble_size_for_type[] = {
    0, HCI_COMMAND_PREAMBLE_SIZE, HCI_ACL_PREAMBLE_SIZE, HCI_SCO_PREAMBLE_SIZE,
    HCI_EVENT_PREAMBLE_SIZE};
const size_t packet_length_offset_for_type[] = {
    0, HCI_LENGTH_OFFSET_CMD, HCI_LENGTH_OFFSET_ACL, HCI_LENGTH_OFFSET_SCO,
    HCI_LENGTH_OFFSET_EVT};

size_t HciGetPacketLengthForType(HciPacketType type, const uint8_t* preamble) {
  size_t offset = packet_length_offset_for_type[type];
  if (type != HCI_PACKET_TYPE_ACL_DATA) return preamble[offset];
  return (((preamble[offset + 1]) << 8) | preamble[offset]);
}

}  // namespace

namespace android {
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_;
}

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: {
      size_t bytes_read = TEMP_FAILURE_RETRY(
          read(fd, hci_packet_preamble_ + hci_packet_bytes_read_,
               hci_packet_bytes_remaining_));
      CHECK(bytes_read > 0);
      hci_packet_bytes_remaining_ -= bytes_read;
      hci_packet_bytes_read_ += bytes_read;
      if (hci_packet_bytes_remaining_ == 0) {
        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;
      }
      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_));
      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;
      }
      break;
    }
  }
}

}  // namespace hci
}  // namespace bluetooth
}  // namespace hardware
}  // namespace android
+54 −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 <functional>

#include <hidl/HidlSupport.h>

#include "hci_internals.h"

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

using ::android::hardware::hidl_vec;
using HciPacketReadyCallback = std::function<void(void)>;

class HciPacketizer {
 public:
  HciPacketizer(HciPacketReadyCallback packet_cb) : hci_packet_ready_cb_(packet_cb) {};
  void OnDataReady(int fd);
  const hidl_vec<uint8_t>& GetPacket() const;
  HciPacketType GetPacketType() const;

 protected:
  enum HciParserState { HCI_IDLE, HCI_TYPE_READY, HCI_PAYLOAD };
  HciParserState hci_parser_state_{HCI_IDLE};
  HciPacketType hci_packet_type_{HCI_PACKET_TYPE_UNKNOWN};
  uint8_t hci_packet_preamble_[HCI_PREAMBLE_SIZE_MAX];
  hidl_vec<uint8_t> hci_packet_;
  size_t hci_packet_bytes_remaining_;
  size_t hci_packet_bytes_read_;
  HciPacketReadyCallback hci_packet_ready_cb_;
};

}  // namespace hci
}  // namespace bluetooth
}  // namespace hardware
}  // namespace android
+11 −70
Original line number Diff line number Diff line
@@ -51,19 +51,6 @@ bool recent_activity_flag;

VendorInterface* g_vendor_interface = nullptr;

const size_t preamble_size_for_type[] = {
    0, HCI_COMMAND_PREAMBLE_SIZE, HCI_ACL_PREAMBLE_SIZE, HCI_SCO_PREAMBLE_SIZE,
    HCI_EVENT_PREAMBLE_SIZE};
const size_t packet_length_offset_for_type[] = {
    0, HCI_LENGTH_OFFSET_CMD, HCI_LENGTH_OFFSET_ACL, HCI_LENGTH_OFFSET_SCO,
    HCI_LENGTH_OFFSET_EVT};

size_t HciGetPacketLengthForType(HciPacketType type, const uint8_t* preamble) {
  size_t offset = packet_length_offset_for_type[type];
  if (type != HCI_PACKET_TYPE_ACL_DATA) return preamble[offset];
  return (((preamble[offset + 1]) << 8) | preamble[offset]);
}

HC_BT_HDR* WrapPacketAndCopy(uint16_t event, const hidl_vec<uint8_t>& data) {
  size_t packet_size = data.size() + sizeof(HC_BT_HDR);
  HC_BT_HDR* packet = reinterpret_cast<HC_BT_HDR*>(new uint8_t[packet_size]);
@@ -274,7 +261,7 @@ bool VendorInterface::Open(InitializeCompleteCallback initialize_complete_cb,
  ALOGI("%s UART fd: %d", __func__, uart_fd_);

  fd_watcher_.WatchFdForNonBlockingReads(uart_fd_,
                                         [this](int fd) { OnDataReady(fd); });
                                         [this](int fd) { hci_packetizer_.OnDataReady(fd); });

  // Initially, the power management is off.
  lpm_wake_deasserted = true;
@@ -370,71 +357,25 @@ void VendorInterface::OnTimeout() {
  recent_activity_flag = false;
}

void VendorInterface::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]);
      // TODO(eisenbach): Check for workaround(s)
      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: {
      size_t bytes_read = TEMP_FAILURE_RETRY(
          read(fd, hci_packet_preamble_ + hci_packet_bytes_read_,
               hci_packet_bytes_remaining_));
      CHECK(bytes_read > 0);
      hci_packet_bytes_remaining_ -= bytes_read;
      hci_packet_bytes_read_ += bytes_read;
      if (hci_packet_bytes_remaining_ == 0) {
        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;
      }
      break;
void VendorInterface::OnPacketReady() {
  VendorInterface::get()->HandleIncomingPacket();
}

    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_));
      CHECK(bytes_read > 0);
      hci_packet_bytes_remaining_ -= bytes_read;
      hci_packet_bytes_read_ += bytes_read;
      if (hci_packet_bytes_remaining_ == 0) {
void VendorInterface::HandleIncomingPacket() {
  HciPacketType hci_packet_type = hci_packetizer_.GetPacketType();
  hidl_vec<uint8_t> hci_packet = hci_packetizer_.GetPacket();
        if (internal_command.cb != nullptr &&
            hci_packet_type_ == HCI_PACKET_TYPE_EVENT &&
            internal_command_event_match(hci_packet_)) {
            hci_packet_type == HCI_PACKET_TYPE_EVENT &&
            internal_command_event_match(hci_packet)) {
          HC_BT_HDR* bt_hdr =
              WrapPacketAndCopy(HCI_PACKET_TYPE_EVENT, hci_packet_);
              WrapPacketAndCopy(HCI_PACKET_TYPE_EVENT, hci_packet);

          // The callbacks can send new commands, so don't zero after calling.
          tINT_CMD_CBACK saved_cb = internal_command.cb;
          internal_command.cb = nullptr;
          saved_cb(bt_hdr);
        } else {
          packet_read_cb_(hci_packet_type_, hci_packet_);
        }
        hci_parser_state_ = HCI_IDLE;
      }
      break;
    }
          packet_read_cb_(hci_packet_type, hci_packet);
        }
}

Loading