OSDN Git Service

test_vendor_lib: Initial commit
[android-x86/system-bt.git] / vendor_libs / test_vendor_lib / src / hci_transport.cc
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 extern "C" {
22 #include "stack/include/hcidefs.h"
23 #include "osi/include/log.h"
24
25 #include <sys/ioctl.h>
26 #include <sys/socket.h>
27 #include <sys/un.h>
28 #include <assert.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31 }  // extern "C"
32
33 namespace {
34 // The maximum number of events in the epoll event buffer.
35 const int kMaxEpollEvents = 10;
36 }  // namespace
37
38 namespace test_vendor_lib {
39
40 // Global HciTransport instance used in the vendor library.
41 // TODO(dennischeng): Should this be moved to an unnamed namespace?
42 HciTransport* g_transporter = nullptr;
43
44 HciTransport::HciTransport() : epoll_fd_(-1), connected_(false) {}
45
46 HciTransport::~HciTransport() {
47   close(epoll_fd_);
48 }
49
50 bool HciTransport::ConfigEpoll() {
51   epoll_fd_ = epoll_create1(EPOLL_CLOEXEC);
52   epoll_event event;
53   event.events = EPOLLIN;
54   event.data.fd = socketpair_fds_[0];
55   return epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, socketpair_fds_[0], &event) >= 0;
56 }
57
58 int HciTransport::GetHciFd() const {
59   return socketpair_fds_[1];
60 }
61
62 // static
63 HciTransport* HciTransport::Get() {
64   // Initialize should have been called already.
65   // TODO(dennischeng): use CHECK and DCHECK when libbase is imported.
66   assert(g_transporter);
67   return g_transporter;
68 }
69
70 // static
71 void HciTransport::Initialize() {
72   // Multiple calls to Initialize should not be made.
73   // TODO(dennischeng): use CHECK and DCHECK when libbase is imported.
74   assert(!g_transporter);
75   g_transporter = new HciTransport();
76 }
77
78 // static
79 void HciTransport::CleanUp() {
80   delete g_transporter;
81   g_transporter = nullptr;
82 }
83
84 bool HciTransport::Connect() {
85   if (connected_) {
86     LOG_ERROR(LOG_TAG, "Error: transporter is already connected.");
87     return false;
88   }
89
90   // TODO(dennischeng): Use SOCK_SEQPACKET here.
91   if (socketpair(AF_LOCAL, SOCK_STREAM, 0, socketpair_fds_) < 0) {
92     LOG_ERROR(LOG_TAG, "Error: creating socketpair in HciTransport.");
93     return false;
94   }
95
96   // Set the descriptor for the packet stream object. |packet_stream_| will take
97   // ownership of the descriptor.
98   packet_stream_.SetFd(socketpair_fds_[0]);
99
100   // Initialize epoll instance and set the file descriptor to listen on.
101   if (ConfigEpoll() < 0) {
102     LOG_ERROR(LOG_TAG, "Error: registering hci listener with epoll instance.");
103     return false;
104   }
105
106   connected_ = true;
107   return true;
108 }
109
110 bool HciTransport::Listen() {
111   epoll_event event_buffer[kMaxEpollEvents];
112   int num_ready;
113
114   // Check for ready events.
115   if ((num_ready = epoll_wait(epoll_fd_, event_buffer, kMaxEpollEvents, -1)) <
116       0) {
117      LOG_ERROR(LOG_TAG, "Error: epoll wait.");
118      return false;
119   }
120
121   return ReceiveReadyPackets(*event_buffer, num_ready);
122 }
123
124 bool HciTransport::ReceiveReadyPackets(const epoll_event& event_buffer,
125                                        int num_ready) {
126   for (int i = 0; i < num_ready; ++i) {
127     // Event has data ready to be read.
128     if ((&event_buffer)[i].events & EPOLLIN) {
129       LOG_INFO(LOG_TAG, "Event ready in HciTransport.");
130       serial_data_type_t packet_type = packet_stream_.ReceivePacketType();
131
132       switch (packet_type) {
133         case (DATA_TYPE_COMMAND): {
134           ReceiveReadyCommand();
135           return true;
136         }
137
138         case (DATA_TYPE_ACL): {
139           LOG_INFO(LOG_TAG, "ACL data packets not currently supported.");
140           return true;
141         }
142
143         case (DATA_TYPE_SCO): {
144           LOG_INFO(LOG_TAG, "SCO data packets not currently supported.");
145           return true;
146         }
147
148         // TODO(dennischeng): Add debug level assert here.
149         default: {
150           LOG_INFO(LOG_TAG,
151                    "Error received an invalid packet type from the HCI.");
152           return false;
153         }
154       }
155     }
156   }
157   return false;
158 }
159
160 void HciTransport::ReceiveReadyCommand() {
161   std::unique_ptr<CommandPacket> command =
162       packet_stream_.ReceiveCommand();
163   command_callback_(std::move(command));
164 }
165
166 void HciTransport::RegisterCommandCallback(
167     std::function<void(std::unique_ptr<CommandPacket>)> callback) {
168   command_callback_ = callback;
169 }
170
171 void HciTransport::SendEvent(const EventPacket& event) {
172   packet_stream_.SendEvent(event);
173 }
174
175 }  // namespace test_vendor_lib