rusefi-1/firmware/controllers/can/rusefi_wideband.cpp

135 lines
3.7 KiB
C++

#include "pch.h"
#if EFI_WIDEBAND_FIRMWARE_UPDATE && EFI_CAN_SUPPORT
#include "ch.h"
#include "can_msg_tx.h"
#include "rusefi_wideband.h"
// This file contains an array called build_wideband_noboot_bin
// This array contains the firmware image for the wideband contoller
#include "wideband_firmware/for_rusefi/wideband_image.h"
#define EVT_BOOTLOADER_ACK EVENT_MASK(0)
static thread_t* waitingBootloaderThread = nullptr;
void handleWidebandBootloaderAck() {
auto t = waitingBootloaderThread;
if (t) {
chEvtSignal(t, EVT_BOOTLOADER_ACK);
}
}
bool waitAck() {
return chEvtWaitAnyTimeout(EVT_BOOTLOADER_ACK, TIME_MS2I(1000)) != 0;
}
void updateWidebandFirmware() {
// Clear any pending acks for this thread
chEvtGetAndClearEvents(EVT_BOOTLOADER_ACK);
// Send messages to the current thread when acks come in
waitingBootloaderThread = chThdGetSelfX();
efiPrintf("***************************************");
efiPrintf(" WIDEBAND FIRMWARE UPDATE");
efiPrintf("***************************************");
efiPrintf("Wideband Update: Rebooting to bootloader...");
// The first request will reboot the chip (if necessary), and the second one will enable bootloader mode
// If the chip was already in bootloader (aka manual mode), then that's ok - the second request will
// just be safely ignored (but acked)
for (int i = 0; i < 2; i++) {
{
// Send bootloader entry command
CanTxMessage m(CanCategory::WBO_SERVICE, 0xEF0'0000, 0, true);
}
if (!waitAck()) {
efiPrintf("Wideband Update ERROR: Expected ACK from entry to bootloader, didn't get one.");
return;
}
// Let the controller reboot (and show blinky lights for a second before the update begins)
chThdSleepMilliseconds(200);
}
efiPrintf("Wideband Update: in update mode, erasing flash...");
{
// Erase flash - opcode 1, magic value 0x5A5A
CanTxMessage m(CanCategory::WBO_SERVICE, 0xEF1'5A5A, 0, true);
}
if (!waitAck()) {
efiPrintf("Wideband Update ERROR: Expected ACK from flash erase command, didn't get one.");
return;
}
size_t totalSize = sizeof(build_wideband_image_bin);
efiPrintf("Wideband Update: Flash erased! Sending %d bytes...", totalSize);
// Send flash data 8 bytes at a time
for (size_t i = 0; i < totalSize; i += 8) {
{
CanTxMessage m(CanCategory::WBO_SERVICE, 0xEF2'0000 + i, 8, true);
memcpy(&m[0], build_wideband_image_bin + i, 8);
}
if (!waitAck()) {
efiPrintf("Wideband Update ERROR: Expected ACK from data write, didn't get one.");
return;
}
}
efiPrintf("Wideband Update: Update complete! Rebooting controller.");
{
// Reboot to firmware!
CanTxMessage m(CanCategory::WBO_SERVICE, 0xEF3'0000, 0, true);
}
waitAck();
waitingBootloaderThread = nullptr;
}
void setWidebandOffset(uint8_t index) {
// Clear any pending acks for this thread
chEvtGetAndClearEvents(EVT_BOOTLOADER_ACK);
// Send messages to the current thread when acks come in
waitingBootloaderThread = chThdGetSelfX();
efiPrintf("***************************************");
efiPrintf(" WIDEBAND INDEX SET");
efiPrintf("***************************************");
efiPrintf("Setting all connected widebands to index %d...", index);
{
CanTxMessage m(CanCategory::WBO_SERVICE, 0xEF4'0000, 1, true);
m[0] = index;
}
if (!waitAck()) {
firmwareError(OBD_PCM_Processor_Fault, "Wideband index set failed: no controller detected!");
}
waitingBootloaderThread = nullptr;
}
void sendWidebandInfo() {
CanTxMessage m(CanCategory::WBO_SERVICE, 0xEF5'0000, 2, true);
float vbatt = Sensor::getOrZero(SensorType::BatteryVoltage) * 10;
m[0] = vbatt;
// Offset 1 bit 0 = heater enable
m[1] = enginePins.o2heater.getLogicValue() ? 0x01 : 0x00;
}
#endif // EFI_WIDEBAND_FIRMWARE_UPDATE && HAL_USE_CAN