/* * @file launch_control.cpp * * @date 10. sep. 2019 * Author: Ola Ruud */ #include "pch.h" #if EFI_LAUNCH_CONTROL #include "boost_control.h" #include "launch_control.h" #include "periodic_task.h" #include "advance_map.h" #include "engine_state.h" #include "advance_map.h" #include "tinymt32.h" /** * We can have active condition from switch or from clutch. * In case we are dependent on VSS we just return true. */ bool LaunchControlBase::isInsideSwitchCondition() { isSwitchActivated = engineConfiguration->launchActivationMode == SWITCH_INPUT_LAUNCH; isClutchActivated = engineConfiguration->launchActivationMode == CLUTCH_INPUT_LAUNCH; if (isSwitchActivated) { #if !EFI_SIMULATOR if (isBrainPinValid(engineConfiguration->launchActivatePin)) { launchActivatePinState = engineConfiguration->launchActivateInverted ^ efiReadPin(engineConfiguration->launchActivatePin); } #endif // EFI_PROD_CODE return launchActivatePinState; } else if (isClutchActivated) { if (isBrainPinValid(engineConfiguration->clutchDownPin)) { return engine->engineState.clutchDownState; } else { return false; } } else { // ALWAYS_ACTIVE_LAUNCH return true; } } /** * Returns True when Vehicle speed ALLOWS launch control */ bool LaunchControlBase::isInsideSpeedCondition() const { if (engineConfiguration->launchSpeedThreshold == 0) { return true; // allow launch, speed does not matter } int speed = Sensor::getOrZero(SensorType::VehicleSpeed); return engineConfiguration->launchSpeedThreshold > speed; } /** * Returns false if TPS is invalid or TPS > preset threshold */ bool LaunchControlBase::isInsideTpsCondition() const { auto tps = Sensor::get(SensorType::DriverThrottleIntent); // Disallow launch without valid TPS if (!tps.Valid) { return false; } // todo: should this be 'launchTpsThreshold <= tps.Value' so that nicely calibrated TPS of zero does not prevent launch? return engineConfiguration->launchTpsThreshold < tps.Value; } /** * Condition is true as soon as we are above LaunchRpm */ bool LaunchControlBase::isInsideRPMCondition(int rpm) const { int launchRpm = engineConfiguration->launchRpm; return (launchRpm < rpm); } bool LaunchControlBase::isLaunchConditionMet(int rpm) { activateSwitchCondition = isInsideSwitchCondition(); rpmCondition = isInsideRPMCondition(rpm); speedCondition = isInsideSpeedCondition(); tpsCondition = isInsideTpsCondition(); return speedCondition && activateSwitchCondition && rpmCondition && tpsCondition; } LaunchControlBase::LaunchControlBase() { launchActivatePinState = false; isLaunchCondition = false; } bool LaunchControlBase::getFuelCoefficient() const { return 1 + (isLaunchCondition && engineConfiguration->launchControlEnabled ? engineConfiguration->launchFuelAdderPercent / 100.0 : 0); } void LaunchControlBase::update() { if (!engineConfiguration->launchControlEnabled) { return; } int rpm = Sensor::getOrZero(SensorType::Rpm); combinedConditions = isLaunchConditionMet(rpm); //and still recalculate in case user changed the values retardThresholdRpm = engineConfiguration->launchRpm /* we never had UI for 'launchAdvanceRpmRange' so it was always zero. are we supposed to forget about this dead line or it is supposed to be referencing 'launchTimingRpmRange'? + (engineConfiguration->enableLaunchRetard ? engineConfiguration->launchAdvanceRpmRange : 0) */ + engineConfiguration->hardCutRpmRange; if (!combinedConditions) { // conditions not met, reset timer m_launchTimer.reset(); isLaunchCondition = false; } else { // If conditions are met... isLaunchCondition = m_launchTimer.hasElapsedSec(engineConfiguration->launchActivateDelay); } } bool LaunchControlBase::isLaunchRpmRetardCondition() const { return isLaunchCondition && (retardThresholdRpm < Sensor::getOrZero(SensorType::Rpm)); } bool LaunchControlBase::isLaunchSparkRpmRetardCondition() const { return isLaunchRpmRetardCondition() && engineConfiguration->launchSparkCutEnable; } bool LaunchControlBase::isLaunchFuelRpmRetardCondition() const { return isLaunchRpmRetardCondition() && engineConfiguration->launchFuelCutEnable; } SoftSparkLimiter::SoftSparkLimiter(bool p_allowHardCut) { this->allowHardCut = p_allowHardCut; #if EFI_UNIT_TEST initLaunchControl(); #endif // EFI_UNIT_TEST } void SoftSparkLimiter::setTargetSkipRatio(float p_targetSkipRatio) { this->targetSkipRatio = p_targetSkipRatio; } static tinymt32_t tinymt; bool SoftSparkLimiter::shouldSkip() { if (targetSkipRatio == 0 || (!allowHardCut && wasJustSkipped)) { wasJustSkipped = false; return false; } float r = tinymt32_generate_float(&tinymt); wasJustSkipped = r < (allowHardCut ? 1 : 2) * targetSkipRatio; return wasJustSkipped; } void initLaunchControl() { tinymt32_init(&tinymt, 1345135); } #endif /* EFI_LAUNCH_CONTROL */