rusEFI
The most advanced open source ECU
Loading...
Searching...
No Matches
can_hw.cpp
Go to the documentation of this file.
1/**
2 * @file can_hw.cpp
3 * @brief CAN bus low level code
4 *
5 * todo: this file should be split into two - one for CAN transport level ONLY and
6 * another one with actual messages
7 *
8 * @see can_verbose.cpp for higher level logic
9 * @see obd2.cpp for OBD-II messages via CAN
10 *
11 * @date Dec 11, 2013
12 * @author Andrey Belomutskiy, (c) 2012-2020
13 */
14
15#include "pch.h"
16
17#if EFI_CAN_SUPPORT
18
19#include "can.h"
20#include "can_hw.h"
21#include "can_msg_tx.h"
22#include "string.h"
23#include "mpu_util.h"
24
25static bool isCanEnabled = false;
26
27#if EFI_PROD_CODE
28
29extern const CANConfig *findCanConfig(can_baudrate_e rate);
30
31#else // not EFI_PROD_CODE
32// Nothing to actually set for the simulator's CAN config.
33// It's impossible to set CAN bitrate from userspace, so we can't set it.
34static const CANConfig canConfig_dummy;
35
36static const CANConfig * findCanConfig(can_baudrate_e rate)
37{
38 return &canConfig_dummy;
39}
40
41#endif
42
43class CanRead final : protected ThreadController<UTILITY_THREAD_STACK_SIZE> {
44public:
45 CanRead(size_t index)
46 : ThreadController("CAN RX", PRIO_CAN_RX)
47 , m_index(index)
48 {
49 }
50
51 void start(CANDriver* device) {
52 m_device = device;
53
54 if (device) {
56 }
57 }
58
59 void ThreadTask() override {
60 while (true) {
61 // Block until we get a message
62 msg_t result = canReceiveTimeout(m_device, CAN_ANY_MAILBOX, &m_buffer, CAN_RX_TIMEOUT);
63
64 if (result != MSG_OK) {
65 canHwRecover(m_index, m_device);
66 continue;
67 }
68
69 // Process the message
71
72 processCanRxMessage(m_index, m_buffer, getTimeNowNt());
73 }
74 }
75
76private:
77 const size_t m_index;
78 CANRxFrame m_buffer;
79 CANDriver* m_device;
80};
81
82CCM_OPTIONAL static CanRead canRead1(0);
83CCM_OPTIONAL static CanRead canRead2(1);
84#if (EFI_CAN_BUS_COUNT >= 3)
85CCM_OPTIONAL static CanRead canRead3(2);
86#endif
87static CanWrite canWrite CCM_OPTIONAL;
88
89#if EFI_PROD_CODE
90static CANDriver* getCanDevice(size_t index)
91{
92 switch (index) {
93 case 0:
95 case 1:
97#if (EFI_CAN_BUS_COUNT >= 3)
98 case 2:
100#endif
101 }
102
103 return nullptr;
104}
105#endif
106
107int txErrorCount[EFI_CAN_BUS_COUNT] = {};
108
109static void canInfo() {
110 if (!isCanEnabled) {
111 efiPrintf("CAN is not enabled, please enable & restart");
112 return;
113 }
114
116 efiPrintf("CAN1 RX %s", hwPortname(engineConfiguration->canRxPin));
118
120 efiPrintf("CAN2 RX %s", hwPortname(engineConfiguration->can2RxPin));
122
123#if (EFI_CAN_BUS_COUNT >= 3)
125 efiPrintf("CAN3 RX %s", hwPortname(engineConfiguration->can3RxPin));
127#endif
128
129 efiPrintf("type=%d canReadEnabled=%s canWriteEnabled=%s period=%d", engineConfiguration->canNbcType,
132
133 efiPrintf("CAN rx_cnt=%d/tx_ok=%d/tx_not_ok=%d",
137}
138
139void setCanType(int type) {
141 canInfo();
142}
143
145 efiSetPadUnusedIfConfigurationChanged(canTxPin);
146 efiSetPadUnusedIfConfigurationChanged(canRxPin);
147 efiSetPadUnusedIfConfigurationChanged(can2TxPin);
148 efiSetPadUnusedIfConfigurationChanged(can2RxPin);
149#if (EFI_CAN_BUS_COUNT >= 3)
150 efiSetPadUnusedIfConfigurationChanged(can3TxPin);
151 efiSetPadUnusedIfConfigurationChanged(can3RxPin);
152#endif
153}
154
155// at the moment we support only very limited runtime configuration change, still not supporting online CAN toggle
157 // nothing to do if we aren't enabled...
158 if (!isCanEnabled) {
159 return;
160 }
161
162 // Validate pins
165 // todo: smarter online change of settings, kill isCanEnabled with fire
166 return;
167 }
169 return;
170 }
171
174 // todo: smarter online change of settings, kill isCanEnabled with fire
175 return;
176 }
178 return;
179 }
180
181#if EFI_PROD_CODE
182 efiSetPadModeIfConfigurationChanged("CAN TX", canTxPin, PAL_MODE_ALTERNATE(EFI_CAN_TX_AF));
183 efiSetPadModeIfConfigurationChanged("CAN RX", canRxPin, PAL_MODE_ALTERNATE(EFI_CAN_RX_AF));
184
185 efiSetPadModeIfConfigurationChanged("CAN2 TX", can2TxPin, PAL_MODE_ALTERNATE(EFI_CAN_TX_AF));
186 efiSetPadModeIfConfigurationChanged("CAN2 RX", can2RxPin, PAL_MODE_ALTERNATE(EFI_CAN_RX_AF));
187
188#if (EFI_CAN_BUS_COUNT >= 3)
189 efiSetPadModeIfConfigurationChanged("CAN3 TX", can3TxPin, PAL_MODE_ALTERNATE(EFI_CAN3_TX_AF));
190 efiSetPadModeIfConfigurationChanged("CAN3 RX", can3RxPin, PAL_MODE_ALTERNATE(EFI_CAN3_RX_AF));
191#endif // EFI_CAN_BUS_COUNT >= 3
192#endif // EFI_PROD_CODE
193}
194
195// Move to port CAN helpers file
196static void applyListenOnly(CANConfig* canConfig, bool isListenOnly) {
197#if defined(STM32F4XX) || defined(STM32F7XX)
198 if (isListenOnly) {
199 canConfig->btr |= CAN_BTR_SILM;
200 }
201#elif defined(STM32H7XX)
202 // TODO: move to ChibiOS stm32_fdcan.h
203 #define FDCAN_CONFIG_CCCR_MON (1u << 5)
204 if (isListenOnly) {
205 canConfig->CCCR |= FDCAN_CONFIG_CCCR_MON;
206 }
207#endif
208}
209
210void initCan() {
211 addConsoleAction("caninfo", canInfo);
212
213 isCanEnabled = false;
214
215 // No CAN features enabled, nothing more to do.
217 return;
218 }
219
220 // Determine physical CAN peripherals based on selected pins
221 auto device1 = getCanDevice(0);
222 auto device2 = getCanDevice(1);
223#if (EFI_CAN_BUS_COUNT >= 3)
224 auto device3 = getCanDevice(2);
225#endif
226
227 // If all devices are null, a firmware error was already thrown by detectCanDevice, but we shouldn't continue
228 if (!device1 && !device2) {
229#if (EFI_CAN_BUS_COUNT >= 3)
230 if (!device3)
231#endif
232 return;
233 }
234
235 // Devices can't be the same!
236 if (((device1 == device2) && device1) ||
237#if (EFI_CAN_BUS_COUNT >= 3)
238 ((device2 == device3) && device2) ||
239 ((device3 == device1) && device3) ||
240#endif
241 0) {
242 criticalError("CAN pins must be set to different devices");
243 return;
244 }
245
246 // Initialize peripherals
247 if (device1) {
248 // Config based on baud rate
249 // Pointer to this local canConfig is stored inside CANDriver
250 // even it is used only during canStart this is wierd
251 CANConfig canConfig;
252 memcpy(&canConfig, findCanConfig(engineConfiguration->canBaudRate), sizeof(canConfig));
254 canStart(device1, &canConfig);
255
256 // Plumb CAN devices to tx system
257 CanTxMessage::setDevice(0, device1);
258 }
259
260 if (device2) {
261 CANConfig canConfig;
262 memcpy(&canConfig, findCanConfig(engineConfiguration->can2BaudRate), sizeof(canConfig));
264 canStart(device2, &canConfig);
265
266 // Plumb CAN devices to tx system
267 CanTxMessage::setDevice(1, device2);
268 }
269
270#if (EFI_CAN_BUS_COUNT >= 3)
271 if (device3) {
272 CANConfig canConfig;
273 memcpy(&canConfig, findCanConfig(engineConfiguration->can3BaudRate), sizeof(canConfig));
275 canStart(device3, &canConfig);
276
277 // Plumb CAN devices to tx system
278 CanTxMessage::setDevice(2, device3);
279 }
280#endif
281
282 // fire up threads, as necessary
284 canWrite.start();
285 }
286
288 canRead1.start(device1);
289 canRead2.start(device2);
290#if (EFI_CAN_BUS_COUNT >= 3)
291 canRead3.start(device3);
292#endif
293 }
294
295 isCanEnabled = true;
296}
297
298bool getIsCanEnabled(void) {
299 return isCanEnabled;
300}
301
302#endif /* EFI_CAN_SUPPORT */
CANDriver * detectCanDevice(brain_pin_e pinRx, brain_pin_e pinTx)
Definition at32_can.cpp:93
bool isValidCanRxPin(brain_pin_e pin)
Definition at32_can.cpp:89
void canHwRecover(const size_t, CANDriver *)
Definition at32_can.cpp:135
bool isValidCanTxPin(brain_pin_e pin)
Definition at32_can.cpp:85
void canHwInfo(CANDriver *cand)
Definition at32_can.cpp:129
const char * getCan_baudrate_e(can_baudrate_e value)
uint32_t rate
Definition bluetooth.cpp:39
void processCanRxMessage(const size_t busIndex, const CANRxFrame &msg, efitick_t nowNt)
Definition can_rx.cpp:227
void stopCanPins()
Definition can_hw.cpp:144
bool getIsCanEnabled(void)
Definition can_hw.cpp:298
static bool isCanEnabled
Definition can_hw.cpp:25
static void applyListenOnly(CANConfig *canConfig, bool isListenOnly)
Definition can_hw.cpp:196
void initCan()
Definition can_hw.cpp:210
static void canInfo()
Definition can_hw.cpp:109
static CCM_OPTIONAL CanRead canRead1(0)
static CANDriver * getCanDevice(size_t index)
Definition can_hw.cpp:90
int txErrorCount[EFI_CAN_BUS_COUNT]
Definition can_hw.cpp:107
static CCM_OPTIONAL CanRead canRead3(2)
void startCanPins()
Definition can_hw.cpp:156
void setCanType(int type)
Definition can_hw.cpp:139
static CanWrite canWrite CCM_OPTIONAL
Definition can_hw.cpp:87
static CCM_OPTIONAL CanRead canRead2(1)
static const CANConfig canConfig_dummy
Definition can_hw.cpp:34
const CANConfig * findCanConfig(can_baudrate_e rate)
Definition can_hw.cpp:36
static void setDevice(size_t idx, CANDriver *device)
Definition can.h:67
TunerStudioOutputChannels outputChannels
Definition engine.h:113
A base class for a controller that requires its own thread.
virtual void ThreadTask()=0
void start()
Start the thread.
void addConsoleAction(const char *token, Void callback)
Register console action without parameters.
const char * boolToString(bool value)
Definition efilib.cpp:19
efitick_t getTimeNowNt()
Definition efitime.cpp:19
static EngineAccessor engine
Definition engine.h:415
static constexpr engine_configuration_s * engineConfiguration
void firmwareError(ObdCode code, const char *fmt,...)
static Lps25 device
Definition init_baro.cpp:4
@ CUSTOM_OBD_70
const char * hwPortname(brain_pin_e brainPin)
bool isBrainPinValid(brain_pin_e brainPin)
can_baudrate_e
can_nbc_e