2019-01-04 21:32:56 -08:00
|
|
|
/*
|
|
|
|
* engine2.cpp
|
|
|
|
*
|
|
|
|
* @date Jan 5, 2019
|
2020-01-07 21:02:40 -08:00
|
|
|
* @author Andrey Belomutskiy, (c) 2012-2020
|
2019-01-04 21:32:56 -08:00
|
|
|
*/
|
|
|
|
|
|
|
|
// todo: move this code to more proper locations
|
|
|
|
|
2021-07-25 22:05:17 -07:00
|
|
|
#include "pch.h"
|
2021-08-03 19:05:01 -07:00
|
|
|
|
2022-09-07 12:56:45 -07:00
|
|
|
|
2019-01-04 21:32:56 -08:00
|
|
|
#include "speed_density.h"
|
|
|
|
#include "fuel_math.h"
|
|
|
|
#include "advance_map.h"
|
|
|
|
#include "aux_valves.h"
|
2020-05-31 13:59:05 -07:00
|
|
|
#include "closed_loop_fuel.h"
|
2020-12-01 10:03:42 -08:00
|
|
|
#include "launch_control.h"
|
2021-03-03 04:30:56 -08:00
|
|
|
#include "injector_model.h"
|
2022-07-30 09:23:53 -07:00
|
|
|
#include "tunerstudio.h"
|
2020-12-01 10:03:42 -08:00
|
|
|
|
2019-01-11 16:08:15 -08:00
|
|
|
#if ! EFI_UNIT_TEST
|
|
|
|
#include "status_loop.h"
|
|
|
|
#endif
|
2019-01-04 21:32:56 -08:00
|
|
|
|
2019-01-11 06:58:48 -08:00
|
|
|
WarningCodeState::WarningCodeState() {
|
2019-01-12 05:34:38 -08:00
|
|
|
clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void WarningCodeState::clear() {
|
2019-01-11 06:58:48 -08:00
|
|
|
warningCounter = 0;
|
2023-04-11 17:01:34 -07:00
|
|
|
lastErrorCode = ObdCode::None;
|
2019-01-12 18:36:50 -08:00
|
|
|
recentWarnings.clear();
|
2019-01-11 06:58:48 -08:00
|
|
|
}
|
|
|
|
|
2023-04-11 16:32:47 -07:00
|
|
|
void WarningCodeState::addWarningCode(ObdCode code) {
|
2019-01-11 06:58:48 -08:00
|
|
|
warningCounter++;
|
|
|
|
lastErrorCode = code;
|
2022-08-16 22:12:25 -07:00
|
|
|
|
|
|
|
warning_t* existing = recentWarnings.find(code);
|
|
|
|
|
|
|
|
if (!existing) {
|
2021-11-20 00:01:11 -08:00
|
|
|
chibios_rt::CriticalSectionLocker csl;
|
|
|
|
|
2022-08-16 22:12:25 -07:00
|
|
|
// Add the code to the list
|
|
|
|
existing = recentWarnings.add(warning_t(code));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (existing) {
|
|
|
|
// Reset the timer on the code to now
|
|
|
|
existing->LastTriggered.reset();
|
2019-01-12 11:19:21 -08:00
|
|
|
}
|
2022-08-16 22:12:25 -07:00
|
|
|
|
|
|
|
// Reset the "any warning" timer too
|
|
|
|
timeSinceLastWarning.reset();
|
2019-01-11 06:58:48 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param forIndicator if we want to retrieving value for TS indicator, this case a minimal period is applued
|
|
|
|
*/
|
2022-08-16 22:12:25 -07:00
|
|
|
bool WarningCodeState::isWarningNow() const {
|
|
|
|
int period = maxI(3, engineConfiguration->warningPeriod);
|
|
|
|
|
|
|
|
return !timeSinceLastWarning.hasElapsedSec(period);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check whether a particular warning is active
|
2023-04-11 16:32:47 -07:00
|
|
|
bool WarningCodeState::isWarningNow(ObdCode code) const {
|
2022-08-16 22:12:25 -07:00
|
|
|
warning_t* warn = recentWarnings.find(code);
|
|
|
|
|
|
|
|
// No warning found at all
|
|
|
|
if (!warn) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the warning is old, it is not active
|
|
|
|
return !warn->LastTriggered.hasElapsedSec(maxI(3, engineConfiguration->warningPeriod));
|
2019-01-11 06:58:48 -08:00
|
|
|
}
|
2019-01-04 21:32:56 -08:00
|
|
|
|
|
|
|
EngineState::EngineState() {
|
2024-04-25 16:26:37 -07:00
|
|
|
timeSinceLastTChargeK.reset(getTimeNowNt());
|
2019-01-04 21:32:56 -08:00
|
|
|
}
|
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
void EngineState::updateSlowSensors() {
|
2019-01-04 21:32:56 -08:00
|
|
|
}
|
|
|
|
|
2024-03-04 18:21:17 -08:00
|
|
|
void EngineState::updateSparkSkip() {
|
2024-03-04 19:40:28 -08:00
|
|
|
#if EFI_LAUNCH_CONTROL
|
2024-06-06 07:29:48 -07:00
|
|
|
engine->softSparkLimiter.updateTargetSkipRatio(luaSoftSparkSkip, tractionControlSparkSkip);
|
2024-06-07 04:55:15 -07:00
|
|
|
engine->hardSparkLimiter.updateTargetSkipRatio(
|
|
|
|
luaHardSparkSkip,
|
|
|
|
tractionControlSparkSkip,
|
|
|
|
/*
|
|
|
|
* We are applying launch controller spark skip ratio only for hard skip limiter (see
|
|
|
|
* https://github.com/rusefi/rusefi/issues/6566#issuecomment-2153149902).
|
|
|
|
*/
|
2024-10-04 15:19:48 -07:00
|
|
|
engine->launchController.getSparkSkipRatio() + engine->shiftTorqueReductionController.getSparkSkipRatio()
|
2024-06-07 04:55:15 -07:00
|
|
|
);
|
2024-03-04 19:40:28 -08:00
|
|
|
#endif // EFI_LAUNCH_CONTROL
|
2024-03-04 18:21:17 -08:00
|
|
|
}
|
|
|
|
|
2024-03-20 11:43:50 -07:00
|
|
|
#define MAKE_HUMAN_READABLE_ADVANCE(advance) (advance > getEngineState()->engineCycle / 2 ? advance - getEngineState()->engineCycle : advance)
|
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
void EngineState::periodicFastCallback() {
|
2019-10-11 17:43:21 -07:00
|
|
|
ScopePerf perf(PE::EngineStatePeriodicFastCallback);
|
|
|
|
|
2023-10-12 06:09:29 -07:00
|
|
|
#if EFI_SHAFT_POSITION_INPUT
|
2019-01-14 05:57:08 -08:00
|
|
|
if (!engine->slowCallBackWasInvoked) {
|
2023-04-11 17:01:34 -07:00
|
|
|
warning(ObdCode::CUSTOM_SLOW_NOT_INVOKED, "Slow not invoked yet");
|
2019-01-14 05:57:08 -08:00
|
|
|
}
|
2019-01-04 21:32:56 -08:00
|
|
|
efitick_t nowNt = getTimeNowNt();
|
2024-01-07 17:41:52 -08:00
|
|
|
|
2021-11-17 00:54:21 -08:00
|
|
|
if (engine->rpmCalculator.isCranking()) {
|
2022-06-17 18:20:47 -07:00
|
|
|
crankingTimer.reset(nowNt);
|
2019-01-04 21:32:56 -08:00
|
|
|
}
|
2022-06-17 18:20:47 -07:00
|
|
|
|
2023-01-14 09:51:56 -08:00
|
|
|
engine->fuelComputer.running.timeSinceCrankingInSecs = crankingTimer.getElapsedSeconds(nowNt);
|
2022-06-17 18:20:47 -07:00
|
|
|
|
2024-09-04 20:40:12 -07:00
|
|
|
#if EFI_AUX_VALVES
|
2021-11-16 01:15:29 -08:00
|
|
|
recalculateAuxValveTiming();
|
2024-09-04 20:40:12 -07:00
|
|
|
#endif //EFI_AUX_VALVES
|
2019-01-04 21:32:56 -08:00
|
|
|
|
2024-08-02 22:04:21 -07:00
|
|
|
float rpm = Sensor::getOrZero(SensorType::Rpm);
|
2023-01-15 05:26:08 -08:00
|
|
|
engine->ignitionState.sparkDwell = engine->ignitionState.getSparkDwell(rpm);
|
2024-07-23 05:00:34 -07:00
|
|
|
engine->ignitionState.dwellDurationAngle = std::isnan(rpm) ? NAN : engine->ignitionState.sparkDwell / getOneDegreeTimeMs(rpm);
|
2019-01-04 21:32:56 -08:00
|
|
|
|
|
|
|
// todo: move this into slow callback, no reason for IAT corr to be here
|
2023-01-14 09:51:56 -08:00
|
|
|
engine->fuelComputer.running.intakeTemperatureCoefficient = getIatFuelCorrection();
|
2019-01-04 21:32:56 -08:00
|
|
|
// todo: move this into slow callback, no reason for CLT corr to be here
|
2023-01-14 09:51:56 -08:00
|
|
|
engine->fuelComputer.running.coolantTemperatureCoefficient = getCltFuelCorrection();
|
2019-01-04 21:32:56 -08:00
|
|
|
|
2022-01-23 16:44:41 -08:00
|
|
|
engine->module<DfcoController>()->update();
|
2023-04-15 09:03:47 -07:00
|
|
|
// should be called before getInjectionMass() and getLimitingTimingRetard()
|
|
|
|
getLimpManager()->updateRevLimit(rpm);
|
2019-01-04 21:32:56 -08:00
|
|
|
|
|
|
|
// post-cranking fuel enrichment.
|
2023-10-23 12:41:35 -07:00
|
|
|
float m_postCrankingFactor = interpolate3d(
|
2024-07-30 17:47:35 -07:00
|
|
|
config->postCrankingFactor,
|
|
|
|
config->postCrankingCLTBins, Sensor::getOrZero(SensorType::Clt),
|
|
|
|
config->postCrankingDurationBins, engine->rpmCalculator.getRevolutionCounterSinceStart()
|
2023-10-23 12:41:35 -07:00
|
|
|
);
|
2021-05-17 14:24:29 -07:00
|
|
|
// for compatibility reasons, apply only if the factor is greater than unity (only allow adding fuel)
|
2023-10-23 12:41:35 -07:00
|
|
|
// if the engine run time is past the last bin, disable ASE in case the table is filled with values more than 1.0, helps with compatibility
|
2024-07-30 17:47:35 -07:00
|
|
|
if ((m_postCrankingFactor < 1.0f) || (engine->rpmCalculator.getRevolutionCounterSinceStart() > config->postCrankingDurationBins[efi::size(config->postCrankingDurationBins)-1])) {
|
2023-10-23 12:41:35 -07:00
|
|
|
m_postCrankingFactor = 1.0f;
|
2019-01-04 21:32:56 -08:00
|
|
|
}
|
2023-10-23 12:41:35 -07:00
|
|
|
engine->fuelComputer.running.postCrankingFuelCorrection = m_postCrankingFactor;
|
2019-01-04 21:32:56 -08:00
|
|
|
|
2023-01-15 05:26:08 -08:00
|
|
|
engine->ignitionState.cltTimingCorrection = getCltTimingCorrection();
|
2019-01-04 21:32:56 -08:00
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
baroCorrection = getBaroCorrection();
|
2019-01-04 21:32:56 -08:00
|
|
|
|
2020-09-06 16:06:32 -07:00
|
|
|
auto tps = Sensor::get(SensorType::Tps1);
|
2021-11-16 01:15:29 -08:00
|
|
|
updateTChargeK(rpm, tps.value_or(0));
|
2021-03-03 04:30:56 -08:00
|
|
|
|
2023-11-01 14:19:29 -07:00
|
|
|
float untrimmedInjectionMass = getInjectionMass(rpm) * engine->engineState.lua.fuelMult + engine->engineState.lua.fuelAdd;
|
2021-11-16 01:15:29 -08:00
|
|
|
auto clResult = fuelClosedLoopCorrection();
|
2021-05-08 14:41:50 -07:00
|
|
|
|
2024-04-17 00:52:10 -07:00
|
|
|
injectionStage2Fraction = getStage2InjectionFraction(rpm, engine->fuelComputer.afrTableYAxis);
|
2024-01-07 18:20:45 -08:00
|
|
|
float stage2InjectionMass = untrimmedInjectionMass * injectionStage2Fraction;
|
|
|
|
float stage1InjectionMass = untrimmedInjectionMass - stage2InjectionMass;
|
|
|
|
|
2021-03-03 04:30:56 -08:00
|
|
|
// Store the pre-wall wetting injection duration for scheduling purposes only, not the actual injection duration
|
2024-01-07 18:20:45 -08:00
|
|
|
engine->engineState.injectionDuration = engine->module<InjectorModelPrimary>()->getInjectionDuration(stage1InjectionMass);
|
|
|
|
engine->engineState.injectionDurationStage2 =
|
|
|
|
engineConfiguration->enableStagedInjection
|
|
|
|
? engine->module<InjectorModelSecondary>()->getInjectionDuration(stage2InjectionMass)
|
|
|
|
: 0;
|
2020-07-20 23:11:48 -07:00
|
|
|
|
2024-04-17 00:52:10 -07:00
|
|
|
float fuelLoad = getFuelingLoad();
|
2021-11-16 01:15:29 -08:00
|
|
|
injectionOffset = getInjectionOffset(rpm, fuelLoad);
|
2023-06-28 23:49:50 -07:00
|
|
|
engine->lambdaMonitor.update(rpm, fuelLoad);
|
2020-07-20 23:11:48 -07:00
|
|
|
|
2024-06-07 08:20:54 -07:00
|
|
|
#if EFI_LAUNCH_CONTROL
|
|
|
|
engine->launchController.update();
|
2024-10-02 07:00:39 -07:00
|
|
|
engine->shiftTorqueReductionController.update();
|
2024-06-07 08:20:54 -07:00
|
|
|
#endif //EFI_LAUNCH_CONTROL
|
|
|
|
|
2023-11-01 07:21:27 -07:00
|
|
|
float l_ignitionLoad = getIgnitionLoad();
|
2024-07-25 09:43:49 -07:00
|
|
|
float baseAdvance = getWrappedAdvance(rpm, l_ignitionLoad);
|
2024-09-01 13:58:04 -07:00
|
|
|
float corrections = engineConfiguration->timingMode == TM_DYNAMIC ?
|
2023-04-12 14:22:28 -07:00
|
|
|
// Pull any extra timing for knock retard
|
2023-04-12 14:31:00 -07:00
|
|
|
- engine->module<KnockController>()->getKnockRetard()
|
|
|
|
// Degrees of timing REMOVED from actual timing during soft RPM limit window
|
2024-09-01 13:58:04 -07:00
|
|
|
- getLimpManager()->getLimitingTimingRetard() :
|
|
|
|
0;
|
|
|
|
float correctedIgnitionAdvance = baseAdvance + corrections;
|
2023-04-12 14:22:28 -07:00
|
|
|
// these fields are scaled_channel so let's only use for observability, with a local variables holding value while it matters locally
|
2024-03-20 11:43:50 -07:00
|
|
|
engine->ignitionState.baseIgnitionAdvance = MAKE_HUMAN_READABLE_ADVANCE(baseAdvance);
|
|
|
|
engine->ignitionState.correctedIgnitionAdvance = MAKE_HUMAN_READABLE_ADVANCE(correctedIgnitionAdvance);
|
2023-04-12 14:22:28 -07:00
|
|
|
|
2021-12-06 18:19:37 -08:00
|
|
|
|
2021-12-31 23:19:59 -08:00
|
|
|
// compute per-bank fueling
|
|
|
|
for (size_t i = 0; i < STFT_BANK_COUNT; i++) {
|
|
|
|
float corr = clResult.banks[i];
|
2024-06-05 18:43:09 -07:00
|
|
|
// todo: move to engine_state.txt and get rid of fuelPidCorrection in output_channels.txt?
|
|
|
|
engine->engineState.stftCorrection[i] = corr;
|
2021-12-31 23:19:59 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Now apply that to per-cylinder fueling and timing
|
2023-03-27 00:58:18 -07:00
|
|
|
for (size_t i = 0; i < engineConfiguration->cylindersCount; i++) {
|
2021-12-31 23:19:59 -08:00
|
|
|
uint8_t bankIndex = engineConfiguration->cylinderBankSelect[i];
|
2024-06-05 18:43:09 -07:00
|
|
|
auto bankTrim = engine->engineState.stftCorrection[bankIndex];
|
2021-12-31 23:19:59 -08:00
|
|
|
auto cylinderTrim = getCylinderFuelTrim(i, rpm, fuelLoad);
|
2024-10-31 06:26:10 -07:00
|
|
|
auto knockTrim = engine->module<KnockController>()->getFuelTrimMultiplier();
|
2021-12-31 23:19:59 -08:00
|
|
|
|
|
|
|
// Apply both per-bank and per-cylinder trims
|
2024-10-31 06:26:10 -07:00
|
|
|
engine->engineState.injectionMass[i] = untrimmedInjectionMass * bankTrim * cylinderTrim * knockTrim;
|
2024-09-01 13:58:04 -07:00
|
|
|
// todo: is it OK to apply cylinder trim with FIXED timing?
|
2024-02-29 09:29:46 -08:00
|
|
|
timingAdvance[i] = correctedIgnitionAdvance + getCylinderIgnitionTrim(i, rpm, l_ignitionLoad);
|
2021-12-06 18:19:37 -08:00
|
|
|
}
|
2021-07-09 05:37:46 -07:00
|
|
|
|
2023-10-11 23:43:31 -07:00
|
|
|
shouldUpdateInjectionTiming = getInjectorDutyCycle(rpm) < 90;
|
|
|
|
|
2021-07-09 05:37:46 -07:00
|
|
|
// TODO: calculate me from a table!
|
2021-11-17 00:54:21 -08:00
|
|
|
trailingSparkAngle = engineConfiguration->trailingSparkAngle;
|
2021-07-09 05:37:46 -07:00
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
multispark.count = getMultiSparkCount(rpm);
|
2020-12-01 10:03:42 -08:00
|
|
|
|
2022-12-21 17:12:00 -08:00
|
|
|
#if EFI_ANTILAG_SYSTEM
|
|
|
|
engine->antilagController.update();
|
|
|
|
#endif //EFI_ANTILAG_SYSTEM
|
2023-10-12 06:09:29 -07:00
|
|
|
#endif // EFI_SHAFT_POSITION_INPUT
|
2019-01-04 21:32:56 -08:00
|
|
|
}
|
|
|
|
|
2019-04-12 19:07:03 -07:00
|
|
|
#if EFI_ENGINE_CONTROL
|
2024-09-25 00:04:00 -07:00
|
|
|
void EngineState::updateTChargeK(float rpm, float tps) {
|
2022-11-26 09:25:04 -08:00
|
|
|
float newTCharge = engine->fuelComputer.getTCharge(rpm, tps);
|
2024-07-22 16:00:59 -07:00
|
|
|
if (!std::isnan(newTCharge)) {
|
2019-01-04 21:32:56 -08:00
|
|
|
// control the rate of change or just fill with the initial value
|
2024-04-25 16:26:37 -07:00
|
|
|
efitick_t nowNt = getTimeNowNt();
|
|
|
|
float secsPassed = timeSinceLastTChargeK.getElapsedSeconds(nowNt);
|
2021-11-17 00:54:21 -08:00
|
|
|
sd.tCharge = (sd.tChargeK == 0) ? newTCharge : limitRateOfChange(newTCharge, sd.tCharge, engineConfiguration->tChargeAirIncrLimit, engineConfiguration->tChargeAirDecrLimit, secsPassed);
|
2019-06-19 19:34:11 -07:00
|
|
|
sd.tChargeK = convertCelsiusToKelvin(sd.tCharge);
|
2024-04-25 16:26:37 -07:00
|
|
|
timeSinceLastTChargeK.reset(nowNt);
|
2019-01-04 21:32:56 -08:00
|
|
|
}
|
|
|
|
}
|
2023-11-05 10:54:06 -08:00
|
|
|
#endif
|
2019-01-04 21:32:56 -08:00
|
|
|
|
2020-10-05 13:42:50 -07:00
|
|
|
void TriggerConfiguration::update() {
|
|
|
|
VerboseTriggerSynchDetails = isVerboseTriggerSynchDetails();
|
|
|
|
TriggerType = getType();
|
|
|
|
}
|
|
|
|
|
2022-05-30 16:36:47 -07:00
|
|
|
trigger_config_s PrimaryTriggerConfiguration::getType() const {
|
|
|
|
return engineConfiguration->trigger;
|
2020-08-23 22:21:42 -07:00
|
|
|
}
|
|
|
|
|
2020-08-23 23:01:50 -07:00
|
|
|
bool PrimaryTriggerConfiguration::isVerboseTriggerSynchDetails() const {
|
2021-11-17 00:54:21 -08:00
|
|
|
return engineConfiguration->verboseTriggerSynchDetails;
|
2020-08-26 20:35:11 -07:00
|
|
|
}
|
|
|
|
|
2022-05-30 16:36:47 -07:00
|
|
|
trigger_config_s VvtTriggerConfiguration::getType() const {
|
|
|
|
// Convert from VVT type to trigger_config_s
|
|
|
|
return { getVvtTriggerType(engineConfiguration->vvtMode[index]), 0, 0 };
|
2020-08-26 20:35:11 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool VvtTriggerConfiguration::isVerboseTriggerSynchDetails() const {
|
2021-11-17 00:54:21 -08:00
|
|
|
return engineConfiguration->verboseVVTDecoding;
|
2020-08-26 20:35:11 -07:00
|
|
|
}
|
2022-07-30 09:23:53 -07:00
|
|
|
|
|
|
|
bool isLockedFromUser() {
|
|
|
|
int lock = engineConfiguration->tuneHidingKey;
|
|
|
|
bool isLocked = lock > 0;
|
|
|
|
if (isLocked) {
|
2023-10-19 06:46:25 -07:00
|
|
|
criticalError("Tune is password protected. Please use console to unlock tune.");
|
2022-07-30 09:23:53 -07:00
|
|
|
}
|
|
|
|
return isLocked;
|
|
|
|
}
|
|
|
|
|
|
|
|
void unlockEcu(int password) {
|
|
|
|
if (password != engineConfiguration->tuneHidingKey) {
|
|
|
|
efiPrintf("Nope rebooting...");
|
2022-07-30 11:16:11 -07:00
|
|
|
#if EFI_PROD_CODE
|
2022-07-30 09:23:53 -07:00
|
|
|
scheduleReboot();
|
2022-07-30 11:16:11 -07:00
|
|
|
#endif // EFI_PROD_CODE
|
2022-07-30 09:23:53 -07:00
|
|
|
} else {
|
|
|
|
efiPrintf("Unlocked! Burning...");
|
|
|
|
engineConfiguration->tuneHidingKey = 0;
|
|
|
|
requestBurn();
|
|
|
|
}
|
|
|
|
}
|