LCOV - code coverage report
Current view: top level - platforms/posix/bsp/socketCanTransceiver/src/can - SocketCanTransceiver.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 6.4 % 141 9
Test Date: 2026-04-15 11:38:51 Functions: 4.3 % 23 1

            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              : #include <etl/char_traits.h>
      19              : #include <etl/error_handler.h>
      20              : #include <etl/span.h>
      21              : #include <sys/types.h>
      22              : 
      23              : static_assert(
      24              :     std::is_standard_layout<::can::CANFrame>::value
      25              :         && std::is_trivially_destructible<::can::CANFrame>::value,
      26              :     "check for UB while passing through TxQueue");
      27              : 
      28              : namespace can
      29              : {
      30              : 
      31              : using ::util::logger::CAN;
      32              : using ::util::logger::Logger;
      33              : 
      34              : namespace
      35              : {
      36              : 
      37              : template<typename F>
      38            0 : void signalGuarded(F&& function)
      39              : {
      40              :     sigset_t set, oldSet;
      41            0 :     sigfillset(&set);
      42            0 :     pthread_sigmask(SIG_SETMASK, &set, &oldSet);
      43            0 :     ::std::forward<F>(function)();
      44            0 :     pthread_sigmask(SIG_SETMASK, &oldSet, nullptr);
      45            0 : }
      46              : 
      47              : } // namespace
      48              : 
      49              : // needed if ODR-used
      50              : size_t const SocketCanTransceiver::TX_QUEUE_SIZE_BYTES;
      51              : 
      52            1 : SocketCanTransceiver::SocketCanTransceiver(DeviceConfig const& config)
      53            1 : : AbstractCANTransceiver(config.busId)
      54            1 : , _txQueue()
      55            1 : , _txReader(_txQueue)
      56            1 : , _txWriter(_txQueue)
      57            1 : , _config(config)
      58            1 : , _fileDescriptor(-1)
      59            2 : , _writable(false)
      60            1 : {}
      61              : 
      62            0 : ICanTransceiver::ErrorCode SocketCanTransceiver::init()
      63              : {
      64            0 :     if (!isInState(State::CLOSED))
      65              :     {
      66            0 :         return ErrorCode::CAN_ERR_ILLEGAL_STATE;
      67              :     }
      68            0 :     setState(State::INITIALIZED);
      69            0 :     return ErrorCode::CAN_ERR_OK;
      70              : }
      71              : 
      72            0 : ICanTransceiver::ErrorCode SocketCanTransceiver::open()
      73              : {
      74            0 :     if (!isInState(State::INITIALIZED))
      75              :     {
      76            0 :         return ErrorCode::CAN_ERR_ILLEGAL_STATE;
      77              :     }
      78            0 :     signalGuarded([this] { guardedOpen(); });
      79            0 :     setState(State::OPEN);
      80            0 :     _writable.store(true);
      81            0 :     return ErrorCode::CAN_ERR_OK;
      82              : }
      83              : 
      84            0 : ICanTransceiver::ErrorCode SocketCanTransceiver::open(CANFrame const& /* frame */)
      85              : {
      86            0 :     ETL_ASSERT_FAIL(ETL_ERROR_GENERIC("not implemented"));
      87              :     return ErrorCode::CAN_ERR_ILLEGAL_STATE;
      88              : }
      89              : 
      90            0 : ICanTransceiver::ErrorCode SocketCanTransceiver::close()
      91              : {
      92            0 :     if (!isInState(State::OPEN) && !isInState(State::MUTED))
      93              :     {
      94            0 :         return ErrorCode::CAN_ERR_ILLEGAL_STATE;
      95              :     }
      96            0 :     signalGuarded([this] { guardedClose(); });
      97            0 :     _writable.store(false);
      98            0 :     setState(State::CLOSED);
      99            0 :     return ErrorCode::CAN_ERR_OK;
     100              : }
     101              : 
     102            0 : void SocketCanTransceiver::shutdown() {}
     103              : 
     104            0 : ICanTransceiver::ErrorCode SocketCanTransceiver::write(CANFrame const& frame)
     105              : {
     106            0 :     return writeImpl(frame, nullptr);
     107              : }
     108              : 
     109              : ICanTransceiver::ErrorCode
     110            0 : SocketCanTransceiver::write(CANFrame const& frame, ICANFrameSentListener& listener)
     111              : {
     112            0 :     return writeImpl(frame, &listener);
     113              : }
     114              : 
     115              : ICanTransceiver::ErrorCode
     116            0 : SocketCanTransceiver::writeImpl(CANFrame const& frame, ICANFrameSentListener* listener)
     117              : {
     118            0 :     if (!_writable.load(std::memory_order_relaxed))
     119              :     {
     120            0 :         return ErrorCode::CAN_ERR_ILLEGAL_STATE;
     121              :     }
     122            0 :     auto memory = _txWriter.allocate(TX_ELEMENT_SIZE_BYTES);
     123            0 :     if (memory.size() < TX_ELEMENT_SIZE_BYTES)
     124              :     {
     125            0 :         return ErrorCode::CAN_ERR_TX_HW_QUEUE_FULL;
     126              :     }
     127            0 :     ::std::memcpy(memory.data(), &frame, sizeof(frame));
     128            0 :     ::std::memcpy(memory.data() + sizeof(frame), static_cast<void*>(&listener), sizeof(void*));
     129            0 :     _txWriter.commit();
     130            0 :     return ErrorCode::CAN_ERR_OK;
     131              : }
     132              : 
     133            0 : ICanTransceiver::ErrorCode SocketCanTransceiver::mute()
     134              : {
     135            0 :     if (!isInState(State::OPEN))
     136              :     {
     137            0 :         return ErrorCode::CAN_ERR_ILLEGAL_STATE;
     138              :     }
     139            0 :     _writable.store(false);
     140            0 :     setState(State::MUTED);
     141            0 :     return ErrorCode::CAN_ERR_OK;
     142              : }
     143              : 
     144            0 : ICanTransceiver::ErrorCode SocketCanTransceiver::unmute()
     145              : {
     146            0 :     if (!isInState(State::MUTED))
     147              :     {
     148            0 :         return ErrorCode::CAN_ERR_ILLEGAL_STATE;
     149              :     }
     150            0 :     setState(State::OPEN);
     151            0 :     _writable.store(true);
     152            0 :     return ErrorCode::CAN_ERR_OK;
     153              : }
     154              : 
     155            0 : uint32_t SocketCanTransceiver::getBaudrate() const { return 500000U; }
     156              : 
     157            0 : uint16_t SocketCanTransceiver::getHwQueueTimeout() const { return 1U; }
     158              : 
     159            0 : void SocketCanTransceiver::run(int maxSentPerRun, int maxReceivedPerRun)
     160              : {
     161            0 :     signalGuarded([this, maxSentPerRun, maxReceivedPerRun]
     162            0 :                   { guardedRun(maxSentPerRun, maxReceivedPerRun); });
     163            0 : }
     164              : 
     165            0 : void SocketCanTransceiver::guardedOpen()
     166              : {
     167              :     // NOLINTBEGIN(cppcoreguidelines-pro-type-vararg): Logger API is variadic by design.
     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              :     struct ifreq ifr;
     179            0 :     etl::strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name) / sizeof(ifr.ifr_name[0]));
     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              :     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              :     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): POSIX bind() requires sockaddr*
     216            0 :     error            = bind(fd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr));
     217            0 :     if (error < 0)
     218              :     {
     219            0 :         Logger::error(
     220              :             CAN, "[SocketCanTransceiver] Failed to bind socket (node=%s, error=%d)", name, error);
     221            0 :         return;
     222              :     }
     223              : 
     224            0 :     _fileDescriptor = fd;
     225              :     // NOLINTEND(cppcoreguidelines-pro-type-vararg)
     226              : }
     227              : 
     228            0 : void SocketCanTransceiver::guardedClose()
     229              : {
     230            0 :     ::close(_fileDescriptor);
     231            0 :     _fileDescriptor = -1;
     232            0 : }
     233              : 
     234            0 : void SocketCanTransceiver::guardedRun(int maxSentPerRun, int maxReceivedPerRun)
     235              : {
     236              :     // MUTED condition does not affect the messages already in the write queue;
     237              :     // the idea is that once we confirmed that we had accepted the message for delivery,
     238              :     // we shall try to deliver it.
     239            0 :     for (int count = 0; count < maxSentPerRun; ++count)
     240              :     {
     241            0 :         auto memory = _txReader.peek();
     242            0 :         if (memory.size() < TX_ELEMENT_SIZE_BYTES)
     243              :         {
     244            0 :             break;
     245              :         }
     246            0 :         CANFrame canFrame;
     247            0 :         ::std::memcpy(static_cast<void*>(&canFrame), memory.data(), sizeof(canFrame));
     248            0 :         ICANFrameSentListener* listener = nullptr;
     249            0 :         ::std::memcpy(
     250            0 :             static_cast<void*>(&listener), memory.data() + sizeof(canFrame), sizeof(void*));
     251            0 :         _txReader.release();
     252              :         can_frame socketCanFrame;
     253            0 :         ::std::memset(&socketCanFrame, 0, sizeof(socketCanFrame));
     254            0 :         socketCanFrame.can_id  = canFrame.getId();
     255            0 :         int length             = canFrame.getPayloadLength();
     256            0 :         socketCanFrame.can_dlc = length;
     257            0 :         ::std::memcpy(socketCanFrame.data, canFrame.getPayload(), length);
     258            0 :         ::std::memset(socketCanFrame.data + length, 0, sizeof(socketCanFrame.data) - length);
     259            0 :         ssize_t const bytesWritten = ::write(_fileDescriptor, &socketCanFrame, CAN_MTU);
     260            0 :         if (bytesWritten != CAN_MTU)
     261              :         {
     262            0 :             break;
     263              :         }
     264            0 :         if (listener != nullptr)
     265              :         {
     266            0 :             listener->canFrameSent(canFrame);
     267              :         }
     268            0 :         notifySentListeners(canFrame);
     269              :     }
     270              : 
     271            0 :     for (int count = 0; count < maxReceivedPerRun; ++count)
     272              :     {
     273              :         alignas(can_frame) uint8_t buffer[CANFD_MTU];
     274            0 :         ssize_t const length = read(_fileDescriptor, buffer, CANFD_MTU);
     275            0 :         if (length < 0)
     276              :         {
     277            0 :             break;
     278              :         }
     279            0 :         if (length == CAN_MTU)
     280              :         {
     281              :             // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
     282            0 :             can_frame const& socketCanFrame = *reinterpret_cast<can_frame const*>(buffer);
     283              :             // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg): Logger API is variadic by design.
     284            0 :             Logger::debug(
     285              :                 CAN,
     286              :                 "[SocketCanTransceiver] received CAN frame, id=0x%X, length=%d",
     287            0 :                 static_cast<int>(socketCanFrame.can_id),
     288            0 :                 static_cast<int>(socketCanFrame.can_dlc));
     289            0 :             CANFrame canFrame;
     290            0 :             canFrame.setId(socketCanFrame.can_id);
     291            0 :             canFrame.setPayload(socketCanFrame.data, socketCanFrame.can_dlc);
     292            0 :             canFrame.setPayloadLength(socketCanFrame.can_dlc);
     293            0 :             canFrame.setTimestamp(0);
     294              : 
     295            0 :             notifyListeners(canFrame);
     296              :         }
     297              :     }
     298            0 : }
     299              : 
     300              : } // namespace can
        

Generated by: LCOV version 2.0-1