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
|
|
|
|
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"
|
2020-12-01 10:03:42 -08:00
|
|
|
|
2019-01-11 16:08:15 -08:00
|
|
|
#if EFI_PROD_CODE
|
|
|
|
#include "svnversion.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#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;
|
|
|
|
lastErrorCode = 0;
|
2020-01-30 22:21:56 -08:00
|
|
|
timeOfPreviousWarning = DEEP_IN_THE_PAST_SECONDS;
|
2019-01-12 18:36:50 -08:00
|
|
|
recentWarnings.clear();
|
2019-01-11 06:58:48 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void WarningCodeState::addWarningCode(obd_code_e code) {
|
|
|
|
warningCounter++;
|
|
|
|
lastErrorCode = code;
|
2019-01-12 18:36:50 -08:00
|
|
|
if (!recentWarnings.contains(code)) {
|
|
|
|
recentWarnings.add((int)code);
|
2019-01-12 11:19:21 -08:00
|
|
|
}
|
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
|
|
|
|
*/
|
2021-11-16 01:15:29 -08:00
|
|
|
bool WarningCodeState::isWarningNow(efitimesec_t now, bool forIndicator) const {
|
2019-01-11 06:58:48 -08:00
|
|
|
int period = forIndicator ? maxI(3, engineConfiguration->warningPeriod) : engineConfiguration->warningPeriod;
|
|
|
|
return absI(now - timeOfPreviousWarning) < period;
|
|
|
|
}
|
2019-01-04 21:32:56 -08:00
|
|
|
|
|
|
|
MockAdcState::MockAdcState() {
|
|
|
|
memset(hasMockAdc, 0, sizeof(hasMockAdc));
|
|
|
|
}
|
|
|
|
|
2019-09-19 21:25:43 -07:00
|
|
|
#if EFI_ENABLE_MOCK_ADC
|
2021-11-16 01:15:29 -08:00
|
|
|
void MockAdcState::setMockVoltage(int hwChannel, float voltage) {
|
2019-09-22 14:39:13 -07:00
|
|
|
efiAssertVoid(OBD_PCM_Processor_Fault, hwChannel >= 0 && hwChannel < MOCK_ADC_SIZE, "hwChannel out of bounds");
|
2021-04-19 05:11:59 -07:00
|
|
|
efiPrintf("fake voltage: channel %d value %.2f", hwChannel, voltage);
|
2019-01-04 21:32:56 -08:00
|
|
|
|
|
|
|
fakeAdcValues[hwChannel] = voltsToAdc(voltage);
|
|
|
|
hasMockAdc[hwChannel] = true;
|
|
|
|
}
|
|
|
|
#endif /* EFI_ENABLE_MOCK_ADC */
|
|
|
|
|
2021-03-19 14:04:42 -07:00
|
|
|
void FuelConsumptionState::consumeFuel(float grams, efitick_t nowNt) {
|
|
|
|
m_consumedGrams += grams;
|
2019-01-04 21:32:56 -08:00
|
|
|
|
2021-03-19 14:04:42 -07:00
|
|
|
float elapsedSecond = m_timer.getElapsedSecondsAndReset(nowNt);
|
2019-01-04 21:32:56 -08:00
|
|
|
|
2021-03-19 14:04:42 -07:00
|
|
|
// If it's been a long time since last injection, ignore this pulse
|
|
|
|
if (elapsedSecond > 0.2f) {
|
|
|
|
m_rate = 0;
|
|
|
|
} else {
|
|
|
|
m_rate = grams / elapsedSecond;
|
2019-01-04 21:32:56 -08:00
|
|
|
}
|
2021-03-19 14:04:42 -07:00
|
|
|
}
|
2019-01-04 21:32:56 -08:00
|
|
|
|
2021-03-19 14:04:42 -07:00
|
|
|
float FuelConsumptionState::getConsumedGrams() const {
|
|
|
|
return m_consumedGrams;
|
2019-01-04 21:32:56 -08:00
|
|
|
}
|
|
|
|
|
2021-03-19 14:04:42 -07:00
|
|
|
float FuelConsumptionState::getConsumptionGramPerSecond() const {
|
|
|
|
return m_rate;
|
2019-01-04 21:32:56 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
EngineState::EngineState() {
|
|
|
|
timeSinceLastTChargeK = getTimeNowNt();
|
|
|
|
}
|
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
void EngineState::updateSlowSensors() {
|
2019-01-04 21:32:56 -08:00
|
|
|
}
|
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
void EngineState::periodicFastCallback() {
|
2019-10-11 17:43:21 -07:00
|
|
|
ScopePerf perf(PE::EngineStatePeriodicFastCallback);
|
|
|
|
|
2019-04-12 19:07:03 -07:00
|
|
|
#if EFI_ENGINE_CONTROL
|
2019-01-14 05:57:08 -08:00
|
|
|
if (!engine->slowCallBackWasInvoked) {
|
2019-12-02 17:16:41 -08:00
|
|
|
warning(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();
|
2021-11-17 00:54:21 -08:00
|
|
|
if (engine->rpmCalculator.isCranking()) {
|
2019-01-04 21:32:56 -08:00
|
|
|
crankingTime = nowNt;
|
|
|
|
timeSinceCranking = 0.0f;
|
|
|
|
} else {
|
|
|
|
timeSinceCranking = nowNt - crankingTime;
|
|
|
|
}
|
2021-11-16 01:15:29 -08:00
|
|
|
recalculateAuxValveTiming();
|
2019-01-04 21:32:56 -08:00
|
|
|
|
2021-11-17 00:54:21 -08:00
|
|
|
int rpm = engine->rpmCalculator.getRpm();
|
2021-11-16 01:15:29 -08:00
|
|
|
sparkDwell = getSparkDwell(rpm);
|
2019-01-04 21:32:56 -08:00
|
|
|
dwellAngle = cisnan(rpm) ? NAN : sparkDwell / getOneDegreeTimeMs(rpm);
|
|
|
|
|
|
|
|
// todo: move this into slow callback, no reason for IAT corr to be here
|
2021-11-16 01:15:29 -08:00
|
|
|
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
|
2021-11-16 01:15:29 -08:00
|
|
|
running.coolantTemperatureCoefficient = getCltFuelCorrection();
|
2019-01-04 21:32:56 -08:00
|
|
|
|
|
|
|
// Fuel cut-off isn't just 0 or 1, it can be tapered
|
2021-11-16 01:15:29 -08:00
|
|
|
fuelCutoffCorrection = getFuelCutOffCorrection(nowNt, rpm);
|
2019-01-04 21:32:56 -08:00
|
|
|
|
|
|
|
// post-cranking fuel enrichment.
|
2021-05-17 14:24:29 -07:00
|
|
|
// for compatibility reasons, apply only if the factor is greater than unity (only allow adding fuel)
|
|
|
|
if (engineConfiguration->postCrankingFactor > 1.0f) {
|
2019-01-04 21:32:56 -08:00
|
|
|
// convert to microsecs and then to seconds
|
2021-08-09 13:33:06 -07:00
|
|
|
running.timeSinceCrankingInSecs = NT2US(timeSinceCranking) / US_PER_SECOND_F;
|
2019-01-04 21:32:56 -08:00
|
|
|
// use interpolation for correction taper
|
2019-08-26 20:41:04 -07:00
|
|
|
running.postCrankingFuelCorrection = interpolateClamped(0.0f, engineConfiguration->postCrankingFactor,
|
|
|
|
engineConfiguration->postCrankingDurationSec, 1.0f, running.timeSinceCrankingInSecs);
|
2019-01-04 21:32:56 -08:00
|
|
|
} else {
|
2019-08-26 20:41:04 -07:00
|
|
|
running.postCrankingFuelCorrection = 1.0f;
|
2019-01-04 21:32:56 -08:00
|
|
|
}
|
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
cltTimingCorrection = getCltTimingCorrection();
|
2019-01-04 21:32:56 -08:00
|
|
|
|
2021-09-20 11:27:26 -07:00
|
|
|
knockThreshold = interpolate2d(rpm, engineConfiguration->knockNoiseRpmBins,
|
2019-07-09 11:16:36 -07:00
|
|
|
engineConfiguration->knockNoise);
|
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
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
float injectionMass = getInjectionMass(rpm);
|
|
|
|
auto clResult = fuelClosedLoopCorrection();
|
2021-05-08 14:41:50 -07:00
|
|
|
|
|
|
|
// compute per-bank fueling
|
|
|
|
for (size_t i = 0; i < STFT_BANK_COUNT; i++) {
|
|
|
|
float corr = clResult.banks[i];
|
2021-11-17 00:54:21 -08:00
|
|
|
engine->injectionMass[i] = injectionMass * corr;
|
|
|
|
engine->stftCorrection[i] = corr;
|
2021-05-08 14:41:50 -07:00
|
|
|
}
|
|
|
|
|
2021-03-03 04:30:56 -08:00
|
|
|
// Store the pre-wall wetting injection duration for scheduling purposes only, not the actual injection duration
|
2021-11-17 09:13:19 -08:00
|
|
|
engine->injectionDuration = engine->engineModules.get<InjectorModel>().getInjectionDuration(injectionMass);
|
2020-07-20 23:11:48 -07:00
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
float fuelLoad = getFuelingLoad();
|
|
|
|
injectionOffset = getInjectionOffset(rpm, fuelLoad);
|
2020-07-20 23:11:48 -07:00
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
float ignitionLoad = getIgnitionLoad();
|
|
|
|
timingAdvance = getAdvance(rpm, ignitionLoad) * luaAdjustments.ignitionTimingMult + luaAdjustments.ignitionTimingAdd;
|
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
|
|
|
|
|
|
|
#if EFI_LAUNCH_CONTROL
|
2021-11-15 15:57:12 -08:00
|
|
|
engine->launchController.update();
|
2020-12-01 10:03:42 -08:00
|
|
|
#endif //EFI_LAUNCH_CONTROL
|
|
|
|
|
2021-06-16 14:20:28 -07:00
|
|
|
engine->limpManager.updateState(rpm, nowNt);
|
2020-12-26 14:30:46 -08:00
|
|
|
|
2020-06-17 14:15:04 -07:00
|
|
|
#endif // EFI_ENGINE_CONTROL
|
2019-01-04 21:32:56 -08:00
|
|
|
}
|
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
void EngineState::updateTChargeK(int rpm, float tps) {
|
2019-04-12 19:07:03 -07:00
|
|
|
#if EFI_ENGINE_CONTROL
|
2021-11-16 01:15:29 -08:00
|
|
|
float newTCharge = getTCharge(rpm, tps);
|
2019-01-04 21:32:56 -08:00
|
|
|
// convert to microsecs and then to seconds
|
|
|
|
efitick_t curTime = getTimeNowNt();
|
2021-08-09 13:33:06 -07:00
|
|
|
float secsPassed = (float)NT2US(curTime - timeSinceLastTChargeK) / US_PER_SECOND_F;
|
2019-01-04 21:32:56 -08:00
|
|
|
if (!cisnan(newTCharge)) {
|
|
|
|
// control the rate of change or just fill with the initial value
|
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);
|
2019-01-04 21:32:56 -08:00
|
|
|
timeSinceLastTChargeK = curTime;
|
|
|
|
}
|
2019-01-31 08:57:15 -08:00
|
|
|
#endif
|
2019-01-04 21:32:56 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
SensorsState::SensorsState() {
|
|
|
|
}
|
|
|
|
|
2019-01-15 17:24:36 -08:00
|
|
|
int MockAdcState::getMockAdcValue(int hwChannel) const {
|
2019-09-22 14:43:00 -07:00
|
|
|
efiAssert(OBD_PCM_Processor_Fault, hwChannel >= 0 && hwChannel < MOCK_ADC_SIZE, "hwChannel out of bounds", -1);
|
2019-01-04 21:32:56 -08:00
|
|
|
return fakeAdcValues[hwChannel];
|
|
|
|
}
|
|
|
|
|
|
|
|
StartupFuelPumping::StartupFuelPumping() {
|
|
|
|
isTpsAbove50 = false;
|
|
|
|
pumpsCounter = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void StartupFuelPumping::setPumpsCounter(int newValue) {
|
|
|
|
if (pumpsCounter != newValue) {
|
|
|
|
pumpsCounter = newValue;
|
|
|
|
|
|
|
|
if (pumpsCounter == PUMPS_TO_PRIME) {
|
2021-04-19 05:11:59 -07:00
|
|
|
efiPrintf("let's squirt prime pulse %.2f", pumpsCounter);
|
2019-01-04 21:32:56 -08:00
|
|
|
pumpsCounter = 0;
|
|
|
|
} else {
|
2021-04-19 05:11:59 -07:00
|
|
|
efiPrintf("setPumpsCounter %d", pumpsCounter);
|
2019-01-04 21:32:56 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
void StartupFuelPumping::update() {
|
2019-01-21 18:48:58 -08:00
|
|
|
if (GET_RPM() == 0) {
|
2021-10-05 16:59:07 -07:00
|
|
|
bool isTpsAbove50 = Sensor::getOrZero(SensorType::DriverThrottleIntent) >= 50;
|
2019-01-04 21:32:56 -08:00
|
|
|
|
|
|
|
if (this->isTpsAbove50 != isTpsAbove50) {
|
|
|
|
setPumpsCounter(pumpsCounter + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
/**
|
|
|
|
* Engine is not stopped - not priming pumping mode
|
|
|
|
*/
|
|
|
|
setPumpsCounter(0);
|
|
|
|
isTpsAbove50 = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-11 16:08:15 -08:00
|
|
|
#if EFI_SIMULATOR
|
|
|
|
#define VCS_VERSION "123"
|
|
|
|
#endif
|
|
|
|
|
2019-07-13 11:08:08 -07:00
|
|
|
void printCurrentState(Logging *logging, int seconds, const char *engineTypeName, const char *firmwareBuildId) {
|
2020-12-05 18:56:39 -08:00
|
|
|
// VersionChecker in rusEFI console is parsing these version string, please follow the expected format
|
|
|
|
logging->appendPrintf("%s%s%d@%s %s %s %d%s", PROTOCOL_VERSION_TAG, DELIMETER,
|
2019-01-11 16:08:15 -08:00
|
|
|
getRusEfiVersion(), VCS_VERSION,
|
2019-07-13 11:08:08 -07:00
|
|
|
firmwareBuildId,
|
|
|
|
engineTypeName,
|
2019-01-11 16:08:15 -08:00
|
|
|
seconds,
|
|
|
|
DELIMETER);
|
|
|
|
}
|
2019-01-04 21:32:56 -08:00
|
|
|
|
2020-10-05 13:42:50 -07:00
|
|
|
void TriggerConfiguration::update() {
|
|
|
|
UseOnlyRisingEdgeForTrigger = isUseOnlyRisingEdgeForTrigger();
|
|
|
|
VerboseTriggerSynchDetails = isVerboseTriggerSynchDetails();
|
|
|
|
TriggerType = getType();
|
|
|
|
}
|
|
|
|
|
2020-08-23 23:01:50 -07:00
|
|
|
bool PrimaryTriggerConfiguration::isUseOnlyRisingEdgeForTrigger() const {
|
2021-11-17 00:54:21 -08:00
|
|
|
return engineConfiguration->useOnlyRisingEdgeForTrigger;
|
2020-08-23 22:21:42 -07:00
|
|
|
}
|
|
|
|
|
2020-08-23 23:01:50 -07:00
|
|
|
trigger_type_e PrimaryTriggerConfiguration::getType() const {
|
2021-11-17 00:54:21 -08:00
|
|
|
return engineConfiguration->trigger.type;
|
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
|
|
|
}
|
|
|
|
|
|
|
|
bool VvtTriggerConfiguration::isUseOnlyRisingEdgeForTrigger() const {
|
2021-11-17 00:54:21 -08:00
|
|
|
return engineConfiguration->vvtCamSensorUseRise;
|
2020-08-26 20:35:11 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
trigger_type_e VvtTriggerConfiguration::getType() const {
|
2021-02-08 19:30:02 -08:00
|
|
|
return engine->triggerCentral.vvtTriggerType[index];
|
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
|
|
|
}
|