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

Generated by: LCOV version 2.0-1