2015-07-10 06:01:56 -07:00
|
|
|
/**
|
|
|
|
* @file trigger_structure.cpp
|
|
|
|
*
|
|
|
|
* @date Jan 20, 2014
|
2018-01-20 17:55:31 -08:00
|
|
|
* @author Andrey Belomutskiy, (c) 2012-2018
|
2015-07-10 06:01:56 -07:00
|
|
|
*
|
|
|
|
* This file is part of rusEfi - see http://rusefi.com
|
|
|
|
*
|
|
|
|
* rusEfi is free software; you can redistribute it and/or modify it under the terms of
|
|
|
|
* the GNU General Public License as published by the Free Software Foundation; either
|
|
|
|
* version 3 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* rusEfi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
|
|
|
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along with this program.
|
|
|
|
* If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2018-12-08 13:31:46 -08:00
|
|
|
|
2018-09-16 19:26:57 -07:00
|
|
|
#include "global.h"
|
2015-07-10 06:01:56 -07:00
|
|
|
#include "trigger_structure.h"
|
|
|
|
#include "trigger_decoder.h"
|
|
|
|
#include "engine_math.h"
|
2017-01-03 13:02:43 -08:00
|
|
|
#include "trigger_universal.h"
|
2017-05-19 10:04:16 -07:00
|
|
|
#if EFI_SENSOR_CHART || defined(__DOXYGEN__)
|
2017-05-18 13:39:04 -07:00
|
|
|
#include "sensor_chart.h"
|
2017-05-19 10:04:16 -07:00
|
|
|
#endif /* EFI_SENSOR_CHART */
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
EXTERN_ENGINE;
|
|
|
|
|
|
|
|
trigger_shape_helper::trigger_shape_helper() {
|
|
|
|
memset(&pinStates, 0, sizeof(pinStates));
|
|
|
|
for (int i = 0; i < TRIGGER_CHANNEL_COUNT; i++) {
|
|
|
|
waves[i].init(pinStates[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TriggerShape::TriggerShape() :
|
|
|
|
wave(switchTimesBuffer, NULL) {
|
2018-02-03 13:06:34 -08:00
|
|
|
version = 0;
|
2015-10-29 11:02:52 -07:00
|
|
|
initialize(OM_NONE, false);
|
2015-07-10 06:01:56 -07:00
|
|
|
wave.waves = h.waves;
|
2016-08-18 21:02:50 -07:00
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
memset(triggerIndexByAngle, 0, sizeof(triggerIndexByAngle));
|
|
|
|
}
|
|
|
|
|
2017-05-15 20:28:49 -07:00
|
|
|
void TriggerShape::calculateTriggerSynchPoint(TriggerState *state DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
2015-09-13 07:01:39 -07:00
|
|
|
#if EFI_PROD_CODE || defined(__DOXYGEN__)
|
2018-07-25 20:03:04 -07:00
|
|
|
efiAssertVoid(CUSTOM_ERR_6642, getRemainingStack(chThdGetSelfX()) > 256, "calc s");
|
2015-09-13 07:01:39 -07:00
|
|
|
#endif
|
2015-07-10 06:01:56 -07:00
|
|
|
trigger_config_s const*triggerConfig = &engineConfiguration->trigger;
|
|
|
|
|
2017-05-15 20:28:49 -07:00
|
|
|
triggerShapeSynchPointIndex = findTriggerZeroEventIndex(state, this, triggerConfig PASS_ENGINE_PARAMETER_SUFFIX);
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2017-05-05 12:57:15 -07:00
|
|
|
int length = getLength();
|
|
|
|
engine->engineCycleEventCount = length;
|
2018-09-10 19:10:55 -07:00
|
|
|
efiAssertVoid(CUSTOM_SHAPE_LEN_ZERO, length > 0, "shapeLength=0");
|
2017-05-05 12:57:15 -07:00
|
|
|
if (length >= PWM_PHASE_MAX_COUNT) {
|
|
|
|
warning(CUSTOM_ERR_TRIGGER_SHAPE_TOO_LONG, "Count above %d", length);
|
|
|
|
shapeDefinitionError = true;
|
|
|
|
return;
|
|
|
|
}
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
float firstAngle = getAngle(triggerShapeSynchPointIndex);
|
2018-07-23 18:03:20 -07:00
|
|
|
assertAngleRange(triggerShapeSynchPointIndex, "firstAngle", CUSTOM_ERR_6551);
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
int frontOnlyIndex = 0;
|
|
|
|
|
2017-05-05 12:57:15 -07:00
|
|
|
for (int eventIndex = 0; eventIndex < length; eventIndex++) {
|
2015-07-10 06:01:56 -07:00
|
|
|
if (eventIndex == 0) {
|
|
|
|
// explicit check for zero to avoid issues where logical zero is not exactly zero due to float nature
|
|
|
|
eventAngles[0] = 0;
|
|
|
|
// this value would be used in case of front-only
|
|
|
|
eventAngles[1] = 0;
|
|
|
|
frontOnlyIndexes[0] = 0;
|
|
|
|
} else {
|
2018-07-23 18:03:20 -07:00
|
|
|
assertAngleRange(triggerShapeSynchPointIndex, "triggerShapeSynchPointIndex", CUSTOM_ERR_6552);
|
2015-07-10 06:01:56 -07:00
|
|
|
int triggerDefinitionCoordinate = (triggerShapeSynchPointIndex + eventIndex) % engine->engineCycleEventCount;
|
2018-07-25 20:03:04 -07:00
|
|
|
efiAssertVoid(CUSTOM_ERR_6595, engine->engineCycleEventCount != 0, "zero engineCycleEventCount");
|
2018-11-21 16:40:19 -08:00
|
|
|
int triggerDefinitionIndex = triggerDefinitionCoordinate >= privateTriggerDefinitionSize ? triggerDefinitionCoordinate - privateTriggerDefinitionSize : triggerDefinitionCoordinate;
|
2015-07-10 06:01:56 -07:00
|
|
|
float angle = getAngle(triggerDefinitionCoordinate) - firstAngle;
|
2018-07-25 20:03:04 -07:00
|
|
|
efiAssertVoid(CUSTOM_ERR_6596, !cisnan(angle), "trgSyncNaN");
|
2018-07-23 18:38:05 -07:00
|
|
|
fixAngle(angle, "trgSync", CUSTOM_ERR_6559);
|
2016-02-27 20:03:34 -08:00
|
|
|
if (engineConfiguration->useOnlyRisingEdgeForTrigger) {
|
2015-07-10 06:01:56 -07:00
|
|
|
if (isFrontEvent[triggerDefinitionIndex]) {
|
|
|
|
frontOnlyIndex += 2;
|
|
|
|
eventAngles[frontOnlyIndex] = angle;
|
|
|
|
eventAngles[frontOnlyIndex + 1] = angle;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
eventAngles[eventIndex] = angle;
|
|
|
|
}
|
|
|
|
|
|
|
|
frontOnlyIndexes[eventIndex] = frontOnlyIndex;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-31 09:01:48 -07:00
|
|
|
void TriggerShape::initialize(operation_mode_e operationMode, bool needSecondTriggerInput) {
|
2016-08-17 21:02:22 -07:00
|
|
|
isSynchronizationNeeded = true; // that's default value
|
|
|
|
this->needSecondTriggerInput = needSecondTriggerInput;
|
2018-02-05 14:16:34 -08:00
|
|
|
memset(expectedDutyCycle, 0, sizeof(expectedDutyCycle));
|
2016-08-17 21:02:22 -07:00
|
|
|
memset(eventAngles, 0, sizeof(eventAngles));
|
|
|
|
// memset(triggerIndexByAngle, 0, sizeof(triggerIndexByAngle));
|
2016-08-18 19:01:57 -07:00
|
|
|
|
2018-10-21 10:58:54 -07:00
|
|
|
setTriggerSynchronizationGap(2);
|
2018-10-23 00:47:30 -07:00
|
|
|
for (int index = 1; index < GAP_TRACKING_LENGTH ; index++) {
|
2018-10-21 10:58:54 -07:00
|
|
|
// NaN means do not use this gap ratio
|
|
|
|
setTriggerSynchronizationGap3(index, NAN, 100000);
|
|
|
|
}
|
2016-08-18 19:01:57 -07:00
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
tdcPosition = 0;
|
2017-02-23 10:53:27 -08:00
|
|
|
shapeDefinitionError = useOnlyPrimaryForSync = false;
|
2015-07-10 06:01:56 -07:00
|
|
|
useRiseEdge = true;
|
2017-03-18 17:59:52 -07:00
|
|
|
gapBothDirections = false;
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
invertOnAdd = false;
|
|
|
|
|
|
|
|
this->operationMode = operationMode;
|
2018-11-21 16:40:19 -08:00
|
|
|
privateTriggerDefinitionSize = 0;
|
2015-07-10 06:01:56 -07:00
|
|
|
triggerShapeSynchPointIndex = 0;
|
|
|
|
memset(initialState, 0, sizeof(initialState));
|
|
|
|
memset(switchTimesBuffer, 0, sizeof(switchTimesBuffer));
|
|
|
|
memset(expectedEventCount, 0, sizeof(expectedEventCount));
|
|
|
|
wave.reset();
|
|
|
|
previousAngle = 0;
|
2016-08-19 20:02:21 -07:00
|
|
|
memset(frontOnlyIndexes, 0, sizeof(frontOnlyIndexes));
|
|
|
|
memset(isFrontEvent, 0, sizeof(isFrontEvent));
|
2016-08-19 21:02:28 -07:00
|
|
|
#if EFI_UNIT_TEST || defined(__DOXYGEN__)
|
|
|
|
memset(&triggerSignals, 0, sizeof(triggerSignals));
|
|
|
|
#endif
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2016-08-20 06:02:06 -07:00
|
|
|
int TriggerShape::getSize() const {
|
2018-11-21 16:40:19 -08:00
|
|
|
return privateTriggerDefinitionSize;
|
2016-08-20 06:02:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
int TriggerShape::getTriggerShapeSynchPointIndex() {
|
|
|
|
return triggerShapeSynchPointIndex;
|
|
|
|
}
|
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
efitime_t TriggerState::getStartOfRevolutionIndex() {
|
|
|
|
return totalEventCountBase;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TriggerState::resetRunningCounters() {
|
|
|
|
runningRevolutionCounter = 0;
|
|
|
|
runningTriggerErrorCounter = 0;
|
|
|
|
runningOrderingErrorCounter = 0;
|
|
|
|
}
|
|
|
|
|
2017-12-03 21:04:47 -08:00
|
|
|
void TriggerState::runtimeStatistics(efitime_t nowNt DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
2017-05-18 13:16:55 -07:00
|
|
|
// empty base implementation
|
|
|
|
}
|
|
|
|
|
2017-12-13 18:08:34 -08:00
|
|
|
TriggerStateWithRunningStatistics::TriggerStateWithRunningStatistics() {
|
|
|
|
instantRpm = 0;
|
2018-03-10 17:58:51 -08:00
|
|
|
prevInstantRpmValue = 0;
|
|
|
|
// avoid ill-defined instant RPM when the data is not gathered yet
|
|
|
|
efitime_t nowNt = getTimeNowNt();
|
|
|
|
for (int i = 0; i < PWM_PHASE_MAX_COUNT; i++) {
|
|
|
|
timeOfLastEvent[i] = nowNt;
|
|
|
|
}
|
2017-12-13 18:08:34 -08:00
|
|
|
}
|
|
|
|
|
2017-12-03 20:58:48 -08:00
|
|
|
float TriggerStateWithRunningStatistics::calculateInstantRpm(int *prevIndex, efitime_t nowNt DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
2017-12-13 18:08:34 -08:00
|
|
|
int current_index = currentCycle.current_index; // local copy so that noone changes the value on us
|
2017-12-03 20:58:48 -08:00
|
|
|
/**
|
|
|
|
* Here we calculate RPM based on last 90 degrees
|
|
|
|
*/
|
2017-12-13 18:08:34 -08:00
|
|
|
angle_t currentAngle = TRIGGER_SHAPE(eventAngles[current_index]);
|
|
|
|
// todo: make this '90' depend on cylinder count or trigger shape?
|
2017-12-03 20:58:48 -08:00
|
|
|
angle_t previousAngle = currentAngle - 90;
|
2018-07-23 18:38:05 -07:00
|
|
|
fixAngle(previousAngle, "prevAngle", CUSTOM_ERR_6560);
|
2017-12-03 20:58:48 -08:00
|
|
|
// todo: prevIndex should be pre-calculated
|
|
|
|
*prevIndex = TRIGGER_SHAPE(triggerIndexByAngle[(int)previousAngle]);
|
|
|
|
|
|
|
|
// now let's get precise angle for that event
|
|
|
|
angle_t prevIndexAngle = TRIGGER_SHAPE(eventAngles[*prevIndex]);
|
|
|
|
uint32_t time = nowNt - timeOfLastEvent[*prevIndex];
|
|
|
|
angle_t angleDiff = currentAngle - prevIndexAngle;
|
|
|
|
// todo: angle diff should be pre-calculated
|
2018-07-23 18:38:05 -07:00
|
|
|
fixAngle(angleDiff, "angleDiff", CUSTOM_ERR_6561);
|
2017-12-03 20:58:48 -08:00
|
|
|
|
2018-03-10 17:58:51 -08:00
|
|
|
// just for safety
|
|
|
|
if (time == 0)
|
|
|
|
return prevInstantRpmValue;
|
|
|
|
|
2017-12-03 20:58:48 -08:00
|
|
|
float instantRpm = (60000000.0 / 360 * US_TO_NT_MULTIPLIER) * angleDiff / time;
|
2017-12-13 18:08:34 -08:00
|
|
|
instantRpmValue[current_index] = instantRpm;
|
|
|
|
timeOfLastEvent[current_index] = nowNt;
|
2017-12-03 20:58:48 -08:00
|
|
|
|
2018-03-10 17:58:51 -08:00
|
|
|
// This fixes early RPM instability based on incomplete data
|
|
|
|
if (instantRpm < RPM_LOW_THRESHOLD)
|
|
|
|
return prevInstantRpmValue;
|
|
|
|
prevInstantRpmValue = instantRpm;
|
|
|
|
|
2017-12-03 20:58:48 -08:00
|
|
|
return instantRpm;
|
|
|
|
}
|
|
|
|
|
2018-03-10 17:58:51 -08:00
|
|
|
void TriggerStateWithRunningStatistics::setLastEventTimeForInstantRpm(efitime_t nowNt DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
|
|
|
timeOfLastEvent[currentCycle.current_index] = nowNt;
|
|
|
|
}
|
|
|
|
|
2017-12-03 21:04:47 -08:00
|
|
|
void TriggerStateWithRunningStatistics::runtimeStatistics(efitime_t nowNt DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
2017-12-16 21:17:55 -08:00
|
|
|
if (engineConfiguration->debugMode == DBG_INSTANT_RPM) {
|
2017-12-13 18:08:34 -08:00
|
|
|
int prevIndex;
|
|
|
|
instantRpm = calculateInstantRpm(&prevIndex, nowNt PASS_ENGINE_PARAMETER_SUFFIX);
|
|
|
|
}
|
2017-05-18 13:39:04 -07:00
|
|
|
if (ENGINE(sensorChartMode) == SC_RPM_ACCEL || ENGINE(sensorChartMode) == SC_DETAILED_RPM) {
|
2017-12-03 20:58:48 -08:00
|
|
|
int prevIndex;
|
2017-12-13 18:08:34 -08:00
|
|
|
instantRpm = calculateInstantRpm(&prevIndex, nowNt PASS_ENGINE_PARAMETER_SUFFIX);
|
2017-05-18 13:39:04 -07:00
|
|
|
|
|
|
|
#if EFI_SENSOR_CHART || defined(__DOXYGEN__)
|
2017-12-03 20:58:48 -08:00
|
|
|
angle_t currentAngle = TRIGGER_SHAPE(eventAngles[currentCycle.current_index]);
|
2017-05-18 13:39:04 -07:00
|
|
|
if (boardConfiguration->sensorChartMode == SC_DETAILED_RPM) {
|
2017-12-03 20:58:48 -08:00
|
|
|
scAddData(currentAngle, instantRpm);
|
2017-05-18 13:39:04 -07:00
|
|
|
} else {
|
2017-12-03 20:58:48 -08:00
|
|
|
scAddData(currentAngle, instantRpm / instantRpmValue[prevIndex]);
|
2017-05-18 13:39:04 -07:00
|
|
|
}
|
2017-05-19 10:04:16 -07:00
|
|
|
#endif /* EFI_SENSOR_CHART */
|
2017-05-18 13:39:04 -07:00
|
|
|
}
|
2017-05-18 13:16:55 -07:00
|
|
|
}
|
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
efitime_t TriggerState::getTotalEventCounter() {
|
2015-09-08 20:01:07 -07:00
|
|
|
return totalEventCountBase + currentCycle.current_index;
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
int TriggerState::getTotalRevolutionCounter() {
|
|
|
|
return totalRevolutionCounter;
|
|
|
|
}
|
|
|
|
|
2016-08-23 19:02:18 -07:00
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
/**
|
2016-11-14 12:04:44 -08:00
|
|
|
* physical primary trigger duration
|
2015-07-10 06:01:56 -07:00
|
|
|
*/
|
2016-11-14 12:04:44 -08:00
|
|
|
angle_t TriggerShape::getCycleDuration() const {
|
2016-11-13 21:02:13 -08:00
|
|
|
switch (operationMode) {
|
|
|
|
case FOUR_STROKE_SYMMETRICAL_CRANK_SENSOR:
|
2016-11-14 12:04:44 -08:00
|
|
|
return 180;
|
2016-11-13 21:02:13 -08:00
|
|
|
case FOUR_STROKE_CRANK_SENSOR:
|
2016-11-14 12:04:44 -08:00
|
|
|
case TWO_STROKE:
|
|
|
|
return 360;
|
2016-11-13 21:02:13 -08:00
|
|
|
default:
|
2016-11-14 12:04:44 -08:00
|
|
|
return 720;
|
2016-11-13 21:02:13 -08:00
|
|
|
}
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2016-11-14 12:04:44 -08:00
|
|
|
/**
|
|
|
|
* Trigger event count equals engine cycle event count if we have a cam sensor.
|
|
|
|
* Two trigger cycles make one engine cycle in case of a four stroke engine If we only have a cranksensor.
|
|
|
|
*/
|
|
|
|
uint32_t TriggerShape::getLength() const {
|
|
|
|
/**
|
|
|
|
* 4 for FOUR_STROKE_SYMMETRICAL_CRANK_SENSOR
|
|
|
|
* 2 for FOUR_STROKE_CRANK_SENSOR
|
|
|
|
* 1 otherwise
|
|
|
|
*/
|
|
|
|
int multiplier = getEngineCycle(operationMode) / getCycleDuration();
|
|
|
|
return multiplier * getSize();
|
|
|
|
}
|
|
|
|
|
2016-01-14 20:03:17 -08:00
|
|
|
angle_t TriggerShape::getAngle(int index) const {
|
2015-07-10 06:01:56 -07:00
|
|
|
// todo: why is this check here? looks like the code below could be used universally
|
|
|
|
if (operationMode == FOUR_STROKE_CAM_SENSOR) {
|
|
|
|
return getSwitchAngle(index);
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* FOUR_STROKE_CRANK_SENSOR magic:
|
|
|
|
* We have two crank shaft revolutions for each engine cycle
|
|
|
|
* See also trigger_central.cpp
|
|
|
|
* See also getEngineCycleEventCount()
|
|
|
|
*/
|
2018-11-21 16:40:19 -08:00
|
|
|
efiAssert(CUSTOM_ERR_ASSERT, privateTriggerDefinitionSize != 0, "shapeSize=0", NAN);
|
|
|
|
int crankCycle = index / privateTriggerDefinitionSize;
|
|
|
|
int remainder = index % privateTriggerDefinitionSize;
|
2016-11-13 21:02:13 -08:00
|
|
|
|
|
|
|
return getCycleDuration() * crankCycle + getSwitchAngle(remainder);
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2017-05-15 20:28:49 -07:00
|
|
|
void TriggerShape::addEvent2(angle_t angle, trigger_wheel_e const waveIndex, trigger_value_e const stateParam, float filterLeft, float filterRight DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
2015-07-10 06:01:56 -07:00
|
|
|
if (angle > filterLeft && angle < filterRight)
|
2017-05-15 20:28:49 -07:00
|
|
|
addEvent2(angle, waveIndex, stateParam PASS_ENGINE_PARAMETER_SUFFIX);
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
operation_mode_e TriggerShape::getOperationMode() {
|
|
|
|
return operationMode;
|
|
|
|
}
|
|
|
|
|
2015-09-11 22:02:28 -07:00
|
|
|
#if EFI_UNIT_TEST || defined(__DOXYGEN__)
|
2015-09-10 20:01:32 -07:00
|
|
|
extern bool printTriggerDebug;
|
|
|
|
#endif
|
|
|
|
|
2017-05-15 20:28:49 -07:00
|
|
|
void TriggerShape::addEvent2(angle_t angle, trigger_wheel_e const waveIndex, trigger_value_e const stateParam DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
2018-09-10 19:10:55 -07:00
|
|
|
efiAssertVoid(CUSTOM_OMODE_UNDEF, operationMode != OM_NONE, "operationMode not set");
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2018-07-25 20:03:04 -07:00
|
|
|
efiAssertVoid(CUSTOM_ERR_6598, waveIndex!= T_SECONDARY || needSecondTriggerInput, "secondary needed or not?");
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2015-09-11 22:02:28 -07:00
|
|
|
#if EFI_UNIT_TEST || defined(__DOXYGEN__)
|
2015-09-10 20:01:32 -07:00
|
|
|
if (printTriggerDebug) {
|
2018-01-23 09:05:14 -08:00
|
|
|
printf("addEvent2 %.2f i=%d r/f=%d\r\n", angle, waveIndex, stateParam);
|
2015-09-10 20:01:32 -07:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
trigger_value_e state;
|
|
|
|
if (invertOnAdd) {
|
2015-10-31 13:02:10 -07:00
|
|
|
state = (stateParam == TV_FALL) ? TV_RISE : TV_FALL;
|
2015-07-10 06:01:56 -07:00
|
|
|
} else {
|
|
|
|
state = stateParam;
|
|
|
|
}
|
|
|
|
|
2015-08-30 11:01:28 -07:00
|
|
|
#if EFI_UNIT_TEST || defined(__DOXYGEN__)
|
2015-07-10 06:01:56 -07:00
|
|
|
int signal = waveIndex * 1000 + stateParam;
|
2018-11-21 16:40:19 -08:00
|
|
|
triggerSignals[privateTriggerDefinitionSize] = signal;
|
2015-07-10 06:01:56 -07:00
|
|
|
#endif
|
|
|
|
|
|
|
|
float engineCycle = getEngineCycle(operationMode);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* While '720' value works perfectly it has not much sense for crank sensor-only scenario.
|
|
|
|
* todo: accept angle as a value in the 0..1 range?
|
|
|
|
*/
|
|
|
|
angle /= engineCycle;
|
|
|
|
|
2016-02-27 20:03:34 -08:00
|
|
|
if (!engineConfiguration->useOnlyRisingEdgeForTrigger || stateParam == TV_RISE) {
|
2015-07-10 06:01:56 -07:00
|
|
|
expectedEventCount[waveIndex]++;
|
|
|
|
}
|
|
|
|
|
2018-07-25 20:03:04 -07:00
|
|
|
efiAssertVoid(CUSTOM_ERR_6599, angle > 0, "angle should be positive");
|
2018-11-21 16:40:19 -08:00
|
|
|
if (privateTriggerDefinitionSize > 0) {
|
2015-07-10 06:01:56 -07:00
|
|
|
if (angle <= previousAngle) {
|
2018-11-21 16:40:19 -08:00
|
|
|
warning(CUSTOM_ERR_TRG_ANGLE_ORDER, "invalid angle order: new=%.2f and prev=%.2f, size=%d", angle, previousAngle, privateTriggerDefinitionSize);
|
2017-03-12 19:46:01 -07:00
|
|
|
shapeDefinitionError = true;
|
2015-07-10 06:01:56 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
previousAngle = angle;
|
2018-11-21 16:40:19 -08:00
|
|
|
if (privateTriggerDefinitionSize == 0) {
|
|
|
|
privateTriggerDefinitionSize = 1;
|
2015-07-10 06:01:56 -07:00
|
|
|
for (int i = 0; i < PWM_PHASE_MAX_WAVE_PER_PWM; i++) {
|
|
|
|
single_wave_s *wave = &this->wave.waves[i];
|
|
|
|
|
|
|
|
if (wave->pinStates == NULL) {
|
2017-03-12 19:46:01 -07:00
|
|
|
warning(CUSTOM_ERR_STATE_NULL, "wave pinStates is NULL");
|
|
|
|
shapeDefinitionError = true;
|
2015-07-10 06:01:56 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
wave->pinStates[0] = initialState[i];
|
|
|
|
}
|
|
|
|
|
2015-10-31 13:02:10 -07:00
|
|
|
isFrontEvent[0] = TV_RISE == stateParam;
|
2015-07-10 06:01:56 -07:00
|
|
|
wave.setSwitchTime(0, angle);
|
|
|
|
wave.waves[waveIndex].pinStates[0] = state;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-11-21 16:40:19 -08:00
|
|
|
int exactMatch = wave.findAngleMatch(angle, privateTriggerDefinitionSize);
|
2015-07-10 06:01:56 -07:00
|
|
|
if (exactMatch != EFI_ERROR_CODE) {
|
2017-04-19 19:03:14 -07:00
|
|
|
warning(CUSTOM_ERR_SAME_ANGLE, "same angle: not supported");
|
2017-03-12 19:46:01 -07:00
|
|
|
shapeDefinitionError = true;
|
2015-07-10 06:01:56 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-11-21 16:40:19 -08:00
|
|
|
int index = wave.findInsertionAngle(angle, privateTriggerDefinitionSize);
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2018-04-29 23:22:54 -07:00
|
|
|
/**
|
|
|
|
* todo: it would be nice to be able to provide trigger angles without sorting them externally
|
|
|
|
* The idea here is to shift existing data - including handling high vs low state of the signals
|
|
|
|
*/
|
2018-02-05 14:16:34 -08:00
|
|
|
// todo: does this logic actually work? I think it does not! due to broken state handling
|
2018-04-29 23:22:54 -07:00
|
|
|
/*
|
2015-07-10 06:01:56 -07:00
|
|
|
for (int i = size - 1; i >= index; i--) {
|
|
|
|
for (int j = 0; j < PWM_PHASE_MAX_WAVE_PER_PWM; j++) {
|
|
|
|
wave.waves[j].pinStates[i + 1] = wave.getChannelState(j, index);
|
|
|
|
}
|
|
|
|
wave.setSwitchTime(i + 1, wave.getSwitchTime(i));
|
|
|
|
}
|
2018-04-29 23:22:54 -07:00
|
|
|
*/
|
2015-10-31 13:02:10 -07:00
|
|
|
isFrontEvent[index] = TV_RISE == stateParam;
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2018-11-21 16:40:19 -08:00
|
|
|
if (index != privateTriggerDefinitionSize) {
|
2017-05-29 16:23:15 -07:00
|
|
|
firmwareError(ERROR_TRIGGER_DRAMA, "are we ever here?");
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2018-11-21 16:40:19 -08:00
|
|
|
privateTriggerDefinitionSize++;
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
for (int i = 0; i < PWM_PHASE_MAX_WAVE_PER_PWM; i++) {
|
|
|
|
wave.waves[i].pinStates[index] = wave.getChannelState(i, index - 1);
|
|
|
|
}
|
|
|
|
wave.setSwitchTime(index, angle);
|
|
|
|
wave.waves[waveIndex].pinStates[index] = state;
|
|
|
|
}
|
|
|
|
|
2016-01-14 20:03:17 -08:00
|
|
|
angle_t TriggerShape::getSwitchAngle(int index) const {
|
2015-07-10 06:01:56 -07:00
|
|
|
return getCycleDuration() * wave.getSwitchTime(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
void setToothedWheelConfiguration(TriggerShape *s, int total, int skipped,
|
2017-05-15 20:28:49 -07:00
|
|
|
operation_mode_e operationMode DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
2015-08-30 11:01:28 -07:00
|
|
|
#if EFI_ENGINE_CONTROL || defined(__DOXYGEN__)
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
s->useRiseEdge = true;
|
|
|
|
|
|
|
|
initializeSkippedToothTriggerShapeExt(s, total, skipped,
|
2017-05-15 20:28:49 -07:00
|
|
|
operationMode PASS_ENGINE_PARAMETER_SUFFIX);
|
2015-07-10 06:01:56 -07:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void TriggerShape::setTriggerSynchronizationGap2(float syncRatioFrom, float syncRatioTo) {
|
2018-10-21 10:41:01 -07:00
|
|
|
setTriggerSynchronizationGap3(0, syncRatioFrom, syncRatioTo);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TriggerShape::setTriggerSynchronizationGap3(int index, float syncRatioFrom, float syncRatioTo) {
|
2015-07-10 06:01:56 -07:00
|
|
|
isSynchronizationNeeded = true;
|
2018-10-21 10:41:01 -07:00
|
|
|
this->syncronizationRatioFrom[index] = syncRatioFrom;
|
|
|
|
this->syncronizationRatioTo[index] = syncRatioTo;
|
|
|
|
if (index == 0) {
|
|
|
|
// we have a special case here - only sync with one gap has this feature
|
|
|
|
this->syncRatioAvg = (int)efiRound((syncRatioFrom + syncRatioTo) * 0.5f, 1.0f);
|
|
|
|
}
|
|
|
|
|
2017-03-04 16:47:15 -08:00
|
|
|
#if EFI_UNIT_TEST || defined(__DOXYGEN__)
|
|
|
|
if (printTriggerDebug) {
|
2018-10-21 10:41:01 -07:00
|
|
|
printf("setTriggerSynchronizationGap3 %d %.2f %.2f\r\n", index, syncRatioFrom, syncRatioTo);
|
2017-03-04 16:47:15 -08:00
|
|
|
}
|
|
|
|
#endif /* EFI_UNIT_TEST */
|
2018-10-21 10:41:01 -07:00
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2015-12-27 13:02:44 -08:00
|
|
|
void TriggerShape::setTriggerSynchronizationGap(float syncRatio) {
|
2018-10-21 10:41:01 -07:00
|
|
|
setTriggerSynchronizationGap3(0, syncRatio * 0.75f, syncRatio * 1.25f);
|
2015-09-12 12:02:40 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void TriggerShape::setSecondTriggerSynchronizationGap2(float syncRatioFrom, float syncRatioTo) {
|
2018-10-21 10:41:01 -07:00
|
|
|
setTriggerSynchronizationGap3(1, syncRatioFrom, syncRatioTo);
|
2015-09-12 12:02:40 -07:00
|
|
|
}
|
|
|
|
|
2015-12-27 13:02:44 -08:00
|
|
|
void TriggerShape::setThirdTriggerSynchronizationGap(float syncRatio) {
|
2018-10-21 10:41:01 -07:00
|
|
|
setTriggerSynchronizationGap3(2, syncRatio * 0.75f, syncRatio * 1.25f);
|
2015-12-27 13:02:44 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void TriggerShape::setSecondTriggerSynchronizationGap(float syncRatio) {
|
2018-10-21 10:41:01 -07:00
|
|
|
setTriggerSynchronizationGap3(1, syncRatio * 0.75f, syncRatio * 1.25f);
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|