wideband live data (#4276)

* wideband live data magic

* test build happy

* test even happier
This commit is contained in:
Matthew Kennedy 2022-06-23 17:04:26 -07:00 committed by GitHub
parent fe6d63f4f2
commit 840bf6fb27
12 changed files with 81 additions and 50 deletions

View File

@ -1,12 +1,9 @@
#include "pch.h" #include "pch.h"
#include "live_data.h"
#include "tunerstudio.h" #include "tunerstudio.h"
#include "wideband_state_generated.h"
template <typename TStruct>
const TStruct* getLiveDataAddr();
template <typename TStruct>
const TStruct* getLiveDataAddr(size_t index);
template<> template<>
const output_channels_s* getLiveDataAddr() { const output_channels_s* getLiveDataAddr() {

View File

@ -1,3 +1,11 @@
#pragma once #pragma once
#include "FragmentEntry.h"
template <typename TStruct>
const TStruct* getLiveDataAddr();
template <typename TStruct>
const TStruct* getLiveDataAddr(size_t index);
FragmentList getLiveDataFragments(); FragmentList getLiveDataFragments();

View File

@ -251,9 +251,6 @@ uint16_t rpmAcceleration;dRPM;"RPM/s",1, 0, 0, 5, 0
uint32_t resetCounter;;"", 1, 0, 0, 10000, 0 uint32_t resetCounter;;"", 1, 0, 0, 10000, 0
end_struct 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 tps1Split;;"%",{1/@@PACK_MULT_PERCENT@@}, 0, 0, 0, 0
int16_t autoscale tps2Split;;"%",{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 int16_t autoscale tps12Split;;"%",{1/@@PACK_MULT_PERCENT@@}, 0, 0, 0, 0

View File

@ -296,7 +296,7 @@ typedef enum __attribute__ ((__packed__)) {
DBG_43 = 43, DBG_43 = 43,
DBG_DYNO_VIEW = 44, DBG_DYNO_VIEW = 44,
DBG_LOGIC_ANALYZER = 45, DBG_LOGIC_ANALYZER = 45,
DBG_RUSEFI_WIDEBAND = 46, DBG_46 = 46,
DBG_TCU = 47, DBG_TCU = 47,
DBG_LUA = 48, DBG_LUA = 48,
DBG_VVT_2_PID = 49, DBG_VVT_2_PID = 49,

View File

@ -1156,7 +1156,7 @@ typedef enum {
//P2228 Barometric Press Circ Low //P2228 Barometric Press Circ Low
//P2229 Barometric Press Circ High //P2229 Barometric Press Circ High
//P2230 Barometric Press Circ Interm //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 //P2232 O2 Sensor Signal Circ Shorted to Heater Circ Bank1 Sensor 2
//P2233 O2 Sensor Signal Circ Shorted to Heater Circ Bank1 Sensor 3 //P2233 O2 Sensor Signal Circ Shorted to Heater Circ Bank1 Sensor 3
//P2234 O2 Sensor Signal Circ Shorted to Heater Circ Bank2 Sensor 1 //P2234 O2 Sensor Signal Circ Shorted to Heater Circ Bank2 Sensor 1

View File

@ -58,30 +58,6 @@ void AemXSeriesWideband::decodeAemXSeries(const CANRxFrame& frame, efitick_t now
uint16_t lambdaInt = SWAP_UINT16(frame.data16[0]); uint16_t lambdaInt = SWAP_UINT16(frame.data16[0]);
float lambdaFloat = 0.0001f * lambdaInt; 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 // bit 6 indicates sensor fault
bool sensorFault = frame.data8[7] & 0x40; bool sensorFault = frame.data8[7] & 0x40;
if (sensorFault) { if (sensorFault) {
@ -105,12 +81,13 @@ void AemXSeriesWideband::decodeRusefiStandard(const CANRxFrame& frame, efitick_t
auto data = reinterpret_cast<const wbo::StandardData*>(&frame.data8[0]); auto data = reinterpret_cast<const wbo::StandardData*>(&frame.data8[0]);
if (data->Version != RUSEFI_WIDEBAND_VERSION) { 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; tempC = data->TemperatureC;
engine->outputChannels.wbTemperature[m_sensorIndex] = data->TemperatureC;
float lambda = 0.0001f * data->Lambda;
bool valid = data->Valid != 0; bool valid = data->Valid != 0;
if (valid) { if (valid) {
@ -123,12 +100,17 @@ void AemXSeriesWideband::decodeRusefiStandard(const CANRxFrame& frame, efitick_t
void AemXSeriesWideband::decodeRusefiDiag(const CANRxFrame& frame) { void AemXSeriesWideband::decodeRusefiDiag(const CANRxFrame& frame) {
auto data = reinterpret_cast<const wbo::DiagData*>(&frame.data8[0]); auto data = reinterpret_cast<const wbo::DiagData*>(&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) { // convert to volts
engine->outputChannels.debugFloatField1 = data->PumpDuty / 255.0f; nernstVoltage = data->NernstDc * 0.001f;
engine->outputChannels.debugFloatField3 = data->NernstDc / 1000.0f;
} // no conversion, just ohms
esr = data->Esr;
faultCode = static_cast<uint8_t>(data->Status);
} }
#endif #endif

View File

@ -2,7 +2,9 @@
#include "can_sensor.h" #include "can_sensor.h"
class AemXSeriesWideband final : public CanSensorBase { #include "wideband_state_generated.h"
class AemXSeriesWideband final : public CanSensorBase, public wideband_state_s {
public: public:
AemXSeriesWideband(uint8_t sensorIndex, SensorType type); AemXSeriesWideband(uint8_t sensorIndex, SensorType type);

View File

@ -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

View File

@ -3,6 +3,7 @@
#include "init.h" #include "init.h"
#include "adc_subscription.h" #include "adc_subscription.h"
#include "function_pointer_sensor.h" #include "function_pointer_sensor.h"
#include "live_data.h"
struct GetAfrWrapper { struct GetAfrWrapper {
float getLambda() { float getLambda() {
@ -17,12 +18,25 @@ static FunctionPointerSensor lambdaSensor(SensorType::Lambda1,
return afrWrapper.getLambda(); return afrWrapper.getLambda();
}); });
#if EFI_CAN_SUPPORT
#include "AemXSeriesLambda.h" #include "AemXSeriesLambda.h"
#if EFI_CAN_SUPPORT
static AemXSeriesWideband aem1(0, SensorType::Lambda1); static AemXSeriesWideband aem1(0, SensorType::Lambda1);
static AemXSeriesWideband aem2(1, SensorType::Lambda2); static AemXSeriesWideband aem2(1, SensorType::Lambda2);
#endif #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() { void initLambda() {
#if EFI_CAN_SUPPORT #if EFI_CAN_SUPPORT

View File

@ -103,3 +103,8 @@ Usages:
java: ElectronicThrottle.java java: ElectronicThrottle.java
folder: controllers/actuators folder: controllers/actuators
output_name: [ "etb1", "etb2" ] output_name: [ "etb1", "etb2" ]
- name: wideband_state
java: WidebandController.java
folder: controllers/sensors/
output_name: [ "wb1", "wb2" ]

View File

@ -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 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 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@@ custom debug_mode_e 1 bits, U08, @OFFSET@, [0:5], @@debug_mode_e_enum@@
#define VM_VVT_INACTIVE 0 #define VM_VVT_INACTIVE 0

View File

@ -108,7 +108,7 @@ TEST(CanWideband, DecodeRusefiStandard)
frame.DLC = 8; frame.DLC = 8;
// version // version
frame.data8[0] = 0; frame.data8[0] = RUSEFI_WIDEBAND_VERSION;
// valid // valid
frame.data8[1] = 1; frame.data8[1] = 1;
@ -119,8 +119,6 @@ TEST(CanWideband, DecodeRusefiStandard)
// data = 1234 deg C // data = 1234 deg C
*reinterpret_cast<uint16_t*>(&frame.data8[4]) = 1234; *reinterpret_cast<uint16_t*>(&frame.data8[4]) = 1234;
engine->outputChannels.wbTemperature[0] = 0;
// check not set // check not set
EXPECT_FLOAT_EQ(-1, Sensor::get(SensorType::Lambda1).value_or(-1)); 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)); EXPECT_FLOAT_EQ(0.7f, Sensor::get(SensorType::Lambda1).value_or(-1));
// Check that temperature updates // 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) // Check that valid bit is respected (should be invalid now)
frame.data8[1] = 0; frame.data8[1] = 0;
dut.processFrame(frame, getTimeNowNt()); dut.processFrame(frame, getTimeNowNt());
EXPECT_FLOAT_EQ(-1, Sensor::get(SensorType::Lambda1).value_or(-1)); 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()));
}