Beispiel #1
0
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);

}
Beispiel #2
0
static void digitalMapWidthCallback(void) {
	efitick_t nowNt = getTimeNowNt();

	mapFreq = 1000000.0 / NT2US(nowNt - prevWidthTimeNt);

	prevWidthTimeNt = nowNt;
}
Beispiel #3
0
/**
 * @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;
}
Beispiel #4
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) {
	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++;
}
Beispiel #5
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) {
	/**
	 * #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++;
}
Beispiel #6
0
/*
 * 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;
}
Beispiel #7
0
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;
}
Beispiel #8
0
/**
 * @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);
}
Beispiel #9
0
/**
 * @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;
}
Beispiel #10
0
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;
}
Beispiel #11
0
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        
}
Beispiel #12
0
/**
 * 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;
}
Beispiel #13
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);

	lastSetTimerTimeNt = getTimeNowNt();
	lastSetTimerValue = timeUs;
	isTimerPending = TRUE;
	timerRestartCounter++;
}
Beispiel #14
0
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()
//	;
}
Beispiel #15
0
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
		}
	}
}
Beispiel #17
0
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
}
Beispiel #18
0
/**
 * @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
}
Beispiel #19
0
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
}
Beispiel #20
0
FuelConsumptionState::FuelConsumptionState() {
	perSecondConsumption = perSecondAccumulator = 0;
	perMinuteConsumption = perMinuteAccumulator = 0;
	accumulatedSecondPrevNt = accumulatedMinutePrevNt = getTimeNowNt();
}
Beispiel #21
0
static void vsAnaWidthCallback(void) {
	engine->engineState.vssEventCounter++;
	efitick_t nowNt = getTimeNowNt();
	vssDiff = nowNt - lastSignalTimeNt;
	lastSignalTimeNt = nowNt;
}
Beispiel #22
0
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);
	}

}
Beispiel #23
0
static void vsAnaWidthCallback(void) {
	vssCounter++;
	efitick_t nowNt = getTimeNowNt();
	vssDiff = nowNt - lastSignalTimeNt;
	lastSignalTimeNt = nowNt;
}
Beispiel #24
0
/**
 * @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 */
}
Beispiel #25
0
	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);
		}
Beispiel #26
0
static bool_t isTriggerErrorNow() {
	bool_t justHadError = (getTimeNowNt() - lastDecodingErrorTime) < US2NT(2 * 1000 * 3 * blinkingPeriod);
	return justHadError || isTriggerDecoderError();
}
Beispiel #27
0
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 */
}
Beispiel #28
0
/**
 * @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);
}
Beispiel #29
0
void stopEngine(void) {
	engine->stopEngineRequestTimeNt = getTimeNowNt();
}
Beispiel #30
0
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);
	}
}