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);
	}
}
Esempio n. 2
0
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
}
Esempio n. 3
0
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);
	}
}
Esempio n. 4
0
/**
 *
 * @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);
}
Esempio n. 5
0
/**
 *
 * @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
}
Esempio n. 6
0
/**
 * 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;
}
Esempio n. 7
0
/**
 * 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;
}