/** * The idea of this method is to execute all heavy calculations in a lower-priority thread, * so that trigger event handler/IO scheduler tasks are faster. */ void Engine::periodicFastCallback(DECLARE_ENGINE_PARAMETER_F) { int rpm = rpmCalculator.rpmValue; if (isValidRpm(rpm)) { MAP_sensor_config_s * c = &engineConfiguration->map; angle_t start = interpolate2d(rpm, c->samplingAngleBins, c->samplingAngle, MAP_ANGLE_SIZE); angle_t offsetAngle = TRIGGER_SHAPE(eventAngles[CONFIG(mapAveragingSchedulingAtIndex)]); for (int i = 0; i < engineConfiguration->specs.cylindersCount; i++) { angle_t cylinderOffset = getEngineCycle(engineConfiguration->operationMode) * i / engineConfiguration->specs.cylindersCount; float cylinderStart = start + cylinderOffset - offsetAngle + tdcPosition(); fixAngle(cylinderStart, "cylinderStart"); engine->engineState.mapAveragingStart[i] = cylinderStart; } engine->engineState.mapAveragingDuration = interpolate2d(rpm, c->samplingWindowBins, c->samplingWindow, MAP_WINDOW_SIZE); } else { for (int i = 0; i < engineConfiguration->specs.cylindersCount; i++) { engine->engineState.mapAveragingStart[i] = NAN; } engine->engineState.mapAveragingDuration = NAN; } engineState.periodicFastCallback(PASS_ENGINE_PARAMETER_F); engine->m.beforeFuelCalc = GET_TIMESTAMP(); ENGINE(fuelMs) = getInjectionDuration(rpm PASS_ENGINE_PARAMETER) * engineConfiguration->globalFuelCorrection; engine->m.fuelCalcTime = GET_TIMESTAMP() - engine->m.beforeFuelCalc; }
void Engine::checkShutdown() { #if EFI_MAIN_RELAY_CONTROL || defined(__DOXYGEN__) int rpm = rpmCalculator.getRpm(); const float vBattThreshold = 5.0f; if (isValidRpm(rpm) && sensors.vBatt < vBattThreshold && stopEngineRequestTimeNt == 0) { stopEngine(); // todo: add stepper motor parking } #endif /* EFI_MAIN_RELAY_CONTROL */ }
/** * Schedules a callback 'angle' degree of crankshaft from now. * The callback would be executed once after the duration of time which * it takes the crankshaft to rotate to the specified angle. */ void scheduleByAngle(int rpm, scheduling_s *timer, angle_t angle, schfunc_t callback, void *param) { if (!isValidRpm(rpm)) { /** * this might happen in case of a single trigger event after a pause - this is normal, so no * warning here */ return; } float delayUs = getOneDegreeTimeUs(rpm) * angle; if (cisnan(delayUs)) { firmwareError("NaN delay?"); return; } scheduleTask("by angle", timer, (int) delayUs, callback, param); }
static void auxValveTriggerCallback(trigger_event_e ckpSignalType, uint32_t index DECLARE_ENGINE_PARAMETER_SUFFIX) { UNUSED(ckpSignalType); #if EFI_PROD_CODE || EFI_SIMULATOR if (index != SCHEDULING_TRIGGER_INDEX) { return; } int rpm = GET_RPM_VALUE; if (!isValidRpm(rpm)) { return; } for (int valveIndex = 0; valveIndex < AUX_DIGITAL_VALVE_COUNT; valveIndex++) { NamedOutputPin *output = &enginePins.auxValve[valveIndex]; for (int phaseIndex = 0; phaseIndex < 2; phaseIndex++) { /* I believe a more correct implementation is the following: * here we properly account for trigger angle position in engine cycle coordinates // todo: at the moment this logic is assuming four-stroke 720-degree engine cycle angle_t extra = phaseIndex * 360 // cycle opens twice per 720 engine cycle + valveIndex * 180 // 2nd valve is operating at 180 offset to first + tdcPosition() // engine cycle position to trigger cycle position conversion - ENGINE(triggerCentral.triggerShape.eventAngles[SCHEDULING_TRIGGER_INDEX]) ; */ angle_t extra = phaseIndex * 360 + valveIndex * 180; angle_t onTime = extra + engine->engineState.auxValveStart; fixAngle(onTime, "onTime", CUSTOM_ERR_6556); scheduleByAngle(rpm, &turnOnEvent[valveIndex][phaseIndex], onTime, (schfunc_t) &turnOn, output, &engine->rpmCalculator); angle_t offTime = extra + engine->engineState.auxValveEnd; fixAngle(offTime, "offTime", CUSTOM_ERR_6557); scheduleByAngle(rpm, &turnOffEvent[valveIndex][phaseIndex], offTime, (schfunc_t) &turnOff, output, &engine->rpmCalculator); } } #endif /* EFI_PROD_CODE || EFI_SIMULATOR */ }
/** * Shaft Position callback used to start or finish HIP integration */ static void intHoldCallback(trigger_event_e ckpEventType, uint32_t index DECLARE_ENGINE_PARAMETER_S) { // this callback is invoked on interrupt thread engine->m.beforeHipCb = GET_TIMESTAMP(); if (index != 0) return; int rpm = engine->rpmCalculator.rpmValue; if (!isValidRpm(rpm)) return; int structIndex = getRevolutionCounter() % 2; // todo: schedule this based on closest trigger event, same as ignition works scheduleByAngle(rpm, &startTimer[structIndex], engineConfiguration->knockDetectionWindowStart, (schfunc_t) &startIntegration, NULL, &engine->rpmCalculator); hipLastExecutionCount = lastExecutionCount; scheduleByAngle(rpm, &endTimer[structIndex], engineConfiguration->knockDetectionWindowEnd, (schfunc_t) &endIntegration, NULL, &engine->rpmCalculator); engine->m.hipCbTime = GET_TIMESTAMP() - engine->m.beforeHipCb; }
/** * Shaft Position callback used to start or finish HIP integration */ static void intHoldCallback(trigger_event_e ckpEventType, uint32_t index DECLARE_ENGINE_PARAMETER_SUFFIX) { (void)ckpEventType; // this callback is invoked on interrupt thread if (index != 0) return; engine->m.beforeHipCb = getTimeNowLowerNt(); int rpm = GET_RPM_VALUE; if (!isValidRpm(rpm)) return; int structIndex = getRevolutionCounter() % 2; // todo: schedule this based on closest trigger event, same as ignition works scheduleByAngle(rpm, &startTimer[structIndex], engineConfiguration->knockDetectionWindowStart, (schfunc_t) &startIntegration, NULL, &engine->rpmCalculator); #if EFI_PROD_CODE hipLastExecutionCount = lastExecutionCount; #endif /* EFI_PROD_CODE */ scheduleByAngle(rpm, &endTimer[structIndex], engineConfiguration->knockDetectionWindowEnd, (schfunc_t) &endIntegration, NULL, &engine->rpmCalculator); engine->m.hipCbTime = getTimeNowLowerNt() - engine->m.beforeHipCb; }