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.1 % 188 177
Test Date: 2026-02-24 11:21:15 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            0 :     auto const timeout = ((53U + 64U) * 1000U / (fFlexCANDevice.getBaudrate()));
     224            0 :     return static_cast<uint16_t>(timeout);
     225              : }
     226              : 
     227            1 : uint16_t CanFlex2Transceiver::getFirstFrameId() const
     228              : {
     229            1 :     return static_cast<uint16_t>(fFlexCANDevice.getFirstCanId());
     230              : }
     231              : 
     232            1 : void CanFlex2Transceiver::resetFirstFrame()
     233              : {
     234            1 :     fFlexCANDevice.resetFirstFrame();
     235            1 :     fFirstFrameNotified = false;
     236            1 : }
     237              : 
     238            0 : ::can::ICanTransceiver::ErrorCode CanFlex2Transceiver::open(::can::CANFrame const& /* frame */)
     239              : {
     240              :     // not implemented
     241            0 :     ETL_ASSERT_FAIL(ETL_ERROR_GENERIC("not implemented"));
     242              :     return ::can::ICanTransceiver::ErrorCode::CAN_ERR_ILLEGAL_STATE;
     243              : }
     244              : 
     245           15 : ::can::ICanTransceiver::ErrorCode CanFlex2Transceiver::open()
     246              : {
     247           15 :     if ((State::INITIALIZED == _state) || (State::CLOSED == _state))
     248              :     {
     249           14 :         if (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              :         else
     264              :         {
     265            0 :             return ErrorCode::CAN_ERR_ILLEGAL_STATE;
     266              :         }
     267              :     }
     268              :     else
     269              :     {
     270            1 :         return ErrorCode::CAN_ERR_ILLEGAL_STATE;
     271              :     }
     272              : }
     273              : 
     274            4 : ::can::ICanTransceiver::ErrorCode CanFlex2Transceiver::close()
     275              : {
     276            4 :     if ((State::OPEN == _state) || (State::MUTED == _state))
     277              :     {
     278            3 :         fFlexCANDevice.stop();
     279            3 :         (void)fFlexCANDevice.getPhy().setMode(CanPhy::CAN_PHY_MODE_STANDBY, fdevConfig.BusId);
     280              : 
     281            3 :         _cyclicTaskTimeout.cancel();
     282              : 
     283            3 :         _state = State::CLOSED;
     284              :         {
     285            3 :             ::async::LockType const lock;
     286            3 :             fTxQueue.clear();
     287            3 :         }
     288            3 :         return ErrorCode::CAN_ERR_OK;
     289              :     }
     290              :     else
     291              :     {
     292            1 :         return ErrorCode::CAN_ERR_ILLEGAL_STATE;
     293              :     }
     294              : }
     295              : 
     296            0 : void CanFlex2Transceiver::shutdown()
     297              : {
     298            0 :     (void)close();
     299            0 :     _cyclicTaskTimeout.cancel();
     300            0 : }
     301              : 
     302            8 : ::can::ICanTransceiver::ErrorCode CanFlex2Transceiver::mute()
     303              : {
     304            8 :     if (State::OPEN == _state)
     305              :     {
     306            6 :         fFlexCANDevice.mute();
     307              :         {
     308            6 :             async::LockType const lock;
     309            6 :             fTxQueue.clear();
     310            6 :         }
     311            6 :         _state = State::MUTED;
     312            6 :         return ErrorCode::CAN_ERR_OK;
     313              :     }
     314              :     else
     315              :     {
     316            2 :         return ErrorCode::CAN_ERR_ILLEGAL_STATE;
     317              :     }
     318              : }
     319              : 
     320            2 : ::can::ICanTransceiver::ErrorCode CanFlex2Transceiver::unmute()
     321              : {
     322            2 :     if (State::MUTED == _state)
     323              :     {
     324            1 :         fFlexCANDevice.unmute();
     325            1 :         _state = State::OPEN;
     326            1 :         return ErrorCode::CAN_ERR_OK;
     327              :     }
     328              :     else
     329              :     {
     330            1 :         return ErrorCode::CAN_ERR_ILLEGAL_STATE;
     331              :     }
     332              : }
     333              : 
     334            2 : void CanFlex2Transceiver::receiveTask()
     335              : {
     336            2 :     ::async::ModifiableLockType mlock;
     337            3 :     while (!fFlexCANDevice.isRxQueueEmpty())
     338              :     {
     339            1 :         ::can::CANFrame& frame = fFlexCANDevice.getRxFrameQueueFront();
     340            1 :         mlock.unlock();
     341            1 :         notifyListeners(frame);
     342            1 :         mlock.lock();
     343            1 :         fFlexCANDevice.dequeueRxFrame();
     344              :     }
     345            2 : }
     346              : 
     347           10 : void CanFlex2Transceiver::cyclicTask()
     348              : {
     349           10 :     if (fFlexCANDevice.getBusOffState() == FlexCANDevice::BUS_OFF)
     350              :     {
     351            2 :         if (_transceiverState != ::can::ICANTransceiverStateListener::CANTransceiverState::BUS_OFF)
     352              :         {
     353            2 :             _transceiverState = ::can::ICANTransceiverStateListener::CANTransceiverState::BUS_OFF;
     354            2 :             notifyStateListenerWithState(_transceiverState);
     355              :         }
     356              :     }
     357              :     else
     358              :     {
     359            8 :         if (_transceiverState != ::can::ICANTransceiverStateListener::CANTransceiverState::ACTIVE)
     360              :         {
     361            2 :             _transceiverState = ::can::ICANTransceiverStateListener::CANTransceiverState::ACTIVE;
     362            2 :             notifyStateListenerWithState(_transceiverState);
     363              :         }
     364              :     }
     365              : 
     366           10 :     CanPhy::ErrorCode const phyState = fFlexCANDevice.getPhy().getPhyErrorStatus(fdevConfig.BusId);
     367              : 
     368           10 :     if (phyState != CanPhy::CAN_PHY_ERROR_UNSUPPORTED)
     369              :     {
     370            9 :         if (phyState == CanPhy::CAN_PHY_ERROR)
     371              :         {
     372            2 :             if (!fIsPhyErrorPresent)
     373              :             {
     374            1 :                 fIsPhyErrorPresent = true;
     375            1 :                 notifyStateListenerWithPhyError();
     376              :             }
     377              :         }
     378              :         else
     379              :         {
     380            7 :             fIsPhyErrorPresent = false;
     381              :         }
     382              :     }
     383              :     // Check whether CAN was active since last poll
     384           10 :     if (fFlexCANDevice.getRxAlive() != 0)
     385              :     {
     386            6 :         fRxAlive = true;
     387              :     }
     388              :     else
     389              :     {
     390            4 :         fRxAlive = false;
     391              :     }
     392           10 :     fFlexCANDevice.clearRxAlive();
     393           10 : }
     394              : 
     395              : } // namespace bios
        

Generated by: LCOV version 2.0-1