SAE Teensy ECU
IIT SAE Microcontroller programming
Loading...
Searching...
No Matches
Pins.cpp
Go to the documentation of this file.
1
12// @cond
13
14#include "Pins.h"
15#include "IntervalTimer.h"
16#include "map" // FIXME: Linker error when using unordered_map, something to do with allocation? compilation may not be correct
17
18#include "Canbus.h"
19#include "ECUGlobalConfig.h"
20#include "Log.h"
21#include "PinConfig.def"
22
23namespace Pins {
24
25// NOTE: analogpin indexes extend beyond CORE_NUM_TOTAL_PINS, eg. DAC0
26
27// TODO: Test whether analog write pins need to be set to a freq of 14648.437 Hz
28
29// static int A_GPIO[CORE_NUM_TOTAL_PINS]; // IMPROVE: Use CORE_NUM_ANALOG instead
30
31#define X ,
32
33static const uint analogCanMsgCount_OUT = PP_NARG_MO(PINS_CANBUS_ANALOG_OUT) / 2 + PP_NARG_MO(PINS_CANBUS_ANALOG_OUT) % 2;
34static const uint analogCanPinCount_OUT = PP_NARG_MO(PINS_CANBUS_ANALOG_OUT);
35static const uint digitalCanPinCount_OUT = PP_NARG_MO(PINS_CANBUS_DIGITAL_OUT);
36static const uint analogCanPinCount_IN = PP_NARG_MO(PINS_CANBUS_ANALOG_IN);
37static const uint analogCanMsgCount_IN = PP_NARG_MO(PINS_CANBUS_ANALOG_IN) / 2 + PP_NARG_MO(PINS_CANBUS_ANALOG_IN) % 2;
38static const uint digitalCanPinCount_IN = PP_NARG_MO(PINS_CANBUS_DIGITAL_IN);
39
40#if PP_NARG_MO(PINS_CANBUS_DIGITAL_OUT) > 8
41#error Too many digital out canPins defined
42#elif PP_NARG_MO(PINS_CANBUS_DIGITAL_IN) > 8
43#error Too many digital in canPins defined
44#endif
45#undef X
46
47static std::map<uint8_t, int *> CAN_GPIO_MAP_IN;
48static int CAN_GPIO_IN[analogCanPinCount_IN + digitalCanPinCount_IN] = {0}; // Store incoming canpin values
49static std::map<uint8_t, int> CAN_GPIO_MAP_OUT; // Store outgoing canpin values
50static const int maxActiveDigitalPins = 8; // NOTE: MAX 8 Digital pins per msg for now
51
52static IntervalTimer canbusPinUpdate;
53static const LOG_TAG ID = "Pins";
54
55struct CanPinMsg_t {
56 uint32_t address;
57 uint8_t buf[8] = {0};
58 uint64_t *bufmap = (uint64_t *)buf;
59};
60
61static int getOutgoingPinValue(uint8_t GPIO_Pin);
62
63// IMPROVE: Make use of all 64 avaliable flags
64struct digitalCanPinMsg_t : CanPinMsg_t {
65 uint32_t activedigitalCanPins = 0;
66 uint8_t digitalPins[maxActiveDigitalPins];
67 uint digitalPinPos[maxActiveDigitalPins];
68 void send() {
69 memset(buf, 0, 8);
70 for (size_t i = 0; i < activedigitalCanPins; i++) {
71 *bufmap = *bufmap << 1;
72 *bufmap |= (bool)getOutgoingPinValue(digitalPins[i]);
73 }
74 // Log.d(ID, "Sending Digital Pins", address);
75 Canbus::sendData(address, buf);
76 }
77 void receive(uint8_t buffer[8]) {
78 bufmap = (uint64_t *)buffer; // use bufmap, as if we are receiving we can't be sending
79 for (int i = activedigitalCanPins - 1; i >= 0; i--) {
80 CAN_GPIO_IN[digitalPinPos[i]] = *bufmap & 1;
81 // Log.d(ID, "Received digital canPin:", digitalPinPos[i]);
82 // Log.d(ID, "Value:", CAN_GPIO_IN[digitalPinPos[i]]);
83 *bufmap = *bufmap >> 1;
84 }
85 }
86 void debugPrint() {
87 Serial.printf("Printing outgoing digital pin values: ");
88 Serial.println(activedigitalCanPins);
89 for (size_t i = 0; i < activedigitalCanPins; i++) {
90 Serial.print(digitalPins[i]);
91 Serial.print(" = ");
92 Serial.println(getOutgoingPinValue(digitalPins[i]));
93 }
94 }
95};
96
97struct analogCanPinMsg_t : CanPinMsg_t {
98 uint8_t analogPins[2] = {255, 255}; // NOTE: If pin 255 exists it cannot be used, mostly likely will not happen?
99 uint analogPinPos[2];
100 void send() {
101 memset(buf, 0, 8);
102 for (size_t i = 0; i < 2; i++) {
103 *bufmap = *bufmap << 32;
104 if (analogPins[i] != 255)
105 *bufmap |= getOutgoingPinValue(analogPins[i]);
106 }
107 // Log.d(ID, "Sending Analog Pins", address);
108 Canbus::sendData(address, buf);
109 }
110 void receive(uint8_t buffer[8]) {
111 bufmap = (uint64_t *)buffer; // use bufmap, as if we are receiving we can't be sending
112 int a0 = *bufmap >> 32;
113 int a1 = *bufmap & 0x00000000FFFFFFFF;
114 CAN_GPIO_IN[analogPinPos[0]] = a0;
115 if (analogPins[1] != 255) // Ensure this buffer only allocated one analog val
116 CAN_GPIO_IN[analogPinPos[1]] = a1;
117 // Log.d(ID, "Received analog canPin:", analogPinPos[0]);
118 // Log.d(ID, "Received analog canPin:", analogPinPos[1]);
119 }
120 void debugPrint() {
121 Serial.printf("Printing outgoing analog pin values for address: %u\n", address);
122 Serial.print(analogPins[0]);
123 Serial.print(" = ");
124 Serial.println(getOutgoingPinValue(analogPins[0]));
125 if (analogPins[1] != 255) { // Ensure this buffer only allocated one analog val
126 Serial.print(analogPins[1]);
127 Serial.print(" = ");
128 Serial.println(getOutgoingPinValue(analogPins[1]));
129 }
130 }
131};
132
133static digitalCanPinMsg_t digitalCanPinMessage_IN;
134static digitalCanPinMsg_t digitalCanPinMessage_OUT;
135static analogCanPinMsg_t analogCanPinMessages_IN[analogCanMsgCount_IN];
136static analogCanPinMsg_t analogCanPinMessages_OUT[analogCanMsgCount_OUT];
137
138#define __WRITEPIN_DIGITALOUTPUT(PIN, VAL) \
139 } \
140 else if (GPIO_Pin == PIN) { \
141 return digitalWriteFast(PIN, VAL);
142
143#define __WRITEPIN_ANALOGOUTPUT(PIN, VAL) \
144 } \
145 else if (GPIO_Pin == PIN) { \
146 return analogWrite(PIN, VAL);
147
148#define __READPIN_DIGITALINPUT(PIN) \
149 } \
150 else if (GPIO_Pin == PIN) { \
151 return digitalReadFast(PIN);
152
153// IMPROVE: actually implement analog value caching
154#define __READPIN_ANALOGINPUT(PIN) \
155 } \
156 else if (GPIO_Pin == PIN) { \
157 return analogRead(PIN); \
158 // return A_GPIO[PIN];
159
160#define __WRITEPIN_DIGITALINPUT(PIN, VAL)
161#define __WRITEPIN_ANALOGINPUT(PIN, VAL)
162#define __READPIN_DIGITALOUTPUT(PIN)
163#define __READPIN_ANALOGOUTPUT(PIN)
164
165// #define __INTERNAL_READ_ANALOG(PIN) A_GPIO[PIN] = analogRead(PIN);
166// #define __INTERNAL_READ_DIGITAL(PIN)
167
168static void _receiveDigitalCanbusPin(uint32_t address, volatile uint8_t *buffer) {
169 digitalCanPinMessage_IN.receive((uint8_t *)buffer);
170}
171
172static void _receiveAnalogCanbusPin(uint32_t address, volatile uint8_t *buffer) {
173 for (size_t i = 0; i < analogCanMsgCount_IN; i++) {
174 if (analogCanPinMessages_IN[i].address == address) {
175 analogCanPinMessages_IN[i].receive((uint8_t *)buffer);
176 break;
177 }
178 }
179}
180
181void debugPrint(void) {
182 // digitalCanPinMessage_OUT.debugPrint();
183 // for (size_t i = 0; i < analogCanMsgCount_OUT; i++) {
184 // analogCanPinMessages_OUT[i].debugPrint();
185 // }
186 // digitalCanPinMessage_IN.debugPrint();
187 // for (size_t i = 0; i < analogCanMsgCount_IN; i++) {
188 // analogCanPinMessages_IN[i].debugPrint();
189 // }
190 // Serial.println("Printing CanPin Map");
191 // for (auto i : CAN_GPIO_MAP_IN) {
192 // Serial.print(i.first);
193 // Serial.print(" : ");
194 // Serial.println(*i.second);
195 // }
196 // for (auto i : CAN_GPIO_MAP_OUT) {
197 // Serial.print(i.first);
198 // Serial.print(" : ");
199 // Serial.println(i.second);
200 // }
201 // Serial.println("Printing Pin Map");
202
203#define X(pin, Type, IO, init) \
204 Serial.print(pin); \
205 Serial.print(" : "); \
206 Serial.println(getPinValue(pin));
208#undef X
209}
210
211static void _pushCanbusPins(void) {
212 digitalCanPinMessage_OUT.send();
213 for (size_t i = 0; i < analogCanMsgCount_OUT; i++) {
214 analogCanPinMessages_OUT[i].send();
215 }
216}
217
218void setInternalValue(uint8_t Internal_Pin, int value) {
219#ifdef CONF_ECU_DEBUG
220 if (CAN_GPIO_MAP_OUT.find(Internal_Pin) != CAN_GPIO_MAP_OUT.end()) {
221 if (CAN_GPIO_MAP_OUT[Internal_Pin] == value)
222 return;
223 Log.d(ID, "Setting Internal pin:", Internal_Pin);
224 Log.d(ID, "Setting Internal pin to int:", value);
225 CAN_GPIO_MAP_OUT[Internal_Pin] = value;
226 } else {
227 Log.w(ID, "Unable to set Internal pin to int:", value);
228 Log.w(ID, "Pin:", Internal_Pin);
229 }
230
231#else
232 if (CAN_GPIO_MAP_OUT.find(Internal_Pin) != CAN_GPIO_MAP_OUT.end())
233 CAN_GPIO_MAP_OUT[Internal_Pin] = value;
234#endif
235}
236
237static int getOutgoingPinValue(uint8_t GPIO_Pin) {
238 if (GPIO_Pin >= 100)
239 return CAN_GPIO_MAP_OUT[GPIO_Pin];
240 return getPinValue(GPIO_Pin);
241}
242
243int getCanPinValue(uint8_t CAN_GPIO_Pin) {
244#ifdef CONF_ECU_DEBUG
245 if (CAN_GPIO_MAP_IN.find(CAN_GPIO_Pin) != CAN_GPIO_MAP_IN.end()) {
246 return *CAN_GPIO_MAP_IN[CAN_GPIO_Pin];
247 } else {
248 Log.e(ID, "Canpin was not defined before hand:", CAN_GPIO_Pin);
249 return 0;
250 }
251#else
252 return *CAN_GPIO_MAP_IN[CAN_GPIO_Pin];
253#endif
254}
255
256int getPinValue(uint8_t GPIO_Pin) { // IMPROVE: Make getPinValue compatible with canPins
257 if (GPIO_Pin >= 100) { // pins >= 100 are internal pins
258 return getCanPinValue(GPIO_Pin);
259#define X(pin, Type, IO, init) __READPIN_##Type##IO(pin);
261#undef X
262 } else {
263#ifdef CONF_ECU_DEBUG
264 Log.d(ID, "No pin defined", GPIO_Pin);
265#endif
266 return 0;
267 }
268}
269
270void setPinValue(uint8_t GPIO_Pin, int value) { // IMPROVE: Make setPinValue compatible with canPins
271 if (GPIO_Pin >= 100) {
272 return setInternalValue(GPIO_Pin, value);
273#define X(pin, Type, IO, init) __WRITEPIN_##Type##IO(pin, value);
275#undef X
276 }
277#ifdef CONF_ECU_DEBUG
278 else {
279 Log.d(ID, "No pin defined", GPIO_Pin);
280 }
281#endif
282}
283
284void update(void) {
285 // #define X(pin, Type, IO) __INTERNAL_READ_##Type(pin);
286 // ECU_PINS
287 // #undef X
288}
289
290static void populateCanbusMap(std::multimap<uint32_t, std::tuple<uint, uint8_t, bool>> pinMap, analogCanPinMsg_t *analogCanPinStructArray, uint maxAnalogMsg, digitalCanPinMsg_t *digitalCanPinStruct, uint activeDigitalCanPinCount) {
291 uint amsgc = 0;
292 uint dmsgc = 0;
293 decltype(pinMap.equal_range(0)) range;
294 for (auto i = pinMap.begin(); i != pinMap.end(); i = range.second) {
295 range = pinMap.equal_range(i->first);
296
297 uint ac = 0;
298 uint dc = 0;
299 uint32_t address = i->first;
300
301 for (auto d = range.first; d != range.second; ++d) {
302 if (std::get<2>(d->second)) { // Analog
303 if (amsgc == maxAnalogMsg) {
304 Log.e(ID, "Exceeded number of allocated analog canbus buffers, maximize the number of analog pins per address", amsgc);
305 break;
306 }
307 if (ac == 2) {
308 Log.w(ID, "Address has too many analog pins allocated, ignoring additional pins", address);
309 break;
310 }
311 analogCanPinStructArray[amsgc].address = address;
312 analogCanPinStructArray[amsgc].analogPinPos[ac] = std::get<0>(d->second);
313 analogCanPinStructArray[amsgc].analogPins[ac] = std::get<1>(d->second);
314 Log.d(ID, "", std::get<1>(d->second));
315 ac++;
316 } else { // Digital
317 if (dmsgc == 1) { // NOTE: Hardcoded single digital message
318 Log.e(ID, "Exceeded number of allocated digital canbus buffers, currently only one digital buffer is supported", dmsgc);
319 break;
320 }
321 if (dc == activeDigitalCanPinCount) {
322 Log.w(ID, "Address has too many digital pins allocated, ignoring additional pins", address);
323 break;
324 }
325 digitalCanPinStruct->address = address;
326 digitalCanPinStruct->digitalPinPos[dc] = std::get<0>(d->second);
327 digitalCanPinStruct->digitalPins[dc] = std::get<1>(d->second);
328 dc++;
329 digitalCanPinStruct->activedigitalCanPins = dc; // Set number of active pins out of 8 on digital message
330 }
331 }
332
333 if (ac || dc) {
334 if (ac != 0) {
335 amsgc++;
336 Log.i(ID, "Set analog canbus buffer:", address);
337 }
338 if (dc != 0) {
339 dmsgc++;
340 Log.i(ID, "Set digital canbus buffer:", address);
341 for (auto d = range.first; d != range.second; ++d) {
342 Log.d(ID, "", std::get<1>(d->second));
343 }
344 }
345 } else {
346 Log.w(ID, "No pins were set for address: ", address);
347 }
348 }
349}
350
351void resetPhysicalPins() {
352#define X(pin, Type, IO, init) \
353 pinMode(pin, IO); \
354 if (init != NIL) { \
355 Log.d(ID, "Reset pin", pin); \
356 setPinValue(pin, init); \
357 }
359#undef X
360}
361
362void stopCanPins(void) {
363 canbusPinUpdate.end();
364}
365
366void startCanPins(void) {
367 if (digitalCanPinCount_OUT + analogCanPinCount_OUT != 0) {
368 Log.i(ID, "Starting outgoing canpin update timer");
369 canbusPinUpdate.begin(_pushCanbusPins, CONF_PINS_CANBUS_UPDATE_INTERVAL_MICRO);
370 }
371}
372
373void initialize(void) {
374 Log.i(ID, "Setting up physical pins");
375
376 analogWriteResolution(PINS_ANALOG_RES);
377 analogReadResolution(PINS_ANALOG_RES);
379
380 Log.i(ID, "Setting up outgoing canbus pins");
381 std::multimap<uint32_t, std::tuple<uint, uint8_t, bool>> pinMap;
382 bool isAnalog = true;
383 uint i = 0;
384
385#define X(address, pin) \
386 pinMap.insert(std::make_pair(address, std::make_tuple(i, pin, isAnalog))); \
387 CAN_GPIO_MAP_OUT[pin] = 0; \
388 i++;
390 isAnalog = false;
392#undef X
393
394 Log.i(ID, "Populating outgoing messages");
395 populateCanbusMap(pinMap, analogCanPinMessages_OUT, analogCanMsgCount_OUT, &digitalCanPinMessage_OUT, digitalCanPinCount_OUT);
396
397 Log.i(ID, "Setting up incoming canbus pins");
398 pinMap.clear();
399 isAnalog = true;
400 i = 0;
401
402#define X(address, pin) \
403 pinMap.insert(std::make_pair(address, std::make_tuple(i, pin, isAnalog))); \
404 CAN_GPIO_MAP_IN[pin] = &CAN_GPIO_IN[i]; \
405 i++;
407 isAnalog = false;
409#undef X
410
411 Log.i(ID, "Populating incoming messages");
412 populateCanbusMap(pinMap, analogCanPinMessages_IN, analogCanMsgCount_IN, &digitalCanPinMessage_IN, digitalCanPinCount_IN);
413
414 Log.i(ID, "Adding incoming canpin callbacks");
415 if (digitalCanPinCount_IN != 0)
416 Canbus::addCallback(digitalCanPinMessage_IN.address, _receiveDigitalCanbusPin);
417 for (size_t i = 0; i < analogCanMsgCount_IN; i++) {
418 Canbus::addCallback(analogCanPinMessages_IN[i].address, _receiveAnalogCanbusPin);
419 }
420
421 startCanPins();
422
423#ifdef CONF_LOGGING_ASCII_DEBUG
424 debugPrint();
425#endif
426}
427
428} // namespace Pins
429
430// @endcond
FlexCAN_T4 wrapper.
Configure global build properties.
Special logging functionality.
const char * LOG_TAG
Type definition of logging tags This typedef is necessary to allow for easier manipulation of code by...
Definition Log.h:48
Logging::Log_t Log
The global logging object.
Pin Configuration.
#define PINS_CANBUS_DIGITAL_OUT
Same as PINS_CANBUS_DIGITAL_IN only for the digital pins that are outgoing.
#define CONF_PINS_CANBUS_UPDATE_INTERVAL_MICRO
The interval in micros to update outgoing canPins.
Definition PinConfig.def:47
#define PINS_CANBUS_ANALOG_IN
The defintions of every analog pin to be received over canbus.
#define PINS_CANBUS_ANALOG_OUT
Same as PINS_CANBUS_ANALOG_IN only for the analog pins that are outgoing.
#define ECU_PINS
The defintions of every physical pin.
#define PINS_CANBUS_DIGITAL_IN
The defintions of every digital pin to be received over canbus.
Update, set, and get predefined pin values.
#define PINS_ANALOG_RES
The current target bit resolution of the ECU, set by PinConfig.def.
Definition Pins.h:59
Get and set values to predefined pins.
Definition Pins.h:85
void stopCanPins(void)
Stops background interrupts from sending canPins.
void setPinValue(uint8_t GPIO_Pin, int value)
Set the pin value of a predefined pin.
int getCanPinValue(uint8_t CAN_GPIO_Pin)
Get the pin value of a predefined canbus pin.
void initialize(void)
Initialize all predefined pins.
int getPinValue(uint8_t GPIO_Pin)
Get the pin value of a predefined pin.
void update(void)
Poll analog pin values.
void startCanPins(void)
Starts background interrupts to send canPins, if any are to be sent.
void setInternalValue(uint8_t Internal_Pin, int value)
Set the value of an internal pin.
void debugPrint(void)
Used for debugging.
void resetPhysicalPins()
Resets physical pins to their inital state.
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.
void i(LOG_TAG TAG, LOG_MSG message)
Log a string using an info tag.