Bluetooth: Make HciPacketizer reusable
Test: VtsHalBluetoothV1_0TargetTest passes
Change-Id: I480d156225af2a5dd879f47a897af0b01dab5663
diff --git a/bluetooth/1.0/default/Android.bp b/bluetooth/1.0/default/Android.bp
index f82bc1f..69cefd6 100644
--- a/bluetooth/1.0/default/Android.bp
+++ b/bluetooth/1.0/default/Android.bp
@@ -34,6 +34,7 @@
],
static_libs: [
"android.hardware.bluetooth-async",
+ "android.hardware.bluetooth-hci",
],
}
@@ -51,6 +52,21 @@
],
}
+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: [
diff --git a/bluetooth/1.0/default/hci_internals.h b/bluetooth/1.0/default/hci_internals.h
index d5714be..1e1f300 100644
--- a/bluetooth/1.0/default/hci_internals.h
+++ b/bluetooth/1.0/default/hci_internals.h
@@ -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,
diff --git a/bluetooth/1.0/default/hci_packetizer.cc b/bluetooth/1.0/default/hci_packetizer.cc
new file mode 100644
index 0000000..1a50196
--- /dev/null
+++ b/bluetooth/1.0/default/hci_packetizer.cc
@@ -0,0 +1,115 @@
+//
+// 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
diff --git a/bluetooth/1.0/default/hci_packetizer.h b/bluetooth/1.0/default/hci_packetizer.h
new file mode 100644
index 0000000..e9c01dc
--- /dev/null
+++ b/bluetooth/1.0/default/hci_packetizer.h
@@ -0,0 +1,54 @@
+//
+// 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
diff --git a/bluetooth/1.0/default/vendor_interface.cc b/bluetooth/1.0/default/vendor_interface.cc
index 7737dd2..3878129 100644
--- a/bluetooth/1.0/default/vendor_interface.cc
+++ b/bluetooth/1.0/default/vendor_interface.cc
@@ -51,19 +51,6 @@
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 @@
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,72 +357,26 @@
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;
- }
+void VendorInterface::OnPacketReady() {
+ VendorInterface::get()->HandleIncomingPacket();
+}
- 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) {
+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_);
+ packet_read_cb_(hci_packet_type, hci_packet);
}
- hci_parser_state_ = HCI_IDLE;
- }
- break;
- }
- }
}
} // namespace implementation
diff --git a/bluetooth/1.0/default/vendor_interface.h b/bluetooth/1.0/default/vendor_interface.h
index 98357f5..8115640 100644
--- a/bluetooth/1.0/default/vendor_interface.h
+++ b/bluetooth/1.0/default/vendor_interface.h
@@ -20,7 +20,7 @@
#include "async_fd_watcher.h"
#include "bt_vendor_lib.h"
-#include "hci_internals.h"
+#include "hci_packetizer.h"
namespace android {
namespace hardware {
@@ -46,6 +46,8 @@
void OnFirmwareConfigured(uint8_t result);
+ static void OnPacketReady();
+
private:
virtual ~VendorInterface() = default;
@@ -55,7 +57,7 @@
void OnTimeout();
- void OnDataReady(int fd);
+ void HandleIncomingPacket();
void *lib_handle_;
bt_vendor_interface_t *lib_interface_;
@@ -64,13 +66,7 @@
PacketReadCallback packet_read_cb_;
InitializeCompleteCallback initialize_complete_cb_;
- 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_;
+ hci::HciPacketizer hci_packetizer_ {VendorInterface::OnPacketReady};
FirmwareStartupTimer *firmware_startup_timer_;
};