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