rusEFI
The most advanced open source ECU
can_dash.cpp
Go to the documentation of this file.
1 /**
2  * @file can_dash.cpp
3  *
4  * This file handles transmission of ECU data to various OE dashboards.
5  *
6  * @date Mar 19, 2020
7  * @author Matthew Kennedy, (c) 2020
8  */
9 
10 #include "pch.h"
11 
12 #if EFI_CAN_SUPPORT
13 #include "can_dash.h"
14 #include "can_dash_ms.h"
15 #include "can_msg_tx.h"
16 #include "can_bmw.h"
17 #include "can_vag.h"
18 
19 #include "rusefi_types.h"
20 #include "rtc_helper.h"
21 #include "fuel_math.h"
22 
23 // CAN Bus ID for broadcast
24 #define CAN_FIAT_MOTOR_INFO 0x561
25 #define CAN_MAZDA_RX_RPM_SPEED 0x201
26 #define CAN_MAZDA_RX_STEERING_WARNING 0x300
27 #define CAN_MAZDA_RX_STATUS_1 0x212
28 #define CAN_MAZDA_RX_STATUS_2 0x420
29 
30 //w202 DASH
31 #define W202_STAT_1 0x308 /* _20ms cycle */
32 #define W202_STAT_2 0x608 /* _100ms cycle */
33 #define W202_ALIVE 0x210 /* _200ms cycle */
34 #define W202_STAT_3 0x310 /* _200ms cycle */
35 
36 //BMW E90 DASH
37 #define E90_ABS_COUNTER 0x0C0
38 #define E90_SEATBELT_COUNTER 0x0D7
39 #define E90_T15 0x130
40 #define E90_RPM 0x175
41 #define E90_BRAKE_COUNTER 0x19E
42 #define E90_SPEED 0x1A6
43 #define E90_TEMP 0x1D0
44 #define E90_GEAR 0x1D2
45 #define E90_FUEL 0x349
46 #define E90_EBRAKE 0x34F
47 #define E90_TIME 0x39E
48 
49 #define HONDA_SPEED_158 0x158
50 #define HONDA_TACH_1DC 0x1DC
51 
52 static time_msecs_t mph_timer;
53 static time_msecs_t mph_ctr;
54 
55 /**
56  * https://docs.google.com/spreadsheets/d/1IkP05ODpjNt-k4YQLYl58_TNlN9U4IBu5z7i0BPVEM4
57  */
58 #define GENESIS_COUPLE_RPM_316 0x316
59 #define GENESIS_COUPLE_COOLANT_329 0x329
60 #define GENESIS_COUPLE_SENSORS_382 0x382
61 // when A/C compressor is allowed to be on, these values need to be sent so the A/C panel activates the compressor
62 #define GENESIS_COUPLE_AC_ENABLE_18F 0x18F
63 
64 //https://www.drive2.ru/b/500679938089681452/
65 #define NISSAN_STEERING_WHEEL 0x002
66 
67 // 505
68 #define NISSAN_RPM_1F9 0x1F9
69 
70 // 561
71 #define NISSAN_ENGINE_2 0x231
72 // 563
73 #define NISSAN_UNKNOWN_2 0x233
74 // Nissan z33 350Z and else
75 // 0x23d = 573
76 #define NISSAN_RPM_CLT 0x23D
77 // 574
78 #define NISSAN_UNKNOWN_3 0x23E
79 
80 #define NISSAN_TCU_1 0x251
81 #define NISSAN_TCU_2 0x253
82 
83 // 640
84 #define NISSAN_VEHICLE_SPEED_280 0x280
85 // wheel speed see "102 CAN Communication decoded"
86 // 19500 value would be 100 kph
87 // 644
88 #define NISSAN_WHEEL_SPEED1 0x284
89 // 645
90 #define NISSAN_WHEEL_SPEED2 0x285
91 
92 // 670
93 #define NISSAN_UNKNOWN_4 0x29E
94 
95 #define NISSAN_ABS 0x2A0
96 
97 // 833 doors
98 #define NISSAN_BCM 0x341
99 
100 // https://www.drive2.com/l/530057789272229668/
101 // 852
102 #define NISSAN_VEHICLE_SPEED 0x354
103 
104 // 1361
105 #define NISSAN_CLT_551 0x551
106 // 1408
107 #define NISSAN_RPM_AGAIN 0x580
108 #define NISSAN_ODOMETER 0x5C5
109 // 1549
110 #define NISSAN_BCM_2 0x60D
111 
112 static uint8_t rpmcounter;
113 static uint8_t seatbeltcnt;
114 static uint8_t abscounter = 0xF0;
115 static uint8_t brakecnt_1 = 0xF0, brakecnt_2 = 0xF0;
116 static uint8_t mph_a, mph_2a, mph_last, tmp_cnt, gear_cnt;
117 static uint16_t mph_counter = 0xF000;
118 static bool cluster_time_set;
119 
120 constexpr uint8_t e90_temp_offset = 49;
121 
122 // todo: those forward declarations are out of overall code style
123 void canDashboardFiat(CanCycle cycle);
124 void canMazdaRX8(CanCycle cycle);
125 void canDashboardW202(CanCycle cycle);
126 void canDashboardVagMqb(CanCycle cycle);
127 void canDashboardNissanVQ(CanCycle cycle);
129 void canDashboardAim(CanCycle cycle);
130 void canDashboardHaltech(CanCycle cycle);
131 
132 //BMW Dashboard
133 //todo: we use 50ms fixed cycle, trace is needed to check for correct period
134 static void canDashboardBmwE46(CanCycle cycle) {
135 
136  if (cycle.isInterval(CI::_50ms)) {
137  {
138  CanTxMessage msg(CanCategory::NBC, CAN_BMW_E46_SPEED);
139  msg.setShortValue(10 * 8, 1);
140  }
141 
142  {
143  CanTxMessage msg(CanCategory::NBC, CAN_BMW_E46_RPM);
144  msg.setShortValue((int) (Sensor::getOrZero(SensorType::Rpm) * 6.4), 2);
145  }
146 
147  {
148  CanTxMessage msg(CanCategory::NBC, CAN_BMW_E46_DME2);
149  msg.setShortValue((int) ((Sensor::getOrZero(SensorType::Clt) + 48.373) / 0.75), 1);
150  }
151  }
152 }
153 
154 //todo: we use 50ms fixed cycle, trace is needed to check for correct period
155 void canMazdaRX8(CanCycle cycle) {
156  if (cycle.isInterval(CI::_50ms)) {
157  {
158  CanTxMessage msg(CanCategory::NBC, CAN_MAZDA_RX_STEERING_WARNING);
159  // todo: something needs to be set here? see http://rusefi.com/wiki/index.php?title=Vehicle:Mazda_Rx8_2004
160  }
161 
162  {
163  CanTxMessage msg(CanCategory::NBC, CAN_MAZDA_RX_RPM_SPEED);
164 
166 
167  // todo: LSB+SWAP? lol, that's MSB?
169  msg.setShortValue(0xFFFF, 2);
170  // todo: LSB+SWAP? lol, that's MSB?
171  msg.setShortValue(SWAP_UINT16((int )(100 * kph + 10000)), 4);
172  msg.setShortValue(0, 6);
173  }
174 
175  {
176  CanTxMessage msg(CanCategory::NBC, CAN_MAZDA_RX_STATUS_1);
177  msg[0] = 0xFE; //Unknown
178  msg[1] = 0xFE; //Unknown
179  msg[2] = 0xFE; //Unknown
180  msg[3] = 0x34; //DSC OFF in combo with byte 5 Live data only seen 0x34
181  msg[4] = 0x00; // B01000000; // Brake warning B00001000; //ABS warning
182  msg[5] = 0x40; // TCS in combo with byte 3
183  msg[6] = 0x00; // Unknown
184  msg[7] = 0x00; // Unused
185  }
186 
187  {
188  CanTxMessage msg(CanCategory::NBC, CAN_MAZDA_RX_STATUS_2);
190  msg[0] = (uint8_t)(clt.value_or(0) + 69); //temp gauge //~170 is red, ~165 last bar, 152 centre, 90 first bar, 92 second bar
191  // TODO: fixme!
192  //msg[1] = ((int16_t)(engine->engineState.vssEventCounter*(engineConfiguration->vehicleSpeedCoef*0.277*2.58))) & 0xff;
193  msg[2] = 0x00; // unknown
194  msg[3] = 0x00; //unknown
195  msg[4] = 0x01; //Oil Pressure (not really a gauge)
196  msg[5] = 0x00; //check engine light
197  msg[6] = 0x00; //Coolant, oil and battery
198  if ((Sensor::getOrZero(SensorType::Rpm)>0) && (Sensor::get(SensorType::BatteryVoltage).value_or(VBAT_FALLBACK_VALUE)<13)) {
199  msg.setBit(6, 6); // battery light
200  }
201  if (!clt.Valid || clt.Value > 105) {
202  // coolant light, 101 - red zone, light means its get too hot
203  // Also turn on the light in case of sensor failure
204  msg.setBit(6, 1);
205  }
206  //oil pressure warning lamp bit is 7
207  msg[7] = 0x00; //unused
208  }
209  }
210 
211 }
212 
214  if (cycle.isInterval(CI::_50ms)) {
215  {
216  //Fiat Dashboard
217  CanTxMessage msg(CanCategory::NBC, CAN_FIAT_MOTOR_INFO);
218  msg.setShortValue((int) (Sensor::getOrZero(SensorType::Clt) - 40), 3); //Coolant Temp
219  msg.setShortValue(Sensor::getOrZero(SensorType::Rpm) / 32, 6); //RPM
220  }
221  }
222 }
223 
225  if (cycle.isInterval(CI::_10ms)) {
226  {
227  // https://github.com/commaai/opendbc/blob/57c8340a180dd8c75139b18050eb17c72c9cb6e4/vw_golf_mk4.dbc#L394
228  //VAG Dashboard
229  CanTxMessage msg(CanCategory::NBC, CAN_VAG_Motor_1);
231  }
232 
234 
235  {
236  CanTxMessage msg(CanCategory::NBC, CAN_VAG_Motor_2);
237  msg.setShortValue((int) ((clt + 48.373) / 0.75), 1); //Coolant Temp
238  }
239 
240  {
241  CanTxMessage msg(CanCategory::NBC, CAN_VAG_CLT_V2);
242  msg.setShortValue((int) ((clt + 48.373) / 0.75), 4); //Coolant Temp
243  }
244 
245  {
246  CanTxMessage msg(CanCategory::NBC, CAN_VAG_IMMO);
247  msg.setShortValue(0x80, 1);
248  }
249  }
250 }
251 
253  if (cycle.isInterval(CI::_20ms)) {
254  {
255  CanTxMessage msg(CanCategory::NBC, W202_STAT_1);
256  msg[0] = 0x08; // Unknown
258  msg[3] = 0x00; // 0x01 - tank blink, 0x02 - EPC
259  msg[4] = 0x00; // Unknown
260  msg[5] = 0x00; // Unknown
261  msg[6] = 0x00; // Unknown - oil info
262  msg[7] = 0x00; // Unknown - oil info
263  }
264  }
265 
266  if (cycle.isInterval(CI::_100ms)) {
267  {
268  CanTxMessage msg(CanCategory::NBC, W202_STAT_2); //dlc 7
269  msg[0] = (int)(Sensor::getOrZero(SensorType::Clt) + 40); // CLT -40 offset
270  msg[1] = 0x3D; // TBD
271  msg[2] = 0x63; // Const
272  msg[3] = 0x41; // Const
273  msg[4] = 0x00; // Unknown
274  msg[5] = 0x05; // Const
275  msg[6] = 0x50; // TBD
276  msg[7] = 0x00; // Unknown
277  }
278  }
279 
280  if (cycle.isInterval(CI::_200ms)) {
281  {
282  CanTxMessage msg(CanCategory::NBC, W202_ALIVE);
283  msg[0] = 0x0A; // Const
284  msg[1] = 0x18; // Const
285  msg[2] = 0x00; // Const
286  msg[3] = 0x00; // Const
287  msg[4] = 0xC0; // Const
288  msg[5] = 0x00; // Const
289  msg[6] = 0x00; // Const
290  msg[7] = 0x00; // Const
291  }
292 
293  {
294  CanTxMessage msg(CanCategory::NBC, W202_STAT_3);
295  msg[0] = 0x00; // Const
296  msg[1] = 0x00; // Const
297  msg[2] = 0x6D; // TBD
298  msg[3] = 0x7B; // Const
299  msg[4] = 0x21; // TBD
300  msg[5] = 0x07; // Const
301  msg[6] = 0x33; // Const
302  msg[7] = 0x05; // Const
303  }
304  }
305 }
306 
307 static int rollingId = 0;
308 
310  if (cycle.isInterval(CI::_50ms)) {
311  {
312  CanTxMessage msg(CanCategory::NBC, GENESIS_COUPLE_RPM_316, 8);
313  msg.setShortValueMsb(Sensor::getOrZero(SensorType::Rpm) * 4, /*offset*/ 3);
314  }
315  {
316  CanTxMessage msg(CanCategory::NBC, GENESIS_COUPLE_COOLANT_329, 8);
318  msg[1] = clt;
319  }
320  }
321 }
322 
324  if (cycle.isInterval(CI::_50ms)) {
325  {
326  CanTxMessage msg(CanCategory::NBC, NISSAN_RPM_1F9, 8);
327  msg.setShortValueMsb(Sensor::getOrZero(SensorType::Rpm) * 8, /*offset*/ 2);
328  }
329 
330  {
331  CanTxMessage msg(CanCategory::OBD, NISSAN_CLT_551, 8);
332 
334  msg[0] = clt + 45;
335  }
336 
337 
338  {
339  CanTxMessage msg(CanCategory::NBC, NISSAN_RPM_CLT, 8);
340 
341  rollingId = (rollingId + 1) % 4;
342  const uint8_t magicByte[4] = {0x03, 0x23, 0x42, 0x63};
343 
344  msg[0] = magicByte[rollingId];
345  msg[1] = (int)(Sensor::getOrZero(SensorType::AcceleratorPedal) * 255 / 100);
346 
347  // thank you "102 CAN Communication decoded"
348 #define CAN_23D_RPM_MULT 3.15
349  int rpm315 = (int)(Sensor::getOrZero(SensorType::Rpm) / CAN_23D_RPM_MULT);
350  msg.setShortValue(rpm315, /*offset*/ 3);
351 
352  msg[7] = 0x70; // todo: CLT decoding?
353  }
354  }
355 }
356 
357 /**
358  * https://docs.google.com/spreadsheets/d/1XMfeGlhgl0lBL54lNtPdmmFd8gLr2T_YTriokb30kJg
359  */
361  if (cycle.isInterval(CI::_50ms)) {
362 
363  { // 'turn-on'
364  CanTxMessage msg(CanCategory::NBC, 0x3C0, 4);
365  // ignition ON
366  msg[2] = 3;
367  }
368 
369  { //RPM
370  CanTxMessage msg(CanCategory::NBC, 0x107, 8);
371  msg.setShortValue(Sensor::getOrZero(SensorType::Rpm) / 3.5, /*offset*/ 3);
372  }
373  }
374 }
375 
376 static void canDashboardBmwE90(CanCycle cycle) {
377 
378  if (cycle.isInterval(CI::_50ms)) {
379 
380  { //T15 'turn-on'
381  CanTxMessage msg(CanCategory::NBC, E90_T15, 5);
382  msg[0] = 0x45;
383  msg[1] = 0x41;
384  msg[2] = 0x61;
385  msg[3] = 0x8F;
386  msg[4] = 0xFC;
387  }
388 
389  { //Ebrake light
390  CanTxMessage msg(CanCategory::OBD, E90_EBRAKE, 2);
391  msg[0] = 0xFD;
392  msg[1] = 0xFF;
393  }
394 
395  { //RPM
396  rpmcounter++;
397  if (rpmcounter > 0xFE)
398  rpmcounter = 0xF0;
399  CanTxMessage msg(CanCategory::OBD, E90_RPM, 3);
400  msg[0] = rpmcounter;
402  }
403 
404  { //oil & coolant temp (all in C, despite gauge being F)
405  tmp_cnt++;
406  if (tmp_cnt >= 0x0F)
407  tmp_cnt = 0x00;
408  CanTxMessage msg(CanCategory::OBD, E90_TEMP, 8);
409  msg[0] = (int)(Sensor::getOrZero(SensorType::Clt) + e90_temp_offset); //coolant
410  msg[1] = (int)(Sensor::getOrZero(SensorType::AuxTemp1) + e90_temp_offset); //oil (AuxTemp1)
411  msg[2] = tmp_cnt;
412  msg[3] = 0xC8;
413  msg[4] = 0xA7;
414  msg[5] = 0xD3;
415  msg[6] = 0x0D;
416  msg[7] = 0xA8;
417  }
418  }
419 
420  if (cycle.isInterval(CI::_100ms)) {
421  {
422  //Seatbelt counter
423  seatbeltcnt++;
424  if (seatbeltcnt > 0xFE)
425  seatbeltcnt = 0x00;
426  CanTxMessage msg(CanCategory::NBC, E90_SEATBELT_COUNTER, 2);
427  msg[0] = seatbeltcnt;
428  msg[1] = 0xFF;
429  }
430 
431  {
432  //Brake counter 100ms
433  brakecnt_1 += 16;
434  brakecnt_2 += 16;
435  if (brakecnt_1 > 0xEF)
436  brakecnt_1 = 0x0F;
437  if (brakecnt_2 > 0xF0)
438  brakecnt_2 = 0xA0;
439  CanTxMessage msg(CanCategory::NBC, E90_BRAKE_COUNTER, 8);
440  msg[0] = 0x00;
441  msg[1] = 0xE0;
442  msg[2] = brakecnt_1;
443  msg[3] = 0xFC;
444  msg[4] = 0xFE;
445  msg[5] = 0x41;
446  msg[6] = 0x00;
447  msg[7] = brakecnt_2;
448  }
449 
450  { //ABS counter
451  abscounter++;
452  if (abscounter > 0xFE)
453  abscounter = 0xF0;
454  CanTxMessage msg(CanCategory::NBC, E90_ABS_COUNTER, 2);
455  msg[0] = abscounter;
456  msg[1] = 0xFF;
457  }
458 
459  { //Fuel gauge
460  CanTxMessage msg(CanCategory::NBC, E90_FUEL, 5); //fuel gauge
461  msg[0] = 0x76;
462  msg[1] = 0x0F;
463  msg[2] = 0xBE;
464  msg[3] = 0x1A;
465  msg[4] = 0x00;
466  }
467 
468  { //Gear indicator/counter
469  gear_cnt++;
470  if (gear_cnt >= 0x0F)
471  gear_cnt = 0x00;
472  CanTxMessage msg(CanCategory::NBC, E90_GEAR, 6);
473  msg[0] = 0x78;
474  msg[1] = 0x0F;
475  msg[2] = 0xFF;
476  msg[3] = (gear_cnt << 4) | 0xC;
477  msg[4] = 0xF1;
478  msg[5] = 0xFF;
479  }
480 
481  { //E90_SPEED
482  auto vehicleSpeed = Sensor::getOrZero(SensorType::VehicleSpeed);
483  float mph = vehicleSpeed * 0.6213712;
484  mph_ctr = ((TIME_I2MS(chVTGetSystemTime()) - mph_timer) / 50);
485  mph_a = (mph_ctr * mph / 2);
486  mph_2a = mph_a + mph_last;
487  mph_last = mph_2a;
488  mph_counter += mph_ctr * 100;
489  if(mph_counter >= 0xFFF0)
490  mph_counter = 0xF000;
491  mph_timer = TIME_I2MS(chVTGetSystemTime());
492  CanTxMessage msg(CanCategory::NBC, E90_SPEED, 8);
493  msg.setShortValue(mph_2a, 0);
494  msg.setShortValue(mph_2a, 2);
495  msg.setShortValue(mph_2a, 4);
496  msg[6] = mph_counter & 0xFF;
497  // todo: what are we packing into what exactly? note the '| 0xF0'
498  msg[7] = (mph_counter >> 8) | 0xF0;
499  }
500  }
501 
502  {
503  if (!cluster_time_set) {
504 #if EFI_RTC
505  efidatetime_t dateTime = getRtcDateTime();
506 #else // EFI_RTC
507  efidatetime_t dateTime = {
508  .year = 0, .month = 0, .day = 0,
509  .hour = 0, .minute = 0, .second = 0,
510  };
511 #endif // EFI_RTC
512  CanTxMessage msg(CanCategory::NBC, E90_TIME, 8);
513  msg[0] = dateTime.hour;
514  msg[1] = dateTime.minute;
515  msg[2] = dateTime.second;
516  msg[3] = dateTime.day;
517  msg[4] = (dateTime.month << 4) | 0x0F;
518  msg[5] = dateTime.year & 0xFF;
519  msg[6] = (dateTime.year >> 8) | 0xF0; // collides CAN dash at 4096!
520  msg[7] = 0xF2;
521  cluster_time_set = 1;
522  }
523  }
524 }
525 
526 // https://support.haltech.com/portal/en/kb/articles/haltech-can-ecu-broadcast-protocol
528  if (cycle.isInterval(CI::_20ms)) {
529  /* 0x360 - 50Hz rate */
530  {
531  CanTxMessage msg(CanCategory::NBC, 0x360, 8);
534  /* TPS y = x/10 */
536  /* Coolant pressure */
537  msg[6] = 0;
538  msg[7] = 0;
539  }
540 
541  /* 0x361 - 50Hz rate */
542  {
543  CanTxMessage msg(CanCategory::NBC, 0x361, 8);
544  /* Fuel pressure */
546  /* Oil pressure */
548  /* Engine Demand */
550  /* Wastegate Pressure */
551  msg[6] = 0;
552  msg[7] = 0;
553  }
554 
555 #if EFI_ENGINE_CONTROL
556  /* 0x362 - 50Hz rate */
557  {
558  CanTxMessage msg(CanCategory::NBC, 0x362, 6);
559  /* Injection Stage 1 Duty Cycle - y = x/10 */
560  uint16_t rpm = Sensor::getOrZero(SensorType::Rpm);
561  msg.setShortValueMsb(getInjectorDutyCycle(rpm) * 10, 0);
562  /* Injection Stage 2 Duty Cycle */
563  msg[2] = 0x00;
564  msg[3] = 0x00;
565  /* Ignition Angle (Leading) - y = x/10 */
566  float timing = engine->engineState.timingAdvance[0];
567  int16_t ignAngle = ((timing > 360 ? timing - 720 : timing) * 10);
568  msg.setShortValueMsb(ignAngle, 4);
569  }
570 #endif // EFI_ENGINE_CONTROL
571 
572  /* todo: 0x3E5 = 50Hz rate */
573  {
574  CanTxMessage msg(CanCategory::NBC, 0x3E5, 8);
575  msg[0] = 0x00;
576  msg[1] = 0x00;
577  msg[2] = 0x00;
578  msg[3] = 0x00;
579  msg[4] = 0x00;
580  msg[5] = 0x00;
581  msg[6] = 0x00;
582  msg[7] = 0x00;
583  }
584 
585  /* todo: 0x3EA = 50Hz rate */
586  {
587  CanTxMessage msg(CanCategory::NBC, 0x3EA, 8);
588  msg[0] = 0x00;
589  msg[1] = 0x00;
590  msg[2] = 0x00;
591  msg[3] = 0x00;
592  msg[4] = 0x00;
593  msg[5] = 0x00;
594  msg[6] = 0x00;
595  msg[7] = 0x00;
596  }
597 
598  /* todo: 0x3EB = 50Hz rate */
599  {
600  CanTxMessage msg(CanCategory::NBC, 0x3EB, 8);
601  msg[0] = 0x00;
602  msg[1] = 0x00;
603  msg[2] = 0x00;
604  msg[3] = 0x00;
605  msg[4] = 0x00;
606  msg[5] = 0x00;
607  msg[6] = 0x00;
608  msg[7] = 0x00;
609  }
610 
611  /* todo: 0x3EC = 50Hz rate */
612  {
613  CanTxMessage msg(CanCategory::NBC, 0x3EC, 8);
614  msg[0] = 0x00;
615  msg[1] = 0x00;
616  msg[2] = 0x00;
617  msg[3] = 0x00;
618  msg[4] = 0x00;
619  msg[5] = 0x00;
620  msg[6] = 0x00;
621  msg[7] = 0x00;
622  }
623 
624  /* todo: 0x3ED = 50Hz rate */
625  {
626  CanTxMessage msg(CanCategory::NBC, 0x3ED, 2);
627  msg[0] = 0x00;
628  msg[1] = 0x00;
629  }
630 
631  /* todo: 0x471 = 50Hz rate */
632  {
633  CanTxMessage msg(CanCategory::NBC, 0x471, 2);
634  msg[0] = 0x00;
635  msg[1] = 0x00;
637  }
638  }
639 
640  if (cycle.isInterval(CI::_50ms)) {
641 
642  /* 0x363 - 20Hz rate */
643  {
644  CanTxMessage msg(CanCategory::NBC, 0x363, 4);
645  /* Wheel Slip */
646  msg[0] = 0x00;
647  msg[1] = 0x00;
648  /* Wheel Diff */
649  msg[2] = 0x00;
650  msg[3] = 0x00 ;
651  }
652 
653  /* 0x368 - 20Hz rate */
654  {
655  CanTxMessage msg(CanCategory::NBC, 0x368, 8);
656  /* Wideband Sensor 1 */
658  /* Wideband Sensor 2 */
660  /* Wideband Sensor 3 */
661  msg[4] = 0x00;
662  msg[5] = 0x00;
663  /* Wideband Sensor 4 */
664  msg[6] = 0x00;
665  msg[7] = 0x00;
666  }
667 
668 #if EFI_SHAFT_POSITION_INPUT
669  /* 0x369 - 20Hz rate */
670  {
671  CanTxMessage msg(CanCategory::NBC, 0x369, 8);
672  /* Trigger System Error Count */
674  /* Trigger Counter ?? */
676  /* unused */
677  msg[4] = 0x00;
678  msg[5] = 0x00;
679  /* Trigger Sync Level ?? */
680  msg[6] = 0x00;
681  msg[7] = 0x00;
682  }
683 #endif // EFI_SHAFT_POSITION_INPUT
684 
685  /* 0x36A - 20Hz rate */
686  /* todo: one day we should split this */
687  {
688  CanTxMessage msg(CanCategory::NBC, 0x36A, 4);
689  /* Knock Level 1 */
690  int knock100 = engine->module<KnockController>()->m_knockLevel * 100;
691  msg.setShortValueMsb(knock100, 0);
692  /* Knock Level 2 */
693  msg.setShortValueMsb(knock100, 2);
694  }
695 
696  /* 0x36B - 20Hz rate */
697  {
698  CanTxMessage msg(CanCategory::NBC, 0x36B, 8);
699  /* Break Pressure */
700  msg[0] = 0x00;
701  msg[1] = 0x00;
702  /* NOS pressure Sensor 1 */
703  msg[2] = 0x00;
704  msg[3] = 0x00;
705  /* Turbo Speed Sensor 1 */
706  msg[4] = 0x00;
707  msg[5] = 0x00;
708  /* Lateral G */
709  msg[6] = 0x00;
710  msg[7] = 0x00;
711  }
712 
713  /* 0x36C = 20Hz rate */
714  {
715  CanTxMessage msg(CanCategory::NBC, 0x36C, 8);
716  /* Wheel Speed Front Left */
717  auto vehicleSpeed10 = Sensor::getOrZero(SensorType::VehicleSpeed) * 10;
718  msg.setShortValueMsb(vehicleSpeed10, 0);
719  /* Wheel Speed Front Right */
720  msg.setShortValueMsb(vehicleSpeed10, 2);
721  /* Wheel Speed Read Left */
722  msg.setShortValueMsb(vehicleSpeed10, 4);
723  /* Wheel Speed Read Right */
724  msg.setShortValueMsb(vehicleSpeed10, 6);
725  }
726 
727  /* 0x36D = 20Hz rate */
728  {
729  CanTxMessage msg(CanCategory::NBC, 0x36D, 8);
730  /* Unused */
731  msg[0] = 0x00;
732  msg[1] = 0x00;
733  msg[2] = 0x00;
734  msg[3] = 0x00;
735  /* Exhaust Cam Angle 1 */
736  msg[4] = 0x00;
737  msg[5] = 0x00;
738  /* Exhaust Cam Angle 2 */
739  msg[6] = 0x00;
740  msg[7] = 0x00;
741  }
742 
743  /* 0x36E = 20Hz rate */
744  {
745  CanTxMessage msg(CanCategory::NBC, 0x36E, 8);
746  /* Engine Limiting Active 0 = off/1=on*/
747  msg[0] = 0x00;
748  msg[1] = 0x00;
749  /* Launch Control Ignition Retard */
750  msg[2] = 0x00;
751  msg[3] = 0x00;
752  /* Launch Control Fuel Enrich */
753  msg[4] = 0x00;
754  msg[5] = 0x00;
755  /* Longitudinal G */
756  msg[6] = 0x00;
757  msg[7] = 0x00;
758  }
759 
760  /* 0x36F = 20Hz rate */
761  {
762  CanTxMessage msg(CanCategory::NBC, 0x36F, 4);
763  /* Generic Output 1 Duty Cycle */
764  msg[0] = 0x00;
765  msg[1] = 0x00;
766  /* Boost Control Output */
767  msg[2] = 0x00;
768  msg[3] = 0x00;
769  }
770 
771  /* 0x370 = 20Hz rate */
772  {
773  CanTxMessage msg(CanCategory::NBC, 0x370, 8);
774  /* Vehicle Speed */
775  auto vehicleSpeed10 = Sensor::getOrZero(SensorType::VehicleSpeed);
776  msg.setShortValueMsb(vehicleSpeed10, 0);
777  /* unused */
778  msg[2] = 0x00;
779  msg[3] = 0x00;
780  /* Intake Cam Angle 1 */
781  msg[4] = 0x00;
782  msg[5] = 0x00;
783  /* Intake Cam Angle 2 */
784  msg[6] = 0x00;
785  msg[7] = 0x00;
786  }
787 
788  /* todo: 0x3E6 = 20Hz rate */
789  {
790  CanTxMessage msg(CanCategory::NBC, 0x3E6, 8);
791  msg[0] = 0x00;
792  msg[1] = 0x00;
793  msg[2] = 0x00;
794  msg[3] = 0x00;
795  msg[4] = 0x00;
796  msg[5] = 0x00;
797  msg[6] = 0x00;
798  msg[7] = 0x00;
799  }
800 
801  /* todo: 0x3E7 = 20Hz rate */
802  {
803  CanTxMessage msg(CanCategory::NBC, 0x3E7, 8);
804  msg[0] = 0x00;
805  msg[1] = 0x00;
806  msg[2] = 0x00;
807  msg[3] = 0x00;
808  msg[4] = 0x00;
809  msg[5] = 0x00;
810  msg[6] = 0x00;
811  msg[7] = 0x00;
812  }
813 
814  /* todo: 0x3E8 = 20Hz rate */
815  {
816  CanTxMessage msg(CanCategory::NBC, 0x3E8, 8);
817  msg[0] = 0x00;
818  msg[1] = 0x00;
819  msg[2] = 0x00;
820  msg[3] = 0x00;
821  msg[4] = 0x00;
822  msg[5] = 0x00;
823  msg[6] = 0x00;
824  msg[7] = 0x00;
825  }
826 
827  /* todo: 0x3E9 = 20Hz rate */
828  {
829  CanTxMessage msg(CanCategory::NBC, 0x3E9, 8);
830  msg[0] = 0x00;
831  msg[1] = 0x00;
832  msg[2] = 0x00;
833  msg[3] = 0x00;
834  msg[4] = 0x00;
835  msg[5] = 0x00;
836  msg[6] = 0x00;
837  msg[7] = 0x00;
838  }
839 
840  /* todo: 0x3EE = 20Hz rate */
841  {
842  CanTxMessage msg(CanCategory::NBC, 0x3EE, 8);
843  msg[0] = 0x00;
844  msg[1] = 0x00;
845  msg[2] = 0x00;
846  msg[3] = 0x00;
847  msg[4] = 0x00;
848  msg[5] = 0x00;
849  msg[6] = 0x00;
850  msg[7] = 0x00;
851  }
852 
853  /* todo: 0x3EF = 20Hz rate */
854  {
855  CanTxMessage msg(CanCategory::NBC, 0x3EF, 8);
856  msg[0] = 0x00;
857  msg[1] = 0x00;
858  msg[2] = 0x00;
859  msg[3] = 0x00;
860  msg[4] = 0x00;
861  msg[5] = 0x00;
862  msg[6] = 0x00;
863  msg[7] = 0x00;
864  }
865 
866  /* todo: 0x470 = 20Hz rate */
867  {
868  CanTxMessage msg(CanCategory::NBC, 0x470, 8);
869  msg[0] = 0x00;
870  msg[1] = 0x00;
871  msg[2] = 0x00;
872  msg[3] = 0x00;
873  msg[4] = 0x00;
874  msg[5] = 0x00;
875  // todo: open question what are Haltech Special Values for gear encoding
877  msg[7] = 0x00;
878  }
879 
880  /* todo: 0x472 = 20Hz rate */
881  {
882  CanTxMessage msg(CanCategory::NBC, 0x472, 8);
883  msg[0] = 0x00;
884  msg[1] = 0x00;
885  msg[2] = 0x00;
886  msg[3] = 0x00;
887  msg[4] = 0x00;
888  msg[5] = 0x00;
889  msg[6] = 0x00;
890  msg[7] = 0x00;
891  }
892  }
893 
894  if (cycle.isInterval(CI::_100ms)) {
895 
896  /* 0x371 = 10Hz rate */
897  {
898  CanTxMessage msg(CanCategory::NBC, 0x371, 4);
899  /* Fuel Flow */
900  msg[0] = 0x00;
901  msg[1] = 0x00;
902  /* Fuel Flow Return */
903  msg[2] = 0x00;
904  msg[3] = 0x00;
905  }
906 
907  /* 0x372 = 10Hz rate */
908  {
909  CanTxMessage msg(CanCategory::NBC, 0x372, 8);
910  /* Battery Voltage */
912  /* unused */
913  msg[2] = 0x00;
914  msg[3] = 0x00;
915  /* Target Boost Level todo */
916  msg[4] = 0x00;
917  msg[5] = 0x00;
918  /* Barometric pressure */
920  }
921 
922  /* 0x373 = 10Hz rate */
923  {
924  CanTxMessage msg(CanCategory::NBC, 0x373, 8);
925  /* EGT1 */
926  msg[0] = 0x00;
927  msg[1] = 0x00;
928  /* EGT2 */
929  msg[2] = 0x00;
930  msg[3] = 0x00;
931  /* EGT3 */
932  msg[4] = 0x00;
933  msg[5] = 0x00;
934  /* EGT4 */
935  msg[6] = 0x00;
936  msg[7] = 0x00;
937  }
938 
939  /* 0x374 = 10Hz rate */
940  {
941  CanTxMessage msg(CanCategory::NBC, 0x374, 8);
942  /* EGT5 */
943  msg[0] = 0x00;
944  msg[1] = 0x00;
945  /* EGT6 */
946  msg[2] = 0x00;
947  msg[3] = 0x00;
948  /* EGT7 */
949  msg[4] = 0x00;
950  msg[5] = 0x00;
951  /* EGT8 */
952  msg[6] = 0x00;
953  msg[7] = 0x00;
954  }
955 
956  /* 0x375 = 10Hz rate */
957  {
958  CanTxMessage msg(CanCategory::NBC, 0x375, 8);
959  /* EGT9 */
960  msg[0] = 0x00;
961  msg[1] = 0x00;
962  /* EGT10 */
963  msg[2] = 0x00;
964  msg[3] = 0x00;
965  /* EGT11 */
966  msg[4] = 0x00;
967  msg[5] = 0x00;
968  /* EGT12 */
969  msg[6] = 0x00;
970  msg[7] = 0x00;
971  }
972 
973  /* 0x376 = 10Hz rate */
974  {
975  CanTxMessage msg(CanCategory::NBC, 0x376, 8);
976  /* Ambient Air Temperature */
977  msg[0] = 0x00;
978  msg[1] = 0x00;
979  /* Relative Humidity */
980  msg[2] = 0x00;
981  msg[3] = 0x00;
982  /* Specific Humidity */
983  msg[4] = 0x00;
984  msg[5] = 0x00;
985  /* Absolute Humidity */
986  msg[6] = 0x00;
987  msg[7] = 0x00;
988  }
989  }
990 
991  if (cycle.isInterval(CI::_200ms)) {
992  /* 0x3E0 = 5Hz rate */
993  {
994  CanTxMessage msg(CanCategory::NBC, 0x3E0, 8);
995  /* Coolant temperature in K y = x/10 */
996  msg.setShortValueMsb((Sensor::getOrZero(SensorType::Clt) + 273.15) * 10, 0);
997  /* Air Temperature */
998  msg.setShortValueMsb((Sensor::getOrZero(SensorType::Iat) + 273.15) * 10, 2);
999  /* Fuel Temperature */
1000  msg[4] = 0x00;
1001  msg[5] = 0x00;
1002  /* Oil Temperature */
1003  msg[6] = 0x00;
1004  msg[7] = 0x00;
1005  }
1006 
1007  /* 0x3E1 = 5Hz rate */
1008  {
1009  CanTxMessage msg(CanCategory::NBC, 0x3E1, 6);
1010  /* Gearbox Oil Temperature */
1011  msg[0] = 0x00;
1012  msg[1] = 0x00;
1013  /* Diff oil Temperature */
1014  msg[2] = 0x00;
1015  msg[3] = 0x00;
1016  /* Fuel Composition */
1017  msg[4] = 0x00;
1018  msg[5] = 0x00;
1019  }
1020 
1021  /* 0x3E2 = 5Hz rate */
1022  {
1023  CanTxMessage msg(CanCategory::NBC, 0x3E2, 2);
1024  /* Fuel Level in Liters */
1026  }
1027 
1028  /* 0x3E3 = 5Hz rate */
1029  {
1030  CanTxMessage msg(CanCategory::NBC, 0x3E3, 8);
1031  /* Fuel Trim Short Term Bank 1*/
1032  msg[0] = 0x00;
1033  msg[1] = 0x00;
1034  /* Fuel Trim Short Term Bank 2*/
1035  msg[2] = 0x00;
1036  msg[3] = 0x00;
1037  /* Fuel Trim Long Term Bank 1*/
1038  msg[4] = 0x00;
1039  msg[5] = 0x00;
1040  /* Fuel Trim Long Term Bank 2*/
1041  msg[6] = 0x00;
1042  msg[7] = 0x00;
1043  }
1044 
1045  /* todo: 0x3E4 = 5Hz rate */
1046  {
1047  CanTxMessage msg(CanCategory::NBC, 0x3E4, 8);
1048  msg[0] = 0x00; //unused
1050  msg.setBit(1, 2); // Brake active
1051  }
1053  msg.setBit(1, 1); // Clutch active
1054  }
1055 #if EFI_LAUNCH_CONTROL
1057  msg.setBit(2, 7); // Launch active
1058  }
1060  msg.setBit(2, 6); // Launch Switch active
1061  }
1062 #endif
1064  msg.setBit(3, 5); // AC Request
1065  }
1067  msg.setBit(3, 4); // AC Output
1068  }
1070  msg.setBit(3, 1); // Fan2 active
1071  }
1073  msg.setBit(3, 0); // Fan active
1074  }
1075  /* Switch status */
1076  msg[4] = 0x00;
1077  msg[5] = 0x00;
1078  msg[6] = 0x00;
1079  if ((Sensor::getOrZero(SensorType::Rpm)>0) && (Sensor::get(SensorType::BatteryVoltage).value_or(VBAT_FALLBACK_VALUE)<13)) {
1080  msg.setBit(7, 6); // battery light
1081  }
1082  }
1083 
1084  }
1085 }
1086 
1087 //Based on AIM can protocol
1088 //https://www.aimtechnologies.com/support/racingecu/AiM_CAN_101_eng.pdf
1089 
1090 struct Aim5f0 {
1091  scaled_channel<uint16_t, 1> Rpm;
1092  scaled_channel<uint16_t, 650> Tps;
1093  scaled_channel<uint16_t, 650> Pps;
1094  scaled_channel<uint16_t, 100> Vss;
1095 };
1096 
1097 static void populateFrame(Aim5f0& msg) {
1102 }
1103 
1104 struct Aim5f1 {
1105  scaled_channel<uint16_t, 10> WheelSpeedFR;
1106  scaled_channel<uint16_t, 10> WheelSpeedFL;
1107  scaled_channel<uint16_t, 10> WheelSpeedRR;
1108  scaled_channel<uint16_t, 10> WheelSpeedRL;
1109 };
1110 
1111 static void populateFrame(Aim5f1& msg) {
1112  // We don't handle wheel speed, just set to 0?
1113  msg.WheelSpeedFR = 0;
1114  msg.WheelSpeedFL = 0;
1115  msg.WheelSpeedRR = 0;
1116  msg.WheelSpeedRL = 0;
1117 }
1118 
1119 struct Aim5f2 {
1120  scaled_channel<uint16_t, 190> Iat;
1121  scaled_channel<uint16_t, 190> Ect;
1122  scaled_channel<uint16_t, 190> FuelT;
1123  scaled_channel<uint16_t, 190> OilT;
1124 };
1125 
1126 static void populateFrame(Aim5f2& msg) {
1127  msg.Iat = Sensor::getOrZero(SensorType::Iat) + 45;
1128  msg.Ect = Sensor::getOrZero(SensorType::Clt) + 45;
1129  msg.FuelT = Sensor::getOrZero(SensorType::AuxTemp1) + 45;
1130  msg.OilT = Sensor::getOrZero(SensorType::AuxTemp2) + 45;
1131 }
1132 
1133 struct Aim5f3 {
1134  scaled_channel<uint16_t, 10> Map;
1135  scaled_channel<uint16_t, 10> Baro;
1136  scaled_channel<uint16_t, 1000> OilP;
1137  scaled_channel<uint16_t, 20> FuelP;
1138 };
1139 
1140 static void populateFrame(Aim5f3& msg) {
1141  // MAP/Baro are sent in millibar -> 10 millibar per kpa
1142  msg.Map = 10 * Sensor::getOrZero(SensorType::Map);
1144 
1145  // Oil/Fuel P use bar -> 100 kpa per bar
1146  msg.OilP = Sensor::getOrZero(SensorType::OilPressure) / 100;
1148 }
1149 
1150 struct Aim5f4 {
1151  scaled_channel<uint16_t, 10000> Boost;
1152  scaled_channel<uint16_t, 3200> Vbat;
1153  scaled_channel<uint16_t, 10> FuelUse;
1154  scaled_channel<int16_t, 1> Gear;
1155 };
1156 
1157 static void populateFrame(Aim5f4& msg) {
1158  float deltaKpa = Sensor::getOrZero(SensorType::Map)
1159  - Sensor::get(SensorType::BarometricPressure).value_or(101.325);
1160  float boostBar = deltaKpa / 100;
1161 
1162  msg.Boost = boostBar;
1164  msg.FuelUse = 0;
1166 }
1167 
1168 struct Aim5f5 {
1169  scaled_channel<uint16_t, 1> ShiftFlag;
1170  scaled_channel<uint16_t, 1> GearTime;
1171  scaled_channel<uint16_t, 1> TpsV;
1172  scaled_channel<uint16_t, 100> FuelLevel;
1173 };
1174 
1175 static void populateFrame(Aim5f5& msg) {
1176  msg.FuelLevel = Sensor::getOrZero(SensorType::FuelLevel);
1177 
1178  // Dunno what to do with these
1179  msg.ShiftFlag = 0;
1180  msg.GearTime = 0;
1181  msg.TpsV = 0;
1182 }
1183 
1184 struct Aim5f6 {
1185  scaled_channel<uint16_t, 2000> Lambda1;
1186  scaled_channel<uint16_t, 2000> Lambda2;
1187  scaled_channel<uint16_t, 10> LambdaTemp1;
1188  scaled_channel<uint16_t, 10> LambdaTemp2;
1189 };
1190 
1191 static void populateFrame(Aim5f6& msg) {
1192  msg.Lambda1 = Sensor::getOrZero(SensorType::Lambda1);
1193  msg.Lambda2 = Sensor::getOrZero(SensorType::Lambda2);
1194  msg.LambdaTemp1 = 0;
1195  msg.LambdaTemp2 = 0;
1196 }
1197 
1198 struct Aim5f7 {
1199  scaled_channel<uint16_t, 10> LambdaErr1;
1200  scaled_channel<uint16_t, 10> LambdaErr2;
1201  scaled_channel<uint16_t, 2000> LambdaTarget1;
1202  scaled_channel<uint16_t, 2000> LambdaTarget2;
1203 };
1204 
1205 static void populateFrame(Aim5f7& msg) {
1206 #if EFI_ENGINE_CONTROL
1207  // We don't handle wheel speed, just set to 0?
1208  msg.LambdaErr1 = 0;
1209  msg.LambdaErr2 = 0;
1210  // both targets are the same for now
1211  msg.LambdaTarget1 = (float)engine->fuelComputer.targetLambda;
1212  msg.LambdaTarget2 = (float)engine->fuelComputer.targetLambda;
1213 #endif // EFI_ENGINE_CONTROL
1214 }
1215 
1217  if (!cycle.isInterval(CI::_10ms)) {
1218  return;
1219  }
1220 
1222 
1223  transmitStruct<Aim5f0>(CanCategory::NBC, 0x5f0, false, canChannel);
1224  transmitStruct<Aim5f1>(CanCategory::NBC, 0x5f1, false, canChannel);
1225  transmitStruct<Aim5f2>(CanCategory::NBC, 0x5f2, false, canChannel);
1226  transmitStruct<Aim5f3>(CanCategory::NBC, 0x5f3, false, canChannel);
1227  transmitStruct<Aim5f4>(CanCategory::NBC, 0x5f4, false, canChannel);
1228  transmitStruct<Aim5f5>(CanCategory::NBC, 0x5f5, false, canChannel);
1229  transmitStruct<Aim5f6>(CanCategory::NBC, 0x5f6, false, canChannel);
1230  transmitStruct<Aim5f7>(CanCategory::NBC, 0x5f7, false, canChannel);
1231 
1232  // there are more, but less important for us
1233  // transmitStruct<Aim5f8>(0x5f8, false);
1234  // transmitStruct<Aim5f9>(0x5f9, false);
1235  // transmitStruct<Aim5fa>(0x5fa, false);
1236  // transmitStruct<Aim5fb>(0x5fb, false);
1237  // transmitStruct<Aim5fc>(0x5fc, false);
1238  // transmitStruct<Aim5fd>(0x5fd, false);
1239 }
1240 
1241 PUBLIC_API_WEAK void boardUpdateDash(CanCycle cycle) {}
1242 
1243 void updateDash(CanCycle cycle) {
1245  boardUpdateDash(cycle);
1246  }
1247 
1248  // Transmit dash data, if enabled
1249  switch (engineConfiguration->canNbcType) {
1250  case CAN_BUS_NBC_NONE:
1251  break;
1252  case CAN_BUS_BMW_E46:
1253  canDashboardBmwE46(cycle);
1254  break;
1255  case CAN_BUS_Haltech:
1256  canDashboardHaltech(cycle);
1257  break;
1258  case CAN_BUS_NBC_FIAT:
1259  canDashboardFiat(cycle);
1260  break;
1261  case CAN_BUS_NBC_VAG:
1262  canDashboardVAG(cycle);
1263  break;
1264  case CAN_BUS_MAZDA_RX8:
1265  canMazdaRX8(cycle);
1266  break;
1267  case CAN_BUS_W202_C180:
1268  canDashboardW202(cycle);
1269  break;
1270  case CAN_BUS_BMW_E90:
1271  canDashboardBmwE90(cycle);
1272  break;
1273  case CAN_BUS_MQB:
1274  canDashboardVagMqb(cycle);
1275  break;
1276  case CAN_BUS_NISSAN_VQ:
1277  canDashboardNissanVQ(cycle);
1278  break;
1279  case CAN_BUS_GENESIS_COUPE:
1280  canDashboardGenesisCoupe(cycle);
1281  break;
1282  case CAN_AIM_DASH:
1283  canDashboardAim(cycle);
1284  break;
1285  case CAN_BUS_MS_SIMPLE_BROADCAST:
1286  canDashboardTS(cycle);
1287  break;
1288  default:
1289  criticalError("Nothing for canNbcType %s", getCan_nbc_e(engineConfiguration->canNbcType));
1290  break;
1291  }
1292 }
1293 
1294 #endif // EFI_CAN_SUPPORT
const char * getCan_nbc_e(can_nbc_e value)
static uint8_t mph_last
Definition: can_dash.cpp:116
static uint8_t brakecnt_2
Definition: can_dash.cpp:115
static uint8_t tmp_cnt
Definition: can_dash.cpp:116
void canDashboardNissanVQ(CanCycle cycle)
Definition: can_dash.cpp:323
static void canDashboardBmwE46(CanCycle cycle)
Definition: can_dash.cpp:134
void canMazdaRX8(CanCycle cycle)
Definition: can_dash.cpp:155
static void canDashboardBmwE90(CanCycle cycle)
Definition: can_dash.cpp:376
constexpr uint8_t e90_temp_offset
Definition: can_dash.cpp:120
PUBLIC_API_WEAK void boardUpdateDash(CanCycle cycle)
Definition: can_dash.cpp:1241
void canDashboardW202(CanCycle cycle)
Definition: can_dash.cpp:252
static time_msecs_t mph_ctr
Definition: can_dash.cpp:53
static uint8_t rpmcounter
Definition: can_dash.cpp:112
static uint8_t gear_cnt
Definition: can_dash.cpp:116
static uint16_t mph_counter
Definition: can_dash.cpp:117
void canDashboardAim(CanCycle cycle)
Definition: can_dash.cpp:1216
void canDashboardVAG(CanCycle cycle)
Definition: can_dash.cpp:224
static uint8_t abscounter
Definition: can_dash.cpp:114
void canDashboardGenesisCoupe(CanCycle cycle)
Definition: can_dash.cpp:309
static int rollingId
Definition: can_dash.cpp:307
void canDashboardFiat(CanCycle cycle)
Definition: can_dash.cpp:213
static uint8_t mph_2a
Definition: can_dash.cpp:116
static uint8_t brakecnt_1
Definition: can_dash.cpp:115
static uint8_t seatbeltcnt
Definition: can_dash.cpp:113
static uint8_t mph_a
Definition: can_dash.cpp:116
static void populateFrame(Aim5f0 &msg)
Definition: can_dash.cpp:1097
static bool cluster_time_set
Definition: can_dash.cpp:118
void canDashboardVagMqb(CanCycle cycle)
Definition: can_dash.cpp:360
void canDashboardHaltech(CanCycle cycle)
Definition: can_dash.cpp:527
void updateDash(CanCycle cycle)
Definition: can_dash.cpp:1243
static time_msecs_t mph_timer
Definition: can_dash.cpp:52
void canDashboardTS(CanCycle cycle)
Definition: can.h:84
bool isInterval(CanInterval interval)
Definition: can.h:91
void setBit(size_t byteIdx, size_t bitIdx)
Set a single bit in the transmit buffer. Useful for single-bit flags.
Definition: can_msg_tx.cpp:128
void setShortValueMsb(uint16_t value, size_t offset)
Definition: can_msg_tx.cpp:123
void setShortValue(uint16_t value, size_t offset)
Write a 16-bit short value to the buffer. Note: this writes in little endian byte order.
Definition: can_msg_tx.cpp:117
FuelComputer fuelComputer
Definition: engine.h:121
TriggerCentral triggerCentral
Definition: engine.h:286
LaunchControlBase launchController
Definition: engine.h:192
EngineState engineState
Definition: engine.h:315
constexpr auto & module()
Definition: engine.h:177
RegisteredOutputPin fanRelay
Definition: efi_gpio.h:86
RegisteredOutputPin fanRelay2
Definition: efi_gpio.h:87
angle_t timingAdvance[MAX_CYLINDER_COUNT]
Definition: engine_state.h:58
bool getLogicValue() const
Definition: efi_gpio.cpp:646
virtual SensorResult get() const =0
static float getOrZero(SensorType type)
Definition: sensor.h:92
PrimaryTriggerDecoder triggerState
int getHwEventCounter(int index) const
uint32_t totalTriggerErrorCounter
EnginePins enginePins
Definition: efi_gpio.cpp:24
uint16_t SWAP_UINT16(uint16_t x)
Definition: efilib.h:22
Engine * engine
percent_t getInjectorDutyCycle(int rpm)
Definition: fuel_math.cpp:279
static CCM_OPTIONAL FunctionalSensor clt(SensorType::Clt, MS2NT(10))
engine_configuration_s * engineConfiguration
efidatetime_t getRtcDateTime()
Definition: rtc_helper.cpp:55
Real Time Clock helper.
@ FuelPressureInjector
@ BarometricPressure
m_knockLevel("Knock: Current level", SensorCategory.SENSOR_INPUTS, FieldType.INT, 924, 1.0, 0.0, 0.0, "Volts")
@ SHAFT_PRIMARY_FALLING
uint8_t minute
Definition: rusefi_types.h:53
uint8_t hour
Definition: rusefi_types.h:52
uint8_t second
Definition: rusefi_types.h:54
uint32_t year
Definition: rusefi_types.h:49
uint8_t month
Definition: rusefi_types.h:50
scaled_channel< uint16_t, 10000, 1 > targetLambda
static CanTsChannel canChannel