LCOV - code coverage report
Current view: top level - platforms/s32k1xx/bsp/canflex2Transceiver/src/can/transceiver/canflex2 - CanFlex2Transceiver.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 94.7 % 187 177
Test Date: 2026-04-15 11:38:51 Functions: 83.3 % 18 15

            Line data    Source code
       1              : // Copyright 2024 Accenture.
       2              : 
       3              : #include "can/transceiver/canflex2/CanFlex2Transceiver.h"
       4              : 
       5              : #include <async/Types.h>
       6              : #include <can/CanLogger.h>
       7              : #include <can/framemgmt/IFilteredCANFrameSentListener.h>
       8              : #include <common/busid/BusId.h>
       9              : 
      10              : #include <platform/config.h>
      11              : #include <platform/estdint.h>
      12              : 
      13              : #include <etl/delegate.h>
      14              : #include <etl/error_handler.h>
      15              : 
      16              : namespace logger = ::util::logger;
      17              : 
      18              : namespace bios
      19              : {
      20              : CanFlex2Transceiver* CanFlex2Transceiver::fpCanTransceivers[8] = {0};
      21              : 
      22           36 : CanFlex2Transceiver::CanFlex2Transceiver(
      23              :     ::async::ContextType context,
      24              :     uint8_t const busId,
      25              :     FlexCANDevice::Config const& devConfig,
      26              :     CanPhy& Phy,
      27           36 :     IEcuPowerStateController& powerStateController)
      28              : : AbstractCANTransceiver(busId)
      29           36 : , fdevConfig(devConfig)
      30           36 : , fFlexCANDevice(
      31              :       devConfig,
      32              :       Phy,
      33              :       ::etl::delegate<
      34              :           void()>::create<CanFlex2Transceiver, &CanFlex2Transceiver::canFrameSentCallback>(*this),
      35              :       powerStateController)
      36           36 : , fIsPhyErrorPresent(false)
      37           36 : , fTxOfflineErrors(0)
      38           36 : , fOverrunCount(0)
      39           36 : , fFramesSentCount(0)
      40           36 : , fTxQueue()
      41           36 : , fFirstFrameNotified(false)
      42           36 : , fRxAlive(false)
      43           36 : , _context(context)
      44           36 : , _cyclicTask(
      45           36 :       ::async::Function::CallType::create<CanFlex2Transceiver, &CanFlex2Transceiver::cyclicTask>(
      46              :           *this))
      47              : , _cyclicTaskTimeout()
      48           36 : , _canFrameSent(
      49              :       ::async::Function::CallType::
      50           72 :           create<CanFlex2Transceiver, &CanFlex2Transceiver::canFrameSentAsyncCallback>(*this))
      51              : {
      52           36 :     fpCanTransceivers[fFlexCANDevice.getIndex()] = this;
      53           36 : }
      54              : 
      55           37 : ::can::ICanTransceiver::ErrorCode CanFlex2Transceiver::init()
      56              : {
      57           37 :     if (State::CLOSED == _state)
      58              :     {
      59              :         {
      60           36 :             ::async::LockType const lock;
      61           36 :             if (ErrorCode::CAN_ERR_INIT_FAILED == fFlexCANDevice.init())
      62              :             {
      63            1 :                 return ErrorCode::CAN_ERR_INIT_FAILED;
      64              :             }
      65           36 :         }
      66           35 :         (void)fFlexCANDevice.getPhy().setMode(CanPhy::CAN_PHY_MODE_ACTIVE, fdevConfig.BusId);
      67           35 :         _state = State::INITIALIZED;
      68           35 :         return ErrorCode::CAN_ERR_OK;
      69              :     }
      70            1 :     return ErrorCode::CAN_ERR_ILLEGAL_STATE;
      71              : }
      72              : 
      73            8 : ::can::ICanTransceiver::ErrorCode CanFlex2Transceiver::write(::can::CANFrame const& frame)
      74              : {
      75            8 :     return write(frame, nullptr);
      76              : }
      77              : 
      78              : ::can::ICanTransceiver::ErrorCode
      79           19 : CanFlex2Transceiver::write(::can::CANFrame const& frame, ::can::ICANFrameSentListener& listener)
      80              : {
      81           19 :     return write(frame, &listener);
      82              : }
      83              : 
      84           27 : ::can::ICanTransceiver::ErrorCode CanFlex2Transceiver::write(
      85              :     ::can::CANFrame const& frame, ::can::ICANFrameSentListener* const pListener)
      86              : {
      87           27 :     if (State::MUTED == _state)
      88              :     {
      89              :         // Logger API is variadic by design.
      90              :         // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
      91            1 :         logger::Logger::warn(
      92              :             logger::CAN,
      93              :             "Write Id 0x%x to muted %s",
      94              :             frame.getId(),
      95            1 :             ::common::busid::BusIdTraits::getName(_busId));
      96            1 :         return ErrorCode::CAN_ERR_ILLEGAL_STATE;
      97              :     }
      98           26 :     if (State::CLOSED == _state)
      99              :     {
     100            1 :         fTxOfflineErrors++;
     101            1 :         return ErrorCode::CAN_ERR_TX_OFFLINE;
     102              :     }
     103              : 
     104           25 :     ::async::ModifiableLockType mlock;
     105           25 :     if (pListener == nullptr)
     106              :     {
     107            6 :         uint8_t const messageBuffer = fFlexCANDevice.getTransmitBuffer(frame, false);
     108            6 :         if (FlexCANDevice::TRANSMIT_BUFFER_UNAVAILABLE == messageBuffer)
     109              :         {
     110            1 :             fOverrunCount++;
     111            1 :             mlock.unlock();
     112            1 :             notifyRegisteredSentListener(frame);
     113            1 :             return ErrorCode::CAN_ERR_TX_HW_QUEUE_FULL;
     114              :         }
     115              : 
     116            5 :         ErrorCode const status = fFlexCANDevice.transmit(frame, messageBuffer, false);
     117            5 :         if (ErrorCode::CAN_ERR_OK == status)
     118              :         {
     119            4 :             fFramesSentCount++;
     120            4 :             mlock.unlock();
     121            4 :             notifyRegisteredSentListener(frame);
     122            4 :             return ErrorCode::CAN_ERR_OK;
     123              :         }
     124            1 :         mlock.unlock();
     125            1 :         notifyRegisteredSentListener(frame);
     126            1 :         return ErrorCode::CAN_ERR_TX_FAIL;
     127              :     }
     128              : 
     129           19 :     if (fTxQueue.full())
     130              :     {
     131              :         // no more room for a sender with callback
     132            1 :         fOverrunCount++;
     133            1 :         mlock.unlock();
     134            1 :         notifyRegisteredSentListener(frame);
     135            1 :         return ErrorCode::CAN_ERR_TX_HW_QUEUE_FULL;
     136              :     }
     137           18 :     bool const wasEmpty = fTxQueue.empty();
     138           18 :     fTxQueue.emplace_back(*pListener, frame);
     139           18 :     if (!wasEmpty)
     140              :     {
     141              :         // nothing to do next frame will be sent from tx isr
     142            7 :         return ErrorCode::CAN_ERR_OK;
     143              :     }
     144              :     ErrorCode status;
     145              :     // we are the first sender --> transmit
     146           11 :     uint8_t const messageBuffer = fFlexCANDevice.getTransmitBuffer(frame, true);
     147           11 :     if (messageBuffer != FlexCANDevice::TRANSMIT_BUFFER_UNAVAILABLE)
     148              :     {
     149           10 :         status = fFlexCANDevice.transmit(frame, messageBuffer, true);
     150           10 :         if (ErrorCode::CAN_ERR_OK == status)
     151              :         {
     152              :             // wait until tx interrupt ...
     153              :             // ... then canFrameSentCallback() is called
     154            8 :             return ErrorCode::CAN_ERR_OK;
     155              :         }
     156            2 :         status = ErrorCode::CAN_ERR_TX_FAIL;
     157              :     }
     158              :     else
     159              :     {
     160            1 :         status = ErrorCode::CAN_ERR_TX_HW_QUEUE_FULL;
     161              :     }
     162            3 :     fTxQueue.pop_front();
     163            3 :     mlock.unlock();
     164            3 :     notifyRegisteredSentListener(frame);
     165            3 :     return status;
     166           25 : }
     167              : 
     168            7 : void CanFlex2Transceiver::canFrameSentCallback() { ::async::execute(_context, _canFrameSent); }
     169              : 
     170            7 : void CanFlex2Transceiver::canFrameSentAsyncCallback()
     171              : {
     172            7 :     ::async::ModifiableLockType mlock;
     173            7 :     fFramesSentCount++;
     174            7 :     if (!fTxQueue.empty())
     175              :     {
     176            5 :         bool sendAgain = false;
     177              :         {
     178            5 :             TxJobWithCallback& job                 = fTxQueue.front();
     179            5 :             ::can::CANFrame const& frame           = job._frame;
     180            5 :             ::can::ICANFrameSentListener& listener = job._listener;
     181            5 :             fTxQueue.pop_front();
     182            5 :             if (!fTxQueue.empty())
     183              :             {
     184              :                 // send again only if same precondition as for write() is satisfied!
     185            4 :                 if ((State::OPEN == _state) || (State::INITIALIZED == _state))
     186              :                 {
     187            4 :                     sendAgain = true;
     188              :                 }
     189              :                 else
     190              :                 {
     191            0 :                     fTxQueue.clear();
     192              :                 }
     193              :             }
     194            5 :             mlock.unlock();
     195            5 :             listener.canFrameSent(frame);
     196            5 :             notifyRegisteredSentListener(frame);
     197              :         }
     198            5 :         if (sendAgain)
     199              :         {
     200            4 :             mlock.lock();
     201            4 :             ::can::CANFrame const& frame = fTxQueue.front()._frame;
     202            4 :             uint8_t const messageBuffer  = fFlexCANDevice.getTransmitBuffer(frame, true);
     203            4 :             if (FlexCANDevice::TRANSMIT_BUFFER_UNAVAILABLE != messageBuffer)
     204              :             {
     205            3 :                 ErrorCode const status = fFlexCANDevice.transmit(frame, messageBuffer, true);
     206            3 :                 if (ErrorCode::CAN_ERR_OK == status)
     207              :                 {
     208              :                     // wait until tx interrupt ...
     209              :                     // ... then canFrameSentCallback() is called
     210            2 :                     return;
     211              :                 }
     212              :             }
     213              :             // no interrupt will ever retrigger this call => remove all queued frames
     214            2 :             fTxQueue.clear();
     215            2 :             mlock.unlock();
     216            2 :             notifyRegisteredSentListener(frame);
     217              :         }
     218              :     }
     219            7 : }
     220              : 
     221            0 : uint16_t CanFlex2Transceiver::getHwQueueTimeout() const
     222              : {
     223              :     // 64 = 8 byte payload
     224              :     // 53 = CAN overhead
     225              :     // NOLINTNEXTLINE(clang-analyzer-core.DivideZero): CAN Baudrate can never be zero here.
     226            0 :     auto const timeout = ((53U + 64U) * 1000U / (fFlexCANDevice.getBaudrate()));
     227            0 :     return static_cast<uint16_t>(timeout);
     228              : }
     229              : 
     230            1 : uint16_t CanFlex2Transceiver::getFirstFrameId() const
     231              : {
     232            1 :     return static_cast<uint16_t>(fFlexCANDevice.getFirstCanId());
     233              : }
     234              : 
     235            1 : void CanFlex2Transceiver::resetFirstFrame()
     236              : {
     237            1 :     fFlexCANDevice.resetFirstFrame();
     238            1 :     fFirstFrameNotified = false;
     239            1 : }
     240              : 
     241            0 : ::can::ICanTransceiver::ErrorCode CanFlex2Transceiver::open(::can::CANFrame const& /* frame */)
     242              : {
     243              :     // not implemented
     244            0 :     ETL_ASSERT_FAIL(ETL_ERROR_GENERIC("not implemented"));
     245              :     return ::can::ICanTransceiver::ErrorCode::CAN_ERR_ILLEGAL_STATE;
     246              : }
     247              : 
     248           15 : ::can::ICanTransceiver::ErrorCode CanFlex2Transceiver::open()
     249              : {
     250           15 :     bool const isStateValid = (State::INITIALIZED == _state) || (State::CLOSED == _state);
     251           15 :     if (isStateValid && (ErrorCode::CAN_ERR_OK == fFlexCANDevice.start()))
     252              :     {
     253           14 :         (void)fFlexCANDevice.getPhy().setMode(CanPhy::CAN_PHY_MODE_ACTIVE, fdevConfig.BusId);
     254           14 :         _state = State::OPEN;
     255              : 
     256           14 :         ::async::scheduleAtFixedRate(
     257           14 :             _context,
     258              :             _cyclicTask,
     259           14 :             _cyclicTaskTimeout,
     260              :             ERROR_POLLING_TIMEOUT,
     261              :             ::async::TimeUnitType::MILLISECONDS);
     262              : 
     263           14 :         return ErrorCode::CAN_ERR_OK;
     264              :     }
     265              : 
     266            1 :     return ErrorCode::CAN_ERR_ILLEGAL_STATE;
     267              : }
     268              : 
     269            4 : ::can::ICanTransceiver::ErrorCode CanFlex2Transceiver::close()
     270              : {
     271            4 :     if ((State::OPEN == _state) || (State::MUTED == _state))
     272              :     {
     273            3 :         fFlexCANDevice.stop();
     274            3 :         (void)fFlexCANDevice.getPhy().setMode(CanPhy::CAN_PHY_MODE_STANDBY, fdevConfig.BusId);
     275              : 
     276            3 :         _cyclicTaskTimeout.cancel();
     277              : 
     278            3 :         _state = State::CLOSED;
     279              :         {
     280            3 :             ::async::LockType const lock;
     281            3 :             fTxQueue.clear();
     282            3 :         }
     283            3 :         return ErrorCode::CAN_ERR_OK;
     284              :     }
     285              : 
     286            1 :     return ErrorCode::CAN_ERR_ILLEGAL_STATE;
     287              : }
     288              : 
     289            0 : void CanFlex2Transceiver::shutdown()
     290              : {
     291            0 :     (void)close();
     292            0 :     _cyclicTaskTimeout.cancel();
     293            0 : }
     294              : 
     295            8 : ::can::ICanTransceiver::ErrorCode CanFlex2Transceiver::mute()
     296              : {
     297            8 :     if (State::OPEN == _state)
     298              :     {
     299            6 :         fFlexCANDevice.mute();
     300              :         {
     301            6 :             async::LockType const lock;
     302            6 :             fTxQueue.clear();
     303            6 :         }
     304            6 :         _state = State::MUTED;
     305            6 :         return ErrorCode::CAN_ERR_OK;
     306              :     }
     307              : 
     308            2 :     return ErrorCode::CAN_ERR_ILLEGAL_STATE;
     309              : }
     310              : 
     311            2 : ::can::ICanTransceiver::ErrorCode CanFlex2Transceiver::unmute()
     312              : {
     313            2 :     if (State::MUTED == _state)
     314              :     {
     315            1 :         fFlexCANDevice.unmute();
     316            1 :         _state = State::OPEN;
     317            1 :         return ErrorCode::CAN_ERR_OK;
     318              :     }
     319              : 
     320            1 :     return ErrorCode::CAN_ERR_ILLEGAL_STATE;
     321              : }
     322              : 
     323            2 : void CanFlex2Transceiver::receiveTask()
     324              : {
     325            2 :     ::async::ModifiableLockType mlock;
     326            3 :     while (!fFlexCANDevice.isRxQueueEmpty())
     327              :     {
     328            1 :         ::can::CANFrame& frame = fFlexCANDevice.getRxFrameQueueFront();
     329            1 :         mlock.unlock();
     330            1 :         notifyListeners(frame);
     331            1 :         mlock.lock();
     332            1 :         fFlexCANDevice.dequeueRxFrame();
     333              :     }
     334            2 : }
     335              : 
     336           10 : void CanFlex2Transceiver::cyclicTask()
     337              : {
     338           10 :     if (fFlexCANDevice.getBusOffState() == FlexCANDevice::BUS_OFF)
     339              :     {
     340            2 :         if (_transceiverState != ::can::ICANTransceiverStateListener::CANTransceiverState::BUS_OFF)
     341              :         {
     342            2 :             _transceiverState = ::can::ICANTransceiverStateListener::CANTransceiverState::BUS_OFF;
     343            2 :             notifyStateListenerWithState(_transceiverState);
     344              :         }
     345              :     }
     346              :     else
     347              :     {
     348            8 :         if (_transceiverState != ::can::ICANTransceiverStateListener::CANTransceiverState::ACTIVE)
     349              :         {
     350            2 :             _transceiverState = ::can::ICANTransceiverStateListener::CANTransceiverState::ACTIVE;
     351            2 :             notifyStateListenerWithState(_transceiverState);
     352              :         }
     353              :     }
     354              : 
     355           10 :     CanPhy::ErrorCode const phyState = fFlexCANDevice.getPhy().getPhyErrorStatus(fdevConfig.BusId);
     356              : 
     357           10 :     if (phyState != CanPhy::CAN_PHY_ERROR_UNSUPPORTED)
     358              :     {
     359            9 :         if (phyState == CanPhy::CAN_PHY_ERROR)
     360              :         {
     361            2 :             if (!fIsPhyErrorPresent)
     362              :             {
     363            1 :                 fIsPhyErrorPresent = true;
     364            1 :                 notifyStateListenerWithPhyError();
     365              :             }
     366              :         }
     367              :         else
     368              :         {
     369            7 :             fIsPhyErrorPresent = false;
     370              :         }
     371              :     }
     372              :     // Check whether CAN was active since last poll
     373           10 :     if (fFlexCANDevice.getRxAlive() != 0)
     374              :     {
     375            6 :         fRxAlive = true;
     376              :     }
     377              :     else
     378              :     {
     379            4 :         fRxAlive = false;
     380              :     }
     381           10 :     fFlexCANDevice.clearRxAlive();
     382           10 : }
     383              : 
     384              : } // namespace bios
        

Generated by: LCOV version 2.0-1