rusEFI
The most advanced open source ECU
Loading...
Searching...
No Matches
can_dash_haltech.cpp
Go to the documentation of this file.
1// file can_dash_haltech.cpp
2//
3// Haltech CAN bus operates at 1 MBit/s and uses 11-bit IDs
4// https://support.haltech.com/portal/en/kb/articles/haltech-can-ecu-broadcast-protocol
5// https://support.haltech.com/portal/en/kb/articles/haltech-can-protocol-specification
6
7#include "pch.h"
8
9#if EFI_CAN_SUPPORT
10#include "can.h"
11#include "can_msg_tx.h"
12#include "fuel_math.h"
13
15 criticalAssertVoid(engineConfiguration->canBaudRate == B1MBPS, "Haltech requires 1Mbps baud rate");
16
17 if (cycle.isInterval(CI::_20ms)) {
18 /* 0x360 - 50Hz rate */
19 {
20 CanTxMessage msg(CanCategory::NBC, 0x360, 8);
23 /* TPS y = x/10 */
25 /* Coolant pressure */
26 msg[6] = 0;
27 msg[7] = 0;
28 }
29
30 /* 0x361 - 50Hz rate */
31 {
32 CanTxMessage msg(CanCategory::NBC, 0x361, 8);
33 /* Fuel pressure */
34 msg.setShortValueMsb((Sensor::getOrZero(SensorType::FuelPressureLow) + STD_ATMOSPHERE) * 10, 0);
35 /* Oil pressure */
36 msg.setShortValueMsb((Sensor::getOrZero(SensorType::OilPressure) + STD_ATMOSPHERE) * 10, 2);
37 /* Engine Demand */
39 /* Wastegate Pressure */
40 msg[6] = 0;
41 msg[7] = 0;
42 }
43
44#if EFI_ENGINE_CONTROL
45 /* 0x362 - 50Hz rate */
46 {
47 CanTxMessage msg(CanCategory::NBC, 0x362, 6);
48 /* Injection Stage 1 Duty Cycle - y = x/10 */
49 uint16_t rpm = Sensor::getOrZero(SensorType::Rpm);
50 msg.setShortValueMsb(getInjectorDutyCycle(rpm) * 10, 0);
51 /* Injection Stage 2 Duty Cycle */
52 msg[2] = 0x00;
53 msg[3] = 0x00;
54 /* Ignition Angle (Leading) - y = x/10 */
55 float timing = engine->engineState.timingAdvance[0];
56 int16_t ignAngle = ((timing > 360 ? timing - 720 : timing) * 10);
57 msg.setShortValueMsb(ignAngle, 4);
58 }
59#endif // EFI_ENGINE_CONTROL
60
61 /* todo: 0x3E5 = 50Hz rate */
62 {
63 CanTxMessage msg(CanCategory::NBC, 0x3E5, 8);
64 msg[0] = 0x00; //Ignition Switch
65 msg[1] = 0x00; //Turbo Timer - Time Remaining
66 msg[2] = 0x00; //Turbo Timer - Engine Time Remaining
67 msg[3] = 0x00;
68 msg[4] = 0x00; //4-5 Steering Wheel Angle
69 msg[5] = 0x00;
70 msg[6] = 0x00; //6-7 Driveshaft RPM
71 msg[7] = 0x00;
72 }
73
74 /* todo: 0x3EA = 50Hz rate */
75 {
76 CanTxMessage msg(CanCategory::NBC, 0x3EA, 8);
77 msg[0] = 0x00; //0-1 Gearbox Line Pressure
78 msg[1] = 0x00;
79 msg[2] = 0x00; //2-3 Injection Stage 3 Duty Cycle
80 msg[3] = 0x00;
81 msg[4] = 0x00; //4-5 Injection Stage 4 Duty Cycle
82 msg[5] = 0x00;
83 msg[6] = 0x00; //Crank Case Pressure
84 msg[7] = 0x00;
85 }
86
87 /* todo: 0x3EB = 50Hz rate */
88 {
89 CanTxMessage msg(CanCategory::NBC, 0x3EB, 8);
90 msg[0] = 0x00; //0-3 Race Timer
91 msg[1] = 0x00;
92 msg[2] = 0x00;
93 msg[3] = 0x00;
94 msg[4] = 0x00; //4-5 Ignition Angle Bank 1
95 msg[5] = 0x00;
96 msg[6] = 0x00; //6-7 Ignition Angle Bank 2
97 msg[7] = 0x00;
98 }
99
100 /* todo: 0x3EC = 50Hz rate */
101 {
102 CanTxMessage msg(CanCategory::NBC, 0x3EC, 8);
103 msg[0] = 0x00; //0-1 Torque Management Driveshaft RPM Target
104 msg[1] = 0x00;
105 msg[2] = 0x00; //2-3 Torque Management Driveshaft RPM Target Error
106 msg[3] = 0x00;
107 msg[4] = 0x00; //4-5 Torque Management Driveshaft RPM Target Error Ignition Correction
108 msg[5] = 0x00;
109 msg[6] = 0x00; //6-7 Torque Management Driveshaft RPM Timed Ignition Correction
110 msg[7] = 0x00;
111 }
112
113 /* todo: 0x3ED = 50Hz rate */
114 {
115 CanTxMessage msg(CanCategory::NBC, 0x3ED, 2);
116 msg[0] = 0x00; //0-1 Torque Management Combined Ignition Correction
117 msg[1] = 0x00;
118 }
119
120 /* todo: 0x471 = 50Hz rate */
121 {
122 CanTxMessage msg(CanCategory::NBC, 0x471, 6);
123 msg[0] = 0x00; //0-1 Injector Pressure Differential
124 msg[1] = 0x00;
126 msg[4] = 0x00; //4-5 Exhaust Manifold Pressure
127 msg[5] = 0x00;
128 }
129 }
130
131 if (cycle.isInterval(CI::_50ms)) {
132
133 /* 0x363 - 20Hz rate */
134 {
135 CanTxMessage msg(CanCategory::NBC, 0x363, 4);
136 /* Wheel Slip */
137 msg[0] = 0x00;
138 msg[1] = 0x00;
139 /* Wheel Diff */
140 msg[2] = 0x00;
141 msg[3] = 0x00 ;
142 }
143
144 /* 0x368 - 20Hz rate */
145 {
146 CanTxMessage msg(CanCategory::NBC, 0x368, 8);
147 /* Wideband Sensor 1 */
149 /* Wideband Sensor 2 */
151 /* Wideband Sensor 3 */
152 msg[4] = 0x00;
153 msg[5] = 0x00;
154 /* Wideband Sensor 4 */
155 msg[6] = 0x00;
156 msg[7] = 0x00;
157 }
158
159#if EFI_SHAFT_POSITION_INPUT
160 /* 0x369 - 20Hz rate */
161 {
162 CanTxMessage msg(CanCategory::NBC, 0x369, 8);
163 /* Trigger System Error Count */
165 /* Trigger Counter ?? */
167 /* unused */
168 msg[4] = 0x00;
169 msg[5] = 0x00;
170 /* Trigger Sync Level ?? */
171 msg[6] = 0x00;
172 msg[7] = 0x00;
173 }
174#endif // EFI_SHAFT_POSITION_INPUT
175
176 /* 0x36A - 20Hz rate */
177 /* todo: one day we should split this */
178 {
179 CanTxMessage msg(CanCategory::NBC, 0x36A, 4);
180 /* Knock Level 1 */
181 int knock100 = engine->module<KnockController>()->m_knockLevel * 100;
182 msg.setShortValueMsb(knock100, 0);
183 /* Knock Level 2 */
184 msg.setShortValueMsb(knock100, 2);
185 }
186
187 /* 0x36B - 20Hz rate */
188 {
189 CanTxMessage msg(CanCategory::NBC, 0x36B, 8);
190 /* Break Pressure */
191 msg[0] = 0x00;
192 msg[1] = 0x00;
193 /* NOS pressure Sensor 1 */
194 msg[2] = 0x00;
195 msg[3] = 0x00;
196 /* Turbo Speed Sensor 1 */
197 msg[4] = 0x00;
198 msg[5] = 0x00;
199 /* Lateral G */
200 msg[6] = 0x00;
201 msg[7] = 0x00;
202 }
203
204 /* 0x36C = 20Hz rate */
205 {
206 CanTxMessage msg(CanCategory::NBC, 0x36C, 8);
207 /* Wheel Speed Front Left */
208 auto vehicleSpeed10 = Sensor::getOrZero(SensorType::VehicleSpeed) * 10;
209 msg.setShortValueMsb(vehicleSpeed10, 0);
210 /* Wheel Speed Front Right */
211 msg.setShortValueMsb(vehicleSpeed10, 2);
212 /* Wheel Speed Read Left */
213 msg.setShortValueMsb(vehicleSpeed10, 4);
214 /* Wheel Speed Read Right */
215 msg.setShortValueMsb(vehicleSpeed10, 6);
216 }
217
218 /* 0x36D = 20Hz rate */
219 {
220 CanTxMessage msg(CanCategory::NBC, 0x36D, 8);
221 /* Unused */
222 msg[0] = 0x00;
223 msg[1] = 0x00;
224 msg[2] = 0x00;
225 msg[3] = 0x00;
226 /* Exhaust Cam Angle 1 */
227 msg[4] = 0x00;
228 msg[5] = 0x00;
229 /* Exhaust Cam Angle 2 */
230 msg[6] = 0x00;
231 msg[7] = 0x00;
232 }
233
234 /* 0x36E = 20Hz rate */
235 {
236 CanTxMessage msg(CanCategory::NBC, 0x36E, 8);
237 /* Engine Limiting Active 0 = off/1=on*/
238 msg[0] = 0x00;
239 msg[1] = 0x00;
240 /* Launch Control Ignition Retard */
241 msg[2] = 0x00;
242 msg[3] = 0x00;
243 /* Launch Control Fuel Enrich */
244 msg[4] = 0x00;
245 msg[5] = 0x00;
246 /* Longitudinal G */
247 msg[6] = 0x00;
248 msg[7] = 0x00;
249 }
250
251 /* 0x36F = 20Hz rate */
252 {
253 CanTxMessage msg(CanCategory::NBC, 0x36F, 4);
254 /* Generic Output 1 Duty Cycle */
255 msg[0] = 0x00;
256 msg[1] = 0x00;
257 /* Boost Control Output */
258 msg[2] = 0x00;
259 msg[3] = 0x00;
260 }
261
262 /* 0x370 = 20Hz rate */
263 {
264 CanTxMessage msg(CanCategory::NBC, 0x370, 8);
265 /* Vehicle Speed */
266 auto vehicleSpeed10 = Sensor::getOrZero(SensorType::VehicleSpeed) * 10;
267 msg.setShortValueMsb(vehicleSpeed10, 0);
268 /* unused */
269 msg[2] = 0x00;
270 msg[3] = 0x00;
271 /* Intake Cam Angle 1 */
272 msg[4] = 0x00;
273 msg[5] = 0x00;
274 /* Intake Cam Angle 2 */
275 msg[6] = 0x00;
276 msg[7] = 0x00;
277 }
278
279 /* todo: 0x3E6 = 20Hz rate */
280 {
281 CanTxMessage msg(CanCategory::NBC, 0x3E6, 8);
282 msg[0] = 0x00; //0-1 NOS Pressure Sensor 2
283 msg[1] = 0x00;
284 msg[2] = 0x00; //2-3 NOS Pressure Sensor 3
285 msg[3] = 0x00;
286 msg[4] = 0x00; //4-5 NOS Pressure Sensor 4
287 msg[5] = 0x00;
288 msg[6] = 0x00; //6-7 Turbo Speed Sensor 2
289 msg[7] = 0x00;
290 }
291
292 /* todo: 0x3E7 = 20Hz rate */
293 {
294 CanTxMessage msg(CanCategory::NBC, 0x3E7, 8);
295 msg[0] = 0x00; //0-1 Generic Sensor 1
296 msg[1] = 0x00;
297 msg[2] = 0x00; //2-3 Generic Sensor 2
298 msg[3] = 0x00;
299 msg[4] = 0x00; //4-5 Generic Sensor 3
300 msg[5] = 0x00;
301 msg[6] = 0x00; //6-7 Generic Sensor 4
302 msg[7] = 0x00;
303 }
304
305 /* todo: 0x3E8 = 20Hz rate */
306 {
307 CanTxMessage msg(CanCategory::NBC, 0x3E8, 8);
308 msg[0] = 0x00; //0-1 Generic Sensor 5
309 msg[1] = 0x00;
310 msg[2] = 0x00; //2-3 Generic Sensor 6
311 msg[3] = 0x00;
312 msg[4] = 0x00; //4-5 Generic Sensor 7
313 msg[5] = 0x00;
314 msg[6] = 0x00; //6-7 Generic Sensor 8
315 msg[7] = 0x00;
316 }
317
318 /* todo: 0x3E9 = 20Hz rate */
319 {
320 CanTxMessage msg(CanCategory::NBC, 0x3E9, 8);
321 msg[0] = 0x00; //0-1 Generic Sensor 9
322 msg[1] = 0x00;
323 msg[2] = 0x00; //2-3 Generic Sensor 10
324 msg[3] = 0x00;
325 msg[4] = 0x00; //4-5 Target Lambda
326 msg[5] = 0x00;
327 msg[6] = 0x00; //Nitous Stage Output
328 msg[7] = 0x00; //Torque Management Knob
329 }
330
331 /* todo: 0x3EE = 20Hz rate */
332 {
333 CanTxMessage msg(CanCategory::NBC, 0x3EE, 8);
334 msg[0] = 0x00; //0-1 Wideband Sensor 5
335 msg[1] = 0x00;
336 msg[2] = 0x00; //2-3 Wideband Sensor 6
337 msg[3] = 0x00;
338 msg[4] = 0x00; //4-5 Wideband Sensor 7
339 msg[5] = 0x00;
340 msg[6] = 0x00; //6-7 Wideband Sensor 8
341 msg[7] = 0x00;
342 }
343
344 /* todo: 0x3EF = 20Hz rate */
345 {
346 CanTxMessage msg(CanCategory::NBC, 0x3EF, 8);
347 msg[0] = 0x00; //0-1 Wideband Sensor 9
348 msg[1] = 0x00;
349 msg[2] = 0x00; //2-3 Wideband Sensor 10
350 msg[3] = 0x00;
351 msg[4] = 0x00; //4-5 Wideband Sensor 11
352 msg[5] = 0x00;
353 msg[6] = 0x00; //6-7 Wideband Sensor 12
354 msg[7] = 0x00;
355 }
356
357 /* todo: 0x470 = 20Hz rate */
358 {
359 CanTxMessage msg(CanCategory::NBC, 0x470, 8);
360 msg[0] = 0x00; //0-1 Wideband Overall
361 msg[1] = 0x00;
362 msg[2] = 0x00; //2-3 Wideband Bank 1
363 msg[3] = 0x00;
364 msg[4] = 0x00; //4-5 Wideband Bank 2
365 msg[5] = 0x00;
366 // todo: open question what are Haltech Special Values for gear encoding
367 msg[6] = 0x00; //Gear Selector Position
369 }
370
371 /* todo: 0x472 = 20Hz rate */
372 {
373 CanTxMessage msg(CanCategory::NBC, 0x472, 8);
374 msg[0] = 0x00; //0-1 Cruise Control Target Speed
375 msg[1] = 0x00;
376 msg[2] = 0x00; //2-3 Cruise Control Last Target Speed
377 msg[3] = 0x00;
378 msg[4] = 0x00; //4-5 Cruise Control Speed Error
379 msg[5] = 0x00;
380 msg[6] = 0x00; //Cruise Control Controller state (enum)
381 msg[7] = 0x00; //Cruise Control Input State (bit-field)
382 }
383 }
384
385 if (cycle.isInterval(CI::_100ms)) {
386
387 /* 0x371 = 10Hz rate */
388 {
389 CanTxMessage msg(CanCategory::NBC, 0x371, 4);
390 /* Fuel Flow */
391 msg[0] = 0x00;
392 msg[1] = 0x00;
393 /* Fuel Flow Return */
394 msg[2] = 0x00;
395 msg[3] = 0x00;
396 }
397
398 /* 0x372 = 10Hz rate */
399 {
400 CanTxMessage msg(CanCategory::NBC, 0x372, 8);
401 /* Battery Voltage */
403 /* unused */
404 msg[2] = 0x00;
405 msg[3] = 0x00;
406 /* Target Boost Level todo */
407 msg[4] = 0x00;
408 msg[5] = 0x00;
409 /* Barometric pressure */
411 }
412
413 /* 0x373 = 10Hz rate */
414 {
415 CanTxMessage msg(CanCategory::NBC, 0x373, 8);
416 /* EGT1 */
418 /* EGT2 */
420 /* EGT3 */
422 /* EGT4 */
424 }
425
426 /* 0x374 = 10Hz rate */
427 {
428 CanTxMessage msg(CanCategory::NBC, 0x374, 8);
429 /* EGT5 */
430 msg[0] = 0x00;
431 msg[1] = 0x00;
432 /* EGT6 */
433 msg[2] = 0x00;
434 msg[3] = 0x00;
435 /* EGT7 */
436 msg[4] = 0x00;
437 msg[5] = 0x00;
438 /* EGT8 */
439 msg[6] = 0x00;
440 msg[7] = 0x00;
441 }
442
443 /* 0x375 = 10Hz rate */
444 {
445 CanTxMessage msg(CanCategory::NBC, 0x375, 8);
446 /* EGT9 */
447 msg[0] = 0x00;
448 msg[1] = 0x00;
449 /* EGT10 */
450 msg[2] = 0x00;
451 msg[3] = 0x00;
452 /* EGT11 */
453 msg[4] = 0x00;
454 msg[5] = 0x00;
455 /* EGT12 */
456 msg[6] = 0x00;
457 msg[7] = 0x00;
458 }
459
460 /* 0x376 = 10Hz rate */
461 {
462 CanTxMessage msg(CanCategory::NBC, 0x376, 8);
463 /* Ambient Air Temperature */
464 msg[0] = 0x00;
465 msg[1] = 0x00;
466 /* Relative Humidity */
467 msg[2] = 0x00;
468 msg[3] = 0x00;
469 /* Specific Humidity */
470 msg[4] = 0x00;
471 msg[5] = 0x00;
472 /* Absolute Humidity */
473 msg[6] = 0x00;
474 msg[7] = 0x00;
475 }
476 }
477
478 if (cycle.isInterval(CI::_200ms)) {
479 /* 0x3E0 = 5Hz rate */
480 {
481 CanTxMessage msg(CanCategory::NBC, 0x3E0, 8);
482 /* Coolant temperature in K y = x/10 */
483 msg.setShortValueMsb((Sensor::getOrZero(SensorType::Clt) + C_K_OFFSET) * 10, 0);
484 /* Air Temperature */
485 msg.setShortValueMsb((Sensor::getOrZero(SensorType::Iat) + C_K_OFFSET) * 10, 2);
486 /* Fuel Temperature */
488 /* Oil Temperature */
489 msg[6] = 0x00;
490 msg[7] = 0x00;
491 }
492
493 /* 0x3E1 = 5Hz rate */
494 {
495 CanTxMessage msg(CanCategory::NBC, 0x3E1, 6);
496 /* Gearbox Oil Temperature */
497 msg[0] = 0x00;
498 msg[1] = 0x00;
499 /* Diff oil Temperature */
500 msg[2] = 0x00;
501 msg[3] = 0x00;
502 /* Fuel Composition */
504 }
505
506 /* 0x3E2 = 5Hz rate */
507 {
508 CanTxMessage msg(CanCategory::NBC, 0x3E2, 2);
509 /* Fuel Level in Liters */
511 }
512
513 /* 0x3E3 = 5Hz rate */
514 {
515 CanTxMessage msg(CanCategory::NBC, 0x3E3, 8);
516 /* Fuel Trim Short Term Bank 1*/
517 msg[0] = 0x00;
518 msg[1] = 0x00;
519 /* Fuel Trim Short Term Bank 2*/
520 msg[2] = 0x00;
521 msg[3] = 0x00;
522 /* Fuel Trim Long Term Bank 1*/
523 msg[4] = 0x00;
524 msg[5] = 0x00;
525 /* Fuel Trim Long Term Bank 2*/
526 msg[6] = 0x00;
527 msg[7] = 0x00;
528 }
529
530 /* todo: 0x3E4 = 5Hz rate */
531 {
532 CanTxMessage msg(CanCategory::NBC, 0x3E4, 8);
533 msg[0] = 0x00; //unused
535 msg.setBit(1, 2); // Brake active
536 }
538 msg.setBit(1, 1); // Clutch active
539 }
540#if EFI_LAUNCH_CONTROL
542 msg.setBit(2, 7); // Launch active
543 }
545 msg.setBit(2, 6); // Launch Switch active
546 }
547#endif
549 msg.setBit(3, 5); // AC Request
550 }
552 msg.setBit(3, 4); // AC Output
553 }
555 msg.setBit(3, 1); // Fan2 active
556 }
558 msg.setBit(3, 0); // Fan active
559 }
560 /* Switch status */
561 msg[4] = 0x00;
562 msg[5] = 0x00;
563 msg[6] = 0x00;
564 if ((Sensor::getOrZero(SensorType::Rpm)>0) && (Sensor::get(SensorType::BatteryVoltage).value_or(VBAT_FALLBACK_VALUE)<13)) {
565 msg.setBit(7, 6); // battery light
566 }
567 }
568
569 }
570}
571
572#endif
void canDashboardHaltech(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.
void setShortValueMsb(uint16_t value, size_t offset)
TriggerCentral triggerCentral
Definition engine.h:318
LaunchControlBase launchController
Definition engine.h:220
EngineState engineState
Definition engine.h:344
constexpr auto & module()
Definition engine.h:200
RegisteredOutputPin fanRelay
Definition efi_gpio.h:86
RegisteredOutputPin fanRelay2
Definition efi_gpio.h:87
angle_t timingAdvance[MAX_CYLINDER_COUNT]
bool getLogicValue() const
Definition efi_gpio.cpp:667
virtual SensorResult get() const =0
static float getOrZero(SensorType type)
Definition sensor.h:83
PrimaryTriggerDecoder triggerState
int getHwEventCounter(int index) const
uint32_t totalTriggerErrorCounter
EnginePins enginePins
Definition efi_gpio.cpp:24
static EngineAccessor engine
Definition engine.h:413
static constexpr engine_configuration_s * engineConfiguration
percent_t getInjectorDutyCycle(float rpm)
@ FuelEthanolPercent
@ BarometricPressure
m_knockLevel("Knock: Current level", SensorCategory.SENSOR_INPUTS, FieldType.INT, 996, 1.0, 0.0, 0.0, "Volts")
@ SHAFT_PRIMARY_FALLING