rusEFI
The most advanced open source ECU
rusefi_wideband.cpp
Go to the documentation of this file.
1 #include "pch.h"
2 
3 // do we use some sort of a custom bootloader protocol in rusEFI WBO?
4 // todo: should we move to any widely used protocol like OpenBLT or else?
5 
6 #if EFI_WIDEBAND_FIRMWARE_UPDATE && EFI_CAN_SUPPORT
7 
8 #include "ch.h"
9 #include "can_msg_tx.h"
10 #include "rusefi_wideband.h"
11 #pragma GCC diagnostic push
12 #pragma GCC diagnostic ignored "-Wunused-function"
13 #include "wideband_firmware/for_rusefi/wideband_can.h"
14 #pragma GCC diagnostic pop
15 
16 // This file contains an array called build_wideband_noboot_bin
17 // This array contains the firmware image for the wideband contoller
18 #include "wideband_firmware/for_rusefi/wideband_image.h"
19 
20 #define EVT_BOOTLOADER_ACK EVENT_MASK(0)
21 
22 static thread_t* waitingBootloaderThread = nullptr;
23 
25  auto t = waitingBootloaderThread;
26  if (t) {
27  chEvtSignal(t, EVT_BOOTLOADER_ACK);
28  }
29 }
30 
31 bool waitAck() {
32  return chEvtWaitAnyTimeout(EVT_BOOTLOADER_ACK, TIME_MS2I(1000)) != 0;
33 }
34 
35 static size_t getWidebandBus() {
37 }
38 
40  size_t bus = getWidebandBus();
41 
42  // Clear any pending acks for this thread
43  chEvtGetAndClearEvents(EVT_BOOTLOADER_ACK);
44 
45  // Send messages to the current thread when acks come in
46  waitingBootloaderThread = chThdGetSelfX();
47 
48  efiPrintf("***************************************");
49  efiPrintf(" WIDEBAND FIRMWARE UPDATE");
50  efiPrintf("***************************************");
51  efiPrintf("Wideband Update: Rebooting to bootloader...");
52 
53  // The first request will reboot the chip (if necessary), and the second one will enable bootloader mode
54  // If the chip was already in bootloader (aka manual mode), then that's ok - the second request will
55  // just be safely ignored (but acked)
56  for (int i = 0; i < 2; i++) {
57  {
58  // Send bootloader entry command
59  CanTxMessage m(CanCategory::WBO_SERVICE, WB_BL_ENTER, 0, bus, true);
60  }
61 
62  if (!waitAck()) {
63  efiPrintf("Wideband Update ERROR: Expected ACK from entry to bootloader, didn't get one.");
64  return;
65  }
66 
67  // Let the controller reboot (and show blinky lights for a second before the update begins)
68  chThdSleepMilliseconds(200);
69  }
70 
71  efiPrintf("Wideband Update: in update mode, erasing flash...");
72 
73  {
74  // Erase flash - opcode 1, magic value 0x5A5A
75  CanTxMessage m(CanCategory::WBO_SERVICE, 0xEF1'5A5A, 0, bus, true);
76  }
77 
78  if (!waitAck()) {
79  efiPrintf("Wideband Update ERROR: Expected ACK from flash erase command, didn't get one.");
80  return;
81  }
82 
83  size_t totalSize = sizeof(build_wideband_image_bin);
84 
85  efiPrintf("Wideband Update: Flash erased! Sending %d bytes...", totalSize);
86 
87  // Send flash data 8 bytes at a time
88  for (size_t i = 0; i < totalSize; i += 8) {
89  {
90  CanTxMessage m(CanCategory::WBO_SERVICE, 0xEF2'0000 + i, 8, bus, true);
91  memcpy(&m[0], build_wideband_image_bin + i, 8);
92  }
93 
94  if (!waitAck()) {
95  efiPrintf("Wideband Update ERROR: Expected ACK from data write, didn't get one.");
96  return;
97  }
98  }
99 
100  efiPrintf("Wideband Update: Update complete! Rebooting controller.");
101 
102  {
103  // Reboot to firmware!
104  CanTxMessage m(CanCategory::WBO_SERVICE, 0xEF3'0000, 0, bus, true);
105  }
106 
107  waitAck();
108 
109  waitingBootloaderThread = nullptr;
110 }
111 
112 void setWidebandOffset(uint8_t index) {
113  // Clear any pending acks for this thread
114  chEvtGetAndClearEvents(EVT_BOOTLOADER_ACK);
115 
116  // Send messages to the current thread when acks come in
117  waitingBootloaderThread = chThdGetSelfX();
118 
119  efiPrintf("***************************************");
120  efiPrintf(" WIDEBAND INDEX SET");
121  efiPrintf("***************************************");
122  efiPrintf("Setting all connected widebands to index %d...", index);
123 
124  {
125  CanTxMessage m(CanCategory::WBO_SERVICE, WB_MSG_SET_INDEX, 1, getWidebandBus(), true);
126  m[0] = index;
127  }
128 
129  if (!waitAck()) {
130  criticalError("Wideband index set failed: no controller detected!");
131  }
132 
133  waitingBootloaderThread = nullptr;
134 }
135 
136 // huh? this code here should not be hidden under 'EFI_WIDEBAND_FIRMWARE_UPDATE' condition?!
138  CanTxMessage m(CanCategory::WBO_SERVICE, WB_MGS_ECU_STATUS, 2, getWidebandBus(), true);
139 
140  float vbatt = Sensor::getOrZero(SensorType::BatteryVoltage) * 10;
141 
142  m[0] = vbatt;
143 
144  // Offset 1 bit 0 = heater enable
145  m[1] = engine->engineState.heaterControlEnabled ? 0x01 : 0x00;
146 }
147 
148 #endif // EFI_WIDEBAND_FIRMWARE_UPDATE && HAL_USE_CAN
EngineState engineState
Definition: engine.h:310
static float getOrZero(SensorType type)
Definition: sensor.h:92
Engine * engine
engine_configuration_s * engineConfiguration
void setWidebandOffset(uint8_t index)
static thread_t * waitingBootloaderThread
void handleWidebandBootloaderAck()
static size_t getWidebandBus()
void updateWidebandFirmware()
bool waitAck()
void sendWidebandInfo()