1//
2// Copyright 2015 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#define LOG_TAG "hci_transport"
18
19#include "vendor_libs/test_vendor_lib/include/hci_transport.h"
20
21#include "base/logging.h"
22#include "base/bind.h"
23#include "base/thread_task_runner_handle.h"
24
25extern "C" {
26#include <sys/socket.h>
27
28#include "stack/include/hcidefs.h"
29#include "osi/include/log.h"
30}  // extern "C"
31
32namespace test_vendor_lib {
33
34HciTransport::HciTransport() : weak_ptr_factory_(this) {}
35
36void HciTransport::CloseHciFd() {
37  hci_fd_.reset(nullptr);
38}
39
40void HciTransport::CloseVendorFd() {
41  vendor_fd_.reset(nullptr);
42}
43
44int HciTransport::GetHciFd() const {
45  return hci_fd_->get();
46}
47
48int HciTransport::GetVendorFd() const {
49  return vendor_fd_->get();
50}
51
52bool HciTransport::SetUp() {
53  int socketpair_fds[2];
54  // TODO(dennischeng): Use SOCK_SEQPACKET here.
55  const int success = socketpair(AF_LOCAL, SOCK_STREAM, 0, socketpair_fds);
56  if (success < 0)
57    return false;
58  hci_fd_.reset(new base::ScopedFD(socketpair_fds[0]));
59  vendor_fd_.reset(new base::ScopedFD(socketpair_fds[1]));
60  return true;
61}
62
63void HciTransport::OnFileCanReadWithoutBlocking(int fd) {
64  CHECK(fd == GetVendorFd());
65  LOG_INFO(LOG_TAG, "Event ready in HciTransport on fd: %d.", fd);
66
67  const serial_data_type_t packet_type = packet_stream_.ReceivePacketType(fd);
68  switch (packet_type) {
69    case (DATA_TYPE_COMMAND): {
70      ReceiveReadyCommand();
71      break;
72    }
73
74    case (DATA_TYPE_ACL): {
75      LOG_INFO(LOG_TAG, "ACL data packets not currently supported.");
76      break;
77    }
78
79    case (DATA_TYPE_SCO): {
80      LOG_INFO(LOG_TAG, "SCO data packets not currently supported.");
81      break;
82    }
83
84    // TODO(dennischeng): Add debug level assert here.
85    default: {
86      LOG_INFO(LOG_TAG, "Error received an invalid packet type from the HCI.");
87      break;
88    }
89  }
90}
91
92void HciTransport::ReceiveReadyCommand() const {
93  std::unique_ptr<CommandPacket> command =
94      packet_stream_.ReceiveCommand(GetVendorFd());
95  LOG_INFO(LOG_TAG, "Received command packet.");
96  command_handler_(std::move(command));
97}
98
99void HciTransport::RegisterCommandHandler(
100    std::function<void(std::unique_ptr<CommandPacket>)> callback) {
101  command_handler_ = callback;
102}
103
104void HciTransport::OnFileCanWriteWithoutBlocking(int fd) {
105  CHECK(fd == GetVendorFd());
106  if (!outbound_events_.empty()) {
107    base::TimeTicks current_time = base::TimeTicks::Now();
108    auto it = outbound_events_.begin();
109    // Check outbound events for events that can be sent, i.e. events with a
110    // timestamp before the current time. Stop sending events when
111    // |packet_stream_| fails writing.
112    for (auto it = outbound_events_.begin(); it != outbound_events_.end();) {
113      if ((*it)->GetTimeStamp() > current_time) {
114        ++it;
115        continue;
116      }
117      if (!packet_stream_.SendEvent((*it)->GetEvent(), fd))
118        return;
119      it = outbound_events_.erase(it);
120    }
121  }
122}
123
124void HciTransport::AddEventToOutboundEvents(
125    std::unique_ptr<TimeStampedEvent> event) {
126  outbound_events_.push_back(std::move(event));
127}
128
129void HciTransport::PostEventResponse(std::unique_ptr<EventPacket> event) {
130  AddEventToOutboundEvents(
131      std::make_unique<TimeStampedEvent>(std::move(event)));
132}
133
134void HciTransport::PostDelayedEventResponse(std::unique_ptr<EventPacket> event,
135                                            base::TimeDelta delay) {
136  // TODO(dennischeng): When it becomes available for MessageLoopForIO, use the
137  // thread's task runner to post |PostEventResponse| as a delayed task, being
138  // sure to CHECK the appropriate task runner attributes using
139  // base::ThreadTaskRunnerHandle.
140
141  // The system does not support high resolution timing and the clock could be
142  // as coarse as ~15.6 ms so the event is sent without a delay to avoid
143  // inconsistent event responses.
144  if (!base::TimeTicks::IsHighResolution()) {
145    LOG_INFO(LOG_TAG,
146              "System does not support high resolution timing. Sending event "
147              "without delay.");
148    PostEventResponse(std::move(event));
149  }
150
151  LOG_INFO(LOG_TAG, "Posting event response with delay of %lld ms.",
152           delay.InMilliseconds());
153
154  AddEventToOutboundEvents(
155      std::make_unique<TimeStampedEvent>(std::move(event), delay));
156}
157
158HciTransport::TimeStampedEvent::TimeStampedEvent(
159    std::unique_ptr<EventPacket> event, base::TimeDelta delay)
160    : event_(std::move(event)), time_stamp_(base::TimeTicks::Now() + delay) {}
161
162HciTransport::TimeStampedEvent::TimeStampedEvent(
163    std::unique_ptr<EventPacket> event)
164    : event_(std::move(event)), time_stamp_(base::TimeTicks::UnixEpoch()) {}
165
166const base::TimeTicks& HciTransport::TimeStampedEvent::GetTimeStamp() const {
167  return time_stamp_;
168}
169
170const EventPacket& HciTransport::TimeStampedEvent::GetEvent() {
171  return *(event_.get());
172}
173
174}  // namespace test_vendor_lib
175