rusefi-1/firmware/controllers/algo/engine.cpp

565 lines
18 KiB
C++
Raw Normal View History

2015-07-10 06:01:56 -07:00
/**
* @file engine.cpp
*
*
* This might be a http://en.wikipedia.org/wiki/God_object but that's best way I can
* express myself in C/C++. I am open for suggestions :)
*
* @date May 21, 2014
2020-01-07 21:02:40 -08:00
* @author Andrey Belomutskiy, (c) 2012-2020
2015-07-10 06:01:56 -07:00
*/
#include "engine.h"
2019-05-27 15:58:43 -07:00
#include "allsensors.h"
2019-03-29 06:11:13 -07:00
#include "efi_gpio.h"
2015-07-10 06:01:56 -07:00
#include "trigger_central.h"
#include "fuel_math.h"
#include "engine_math.h"
#include "advance_map.h"
#include "speed_density.h"
2016-01-01 16:02:59 -08:00
#include "advance_map.h"
2019-07-06 17:15:49 -07:00
#include "os_util.h"
#include "settings.h"
2017-11-26 19:30:37 -08:00
#include "aux_valves.h"
#include "map_averaging.h"
#include "fsio_impl.h"
2019-10-11 17:43:21 -07:00
#include "perf_trace.h"
#include "sensor.h"
#include "gppwm.h"
#include "tachometer.h"
2015-07-10 06:01:56 -07:00
2020-05-09 19:43:39 -07:00
#if EFI_TUNER_STUDIO
2020-05-25 10:02:05 -07:00
#include "tunerstudio_outputs.h"
2020-05-09 19:43:39 -07:00
#endif /* EFI_TUNER_STUDIO */
2019-04-12 19:07:03 -07:00
#if EFI_PROD_CODE
#include "bench_test.h"
2015-07-10 06:01:56 -07:00
#else
#define isRunningBenchTest() true
2016-01-23 15:01:40 -08:00
#endif /* EFI_PROD_CODE */
2015-07-10 06:01:56 -07:00
#if (BOARD_TLE8888_COUNT > 0)
#include "gpio/tle8888.h"
#endif
2019-01-04 21:32:56 -08:00
LoggingWithStorage engineLogger("engine");
2016-01-01 16:02:59 -08:00
EXTERN_ENGINE;
2015-07-10 06:01:56 -07:00
2019-12-21 17:43:11 -08:00
#if EFI_ENGINE_SNIFFER
#include "engine_sniffer.h"
extern int waveChartUsedSize;
extern WaveChart waveChart;
#endif /* EFI_ENGINE_SNIFFER */
FsioState::FsioState() {
#if EFI_ENABLE_ENGINE_WARNING
isEngineWarning = FALSE;
#endif
#if EFI_ENABLE_CRITICAL_ENGINE_STOP
isCriticalEngineCondition = FALSE;
#endif
}
2016-01-23 15:01:40 -08:00
2019-12-21 17:43:11 -08:00
void Engine::resetEngineSnifferIfInTestMode() {
#if EFI_ENGINE_SNIFFER
if (isFunctionalTestMode) {
// TODO: what is the exact reasoning for the exact engine sniffer pause time I wonder
waveChart.pauseEngineSnifferUntilNt = getTimeNowNt() + MS2NT(300);
2019-12-21 17:43:11 -08:00
waveChart.reset();
}
#endif /* EFI_ENGINE_SNIFFER */
}
2020-08-26 10:30:55 -07:00
trigger_type_e getVvtTriggerType(vvt_mode_e vvtMode) {
switch (vvtMode) {
case VVT_2JZ:
return TT_VVT_JZ;
case MIATA_NB2:
return TT_VVT_MIATA_NB2;
2020-08-26 21:43:23 -07:00
case VVT_BOSCH_QUICK_START:
return TT_VVT_BOSCH_QUICK_START;
2020-08-26 10:30:55 -07:00
case VVT_FIRST_HALF:
return TT_ONE;
case VVT_SECOND_HALF:
return TT_ONE;
default:
return TT_ONE;
}
}
void Engine::initializeTriggerWaveform(Logging *logger DECLARE_ENGINE_PARAMETER_SUFFIX) {
2020-08-26 20:35:11 -07:00
static TriggerState initState;
2019-04-12 19:07:03 -07:00
#if EFI_ENGINE_CONTROL && EFI_SHAFT_POSITION_INPUT
2018-12-25 18:18:14 -08:00
// we have a confusing threading model so some synchronization would not hurt
bool alreadyLocked = lockAnyContext();
TRIGGER_WAVEFORM(initializeTriggerWaveform(logger,
engineConfiguration->ambiguousOperationMode,
engineConfiguration->useOnlyRisingEdgeForTrigger, &engineConfiguration->trigger));
2018-12-25 18:18:14 -08:00
if (!TRIGGER_WAVEFORM(shapeDefinitionError)) {
2018-12-25 18:18:14 -08:00
/**
2020-08-25 09:45:25 -07:00
* 'initState' instance of TriggerState is used only to initialize 'this' TriggerWaveform instance
2018-12-25 18:18:14 -08:00
* #192 BUG real hardware trigger events could be coming even while we are initializing trigger
*/
calculateTriggerSynchPoint(&ENGINE(triggerCentral.triggerShape),
&initState PASS_ENGINE_PARAMETER_SUFFIX);
2018-12-25 18:18:14 -08:00
engine->engineCycleEventCount = TRIGGER_WAVEFORM(getLength());
2018-12-25 18:18:14 -08:00
}
2020-08-26 10:30:55 -07:00
if (engineConfiguration->vvtMode != VVT_INACTIVE) {
trigger_config_s config;
2020-08-26 21:06:10 -07:00
ENGINE(triggerCentral).vvtTriggerType = config.type = getVvtTriggerType(engineConfiguration->vvtMode);
2020-08-26 10:30:55 -07:00
ENGINE(triggerCentral).vvtShape.initializeTriggerWaveform(logger,
engineConfiguration->ambiguousOperationMode,
2020-08-26 21:06:10 -07:00
engine->engineConfigurationPtr->vvtCamSensorUseRise, &config);
2020-08-26 10:30:55 -07:00
2020-08-26 20:35:11 -07:00
ENGINE(triggerCentral).vvtShape.initializeSyncPoint(&initState,
2020-08-26 21:06:10 -07:00
&engine->vvtTriggerConfiguration,
2020-08-26 20:35:11 -07:00
&config);
2020-08-26 10:30:55 -07:00
}
2018-12-25 18:18:14 -08:00
if (!alreadyLocked) {
unlockAnyContext();
}
if (!TRIGGER_WAVEFORM(shapeDefinitionError)) {
2018-12-25 18:18:14 -08:00
prepareOutputSignals(PASS_ENGINE_PARAMETER_SIGNATURE);
}
2019-01-31 14:55:23 -08:00
#endif /* EFI_ENGINE_CONTROL && EFI_SHAFT_POSITION_INPUT */
}
static void cylinderCleanupControl(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
2019-04-12 19:07:03 -07:00
#if EFI_ENGINE_CONTROL
bool newValue;
if (engineConfiguration->isCylinderCleanupEnabled) {
newValue = !engine->rpmCalculator.isRunning(PASS_ENGINE_PARAMETER_SIGNATURE) && Sensor::get(SensorType::DriverThrottleIntent).value_or(0) > CLEANUP_MODE_TPS;
} else {
newValue = false;
}
if (newValue != engine->isCylinderCleanupMode) {
engine->isCylinderCleanupMode = newValue;
scheduleMsg(&engineLogger, "isCylinderCleanupMode %s", boolToString(newValue));
}
#endif
}
#if HW_CHECK_MODE
static void assertCloseTo(const char * msg, float actual, float expected) {
if (actual < 0.9 * expected || actual > 1.1 * expected) {
firmwareError(OBD_PCM_Processor_Fault, "%s analog input validation failed %f vs %f", msg, actual, expected);
}
}
#endif // HW_CHECK_MODE
void Engine::periodicSlowCallback(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
2019-10-11 17:43:21 -07:00
ScopePerf perf(PE::EnginePeriodicSlowCallback);
watchdog();
updateSlowSensors(PASS_ENGINE_PARAMETER_SIGNATURE);
checkShutdown();
2019-04-12 19:07:03 -07:00
#if EFI_FSIO
runFsio(PASS_ENGINE_PARAMETER_SIGNATURE);
#else
runHardcodedFsio(PASS_ENGINE_PARAMETER_SIGNATURE);
#endif /* EFI_FSIO */
2018-12-25 18:18:14 -08:00
updateGppwm();
cylinderCleanupControl(PASS_ENGINE_PARAMETER_SIGNATURE);
2020-05-05 05:01:40 -07:00
standardAirCharge = getStandardAirCharge(PASS_ENGINE_PARAMETER_SIGNATURE);
#if (BOARD_TLE8888_COUNT > 0)
static efitick_t tle8888CrankingResetTime = 0;
if (CONFIG(useTLE8888_cranking_hack) && ENGINE(rpmCalculator).isCranking(PASS_ENGINE_PARAMETER_SIGNATURE)) {
efitick_t nowNt = getTimeNowNt();
if (nowNt - tle8888CrankingResetTime > MS2NT(300)) {
requestTLE8888initialization();
// let's reset TLE8888 every 300ms while cranking since that's the best we can do to deal with undervoltage reset
// PS: oh yes, it's a horrible design! Please suggest something better!
tle8888CrankingResetTime = nowNt;
}
}
#endif
slowCallBackWasInvoked = true;
#if HW_CHECK_MODE
efiAssertVoid(OBD_PCM_Processor_Fault, CONFIG(clt).adcChannel != EFI_ADC_NONE, "No CLT setting");
assertCloseTo("clt", Sensor::get(SensorType::Clt).Value, 49.3);
assertCloseTo("iat", Sensor::get(SensorType::Iat).Value, 73.2);
assertCloseTo("aut1", Sensor::get(SensorType::AuxTemp1).Value, 13.8);
assertCloseTo("aut2", Sensor::get(SensorType::AuxTemp2).Value, 6.2);
#endif // HW_CHECK_MODE
2018-12-25 18:18:14 -08:00
}
#if (BOARD_TLE8888_COUNT > 0)
extern float vBattForTle8888;
#endif /* BOARD_TLE8888_COUNT */
2015-07-10 06:01:56 -07:00
/**
* We are executing these heavy (logarithm) methods from outside the trigger callbacks for performance reasons.
2016-01-01 14:02:49 -08:00
* See also periodicFastCallback
2015-07-10 06:01:56 -07:00
*/
2017-05-15 20:28:49 -07:00
void Engine::updateSlowSensors(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
2019-04-12 19:07:03 -07:00
#if EFI_ENGINE_CONTROL
2019-01-21 18:48:58 -08:00
int rpm = GET_RPM();
2016-01-30 19:03:36 -08:00
isEngineChartEnabled = CONFIG(isEngineChartEnabled) && rpm < CONFIG(engineSnifferRpmThreshold);
sensorChartMode = rpm < CONFIG(sensorSnifferRpmThreshold) ? CONFIG(sensorChartMode) : SC_OFF;
2016-01-30 19:03:36 -08:00
2017-05-15 20:28:49 -07:00
engineState.updateSlowSensors(PASS_ENGINE_PARAMETER_SIGNATURE);
2015-07-10 06:01:56 -07:00
2017-11-24 16:16:00 -08:00
// todo: move this logic somewhere to sensors folder?
if (CONFIG(fuelLevelSensor) != EFI_ADC_NONE) {
float fuelLevelVoltage = getVoltageDivided("fuel", engineConfiguration->fuelLevelSensor PASS_ENGINE_PARAMETER_SUFFIX);
sensors.fuelTankLevel = interpolateMsg("fgauge", CONFIG(fuelLevelEmptyTankVoltage), 0,
CONFIG(fuelLevelFullTankVoltage), 100,
2015-07-10 06:01:56 -07:00
fuelLevelVoltage);
}
2017-05-15 20:28:49 -07:00
sensors.vBatt = hasVBatt(PASS_ENGINE_PARAMETER_SIGNATURE) ? getVBatt(PASS_ENGINE_PARAMETER_SIGNATURE) : 12;
2015-07-10 06:01:56 -07:00
#if (BOARD_TLE8888_COUNT > 0)
// nasty value injection into C driver which would not be able to access Engine class
vBattForTle8888 = sensors.vBatt;
#endif /* BOARD_TLE8888_COUNT */
2019-08-26 20:41:04 -07:00
engineState.running.injectorLag = getInjectorLag(sensors.vBatt PASS_ENGINE_PARAMETER_SUFFIX);
2019-01-31 08:57:15 -08:00
#endif
2015-07-10 06:01:56 -07:00
}
2017-11-20 12:01:48 -08:00
void Engine::onTriggerSignalEvent(efitick_t nowNt) {
2015-07-10 06:01:56 -07:00
isSpinning = true;
2017-11-20 12:01:48 -08:00
lastTriggerToothEventTimeNt = nowNt;
2015-07-10 06:01:56 -07:00
}
2020-08-26 20:35:11 -07:00
Engine::Engine() : primaryTriggerConfiguration(this), vvtTriggerConfiguration(this) {
2016-12-18 07:02:38 -08:00
reset();
}
2020-08-26 20:35:11 -07:00
Engine::Engine(persistent_config_s *config) : primaryTriggerConfiguration(this), vvtTriggerConfiguration(this) {
2016-12-18 07:02:38 -08:00
setConfig(config);
reset();
}
2019-01-05 20:33:04 -08:00
/**
* @see scheduleStopEngine()
* @return true if there is a reason to stop engine
*/
bool Engine::needToStopEngine(efitick_t nowNt) const {
2019-01-05 20:33:04 -08:00
return stopEngineRequestTimeNt != 0 &&
nowNt - stopEngineRequestTimeNt < 3 * NT_PER_SECOND;
2019-01-05 20:33:04 -08:00
}
int Engine::getGlobalConfigurationVersion(void) const {
return globalConfigurationVersion;
}
2016-12-18 07:02:38 -08:00
void Engine::reset() {
2016-01-14 21:01:42 -08:00
/**
* it's important for fixAngle() that engineCycle field never has zero
*/
engineCycle = getEngineCycle(FOUR_STROKE_CRANK_SENSOR);
2015-07-10 06:01:56 -07:00
memset(&ignitionPin, 0, sizeof(ignitionPin));
}
2016-01-01 14:02:49 -08:00
2015-07-10 06:01:56 -07:00
/**
* Here we have a bunch of stuff which should invoked after configuration change
* so that we can prepare some helper structures
*/
void Engine::preCalculate(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
2020-05-09 19:43:39 -07:00
// todo: start using this 'adcToVoltageInputDividerCoefficient' micro-optimization or... throw it away?
2019-01-31 08:57:15 -08:00
#if HAL_USE_ADC
adcToVoltageInputDividerCoefficient = adcToVolts(1) * engineConfiguration->analogInputDividerCoefficient;
2018-11-03 06:44:34 -07:00
#else
adcToVoltageInputDividerCoefficient = engineConfigurationPtr->analogInputDividerCoefficient;
2018-11-03 06:44:34 -07:00
#endif
2020-05-09 19:43:39 -07:00
#if EFI_TUNER_STUDIO
// we take 2 bytes of crc32, no idea if it's right to call it crc16 or not
2020-05-09 21:59:32 -07:00
// we have a hack here - we rely on the fact that engineMake is the first of three relevant fields
2020-05-09 19:43:39 -07:00
tsOutputChannels.engineMakeCodeNameCrc16 = crc32(engineConfiguration->engineMake, 3 * VEHICLE_INFO_SIZE);
2020-06-04 21:43:05 -07:00
// we need and can empty warning message for CRC purposes
memset(engine->config->warning_message, 0, sizeof(error_message_t));
tsOutputChannels.tuneCrc16 = crc32(engine->config, sizeof(persistent_config_s));
2020-05-09 19:43:39 -07:00
#endif /* EFI_TUNER_STUDIO */
2015-07-10 06:01:56 -07:00
}
#if EFI_SHAFT_POSITION_INPUT
void Engine::OnTriggerStateDecodingError() {
Engine *engine = this;
EXPAND_Engine;
2020-01-26 03:12:01 -08:00
warning(CUSTOM_SYNC_COUNT_MISMATCH, "trigger not happy current %d/%d/%d expected %d/%d/%d",
triggerCentral.triggerState.currentCycle.eventCount[0],
triggerCentral.triggerState.currentCycle.eventCount[1],
triggerCentral.triggerState.currentCycle.eventCount[2],
TRIGGER_WAVEFORM(expectedEventCount[0]),
TRIGGER_WAVEFORM(expectedEventCount[1]),
TRIGGER_WAVEFORM(expectedEventCount[2]));
2020-01-26 03:28:33 -08:00
triggerCentral.triggerState.setTriggerErrorState();
2020-01-26 03:12:01 -08:00
triggerCentral.triggerState.totalTriggerErrorCounter++;
if (CONFIG(verboseTriggerSynchDetails) || (triggerCentral.triggerState.someSortOfTriggerError && !CONFIG(silentTriggerError))) {
#if EFI_PROD_CODE
scheduleMsg(&engineLogger, "error: synchronizationPoint @ index %d expected %d/%d/%d got %d/%d/%d",
triggerCentral.triggerState.currentCycle.current_index,
TRIGGER_WAVEFORM(expectedEventCount[0]),
TRIGGER_WAVEFORM(expectedEventCount[1]),
TRIGGER_WAVEFORM(expectedEventCount[2]),
triggerCentral.triggerState.currentCycle.eventCount[0],
triggerCentral.triggerState.currentCycle.eventCount[1],
triggerCentral.triggerState.currentCycle.eventCount[2]);
#endif /* EFI_PROD_CODE */
}
}
void Engine::OnTriggerStateProperState(efitick_t nowNt) {
Engine *engine = this;
EXPAND_Engine;
2020-01-24 23:00:33 -08:00
2020-08-24 21:59:07 -07:00
triggerCentral.triggerState.runtimeStatistics(&triggerCentral.triggerFormDetails, nowNt PASS_ENGINE_PARAMETER_SUFFIX);
2020-01-24 23:00:33 -08:00
rpmCalculator.setSpinningUp(nowNt PASS_ENGINE_PARAMETER_SUFFIX);
}
2020-01-26 09:02:54 -08:00
void Engine::OnTriggerSynchronizationLost() {
Engine *engine = this;
EXPAND_Engine;
// Needed for early instant-RPM detection
engine->rpmCalculator.setStopSpinning(PASS_ENGINE_PARAMETER_SIGNATURE);
}
2020-01-26 00:33:45 -08:00
void Engine::OnTriggerInvalidIndex(int currentIndex) {
Engine *engine = this;
EXPAND_Engine;
// let's not show a warning if we are just starting to spin
2020-09-03 16:29:15 -07:00
if (GET_RPM() != 0) {
2020-01-26 00:33:45 -08:00
warning(CUSTOM_SYNC_ERROR, "sync error: index #%d above total size %d", currentIndex, triggerCentral.triggerShape.getSize());
2020-01-26 03:28:33 -08:00
triggerCentral.triggerState.setTriggerErrorState();
2020-01-26 00:33:45 -08:00
}
}
2020-01-22 10:25:35 -08:00
void Engine::OnTriggerSyncronization(bool wasSynchronized) {
2020-01-23 10:39:50 -08:00
// We only care about trigger shape once we have synchronized trigger. Anything could happen
// during first revolution and it's fine
if (wasSynchronized) {
Engine *engine = this;
EXPAND_Engine;
/**
* We can check if things are fine by comparing the number of events in a cycle with the expected number of event.
*/
bool isDecodingError = triggerCentral.triggerState.validateEventCounters(&triggerCentral.triggerShape);
2020-01-23 10:39:50 -08:00
enginePins.triggerDecoderErrorPin.setValue(isDecodingError);
// 'triggerStateListener is not null' means we are running a real engine and now just preparing trigger shape
// that's a bit of a hack, a sweet OOP solution would be a real callback or at least 'needDecodingErrorLogic' method?
if (isDecodingError) {
OnTriggerStateDecodingError();
}
engine->triggerErrorDetection.add(isDecodingError);
if (isTriggerDecoderError(PASS_ENGINE_PARAMETER_SIGNATURE)) {
warning(CUSTOM_OBD_TRG_DECODING, "trigger decoding issue. expected %d/%d/%d got %d/%d/%d",
TRIGGER_WAVEFORM(expectedEventCount[0]), TRIGGER_WAVEFORM(expectedEventCount[1]),
TRIGGER_WAVEFORM(expectedEventCount[2]),
triggerCentral.triggerState.currentCycle.eventCount[0],
triggerCentral.triggerState.currentCycle.eventCount[1],
triggerCentral.triggerState.currentCycle.eventCount[2]);
}
}
2020-01-22 10:25:35 -08:00
}
#endif
2016-12-18 07:02:38 -08:00
void Engine::setConfig(persistent_config_s *config) {
2016-01-25 00:02:33 -08:00
this->config = config;
engineConfigurationPtr = &config->engineConfiguration;
2016-01-25 00:02:33 -08:00
memset(config, 0, sizeof(persistent_config_s));
2015-07-10 06:01:56 -07:00
}
void Engine::printKnockState(void) {
2019-01-04 21:32:56 -08:00
scheduleMsg(&engineLogger, "knock now=%s/ever=%s", boolToString(knockNow), boolToString(knockEver));
2015-07-10 06:01:56 -07:00
}
void Engine::knockLogic(float knockVolts DECLARE_ENGINE_PARAMETER_SUFFIX) {
2015-07-11 13:01:31 -07:00
this->knockVolts = knockVolts;
knockNow = knockVolts > engineConfiguration->knockVThreshold;
2015-07-10 06:01:56 -07:00
/**
* KnockCount is directly proportional to the degrees of ignition
* advance removed
* ex: degrees to subtract = knockCount;
*/
/**
* TODO use knockLevel as a factor for amount of ignition advance
* to remove
* Perhaps allow the user to set a multiplier
* ex: degrees to subtract = knockCount + (knockLevel * X)
* X = user configurable multiplier
*/
if (knockNow) {
knockEver = true;
timeOfLastKnockEvent = getTimeNowUs();
if (knockCount < engineConfiguration->maxKnockSubDeg)
2015-07-10 06:01:56 -07:00
knockCount++;
} else if (knockCount >= 1) {
knockCount--;
} else {
knockCount = 0;
}
}
void Engine::watchdog() {
#if EFI_ENGINE_CONTROL
if (isRunningPwmTest)
return;
if (!isSpinning) {
2016-11-03 20:02:58 -07:00
if (!isRunningBenchTest() && enginePins.stopPins()) {
2016-11-04 19:02:42 -07:00
// todo: make this a firmwareError assuming functional tests would run
warning(CUSTOM_ERR_2ND_WATCHDOG, "Some pins were turned off by 2nd pass watchdog");
2015-07-10 06:01:56 -07:00
}
return;
}
efitick_t nowNt = getTimeNowNt();
2017-11-20 12:01:48 -08:00
// note that we are ignoring the number of tooth here - we
// check for duration between tooth as if we only have one tooth per revolution which is not the case
#define REVOLUTION_TIME_HIGH_THRESHOLD (60 * 1000000LL / RPM_LOW_THRESHOLD)
2015-07-10 06:01:56 -07:00
/**
* todo: better watch dog implementation should be implemented - see
* http://sourceforge.net/p/rusefi/tickets/96/
*
* note that the result of this subtraction could be negative, that would happen if
* we have a trigger event between the time we've invoked 'getTimeNow' and here
*/
2017-11-20 12:01:48 -08:00
efitick_t timeSinceLastTriggerEvent = nowNt - lastTriggerToothEventTimeNt;
if (timeSinceLastTriggerEvent < US2NT(REVOLUTION_TIME_HIGH_THRESHOLD)) {
2015-07-10 06:01:56 -07:00
return;
}
isSpinning = false;
2016-12-18 07:02:38 -08:00
ignitionEvents.isReady = false;
2019-04-12 19:07:03 -07:00
#if EFI_PROD_CODE || EFI_SIMULATOR
2019-01-04 21:32:56 -08:00
scheduleMsg(&engineLogger, "engine has STOPPED");
scheduleMsg(&engineLogger, "templog engine has STOPPED [%x][%x] [%x][%x] %d",
2015-07-10 06:01:56 -07:00
(int)(nowNt >> 32), (int)nowNt,
2017-11-20 12:01:48 -08:00
(int)(lastTriggerToothEventTimeNt >> 32), (int)lastTriggerToothEventTimeNt,
2015-07-10 06:01:56 -07:00
(int)timeSinceLastTriggerEvent
);
triggerInfo();
#endif
2016-11-03 20:02:58 -07:00
enginePins.stopPins();
2015-07-10 06:01:56 -07:00
#endif
}
void Engine::checkShutdown() {
2019-04-12 19:07:03 -07:00
#if EFI_MAIN_RELAY_CONTROL
int rpm = rpmCalculator.getRpm();
2019-01-05 20:33:04 -08:00
/**
* Something is weird here: "below 5.0 volts on battery" what is it about? Is this about
* Frankenso powering everything while driver has already turned ignition off? or what is this condition about?
*/
const float vBattThreshold = 5.0f;
if (isValidRpm(rpm) && sensors.vBatt < vBattThreshold && stopEngineRequestTimeNt == 0) {
2019-01-05 20:33:04 -08:00
scheduleStopEngine();
// todo: add stepper motor parking
}
#endif /* EFI_MAIN_RELAY_CONTROL */
}
bool Engine::isInShutdownMode() const {
2019-04-12 19:07:03 -07:00
#if EFI_MAIN_RELAY_CONTROL
if (stopEngineRequestTimeNt == 0) // the shutdown procedure is not started
return false;
const efitick_t engineStopWaitTimeoutNt = 5LL * 1000000LL;
// The engine is still spinning! Give it some time to stop (but wait no more than 5 secs)
if (isSpinning && (getTimeNowNt() - stopEngineRequestTimeNt) < US2NT(engineStopWaitTimeoutNt))
return true;
// todo: add checks for stepper motor parking
#endif /* EFI_MAIN_RELAY_CONTROL */
return false;
}
2017-05-15 20:28:49 -07:00
injection_mode_e Engine::getCurrentInjectionMode(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
2017-07-06 05:49:55 -07:00
return rpmCalculator.isCranking(PASS_ENGINE_PARAMETER_SIGNATURE) ? CONFIG(crankingInjectionMode) : CONFIG(injectionMode);
2016-11-30 19:06:43 -08:00
}
// see also in TunerStudio project '[doesTriggerImplyOperationMode] tag
static bool doesTriggerImplyOperationMode(trigger_type_e type) {
return type != TT_TOOTHED_WHEEL
&& type != TT_ONE
&& type != TT_ONE_PLUS_ONE
&& type != TT_3_1_CAM
&& type != TT_TOOTHED_WHEEL_60_2
&& type != TT_TOOTHED_WHEEL_36_1;
}
operation_mode_e Engine::getOperationMode(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
/**
* here we ignore user-provided setting for well known triggers.
* For instance for Miata NA, there is no reason to allow user to set FOUR_STROKE_CRANK_SENSOR
*/
return doesTriggerImplyOperationMode(engineConfiguration->trigger.type) ? triggerCentral.triggerShape.getOperationMode() : engineConfiguration->ambiguousOperationMode;
}
2020-06-01 06:09:55 -07:00
int Engine::getRpmHardLimit(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
if (engineConfiguration->useFSIO6ForRevLimiter) {
return fsioState.fsioRpmHardLimit;
}
return CONFIG(rpmHardLimit);
}
2015-07-10 06:01:56 -07:00
/**
* The idea of this method is to execute all heavy calculations in a lower-priority thread,
2016-01-01 14:02:49 -08:00
* so that trigger event handler/IO scheduler tasks are faster.
2015-07-10 06:01:56 -07:00
*/
2017-05-15 20:28:49 -07:00
void Engine::periodicFastCallback(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
2019-10-11 17:43:21 -07:00
ScopePerf pc(PE::EnginePeriodicFastCallback);
2016-01-01 14:02:49 -08:00
#if EFI_MAP_AVERAGING
refreshMapAveragingPreCalc(PASS_ENGINE_PARAMETER_SIGNATURE);
#endif
2016-01-01 14:02:49 -08:00
2017-05-15 20:28:49 -07:00
engineState.periodicFastCallback(PASS_ENGINE_PARAMETER_SIGNATURE);
tachSignalCallback(PASS_ENGINE_PARAMETER_SIGNATURE);
2015-07-10 06:01:56 -07:00
}
void doScheduleStopEngine(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
engine->stopEngineRequestTimeNt = getTimeNowNt();
// let's close injectors or else if these happen to be open right now
enginePins.stopPins();
}
2019-11-23 15:38:16 -08:00
void action_s::execute() {
efiAssertVoid(CUSTOM_ERR_ASSERT, callback != NULL, "callback==null1");
callback(param);
}
schfunc_t action_s::getCallback() const {
return callback;
}
void * action_s::getArgument() const {
return param;
}