Beispiel #1
0
static void tempTurnPinHigh(InjectorOutputPin *output) {
	output->overlappingCounter++;

#if FUEL_MATH_EXTREME_LOGGING || defined(__DOXYGEN__)
	printf("seTurnPinHigh %s %d %d\r\n", output->name, output->overlappingCounter, (int)getTimeNowUs());
#endif /* FUEL_MATH_EXTREME_LOGGING */

	if (output->overlappingCounter > 1) {
//		if (output->cancelNextTurningInjectorOff) {
//			// how comes AutoTest.testFordAspire ends up here?
//		} else {
//		/**
//		 * #299
//		 * this is another kind of overlap which happens in case of a small duty cycle after a large duty cycle
//		 */
#if FUEL_MATH_EXTREME_LOGGING || defined(__DOXYGEN__)
		printf("overlapping, no need to touch pin %s %d\r\n", output->name, (int)getTimeNowUs());
#endif /* FUEL_MATH_EXTREME_LOGGING */

//			output->cancelNextTurningInjectorOff = true;
			return;
//		}
	}
#if FUEL_MATH_EXTREME_LOGGING || defined(__DOXYGEN__)
	const char * w = output->currentLogicValue == true ? "err" : "";
//	scheduleMsg(&sharedLogger, "^ %spin=%s eventIndex %d %d", w, output->name,
//			getRevolutionCounter(), getTimeNowUs());
#endif /* FUEL_MATH_EXTREME_LOGGING */

	turnPinHigh(output);
}
Beispiel #2
0
void WaveReader::onFallEvent() {
	efitick_t nowUs = getTimeNowUs();
	fallEventCounter++;
	lastActivityTimeUs = nowUs;
	assertIsrContext(CUSTOM_ERR_6670);
	addEngineSnifferEvent(name, WC_DOWN);

	efitick_t width = nowUs - widthEventTimeUs;
	last_wave_high_widthUs = width;

	int revolutionCounter = engine->rpmCalculator.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
}
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);
	}
}
Beispiel #4
0
void Engine::knockLogic(float knockVolts) {
	this->knockVolts = knockVolts;
    knockNow = knockVolts > engineConfiguration->knockVThreshold;
    /**
     * KnockCount is directly proportional to the degrees of ignition
     * advance removed
     * ex: degrees to subtract = knockCount;
     */

    /**
     * TODO use knockLevel as a factor for amount of ignition advance
     * to remove
     * Perhaps allow the user to set a multiplier
     * ex: degrees to subtract = knockCount + (knockLevel * X)
     * X = user configurable multiplier
     */
    if (knockNow) {
        knockEver = true;
        timeOfLastKnockEvent = getTimeNowUs();
        if (knockCount < engineConfiguration->maxKnockSubDeg)
            knockCount++;
    } else if (knockCount >= 1) {
        knockCount--;
	} else {
        knockCount = 0;
    }
}
Beispiel #5
0
static void testCallback(void *arg) {

	/**
	 * 0.1ms from now please squirt for 1.6ms
	 */
	float delayMs = 0.1;
	float durationMs = 1.6;

	efitimeus_t nowUs = getTimeNowUs();

	scheduleOutput(&outSignals[0], nowUs, delayMs, durationMs);
	scheduleOutput(&outSignals[1], nowUs, delayMs, durationMs);
	scheduleOutput(&outSignals[2], nowUs, delayMs, durationMs);
	scheduleOutput(&outSignals[3], nowUs, delayMs, durationMs);

	scheduleOutput(&outSignals[4], nowUs, delayMs, durationMs);
	scheduleOutput(&outSignals[5], nowUs, delayMs, durationMs);
	scheduleOutput(&outSignals[6], nowUs, delayMs, durationMs);
	scheduleOutput(&outSignals[7], nowUs, delayMs, durationMs);

	/**
	 * this would re-schedule another callback in 2ms from now
	 */
	scheduleTask("test", &ioTest, MS2US(2), testCallback, NULL);
}
Beispiel #6
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
}
Beispiel #7
0
void scheduleTask(const bool monitorReuse, const char *msg, scheduling_s *scheduling, int delayUs,
		schfunc_t callback, void *param) {
	if (debugSignalExecutor) {
		printf("scheduleTask %d\r\n", delayUs);
	}
	scheduleByTime(monitorReuse, msg, scheduling, getTimeNowUs() + delayUs, callback, param);
}
Beispiel #8
0
static float getSignalOnTime(int index) {
	WaveReader *reader = &readers[index];
	ensureInitialized(reader);
	if (getTimeNowUs() - reader->lastActivityTimeUs > 4 * US_PER_SECOND) {
		return 0.0f; // dwell time has expired
	}
	return reader->last_wave_high_widthUs / 1000.0f;
}
Beispiel #9
0
static void waTriggerEventListener(trigger_event_e ckpSignalType, uint32_t index DECLARE_ENGINE_PARAMETER_SUFFIX) {
	(void)ckpSignalType;
	if (index != 0) {
		return;
	}
	efitick_t nowUs = getTimeNowUs();
	engineCycleDurationUs = nowUs - previousEngineCycleTimeUs;
	previousEngineCycleTimeUs = nowUs;
}
Beispiel #10
0
/**
 * I use this questionable feature to tune acceleration enrichment
 */
static void blipIdle(int idlePosition, int durationMs) {
	// todo: add 'blip' feature for automatic target control
	if (timeToStopBlip != 0) {
		return; // already in idle blip
	}
	idlePositionBeforeBlip = boardConfiguration->manIdlePosition;
	setIdleValvePosition(idlePosition);
	timeToStopBlip = getTimeNowUs() + 1000 * durationMs;
}
Beispiel #11
0
static void waTriggerEventListener(trigger_event_e ckpSignalType, uint32_t index, void *arg) {
	(void)ckpSignalType;
	(void)arg;
	if (index != 0) {
		return;
	}
	uint64_t nowUs = getTimeNowUs();
	engineCycleDurationUs = nowUs - previousEngineCycleTimeUs;
	previousEngineCycleTimeUs = nowUs;
}
Beispiel #12
0
static msg_t mwThread(int param) {
	chRegSetThreadName("timer watchdog");

	while (TRUE) {
		chThdSleepMilliseconds(1000); // once a second is enough

		if (getTimeNowUs() >= lastSetTimerTime + 2 * US_PER_SECOND) {
			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(getTimeNowUs() < lastSetTimerTime + 2 * US_PER_SECOND, msg, -1);
	}
#if defined __GNUC__
	return -1;
#endif        
}
Beispiel #13
0
static void waAnaWidthCallback(WaveReader *reader) {
	uint64_t nowUs = getTimeNowUs();
	reader->eventCounter++;
	reader->lastActivityTimeUs = nowUs;
	addWaveChartEvent(reader->name, WC_UP, "");

	uint32_t width = nowUs - reader->periodEventTimeUs;
	reader->last_wave_low_widthUs = width;

	reader->signalPeriodUs = nowUs - reader->widthEventTimeUs;
	reader->widthEventTimeUs = nowUs;
}
Beispiel #14
0
static void timerCallback(scheduling_s *scheduling) {
#if EFI_PRINTF_FUEL_DETAILS
	if (scheduling->callback == (schfunc_t)&seTurnPinLow) {
		printf("executing cb=seTurnPinLow p=%d sch=%d now=%d\r\n", (int)scheduling->param, (int)scheduling,
				(int)getTimeNowUs());
	} else {
//		printf("exec cb=%d p=%d\r\n", (int)scheduling->callback, (int)scheduling->param);
	}

#endif /* EFI_SIMULATOR */
		scheduling->callback(scheduling->param);

}
Beispiel #15
0
static void waAnaWidthCallback(WaveReader *reader) {
	efitick_t nowUs = getTimeNowUs();
	reader->riseEventCounter++;
	reader->lastActivityTimeUs = nowUs;
	assertIsrContext(CUSTOM_ERR_6670);
	addEngineSnifferEvent(reader->name, WC_UP);

	uint32_t width = nowUs - reader->periodEventTimeUs;
	reader->last_wave_low_widthUs = width;

	reader->signalPeriodUs = nowUs - reader->widthEventTimeUs;
	reader->widthEventTimeUs = nowUs;
}
Beispiel #16
0
/**
 * @brief	Register an event for digital sniffer
 */
void addWaveChartEvent3(WaveChart *chart, const char *name, const char * msg, const char * msg2) {
	efiAssertVoid(chart->isInitialized, "chart not initialized");
#if DEBUG_WAVE
	scheduleSimpleMsg(&debugLogging, "current", chart->counter);
#endif
	if (isWaveChartFull(chart)) {
		return;
	}

#if EFI_HISTOGRAMS && EFI_PROD_CODE
	int beforeCallback = hal_lld_get_counter_value();
#endif

	int time100 = getTimeNowUs() / 10;

	bool alreadyLocked = lockOutputBuffer(); // we have multiple threads writing to the same output buffer

	if (chart->counter == 0) {
		chart->startTime = time100;
	}
	chart->counter++;
	if (remainingSize(&chart->logging) > 30) {
		/**
		 * printf is a heavy method, append is used here as a performance optimization
		 */
		appendFast(&chart->logging, name);
		appendFast(&chart->logging, CHART_DELIMETER);
		appendFast(&chart->logging, msg);
		appendFast(&chart->logging, CHART_DELIMETER);
		/**
		 * We want smaller times within a chart in order to reduce packet size.
		 */
		time100 -= chart->startTime;

		itoa10(timeBuffer, time100);
		appendFast(&chart->logging, timeBuffer);
		appendFast(&chart->logging, msg2);
		appendFast(&chart->logging, CHART_DELIMETER);
	}
	if (!alreadyLocked) {
		unlockOutputBuffer();
	}

#if EFI_HISTOGRAMS && EFI_PROD_CODE
	int64_t diff = hal_lld_get_counter_value() - beforeCallback;
	if (diff > 0) {
		hsAdd(&waveChartHisto, diff);
	}
#endif /* EFI_HISTOGRAMS */

}
Beispiel #17
0
static void tempTurnPinLow(InjectorOutputPin *output) {
#if FUEL_MATH_EXTREME_LOGGING || defined(__DOXYGEN__)
	printf("seTurnPinLow %s %d %d\r\n", output->name, output->overlappingCounter, (int)getTimeNowUs());
#endif /* FUEL_MATH_EXTREME_LOGGING */

	if (output->cancelNextTurningInjectorOff) {
		/**
		 * in case of fuel schedule overlap between engine cycles,
		 * and if engine cycle is above say 75% for batch mode on 4 cylinders,
		 * we will get a secondary overlap between the special injection and a normal injection on the same injector.
		 * In such a case want to combine these two injection into one continues injection.
		 * Unneeded turn of injector on is handle while scheduling that second injection, but cancellation
		 * of special injection end has to be taken care of dynamically
		 *
		 */
		output->cancelNextTurningInjectorOff = false;
#if EFI_SIMULATOR || defined(__DOXYGEN__)
		printf("was cancelled %s %d\r\n", output->name, (int)getTimeNowUs());
#endif /* EFI_SIMULATOR */
		return;
	}

	#if FUEL_MATH_EXTREME_LOGGING || defined(__DOXYGEN__)
	const char * w = output->currentLogicValue == false ? "err" : "";

//	scheduleMsg(&sharedLogger, "- %spin=%s eventIndex %d %d", w, output->name,
//			getRevolutionCounter(), getTimeNowUs());
#endif /* FUEL_MATH_EXTREME_LOGGING */

	output->overlappingCounter--;
	if (output->overlappingCounter > 0) {
#if FUEL_MATH_EXTREME_LOGGING || defined(__DOXYGEN__)
		printf("was overlapping, no need to touch pin %s %d\r\n", output->name, (int)getTimeNowUs());
#endif /* FUEL_MATH_EXTREME_LOGGING */
		return;
	}
	turnPinLow(output);
}
Beispiel #18
0
/**
 * 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);

	lastSetTimerTime = getTimeNowUs();
	lastSetTimerValue = timeUs;
	isTimerPending = TRUE;
	timerRestartCounter++;
}
/**
 * @return Next time for signal toggle
 */
efitimeus_t PwmConfig::togglePwmState() {
#if DEBUG_PWM
	scheduleMsg(&logger, "togglePwmState phaseIndex=%d iteration=%d", safe.phaseIndex, safe.iteration);
	scheduleMsg(&logger, "period=%.2f safe.period=%.2f", period, safe.period);
#endif

	if (cisnan(periodNt)) {
		/**
		 * NaN period means PWM is paused
		 */
		return getTimeNowUs() + MS2US(100);
	}

	handleCycleStart();

	/**
	 * Here is where the 'business logic' - the actual pin state change is happening
	 */
	// callback state index is offset by one. todo: why? can we simplify this?
	int cbStateIndex = safe.phaseIndex == 0 ? phaseCount - 1 : safe.phaseIndex - 1;
	stateChangeCallback(this, cbStateIndex);

	efitimeus_t nextSwitchTimeUs = getNextSwitchTimeUs(this);
#if DEBUG_PWM
	scheduleMsg(&logger, "%s: nextSwitchTime %d", state->name, nextSwitchTime);
#endif /* DEBUG_PWM */
	// signed value is needed here
//	int64_t timeToSwitch = nextSwitchTimeUs - getTimeNowUs();
//	if (timeToSwitch < 1) {
//		/**
//		 * We are here if we are late for a state transition.
//		 * At 12000RPM=200Hz with a 60 toothed wheel we need to change state every
//		 * 1000000 / 200 / 120 = ~41 uS. We are kind of OK.
//		 *
//		 * We are also here after a flash write. Flash write freezes the whole chip for a couple of seconds,
//		 * so PWM generation and trigger simulation generation would have to recover from this time lag.
//		 */
//		//todo: introduce error and test this error handling		warning(OBD_PCM_Processor_Fault, "PWM: negative switch time");
//		timeToSwitch = 10;
//	}

	safe.phaseIndex++;
	if (safe.phaseIndex == phaseCount) {
		safe.phaseIndex = 0; // restart
		safe.iteration++;
	}
	return nextSwitchTimeUs;
}
Beispiel #20
0
void initMicrosecondTimer(void) {

	gptStart(&GPTDEVICE, &gpt5cfg);

	lastSetTimerTime = getTimeNowUs();
#if EFI_EMULATE_POSITION_SENSORS
	chThdCreateStatic(mwThreadStack, sizeof(mwThreadStack), NORMALPRIO, (tfunc_t) mwThread, NULL);
#endif /* EFI_ENGINE_EMULATOR */

//	// test code
//	chSysLock()
//	;
//	setHardwareUsTimer(300);
//	chSysUnlock()
//	;
}
Beispiel #21
0
void startIdleBench(void) {
	timeToStopIdleTest = getTimeNowUs() + MS2US(3000); // 3 seconds
	scheduleMsg(logger, "idle valve bench test");
	showIdleInfo();
}
Beispiel #22
0
static void finishIdleTestIfNeeded() {
	if (timeToStopIdleTest != 0 && getTimeNowUs() > timeToStopIdleTest)
		timeToStopIdleTest = 0;
}
Beispiel #23
0
efitick_t getTimeNowNt(void) {
	return getTimeNowUs() * US_TO_NT_MULTIPLIER;
}
Beispiel #24
0
// todo; reduce code duplication with prod code?
efitimems_t currentTimeMillis(void) {
	return getTimeNowUs() / 1000;
}
Beispiel #25
0
static void undoIdleBlipIfNeeded() {
	if (timeToStopBlip != 0 && getTimeNowUs() > timeToStopBlip) {
		timeToStopBlip = 0;
		setIdleValvePosition(idlePositionBeforeBlip);
	}
}
void scheduleByTime(const char *prefix, scheduling_s *scheduling, efitimeus_t time, schfunc_t callback, void *param) {
	scheduleTask(prefix, scheduling, time - getTimeNowUs(), callback, param);
}
Beispiel #27
0
void SleepExecutor::scheduleByTimestamp(scheduling_s *scheduling, efitimeus_t timeUs, schfunc_t callback, void *param) {
	scheduleForLater(scheduling, timeUs - getTimeNowUs(), callback, param);
}
Beispiel #28
0
/**
 * @brief Schedule an event
 *
 * Invokes event callback after the specified amount of time.
 *
 * @param [in, out] scheduling Data structure to keep this event in the collection.
 * @param [in] delayUs the number of microseconds before the output signal immediate output if delay is zero.
 * @param [in] dwell the number of ticks of output duration.
 */
void scheduleTask(const bool monitorReuse, const char *prefix, scheduling_s *scheduling, int delayUs, schfunc_t callback, void *param) {
//	scheduling->name = prefix;
	instance.scheduleByTime(monitorReuse, scheduling, getTimeNowUs() + delayUs, callback, param);
}