SAE Teensy ECU
IIT SAE Microcontroller programming
Loading...
Searching...
No Matches
Canbus.cpp
Go to the documentation of this file.
1
12// @cond
13
14#include "Canbus.h"
15#include "CanBusAddresses.def"
16#include "CanbusConfig.def"
17#include "ECUGlobalConfig.h"
18#include "Log.h"
19#include "SDBC.def"
20
21// IMPROVE: look into filtering only addresses we care about, if it is hardware filtering this should help with bandwidth
22
23namespace CAN {
24static const int TX_MAILBOXES = CONFIG_FLEXCAN_TX_MAILBOXES;
25
26FlexCAN_T4<CONFIG_FLEXCAN_CAN_SELECT, RX_SIZE_256, TX_SIZE_16> F_Can;
27
28volatile uint8_t buffer[CAN_MESSAGE_COUNT + 1][8];
29
30#define __BUF_INTERNAL true
31#define __BUF_EXTERNAL false
32static Buffer buffers[CAN_MESSAGE_COUNT + 1] = {
33#define MSG(c, addr, name, sig_c, sig_def, ie_t, contained) Buffer(addr, (volatile uint8_t *)buffer[c], CONCAT(__BUF_, ie_t)),
34 CAN_MESSAGES
35#undef MSG
36 Buffer(0, (volatile uint8_t *)buffer[CAN_MESSAGE_COUNT]),
37};
38
39static Buffer *invalidBuf = buffers + CAN_MESSAGE_COUNT;
40
41// Reserved msg objs for sending and receiving
42static CAN_message_t receive;
43static Thread::Mutex mux_send;
44static CAN_message_t send;
45static bool started = false;
46
47// FlexCan Callback function
48static void _receiveCan(const CAN_message_t &msg) {
49 Buffer *buf = Canbus_t::getBuffer(msg.id);
50
51 if (buf == invalidBuf || !buf->lock()) {
52#ifdef CONF_ECU_DEBUG
53 Log.w(Canbus_t::ID, "Discarding can msg", msg.id);
54#endif
55 return;
56 }
57
58 buf->set(msg.buf);
59 if (buf->callback)
60 buf->callback(msg.id, buf->buffer);
61 buf->unlock();
62}
63
64constexpr Buffer *Canbus_t::getBuffer(const uint32_t address) {
65 switch (address) {
66#define MSG(c, addr, name, sig_c, sig_def, ie_t, contained) \
67 case addr: \
68 return buffers + c;
69 CAN_MESSAGES
70#undef MSG
71 default:
72 return invalidBuf; // Out of range index
73 }
74}
75
76void Canbus_t::setCallback(const uint32_t address, canCallback callback) {
77 Buffer *buf = getBuffer(address);
78 if (buf == invalidBuf) {
79 Log.e(ID, "Address has not been allocated: ", address);
80 return;
81 }
82
83 buf->lock_wait();
84 buf->callback = callback;
85 buf->unlock();
86}
87
88void Canbus_t::enableInterrupts(bool enable) {
89 F_Can.enableMBInterrupts(enable);
90
91#ifdef CONF_ECU_DEBUG
92 if (enable) {
93 Log.d(ID, "Interrupts enabled");
94 } else {
95 Log.d(ID, "Interrupts disabled");
96 }
97#endif
98}
99
100void Canbus_t::sendData(Buffer &buf) {
101 mux_send.lock();
102 buf.lock_wait();
103 send.id = buf.address;
104 buf.dump(send.buf);
105 buf.unlock();
106 F_Can.write(send);
107 mux_send.unlock();
108}
109
110void Canbus_t::sendData(const uint32_t address, uint8_t buf[8]) {
111 mux_send.lock();
112 send.id = address;
113 memcpy(send.buf, buf, 8); // 8 Bytes
114 F_Can.write(send);
115 mux_send.unlock();
116}
117
118void Canbus_t::sendData(const uint32_t address, const uint8_t buf_0, const uint8_t buf_1, const uint8_t buf_2, const uint8_t buf_3, const uint8_t buf_4, const uint8_t buf_5, const uint8_t buf_6, const uint8_t buf_7) {
119 mux_send.lock();
120 send.id = address;
121 send.buf[0] = buf_0;
122 send.buf[1] = buf_1;
123 send.buf[2] = buf_2;
124 send.buf[3] = buf_3;
125 send.buf[4] = buf_4;
126 send.buf[5] = buf_5;
127 send.buf[6] = buf_6;
128 send.buf[7] = buf_7;
129 F_Can.write(send);
130 mux_send.unlock();
131}
132
133static void _canSniff(const CAN_message_t &msg) {
134 _receiveCan(msg);
135 Serial.print(" ID: ");
136 Serial.print(msg.id, HEX);
137 Serial.print(" Buffer: ");
138 for (uint8_t i = 0; i < msg.len; i++) {
139 Serial.print(msg.buf[i], HEX);
140 Serial.print(" ");
141 }
142 Serial.println();
143}
144
145void Canbus_t::enableCanbusSniffer(bool enable) {
146#ifndef CONF_LOGGING_ASCII_DEBUG
147 Log.w(ID, "Canbus sniffer will now be outputting raw ascii strings");
148#endif
149 if (enable) {
150 Serial.println("Enabling canbus sniffer");
151 F_Can.onReceive(_canSniff);
152 } else {
153 Serial.println("Disabling canbus sniffer");
154 F_Can.onReceive(_receiveCan);
155 }
156}
157
158void Canbus_t::setup(void) { // IMPROVE: filter only for addresses we care about
159 started = false;
160 Log.d(ID, "Starting");
161 F_Can.begin(); // NOTE: canbus must first be started before it can be configured
162 F_Can.setMaxMB(16); // set number of possible TX & RX MBs // NOTE: Teensy 3.6 only has max 16 MBs
163 Log.d(ID, "Setting MB RX");
164 for (int i = TX_MAILBOXES; i < 16; i++) {
165 F_Can.setMB((FLEXCAN_MAILBOX)i, RX, NONE);
166 }
167 Log.d(ID, "Setting MB TX");
168 for (int i = 0; i < TX_MAILBOXES; i++) {
169 F_Can.setMB((FLEXCAN_MAILBOX)i, TX, NONE);
170 }
171 F_Can.setBaudRate(CONFIG_FLEXCAN_BAUD_RATE);
172 Log.d(ID, "Setting Callback");
173 F_Can.onReceive(_receiveCan);
174 Log.d(ID, "Enabling Interrupts");
175 Thread::sleep(500); // Just in case canbus needs to do stuff
176 F_Can.enableMBInterrupts(); // FIXME: Possible issue where it sometimes freezes here
177#ifdef CONF_LOGGING_ASCII_DEBUG
178 F_Can.mailboxStatus();
179#endif
180 started = true;
181}
182
183void Canbus_t::run() {
184 while (1) {
185 for (Buffer &buf : buffers) {
186 if (buf.outgoing && buf.modified) { // IMPROVE: only iterate over outgoing
187 sendData(buf);
188 }
189 }
190 }
191}
192
193} // namespace CAN
194 // @endcond
Define incoming CAN line addresses.
FlexCAN_T4 wrapper.
Configure canbus functionality.
#define CONFIG_FLEXCAN_TX_MAILBOXES
Set the number of outgoing mailboxes.
#define CONFIG_FLEXCAN_BAUD_RATE
Set the baud rate at which the CAN line should run.
Configure global build properties.
Special logging functionality.
Logging::Log_t Log
The global logging object.
static void enableCanbusSniffer(bool enable)
continuously prints out strings of any message that is received through canbus. As such,...
static void sendData(Buffer &buf)
Send data given a buffer object.
void setup(void)
Setup the Canbus line.
static void setCallback(const uint32_t address, canCallback callback)
Set a callback to an incoming address. If an incoming address buffer is updated it will call the give...
void run(void)
Run the teensy Canbus line.
static constexpr Buffer * getBuffer(const uint32_t address)
Get the buffer of an any address. If it is outgoing, use pushData to push the data after modifying th...
static void enableInterrupts(bool enable)
Enable mailbox interrupts, allowing values to automaticaly update. Enabled by default.
Canbus functionality. Refer to Canbus.h for more info.
Definition CanBuffer.cpp:4
void(* canCallback)(uint32_t, volatile uint8_t *)
The function type to pass to addCallback.
Definition CanBuffer.h:17
void d(LOG_TAG TAG, LOG_MSG message)
Log a string using a debug tag.
void w(LOG_TAG TAG, LOG_MSG message)
Log a string using a warning tag.
void e(LOG_TAG TAG, LOG_MSG message)
Log a string using an error tag.