static void usTimerWatchDog(void) { if (getTimeNowNt() >= lastSetTimerTimeNt + 2 * CORE_CLOCK) { strcpy(buff, "no_event"); itoa10(&buff[8], lastSetTimerValue); firmwareError(OBD_PCM_Processor_Fault, buff); return; } msg = isTimerPending ? "No_cb too long" : "Timer not awhile"; // 2 seconds of inactivity would not look right efiAssertVoid(getTimeNowNt() < lastSetTimerTimeNt + 2 * CORE_CLOCK, msg); }
static void digitalMapWidthCallback(void) { efitick_t nowNt = getTimeNowNt(); mapFreq = 1000000.0 / NT2US(nowNt - prevWidthTimeNt); prevWidthTimeNt = nowNt; }
/** * @return vehicle speed, in kilometers per hour */ float getVehicleSpeed(void) { efitick_t nowNt = getTimeNowNt(); if (nowNt - lastSignalTimeNt > US2NT(US_PER_SECOND_LL)) return 0; // previous signal time is too long ago - we are stopped return engineConfiguration->vehicleSpeedCoef * US2NT(US_PER_SECOND_LL) / vssDiff; }
/** * sets the alarm to the specified number of microseconds from now. * This function should be invoked under kernel lock which would disable interrupts. */ void setHardwareUsTimer(int32_t timeUs) { setHwTimerCounter++; /** * #259 BUG error: not positive timeUs * Once in a while we night get an interrupt where we do not expect it */ if (timeUs <= 0) { timerFreezeCounter++; warning(CUSTOM_OBD_LOCAL_FREEZE, "local freeze cnt=%d", timerFreezeCounter); } if (timeUs < 2) timeUs = 2; // for some reason '1' does not really work efiAssertVoid(CUSTOM_ERR_6681, timeUs > 0, "not positive timeUs"); if (timeUs >= 10 * US_PER_SECOND) { firmwareError(CUSTOM_ERR_TIMER_OVERFLOW, "setHardwareUsTimer() too long: %d", timeUs); return; } if (GPTDEVICE.state == GPT_ONESHOT) { gptStopTimerI(&GPTDEVICE); } if (GPTDEVICE.state != GPT_READY) { firmwareError(CUSTOM_HW_TIMER, "HW timer state %d/%d", GPTDEVICE.state, setHwTimerCounter); return; } if (hasFirmwareError()) return; gptStartOneShotI(&GPTDEVICE, timeUs); lastSetTimerTimeNt = getTimeNowNt(); lastSetTimerValue = timeUs; isTimerPending = TRUE; timerRestartCounter++; }
/** * sets the alarm to the specified number of microseconds from now. * This function should be invoked under kernel lock which would disable interrupts. */ void setHardwareUsTimer(int32_t timeUs) { /** * #259 BUG error: not positive timeUs * Once in a while we night get an interrupt where we do not expect it */ if (timeUs <= 0) { timerFreezeCounter++; warning(CUSTOM_OBD_42, "local freeze cnt=%d", timerFreezeCounter); } if (timeUs < 2) timeUs = 2; // for some reason '1' does not really work efiAssertVoid(timeUs > 0, "not positive timeUs"); efiAssertVoid(timeUs < 10 * US_PER_SECOND, "setHardwareUsTimer() too large"); if (GPTDEVICE.state == GPT_ONESHOT) gptStopTimerI(&GPTDEVICE); efiAssertVoid(GPTDEVICE.state == GPT_READY, "hw timer"); if (hasFirmwareError()) return; gptStartOneShotI(&GPTDEVICE, timeUs); lastSetTimerTimeNt = getTimeNowNt(); lastSetTimerValue = timeUs; isTimerPending = TRUE; timerRestartCounter++; }
/* * this private method is executed under lock */ void Executor::doExecute() { /** * Let's execute actions we should execute at this point. * reentrantFlag takes care of the use case where the actions we are executing are scheduling * further invocations */ reentrantFlag = true; int shouldExecute = 1; /** * in real life it could be that while we executing listeners time passes and it's already time to execute * next listeners. * TODO: add a counter & figure out a limit of iterations? */ int totalExecuted = 0; while (shouldExecute > 0) { /** * It's worth noting that that the actions might be adding new actions into the queue */ efitick_t nowNt = getTimeNowNt(); shouldExecute = queue.executeAll(nowNt); totalExecuted += shouldExecute; } lastExecutionCount = totalExecuted; if (!isLocked()) { firmwareError(OBD_PCM_Processor_Fault, "Someone has stolen my lock"); return; } reentrantFlag = false; }
bool WaveChart::isStartedTooLongAgo() { /** * Say at 300rpm we should get at least four events per revolution. * That's 300/60*4=20 events per second * engineChartSize/20 is the longest meaningful chart. * */ efitime_t chartDurationNt = getTimeNowNt() - startTimeNt; return startTimeNt != 0 && NT2US(chartDurationNt) > engineConfiguration->engineChartSize * 1000000 / 20; }
/** * @return true if there was a full shaft revolution within the last second */ bool RpmCalculator::isRunning(DECLARE_ENGINE_PARAMETER_F) { uint64_t nowNt = getTimeNowNt(); if (engine->stopEngineRequestTimeNt != 0) { if (nowNt - engine->stopEngineRequestTimeNt < 3 * US2NT(US_PER_SECOND_LL)) { return false; } } return nowNt - lastRpmEventTimeNt < US2NT(US_PER_SECOND_LL); }
/** * @return vehicle speed, in kilometers per hour */ float getVehicleSpeed(void) { if (mockVehicleSpeed != DEFAULT_MOCK_SPEED) return mockVehicleSpeed; if (!hasVehicleSpeedSensor()) return 0; efitick_t nowNt = getTimeNowNt(); if (nowNt - lastSignalTimeNt > US2NT(US_PER_SECOND_LL)) return 0; // previous signal time is too long ago - we are stopped return engineConfiguration->vehicleSpeedCoef * US2NT(US_PER_SECOND_LL) / vssDiff; }
bool Engine::isInShutdownMode() { #if EFI_MAIN_RELAY_CONTROL || defined(__DOXYGEN__) if (stopEngineRequestTimeNt == 0) // the shutdown procedure is not started return false; const efitime_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; }
static msg_t mwThread(int param) { (void)param; chRegSetThreadName("timer watchdog"); while (TRUE) { chThdSleepMilliseconds(1000); // once a second is enough if (getTimeNowNt() >= lastSetTimerTimeNt + 2 * CORE_CLOCK) { strcpy(buff, "no_event"); itoa10(&buff[8], lastSetTimerValue); firmwareError(buff); return -1; } msg = isTimerPending ? "No_cb too long" : "Timer not awhile"; // 2 seconds of inactivity would not look right efiAssert(getTimeNowNt() < lastSetTimerTimeNt + 2 * CORE_CLOCK, msg, -1); } #if defined __GNUC__ return -1; #endif }
/** * This method is always invoked under a lock */ void Executor::scheduleTimerCallback() { /** * Let's grab fresh time value */ efitick_t nowNt = getTimeNowNt(); nextEventTimeNt = queue.getNextEventTime(nowNt); efiAssertVoid(nextEventTimeNt > nowNt, "setTimer constraint"); if (nextEventTimeNt == EMPTY_QUEUE) return; // no pending events in the queue int32_t hwAlarmTime = NT2US((int32_t)nextEventTimeNt - (int32_t)nowNt); beforeHwSetTimer = GET_TIMESTAMP(); setHardwareUsTimer(hwAlarmTime == 0 ? 1 : hwAlarmTime); hwSetTimerTime = GET_TIMESTAMP() - beforeHwSetTimer; }
/** * sets the alarm to the specified number of microseconds from now. * This function should be invoked under kernel lock which would disable interrupts. */ void setHardwareUsTimer(int32_t timeUs) { if (timeUs == 1) timeUs = 2; // for some reason '1' does not really work efiAssertVoid(timeUs > 0, "neg timeUs"); efiAssertVoid(timeUs < 10 * US_PER_SECOND, "setHardwareUsTimer() too large"); if (GPTDEVICE.state == GPT_ONESHOT) gptStopTimerI(&GPTDEVICE); gptStartOneShotI(&GPTDEVICE, timeUs); lastSetTimerTimeNt = getTimeNowNt(); lastSetTimerValue = timeUs; isTimerPending = TRUE; timerRestartCounter++; }
void initMicrosecondTimer(void) { gptStart(&GPTDEVICE, &gpt5cfg); lastSetTimerTimeNt = getTimeNowNt(); #if EFI_EMULATE_POSITION_SENSORS chThdCreateStatic(mwThreadStack, sizeof(mwThreadStack), NORMALPRIO, (tfunc_t) mwThread, NULL); #endif /* EFI_ENGINE_EMULATOR */ // // test code // chSysLock() // ; // setHardwareUsTimer(300); // chSysUnlock() // ; }
void initMicrosecondTimer(void) { gptStart(&GPTDEVICE, &gpt5cfg); efiAssertVoid(CUSTOM_ERR_TIMER_STATE, GPTDEVICE.state == GPT_READY, "hw state"); lastSetTimerTimeNt = getTimeNowNt(); #if EFI_EMULATE_POSITION_SENSORS watchdogControllerInstance.Start(); #endif /* EFI_ENGINE_EMULATOR */ // // test code // chSysLock() // ; // setHardwareUsTimer(300); // chSysUnlock() // ; }
void PwmConfig::handleCycleStart() { if (safe.phaseIndex == 0) { if (pwmCycleCallback != NULL) { pwmCycleCallback(this); } efiAssertVoid(periodNt != 0, "period not initialized"); if (safe.periodNt != periodNt || safe.iteration == ITERATION_LIMIT) { /** * period length has changed - we need to reset internal state */ safe.startNt = getTimeNowNt(); safe.iteration = 0; safe.periodNt = periodNt; #if DEBUG_PWM scheduleMsg(&logger, "state reset start=%d iteration=%d", state->safe.start, state->safe.iteration); #endif } } }
void Engine::watchdog() { #if EFI_ENGINE_CONTROL if (isRunningPwmTest) return; if (!isSpinning) { if (!isRunningBenchTest() && enginePins.stopPins()) { // todo: make this a firmwareError assuming functional tests would run warning(CUSTOM_ERR_2ND_WATCHDOG, "Some pins were turned off by 2nd pass watchdog"); } return; } efitick_t nowNt = getTimeNowNt(); // 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) /** * 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 */ efitick_t timeSinceLastTriggerEvent = nowNt - lastTriggerToothEventTimeNt; if (timeSinceLastTriggerEvent < US2NT(REVOLUTION_TIME_HIGH_THRESHOLD)) { return; } isSpinning = false; ignitionEvents.isReady = false; #if EFI_PROD_CODE || EFI_SIMULATOR || defined(__DOXYGEN__) scheduleMsg(&logger, "engine has STOPPED"); scheduleMsg(&logger, "templog engine has STOPPED [%x][%x] [%x][%x] %d", (int)(nowNt >> 32), (int)nowNt, (int)(lastTriggerToothEventTimeNt >> 32), (int)lastTriggerToothEventTimeNt, (int)timeSinceLastTriggerEvent ); triggerInfo(); #endif enginePins.stopPins(); #endif }
/** * @brief Shaft position callback used by RPM calculation logic. * * This callback should always be the first of trigger callbacks because other callbacks depend of values * updated here. * This callback is invoked on interrupt thread. */ void rpmShaftPositionCallback(trigger_event_e ckpSignalType, uint32_t index DECLARE_ENGINE_PARAMETER_S) { RpmCalculator *rpmState = &engine->rpmCalculator; uint64_t nowNt = getTimeNowNt(); #if EFI_PROD_CODE efiAssertVoid(getRemainingStack(chThdSelf()) > 256, "lowstck#2z"); #endif if (index != 0) { #if EFI_ANALOG_CHART || defined(__DOXYGEN__) if (boardConfiguration->analogChartMode == AC_TRIGGER) acAddData(getCrankshaftAngleNt(nowNt PASS_ENGINE_PARAMETER), 1000 * ckpSignalType + index); #endif return; } bool hadRpmRecently = rpmState->isRunning(PASS_ENGINE_PARAMETER_F); if (hadRpmRecently) { uint64_t diffNt = nowNt - rpmState->lastRpmEventTimeNt; /** * Four stroke cycle is two crankshaft revolutions * * We always do '* 2' because the event signal is already adjusted to 'per engine cycle' * and each revolution of crankshaft consists of two engine cycles revolutions * */ if (diffNt == 0) { rpmState->setRpmValue(NOISY_RPM); } else { int mult = engineConfiguration->engineCycle / 360; int rpm = (int) (60 * US2NT(US_PER_SECOND_LL) * mult / diffNt); rpmState->setRpmValue(rpm > UNREALISTIC_RPM ? NOISY_RPM : rpm); } } rpmState->onNewEngineCycle(); rpmState->lastRpmEventTimeNt = nowNt; #if EFI_ANALOG_CHART || defined(__DOXYGEN__) if (boardConfiguration->analogChartMode == AC_TRIGGER) acAddData(getCrankshaftAngleNt(nowNt PASS_ENGINE_PARAMETER), index); #endif }
void Engine::watchdog() { #if EFI_ENGINE_CONTROL if (isRunningPwmTest) return; if (!isSpinning) { if (!isRunningBenchTest() && enginePins.stopPins()) { // todo: make this a firmwareError assuming functional tests would run warning(CUSTOM_ERR_2ND_WATCHDOG, "Some pins were turned off by 2nd pass watchdog"); } return; } efitick_t nowNt = getTimeNowNt(); /** * Lowest possible cranking is about 240 RPM, that's 4 revolutions per second. * 0.25 second is 250000 uS * * 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 */ efitick_t timeSinceLastTriggerEvent = nowNt - lastTriggerEventTimeNt; if (timeSinceLastTriggerEvent < US2NT(250000LL)) { return; } isSpinning = false; ignitionEvents.isReady = false; #if EFI_PROD_CODE || EFI_SIMULATOR scheduleMsg(&logger, "engine has STOPPED"); scheduleMsg(&logger, "templog engine has STOPPED [%x][%x] [%x][%x] %d", (int)(nowNt >> 32), (int)nowNt, (int)(lastTriggerEventTimeNt >> 32), (int)lastTriggerEventTimeNt, (int)timeSinceLastTriggerEvent ); triggerInfo(); #endif enginePins.stopPins(); #endif }
FuelConsumptionState::FuelConsumptionState() { perSecondConsumption = perSecondAccumulator = 0; perMinuteConsumption = perMinuteAccumulator = 0; accumulatedSecondPrevNt = accumulatedMinutePrevNt = getTimeNowNt(); }
static void vsAnaWidthCallback(void) { engine->engineState.vssEventCounter++; efitick_t nowNt = getTimeNowNt(); vssDiff = nowNt - lastSignalTimeNt; lastSignalTimeNt = nowNt; }
void EngineState::periodicFastCallback(DECLARE_ENGINE_PARAMETER_F) { int rpm = ENGINE(rpmCalculator.rpmValue); efitick_t nowNt = getTimeNowNt(); if (isCrankingR(rpm)) { crankingTime = nowNt; } else { timeSinceCranking = nowNt - crankingTime; } sparkDwell = getSparkDwell(rpm PASS_ENGINE_PARAMETER); dwellAngle = sparkDwell / getOneDegreeTimeMs(rpm); // todo: move this into slow callback, no reason for IAT corr to be here iatFuelCorrection = getIatCorrection(iat PASS_ENGINE_PARAMETER); // todo: move this into slow callback, no reason for CLT corr to be here if (boardConfiguration->useWarmupPidAfr && clt < engineConfiguration->warmupAfrThreshold) { if (rpm < 200) { cltFuelCorrection = 1; warmupAfrPid.reset(); } else { cltFuelCorrection = warmupAfrPid.getValue(warmupTargetAfr, getAfr(PASS_ENGINE_PARAMETER_F), 1); } #if ! EFI_UNIT_TEST || defined(__DOXYGEN__) if (engineConfiguration->debugMode == WARMUP_ENRICH) { tsOutputChannels.debugFloatField1 = warmupTargetAfr; warmupAfrPid.postState(&tsOutputChannels); } #endif } else { cltFuelCorrection = getCltFuelCorrection(clt PASS_ENGINE_PARAMETER); } cltTimingCorrection = getCltTimingCorrection(clt PASS_ENGINE_PARAMETER); engineNoiseHipLevel = interpolate2d(rpm, engineConfiguration->knockNoiseRpmBins, engineConfiguration->knockNoise, ENGINE_NOISE_CURVE_SIZE); baroCorrection = getBaroCorrection(PASS_ENGINE_PARAMETER_F); injectionOffset = getinjectionOffset(rpm PASS_ENGINE_PARAMETER); float engineLoad = getEngineLoadT(PASS_ENGINE_PARAMETER_F); timingAdvance = getAdvance(rpm, engineLoad PASS_ENGINE_PARAMETER); if (engineConfiguration->fuelAlgorithm == LM_SPEED_DENSITY) { float coolantC = ENGINE(engineState.clt); float intakeC = ENGINE(engineState.iat); float tps = getTPS(PASS_ENGINE_PARAMETER_F); tChargeK = convertCelsiusToKelvin(getTCharge(rpm, tps, coolantC, intakeC PASS_ENGINE_PARAMETER)); float map = getMap(); /** * *0.01 because of https://sourceforge.net/p/rusefi/tickets/153/ */ currentVE = baroCorrection * veMap.getValue(rpm, map) * 0.01; targetAFR = afrMap.getValue(rpm, map); } else { baseTableFuel = getBaseTableFuel(engineConfiguration, rpm, engineLoad); } }
static void vsAnaWidthCallback(void) { vssCounter++; efitick_t nowNt = getTimeNowNt(); vssDiff = nowNt - lastSignalTimeNt; lastSignalTimeNt = nowNt; }
/** * @brief Register an event for digital sniffer */ void WaveChart::addEvent3(const char *name, const char * msg) { #if EFI_TEXT_LOGGING if (!ENGINE(isEngineChartEnabled)) { return; } if (skipUntilEngineCycle != 0 && ENGINE(rpmCalculator.getRevolutionCounter()) < skipUntilEngineCycle) return; #if EFI_SIMULATOR // todo: add UI control to enable this for firmware if desired // CONFIG(alignEngineSnifferAtTDC) && if (!collectingData) { return; } #endif efiAssertVoid(CUSTOM_ERR_6651, name!=NULL, "WC: NULL name"); #if EFI_PROD_CODE efiAssertVoid(CUSTOM_ERR_6652, getCurrentRemainingStack() > 32, "lowstck#2c"); #endif /* EFI_PROD_CODE */ efiAssertVoid(CUSTOM_ERR_6653, isInitialized, "chart not initialized"); #if DEBUG_WAVE scheduleSimpleMsg(&debugLogging, "current", chart->counter); #endif /* DEBUG_WAVE */ if (isFull()) { return; } #if EFI_HISTOGRAMS && EFI_PROD_CODE int beforeCallback = hal_lld_get_counter_value(); #endif efitick_t nowNt = getTimeNowNt(); bool alreadyLocked = lockOutputBuffer(); // we have multiple threads writing to the same output buffer if (counter == 0) { startTimeNt = nowNt; } counter++; /** * We want smaller times within a chart in order to reduce packet size. */ /** * todo: migrate to binary fractions in order to eliminate * this division? I do not like division * * at least that's 32 bit division now */ uint32_t diffNt = nowNt - startTimeNt; uint32_t time100 = NT2US(diffNt / 10); if (remainingSize(&logging) > 35) { /** * printf is a heavy method, append is used here as a performance optimization */ appendFast(&logging, name); appendChar(&logging, CHART_DELIMETER); appendFast(&logging, msg); appendChar(&logging, CHART_DELIMETER); // time100 -= startTime100; itoa10(timeBuffer, time100); appendFast(&logging, timeBuffer); appendChar(&logging, CHART_DELIMETER); logging.linePointer[0] = 0; } if (!alreadyLocked) { unlockOutputBuffer(); } #if EFI_HISTOGRAMS && EFI_PROD_CODE int64_t diff = hal_lld_get_counter_value() - beforeCallback; if (diff > 0) { hsAdd(&engineSnifferHisto, diff); } #endif /* EFI_HISTOGRAMS */ #endif /* EFI_TEXT_LOGGING */ }
cj125spicfg.sspad = getHwPin("cj125", CONFIGB(cj125CsPin)); driver = getSpiDevice(engineConfiguration->cj125SpiDevice); if (driver == NULL) { // error already reported return; } scheduleMsg(logger, "cj125: Starting SPI driver"); spiStart(driver, &cj125spicfg); } /** * @return true if currently in IDLE or ERROR state */ static bool cj125periodic(CJ125 *instance DECLARE_ENGINE_PARAMETER_SUFFIX) { { efitick_t nowNt = getTimeNowNt(); bool isStopped = engine->rpmCalculator.isStopped(PASS_ENGINE_PARAMETER_SIGNATURE); cjUpdateAnalogValues(); // If the controller is disabled if (instance->state == CJ125_IDLE || instance->state == CJ125_ERROR) { return true; } if (instance->state == CJ125_CALIBRATION) { cjCalibrate(); // Start normal operation instance->state = CJ125_INIT; globalInstance.cjSetMode(CJ125_MODE_NORMAL_17); }
static bool_t isTriggerErrorNow() { bool_t justHadError = (getTimeNowNt() - lastDecodingErrorTime) < US2NT(2 * 1000 * 3 * blinkingPeriod); return justHadError || isTriggerDecoderError(); }
void TriggerCentral::handleShaftSignal(trigger_event_e signal DECLARE_ENGINE_PARAMETER_S) { efiAssertVoid(engine!=NULL, "configuration"); nowNt = getTimeNowNt(); efiAssertVoid(engine->engineConfiguration!=NULL, "engineConfiguration"); efiAssertVoid(engine->engineConfiguration2!=NULL, "engineConfiguration2"); engine->onTriggerEvent(nowNt); #if EFI_HISTOGRAMS && EFI_PROD_CODE int beforeCallback = hal_lld_get_counter_value(); #endif int eventIndex = (int) signal; efiAssertVoid(eventIndex >= 0 && eventIndex < HW_EVENT_TYPES, "signal type"); hwEventCounters[eventIndex]++; if (nowNt - previousShaftEventTimeNt > US2NT(US_PER_SECOND_LL)) { /** * We are here if there is a time gap between now and previous shaft event - that means the engine is not runnig. * That means we have lost synchronization since the engine is not running :) */ triggerState.shaft_is_synchronized = false; } previousShaftEventTimeNt = nowNt; /** * This invocation changes the state of triggerState */ triggerState.decodeTriggerEvent(signal, nowNt PASS_ENGINE_PARAMETER); if (!triggerState.shaft_is_synchronized) { // we should not propagate event if we do not know where we are return; } /** * If we only have a crank position sensor, here we are extending crank revolutions with a 360 degree * cycle into a four stroke, 720 degrees cycle. TODO */ int triggerIndexForListeners; if (getOperationMode(engine->engineConfiguration) == FOUR_STROKE_CAM_SENSOR) { // That's easy - trigger cycle matches engine cycle triggerIndexForListeners = triggerState.getCurrentIndex(); } else { bool isEven = triggerState.getTotalRevolutionCounter() & 1; triggerIndexForListeners = triggerState.getCurrentIndex() + (isEven ? 0 : TRIGGER_SHAPE(size)); } reportEventToWaveChart(signal, triggerIndexForListeners); if (triggerState.current_index >= TRIGGER_SHAPE(size)) { warning(OBD_PCM_Processor_Fault, "unexpected eventIndex=%d", triggerState.current_index); } else { /** * Here we invoke all the listeners - the main engine control logic is inside these listeners */ for (int i = 0; i < triggerListeneres.currentListenersCount; i++) { ShaftPositionListener listener = (ShaftPositionListener) triggerListeneres.callbacks[i]; (listener)(signal, triggerIndexForListeners PASS_ENGINE_PARAMETER); } } #if EFI_HISTOGRAMS && EFI_PROD_CODE int afterCallback = hal_lld_get_counter_value(); int diff = afterCallback - beforeCallback; // this counter is only 32 bits so it overflows every minute, let's ignore the value in case of the overflow for simplicity if (diff > 0) { hsAdd(&triggerCallback, diff); } #endif /* EFI_HISTOGRAMS */ }
/** * @brief Trigger decoding happens here * This method changes the state of trigger_state_s data structure according to the trigger event */ void TriggerState::decodeTriggerEvent(trigger_event_e const signal, efitime_t nowNt DECLARE_ENGINE_PARAMETER_S) { efiAssertVoid(signal <= SHAFT_3RD_UP, "unexpected signal"); trigger_wheel_e triggerWheel = eventIndex[signal]; if (!engineConfiguration->useOnlyFrontForTrigger && curSignal == prevSignal) { orderingErrorCounter++; } prevSignal = curSignal; curSignal = signal; eventCount[triggerWheel]++; eventCountExt[signal]++; efitime_t currentDurationLong = getCurrentGapDuration(nowNt); /** * For performance reasons, we want to work with 32 bit values. If there has been more then * 10 seconds since previous trigger event we do not really care. */ currentDuration = currentDurationLong > 10 * US2NT(US_PER_SECOND_LL) ? 10 * US2NT(US_PER_SECOND_LL) : currentDurationLong; if (isLessImportant(signal)) { #if EFI_UNIT_TEST if (printTriggerDebug) { printf("%s isLessImportant %s\r\n", getTrigger_type_e(engineConfiguration->trigger.type), getTrigger_event_e(signal)); } #endif /** * For less important events we simply increment the index. */ nextTriggerEvent() ; if (TRIGGER_SHAPE(gapBothDirections)) { toothed_previous_duration = currentDuration; isFirstEvent = false; toothed_previous_time = nowNt; } return; } isFirstEvent = false; // todo: skip a number of signal from the beginning #if EFI_PROD_CODE // scheduleMsg(&logger, "from %f to %f %d %d", triggerConfig->syncRatioFrom, triggerConfig->syncRatioTo, currentDuration, shaftPositionState->toothed_previous_duration); // scheduleMsg(&logger, "ratio %f", 1.0 * currentDuration/ shaftPositionState->toothed_previous_duration); #else if (toothed_previous_duration != 0) { // printf("ratio %f: cur=%d pref=%d\r\n", 1.0 * currentDuration / shaftPositionState->toothed_previous_duration, // currentDuration, shaftPositionState->toothed_previous_duration); } #endif bool_t isSynchronizationPoint; if (TRIGGER_SHAPE(isSynchronizationNeeded)) { isSynchronizationPoint = currentDuration > toothed_previous_duration * TRIGGER_SHAPE(syncRatioFrom) && currentDuration < toothed_previous_duration * TRIGGER_SHAPE(syncRatioTo); #if EFI_PROD_CODE if (engineConfiguration->isPrintTriggerSynchDetails) { #else if (printTriggerDebug) { #endif /* EFI_PROD_CODE */ float gap = 1.0 * currentDuration / toothed_previous_duration; #if EFI_PROD_CODE scheduleMsg(logger, "gap=%f @ %d", gap, current_index); #else actualSynchGap = gap; print("current gap %f\r\n", gap); #endif /* EFI_PROD_CODE */ } } else { /** * in case of noise the counter could be above the expected number of events */ int d = engineConfiguration->useOnlyFrontForTrigger ? 2 : 1; isSynchronizationPoint = !shaft_is_synchronized || (current_index >= TRIGGER_SHAPE(size) - d); } #if EFI_UNIT_TEST if (printTriggerDebug) { printf("%s isSynchronizationPoint=%d index=%d %s\r\n", getTrigger_type_e(engineConfiguration->trigger.type), isSynchronizationPoint, current_index, getTrigger_event_e(signal)); } #endif if (isSynchronizationPoint) { /** * We can check if things are fine by comparing the number of events in a cycle with the expected number of event. */ bool isDecodingError = eventCount[0] != TRIGGER_SHAPE(expectedEventCount[0]) || eventCount[1] != TRIGGER_SHAPE(expectedEventCount[1]) || eventCount[2] != TRIGGER_SHAPE(expectedEventCount[2]); triggerDecoderErrorPin.setValue(isDecodingError); if (isDecodingError) { lastDecodingErrorTime = getTimeNowNt(); totalTriggerErrorCounter++; if (engineConfiguration->isPrintTriggerSynchDetails) { #if EFI_PROD_CODE scheduleMsg(logger, "error: synchronizationPoint @ index %d expected %d/%d/%d got %d/%d/%d", current_index, TRIGGER_SHAPE(expectedEventCount[0]), TRIGGER_SHAPE(expectedEventCount[1]), TRIGGER_SHAPE(expectedEventCount[2]), eventCount[0], eventCount[1], eventCount[2]); #endif /* EFI_PROD_CODE */ } } errorDetection.add(isDecodingError); if (isTriggerDecoderError()) { warning(OBD_PCM_Processor_Fault, "trigger decoding issue. expected %d/%d/%d got %d/%d/%d", TRIGGER_SHAPE(expectedEventCount[0]), TRIGGER_SHAPE(expectedEventCount[1]), TRIGGER_SHAPE(expectedEventCount[2]), eventCount[0], eventCount[1], eventCount[2]); } shaft_is_synchronized = true; // this call would update duty cycle values nextTriggerEvent() ; nextRevolution(); } else { nextTriggerEvent() ; } toothed_previous_duration = currentDuration; toothed_previous_time = nowNt; } float getEngineCycle(operation_mode_e operationMode) { return operationMode == TWO_STROKE ? 360 : 720; } void addSkippedToothTriggerEvents(trigger_wheel_e wheel, TriggerShape *s, int totalTeethCount, int skippedCount, float toothWidth, float offset, float engineCycle, float filterLeft, float filterRight) { efiAssertVoid(totalTeethCount > 0, "total count"); efiAssertVoid(skippedCount >= 0, "skipped count"); for (int i = 0; i < totalTeethCount - skippedCount - 1; i++) { float angleDown = engineCycle / totalTeethCount * (i + (1 - toothWidth)); float angleUp = engineCycle / totalTeethCount * (i + 1); s->addEvent(offset + angleDown, wheel, TV_HIGH, filterLeft, filterRight); s->addEvent(offset + angleUp, wheel, TV_LOW, filterLeft, filterRight); } float angleDown = engineCycle / totalTeethCount * (totalTeethCount - skippedCount - 1 + (1 - toothWidth) ); s->addEvent(offset + angleDown, wheel, TV_HIGH, filterLeft, filterRight); s->addEvent(offset + engineCycle, wheel, TV_LOW, filterLeft, filterRight); }
void stopEngine(void) { engine->stopEngineRequestTimeNt = getTimeNowNt(); }
void EngineState::periodicFastCallback(DECLARE_ENGINE_PARAMETER_SIGNATURE) { efitick_t nowNt = getTimeNowNt(); if (ENGINE(rpmCalculator).isCranking(PASS_ENGINE_PARAMETER_SIGNATURE)) { crankingTime = nowNt; timeSinceCranking = 0.0f; } else { timeSinceCranking = nowNt - crankingTime; } updateAuxValves(PASS_ENGINE_PARAMETER_SIGNATURE); int rpm = ENGINE(rpmCalculator).getRpm(PASS_ENGINE_PARAMETER_SIGNATURE); sparkDwell = getSparkDwell(rpm PASS_ENGINE_PARAMETER_SUFFIX); dwellAngle = sparkDwell / getOneDegreeTimeMs(rpm); if (hasAfrSensor(PASS_ENGINE_PARAMETER_SIGNATURE)) { engine->sensors.currentAfr = getAfr(PASS_ENGINE_PARAMETER_SIGNATURE); } // todo: move this into slow callback, no reason for IAT corr to be here iatFuelCorrection = getIatFuelCorrection(engine->sensors.iat PASS_ENGINE_PARAMETER_SUFFIX); // todo: move this into slow callback, no reason for CLT corr to be here if (boardConfiguration->useWarmupPidAfr && engine->sensors.clt < engineConfiguration->warmupAfrThreshold) { if (rpm < 200) { cltFuelCorrection = 1; warmupAfrPid.reset(); } else { cltFuelCorrection = warmupAfrPid.getValue(warmupTargetAfr, engine->sensors.currentAfr, 1); } #if ! EFI_UNIT_TEST || defined(__DOXYGEN__) if (engineConfiguration->debugMode == DBG_WARMUP_ENRICH) { tsOutputChannels.debugFloatField1 = warmupTargetAfr; warmupAfrPid.postState(&tsOutputChannels); } #endif } else { cltFuelCorrection = getCltFuelCorrection(PASS_ENGINE_PARAMETER_SIGNATURE); } // update fuel consumption states fuelConsumption.update(nowNt PASS_ENGINE_PARAMETER_SUFFIX); // Fuel cut-off isn't just 0 or 1, it can be tapered fuelCutoffCorrection = getFuelCutOffCorrection(nowNt, rpm PASS_ENGINE_PARAMETER_SUFFIX); // post-cranking fuel enrichment. // for compatibility reasons, apply only if the factor is greater than zero (0.01 margin used) if (engineConfiguration->postCrankingFactor > 0.01f) { // convert to microsecs and then to seconds float timeSinceCrankingInSecs = NT2US(timeSinceCranking) / 1000000.0f; // use interpolation for correction taper postCrankingFuelCorrection = interpolateClamped(0.0f, engineConfiguration->postCrankingFactor, engineConfiguration->postCrankingDurationSec, 1.0f, timeSinceCrankingInSecs); } else { postCrankingFuelCorrection = 1.0f; } cltTimingCorrection = getCltTimingCorrection(PASS_ENGINE_PARAMETER_SIGNATURE); engineNoiseHipLevel = interpolate2d("knock", rpm, engineConfiguration->knockNoiseRpmBins, engineConfiguration->knockNoise, ENGINE_NOISE_CURVE_SIZE); baroCorrection = getBaroCorrection(PASS_ENGINE_PARAMETER_SIGNATURE); injectionOffset = getinjectionOffset(rpm PASS_ENGINE_PARAMETER_SUFFIX); float engineLoad = getEngineLoadT(PASS_ENGINE_PARAMETER_SIGNATURE); timingAdvance = getAdvance(rpm, engineLoad PASS_ENGINE_PARAMETER_SUFFIX); if (engineConfiguration->fuelAlgorithm == LM_SPEED_DENSITY) { float coolantC = ENGINE(sensors.clt); float intakeC = ENGINE(sensors.iat); float tps = getTPS(PASS_ENGINE_PARAMETER_SIGNATURE); tChargeK = convertCelsiusToKelvin(getTCharge(rpm, tps, coolantC, intakeC PASS_ENGINE_PARAMETER_SUFFIX)); float map = getMap(); /** * *0.01 because of https://sourceforge.net/p/rusefi/tickets/153/ */ float rawVe = veMap.getValue(rpm, map); // get VE from the separate table for Idle if (CONFIG(useSeparateVeForIdle)) { float idleVe = interpolate2d("idleVe", rpm, config->idleVeBins, config->idleVe, IDLE_VE_CURVE_SIZE); // interpolate between idle table and normal (running) table using TPS threshold rawVe = interpolateClamped(0.0f, idleVe, boardConfiguration->idlePidDeactivationTpsThreshold, rawVe, tps); } currentVE = baroCorrection * rawVe * 0.01; targetAFR = afrMap.getValue(rpm, map); } else { baseTableFuel = getBaseTableFuel(rpm, engineLoad); } }