LCOV - code coverage report
Current view: top level - workspace/platforms/posix/bsp/socketCanTransceiver/src/can - SocketCanTransceiver.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 9 136 6.6 %
Date: 2025-01-20 13:53:09 Functions: 1 20 5.0 %

          Line data    Source code
       1             : // Copyright 2024 Accenture.
       2             : 
       3             : #include "can/SocketCanTransceiver.h"
       4             : 
       5             : #include <can/CanLogger.h>
       6             : #include <can/canframes/ICANFrameSentListener.h>
       7             : #include <linux/can.h>
       8             : #include <linux/can/raw.h>
       9             : #include <net/if.h>
      10             : #include <sys/ioctl.h>
      11             : #include <sys/socket.h>
      12             : 
      13             : #include <fcntl.h>
      14             : #include <signal.h>
      15             : #include <type_traits>
      16             : #include <unistd.h>
      17             : 
      18             : static_assert(
      19             :     std::is_standard_layout<::can::CANFrame>::value
      20             :         && std::is_trivially_destructible<::can::CANFrame>::value,
      21             :     "check for UB while passing through TxQueue");
      22             : 
      23             : namespace can
      24             : {
      25             : 
      26             : using ::util::logger::CAN;
      27             : using ::util::logger::Logger;
      28             : 
      29             : namespace
      30             : {
      31             : 
      32             : template<typename F>
      33           0 : void signalGuarded(F&& function)
      34             : {
      35             :     sigset_t set, oldSet;
      36           0 :     sigfillset(&set);
      37           0 :     pthread_sigmask(SIG_SETMASK, &set, &oldSet);
      38           0 :     ::std::forward<F>(function)();
      39           0 :     pthread_sigmask(SIG_SETMASK, &oldSet, nullptr);
      40           0 : }
      41             : 
      42             : } // namespace
      43             : 
      44             : // needed if ODR-used
      45             : size_t const SocketCanTransceiver::TX_QUEUE_SIZE_BYTES;
      46             : 
      47           1 : SocketCanTransceiver::SocketCanTransceiver(DeviceConfig const& config)
      48           1 : : AbstractCANTransceiver(config.busId)
      49           1 : , _txQueue()
      50           1 : , _txReader(_txQueue)
      51           1 : , _txWriter(_txQueue)
      52           1 : , _config(config)
      53           1 : , _fileDescriptor(-1)
      54           1 : , _writable(false)
      55           1 : {}
      56             : 
      57           0 : ICanTransceiver::ErrorCode SocketCanTransceiver::init()
      58             : {
      59           0 :     if (!isInState(State::CLOSED))
      60             :     {
      61             :         return ErrorCode::CAN_ERR_ILLEGAL_STATE;
      62             :     }
      63           0 :     setState(State::INITIALIZED);
      64           0 :     return ErrorCode::CAN_ERR_OK;
      65             : }
      66             : 
      67           0 : ICanTransceiver::ErrorCode SocketCanTransceiver::open()
      68             : {
      69           0 :     if (!isInState(State::INITIALIZED))
      70             :     {
      71             :         return ErrorCode::CAN_ERR_ILLEGAL_STATE;
      72             :     }
      73           0 :     signalGuarded([this] { guardedOpen(); });
      74           0 :     setState(State::OPEN);
      75           0 :     _writable.store(true);
      76           0 :     return ErrorCode::CAN_ERR_OK;
      77             : }
      78             : 
      79           0 : ICanTransceiver::ErrorCode SocketCanTransceiver::open(CANFrame const& frame)
      80             : {
      81           0 :     estd_assert(false);
      82             :     return ErrorCode::CAN_ERR_ILLEGAL_STATE;
      83             : }
      84             : 
      85           0 : ICanTransceiver::ErrorCode SocketCanTransceiver::close()
      86             : {
      87           0 :     if (!isInState(State::OPEN) && !isInState(State::MUTED))
      88             :     {
      89             :         return ErrorCode::CAN_ERR_ILLEGAL_STATE;
      90             :     }
      91           0 :     signalGuarded([this] { guardedClose(); });
      92           0 :     _writable.store(false);
      93           0 :     setState(State::CLOSED);
      94           0 :     return ErrorCode::CAN_ERR_OK;
      95             : }
      96             : 
      97           0 : void SocketCanTransceiver::shutdown() {}
      98             : 
      99           0 : ICanTransceiver::ErrorCode SocketCanTransceiver::write(CANFrame const& frame)
     100             : {
     101           0 :     if (!_writable.load(std::memory_order_relaxed))
     102             :     {
     103             :         return ErrorCode::CAN_ERR_ILLEGAL_STATE;
     104             :     }
     105           0 :     FrameWithListener slot{frame, nullptr};
     106           0 :     ::estd::slice<uint8_t> memory = _txWriter.allocate(sizeof(slot));
     107           0 :     if (memory.size() == 0)
     108             :     {
     109             :         return ErrorCode::CAN_ERR_TX_HW_QUEUE_FULL;
     110             :     }
     111           0 :     ::std::memcpy(memory.data(), &slot, sizeof(slot));
     112           0 :     _txWriter.commit();
     113           0 :     return ErrorCode::CAN_ERR_OK;
     114             : }
     115             : 
     116             : ICanTransceiver::ErrorCode
     117           0 : SocketCanTransceiver::write(CANFrame const& frame, ICANFrameSentListener& listener)
     118             : {
     119           0 :     if (!_writable.load(std::memory_order_relaxed))
     120             :     {
     121             :         return ErrorCode::CAN_ERR_ILLEGAL_STATE;
     122             :     }
     123           0 :     FrameWithListener slot{frame, &listener};
     124           0 :     ::estd::slice<uint8_t> memory = _txWriter.allocate(sizeof(slot));
     125           0 :     if (memory.size() == 0)
     126             :     {
     127             :         return ErrorCode::CAN_ERR_TX_HW_QUEUE_FULL;
     128             :     }
     129           0 :     ::std::memcpy(memory.data(), &slot, sizeof(slot));
     130           0 :     _txWriter.commit();
     131           0 :     return ErrorCode::CAN_ERR_OK;
     132             : }
     133             : 
     134           0 : ICanTransceiver::ErrorCode SocketCanTransceiver::mute()
     135             : {
     136           0 :     if (!isInState(State::OPEN))
     137             :     {
     138             :         return ErrorCode::CAN_ERR_ILLEGAL_STATE;
     139             :     }
     140           0 :     _writable.store(false);
     141           0 :     setState(State::MUTED);
     142           0 :     return ErrorCode::CAN_ERR_OK;
     143             : }
     144             : 
     145           0 : ICanTransceiver::ErrorCode SocketCanTransceiver::unmute()
     146             : {
     147           0 :     if (!isInState(State::MUTED))
     148             :     {
     149             :         return ErrorCode::CAN_ERR_ILLEGAL_STATE;
     150             :     }
     151           0 :     setState(State::OPEN);
     152           0 :     _writable.store(true);
     153           0 :     return ErrorCode::CAN_ERR_OK;
     154             : }
     155             : 
     156           0 : uint32_t SocketCanTransceiver::getBaudrate() const { return 500000U; }
     157             : 
     158           0 : uint16_t SocketCanTransceiver::getHwQueueTimeout() const { return 1U; }
     159             : 
     160           0 : void SocketCanTransceiver::run(int maxSentPerRun, int maxReceivedPerRun)
     161             : {
     162           0 :     signalGuarded([this, maxSentPerRun, maxReceivedPerRun]
     163           0 :                   { guardedRun(maxSentPerRun, maxReceivedPerRun); });
     164           0 : }
     165             : 
     166           0 : void SocketCanTransceiver::guardedOpen()
     167             : {
     168           0 :     char const* const name = _config.name;
     169           0 :     int error              = 0;
     170           0 :     int const fd           = socket(PF_CAN, SOCK_RAW, CAN_RAW);
     171           0 :     if (fd < 0)
     172             :     {
     173           0 :         Logger::error(
     174             :             CAN, "[SocketCanTransceiver] Failed to create socket (node=%s, error=%d)", name, fd);
     175           0 :         return;
     176             :     }
     177             : 
     178           0 :     struct ifreq ifr;
     179           0 :     ::std::strcpy(ifr.ifr_name, name);
     180           0 :     error = ioctl(fd, SIOCGIFINDEX, &ifr);
     181           0 :     if (error < 0)
     182             :     {
     183           0 :         Logger::error(
     184             :             CAN, "[SocketCanTransceiver] Failed to ioctl socket (node=%s, error=%d)", name, error);
     185           0 :         return;
     186             :     }
     187             : 
     188           0 :     int const enable_canfd = 1;
     189           0 :     error = setsockopt(fd, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &enable_canfd, sizeof(enable_canfd));
     190           0 :     if (error < 0)
     191             :     {
     192           0 :         Logger::error(
     193             :             CAN,
     194             :             "[SocketCanTransceiver] Failed to setsockopt socket (node=%s, error=%d)",
     195             :             name,
     196             :             error);
     197           0 :         return;
     198             :     }
     199             : 
     200           0 :     error = fcntl(fd, F_SETFL, O_NONBLOCK);
     201           0 :     if (error < 0)
     202             :     {
     203           0 :         Logger::error(
     204             :             CAN,
     205             :             "[SocketCanTransceiver] Failed to switch to non-blocking mode (node=%s, error=%d)",
     206             :             name,
     207             :             error);
     208           0 :         return;
     209             :     }
     210             : 
     211           0 :     struct sockaddr_can addr;
     212           0 :     ::std::memset(&addr, 0, sizeof(addr));
     213           0 :     addr.can_family  = AF_CAN;
     214           0 :     addr.can_ifindex = ifr.ifr_ifindex;
     215           0 :     error            = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
     216           0 :     if (error < 0)
     217             :     {
     218           0 :         Logger::error(
     219             :             CAN, "[SocketCanTransceiver] Failed to bind socket (node=%s, error=%d)", name, error);
     220           0 :         return;
     221             :     }
     222             : 
     223           0 :     _fileDescriptor = fd;
     224             : }
     225             : 
     226           0 : void SocketCanTransceiver::guardedClose()
     227             : {
     228           0 :     ::close(_fileDescriptor);
     229           0 :     _fileDescriptor = -1;
     230           0 : }
     231             : 
     232           0 : void SocketCanTransceiver::guardedRun(int maxSentPerRun, int maxReceivedPerRun)
     233             : {
     234             :     // MUTED condition does not affect the messages already in the write queue;
     235             :     // the idea is that once we confirmed that we had accepted the message for delivery,
     236             :     // we shall try to deliver it.
     237           0 :     for (int count = 0; count < maxSentPerRun; ++count)
     238             :     {
     239           0 :         ::estd::slice<uint8_t const> canFrameSlice = _txReader.peek();
     240           0 :         if (canFrameSlice.size() == 0)
     241             :         {
     242             :             break;
     243             :         }
     244           0 :         FrameWithListener slot;
     245           0 :         ::std::memcpy(static_cast<void*>(&slot), canFrameSlice.data(), sizeof(slot));
     246           0 :         CANFrame& canFrame = slot.frame;
     247           0 :         can_frame socketCanFrame;
     248           0 :         socketCanFrame.can_id  = canFrame.getId();
     249           0 :         int length             = canFrame.getPayloadLength();
     250           0 :         socketCanFrame.can_dlc = length;
     251           0 :         ::std::memcpy(socketCanFrame.data, canFrame.getPayload(), length);
     252           0 :         ::std::memset(socketCanFrame.data + length, 0, sizeof(socketCanFrame.data) - length);
     253           0 :         length = ::write(_fileDescriptor, reinterpret_cast<char*>(&socketCanFrame), CAN_MTU);
     254           0 :         if (length != CAN_MTU)
     255             :         {
     256             :             break;
     257             :         }
     258           0 :         _txReader.release();
     259           0 :         if (slot.listener != nullptr)
     260             :         {
     261           0 :             slot.listener->canFrameSent(canFrame);
     262             :         }
     263           0 :         notifySentListeners(canFrame);
     264             :     }
     265             : 
     266           0 :     for (int count = 0; count < maxReceivedPerRun; ++count)
     267             :     {
     268           0 :         alignas(can_frame) uint8_t buffer[CANFD_MTU];
     269           0 :         int const length = read(_fileDescriptor, reinterpret_cast<char*>(buffer), CANFD_MTU);
     270           0 :         if (length < 0)
     271             :         {
     272             :             break;
     273             :         }
     274           0 :         if (length == CAN_MTU)
     275             :         {
     276           0 :             can_frame const& socketCanFrame = *reinterpret_cast<can_frame const*>(buffer);
     277           0 :             Logger::debug(
     278             :                 CAN,
     279             :                 "[SocketCanTransceiver] received CAN frame, id=0x%X, length=%d",
     280           0 :                 (int)socketCanFrame.can_id,
     281           0 :                 (int)socketCanFrame.can_dlc);
     282           0 :             CANFrame canFrame;
     283           0 :             canFrame.setId(socketCanFrame.can_id);
     284           0 :             canFrame.setPayload(socketCanFrame.data, socketCanFrame.can_dlc);
     285           0 :             canFrame.setPayloadLength(socketCanFrame.can_dlc);
     286           0 :             canFrame.setTimestamp(0);
     287             : 
     288           0 :             notifyListeners(canFrame);
     289             :         }
     290             :     }
     291           0 : }
     292             : 
     293             : } // namespace can

Generated by: LCOV version 1.14