diff --git a/firmware/console/binary/live_data.cpp b/firmware/console/binary/live_data.cpp index 9555f6ab05..97443232ab 100644 --- a/firmware/console/binary/live_data.cpp +++ b/firmware/console/binary/live_data.cpp @@ -1,12 +1,9 @@ #include "pch.h" +#include "live_data.h" + #include "tunerstudio.h" - -template -const TStruct* getLiveDataAddr(); - -template -const TStruct* getLiveDataAddr(size_t index); +#include "wideband_state_generated.h" template<> const output_channels_s* getLiveDataAddr() { diff --git a/firmware/console/binary/live_data.h b/firmware/console/binary/live_data.h index 8722976671..41d237e1fc 100644 --- a/firmware/console/binary/live_data.h +++ b/firmware/console/binary/live_data.h @@ -1,3 +1,11 @@ #pragma once +#include "FragmentEntry.h" + +template +const TStruct* getLiveDataAddr(); + +template +const TStruct* getLiveDataAddr(size_t index); + FragmentList getLiveDataFragments(); diff --git a/firmware/console/binary/output_channels.txt b/firmware/console/binary/output_channels.txt index 4df75406d3..7f49db8fbf 100644 --- a/firmware/console/binary/output_channels.txt +++ b/firmware/console/binary/output_channels.txt @@ -251,9 +251,6 @@ uint16_t rpmAcceleration;dRPM;"RPM/s",1, 0, 0, 5, 0 uint32_t resetCounter;;"", 1, 0, 0, 10000, 0 end_struct - uint16_t[2 iterate] wbTemperature;;"deg C", 1, 0, 0, 1000, 0 - uint8_t[2 iterate] wbHeaterDuty;;"%", 1, 0, 0, 100, 0 - int16_t autoscale tps1Split;;"%",{1/@@PACK_MULT_PERCENT@@}, 0, 0, 0, 0 int16_t autoscale tps2Split;;"%",{1/@@PACK_MULT_PERCENT@@}, 0, 0, 0, 0 int16_t autoscale tps12Split;;"%",{1/@@PACK_MULT_PERCENT@@}, 0, 0, 0, 0 diff --git a/firmware/controllers/algo/engine_types.h b/firmware/controllers/algo/engine_types.h index c99d8842da..d25059a83a 100644 --- a/firmware/controllers/algo/engine_types.h +++ b/firmware/controllers/algo/engine_types.h @@ -296,7 +296,7 @@ typedef enum __attribute__ ((__packed__)) { DBG_43 = 43, DBG_DYNO_VIEW = 44, DBG_LOGIC_ANALYZER = 45, - DBG_RUSEFI_WIDEBAND = 46, + DBG_46 = 46, DBG_TCU = 47, DBG_LUA = 48, DBG_VVT_2_PID = 49, diff --git a/firmware/controllers/algo/obd_error_codes.h b/firmware/controllers/algo/obd_error_codes.h index 754a53a7f5..62d79680fc 100644 --- a/firmware/controllers/algo/obd_error_codes.h +++ b/firmware/controllers/algo/obd_error_codes.h @@ -1156,7 +1156,7 @@ typedef enum { //P2228 Barometric Press Circ Low //P2229 Barometric Press Circ High //P2230 Barometric Press Circ Interm - //P2231 O2 Sensor Signal Circ Shorted to Heater Circ Bank1 Sensor 1 + OBD_WB_FW_Mismatch = 2133, // actually: P2231 O2 Sensor Signal Circ Shorted to Heater Circ Bank1 Sensor 1 //P2232 O2 Sensor Signal Circ Shorted to Heater Circ Bank1 Sensor 2 //P2233 O2 Sensor Signal Circ Shorted to Heater Circ Bank1 Sensor 3 //P2234 O2 Sensor Signal Circ Shorted to Heater Circ Bank2 Sensor 1 diff --git a/firmware/controllers/sensors/AemXSeriesLambda.cpp b/firmware/controllers/sensors/AemXSeriesLambda.cpp index 635cb98329..a77ea42629 100644 --- a/firmware/controllers/sensors/AemXSeriesLambda.cpp +++ b/firmware/controllers/sensors/AemXSeriesLambda.cpp @@ -58,30 +58,6 @@ void AemXSeriesWideband::decodeAemXSeries(const CANRxFrame& frame, efitick_t now uint16_t lambdaInt = SWAP_UINT16(frame.data16[0]); float lambdaFloat = 0.0001f * lambdaInt; - // This bit is a reserved bit on AEM - but is set on rusEfi's controller - bool isRusefiController = frame.data8[7] & 0x80; - -#if EFI_TUNER_STUDIO - // rusEfi controller sends some extra diagnostic data about its internal workings - if (isRusefiController && engineConfiguration->debugMode == DBG_RUSEFI_WIDEBAND) { - float pumpDuty = frame.data8[2] / 255.0f; - float nernstVoltage = frame.data8[4] / 200.0f; - - engine->outputChannels.debugFloatField1 = pumpDuty; - engine->outputChannels.debugFloatField3 = nernstVoltage; - } - - if (isRusefiController) { - float wbEsr = frame.data8[3] * 4; - - // TODO: convert ESR to temperature - engine->outputChannels.wbTemperature[m_sensorIndex] = wbEsr; - - // TODO: decode heater duty - engine->outputChannels.wbHeaterDuty[m_sensorIndex] = 0; - } -#endif - // bit 6 indicates sensor fault bool sensorFault = frame.data8[7] & 0x40; if (sensorFault) { @@ -105,12 +81,13 @@ void AemXSeriesWideband::decodeRusefiStandard(const CANRxFrame& frame, efitick_t auto data = reinterpret_cast(&frame.data8[0]); if (data->Version != RUSEFI_WIDEBAND_VERSION) { - // TODO: firmwareError here + firmwareError(OBD_WB_FW_Mismatch, "Wideband controller index %d has wrong firmware version, please update!", m_sensorIndex); + return; } - float lambda = 0.0001f * data->Lambda; - engine->outputChannels.wbTemperature[m_sensorIndex] = data->TemperatureC; + tempC = data->TemperatureC; + float lambda = 0.0001f * data->Lambda; bool valid = data->Valid != 0; if (valid) { @@ -123,12 +100,17 @@ void AemXSeriesWideband::decodeRusefiStandard(const CANRxFrame& frame, efitick_t void AemXSeriesWideband::decodeRusefiDiag(const CANRxFrame& frame) { auto data = reinterpret_cast(&frame.data8[0]); - engine->outputChannels.wbHeaterDuty[m_sensorIndex] = data->HeaterDuty / 255.0f; + // convert to percent + heaterDuty = data->HeaterDuty / 2.55f; + pumpDuty = data->PumpDuty / 2.55f; - if (m_sensorIndex == 0 || engineConfiguration->debugMode == DBG_RUSEFI_WIDEBAND) { - engine->outputChannels.debugFloatField1 = data->PumpDuty / 255.0f; - engine->outputChannels.debugFloatField3 = data->NernstDc / 1000.0f; - } + // convert to volts + nernstVoltage = data->NernstDc * 0.001f; + + // no conversion, just ohms + esr = data->Esr; + + faultCode = static_cast(data->Status); } #endif diff --git a/firmware/controllers/sensors/AemXSeriesLambda.h b/firmware/controllers/sensors/AemXSeriesLambda.h index 592e5beb98..a08bfab0de 100644 --- a/firmware/controllers/sensors/AemXSeriesLambda.h +++ b/firmware/controllers/sensors/AemXSeriesLambda.h @@ -2,7 +2,9 @@ #include "can_sensor.h" -class AemXSeriesWideband final : public CanSensorBase { +#include "wideband_state_generated.h" + +class AemXSeriesWideband final : public CanSensorBase, public wideband_state_s { public: AemXSeriesWideband(uint8_t sensorIndex, SensorType type); diff --git a/firmware/controllers/sensors/wideband_state.txt b/firmware/controllers/sensors/wideband_state.txt new file mode 100644 index 0000000000..895c3a5d88 --- /dev/null +++ b/firmware/controllers/sensors/wideband_state.txt @@ -0,0 +1,10 @@ +struct_no_prefix wideband_state_s + uint8_t faultCode + + uint8_t autoscale heaterDuty;;"%", 1, 0, 0, 100, 0 + uint8_t autoscale pumpDuty;;"%", 1, 0, 0, 100, 0 + + uint16_t tempC;;"C", 1, 0, 500, 1000, 0 + uint16_t autoscale nernstVoltage;;"V", 0.001, 0, 0, 1, 3 + uint16_t esr +end_struct diff --git a/firmware/init/sensor/init_lambda.cpp b/firmware/init/sensor/init_lambda.cpp index 0aa3554b88..8034c6674e 100644 --- a/firmware/init/sensor/init_lambda.cpp +++ b/firmware/init/sensor/init_lambda.cpp @@ -3,6 +3,7 @@ #include "init.h" #include "adc_subscription.h" #include "function_pointer_sensor.h" +#include "live_data.h" struct GetAfrWrapper { float getLambda() { @@ -17,12 +18,25 @@ static FunctionPointerSensor lambdaSensor(SensorType::Lambda1, return afrWrapper.getLambda(); }); -#if EFI_CAN_SUPPORT #include "AemXSeriesLambda.h" + +#if EFI_CAN_SUPPORT static AemXSeriesWideband aem1(0, SensorType::Lambda1); static AemXSeriesWideband aem2(1, SensorType::Lambda2); #endif +template <> +const wideband_state_s* getLiveDataAddr(size_t idx) { +#if EFI_CAN_SUPPORT + switch (idx) { + case 0: return &aem1; + case 1: return &aem2; + } +#endif + + return nullptr; +} + void initLambda() { #if EFI_CAN_SUPPORT diff --git a/firmware/integration/LiveData.yaml b/firmware/integration/LiveData.yaml index 401a69fd42..e8789adfdd 100644 --- a/firmware/integration/LiveData.yaml +++ b/firmware/integration/LiveData.yaml @@ -103,3 +103,8 @@ Usages: java: ElectronicThrottle.java folder: controllers/actuators output_name: [ "etb1", "etb2" ] + + - name: wideband_state + java: WidebandController.java + folder: controllers/sensors/ + output_name: [ "wb1", "wb2" ] diff --git a/firmware/integration/rusefi_config.txt b/firmware/integration/rusefi_config.txt index e6238d4d16..3646da1fda 100644 --- a/firmware/integration/rusefi_config.txt +++ b/firmware/integration/rusefi_config.txt @@ -306,7 +306,7 @@ float baseFuel;+Base mass of the per-cylinder fuel injected during cranking. Thi int16_t rpm;+This sets the RPM limit below which the ECU will use cranking fuel and ignition logic, typically this is around 350-450rpm. \nset cranking_rpm X;"RPM", 1, 0, 0, 3000, 0 end_struct -#define debug_mode_e_enum "INVALID", "TPS acceleration enrichment", "GPPWM", "Idle Control", "Engine Load accl enrich", "Trigger Counters", "Soft Spark Cut", "VVT1 PID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "SD card", "sr5", "Knock", "INVALID", "Electronic Throttle", "Executor", "Bench Test / TS commands", "INVALID", "Analog inputs #1", "INSTANT_RPM", "INVALID", "Status", "CJ125", "INVALID", "MAP", "Metrics", "INVALID", "Ion Sense", "TLE8888", "Analog inputs #2", "Dwell Metric", "INVALID", "INVALID", "Boost Control", "INVALID", "INVALID", "ETB Autotune", "Composite Log", "INVALID", "INVALID", "INVALID", "Dyno_View", "Logic_Analyzer", "rusEFI Wideband", "TCU", "Lua", "VVT2 PID", "VVT3 PID", "VVT4 PID", "mode 52", "mode 53" +#define debug_mode_e_enum "INVALID", "TPS acceleration enrichment", "GPPWM", "Idle Control", "Engine Load accl enrich", "Trigger Counters", "Soft Spark Cut", "VVT1 PID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "SD card", "sr5", "Knock", "INVALID", "Electronic Throttle", "Executor", "Bench Test / TS commands", "INVALID", "Analog inputs #1", "INSTANT_RPM", "INVALID", "Status", "CJ125", "INVALID", "MAP", "Metrics", "INVALID", "Ion Sense", "TLE8888", "Analog inputs #2", "Dwell Metric", "INVALID", "INVALID", "Boost Control", "INVALID", "INVALID", "ETB Autotune", "Composite Log", "INVALID", "INVALID", "INVALID", "Dyno_View", "Logic_Analyzer", "INVALID", "TCU", "Lua", "VVT2 PID", "VVT3 PID", "VVT4 PID", "mode 52", "mode 53" custom debug_mode_e 1 bits, U08, @OFFSET@, [0:5], @@debug_mode_e_enum@@ #define VM_VVT_INACTIVE 0 diff --git a/unit_tests/tests/test_can_wideband.cpp b/unit_tests/tests/test_can_wideband.cpp index 4cc6e0a093..18dc0de589 100644 --- a/unit_tests/tests/test_can_wideband.cpp +++ b/unit_tests/tests/test_can_wideband.cpp @@ -108,7 +108,7 @@ TEST(CanWideband, DecodeRusefiStandard) frame.DLC = 8; // version - frame.data8[0] = 0; + frame.data8[0] = RUSEFI_WIDEBAND_VERSION; // valid frame.data8[1] = 1; @@ -119,8 +119,6 @@ TEST(CanWideband, DecodeRusefiStandard) // data = 1234 deg C *reinterpret_cast(&frame.data8[4]) = 1234; - engine->outputChannels.wbTemperature[0] = 0; - // check not set EXPECT_FLOAT_EQ(-1, Sensor::get(SensorType::Lambda1).value_or(-1)); @@ -129,10 +127,28 @@ TEST(CanWideband, DecodeRusefiStandard) EXPECT_FLOAT_EQ(0.7f, Sensor::get(SensorType::Lambda1).value_or(-1)); // Check that temperature updates - EXPECT_EQ(engine->outputChannels.wbTemperature[0], 1234); + EXPECT_EQ(dut.tempC, 1234); // Check that valid bit is respected (should be invalid now) frame.data8[1] = 0; dut.processFrame(frame, getTimeNowNt()); EXPECT_FLOAT_EQ(-1, Sensor::get(SensorType::Lambda1).value_or(-1)); } + +TEST(CanWideband, DecodeRusefiStandardWrongVersion) +{ + EngineTestHelper eth(TEST_ENGINE); + + AemXSeriesWideband dut(0, SensorType::Lambda1); + dut.Register(); + + CANRxFrame frame; + frame.SID = 0x190; + frame.IDE = false; + frame.DLC = 8; + + // version - WRONG VERSION ON PURPOSE! + frame.data8[0] = RUSEFI_WIDEBAND_VERSION + 1; + + EXPECT_FATAL_ERROR(dut.processFrame(frame, getTimeNowNt())); +}