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
|