diff --git a/firmware/console/binary/output_channels.txt b/firmware/console/binary/output_channels.txt index cdc89dfd58..64461980a3 100644 --- a/firmware/console/binary/output_channels.txt +++ b/firmware/console/binary/output_channels.txt @@ -368,5 +368,9 @@ bit injectorState12 uint32_t outputRequestPeriod float mapFast float[LUA_GAUGE_COUNT iterate] luaGauges;;"value",1, 0, 0, 50000, 3 - uint8_t[142 iterate] unusedAtTheEnd;;"",1, 0, 0, 0, 0 + + uint16_t autoscale rawMaf2;;"V",{1/@@PACK_MULT_VOLTAGE@@}, 0, 0, 5, 3 + uint16_t autoscale mafMeasured2;@@GAUGE_NAME_AIR_FLOW_MEASURED_2@@;"kg/h",{1/@@PACK_MULT_MASS_FLOW@@}, 0, 0, 0, 1 + + uint8_t[138 iterate] unusedAtTheEnd;;"",1, 0, 0, 0, 0 end_struct diff --git a/firmware/console/status_loop.cpp b/firmware/console/status_loop.cpp index 1b5cb2ddb8..e0aae6fe74 100644 --- a/firmware/console/status_loop.cpp +++ b/firmware/console/status_loop.cpp @@ -508,6 +508,7 @@ static void updateRawSensors() { engine->outputChannels.rawLowFuelPressure = Sensor::getRaw(SensorType::FuelPressureLow); engine->outputChannels.rawHighFuelPressure = Sensor::getRaw(SensorType::FuelPressureHigh); engine->outputChannels.rawMaf = Sensor::getRaw(SensorType::Maf); + engine->outputChannels.rawMaf2 = Sensor::getRaw(SensorType::Maf2); engine->outputChannels.rawMap = Sensor::getRaw(SensorType::MapSlow); engine->outputChannels.rawWastegatePosition = Sensor::getRaw(SensorType::WastegatePosition); engine->outputChannels.rawIdlePositionSensor = Sensor::getRaw(SensorType::IdlePosition); @@ -687,6 +688,7 @@ void updateTunerStudioState() { // Output both the estimated air flow, and measured air flow (if available) tsOutputChannels->mafMeasured = Sensor::getOrZero(SensorType::Maf); + tsOutputChannels->mafMeasured2 = Sensor::getOrZero(SensorType::Maf2); tsOutputChannels->mafEstimate = engine->engineState.airflowEstimate; // offset 116 diff --git a/firmware/controllers/algo/airmass/maf_airmass.cpp b/firmware/controllers/algo/airmass/maf_airmass.cpp index 01e401b9f3..73afe70cec 100644 --- a/firmware/controllers/algo/airmass/maf_airmass.cpp +++ b/firmware/controllers/algo/airmass/maf_airmass.cpp @@ -7,8 +7,33 @@ #include "maf.h" #include "fuel_math.h" +float MafAirmass::getMaf() const { + auto maf = Sensor::get(SensorType::Maf); + + if (Sensor::hasSensor(SensorType::Maf2)) { + auto maf2 = Sensor::get(SensorType::Maf2); + + if (maf && maf2) { + // Both MAFs work, return the sum + return maf.Value + maf2.Value; + } else if (maf) { + // MAF 1 works, but not MAF 2, so double the value from #1 + return 2 * maf.Value; + } else if (maf2) { + // MAF 2 works, but not MAF 1, so double the value from #2 + return 2 * maf2.Value; + } else { + // Both MAFs are broken, give up. + return 0; + } + } else { + return maf.value_or(0); + } +} + AirmassResult MafAirmass::getAirmass(int rpm) { - float maf = Sensor::getOrZero(SensorType::Maf); + float maf = getMaf(); + return getAirmassImpl(maf, rpm); } diff --git a/firmware/controllers/algo/airmass/maf_airmass.h b/firmware/controllers/algo/airmass/maf_airmass.h index f74a12c30c..e56cca51b5 100644 --- a/firmware/controllers/algo/airmass/maf_airmass.h +++ b/firmware/controllers/algo/airmass/maf_airmass.h @@ -10,4 +10,7 @@ public: // Compute airmass based on flow & engine speed AirmassResult getAirmassImpl(float massAirFlow, int rpm) const; + +private: + float getMaf() const; }; diff --git a/firmware/controllers/sensors/sensor_type.h b/firmware/controllers/sensors/sensor_type.h index 3d753627c5..1409e3f2f1 100644 --- a/firmware/controllers/sensors/sensor_type.h +++ b/firmware/controllers/sensors/sensor_type.h @@ -84,6 +84,8 @@ enum class SensorType : unsigned char { EGT1, EGT2, + Maf2, // Second bank MAF sensor + // analog voltage inputs for Lua AuxAnalog1, AuxAnalog2, diff --git a/firmware/init/sensor/init_maf.cpp b/firmware/init/sensor/init_maf.cpp index 61da343f40..50417e4a4f 100644 --- a/firmware/init/sensor/init_maf.cpp +++ b/firmware/init/sensor/init_maf.cpp @@ -5,7 +5,8 @@ #include "functional_sensor.h" #include "table_func.h" -static FunctionalSensor maf(SensorType::Maf, /* timeout = */ MS2NT(50)); +static FunctionalSensor maf (SensorType::Maf , /* timeout = */ MS2NT(50)); +static FunctionalSensor maf2(SensorType::Maf2, /* timeout = */ MS2NT(50)); #if !EFI_UNIT_TEST // extract the type of the elements in the bin/value arrays @@ -15,16 +16,19 @@ using ValueType = std::remove_extent_tmafDecoding)>; // This function converts volts -> kg/h static TableFunc mafCurve(config->mafDecodingBins, config->mafDecoding); -void initMaf() { - adc_channel_e channel = engineConfiguration->mafAdcChannel; - +static void initMaf(adc_channel_e channel, FunctionalSensor& m) { if (!isAdcChannelValid(channel)) { return; } - maf.setFunction(mafCurve); + m.setFunction(mafCurve); - AdcSubscription::SubscribeSensor(maf, channel, /*lowpassCutoff =*/ 50); - maf.Register(); + AdcSubscription::SubscribeSensor(m, channel, /*lowpassCutoff =*/ 50); + m.Register(); +} + +void initMaf() { + initMaf(engineConfiguration->mafAdcChannel, maf); + initMaf(engineConfiguration->maf2AdcChannel, maf2); } #endif // ! EFI_UNIT_TEST diff --git a/firmware/integration/rusefi_config.txt b/firmware/integration/rusefi_config.txt index a4a129f74d..086dea865d 100644 --- a/firmware/integration/rusefi_config.txt +++ b/firmware/integration/rusefi_config.txt @@ -599,7 +599,7 @@ custom spi_device_e 1 bits, U08, @OFFSET@, [0:2], "Off", "SPI1", "SPI2", "SPI3", spi_device_e hip9011SpiDevice; uint8_t failedMapFallback;Single value to be used in event of a failed MAP sensor \nThis value is only used for speed density fueling calculations.;"kPa", 1, 0, 0, 100, 0 uint8_t boostControlSafeDutyCycle;Duty cycle to use in case of a sensor failure. This duty cycle should produce the minimum possible amount of boost. This duty is also used in case any of the minimum RPM/TPS/MAP conditions are not met.;"%", 1, 0, 0, 100, 0 - adc_channel_e mafAdcChannel + adc_channel_e mafAdcChannel float globalFuelCorrection;set global_fuel_correction X;"coef", 1, 0, 0, 1000, 2 @@ -746,7 +746,7 @@ pin_input_mode_e throttlePedalUpPinMode; uint16_t autoscale fordInjectorSmallPulseSlope;;"g/s", 0.001, 0, 0, 65, 3 pin_output_mode_e[TRIGGER_SIMULATOR_PIN_COUNT iterate] triggerSimulatorPinModes; - uint8_t unusedTrigMode + adc_channel_e maf2AdcChannel output_pin_e o2heaterPin;Narrow band o2 heater, not used for CJ125. 'ON' if engine is running, 'OFF' if stopped or cranking. See wboHeaterPin pin_output_mode_e o2heaterPinModeTodO; @@ -1851,6 +1851,7 @@ end_struct #define INDICATOR_NAME_AC_SWITCH "AC switch" #define GAUGE_NAME_AIR_FLOW_MEASURED "MAF sensor" +#define GAUGE_NAME_AIR_FLOW_MEASURED_2 "MAF sensor 2" #define GAUGE_NAME_AIR_FLOW_ESTIMATE "MAF estimate" #define GAUGE_NAME_AIR_MASS "air mass" diff --git a/firmware/tunerstudio/rusefi.input b/firmware/tunerstudio/rusefi.input index df2ad4efa9..a3bfc56052 100644 --- a/firmware/tunerstudio/rusefi.input +++ b/firmware/tunerstudio/rusefi.input @@ -2596,6 +2596,7 @@ cmd_set_engine_type_default = "@@TS_IO_TEST_COMMAND_char@@@@ts_command_e_TS_ field = "TPS1 ADC input", tps1_1AdcChannel field = "TPS2 ADC input", tps2_1AdcChannel field = "MAF ADC input", mafAdcChannel + field = "MAF 2 ADC input", maf2AdcChannel field = "AFR ADC input", afr_hwChannel field = "Baro ADC input", baroSensor_hwChannel field = "MAP ADC input", map_sensor_hwChannel @@ -2932,6 +2933,7 @@ cmd_set_engine_type_default = "@@TS_IO_TEST_COMMAND_char@@@@ts_command_e_TS_ dialog = mafSettings, "MAF sensor", yAxis field = "MAF ADC input", mafAdcChannel + field = "MAF 2 ADC input", maf2AdcChannel ; Sensors->EGO sensor dialog = egoSettings_sensor, "EGO sensor"