Merge branch 'master' of https://github.com/rusefi/rusefi into master

This commit is contained in:
rusefillc 2023-01-10 16:12:13 -05:00
commit ea533fed1d
58 changed files with 2478 additions and 156 deletions

View File

@ -269,7 +269,7 @@ expected<percent_t> EtbController::getSetpoint() {
expected<percent_t> EtbController::getSetpointIdleValve() const {
// VW ETB idle mode uses an ETB only for idle (a mini-ETB sets the lower stop, and a normal cable
// can pull the throttle up off the stop.), so we directly control the throttle with the idle position.
#if EFI_TUNER_STUDIO
#if EFI_TUNER_STUDIO && (EFI_PROD_CODE || EFI_SIMULATOR)
engine->outputChannels.etbTarget = m_idlePosition;
#endif // EFI_TUNER_STUDIO
return clampF(0, m_idlePosition, 100);
@ -637,20 +637,41 @@ void EtbController::update() {
m_pid.iTermMin = engineConfiguration->etb_iTermMin;
m_pid.iTermMax = engineConfiguration->etb_iTermMax;
ClosedLoopController::update();
auto output = ClosedLoopController::update();
if (!output) {
return;
}
checkOutput(output.Value);
}
expected<percent_t> EtbController::getOutput() {
// total open + closed loop parts
expected<percent_t> output = ClosedLoopController::getOutput();
if (!output) {
return output;
}
etbDutyAverage = m_dutyAverage.average(absF(output.Value));
void EtbController::checkOutput(percent_t output) {
etbDutyAverage = m_dutyAverage.average(absF(output));
etbDutyRateOfChange = m_dutyRocAverage.average(absF(output.Value - prevOutput));
prevOutput = output.Value;
return output;
etbDutyRateOfChange = m_dutyRocAverage.average(absF(output - prevOutput));
prevOutput = output;
float integrator = absF(m_pid.getIntegration());
auto integratorLimit = engineConfiguration->etbJamIntegratorLimit;
if (integratorLimit != 0) {
auto nowNt = getTimeNowNt();
if (integrator > integratorLimit) {
if (m_jamDetectTimer.hasElapsedSec(engineConfiguration->etbJamTimeout)) {
// ETB is jammed!
jamDetected = true;
// TODO: do something about it!
}
} else {
m_jamDetectTimer.reset(getTimeNowNt());
jamDetected = false;
}
jamTimer = m_jamDetectTimer.getElapsedSeconds(nowNt);
}
}
void EtbController::autoCalibrateTps() {

View File

@ -53,10 +53,9 @@ public:
virtual void setIdlePosition(percent_t pos) = 0;
virtual void setWastegatePosition(percent_t pos) = 0;
virtual void update() = 0;
virtual expected<percent_t> getOutput() = 0;
virtual void autoCalibrateTps() = 0;
virtual const pid_state_s* getPidState() const = 0;
virtual const pid_state_s& getPidState() const = 0;
virtual void setLuaAdjustment(percent_t adjustment) = 0;
};

View File

@ -12,6 +12,8 @@ float luaAdjustment;"ETB: luaAdjustment"
float etbCurrentAdjustedTarget;;"%", 1, 0, -10000, 10000, 3
bit etbRevLimitActive
bit jamDetected
float etbDutyRateOfChange
float etbDutyAverage
uint16_t etbTpsErrorCounter;"ETB TPS error counter"
@ -19,4 +21,6 @@ float luaAdjustment;"ETB: luaAdjustment"
int8_t etbErrorCode
uint16_t autoscale jamTimer;ETB jam timer;"sec", 0.01, 0, 0, 100, 2
end_struct

View File

@ -34,7 +34,6 @@ public:
// Update the controller's state: read sensors, send output, etc
void update() override;
expected<percent_t> getOutput() override;
// Called when the configuration may have changed. Controller will
// reset if necessary.
@ -57,8 +56,10 @@ public:
void setOutput(expected<percent_t> outputValue) override;
void checkOutput(percent_t output);
// Used to inspect the internal PID controller's state
const pid_state_s* getPidState() const override { return &m_pid; };
const pid_state_s& getPidState() const override { return m_pid; };
// Use the throttle to automatically calibrate the relevant throttle position sensor(s).
void autoCalibrateTps() override;
@ -96,6 +97,8 @@ private:
ExpAverage m_dutyRocAverage;
ExpAverage m_dutyAverage;
Timer m_jamDetectTimer;
// Pedal -> target map
const ValueProvider3D* m_pedalMap = nullptr;

View File

@ -2147,6 +2147,12 @@ typedef enum {
CUSTOM_CAM_TOO_MANY_TEETH = 9004,
CUSTOM_CAM_NOT_ENOUGH_TEETH = 9005,
// Where we expected one trigger edge, we got two in quick succession
CUSTOM_PRIMARY_DOUBLED_EDGE = 9006,
// A trigger tooth arrived at an unexpected time
CUSTOM_PRIMARY_BAD_TOOTH_TIMING = 9007,
/**
* This is not engine miss detection - this is only internal scheduler state validation
* Should not happen

View File

@ -9,12 +9,15 @@
template <typename TInput, typename TOutput>
class ClosedLoopController {
public:
void update() {
expected<TOutput> update() {
expected<TOutput> outputValue = getOutput();
setOutput(outputValue);
return outputValue;
}
virtual expected<TOutput> getOutput() {
private:
expected<TOutput> getOutput() {
expected<TInput> setpoint = getSetpoint();
// If we don't know the setpoint, return failure.
if (!setpoint) {
@ -41,7 +44,6 @@ public:
return openLoopResult.Value + closedLoopResult.Value;
}
private:
// Get the setpoint: where should the controller put the plant?
virtual expected<TInput> getSetpoint() = 0;

View File

@ -139,10 +139,6 @@ bool warning(obd_code_e code, const char *fmt, ...) {
if (hasFirmwareErrorFlag)
return true;
#if EFI_SIMULATOR
printf("sim_warning %s\r\n", fmt);
#endif /* EFI_SIMULATOR */
#if EFI_SIMULATOR || EFI_PROD_CODE
// we just had this same warning, let's not spam
if (engine->engineState.warnings.isWarningNow(code) || !warningEnabled) {

View File

@ -2,5 +2,5 @@
// was generated automatically by rusEFI tool ConfigDefinition.jar based on gen_config.sh by SignatureConsumer
//
#define SIGNATURE_HASH snap_63942
#define TS_SIGNATURE "rusEFI 2023.01.10.48way.snap_63942"
#define SIGNATURE_HASH snap_22196
#define TS_SIGNATURE "rusEFI 2023.01.10.48way.snap_22196"

View File

@ -2,5 +2,5 @@
// was generated automatically by rusEFI tool ConfigDefinition.jar based on gen_config.sh by SignatureConsumer
//
#define SIGNATURE_HASH snap_61833
#define TS_SIGNATURE "rusEFI 2023.01.10.all.snap_61833"
#define SIGNATURE_HASH snap_24315
#define TS_SIGNATURE "rusEFI 2023.01.10.all.snap_24315"

View File

@ -2,5 +2,5 @@
// was generated automatically by rusEFI tool ConfigDefinition.jar based on gen_config.sh by SignatureConsumer
//
#define SIGNATURE_HASH snap_27877
#define TS_SIGNATURE "rusEFI 2023.01.10.alphax-2chan.snap_27877"
#define SIGNATURE_HASH snap_50071
#define TS_SIGNATURE "rusEFI 2023.01.10.alphax-2chan.snap_50071"

View File

@ -2,5 +2,5 @@
// was generated automatically by rusEFI tool ConfigDefinition.jar based on gen_config.sh by SignatureConsumer
//
#define SIGNATURE_HASH snap_57504
#define TS_SIGNATURE "rusEFI 2023.01.10.alphax-4chan.snap_57504"
#define SIGNATURE_HASH snap_20434
#define TS_SIGNATURE "rusEFI 2023.01.10.alphax-4chan.snap_20434"

View File

@ -2,5 +2,5 @@
// was generated automatically by rusEFI tool ConfigDefinition.jar based on gen_config.sh by SignatureConsumer
//
#define SIGNATURE_HASH snap_28165
#define TS_SIGNATURE "rusEFI 2023.01.10.alphax-8chan.snap_28165"
#define SIGNATURE_HASH snap_49527
#define TS_SIGNATURE "rusEFI 2023.01.10.alphax-8chan.snap_49527"

View File

@ -2,5 +2,5 @@
// was generated automatically by rusEFI tool ConfigDefinition.jar based on gen_config.sh by SignatureConsumer
//
#define SIGNATURE_HASH snap_1198
#define TS_SIGNATURE "rusEFI 2023.01.10.atlas.snap_1198"
#define SIGNATURE_HASH snap_43996
#define TS_SIGNATURE "rusEFI 2023.01.10.atlas.snap_43996"

View File

@ -2,5 +2,5 @@
// was generated automatically by rusEFI tool ConfigDefinition.jar based on gen_config.sh by SignatureConsumer
//
#define SIGNATURE_HASH snap_41072
#define TS_SIGNATURE "rusEFI 2023.01.10.core8.snap_41072"
#define SIGNATURE_HASH snap_3842
#define TS_SIGNATURE "rusEFI 2023.01.10.core8.snap_3842"

View File

@ -2,5 +2,5 @@
// was generated automatically by rusEFI tool ConfigDefinition.jar based on hellen_cypress_gen_config.bat by SignatureConsumer
//
#define SIGNATURE_HASH snap_61833
#define TS_SIGNATURE "rusEFI 2023.01.10.cypress.snap_61833"
#define SIGNATURE_HASH snap_24315
#define TS_SIGNATURE "rusEFI 2023.01.10.cypress.snap_24315"

View File

@ -2,5 +2,5 @@
// was generated automatically by rusEFI tool ConfigDefinition.jar based on gen_config.sh by SignatureConsumer
//
#define SIGNATURE_HASH snap_61833
#define TS_SIGNATURE "rusEFI 2023.01.10.f407-discovery.snap_61833"
#define SIGNATURE_HASH snap_24315
#define TS_SIGNATURE "rusEFI 2023.01.10.f407-discovery.snap_24315"

View File

@ -2,5 +2,5 @@
// was generated automatically by rusEFI tool ConfigDefinition.jar based on gen_config.sh by SignatureConsumer
//
#define SIGNATURE_HASH snap_61833
#define TS_SIGNATURE "rusEFI 2023.01.10.f429-discovery.snap_61833"
#define SIGNATURE_HASH snap_24315
#define TS_SIGNATURE "rusEFI 2023.01.10.f429-discovery.snap_24315"

View File

@ -2,5 +2,5 @@
// was generated automatically by rusEFI tool ConfigDefinition.jar based on gen_config.sh by SignatureConsumer
//
#define SIGNATURE_HASH snap_3405
#define TS_SIGNATURE "rusEFI 2023.01.10.frankenso_na6.snap_3405"
#define SIGNATURE_HASH snap_41535
#define TS_SIGNATURE "rusEFI 2023.01.10.frankenso_na6.snap_41535"

View File

@ -2,5 +2,5 @@
// was generated automatically by rusEFI tool ConfigDefinition.jar based on gen_config.sh by SignatureConsumer
//
#define SIGNATURE_HASH snap_46966
#define TS_SIGNATURE "rusEFI 2023.01.10.harley81.snap_46966"
#define SIGNATURE_HASH snap_6148
#define TS_SIGNATURE "rusEFI 2023.01.10.harley81.snap_6148"

View File

@ -2,5 +2,5 @@
// was generated automatically by rusEFI tool ConfigDefinition.jar based on gen_config.sh by SignatureConsumer
//
#define SIGNATURE_HASH snap_37517
#define TS_SIGNATURE "rusEFI 2023.01.10.hellen-gm-e67.snap_37517"
#define SIGNATURE_HASH snap_15871
#define TS_SIGNATURE "rusEFI 2023.01.10.hellen-gm-e67.snap_15871"

View File

@ -2,5 +2,5 @@
// was generated automatically by rusEFI tool ConfigDefinition.jar based on gen_config.sh by SignatureConsumer
//
#define SIGNATURE_HASH snap_49221
#define TS_SIGNATURE "rusEFI 2023.01.10.hellen-nb1.snap_49221"
#define SIGNATURE_HASH snap_28471
#define TS_SIGNATURE "rusEFI 2023.01.10.hellen-nb1.snap_28471"

View File

@ -2,5 +2,5 @@
// was generated automatically by rusEFI tool ConfigDefinition.jar based on gen_config.sh by SignatureConsumer
//
#define SIGNATURE_HASH snap_3099
#define TS_SIGNATURE "rusEFI 2023.01.10.hellen121nissan.snap_3099"
#define SIGNATURE_HASH snap_41833
#define TS_SIGNATURE "rusEFI 2023.01.10.hellen121nissan.snap_41833"

View File

@ -2,5 +2,5 @@
// was generated automatically by rusEFI tool ConfigDefinition.jar based on gen_config.sh by SignatureConsumer
//
#define SIGNATURE_HASH snap_26260
#define TS_SIGNATURE "rusEFI 2023.01.10.hellen121vag.snap_26260"
#define SIGNATURE_HASH snap_51686
#define TS_SIGNATURE "rusEFI 2023.01.10.hellen121vag.snap_51686"

View File

@ -2,5 +2,5 @@
// was generated automatically by rusEFI tool ConfigDefinition.jar based on gen_config.sh by SignatureConsumer
//
#define SIGNATURE_HASH snap_36018
#define TS_SIGNATURE "rusEFI 2023.01.10.hellen128.snap_36018"
#define SIGNATURE_HASH snap_9152
#define TS_SIGNATURE "rusEFI 2023.01.10.hellen128.snap_9152"

View File

@ -2,5 +2,5 @@
// was generated automatically by rusEFI tool ConfigDefinition.jar based on gen_config.sh by SignatureConsumer
//
#define SIGNATURE_HASH snap_52074
#define TS_SIGNATURE "rusEFI 2023.01.10.hellen154hyundai.snap_52074"
#define SIGNATURE_HASH snap_25624
#define TS_SIGNATURE "rusEFI 2023.01.10.hellen154hyundai.snap_25624"

View File

@ -2,5 +2,5 @@
// was generated automatically by rusEFI tool ConfigDefinition.jar based on gen_config.sh by SignatureConsumer
//
#define SIGNATURE_HASH snap_65282
#define TS_SIGNATURE "rusEFI 2023.01.10.hellen72.snap_65282"
#define SIGNATURE_HASH snap_20592
#define TS_SIGNATURE "rusEFI 2023.01.10.hellen72.snap_20592"

View File

@ -2,5 +2,5 @@
// was generated automatically by rusEFI tool ConfigDefinition.jar based on gen_config.sh by SignatureConsumer
//
#define SIGNATURE_HASH snap_28660
#define TS_SIGNATURE "rusEFI 2023.01.10.hellen81.snap_28660"
#define SIGNATURE_HASH snap_49286
#define TS_SIGNATURE "rusEFI 2023.01.10.hellen81.snap_49286"

View File

@ -2,5 +2,5 @@
// was generated automatically by rusEFI tool ConfigDefinition.jar based on gen_config.sh by SignatureConsumer
//
#define SIGNATURE_HASH snap_57925
#define TS_SIGNATURE "rusEFI 2023.01.10.hellen88bmw.snap_57925"
#define SIGNATURE_HASH snap_19767
#define TS_SIGNATURE "rusEFI 2023.01.10.hellen88bmw.snap_19767"

View File

@ -2,5 +2,5 @@
// was generated automatically by rusEFI tool ConfigDefinition.jar based on gen_config.sh by SignatureConsumer
//
#define SIGNATURE_HASH snap_16574
#define TS_SIGNATURE "rusEFI 2023.01.10.hellenNA6.snap_16574"
#define SIGNATURE_HASH snap_61388
#define TS_SIGNATURE "rusEFI 2023.01.10.hellenNA6.snap_61388"

View File

@ -2,5 +2,5 @@
// was generated automatically by rusEFI tool ConfigDefinition.jar based on gen_config.sh by SignatureConsumer
//
#define SIGNATURE_HASH snap_16481
#define TS_SIGNATURE "rusEFI 2023.01.10.hellenNA8_96.snap_16481"
#define SIGNATURE_HASH snap_61203
#define TS_SIGNATURE "rusEFI 2023.01.10.hellenNA8_96.snap_61203"

View File

@ -2,5 +2,5 @@
// was generated automatically by rusEFI tool ConfigDefinition.jar based on kinetis_gen_config.bat by SignatureConsumer
//
#define SIGNATURE_HASH snap_21317
#define TS_SIGNATURE "rusEFI 2023.01.10.kin.snap_21317"
#define SIGNATURE_HASH snap_64567
#define TS_SIGNATURE "rusEFI 2023.01.10.kin.snap_64567"

View File

@ -2,5 +2,5 @@
// was generated automatically by rusEFI tool ConfigDefinition.jar based on gen_config.sh by SignatureConsumer
//
#define SIGNATURE_HASH snap_11442
#define TS_SIGNATURE "rusEFI 2023.01.10.m74_9.snap_11442"
#define SIGNATURE_HASH snap_33728
#define TS_SIGNATURE "rusEFI 2023.01.10.m74_9.snap_33728"

View File

@ -2,5 +2,5 @@
// was generated automatically by rusEFI tool ConfigDefinition.jar based on gen_config.sh by SignatureConsumer
//
#define SIGNATURE_HASH snap_38537
#define TS_SIGNATURE "rusEFI 2023.01.10.mre_f4.snap_38537"
#define SIGNATURE_HASH snap_14843
#define TS_SIGNATURE "rusEFI 2023.01.10.mre_f4.snap_14843"

View File

@ -2,5 +2,5 @@
// was generated automatically by rusEFI tool ConfigDefinition.jar based on gen_config.sh by SignatureConsumer
//
#define SIGNATURE_HASH snap_38537
#define TS_SIGNATURE "rusEFI 2023.01.10.mre_f7.snap_38537"
#define SIGNATURE_HASH snap_14843
#define TS_SIGNATURE "rusEFI 2023.01.10.mre_f7.snap_14843"

View File

@ -2,5 +2,5 @@
// was generated automatically by rusEFI tool ConfigDefinition.jar based on gen_config.sh by SignatureConsumer
//
#define SIGNATURE_HASH snap_10351
#define TS_SIGNATURE "rusEFI 2023.01.10.prometheus_405.snap_10351"
#define SIGNATURE_HASH snap_34589
#define TS_SIGNATURE "rusEFI 2023.01.10.prometheus_405.snap_34589"

View File

@ -2,5 +2,5 @@
// was generated automatically by rusEFI tool ConfigDefinition.jar based on gen_config.sh by SignatureConsumer
//
#define SIGNATURE_HASH snap_10351
#define TS_SIGNATURE "rusEFI 2023.01.10.prometheus_469.snap_10351"
#define SIGNATURE_HASH snap_34589
#define TS_SIGNATURE "rusEFI 2023.01.10.prometheus_469.snap_34589"

View File

@ -2,5 +2,5 @@
// was generated automatically by rusEFI tool ConfigDefinition.jar based on gen_config.sh by SignatureConsumer
//
#define SIGNATURE_HASH snap_14905
#define TS_SIGNATURE "rusEFI 2023.01.10.proteus_f4.snap_14905"
#define SIGNATURE_HASH snap_38219
#define TS_SIGNATURE "rusEFI 2023.01.10.proteus_f4.snap_38219"

View File

@ -2,5 +2,5 @@
// was generated automatically by rusEFI tool ConfigDefinition.jar based on gen_config.sh by SignatureConsumer
//
#define SIGNATURE_HASH snap_14905
#define TS_SIGNATURE "rusEFI 2023.01.10.proteus_f7.snap_14905"
#define SIGNATURE_HASH snap_38219
#define TS_SIGNATURE "rusEFI 2023.01.10.proteus_f7.snap_38219"

View File

@ -2,5 +2,5 @@
// was generated automatically by rusEFI tool ConfigDefinition.jar based on gen_config.sh by SignatureConsumer
//
#define SIGNATURE_HASH snap_14905
#define TS_SIGNATURE "rusEFI 2023.01.10.proteus_h7.snap_14905"
#define SIGNATURE_HASH snap_38219
#define TS_SIGNATURE "rusEFI 2023.01.10.proteus_h7.snap_38219"

View File

@ -2,5 +2,5 @@
// was generated automatically by rusEFI tool ConfigDefinition.jar based on gen_config.sh by SignatureConsumer
//
#define SIGNATURE_HASH snap_50164
#define TS_SIGNATURE "rusEFI 2023.01.10.s105.snap_50164"
#define SIGNATURE_HASH snap_27782
#define TS_SIGNATURE "rusEFI 2023.01.10.s105.snap_27782"

View File

@ -2,5 +2,5 @@
// was generated automatically by rusEFI tool ConfigDefinition.jar based on config/boards/subaru_eg33/config/gen_subaru_config.sh by SignatureConsumer
//
#define SIGNATURE_HASH snap_10323
#define TS_SIGNATURE "rusEFI 2023.01.10.subaru_eg33_f7.snap_10323"
#define SIGNATURE_HASH snap_34593
#define TS_SIGNATURE "rusEFI 2023.01.10.subaru_eg33_f7.snap_34593"

View File

@ -2,5 +2,5 @@
// was generated automatically by rusEFI tool ConfigDefinition.jar based on gen_config.sh by SignatureConsumer
//
#define SIGNATURE_HASH snap_16349
#define TS_SIGNATURE "rusEFI 2023.01.10.tdg-pdm8.snap_16349"
#define SIGNATURE_HASH snap_37039
#define TS_SIGNATURE "rusEFI 2023.01.10.tdg-pdm8.snap_37039"

View File

@ -85,8 +85,8 @@ float getConfigValueByName(const char *name) {
return engineConfiguration->verboseCan;
case -1528619572:
return engineConfiguration->artificialTestMisfire;
case -1571463185:
return engineConfiguration->issue_294_31;
case -1284359115:
return engineConfiguration->useFordRedundantPps;
case 513872736:
return engineConfiguration->tpsMin;
case 513872482:
@ -1041,6 +1041,10 @@ float getConfigValueByName(const char *name) {
return engineConfiguration->ALSSkipRatio;
case 612659807:
return engineConfiguration->ALSMaxDriverThrottleIntent;
case -1744146782:
return engineConfiguration->tpsSecondaryMaximum;
case -727657058:
return engineConfiguration->ppsSecondaryMaximum;
}
return EFI_ERROR_CODE;
}
@ -1252,9 +1256,9 @@ void setConfigValueByName(const char *name, float value) {
engineConfiguration->artificialTestMisfire = (int)value;
return;
}
case -1571463185:
case -1284359115:
{
engineConfiguration->issue_294_31 = (int)value;
engineConfiguration->useFordRedundantPps = (int)value;
return;
}
case 513872736:
@ -3641,6 +3645,16 @@ void setConfigValueByName(const char *name, float value) {
{
engineConfiguration->ALSMaxDriverThrottleIntent = (int)value;
return;
}
case -1744146782:
{
engineConfiguration->tpsSecondaryMaximum = (int)value;
return;
}
case -727657058:
{
engineConfiguration->ppsSecondaryMaximum = (int)value;
return;
}
}
}

View File

@ -35,7 +35,7 @@ This is your injector flow at the fuel pressure used in the vehicle. cc/min, cub
Does the vehicle have a turbo or supercharger?
### useFordRedundantTps
On Ford vehicles one of the sensors is not linear on the full range, i.e. in the specific range of the positions we effectively have only one sensor.
On some Ford and Toyota vehicles one of the throttle sensors is not linear on the full range, i.e. in the specific range of the positions we effectively have only one sensor.
### isVerboseAuxPid1
@ -121,8 +121,8 @@ Print incoming and outgoing first bus CAN messages in rusEFI console
### artificialTestMisfire
Experimental setting that will cause a misfire\nDO NOT ENABLE.
### issue_294_31
### useFordRedundantPps
On some Ford and Toyota vehicles one of the pedal sensors is not linear on the full range, i.e. in the specific range of the positions we effectively have only one sensor.
### tpsMin
Closed throttle, 1 volt = 200 units.\nSee also tps1_1AdcChannel\nset tps_min X
@ -1555,3 +1555,9 @@ null
### ALSMaxDriverThrottleIntent
### tpsSecondaryMaximum
For Ford TPS, use 53%. For Toyota ETCS-i, use 65%
### ppsSecondaryMaximum
For Toyota ETCS-i, use xxx%

View File

@ -639,6 +639,64 @@ void TriggerCentral::decodeMapCam(efitick_t timestamp, float currentPhase) {
}
}
bool TriggerCentral::isToothExpectedNow(efitick_t timestamp) {
// Check that the expected next phase (from the last tooth) is close to the actual current phase:
// basically, check that the tooth width is correct
auto estimatedCurrentPhase = getCurrentEnginePhase(timestamp);
auto lastToothPhase = m_lastToothPhaseFromSyncPoint;
if (expectedNextPhase && estimatedCurrentPhase) {
float angleError = expectedNextPhase.Value - estimatedCurrentPhase.Value;
// Wrap around correctly at the end of the cycle
float cycle = getEngineState()->engineCycle;
if (angleError < -cycle / 2) {
angleError += cycle;
}
triggerToothAngleError = angleError;
// Only perform checks if engine is spinning quickly
// All kinds of garbage happens while cranking
if (Sensor::getOrZero(SensorType::Rpm) > 1000) {
// Now compute how close we are to the last tooth decoded
float angleSinceLastTooth = estimatedCurrentPhase.Value - lastToothPhase;
if (angleSinceLastTooth < 0.5f) {
// This tooth came impossibly early, ignore it
// This rejects things like doubled edges, for example:
// |-| |----------------
// | | |
// ____________| |_|
// 1 2
// #1 will be decoded
// #2 will be ignored
// We're not sure which edge was the "real" one, but they were close enough
// together that it doesn't really matter.
warning(CUSTOM_PRIMARY_DOUBLED_EDGE, "doubled trigger edge after %.2f deg at #%d", angleSinceLastTooth, triggerState.currentCycle.current_index);
return false;
}
// Absolute error from last tooth
float absError = absF(angleError);
float isRpmEnough = Sensor::getOrZero(SensorType::Rpm) > 1000;
// TODO: configurable threshold
if (isRpmEnough && absError > 10 && absError < 180) {
// This tooth came at a very unexpected time, ignore it
warning(CUSTOM_PRIMARY_BAD_TOOTH_TIMING, "tooth #%d error of %.1f", triggerState.currentCycle.current_index, angleError);
// TODO: this causes issues with some real engine logs, should it?
// return false;
}
}
} else {
triggerToothAngleError = 0;
}
// We aren't ready to reject unexpected teeth, so accept this tooth
return true;
}
/**
* This method is NOT invoked for VR falls.
*/
@ -661,6 +719,11 @@ void TriggerCentral::handleShaftSignal(trigger_event_e signal, efitick_t timesta
}
}
if (!isToothExpectedNow(timestamp)) {
triggerIgnoredToothCount++;
return;
}
isSpinningJustForWatchdog = true;
m_lastEventTimer.reset(timestamp);
@ -697,20 +760,6 @@ void TriggerCentral::handleShaftSignal(trigger_event_e signal, efitick_t timesta
// Adjust so currentPhase is in engine-space angle, not trigger-space angle
currentEngineDecodedPhase = wrapAngleMethod(currentPhaseFromSyncPoint - tdcPosition(), "currentEnginePhase", CUSTOM_ERR_6555);
// Check that the expected next phase (from the last tooth) is close to the actual current phase:
// basically, check that the tooth width is correct
auto estimatedCurrentPhase = getCurrentEnginePhase(timestamp);
if (estimatedCurrentPhase) {
float angleError = expectedNextPhase - estimatedCurrentPhase.Value;
float cycle = getEngineState()->engineCycle;
while (angleError < -cycle / 2) {
angleError += cycle;
}
triggerToothAngleError = angleError;
}
// Record precise time and phase of the engine. This is used for VVT decode, and to check that the
// trigger pattern selected matches reality (ie, we check the next tooth is where we think it should be)
{
@ -752,19 +801,20 @@ void TriggerCentral::handleShaftSignal(trigger_event_e signal, efitick_t timesta
wrapAngle(nextPhase, "nextEnginePhase", CUSTOM_ERR_6555);
} while (nextPhase == currentEngineDecodedPhase);
expectedNextPhase = nextPhase + tdcPosition();
wrapAngle(expectedNextPhase, "nextEnginePhase", CUSTOM_ERR_6555);
float expectNextPhase = nextPhase + tdcPosition();
wrapAngle(expectNextPhase, "nextEnginePhase", CUSTOM_ERR_6555);
expectedNextPhase = expectNextPhase;
#if EFI_CDM_INTEGRATION
if (trgEventIndex == 0 && isBrainPinValid(engineConfiguration->cdmInputPin)) {
int cdmKnockValue = getCurrentCdmValue(getTriggerCentral()->triggerState.getCrankSynchronizationCounter());
engine->knockLogic(cdmKnockValue);
}
if (trgEventIndex == 0 && isBrainPinValid(engineConfiguration->cdmInputPin)) {
int cdmKnockValue = getCurrentCdmValue(getTriggerCentral()->triggerState.getCrankSynchronizationCounter());
engine->knockLogic(cdmKnockValue);
}
#endif /* EFI_CDM_INTEGRATION */
if (engine->rpmCalculator.getCachedRpm() > 0 && triggerIndexForListeners == 0) {
engine->tpsAccelEnrichment.onEngineCycleTps();
}
if (engine->rpmCalculator.getCachedRpm() > 0 && triggerIndexForListeners == 0) {
engine->tpsAccelEnrichment.onEngineCycleTps();
}
// Handle ignition and injection
mainTriggerCallback(triggerIndexForListeners, timestamp, currentEngineDecodedPhase, nextPhase);
@ -774,6 +824,8 @@ void TriggerCentral::handleShaftSignal(trigger_event_e signal, efitick_t timesta
} else {
// We don't have sync, but report to the wave chart anyway as index 0.
reportEventToWaveChart(signal, 0, triggerShape.useOnlyRisingEdges);
expectedNextPhase = unexpected;
}
}

View File

@ -199,6 +199,8 @@ public:
private:
void decodeMapCam(efitick_t nowNt, float currentPhase);
bool isToothExpectedNow(efitick_t timestamp);
// Time since the last tooth
Timer m_lastToothTimer;
// Phase of the last tooth relative to the sync point
@ -206,7 +208,7 @@ private:
// At what engine phase do we expect the next tooth to arrive?
// Used for checking whether your trigger pattern is correct.
float expectedNextPhase;
expected<float> expectedNextPhase = unexpected;
};
void triggerInfo(void);

View File

@ -15,5 +15,7 @@ uint32_t vvtCamCounter
float triggerToothAngleError;;"deg", 1, 0, -30, 30, 2
uint8_t triggerIgnoredToothCount
end_struct

View File

@ -41,7 +41,7 @@ public:
return m_sens.Register();
}
void unsubscribe() {
void deinit() {
AdcSubscription::UnsubscribeSensor(m_sens);
}
@ -101,7 +101,7 @@ public:
{
}
void init(bool isFordTps, RedundantFordTps* fordTps, const TpsConfig& primary, const TpsConfig& secondary) {
void init(bool isFordTps, RedundantFordTps* fordTps, float secondaryMaximum, const TpsConfig& primary, const TpsConfig& secondary) {
bool hasFirst = m_pri.init(primary);
if (!hasFirst) {
// no input if we have no first channel
@ -125,7 +125,7 @@ public:
if (isFordTps && fordTps) {
// we have a secondary
fordTps->configure(5.0f, 52.6f);
fordTps->configure(MAX_TPS_PPS_DISCREPANCY, secondaryMaximum);
fordTps->Register();
} else {
// not ford TPS
@ -137,9 +137,16 @@ printf("init m_redund.Register() %s\n", getSensorType(m_redund.type()));
}
}
void unsubscribe() {
m_pri.unsubscribe();
m_sec.unsubscribe();
void deinit(bool isFordTps, RedundantFordTps* fordTps) {
m_pri.deinit();
m_sec.deinit();
if (isFordTps && fordTps) {
fordTps->unregister();
} else {
m_redund.unregister();
}
}
private:
@ -161,6 +168,7 @@ static RedundantPair tps2(tps2p, tps2s, SensorType::Tps2);
// Used only in case of weird Ford-style ETB TPS
static RedundantFordTps fordTps1(SensorType::Tps1, SensorType::Tps1Primary, SensorType::Tps1Secondary);
static RedundantFordTps fordTps2(SensorType::Tps2, SensorType::Tps2Primary, SensorType::Tps2Secondary);
static RedundantFordTps fordPps(SensorType::AcceleratorPedal, SensorType::AcceleratorPedalPrimary, SensorType::AcceleratorPedalSecondary);
// Pedal sensors and redundancy
static FuncSensPair pedalPrimary(1, SensorType::AcceleratorPedalPrimary);
@ -181,19 +189,32 @@ void initTps() {
if (!engineConfiguration->consumeObdSensors) {
bool isFordTps = engineConfiguration->useFordRedundantTps;
bool isFordPps = engineConfiguration->useFordRedundantPps;
tps1.init(isFordTps, &fordTps1,
float tpsSecondaryMaximum = engineConfiguration->tpsSecondaryMaximum;
if (tpsSecondaryMaximum < 20) {
// don't allow <20% split point
tpsSecondaryMaximum = 20;
}
tps1.init(isFordTps, &fordTps1, tpsSecondaryMaximum,
{ engineConfiguration->tps1_1AdcChannel, (float)engineConfiguration->tpsMin, (float)engineConfiguration->tpsMax, min, max },
{ engineConfiguration->tps1_2AdcChannel, (float)engineConfiguration->tps1SecondaryMin, (float)engineConfiguration->tps1SecondaryMax, min, max }
);
tps2.init(isFordTps, &fordTps2,
tps2.init(isFordTps, &fordTps2, tpsSecondaryMaximum,
{ engineConfiguration->tps2_1AdcChannel, (float)engineConfiguration->tps2Min, (float)engineConfiguration->tps2Max, min, max },
{ engineConfiguration->tps2_2AdcChannel, (float)engineConfiguration->tps2SecondaryMin, (float)engineConfiguration->tps2SecondaryMax, min, max }
);
float ppsSecondaryMaximum = engineConfiguration->ppsSecondaryMaximum;
if (ppsSecondaryMaximum < 20) {
// don't allow <20% split point
ppsSecondaryMaximum = 20;
}
// Pedal sensors
pedal.init(false, nullptr,
pedal.init(isFordPps, &fordPps, ppsSecondaryMaximum,
{ engineConfiguration->throttlePedalPositionAdcChannel, engineConfiguration->throttlePedalUpVoltage, engineConfiguration->throttlePedalWOTVoltage, min, max },
{ engineConfiguration->throttlePedalPositionSecondAdcChannel, engineConfiguration->throttlePedalSecondaryUpVoltage, engineConfiguration->throttlePedalSecondaryWOTVoltage, min, max }
);
@ -214,10 +235,13 @@ void initTps() {
}
void deinitTps() {
tps1.unsubscribe();
tps2.unsubscribe();
pedal.unsubscribe();
bool isFordTps = activeConfiguration.useFordRedundantTps;
bool isFordPps = activeConfiguration.useFordRedundantPps;
wastegate.unsubscribe();
idlePos.unsubscribe();
tps1.deinit(isFordTps, &fordTps1);
tps2.deinit(isFordTps, &fordTps2);
pedal.deinit(isFordTps, &fordPps);
wastegate.deinit();
idlePos.deinit();
}

View File

@ -446,7 +446,7 @@ end_struct
injector_s injector
bit isForcedInduction;Does the vehicle have a turbo or supercharger?
bit useFordRedundantTps;On Ford vehicles one of the sensors is not linear on the full range, i.e. in the specific range of the positions we effectively have only one sensor.
bit useFordRedundantTps;On some Ford and Toyota vehicles one of the throttle sensors is not linear on the full range, i.e. in the specific range of the positions we effectively have only one sensor.
bit isVerboseAuxPid1
bit overrideTriggerGaps
bit enableFan1WithAc;Turn on this fan when AC is on.
@ -475,7 +475,7 @@ bit enableMapEstimationTableFallback;If enabled, the MAP estimate table will be
bit usescriptTableForCanSniffingFiltering
bit verboseCan,"Print all","Do not print";Print incoming and outgoing first bus CAN messages in rusEFI console
bit artificialTestMisfire,"Danger Mode","No thank you";Experimental setting that will cause a misfire\nDO NOT ENABLE.
bit issue_294_31,"si_example","nada_example"
bit useFordRedundantPps;On some Ford and Toyota vehicles one of the pedal sensors is not linear on the full range, i.e. in the specific range of the positions we effectively have only one sensor.
!todo: extract these two fields into a structure
@ -1560,7 +1560,8 @@ uint8_t alsEtbPosition;;"", 1, 0, 0, 20000, 0
uint8_t ALSMaxDriverThrottleIntent;;"%", 1, 0, 0, 10, 0
pin_input_mode_e ALSActivatePinMode;
uint8_t[2] unusedHereForYou
uint8_t autoscale tpsSecondaryMaximum;For Ford TPS, use 53%. For Toyota ETCS-i, use 65%;"%", 0.5, 0, 0, 100, 1
uint8_t autoscale ppsSecondaryMaximum;For Toyota ETCS-i, use xxx%;"%", 0.5, 0, 0, 100, 1
pin_input_mode_e[LUA_DIGITAL_INPUT_COUNT iterate] luaDigitalInputPinModes;
uint8_t[96] mainUnusedEnd;;"units", 1, 0, 0, 1, 0

View File

@ -4294,6 +4294,10 @@ dialog = tcuControls, "Transmission Settings"
field = "showHumanReadableWarning (affects Burn)", showHumanReadableWarning
field = "Warning Message", warning_message
field = "Ford redundant TPS mode", useFordRedundantTps
field = "Secondary TPS maximum", tpsSecondaryMaximum, {useFordRedundantTps}
field = "Ford redundant PPS mode", useFordRedundantPps
field = "Secondary PPS maximum", ppsSecondaryMaximum, {useFordRedundantPps}
field = "consumeObdSensors", consumeObdSensors, { canReadEnabled == 1 && canWriteEnabled == 1}
field = "Artificial Misfire", artificialTestMisfire
field = "Always use instant RPM", alwaysInstantRpm

3
misc/tooth_log_converter/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
*.teeth
*.csv
log_convert

View File

@ -0,0 +1,3 @@
#!/bin/bash
g++ -O2 -lstdc++ log_convert.cpp -o log_convert

View File

@ -0,0 +1,46 @@
#include <iostream>
#include <fstream>
#include <iomanip>
typedef struct __attribute__ ((packed)) {
// the whole order of all packet bytes is reversed, not just the 'endian-swap' integers
uint32_t timestamp;
// unfortunately all these fields are required by TS...
bool priLevel : 1;
bool secLevel : 1;
bool trigger : 1;
bool sync : 1;
bool coil : 1;
bool injector : 1;
} composite_logger_s;
static_assert(sizeof(composite_logger_s) == 5);
static inline uint32_t SWAP_UINT32(uint32_t x)
{
return (((x >> 24) & 0x000000ff) | ((x << 8) & 0x00ff0000) |
((x >> 8) & 0x0000ff00) | ((x << 24) & 0xff000000));
}
static constexpr double ticksPerSecond = 1e6;
int main(int argc, char** argv)
{
std::ifstream src(argv[1], std::ios::binary);
std::ofstream dst(argv[2], std::ios::binary);
dst << std::setprecision(10);
dst << "timestamp,pri,sec" << std::endl;
while (!src.eof())
{
composite_logger_s entry;
src.read(reinterpret_cast<char*>(&entry), sizeof(composite_logger_s));
double sec = SWAP_UINT32(entry.timestamp) / ticksPerSecond;
dst << sec << "," << entry.priLevel << "," << entry.secLevel << std::endl;
}
}

View File

@ -0,0 +1,11 @@
# SD Tooth Log Converter
This program converts SD stored tooth logs to csv for analysis or replay as part of a unit test.
Create a log by setting "SD logger mode" to "trigger", then restart the ECU with an SD card present (but without USB connected), then crank/run/etc the engine to save a log. Restart again with USB to pull the log off.
# Usage
`./build.sh`
`./log_convert myToothLog.teeth convertedCsv.csv`

View File

@ -25,12 +25,11 @@ public:
MOCK_METHOD(void, setIdlePosition, (percent_t pos), (override));
MOCK_METHOD(void, setWastegatePosition, (percent_t pos), (override));
MOCK_METHOD(void, autoCalibrateTps, (), (override));
MOCK_METHOD(const pid_state_s*, getPidState, (), (const, override));
MOCK_METHOD(const pid_state_s&, getPidState, (), (const, override));
MOCK_METHOD(void, setLuaAdjustment, (percent_t adjustment), (override));
// ClosedLoopController mocks
MOCK_METHOD(expected<percent_t>, getOutput, (), (override));
MOCK_METHOD(expected<percent_t>, getSetpoint, (), (override));
MOCK_METHOD(expected<percent_t>, observePlant, (), (const, override));
MOCK_METHOD(expected<percent_t>, getOpenLoop, (percent_t setpoint), (override));

View File

@ -198,7 +198,6 @@ TEST(etb, initializationNoPrimarySensor) {
Sensor::resetAllMocks();
EtbController dut;
EngineTestHelper eth(TEST_ENGINE);
// Needs pedal for init
Sensor::setMockValue(SensorType::AcceleratorPedal, 0.0f, true);
@ -470,7 +469,6 @@ TEST(etb, setpointNoPedalMap) {
}
TEST(etb, setpointIdleValveController) {
EngineTestHelper eth(TEST_ENGINE);
EtbController etb;
etb.init(ETB_IdleValve, nullptr, nullptr, nullptr, false);
@ -490,7 +488,6 @@ TEST(etb, setpointIdleValveController) {
}
TEST(etb, setpointWastegateController) {
EngineTestHelper eth(TEST_ENGINE);
EtbController etb;
etb.init(ETB_Wastegate, nullptr, nullptr, nullptr, false);
@ -561,10 +558,6 @@ TEST(etb, setpointLuaAdder) {
}
TEST(etb, etbTpsSensor) {
static engine_configuration_s localConfig;
// huh? how is this breaking the test? EngineTestHelper eth(TEST_ENGINE);
engineConfiguration = &localConfig;
// Throw some distinct values on the TPS sensors so we can identify that we're getting the correct one
Sensor::setMockValue(SensorType::Tps1, 25.0f, true);
Sensor::setMockValue(SensorType::Tps2, 75.0f, true);
@ -601,7 +594,6 @@ TEST(etb, etbTpsSensor) {
etb.init(ETB_IdleValve, nullptr, nullptr, nullptr, true);
EXPECT_EQ(etb.observePlant().Value, 66.0f);
}
engineConfiguration = nullptr;
}
TEST(etb, setOutputInvalid) {
@ -746,9 +738,6 @@ TEST(etb, setOutputLimpHome) {
}
TEST(etb, closedLoopPid) {
static engine_configuration_s localConfig;
// huh? how is this breaking the test? EngineTestHelper eth(TEST_ENGINE);
engineConfiguration = &localConfig;
pid_s pid = {};
pid.pFactor = 5;
pid.maxValue = 75;
@ -762,8 +751,6 @@ TEST(etb, closedLoopPid) {
EtbController etb;
etb.init(ETB_Throttle1, nullptr, &pid, nullptr, true);
// todo: second part dirty hack :(
engineConfiguration = nullptr;
// Disable autotune for now
Engine e;
EngineTestHelperBase base(&e, nullptr, nullptr);
@ -779,6 +766,59 @@ TEST(etb, closedLoopPid) {
EXPECT_FLOAT_EQ(etb.getClosedLoop(50, 30).value_or(-1), 75);
}
extern int timeNowUs;
TEST(etb, jamDetection) {
EngineTestHelper eth(TEST_ENGINE);
pid_s pid = {};
// I-only since we're testing out the integrator
pid.pFactor = 0;
pid.iFactor = 1;
pid.dFactor = 0;
pid.maxValue = 50;
pid.minValue = -50;
// Must have TPS & PPS initialized for ETB setup
Sensor::setMockValue(SensorType::Tps1Primary, 0);
Sensor::setMockValue(SensorType::Tps1, 0.0f, true);
Sensor::setMockValue(SensorType::AcceleratorPedal, 0.0f, true);
// Limit of 5%, 1 second
engineConfiguration->etbJamIntegratorLimit = 5;
engineConfiguration->etbJamTimeout = 1;
EtbController etb;
etb.init(ETB_Throttle1, nullptr, &pid, nullptr, true);
timeNowUs = 0;
// Reset timer while under integrator limit
EXPECT_EQ(etb.getPidState().iTerm, 0);
etb.checkOutput(0);
EXPECT_EQ(etb.jamTimer, 0);
EXPECT_FALSE(etb.jamDetected);
for (size_t i = 0; i < ETB_LOOP_FREQUENCY; i++) {
// Error of 10, should accumulate 10 integrator per second
etb.getClosedLoop(50, 40);
}
EXPECT_NEAR(etb.getPidState().iTerm, 10.0f, 1e-3);
// Just under time limit, no jam yet
timeNowUs = 0.9e6;
etb.checkOutput(0);
EXPECT_NEAR(etb.jamTimer, 0.9f, 1e-3);
EXPECT_FALSE(etb.jamDetected);
// Above the time limit, jam detected!
timeNowUs = 1.1e6;
etb.checkOutput(0);
EXPECT_TRUE(etb.jamDetected);
}
TEST(etb, openLoopThrottle) {
EngineTestHelper eth(TEST_ENGINE);

File diff suppressed because it is too large Load Diff

View File

@ -40,3 +40,37 @@ TEST(real4b11, running) {
ASSERT_EQ(0, eth.recentWarnings()->getCount());
}
TEST(real4b11, runningDoubledEdge) {
CsvReader reader(1, /* vvtCount */ 0);
// This log has an extra duplicate edge at 5.393782 seconds (hand added)
reader.open("tests/trigger/resources/4b11-running-doubled-edge.csv");
EngineTestHelper eth(TEST_ENGINE);
engineConfiguration->isFasterEngineSpinUpEnabled = true;
engineConfiguration->alwaysInstantRpm = true;
eth.setTriggerType(TT_36_2_1);
int eventCount = 0;
bool gotRpm = false;
while (reader.haveMore()) {
reader.processLine(&eth);
eventCount++;
engine->rpmCalculator.onSlowCallback();
auto rpm = Sensor::getOrZero(SensorType::Rpm);
if (!gotRpm && rpm) {
gotRpm = true;
// We should get first RPM on exactly the first sync point - this means the instant RPM pre-sync event copy all worked OK
EXPECT_EQ(eventCount, 30);
EXPECT_NEAR(rpm, 1436.23f, 0.1);
}
}
// Should get a warning for the doubled edge, but NOT one for a trigger error!
ASSERT_EQ(1, eth.recentWarnings()->getCount());
ASSERT_EQ(CUSTOM_PRIMARY_DOUBLED_EDGE, eth.recentWarnings()->get(0).Code);
}