libuav original
Dependents: UAVCAN UAVCAN_Subscriber
socketcan.hpp
00001 /* 00002 * Copyright (C) 2014-2015 Pavel Kirienko <pavel.kirienko@gmail.com> 00003 * Ilia Sheremet <illia.sheremet@gmail.com> 00004 */ 00005 00006 #pragma once 00007 00008 #include <cassert> 00009 #include <cstdint> 00010 #include <queue> 00011 #include <vector> 00012 #include <map> 00013 #include <unordered_set> 00014 #include <memory> 00015 #include <algorithm> 00016 00017 #include <fcntl.h> 00018 #include <sys/socket.h> 00019 #include <sys/ioctl.h> 00020 #include <net/if.h> 00021 #include <linux/can.h> 00022 #include <linux/can/raw.h> 00023 #include <poll.h> 00024 00025 #include <uavcan/uavcan.hpp> 00026 #include <uavcan_linux/clock.hpp> 00027 #include <uavcan_linux/exception.hpp> 00028 00029 00030 namespace uavcan_linux 00031 { 00032 /** 00033 * SocketCan driver class keeps number of each kind of errors occurred since the object was created. 00034 */ 00035 enum class SocketCanError 00036 { 00037 SocketReadFailure, 00038 SocketWriteFailure, 00039 TxTimeout 00040 }; 00041 00042 /** 00043 * Single SocketCAN socket interface. 00044 * 00045 * SocketCAN socket adapter maintains TX and RX queues in user space. At any moment socket's buffer contains 00046 * no more than 'max_frames_in_socket_tx_queue_' TX frames, rest is waiting in the user space TX queue; when the 00047 * socket produces loopback for the previously sent TX frame the next frame from the user space TX queue will 00048 * be sent into the socket. 00049 * 00050 * This approach allows to properly maintain TX timeouts (http://stackoverflow.com/questions/19633015/). 00051 * TX timestamping is implemented by means of reading RX timestamps of loopback frames (see "TX timestamping" on 00052 * linux-can mailing list, http://permalink.gmane.org/gmane.linux.can/5322). 00053 * 00054 * Note that if max_frames_in_socket_tx_queue_ is greater than one, frame reordering may occur (depending on the 00055 * unrderlying logic). 00056 * 00057 * This class is too complex and needs to be refactored later. At least, basic socket IO and configuration 00058 * should be extracted into a different class. 00059 */ 00060 class SocketCanIface : public uavcan::ICanIface 00061 { 00062 static inline ::can_frame makeSocketCanFrame(const uavcan::CanFrame& uavcan_frame) 00063 { 00064 ::can_frame sockcan_frame = ::can_frame(); 00065 sockcan_frame.can_id = uavcan_frame.id & uavcan::CanFrame::MaskExtID; 00066 sockcan_frame.can_dlc = uavcan_frame.dlc; 00067 (void)std::copy(uavcan_frame.data, uavcan_frame.data + uavcan_frame.dlc, sockcan_frame.data); 00068 if (uavcan_frame.isExtended()) 00069 { 00070 sockcan_frame.can_id |= CAN_EFF_FLAG; 00071 } 00072 if (uavcan_frame.isErrorFrame()) 00073 { 00074 sockcan_frame.can_id |= CAN_ERR_FLAG; 00075 } 00076 if (uavcan_frame.isRemoteTransmissionRequest()) 00077 { 00078 sockcan_frame.can_id |= CAN_RTR_FLAG; 00079 } 00080 return sockcan_frame; 00081 } 00082 00083 static inline uavcan::CanFrame makeUavcanFrame(const ::can_frame& sockcan_frame) 00084 { 00085 uavcan::CanFrame uavcan_frame(sockcan_frame.can_id & CAN_EFF_MASK, sockcan_frame.data, sockcan_frame.can_dlc); 00086 if (sockcan_frame.can_id & CAN_EFF_FLAG) 00087 { 00088 uavcan_frame.id |= uavcan::CanFrame::FlagEFF; 00089 } 00090 if (sockcan_frame.can_id & CAN_ERR_FLAG) 00091 { 00092 uavcan_frame.id |= uavcan::CanFrame::FlagERR; 00093 } 00094 if (sockcan_frame.can_id & CAN_RTR_FLAG) 00095 { 00096 uavcan_frame.id |= uavcan::CanFrame::FlagRTR; 00097 } 00098 return uavcan_frame; 00099 } 00100 00101 struct TxItem 00102 { 00103 uavcan::CanFrame frame; 00104 uavcan::MonotonicTime deadline; 00105 uavcan::CanIOFlags flags = 0; 00106 std::uint64_t order = 0; 00107 00108 TxItem(const uavcan::CanFrame& arg_frame, uavcan::MonotonicTime arg_deadline, 00109 uavcan::CanIOFlags arg_flags, std::uint64_t arg_order) 00110 : frame(arg_frame) 00111 , deadline(arg_deadline) 00112 , flags(arg_flags) 00113 , order(arg_order) 00114 { } 00115 00116 bool operator<(const TxItem& rhs) const 00117 { 00118 if (frame.priorityLowerThan(rhs.frame)) 00119 { 00120 return true; 00121 } 00122 if (frame.priorityHigherThan(rhs.frame)) 00123 { 00124 return false; 00125 } 00126 return order > rhs.order; 00127 } 00128 }; 00129 00130 struct RxItem 00131 { 00132 uavcan::CanFrame frame; 00133 uavcan::MonotonicTime ts_mono; 00134 uavcan::UtcTime ts_utc; 00135 uavcan::CanIOFlags flags; 00136 00137 RxItem() 00138 : flags(0) 00139 { } 00140 }; 00141 00142 const SystemClock& clock_; 00143 const int fd_; 00144 00145 const unsigned max_frames_in_socket_tx_queue_; 00146 unsigned frames_in_socket_tx_queue_ = 0; 00147 00148 std::uint64_t tx_frame_counter_ = 0; ///< Increments with every frame pushed into the TX queue 00149 00150 std::map<SocketCanError, std::uint64_t> errors_; 00151 00152 std::priority_queue<TxItem> tx_queue_; // TODO: Use pool allocator 00153 std::queue<RxItem> rx_queue_; // TODO: Use pool allocator 00154 std::unordered_multiset<std::uint32_t> pending_loopback_ids_; // TODO: Use pool allocator 00155 00156 std::vector<::can_filter> hw_filters_container_; 00157 00158 void registerError(SocketCanError e) { errors_[e]++; } 00159 00160 void incrementNumFramesInSocketTxQueue() 00161 { 00162 assert(frames_in_socket_tx_queue_ < max_frames_in_socket_tx_queue_); 00163 frames_in_socket_tx_queue_++; 00164 } 00165 00166 void confirmSentFrame() 00167 { 00168 if (frames_in_socket_tx_queue_ > 0) 00169 { 00170 frames_in_socket_tx_queue_--; 00171 } 00172 else 00173 { 00174 assert(0); // Loopback for a frame that we didn't send. 00175 } 00176 } 00177 00178 bool wasInPendingLoopbackSet(const uavcan::CanFrame& frame) 00179 { 00180 if (pending_loopback_ids_.count(frame.id) > 0) 00181 { 00182 (void)pending_loopback_ids_.erase(frame.id); 00183 return true; 00184 } 00185 return false; 00186 } 00187 00188 int write(const uavcan::CanFrame& frame) const 00189 { 00190 errno = 0; 00191 00192 const ::can_frame sockcan_frame = makeSocketCanFrame(frame); 00193 00194 const int res = ::write(fd_, &sockcan_frame, sizeof(sockcan_frame)); 00195 if (res <= 0) 00196 { 00197 if (errno == ENOBUFS || errno == EAGAIN) // Writing is not possible atm, not an error 00198 { 00199 return 0; 00200 } 00201 return res; 00202 } 00203 if (res != sizeof(sockcan_frame)) 00204 { 00205 return -1; 00206 } 00207 return 1; 00208 } 00209 00210 /** 00211 * SocketCAN git show 1e55659ce6ddb5247cee0b1f720d77a799902b85 00212 * MSG_DONTROUTE is set for any packet from localhost, 00213 * MSG_CONFIRM is set for any pakcet of your socket. 00214 * Diff: https://git.ucsd.edu/abuss/linux/commit/1e55659ce6ddb5247cee0b1f720d77a799902b85 00215 * Man: https://www.kernel.org/doc/Documentation/networking/can.txt (chapter 4.1.6). 00216 */ 00217 int read(uavcan::CanFrame& frame, uavcan::UtcTime& ts_utc, bool& loopback) const 00218 { 00219 auto iov = ::iovec(); 00220 auto sockcan_frame = ::can_frame(); 00221 iov.iov_base = &sockcan_frame; 00222 iov.iov_len = sizeof(sockcan_frame); 00223 00224 static constexpr size_t ControlSize = sizeof(cmsghdr) + sizeof(::timeval); 00225 using ControlStorage = typename std::aligned_storage<ControlSize>::type; 00226 ControlStorage control_storage; 00227 auto control = reinterpret_cast<std::uint8_t *>(&control_storage); 00228 std::fill(control, control + ControlSize, 0x00); 00229 00230 auto msg = ::msghdr(); 00231 msg.msg_iov = &iov; 00232 msg.msg_iovlen = 1; 00233 msg.msg_control = control; 00234 msg.msg_controllen = ControlSize; 00235 00236 const int res = ::recvmsg(fd_, &msg, MSG_DONTWAIT); 00237 if (res <= 0) 00238 { 00239 return (res < 0 && errno == EWOULDBLOCK) ? 0 : res; 00240 } 00241 /* 00242 * Flags 00243 */ 00244 loopback = (msg.msg_flags & static_cast<int>(MSG_CONFIRM)) != 0; 00245 00246 if (!loopback && !checkHWFilters(sockcan_frame)) 00247 { 00248 return 0; 00249 } 00250 00251 frame = makeUavcanFrame(sockcan_frame); 00252 /* 00253 * Timestamp 00254 */ 00255 const ::cmsghdr* const cmsg = CMSG_FIRSTHDR(&msg); 00256 assert(cmsg != nullptr); 00257 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SO_TIMESTAMP) 00258 { 00259 auto tv = ::timeval(); 00260 (void)std::memcpy(&tv, CMSG_DATA(cmsg), sizeof(tv)); // Copy to avoid alignment problems 00261 assert(tv.tv_sec >= 0 && tv.tv_usec >= 0); 00262 ts_utc = uavcan::UtcTime::fromUSec(std::uint64_t(tv.tv_sec) * 1000000ULL + tv.tv_usec); 00263 } 00264 else 00265 { 00266 assert(0); 00267 return -1; 00268 } 00269 return 1; 00270 } 00271 00272 void pollWrite() 00273 { 00274 while (hasReadyTx()) 00275 { 00276 const TxItem tx = tx_queue_.top(); 00277 00278 if (tx.deadline >= clock_.getMonotonic()) 00279 { 00280 const int res = write(tx.frame); 00281 if (res == 1) // Transmitted successfully 00282 { 00283 incrementNumFramesInSocketTxQueue(); 00284 if (tx.flags & uavcan::CanIOFlagLoopback) 00285 { 00286 (void)pending_loopback_ids_.insert(tx.frame.id); 00287 } 00288 } 00289 else if (res == 0) // Not transmitted, nor is it an error 00290 { 00291 break; // Leaving the loop, the frame remains enqueued for the next retry 00292 } 00293 else // Transmission error 00294 { 00295 registerError(SocketCanError::SocketWriteFailure); 00296 } 00297 } 00298 else 00299 { 00300 registerError(SocketCanError::TxTimeout); 00301 } 00302 00303 // Removing the frame from the queue even if transmission failed 00304 tx_queue_.pop(); 00305 } 00306 } 00307 00308 void pollRead() 00309 { 00310 while (true) 00311 { 00312 RxItem rx; 00313 rx.ts_mono = clock_.getMonotonic(); // Monotonic timestamp is not required to be precise (unlike UTC) 00314 bool loopback = false; 00315 const int res = read(rx.frame, rx.ts_utc, loopback); 00316 if (res == 1) 00317 { 00318 assert(!rx.ts_utc.isZero()); 00319 bool accept = true; 00320 if (loopback) // We receive loopback for all CAN frames 00321 { 00322 confirmSentFrame(); 00323 rx.flags |= uavcan::CanIOFlagLoopback; 00324 accept = wasInPendingLoopbackSet(rx.frame); // Do we need to send this loopback into the lib? 00325 } 00326 if (accept) 00327 { 00328 rx.ts_utc += clock_.getPrivateAdjustment(); 00329 rx_queue_.push(rx); 00330 } 00331 } 00332 else if (res == 0) 00333 { 00334 break; 00335 } 00336 else 00337 { 00338 registerError(SocketCanError::SocketReadFailure); 00339 break; 00340 } 00341 } 00342 } 00343 00344 /** 00345 * Returns true if a frame accepted by HW filters 00346 */ 00347 bool checkHWFilters(const ::can_frame& frame) const 00348 { 00349 if (!hw_filters_container_.empty()) 00350 { 00351 for (auto& f : hw_filters_container_) 00352 { 00353 if (((frame.can_id & f.can_mask) ^ f.can_id) == 0) 00354 { 00355 return true; 00356 } 00357 } 00358 return false; 00359 } 00360 else 00361 { 00362 return true; 00363 } 00364 } 00365 00366 public: 00367 /** 00368 * Takes ownership of socket's file descriptor. 00369 * 00370 * @ref max_frames_in_socket_tx_queue See a note in the class comment. 00371 */ 00372 SocketCanIface(const SystemClock& clock, int socket_fd, int max_frames_in_socket_tx_queue = 2) 00373 : clock_(clock) 00374 , fd_(socket_fd) 00375 , max_frames_in_socket_tx_queue_(max_frames_in_socket_tx_queue) 00376 { 00377 assert(fd_ >= 0); 00378 } 00379 00380 /** 00381 * Socket file descriptor will be closed. 00382 */ 00383 virtual ~SocketCanIface() 00384 { 00385 UAVCAN_TRACE("SocketCAN", "SocketCanIface: Closing fd %d", fd_); 00386 (void)::close(fd_); 00387 } 00388 00389 /** 00390 * Assumes that the socket is writeable 00391 */ 00392 std::int16_t send(const uavcan::CanFrame& frame, const uavcan::MonotonicTime tx_deadline, 00393 const uavcan::CanIOFlags flags) override 00394 { 00395 tx_queue_.emplace(frame, tx_deadline, flags, tx_frame_counter_); 00396 tx_frame_counter_++; 00397 pollRead(); // Read poll is necessary because it can release the pending TX flag 00398 pollWrite(); 00399 return 1; 00400 } 00401 00402 /** 00403 * Will read the socket only if RX queue is empty. 00404 * Normally, poll() needs to be executed first. 00405 */ 00406 std::int16_t receive(uavcan::CanFrame& out_frame, uavcan::MonotonicTime& out_ts_monotonic, 00407 uavcan::UtcTime& out_ts_utc, uavcan::CanIOFlags& out_flags) override 00408 { 00409 if (rx_queue_.empty()) 00410 { 00411 pollRead(); // This allows to use the socket not calling poll() explicitly. 00412 if (rx_queue_.empty()) 00413 { 00414 return 0; 00415 } 00416 } 00417 { 00418 const RxItem& rx = rx_queue_.front(); 00419 out_frame = rx.frame; 00420 out_ts_monotonic = rx.ts_mono; 00421 out_ts_utc = rx.ts_utc; 00422 out_flags = rx.flags; 00423 } 00424 rx_queue_.pop(); 00425 return 1; 00426 } 00427 00428 /** 00429 * Performs socket read/write. 00430 * @param read Socket is readable 00431 * @param write Socket is writeable 00432 */ 00433 void poll(bool read, bool write) 00434 { 00435 if (read) 00436 { 00437 pollRead(); // Read poll must be executed first because it may decrement frames_in_socket_tx_queue_ 00438 } 00439 if (write) 00440 { 00441 pollWrite(); 00442 } 00443 } 00444 00445 bool hasReadyRx() const { return !rx_queue_.empty(); } 00446 bool hasReadyTx() const 00447 { 00448 return !tx_queue_.empty() && (frames_in_socket_tx_queue_ < max_frames_in_socket_tx_queue_); 00449 } 00450 00451 std::int16_t configureFilters(const uavcan::CanFilterConfig* const filter_configs, 00452 const std::uint16_t num_configs) override 00453 { 00454 if (filter_configs == nullptr) 00455 { 00456 assert(0); 00457 return -1; 00458 } 00459 hw_filters_container_.clear(); 00460 hw_filters_container_.resize(num_configs); 00461 00462 for (unsigned i = 0; i < num_configs; i++) 00463 { 00464 const uavcan::CanFilterConfig& fc = filter_configs[i]; 00465 hw_filters_container_[i].can_id = fc.id & uavcan::CanFrame::MaskExtID; 00466 hw_filters_container_[i].can_mask = fc.mask & uavcan::CanFrame::MaskExtID; 00467 if (fc.id & uavcan::CanFrame::FlagEFF) 00468 { 00469 hw_filters_container_[i].can_id |= CAN_EFF_FLAG; 00470 } 00471 if (fc.id & uavcan::CanFrame::FlagRTR) 00472 { 00473 hw_filters_container_[i].can_id |= CAN_RTR_FLAG; 00474 } 00475 if (fc.mask & uavcan::CanFrame::FlagEFF) 00476 { 00477 hw_filters_container_[i].can_mask |= CAN_EFF_FLAG; 00478 } 00479 if (fc.mask & uavcan::CanFrame::FlagRTR) 00480 { 00481 hw_filters_container_[i].can_mask |= CAN_RTR_FLAG; 00482 } 00483 } 00484 00485 return 0; 00486 } 00487 00488 /** 00489 * SocketCAN emulates the CAN filters in software, so the number of filters is virtually unlimited. 00490 * This method returns a constant value. 00491 */ 00492 static constexpr unsigned NumFilters = 8; 00493 std::uint16_t getNumFilters() const override { return NumFilters; } 00494 00495 00496 /** 00497 * Returns total number of errors of each kind detected since the object was created. 00498 */ 00499 std::uint64_t getErrorCount() const override 00500 { 00501 std::uint64_t ec = 0; 00502 for (auto& kv : errors_) { ec += kv.second; } 00503 return ec; 00504 } 00505 00506 /** 00507 * Returns number of errors of each kind in a map. 00508 */ 00509 const decltype(errors_) & getErrors() const { return errors_; } 00510 00511 int getFileDescriptor() const { return fd_; } 00512 00513 /** 00514 * Open and configure a CAN socket on iface specified by name. 00515 * @param iface_name String containing iface name, e.g. "can0", "vcan1", "slcan0" 00516 * @return Socket descriptor or negative number on error. 00517 */ 00518 static int openSocket(const std::string& iface_name) 00519 { 00520 errno = 0; 00521 00522 const int s = ::socket(PF_CAN, SOCK_RAW, CAN_RAW); 00523 if (s < 0) 00524 { 00525 return s; 00526 } 00527 00528 class RaiiCloser 00529 { 00530 int fd_; 00531 public: 00532 RaiiCloser(int filedesc) : fd_(filedesc) 00533 { 00534 assert(fd_ >= 0); 00535 } 00536 ~RaiiCloser() 00537 { 00538 if (fd_ >= 0) 00539 { 00540 UAVCAN_TRACE("SocketCAN", "RaiiCloser: Closing fd %d", fd_); 00541 (void)::close(fd_); 00542 } 00543 } 00544 void disarm() { fd_ = -1; } 00545 } raii_closer(s); 00546 00547 // Detect the iface index 00548 auto ifr = ::ifreq(); 00549 if (iface_name.length() >= IFNAMSIZ) 00550 { 00551 errno = ENAMETOOLONG; 00552 return -1; 00553 } 00554 (void)std::strncpy(ifr.ifr_name, iface_name.c_str(), iface_name.length()); 00555 if (::ioctl(s, SIOCGIFINDEX, &ifr) < 0 || ifr.ifr_ifindex < 0) 00556 { 00557 return -1; 00558 } 00559 00560 // Bind to the specified CAN iface 00561 { 00562 auto addr = ::sockaddr_can(); 00563 addr.can_family = AF_CAN; 00564 addr.can_ifindex = ifr.ifr_ifindex; 00565 if (::bind(s, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) 00566 { 00567 return -1; 00568 } 00569 } 00570 00571 // Configure 00572 { 00573 const int on = 1; 00574 // Timestamping 00575 if (::setsockopt(s, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on)) < 0) 00576 { 00577 return -1; 00578 } 00579 // Socket loopback 00580 if (::setsockopt(s, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS, &on, sizeof(on)) < 0) 00581 { 00582 return -1; 00583 } 00584 // Non-blocking 00585 if (::fcntl(s, F_SETFL, O_NONBLOCK) < 0) 00586 { 00587 return -1; 00588 } 00589 } 00590 00591 // Validate the resulting socket 00592 { 00593 int socket_error = 0; 00594 ::socklen_t errlen = sizeof(socket_error); 00595 (void)::getsockopt(s, SOL_SOCKET, SO_ERROR, reinterpret_cast<void*>(&socket_error), &errlen); 00596 if (socket_error != 0) 00597 { 00598 errno = socket_error; 00599 return -1; 00600 } 00601 } 00602 00603 raii_closer.disarm(); 00604 return s; 00605 } 00606 }; 00607 00608 /** 00609 * Multiplexing container for multiple SocketCAN sockets. 00610 * Uses ppoll() for multiplexing. 00611 * 00612 * When an interface becomes down/disconnected while the node is running, 00613 * the driver will silently exclude it from the IO loop and continue to run on the remaining interfaces. 00614 * When all interfaces become down/disconnected, the driver will throw @ref AllIfacesDownException 00615 * from @ref SocketCanDriver::select(). 00616 * Whether a certain interface is down can be checked with @ref SocketCanDriver::isIfaceDown(). 00617 */ 00618 class SocketCanDriver : public uavcan::ICanDriver 00619 { 00620 class IfaceWrapper : public SocketCanIface 00621 { 00622 bool down_ = false; 00623 00624 public: 00625 IfaceWrapper(const SystemClock& clock, int fd) : SocketCanIface(clock, fd) { } 00626 00627 void updateDownStatusFromPollResult(const ::pollfd& pfd) 00628 { 00629 assert(pfd.fd == this->getFileDescriptor()); 00630 if (!down_ && (pfd.revents & POLLERR)) 00631 { 00632 int error = 0; 00633 ::socklen_t errlen = sizeof(error); 00634 (void)::getsockopt(pfd.fd, SOL_SOCKET, SO_ERROR, reinterpret_cast<void*>(&error), &errlen); 00635 00636 down_ = error == ENETDOWN || error == ENODEV; 00637 00638 UAVCAN_TRACE("SocketCAN", "Iface %d is dead; error %d", this->getFileDescriptor(), error); 00639 } 00640 } 00641 00642 bool isDown() const { return down_; } 00643 }; 00644 00645 const SystemClock& clock_; 00646 std::vector<std::unique_ptr<IfaceWrapper>> ifaces_; 00647 00648 public: 00649 /** 00650 * Reference to the clock object shall remain valid. 00651 */ 00652 explicit SocketCanDriver(const SystemClock& clock) 00653 : clock_(clock) 00654 { 00655 ifaces_.reserve(uavcan::MaxCanIfaces); 00656 } 00657 00658 /** 00659 * This function may return before deadline expiration even if no requested IO operations become possible. 00660 * This behavior makes implementation way simpler, and it is OK since libuavcan can properly handle such 00661 * early returns. 00662 * Also it can return more events than were originally requested by uavcan, which is also acceptable. 00663 */ 00664 std::int16_t select(uavcan::CanSelectMasks& inout_masks, 00665 const uavcan::CanFrame* (&)[uavcan::MaxCanIfaces], 00666 uavcan::MonotonicTime blocking_deadline) override 00667 { 00668 // Detecting whether we need to block at all 00669 bool need_block = (inout_masks.write == 0); // Write queue is infinite 00670 for (unsigned i = 0; need_block && (i < ifaces_.size()); i++) 00671 { 00672 const bool need_read = inout_masks.read & (1 << i); 00673 if (need_read && ifaces_[i]->hasReadyRx()) 00674 { 00675 need_block = false; 00676 } 00677 } 00678 00679 if (need_block) 00680 { 00681 // Poll FD set setup 00682 ::pollfd pollfds[uavcan::MaxCanIfaces] = {}; 00683 unsigned num_pollfds = 0; 00684 IfaceWrapper* pollfd_index_to_iface[uavcan::MaxCanIfaces] = { }; 00685 00686 for (unsigned i = 0; i < ifaces_.size(); i++) 00687 { 00688 if (!ifaces_[i]->isDown()) 00689 { 00690 pollfds[num_pollfds].fd = ifaces_[i]->getFileDescriptor(); 00691 pollfds[num_pollfds].events = POLLIN; 00692 if (ifaces_[i]->hasReadyTx() || (inout_masks.write & (1U << i))) 00693 { 00694 pollfds[num_pollfds].events |= POLLOUT; 00695 } 00696 pollfd_index_to_iface[num_pollfds] = ifaces_[i].get(); 00697 num_pollfds++; 00698 } 00699 } 00700 00701 // This is where we abort when the last iface goes down 00702 if (num_pollfds == 0) 00703 { 00704 throw AllIfacesDownException(); 00705 } 00706 00707 // Timeout conversion 00708 const std::int64_t timeout_usec = (blocking_deadline - clock_.getMonotonic()).toUSec(); 00709 auto ts = ::timespec(); 00710 if (timeout_usec > 0) 00711 { 00712 ts.tv_sec = timeout_usec / 1000000LL; 00713 ts.tv_nsec = (timeout_usec % 1000000LL) * 1000; 00714 } 00715 00716 // Blocking here 00717 const int res = ::ppoll(pollfds, num_pollfds, &ts, nullptr); 00718 if (res < 0) 00719 { 00720 return res; 00721 } 00722 00723 // Handling poll output 00724 for (unsigned i = 0; i < num_pollfds; i++) 00725 { 00726 pollfd_index_to_iface[i]->updateDownStatusFromPollResult(pollfds[i]); 00727 00728 const bool poll_read = pollfds[i].revents & POLLIN; 00729 const bool poll_write = pollfds[i].revents & POLLOUT; 00730 pollfd_index_to_iface[i]->poll(poll_read, poll_write); 00731 } 00732 } 00733 00734 // Writing the output masks 00735 inout_masks = uavcan::CanSelectMasks(); 00736 for (unsigned i = 0; i < ifaces_.size(); i++) 00737 { 00738 if (!ifaces_[i]->isDown()) 00739 { 00740 inout_masks.write |= std::uint8_t(1U << i); // Always ready to write if not down 00741 } 00742 if (ifaces_[i]->hasReadyRx()) 00743 { 00744 inout_masks.read |= std::uint8_t(1U << i); // Readability depends only on RX buf, even if down 00745 } 00746 } 00747 00748 // Return value is irrelevant as long as it's non-negative 00749 return ifaces_.size(); 00750 } 00751 00752 SocketCanIface* getIface(std::uint8_t iface_index) override 00753 { 00754 return (iface_index >= ifaces_.size()) ? nullptr : ifaces_[iface_index].get(); 00755 } 00756 00757 std::uint8_t getNumIfaces() const override { return ifaces_.size(); } 00758 00759 /** 00760 * Adds one iface by name. Will fail if there are @ref MaxIfaces ifaces registered already. 00761 * @param iface_name E.g. "can0", "vcan1" 00762 * @return Negative on error, interface index on success. 00763 * @throws uavcan_linux::Exception. 00764 */ 00765 int addIface(const std::string& iface_name) 00766 { 00767 if (ifaces_.size() >= uavcan::MaxCanIfaces) 00768 { 00769 return -1; 00770 } 00771 00772 // Open the socket 00773 const int fd = SocketCanIface::openSocket(iface_name); 00774 if (fd < 0) 00775 { 00776 return fd; 00777 } 00778 00779 // Construct the iface - upon successful construction the iface will take ownership of the fd. 00780 try 00781 { 00782 ifaces_.emplace_back(new IfaceWrapper(clock_, fd)); 00783 } 00784 catch (...) 00785 { 00786 (void)::close(fd); 00787 throw; 00788 } 00789 00790 UAVCAN_TRACE("SocketCAN", "New iface '%s' fd %d", iface_name.c_str(), fd); 00791 00792 return ifaces_.size() - 1; 00793 } 00794 00795 /** 00796 * Returns false if the specified interface is functioning, true if it became unavailable. 00797 */ 00798 bool isIfaceDown(std::uint8_t iface_index) const 00799 { 00800 return ifaces_.at(iface_index)->isDown(); 00801 } 00802 }; 00803 00804 }
Generated on Tue Jul 12 2022 17:17:34 by 1.7.2