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

Generated by: LCOV version 2.0-1