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-10-01 16:17:37 Functions: 83.3 % 18 15

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

Generated by: LCOV version 2.0-1