blob: 86e12d19b134edb1062f05dcb0c39511d4c84872 [file] [log] [blame]
Tomasz Wasilczyk87329672019-07-12 11:43:00 -07001/*
2 * Copyright (C) 2019 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#include "CanSocket.h"
18
19#include <android-base/logging.h>
20#include <libnetdevice/can.h>
21#include <libnetdevice/libnetdevice.h>
22#include <linux/can.h>
23#include <utils/SystemClock.h>
24
25#include <chrono>
26
27namespace android {
28namespace hardware {
29namespace automotive {
30namespace can {
31namespace V1_0 {
32namespace implementation {
33
34using namespace std::chrono_literals;
35
chrisweircf36cea2019-11-08 16:41:02 -080036/* How frequently the read thread checks whether the interface was asked to be down.
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070037 *
38 * Note: This does *not* affect read timing or bandwidth, just CPU load vs time to
chrisweircf36cea2019-11-08 16:41:02 -080039 * down the interface. */
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070040static constexpr auto kReadPooling = 100ms;
41
42std::unique_ptr<CanSocket> CanSocket::open(const std::string& ifname, ReadCallback rdcb,
43 ErrorCallback errcb) {
44 auto sock = netdevice::can::socket(ifname);
45 if (!sock.ok()) {
46 LOG(ERROR) << "Can't open CAN socket on " << ifname;
47 return nullptr;
48 }
49
50 // Can't use std::make_unique due to private CanSocket constructor.
51 return std::unique_ptr<CanSocket>(new CanSocket(std::move(sock), rdcb, errcb));
52}
53
54CanSocket::CanSocket(base::unique_fd socket, ReadCallback rdcb, ErrorCallback errcb)
55 : mReadCallback(rdcb),
56 mErrorCallback(errcb),
57 mSocket(std::move(socket)),
58 mReaderThread(&CanSocket::readerThread, this) {}
59
60CanSocket::~CanSocket() {
61 mStopReaderThread = true;
Tomasz Wasilczyka9061962019-11-04 12:53:09 -080062
63 /* CanSocket can be brought down as a result of read failure, from the same thread,
64 * so let's just detach and let it finish on its own. */
65 if (mReaderThreadFinished) {
66 mReaderThread.detach();
67 } else {
68 mReaderThread.join();
69 }
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070070}
71
72bool CanSocket::send(const struct canfd_frame& frame) {
73 const auto res = write(mSocket.get(), &frame, CAN_MTU);
74 if (res < 0) {
75 LOG(DEBUG) << "CanSocket send failed: " << errno;
76 return false;
77 }
78 if (res != CAN_MTU) {
79 LOG(DEBUG) << "CanSocket sent wrong number of bytes: " << res;
80 return false;
81 }
82 return true;
83}
84
85static struct timeval toTimeval(std::chrono::microseconds t) {
86 struct timeval tv;
87 tv.tv_sec = t / 1s;
88 tv.tv_usec = (t % 1s) / 1us;
89 return tv;
90}
91
92static int selectRead(const base::unique_fd& fd, std::chrono::microseconds timeout) {
93 auto timeouttv = toTimeval(timeout);
94 fd_set readfds;
95 FD_ZERO(&readfds);
96 FD_SET(fd.get(), &readfds);
97 return select(fd.get() + 1, &readfds, nullptr, nullptr, &timeouttv);
98}
99
100void CanSocket::readerThread() {
101 LOG(VERBOSE) << "Reader thread started";
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800102 int errnoCopy = 0;
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700103
104 while (!mStopReaderThread) {
105 /* The ideal would be to have a blocking read(3) call and interrupt it with shutdown(3).
chrisweircf36cea2019-11-08 16:41:02 -0800106 * This is unfortunately not supported for SocketCAN, so we need to rely on select(3). */
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700107 const auto sel = selectRead(mSocket, kReadPooling);
108 if (sel == 0) continue; // timeout
109 if (sel == -1) {
110 LOG(ERROR) << "Select failed: " << errno;
111 break;
112 }
113
114 struct canfd_frame frame;
115 const auto nbytes = read(mSocket.get(), &frame, CAN_MTU);
116
117 /* We could use SIOCGSTAMP to get a precise UNIX timestamp for a given packet, but what
118 * we really need is a time since boot. There is no direct way to convert between these
119 * clocks. We could implement a class to calculate the difference between the clocks
120 * (querying both several times and picking the smallest difference); apply the difference
121 * to a SIOCGSTAMP returned value; re-synchronize if the elapsed time is too much in the
122 * past (indicating the UNIX timestamp might have been adjusted).
123 *
124 * Apart from the added complexity, it's possible the added calculations and system calls
125 * would add so much time to the processing pipeline so the precision of the reported time
126 * was buried under the subsystem latency. Let's just use a local time since boot here and
chrisweircf36cea2019-11-08 16:41:02 -0800127 * leave precise hardware timestamps for custom proprietary implementations (if needed). */
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700128 const std::chrono::nanoseconds ts(elapsedRealtimeNano());
129
130 if (nbytes != CAN_MTU) {
131 if (nbytes >= 0) {
132 LOG(ERROR) << "Failed to read CAN packet, got " << nbytes << " bytes";
133 break;
134 }
135 if (errno == EAGAIN) continue;
136
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800137 errnoCopy = errno;
138 LOG(ERROR) << "Failed to read CAN packet: " << strerror(errno) << " (" << errno << ")";
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700139 break;
140 }
141
142 mReadCallback(frame, ts);
143 }
144
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800145 bool failed = !mStopReaderThread;
146 auto errCb = mErrorCallback;
147 mReaderThreadFinished = true;
148
149 // Don't access any fields from here, see CanSocket::~CanSocket comment about detached thread
150 if (failed) errCb(errnoCopy);
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700151
152 LOG(VERBOSE) << "Reader thread stopped";
153}
154
155} // namespace implementation
156} // namespace V1_0
157} // namespace can
158} // namespace automotive
159} // namespace hardware
160} // namespace android