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
|