static ALWAYS_INLINE void handleFuelInjectionEvent(int eventIndex, bool limitedFuel, InjectionEvent *event, int rpm DECLARE_ENGINE_PARAMETER_S) { if (limitedFuel) return; // todo: move this check up /** * todo: this is a bit tricky with batched injection. is it? Does the same * wetting coefficient works the same way for any injection mode, or is something * x2 or /2? */ floatms_t injectionDuration = ENGINE(wallFuel).adjust(event->injectorIndex, ENGINE(fuelMs) PASS_ENGINE_PARAMETER); ENGINE(actualLastInjection) = injectionDuration; if (cisnan(injectionDuration)) { warning(OBD_PCM_Processor_Fault, "NaN injection pulse"); return; } if (injectionDuration < 0) { warning(OBD_PCM_Processor_Fault, "Negative injection pulse %f", injectionDuration); return; } if (engine->isCylinderCleanupMode) return; floatus_t injectionStartDelayUs = ENGINE(rpmCalculator.oneDegreeUs) * event->injectionStart.angleOffset; OutputSignal *signal = &ENGINE(engineConfiguration2)->fuelActuators[eventIndex]; if (event->isSimultanious) { if (injectionDuration < 0) { firmwareError("duration cannot be negative: %d", injectionDuration); return; } if (cisnan(injectionDuration)) { firmwareError("NaN in scheduleOutput", injectionDuration); return; } /** * this is pretty much copy-paste of 'scheduleOutput' * 'scheduleOutput' is currently only used for injection, so maybe it should be * changed into 'scheduleInjection' and unified? todo: think about it. */ efiAssertVoid(signal!=NULL, "signal is NULL"); int index = getRevolutionCounter() % 2; scheduling_s * sUp = &signal->signalTimerUp[index]; scheduling_s * sDown = &signal->signalTimerDown[index]; scheduleTask("out up", sUp, (int) injectionStartDelayUs, (schfunc_t) &startSimultaniousInjection, engine); scheduleTask("out down", sDown, (int) injectionStartDelayUs + MS2US(injectionDuration), (schfunc_t) &endSimultaniousInjection, engine); } else { #if EFI_UNIT_TEST || defined(__DOXYGEN__) printf("scheduling injection angle=%f/delay=%f injectionDuration=%f\r\n", event->injectionStart.angleOffset, injectionStartDelayUs, injectionDuration); #endif scheduleOutput(signal, getTimeNowUs(), injectionStartDelayUs, MS2US(injectionDuration), event->output); } }
void WaveReader::onFallEvent() { uint64_t nowUs = getTimeNowUs(); eventCounter++; lastActivityTimeUs = nowUs; addWaveChartEvent(name, WC_DOWN, ""); uint64_t width = nowUs - widthEventTimeUs; last_wave_high_widthUs = width; int revolutionCounter = getRevolutionCounter(); totalOnTimeAccumulatorUs += width; if (currentRevolutionCounter != revolutionCounter) { /** * We are here in case of a new engine cycle */ currentRevolutionCounter = revolutionCounter; prevTotalOnTimeUs = totalOnTimeAccumulatorUs; totalOnTimeAccumulatorUs = 0; waveOffsetUs = nowUs - previousEngineCycleTimeUs; } periodEventTimeUs = nowUs; // uint32_t period = engineCycleDurationUs; // local copy of volatile variable }
void scAddData(float angle, float value) { if (!initialized) { return; // this is possible because of initialization sequence } if (engineConfiguration->sensorChartFrequency < 2) { /** * analog chart frequency cannot be 1 because of the way * data flush is implemented, see below */ //todofirmwareError() return; } if (getRevolutionCounter() % engineConfiguration->sensorChartFrequency != 0) { /** * We are here if we do NOT need to add an event to the analog chart */ if (pendingData) { /** * We are here if that's the first time we do not need to add * data after we have added some data - meaning it's time to flush */ // message terminator appendPrintf(&logging, DELIMETER); // output pending data #if EFI_PROD_CODE || defined(__DOXYGEN__) if (getFullLog()) { scheduleLogging(&logging); } #endif pendingData = false; } return; } if (!pendingData) { pendingData = true; resetLogging(&logging); // message header appendPrintf(&logging, "analog_chart%s", DELIMETER); } if (remainingSize(&logging) > 100) { appendPrintf(&logging, "%f|%f|", angle, value); } }
/** * * @param delay the number of ticks before the output signal * immediate output if delay is zero * @param dwell the number of ticks of output duration * */ void scheduleOutput(OutputSignal *signal, float delayMs, float durationMs) { if (durationMs < 0) { firmwareError("duration cannot be negative: %d", durationMs); return; } if (cisnan(durationMs)) { firmwareError("NaN in scheduleOutput", durationMs); return; } int index = getRevolutionCounter() % 2; scheduling_s * sUp = &signal->signalTimerUp[index]; scheduling_s * sDown = &signal->signalTimerDown[index]; scheduleTask("out up", sUp, (int)MS2US(delayMs), (schfunc_t) &turnPinHigh, (void *) signal->io_pin); scheduleTask("out down", sDown, (int)MS2US(delayMs + durationMs), (schfunc_t) &turnPinLow, (void*) signal->io_pin); }
/** * * @param delay the number of ticks before the output signal * immediate output if delay is zero * @param dwell the number of ticks of output duration * */ void scheduleOutput(OutputSignal *signal, efitimeus_t nowUs, float delayUs, float durationUs) { #if EFI_GPIO if (durationUs < 0) { warning(OBD_PCM_Processor_Fault, "duration cannot be negative: %d", durationUs); return; } if (cisnan(durationUs)) { warning(OBD_PCM_Processor_Fault, "NaN in scheduleOutput", durationUs); return; } efiAssertVoid(signal!=NULL, "signal is NULL"); int index = getRevolutionCounter() % 2; scheduling_s * sUp = &signal->signalTimerUp[index]; scheduling_s * sDown = &signal->signalTimerDown[index]; scheduleByTime("out up", sUp, nowUs + (int) delayUs, (schfunc_t) &turnPinHigh, signal->output); scheduleByTime("out down", sDown, nowUs + (int) (delayUs + durationUs), (schfunc_t) &turnPinLow, signal->output); #endif }
/** * 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; }