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
|