Merge "Bring multi-channel transport into the glorious new age"
am: a15a9bbadf
Change-Id: Iec27272215b8e11041c221ad9d338e8011052ae3
This commit is contained in:
commit
2296cfbe55
14 changed files with 907 additions and 154 deletions
|
@ -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",
|
||||
],
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
event_cb_->hciEventReceived(packet);
|
||||
break;
|
||||
case HCI_PACKET_TYPE_ACL_DATA:
|
||||
event_cb_->aclDataReceived(packet);
|
||||
break;
|
||||
case HCI_PACKET_TYPE_SCO_DATA:
|
||||
event_cb_->scoDataReceived(packet);
|
||||
break;
|
||||
default:
|
||||
ALOGE("%s Unexpected event type %d", __func__, type);
|
||||
break;
|
||||
}
|
||||
[this](const hidl_vec<uint8_t>& packet) {
|
||||
event_cb_->hciEventReceived(packet);
|
||||
},
|
||||
[this](const hidl_vec<uint8_t>& packet) {
|
||||
event_cb_->aclDataReceived(packet);
|
||||
},
|
||||
[this](const hidl_vec<uint8_t>& packet) {
|
||||
event_cb_->scoDataReceived(packet);
|
||||
});
|
||||
if (!rc) event_cb_->initializationComplete(Status::INITIALIZATION_ERROR);
|
||||
return Void();
|
||||
|
|
71
bluetooth/1.0/default/h4_protocol.cc
Normal file
71
bluetooth/1.0/default/h4_protocol.cc
Normal file
|
@ -0,0 +1,71 @@
|
|||
//
|
||||
// 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
bluetooth/1.0/default/h4_protocol.h
Normal file
61
bluetooth/1.0/default/h4_protocol.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
//
|
||||
// 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
|
|
@ -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 packet_; }
|
||||
|
||||
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: {
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -32,20 +32,19 @@ using HciPacketReadyCallback = std::function<void(void)>;
|
|||
|
||||
class HciPacketizer {
|
||||
public:
|
||||
HciPacketizer(HciPacketReadyCallback packet_cb) : hci_packet_ready_cb_(packet_cb) {};
|
||||
void OnDataReady(int fd);
|
||||
HciPacketizer(HciPacketReadyCallback packet_cb)
|
||||
: packet_ready_cb_(packet_cb){};
|
||||
void OnDataReady(int fd, HciPacketType packet_type);
|
||||
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_;
|
||||
enum State { HCI_PREAMBLE, HCI_PAYLOAD };
|
||||
State state_{HCI_PREAMBLE};
|
||||
uint8_t preamble_[HCI_PREAMBLE_SIZE_MAX];
|
||||
hidl_vec<uint8_t> packet_;
|
||||
size_t bytes_remaining_{0};
|
||||
size_t bytes_read_{0};
|
||||
HciPacketReadyCallback packet_ready_cb_;
|
||||
};
|
||||
|
||||
} // namespace hci
|
||||
|
|
74
bluetooth/1.0/default/hci_protocol.cc
Normal file
74
bluetooth/1.0/default/hci_protocol.cc
Normal file
|
@ -0,0 +1,74 @@
|
|||
//
|
||||
// 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_protocol.h"
|
||||
|
||||
#define LOG_TAG "android.hardware.bluetooth-hci-hci_protocol"
|
||||
#include <android-base/logging.h>
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <utils/Log.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 {
|
||||
|
||||
size_t HciProtocol::WriteSafely(int fd, const uint8_t* data, size_t length) {
|
||||
size_t transmitted_length = 0;
|
||||
while (length > 0) {
|
||||
ssize_t ret =
|
||||
TEMP_FAILURE_RETRY(write(fd, data + transmitted_length, length));
|
||||
|
||||
if (ret == -1) {
|
||||
if (errno == EAGAIN) continue;
|
||||
ALOGE("%s error writing to UART (%s)", __func__, strerror(errno));
|
||||
break;
|
||||
|
||||
} else if (ret == 0) {
|
||||
// Nothing written :(
|
||||
ALOGE("%s zero bytes written - something went wrong...", __func__);
|
||||
break;
|
||||
}
|
||||
|
||||
transmitted_length += ret;
|
||||
length -= ret;
|
||||
}
|
||||
|
||||
return transmitted_length;
|
||||
}
|
||||
|
||||
} // namespace hci
|
||||
} // namespace bluetooth
|
||||
} // namespace hardware
|
||||
} // namespace android
|
49
bluetooth/1.0/default/hci_protocol.h
Normal file
49
bluetooth/1.0/default/hci_protocol.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
//
|
||||
// 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 "bt_vendor_lib.h"
|
||||
#include "hci_internals.h"
|
||||
#include "hci_packetizer.h"
|
||||
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace bluetooth {
|
||||
namespace hci {
|
||||
|
||||
using ::android::hardware::hidl_vec;
|
||||
using PacketReadCallback = std::function<void(const hidl_vec<uint8_t>&)>;
|
||||
|
||||
// Implementation of HCI protocol bits common to different transports
|
||||
class HciProtocol {
|
||||
public:
|
||||
HciProtocol() = default;
|
||||
virtual ~HciProtocol(){};
|
||||
|
||||
// Protocol-specific implementation of sending packets.
|
||||
virtual size_t Send(uint8_t type, const uint8_t* data, size_t length) = 0;
|
||||
|
||||
protected:
|
||||
static size_t WriteSafely(int fd, const uint8_t* data, size_t length);
|
||||
};
|
||||
|
||||
} // namespace hci
|
||||
} // namespace bluetooth
|
||||
} // namespace hardware
|
||||
} // namespace android
|
71
bluetooth/1.0/default/mct_protocol.cc
Normal file
71
bluetooth/1.0/default/mct_protocol.cc
Normal file
|
@ -0,0 +1,71 @@
|
|||
//
|
||||
// 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 "mct_protocol.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#define LOG_TAG "android.hardware.bluetooth-hci-mct"
|
||||
#include <android-base/logging.h>
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace bluetooth {
|
||||
namespace hci {
|
||||
|
||||
MctProtocol::MctProtocol(int* fds, PacketReadCallback event_cb,
|
||||
PacketReadCallback acl_cb)
|
||||
: event_cb_(event_cb),
|
||||
acl_cb_(acl_cb),
|
||||
event_packetizer_([this]() { OnEventPacketReady(); }),
|
||||
acl_packetizer_([this]() { OnAclDataPacketReady(); }) {
|
||||
for (int i = 0; i < CH_MAX; i++) {
|
||||
uart_fds_[i] = fds[i];
|
||||
}
|
||||
}
|
||||
|
||||
size_t MctProtocol::Send(uint8_t type, const uint8_t* data, size_t length) {
|
||||
if (type == HCI_PACKET_TYPE_COMMAND)
|
||||
return WriteSafely(uart_fds_[CH_CMD], data, length);
|
||||
if (type == HCI_PACKET_TYPE_ACL_DATA)
|
||||
return WriteSafely(uart_fds_[CH_ACL_OUT], data, length);
|
||||
CHECK(type == HCI_PACKET_TYPE_COMMAND || type == HCI_PACKET_TYPE_ACL_DATA);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MctProtocol::OnEventPacketReady() {
|
||||
event_cb_(event_packetizer_.GetPacket());
|
||||
}
|
||||
|
||||
void MctProtocol::OnAclDataPacketReady() {
|
||||
acl_cb_(acl_packetizer_.GetPacket());
|
||||
}
|
||||
|
||||
void MctProtocol::OnEventDataReady(int fd) {
|
||||
event_packetizer_.OnDataReady(fd, HCI_PACKET_TYPE_EVENT);
|
||||
}
|
||||
|
||||
void MctProtocol::OnAclDataReady(int fd) {
|
||||
acl_packetizer_.OnDataReady(fd, HCI_PACKET_TYPE_ACL_DATA);
|
||||
}
|
||||
|
||||
} // namespace hci
|
||||
} // namespace bluetooth
|
||||
} // namespace hardware
|
||||
} // namespace android
|
56
bluetooth/1.0/default/mct_protocol.h
Normal file
56
bluetooth/1.0/default/mct_protocol.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
//
|
||||
// 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 MctProtocol : public HciProtocol {
|
||||
public:
|
||||
MctProtocol(int* fds, PacketReadCallback event_cb, PacketReadCallback acl_cb);
|
||||
|
||||
size_t Send(uint8_t type, const uint8_t* data, size_t length);
|
||||
|
||||
void OnEventPacketReady();
|
||||
void OnAclDataPacketReady();
|
||||
|
||||
void OnEventDataReady(int fd);
|
||||
void OnAclDataReady(int fd);
|
||||
|
||||
private:
|
||||
int uart_fds_[CH_MAX];
|
||||
|
||||
PacketReadCallback event_cb_;
|
||||
PacketReadCallback acl_cb_;
|
||||
|
||||
hci::HciPacketizer event_packetizer_;
|
||||
hci::HciPacketizer acl_packetizer_;
|
||||
};
|
||||
|
||||
} // namespace hci
|
||||
} // namespace bluetooth
|
||||
} // namespace hardware
|
||||
} // namespace android
|
213
bluetooth/1.0/default/test/h4_protocol_unittest.cc
Normal file
213
bluetooth/1.0/default/test/h4_protocol_unittest.cc
Normal file
|
@ -0,0 +1,213 @@
|
|||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#define LOG_TAG "bt_h4_unittest"
|
||||
|
||||
#include "h4_protocol.h"
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <condition_variable>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <utils/Log.h>
|
||||
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace bluetooth {
|
||||
namespace V1_0 {
|
||||
namespace implementation {
|
||||
|
||||
using ::testing::Eq;
|
||||
using hci::H4Protocol;
|
||||
|
||||
static char sample_data1[100] = "A point is that which has no part.";
|
||||
static char sample_data2[100] = "A line is breadthless length.";
|
||||
static char sample_data3[100] = "The ends of a line are points.";
|
||||
static char acl_data[100] =
|
||||
"A straight line is a line which lies evenly with the points on itself.";
|
||||
static char sco_data[100] =
|
||||
"A surface is that which has length and breadth only.";
|
||||
static char event_data[100] = "The edges of a surface are lines.";
|
||||
|
||||
MATCHER_P3(HidlVecMatches, preamble, preamble_length, payload, "") {
|
||||
size_t length = strlen(payload) + preamble_length;
|
||||
if (length != arg.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (memcmp(preamble, arg.data(), preamble_length) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return memcmp(payload, arg.data() + preamble_length,
|
||||
length - preamble_length) == 0;
|
||||
};
|
||||
|
||||
ACTION_P2(Notify, mutex, condition) {
|
||||
ALOGD("%s", __func__);
|
||||
std::unique_lock<std::mutex> lock(*mutex);
|
||||
condition->notify_one();
|
||||
}
|
||||
|
||||
class H4ProtocolTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
ALOGD("%s", __func__);
|
||||
|
||||
int sockfd[2];
|
||||
socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd);
|
||||
H4Protocol* h4_hci =
|
||||
new H4Protocol(sockfd[0], event_cb_.AsStdFunction(),
|
||||
acl_cb_.AsStdFunction(), sco_cb_.AsStdFunction());
|
||||
fd_watcher_.WatchFdForNonBlockingReads(
|
||||
sockfd[0], [h4_hci](int fd) { h4_hci->OnDataReady(fd); });
|
||||
protocol_ = h4_hci;
|
||||
|
||||
fake_uart_ = sockfd[1];
|
||||
}
|
||||
|
||||
void TearDown() override { fd_watcher_.StopWatchingFileDescriptors(); }
|
||||
|
||||
void SendAndReadUartOutbound(uint8_t type, char* data) {
|
||||
ALOGD("%s sending", __func__);
|
||||
int data_length = strlen(data);
|
||||
protocol_->Send(type, (uint8_t*)data, data_length);
|
||||
|
||||
int uart_length = data_length + 1; // + 1 for data type code
|
||||
int i;
|
||||
|
||||
ALOGD("%s reading", __func__);
|
||||
for (i = 0; i < uart_length; i++) {
|
||||
fd_set read_fds;
|
||||
FD_ZERO(&read_fds);
|
||||
FD_SET(fake_uart_, &read_fds);
|
||||
TEMP_FAILURE_RETRY(select(fake_uart_ + 1, &read_fds, NULL, NULL, NULL));
|
||||
|
||||
char byte;
|
||||
TEMP_FAILURE_RETRY(read(fake_uart_, &byte, 1));
|
||||
|
||||
EXPECT_EQ(i == 0 ? type : data[i - 1], byte);
|
||||
}
|
||||
|
||||
EXPECT_EQ(i, uart_length);
|
||||
}
|
||||
|
||||
void WriteAndExpectInboundAclData(char* payload) {
|
||||
// h4 type[1] + handle[2] + size[2]
|
||||
char preamble[5] = {HCI_PACKET_TYPE_ACL_DATA, 19, 92, 0, 0};
|
||||
int length = strlen(payload);
|
||||
preamble[3] = length & 0xFF;
|
||||
preamble[4] = (length >> 8) & 0xFF;
|
||||
|
||||
ALOGD("%s writing", __func__);
|
||||
TEMP_FAILURE_RETRY(write(fake_uart_, preamble, sizeof(preamble)));
|
||||
TEMP_FAILURE_RETRY(write(fake_uart_, payload, strlen(payload)));
|
||||
|
||||
ALOGD("%s waiting", __func__);
|
||||
std::mutex mutex;
|
||||
std::condition_variable done;
|
||||
EXPECT_CALL(acl_cb_, Call(HidlVecMatches(preamble + 1, sizeof(preamble) - 1,
|
||||
payload)))
|
||||
.WillOnce(Notify(&mutex, &done));
|
||||
|
||||
// Fail if it takes longer than 100 ms.
|
||||
auto timeout_time =
|
||||
std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
done.wait_until(lock, timeout_time);
|
||||
}
|
||||
}
|
||||
|
||||
void WriteAndExpectInboundScoData(char* payload) {
|
||||
// h4 type[1] + handle[2] + size[1]
|
||||
char preamble[4] = {HCI_PACKET_TYPE_SCO_DATA, 20, 17, 0};
|
||||
preamble[3] = strlen(payload) & 0xFF;
|
||||
|
||||
ALOGD("%s writing", __func__);
|
||||
TEMP_FAILURE_RETRY(write(fake_uart_, preamble, sizeof(preamble)));
|
||||
TEMP_FAILURE_RETRY(write(fake_uart_, payload, strlen(payload)));
|
||||
|
||||
ALOGD("%s waiting", __func__);
|
||||
std::mutex mutex;
|
||||
std::condition_variable done;
|
||||
EXPECT_CALL(sco_cb_, Call(HidlVecMatches(preamble + 1, sizeof(preamble) - 1,
|
||||
payload)))
|
||||
.WillOnce(Notify(&mutex, &done));
|
||||
|
||||
// Fail if it takes longer than 100 ms.
|
||||
auto timeout_time =
|
||||
std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
done.wait_until(lock, timeout_time);
|
||||
}
|
||||
}
|
||||
|
||||
void WriteAndExpectInboundEvent(char* payload) {
|
||||
// h4 type[1] + event_code[1] + size[1]
|
||||
char preamble[3] = {HCI_PACKET_TYPE_EVENT, 9, 0};
|
||||
preamble[2] = strlen(payload) & 0xFF;
|
||||
ALOGD("%s writing", __func__);
|
||||
TEMP_FAILURE_RETRY(write(fake_uart_, preamble, sizeof(preamble)));
|
||||
TEMP_FAILURE_RETRY(write(fake_uart_, payload, strlen(payload)));
|
||||
|
||||
ALOGD("%s waiting", __func__);
|
||||
std::mutex mutex;
|
||||
std::condition_variable done;
|
||||
EXPECT_CALL(event_cb_, Call(HidlVecMatches(preamble + 1,
|
||||
sizeof(preamble) - 1, payload)))
|
||||
.WillOnce(Notify(&mutex, &done));
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
done.wait(lock);
|
||||
}
|
||||
}
|
||||
|
||||
testing::MockFunction<void(const hidl_vec<uint8_t>&)> event_cb_;
|
||||
testing::MockFunction<void(const hidl_vec<uint8_t>&)> acl_cb_;
|
||||
testing::MockFunction<void(const hidl_vec<uint8_t>&)> sco_cb_;
|
||||
async::AsyncFdWatcher fd_watcher_;
|
||||
H4Protocol* protocol_;
|
||||
int fake_uart_;
|
||||
};
|
||||
|
||||
// Test sending data sends correct data onto the UART
|
||||
TEST_F(H4ProtocolTest, TestSends) {
|
||||
SendAndReadUartOutbound(HCI_PACKET_TYPE_COMMAND, sample_data1);
|
||||
SendAndReadUartOutbound(HCI_PACKET_TYPE_ACL_DATA, sample_data2);
|
||||
SendAndReadUartOutbound(HCI_PACKET_TYPE_SCO_DATA, sample_data3);
|
||||
}
|
||||
|
||||
// Ensure we properly parse data coming from the UART
|
||||
TEST_F(H4ProtocolTest, TestReads) {
|
||||
WriteAndExpectInboundAclData(acl_data);
|
||||
WriteAndExpectInboundScoData(sco_data);
|
||||
WriteAndExpectInboundEvent(event_data);
|
||||
}
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace V1_0
|
||||
} // namespace bluetooth
|
||||
} // namespace hardware
|
||||
} // namespace android
|
200
bluetooth/1.0/default/test/mct_protocol_unittest.cc
Normal file
200
bluetooth/1.0/default/test/mct_protocol_unittest.cc
Normal file
|
@ -0,0 +1,200 @@
|
|||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#define LOG_TAG "bt_h4_unittest"
|
||||
|
||||
#include "mct_protocol.h"
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <condition_variable>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <utils/Log.h>
|
||||
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace bluetooth {
|
||||
namespace V1_0 {
|
||||
namespace implementation {
|
||||
|
||||
using ::testing::Eq;
|
||||
using hci::MctProtocol;
|
||||
|
||||
static char sample_data1[100] = "A point is that which has no part.";
|
||||
static char sample_data2[100] = "A line is breadthless length.";
|
||||
static char sample_data3[100] = "The ends of a line are points.";
|
||||
static char acl_data[100] =
|
||||
"A straight line is a line which lies evenly with the points on itself.";
|
||||
static char sco_data[100] =
|
||||
"A surface is that which has length and breadth only.";
|
||||
static char event_data[100] = "The edges of a surface are lines.";
|
||||
|
||||
MATCHER_P3(HidlVecMatches, preamble, preamble_length, payload, "") {
|
||||
size_t length = strlen(payload) + preamble_length;
|
||||
if (length != arg.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (memcmp(preamble, arg.data(), preamble_length) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return memcmp(payload, arg.data() + preamble_length,
|
||||
length - preamble_length) == 0;
|
||||
};
|
||||
|
||||
ACTION_P2(Notify, mutex, condition) {
|
||||
ALOGD("%s", __func__);
|
||||
std::unique_lock<std::mutex> lock(*mutex);
|
||||
condition->notify_one();
|
||||
}
|
||||
|
||||
class MctProtocolTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
ALOGD("%s", __func__);
|
||||
|
||||
int mct_fds[CH_MAX];
|
||||
MakeFakeUartFd(CH_CMD, mct_fds, fake_uart_);
|
||||
MakeFakeUartFd(CH_EVT, mct_fds, fake_uart_);
|
||||
MakeFakeUartFd(CH_ACL_IN, mct_fds, fake_uart_);
|
||||
MakeFakeUartFd(CH_ACL_OUT, mct_fds, fake_uart_);
|
||||
|
||||
MctProtocol* mct_hci = new MctProtocol(mct_fds, event_cb_.AsStdFunction(),
|
||||
acl_cb_.AsStdFunction());
|
||||
fd_watcher_.WatchFdForNonBlockingReads(
|
||||
mct_fds[CH_EVT], [mct_hci](int fd) { mct_hci->OnEventDataReady(fd); });
|
||||
fd_watcher_.WatchFdForNonBlockingReads(
|
||||
mct_fds[CH_ACL_IN], [mct_hci](int fd) { mct_hci->OnAclDataReady(fd); });
|
||||
protocol_ = mct_hci;
|
||||
}
|
||||
|
||||
void MakeFakeUartFd(int index, int* host_side, int* controller_side) {
|
||||
int sockfd[2];
|
||||
socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd);
|
||||
host_side[index] = sockfd[0];
|
||||
controller_side[index] = sockfd[1];
|
||||
}
|
||||
|
||||
void TearDown() override { fd_watcher_.StopWatchingFileDescriptors(); }
|
||||
|
||||
void SendAndReadUartOutbound(uint8_t type, char* data, int outbound_fd) {
|
||||
ALOGD("%s sending", __func__);
|
||||
int data_length = strlen(data);
|
||||
protocol_->Send(type, (uint8_t*)data, data_length);
|
||||
|
||||
ALOGD("%s reading", __func__);
|
||||
int i;
|
||||
for (i = 0; i < data_length; i++) {
|
||||
fd_set read_fds;
|
||||
FD_ZERO(&read_fds);
|
||||
FD_SET(outbound_fd, &read_fds);
|
||||
TEMP_FAILURE_RETRY(select(outbound_fd + 1, &read_fds, NULL, NULL, NULL));
|
||||
|
||||
char byte;
|
||||
TEMP_FAILURE_RETRY(read(outbound_fd, &byte, 1));
|
||||
|
||||
EXPECT_EQ(data[i], byte);
|
||||
}
|
||||
|
||||
EXPECT_EQ(i, data_length);
|
||||
}
|
||||
|
||||
void WriteAndExpectInboundAclData(char* payload) {
|
||||
// handle[2] + size[2]
|
||||
char preamble[4] = {19, 92, 0, 0};
|
||||
int length = strlen(payload);
|
||||
preamble[2] = length & 0xFF;
|
||||
preamble[3] = (length >> 8) & 0xFF;
|
||||
|
||||
ALOGD("%s writing", __func__);
|
||||
TEMP_FAILURE_RETRY(
|
||||
write(fake_uart_[CH_ACL_IN], preamble, sizeof(preamble)));
|
||||
TEMP_FAILURE_RETRY(write(fake_uart_[CH_ACL_IN], payload, strlen(payload)));
|
||||
|
||||
ALOGD("%s waiting", __func__);
|
||||
std::mutex mutex;
|
||||
std::condition_variable done;
|
||||
EXPECT_CALL(acl_cb_,
|
||||
Call(HidlVecMatches(preamble, sizeof(preamble), payload)))
|
||||
.WillOnce(Notify(&mutex, &done));
|
||||
|
||||
// Fail if it takes longer than 100 ms.
|
||||
auto timeout_time =
|
||||
std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
done.wait_until(lock, timeout_time);
|
||||
}
|
||||
}
|
||||
|
||||
void WriteAndExpectInboundEvent(char* payload) {
|
||||
// event_code[1] + size[1]
|
||||
char preamble[2] = {9, 0};
|
||||
preamble[1] = strlen(payload) & 0xFF;
|
||||
|
||||
ALOGD("%s writing", __func__);
|
||||
TEMP_FAILURE_RETRY(write(fake_uart_[CH_EVT], preamble, sizeof(preamble)));
|
||||
TEMP_FAILURE_RETRY(write(fake_uart_[CH_EVT], payload, strlen(payload)));
|
||||
|
||||
ALOGD("%s waiting", __func__);
|
||||
std::mutex mutex;
|
||||
std::condition_variable done;
|
||||
EXPECT_CALL(event_cb_,
|
||||
Call(HidlVecMatches(preamble, sizeof(preamble), payload)))
|
||||
.WillOnce(Notify(&mutex, &done));
|
||||
|
||||
// Fail if it takes longer than 100 ms.
|
||||
auto timeout_time =
|
||||
std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
done.wait_until(lock, timeout_time);
|
||||
}
|
||||
}
|
||||
|
||||
testing::MockFunction<void(const hidl_vec<uint8_t>&)> event_cb_;
|
||||
testing::MockFunction<void(const hidl_vec<uint8_t>&)> acl_cb_;
|
||||
async::AsyncFdWatcher fd_watcher_;
|
||||
MctProtocol* protocol_;
|
||||
int fake_uart_[CH_MAX];
|
||||
};
|
||||
|
||||
// Test sending data sends correct data onto the UART
|
||||
TEST_F(MctProtocolTest, TestSends) {
|
||||
SendAndReadUartOutbound(HCI_PACKET_TYPE_COMMAND, sample_data1,
|
||||
fake_uart_[CH_CMD]);
|
||||
SendAndReadUartOutbound(HCI_PACKET_TYPE_ACL_DATA, sample_data2,
|
||||
fake_uart_[CH_ACL_OUT]);
|
||||
}
|
||||
|
||||
// Ensure we properly parse data coming from the UART
|
||||
TEST_F(MctProtocolTest, TestReads) {
|
||||
WriteAndExpectInboundAclData(acl_data);
|
||||
WriteAndExpectInboundEvent(event_data);
|
||||
}
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace V1_0
|
||||
} // namespace bluetooth
|
||||
} // namespace hardware
|
||||
} // namespace android
|
|
@ -27,6 +27,8 @@
|
|||
#include <fcntl.h>
|
||||
|
||||
#include "bluetooth_address.h"
|
||||
#include "h4_protocol.h"
|
||||
#include "mct_protocol.h"
|
||||
|
||||
static const char* VENDOR_LIBRARY_NAME = "libbt-vendor.so";
|
||||
static const char* VENDOR_LIBRARY_SYMBOL_NAME =
|
||||
|
@ -64,30 +66,6 @@ HC_BT_HDR* WrapPacketAndCopy(uint16_t event, const hidl_vec<uint8_t>& data) {
|
|||
return packet;
|
||||
}
|
||||
|
||||
size_t write_safely(int fd, const uint8_t* data, size_t length) {
|
||||
size_t transmitted_length = 0;
|
||||
while (length > 0) {
|
||||
ssize_t ret =
|
||||
TEMP_FAILURE_RETRY(write(fd, data + transmitted_length, length));
|
||||
|
||||
if (ret == -1) {
|
||||
if (errno == EAGAIN) continue;
|
||||
ALOGE("%s error writing to UART (%s)", __func__, strerror(errno));
|
||||
break;
|
||||
|
||||
} else if (ret == 0) {
|
||||
// Nothing written :(
|
||||
ALOGE("%s zero bytes written - something went wrong...", __func__);
|
||||
break;
|
||||
}
|
||||
|
||||
transmitted_length += ret;
|
||||
length -= ret;
|
||||
}
|
||||
|
||||
return transmitted_length;
|
||||
}
|
||||
|
||||
bool internal_command_event_match(const hidl_vec<uint8_t>& packet) {
|
||||
uint8_t event_code = packet[0];
|
||||
if (event_code != HCI_COMMAND_COMPLETE_EVENT) {
|
||||
|
@ -185,10 +163,12 @@ class FirmwareStartupTimer {
|
|||
|
||||
bool VendorInterface::Initialize(
|
||||
InitializeCompleteCallback initialize_complete_cb,
|
||||
PacketReadCallback packet_read_cb) {
|
||||
PacketReadCallback event_cb, PacketReadCallback acl_cb,
|
||||
PacketReadCallback sco_cb) {
|
||||
assert(!g_vendor_interface);
|
||||
g_vendor_interface = new VendorInterface();
|
||||
return g_vendor_interface->Open(initialize_complete_cb, packet_read_cb);
|
||||
return g_vendor_interface->Open(initialize_complete_cb, event_cb, acl_cb,
|
||||
sco_cb);
|
||||
}
|
||||
|
||||
void VendorInterface::Shutdown() {
|
||||
|
@ -201,9 +181,10 @@ void VendorInterface::Shutdown() {
|
|||
VendorInterface* VendorInterface::get() { return g_vendor_interface; }
|
||||
|
||||
bool VendorInterface::Open(InitializeCompleteCallback initialize_complete_cb,
|
||||
PacketReadCallback packet_read_cb) {
|
||||
PacketReadCallback event_cb,
|
||||
PacketReadCallback acl_cb,
|
||||
PacketReadCallback sco_cb) {
|
||||
initialize_complete_cb_ = initialize_complete_cb;
|
||||
packet_read_cb_ = packet_read_cb;
|
||||
|
||||
// Initialize vendor interface
|
||||
|
||||
|
@ -241,28 +222,41 @@ bool VendorInterface::Open(InitializeCompleteCallback initialize_complete_cb,
|
|||
power_state = BT_VND_PWR_ON;
|
||||
lib_interface_->op(BT_VND_OP_POWER_CTRL, &power_state);
|
||||
|
||||
// Get the UART socket
|
||||
// Get the UART socket(s)
|
||||
|
||||
int fd_list[CH_MAX] = {0};
|
||||
int fd_count = lib_interface_->op(BT_VND_OP_USERIAL_OPEN, &fd_list);
|
||||
|
||||
if (fd_count != 1) {
|
||||
ALOGE("%s fd count %d != 1; we can't handle this currently...", __func__,
|
||||
fd_count);
|
||||
return false;
|
||||
for (int i = 0; i < fd_count; i++) {
|
||||
if (fd_list[i] == INVALID_FD) {
|
||||
ALOGE("%s: fd %d is invalid!", __func__, fd_list[i]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uart_fd_ = fd_list[0];
|
||||
if (uart_fd_ == INVALID_FD) {
|
||||
ALOGE("%s unable to determine UART fd", __func__);
|
||||
return false;
|
||||
event_cb_ = event_cb;
|
||||
PacketReadCallback intercept_events = [this](const hidl_vec<uint8_t>& event) {
|
||||
HandleIncomingEvent(event);
|
||||
};
|
||||
|
||||
if (fd_count == 1) {
|
||||
hci::H4Protocol* h4_hci =
|
||||
new hci::H4Protocol(fd_list[0], intercept_events, acl_cb, sco_cb);
|
||||
fd_watcher_.WatchFdForNonBlockingReads(
|
||||
fd_list[0], [h4_hci](int fd) { h4_hci->OnDataReady(fd); });
|
||||
hci_ = h4_hci;
|
||||
} else {
|
||||
hci::MctProtocol* mct_hci =
|
||||
new hci::MctProtocol(fd_list, intercept_events, acl_cb);
|
||||
fd_watcher_.WatchFdForNonBlockingReads(
|
||||
fd_list[CH_EVT], [mct_hci](int fd) { mct_hci->OnEventDataReady(fd); });
|
||||
if (fd_count >= CH_ACL_IN)
|
||||
fd_watcher_.WatchFdForNonBlockingReads(
|
||||
fd_list[CH_ACL_IN],
|
||||
[mct_hci](int fd) { mct_hci->OnAclDataReady(fd); });
|
||||
hci_ = mct_hci;
|
||||
}
|
||||
|
||||
ALOGI("%s UART fd: %d", __func__, uart_fd_);
|
||||
|
||||
fd_watcher_.WatchFdForNonBlockingReads(uart_fd_,
|
||||
[this](int fd) { hci_packetizer_.OnDataReady(fd); });
|
||||
|
||||
// Initially, the power management is off.
|
||||
lpm_wake_deasserted = true;
|
||||
|
||||
|
@ -276,12 +270,16 @@ bool VendorInterface::Open(InitializeCompleteCallback initialize_complete_cb,
|
|||
void VendorInterface::Close() {
|
||||
fd_watcher_.StopWatchingFileDescriptors();
|
||||
|
||||
if (hci_ != nullptr) {
|
||||
delete hci_;
|
||||
hci_ = nullptr;
|
||||
}
|
||||
|
||||
if (lib_interface_ != nullptr) {
|
||||
bt_vendor_lpm_mode_t mode = BT_VND_LPM_DISABLE;
|
||||
lib_interface_->op(BT_VND_OP_LPM_SET_MODE, &mode);
|
||||
|
||||
lib_interface_->op(BT_VND_OP_USERIAL_CLOSE, nullptr);
|
||||
uart_fd_ = INVALID_FD;
|
||||
int power_state = BT_VND_PWR_OFF;
|
||||
lib_interface_->op(BT_VND_OP_POWER_CTRL, &power_state);
|
||||
}
|
||||
|
@ -298,8 +296,6 @@ void VendorInterface::Close() {
|
|||
}
|
||||
|
||||
size_t VendorInterface::Send(uint8_t type, const uint8_t* data, size_t length) {
|
||||
if (uart_fd_ == INVALID_FD) return 0;
|
||||
|
||||
recent_activity_flag = true;
|
||||
|
||||
if (lpm_wake_deasserted == true) {
|
||||
|
@ -313,11 +309,7 @@ size_t VendorInterface::Send(uint8_t type, const uint8_t* data, size_t length) {
|
|||
ALOGV("%s: Sent wake before (%02x)", __func__, data[0] | (data[1] << 8));
|
||||
}
|
||||
|
||||
int rv = write_safely(uart_fd_, &type, sizeof(type));
|
||||
if (rv == sizeof(type))
|
||||
rv = write_safely(uart_fd_, data, length);
|
||||
|
||||
return rv;
|
||||
return hci_->Send(type, data, length);
|
||||
}
|
||||
|
||||
void VendorInterface::OnFirmwareConfigured(uint8_t result) {
|
||||
|
@ -357,26 +349,18 @@ void VendorInterface::OnTimeout() {
|
|||
recent_activity_flag = false;
|
||||
}
|
||||
|
||||
void VendorInterface::OnPacketReady() {
|
||||
VendorInterface::get()->HandleIncomingPacket();
|
||||
}
|
||||
void VendorInterface::HandleIncomingEvent(const hidl_vec<uint8_t>& hci_packet) {
|
||||
if (internal_command.cb != nullptr &&
|
||||
internal_command_event_match(hci_packet)) {
|
||||
HC_BT_HDR* bt_hdr = WrapPacketAndCopy(HCI_PACKET_TYPE_EVENT, hci_packet);
|
||||
|
||||
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)) {
|
||||
HC_BT_HDR* bt_hdr =
|
||||
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);
|
||||
}
|
||||
// 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 {
|
||||
event_cb_(hci_packet);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace implementation
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
#include "async_fd_watcher.h"
|
||||
#include "bt_vendor_lib.h"
|
||||
#include "hci_packetizer.h"
|
||||
#include "hci_protocol.h"
|
||||
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
|
@ -30,15 +30,15 @@ namespace implementation {
|
|||
|
||||
using ::android::hardware::hidl_vec;
|
||||
using InitializeCompleteCallback = std::function<void(bool success)>;
|
||||
using PacketReadCallback =
|
||||
std::function<void(HciPacketType, const hidl_vec<uint8_t> &)>;
|
||||
using PacketReadCallback = std::function<void(const hidl_vec<uint8_t>&)>;
|
||||
|
||||
class FirmwareStartupTimer;
|
||||
|
||||
class VendorInterface {
|
||||
public:
|
||||
static bool Initialize(InitializeCompleteCallback initialize_complete_cb,
|
||||
PacketReadCallback packet_read_cb);
|
||||
PacketReadCallback event_cb, PacketReadCallback acl_cb,
|
||||
PacketReadCallback sco_cb);
|
||||
static void Shutdown();
|
||||
static VendorInterface *get();
|
||||
|
||||
|
@ -46,27 +46,25 @@ class VendorInterface {
|
|||
|
||||
void OnFirmwareConfigured(uint8_t result);
|
||||
|
||||
static void OnPacketReady();
|
||||
|
||||
private:
|
||||
virtual ~VendorInterface() = default;
|
||||
|
||||
bool Open(InitializeCompleteCallback initialize_complete_cb,
|
||||
PacketReadCallback packet_read_cb);
|
||||
PacketReadCallback event_cb, PacketReadCallback acl_cb,
|
||||
PacketReadCallback sco_cb);
|
||||
void Close();
|
||||
|
||||
void OnTimeout();
|
||||
|
||||
void HandleIncomingPacket();
|
||||
void HandleIncomingEvent(const hidl_vec<uint8_t>& hci_packet);
|
||||
|
||||
void *lib_handle_;
|
||||
bt_vendor_interface_t *lib_interface_;
|
||||
async::AsyncFdWatcher fd_watcher_;
|
||||
int uart_fd_;
|
||||
PacketReadCallback packet_read_cb_;
|
||||
InitializeCompleteCallback initialize_complete_cb_;
|
||||
hci::HciProtocol* hci_;
|
||||
|
||||
hci::HciPacketizer hci_packetizer_ {VendorInterface::OnPacketReady};
|
||||
PacketReadCallback event_cb_;
|
||||
|
||||
FirmwareStartupTimer *firmware_startup_timer_;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue