rusefi-1/firmware/controllers/core/fsio_impl.cpp

700 lines
22 KiB
C++
Raw Normal View History

2015-07-10 06:01:56 -07:00
/**
* @file fsio_impl.cpp
* @brief FSIO as it's used for GPIO
*
2017-12-17 09:02:35 -08:00
* set debug_mode 23
* https://rusefi.com/wiki/index.php?title=Manual:Flexible_Logic
*
2019-09-11 17:46:50 -07:00
* 'fsioinfo' command in console shows current state of FSIO - formulas and current value
*
2015-07-10 06:01:56 -07:00
* @date Oct 5, 2014
2020-01-07 21:02:40 -08:00
* @author Andrey Belomutskiy, (c) 2012-2020
2015-07-10 06:01:56 -07:00
*/
#include "pch.h"
#include "fsio_impl.h"
2015-07-10 06:01:56 -07:00
#if EFI_PROD_CODE
// todo: that's about bench test mode, wrong header for sure!
#include "bench_test.h"
#endif // EFI_PROD_CODE
2019-04-12 19:07:03 -07:00
#if EFI_FSIO
2015-07-10 06:01:56 -07:00
#include "os_access.h"
2015-07-10 06:01:56 -07:00
2017-07-14 18:35:38 -07:00
/**
* in case of zero frequency pin is operating as simple on/off. '1' for ON and '0' for OFF
*
*/
2015-07-10 06:01:56 -07:00
#define NO_PWM 0
static fsio8_Map3D_f32t fsioTable1;
static fsio8_Map3D_u8t fsioTable2;
static fsio8_Map3D_u8t fsioTable3;
static fsio8_Map3D_u8t fsioTable4;
2016-04-04 07:01:43 -07:00
2015-07-10 06:01:56 -07:00
/**
* Here we define all rusEfi-specific methods
*/
static LENameOrdinalPair leRpm(LE_METHOD_RPM, "rpm");
static LENameOrdinalPair leTps(LE_METHOD_TPS, "tps");
static LENameOrdinalPair lePps(LE_METHOD_PPS, "pps");
2015-07-10 06:01:56 -07:00
static LENameOrdinalPair leMaf(LE_METHOD_MAF, "maf");
2016-07-07 20:01:43 -07:00
static LENameOrdinalPair leMap(LE_METHOD_MAP, "map");
2015-07-10 06:01:56 -07:00
static LENameOrdinalPair leVBatt(LE_METHOD_VBATT, "vbatt");
static LENameOrdinalPair leFan(LE_METHOD_FAN, "fan");
static LENameOrdinalPair leCoolant(LE_METHOD_COOLANT, "coolant");
2020-10-04 18:33:54 -07:00
static LENameOrdinalPair leIntakeTemp(LE_METHOD_INTAKE_AIR, "iat");
2017-06-04 12:00:19 -07:00
static LENameOrdinalPair leIsCoolantBroken(LE_METHOD_IS_COOLANT_BROKEN, "is_clt_broken");
static LENameOrdinalPair leOilPressure(LE_METHOD_OIL_PRESSURE, "oilp");
2019-09-11 17:46:50 -07:00
// @returns boolean state of A/C toggle switch
2015-07-10 06:01:56 -07:00
static LENameOrdinalPair leAcToggle(LE_METHOD_AC_TOGGLE, "ac_on_switch");
2019-09-11 17:46:50 -07:00
// @returns float number of seconds since last A/C toggle
2019-09-08 18:09:45 -07:00
static LENameOrdinalPair leTimeSinceAcToggle(LE_METHOD_TIME_SINCE_AC_TOGGLE, "time_since_ac_on_switch");
2015-07-10 06:01:56 -07:00
static LENameOrdinalPair leTimeSinceBoot(LE_METHOD_TIME_SINCE_BOOT, "time_since_boot");
2020-04-18 18:01:23 -07:00
static LENameOrdinalPair leFsioSetting(LE_METHOD_FSIO_SETTING, FSIO_METHOD_FSIO_SETTING);
static LENameOrdinalPair leFsioTable(LE_METHOD_FSIO_TABLE, FSIO_METHOD_FSIO_TABLE);
static LENameOrdinalPair leFsioAnalogInput(LE_METHOD_FSIO_ANALOG_INPUT, FSIO_METHOD_FSIO_ANALOG_INPUT);
static LENameOrdinalPair leFsioDigitalInput(LE_METHOD_FSIO_DIGITAL_INPUT, FSIO_METHOD_FSIO_DIGITAL_INPUT);
2016-12-17 09:03:02 -08:00
static LENameOrdinalPair leIntakeVVT(LE_METHOD_INTAKE_VVT, "ivvt");
static LENameOrdinalPair leExhaustVVT(LE_METHOD_EXHAUST_VVT, "evvt");
2017-06-14 02:39:00 -07:00
static LENameOrdinalPair leCrankingRpm(LE_METHOD_CRANKING_RPM, "cranking_rpm");
static LENameOrdinalPair leStartupFuelPumpDuration(LE_METHOD_STARTUP_FUEL_PUMP_DURATION, "startup_fuel_pump_duration");
static LENameOrdinalPair leInShutdown(LE_METHOD_IN_SHUTDOWN, "in_shutdown");
2021-01-10 20:46:50 -08:00
static LENameOrdinalPair leInMrBench(LE_METHOD_IN_MR_BENCH, "in_mr_bench");
static LENameOrdinalPair leTimeSinceTrigger(LE_METHOD_TIME_SINCE_TRIGGER_EVENT, "time_since_trigger");
static LENameOrdinalPair leFuelRate(LE_METHOD_FUEL_FLOW_RATE, "fuel_flow");
2015-07-10 06:01:56 -07:00
2019-09-11 16:30:36 -07:00
#include "fsio_names.def"
2021-08-18 12:25:46 -07:00
#define SYS_ELEMENT_POOL_SIZE 24
#define UD_ELEMENT_POOL_SIZE 64
2015-07-10 06:01:56 -07:00
2017-01-06 08:02:49 -08:00
static LEElement sysElements[SYS_ELEMENT_POOL_SIZE] CCM_OPTIONAL;
CCM_OPTIONAL LEElementPool sysPool(sysElements, SYS_ELEMENT_POOL_SIZE);
2015-07-10 06:01:56 -07:00
2017-01-06 08:02:49 -08:00
static LEElement userElements[UD_ELEMENT_POOL_SIZE] CCM_OPTIONAL;
CCM_OPTIONAL LEElementPool userPool(userElements, UD_ELEMENT_POOL_SIZE);
class FsioPointers {
public:
FsioPointers();
LEElement * fsioLogics[FSIO_COMMAND_COUNT];
};
FsioPointers::FsioPointers() : fsioLogics() {
}
static FsioPointers state;
2015-07-10 06:01:56 -07:00
static LEElement * fuelPumpLogic;
2020-03-18 13:32:03 -07:00
static LEElement * starterRelayDisableLogic;
2015-07-10 06:01:56 -07:00
2019-04-12 19:07:03 -07:00
#if EFI_MAIN_RELAY_CONTROL
2017-06-12 15:14:39 -07:00
static LEElement * mainRelayLogic;
#endif /* EFI_MAIN_RELAY_CONTROL */
2018-12-24 05:37:25 -08:00
#if EFI_PROD_CODE || EFI_SIMULATOR
2015-07-10 06:01:56 -07:00
FsioResult getEngineValue(le_action_e action DECLARE_ENGINE_PARAMETER_SUFFIX) {
efiAssert(CUSTOM_ERR_ASSERT, engine!=NULL, "getLEValue", unexpected);
2015-07-10 06:01:56 -07:00
switch (action) {
case LE_METHOD_FAN:
return enginePins.fanRelay.getLogicValue();
2019-09-08 18:05:03 -07:00
case LE_METHOD_TIME_SINCE_AC_TOGGLE:
return (getTimeNowUs() - engine->acSwitchLastChangeTime) / US_PER_SECOND_F;
2015-07-10 06:01:56 -07:00
case LE_METHOD_AC_TOGGLE:
2017-05-15 20:28:49 -07:00
return getAcToggle(PASS_ENGINE_PARAMETER_SIGNATURE);
2015-07-10 06:01:56 -07:00
case LE_METHOD_COOLANT:
2021-10-05 16:59:07 -07:00
return Sensor::getOrZero(SensorType::Clt);
2017-06-04 12:00:19 -07:00
case LE_METHOD_IS_COOLANT_BROKEN:
return !Sensor::get(SensorType::Clt).Valid;
2015-07-10 06:01:56 -07:00
case LE_METHOD_INTAKE_AIR:
2021-10-05 16:59:07 -07:00
return Sensor::getOrZero(SensorType::Iat);
2015-07-10 06:01:56 -07:00
case LE_METHOD_RPM:
2021-10-05 16:59:07 -07:00
return Sensor::getOrZero(SensorType::Rpm);
2016-07-07 20:01:43 -07:00
case LE_METHOD_MAF:
2021-10-05 16:59:07 -07:00
return Sensor::getOrZero(SensorType::Maf);
2016-07-07 20:01:43 -07:00
case LE_METHOD_MAP:
2021-10-05 16:59:07 -07:00
return Sensor::getOrZero(SensorType::Map);
#if EFI_SHAFT_POSITION_INPUT
2016-12-17 09:03:02 -08:00
case LE_METHOD_INTAKE_VVT:
return engine->triggerCentral.getVVTPosition(0, 0);
2016-12-17 09:03:02 -08:00
case LE_METHOD_EXHAUST_VVT:
return engine->triggerCentral.getVVTPosition(0, 1);
#endif
case LE_METHOD_TIME_SINCE_TRIGGER_EVENT:
return engine->triggerCentral.getTimeSinceTriggerEvent(getTimeNowNt());
2015-07-10 06:01:56 -07:00
case LE_METHOD_TIME_SINCE_BOOT:
#if EFI_MAIN_RELAY_CONTROL
// in main relay control mode, we return the number of seconds since the ignition is turned on
// (or negative if the ignition key is switched off)
return engine->getTimeIgnitionSeconds();
#else
2015-07-10 06:01:56 -07:00
return getTimeNowSeconds();
#endif /* EFI_MAIN_RELAY_CONTROL */
case LE_METHOD_STARTUP_FUEL_PUMP_DURATION:
return engineConfiguration->startUpFuelPumpDuration;
2017-06-14 02:39:00 -07:00
case LE_METHOD_CRANKING_RPM:
return engineConfiguration->cranking.rpm;
case LE_METHOD_IN_SHUTDOWN:
return engine->isInShutdownMode();
2021-01-10 20:46:50 -08:00
case LE_METHOD_IN_MR_BENCH:
return engine->isInMainRelayBench();
2015-07-10 06:01:56 -07:00
case LE_METHOD_VBATT:
2021-10-05 16:59:07 -07:00
return Sensor::getOrZero(SensorType::BatteryVoltage);
case LE_METHOD_TPS:
2021-10-05 16:59:07 -07:00
return Sensor::getOrZero(SensorType::DriverThrottleIntent);
case LE_METHOD_FUEL_FLOW_RATE:
return engine->engineState.fuelConsumption.getConsumptionGramPerSecond();
case LE_METHOD_OIL_PRESSURE:
2021-10-05 16:59:07 -07:00
return Sensor::getOrZero(SensorType::OilPressure);
// cfg_xxx references are code generated
2019-09-10 20:49:21 -07:00
#include "fsio_getters.def"
2015-07-10 06:01:56 -07:00
default:
2020-04-10 14:45:04 -07:00
warning(CUSTOM_FSIO_UNEXPECTED, "FSIO ERROR no data for action=%d", action);
return unexpected;
2015-07-10 06:01:56 -07:00
}
}
2019-04-12 19:07:03 -07:00
#if EFI_PROD_CODE
2015-07-10 06:01:56 -07:00
2018-08-01 20:27:22 -07:00
static void setFsioAnalogInputPin(const char *indexStr, const char *pinName) {
// todo: reduce code duplication between all "set pin methods"
int index = atoi(indexStr) - 1;
2021-09-01 04:47:25 -07:00
if (index < 0 || index >= AUX_ANALOG_INPUT_COUNT) {
efiPrintf("invalid FSIO index: %d", index);
2018-08-01 20:27:22 -07:00
return;
}
brain_pin_e pin = parseBrainPin(pinName);
// todo: extract method - code duplication with other 'set_xxx_pin' methods?
if (pin == GPIO_INVALID) {
efiPrintf("invalid pin name [%s]", pinName);
2018-08-01 20:27:22 -07:00
return;
}
2018-08-01 20:33:13 -07:00
engineConfiguration->fsioAdc[index] = (adc_channel_e) pin;
efiPrintf("FSIO analog input pin #%d [%s]", (index + 1), hwPortname(pin));
2018-08-01 20:27:22 -07:00
}
static void setFsioDigitalInputPin(const char *indexStr, const char *pinName) {
2018-08-01 20:27:22 -07:00
// todo: reduce code duplication between all "set pin methods"
2015-07-10 06:01:56 -07:00
int index = atoi(indexStr) - 1;
2017-06-25 23:14:31 -07:00
if (index < 0 || index >= FSIO_COMMAND_COUNT) {
efiPrintf("invalid FSIO index: %d", index);
2015-07-10 06:01:56 -07:00
return;
}
brain_pin_e pin = parseBrainPin(pinName);
// todo: extract method - code duplication with other 'set_xxx_pin' methods?
if (pin == GPIO_INVALID) {
efiPrintf("invalid pin name [%s]", pinName);
2015-07-10 06:01:56 -07:00
return;
}
CONFIG(fsioDigitalInputs)[index] = pin;
efiPrintf("FSIO digital input pin #%d [%s]", (index + 1), hwPortname(pin));
2015-07-10 06:01:56 -07:00
}
2016-12-27 21:02:03 -08:00
static void setFsioPidOutputPin(const char *indexStr, const char *pinName) {
int index = atoi(indexStr) - 1;
2021-02-10 16:51:14 -08:00
if (index < 0 || index >= CAM_INPUTS_COUNT) {
efiPrintf("invalid VVT index: %d", index);
2016-12-27 21:02:03 -08:00
return;
}
brain_pin_e pin = parseBrainPin(pinName);
// todo: extract method - code duplication with other 'set_xxx_pin' methods?
if (pin == GPIO_INVALID) {
efiPrintf("invalid pin name [%s]", pinName);
2016-12-27 21:02:03 -08:00
return;
}
engineConfiguration->auxPidPins[index] = pin;
efiPrintf("VVT pid pin #%d [%s]", (index + 1), hwPortname(pin));
2016-12-27 21:02:03 -08:00
}
2017-12-17 09:02:35 -08:00
static void showFsioInfo(void);
2015-07-10 06:01:56 -07:00
static void setFsioOutputPin(const char *indexStr, const char *pinName) {
int index = atoi(indexStr) - 1;
2017-06-25 23:14:31 -07:00
if (index < 0 || index >= FSIO_COMMAND_COUNT) {
efiPrintf("invalid FSIO index: %d", index);
2015-07-10 06:01:56 -07:00
return;
}
brain_pin_e pin = parseBrainPin(pinName);
// todo: extract method - code duplication with other 'set_xxx_pin' methods?
if (pin == GPIO_INVALID) {
efiPrintf("invalid pin name [%s]", pinName);
2015-07-10 06:01:56 -07:00
return;
}
CONFIG(fsioOutputPins)[index] = pin;
efiPrintf("FSIO output pin #%d [%s]", (index + 1), hwPortname(pin));
efiPrintf("please writeconfig and reboot for pin to take effect");
2017-12-17 09:02:35 -08:00
showFsioInfo();
2015-07-10 06:01:56 -07:00
}
2016-01-12 07:04:06 -08:00
#endif /* EFI_PROD_CODE */
2015-07-10 06:01:56 -07:00
2016-01-12 09:01:43 -08:00
#endif
2016-01-12 19:01:53 -08:00
/**
* index is between zero and LE_COMMAND_LENGTH-1
*/
void setFsioExt(int index, brain_pin_e pin, const char * formula, int pwmFrequency DECLARE_CONFIG_PARAMETER_SUFFIX) {
CONFIG(fsioOutputPins)[index] = pin;
2017-12-17 09:02:35 -08:00
int len = strlen(formula);
2015-07-10 06:01:56 -07:00
if (len >= LE_COMMAND_LENGTH) {
return;
}
2017-12-17 09:02:35 -08:00
strcpy(config->fsioFormulas[index], formula);
CONFIG(fsioFrequency)[index] = pwmFrequency;
2015-07-10 06:01:56 -07:00
}
void setFsio(int index, brain_pin_e pin, const char * exp DECLARE_CONFIG_PARAMETER_SUFFIX) {
setFsioExt(index, pin, exp, NO_PWM PASS_CONFIG_PARAMETER_SUFFIX);
2015-07-10 06:01:56 -07:00
}
2017-05-15 20:28:49 -07:00
void applyFsioConfiguration(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
2016-06-26 17:03:27 -07:00
userPool.reset();
2017-06-25 23:14:31 -07:00
for (int i = 0; i < FSIO_COMMAND_COUNT; i++) {
const char *formula = config->fsioFormulas[i];
int len = strlen(formula);
LEElement *logic = userPool.parseExpression(formula);
if (len > 0 && logic == NULL) {
warning(CUSTOM_FSIO_PARSING, "parsing [%s]", formula);
2015-07-10 06:01:56 -07:00
}
state.fsioLogics[i] = logic;
2015-07-10 06:01:56 -07:00
}
}
void onConfigurationChangeFsioCallback(engine_configuration_s *previousConfiguration DECLARE_ENGINE_PARAMETER_SUFFIX) {
(void)previousConfiguration;
2019-04-12 19:07:03 -07:00
#if EFI_FSIO
applyFsioConfiguration(PASS_ENGINE_PARAMETER_SIGNATURE);
#endif
}
static LECalculator calc CCM_OPTIONAL;
2015-07-10 06:01:56 -07:00
2018-12-24 05:37:25 -08:00
static SimplePwm fsioPwm[FSIO_COMMAND_COUNT] CCM_OPTIONAL;
2015-07-10 06:01:56 -07:00
// that's crazy, but what's an alternative? we need const char *, a shared buffer would not work for pin repository
static const char *getGpioPinName(int index) {
switch (index) {
case 0:
2017-05-12 11:37:07 -07:00
return "FSIO_OUT_0";
2015-07-10 06:01:56 -07:00
case 1:
2017-05-12 11:37:07 -07:00
return "FSIO_OUT_1";
2015-07-10 06:01:56 -07:00
case 10:
2017-05-12 11:37:07 -07:00
return "FSIO_OUT_10";
2015-07-10 06:01:56 -07:00
case 11:
2017-05-12 11:37:07 -07:00
return "FSIO_OUT_11";
2015-07-10 06:01:56 -07:00
case 12:
2017-05-12 11:37:07 -07:00
return "FSIO_OUT_12";
2015-07-10 06:01:56 -07:00
case 13:
2017-05-12 11:37:07 -07:00
return "FSIO_OUT_13";
2015-07-10 06:01:56 -07:00
case 14:
2017-05-12 11:37:07 -07:00
return "FSIO_OUT_14";
2015-07-10 06:01:56 -07:00
case 15:
2017-05-12 11:37:07 -07:00
return "FSIO_OUT_15";
2015-07-10 06:01:56 -07:00
case 2:
2017-05-12 11:37:07 -07:00
return "FSIO_OUT_2";
2015-07-10 06:01:56 -07:00
case 3:
2017-05-12 11:37:07 -07:00
return "FSIO_OUT_3";
2015-07-10 06:01:56 -07:00
case 4:
2017-05-12 11:37:07 -07:00
return "FSIO_OUT_4";
2015-07-10 06:01:56 -07:00
case 5:
2017-05-12 11:37:07 -07:00
return "FSIO_OUT_5";
2015-07-10 06:01:56 -07:00
case 6:
2017-05-12 11:37:07 -07:00
return "FSIO_OUT_6";
2015-07-10 06:01:56 -07:00
case 7:
2017-05-12 11:37:07 -07:00
return "FSIO_OUT_7";
2015-07-10 06:01:56 -07:00
case 8:
2017-05-12 11:37:07 -07:00
return "FSIO_OUT_8";
2015-07-10 06:01:56 -07:00
case 9:
2017-05-12 11:37:07 -07:00
return "FSIO_OUT_9";
2015-07-10 06:01:56 -07:00
}
return NULL;
}
2017-12-16 21:03:26 -08:00
float getFsioOutputValue(int index DECLARE_ENGINE_PARAMETER_SUFFIX) {
if (state.fsioLogics[index] == NULL) {
warning(CUSTOM_NO_FSIO, "no FSIO for #%d %s", index + 1, hwPortname(CONFIG(fsioOutputPins)[index]));
2017-12-16 21:03:26 -08:00
return NAN;
} else {
return calc.evaluate("FSIO", engine->fsioState.fsioLastValue[index], state.fsioLogics[index] PASS_ENGINE_PARAMETER_SUFFIX);
2017-12-16 21:03:26 -08:00
}
}
2016-10-01 06:02:04 -07:00
/**
2017-06-25 23:14:31 -07:00
* @param index from zero for (FSIO_COMMAND_COUNT - 1)
2016-10-01 06:02:04 -07:00
*/
static void runFsioCalculation(int index DECLARE_ENGINE_PARAMETER_SUFFIX) {
if (strlen(config->fsioFormulas[index]) == 0) {
engine->fsioState.fsioLastValue[index] = NAN;
2015-07-10 06:01:56 -07:00
return;
2017-12-17 09:02:35 -08:00
}
2015-07-10 06:01:56 -07:00
bool isPwmMode = CONFIG(fsioFrequency)[index] != NO_PWM;
2015-07-10 06:01:56 -07:00
2017-12-16 21:07:43 -08:00
float fvalue = getFsioOutputValue(index PASS_ENGINE_PARAMETER_SUFFIX);
engine->fsioState.fsioLastValue[index] = fvalue;
2015-07-10 06:01:56 -07:00
if (isPwmMode) {
fsioPwm[index].setSimplePwmDutyCycle(fvalue);
} else {
int value = (int) fvalue;
2016-09-14 16:03:00 -07:00
if (value != enginePins.fsioOutputs[index].getLogicValue()) {
// efiPrintf("setting %s %s", getIo_pin_e(pin), boolToString(value));
2016-09-14 16:03:00 -07:00
enginePins.fsioOutputs[index].setValue(value);
2015-07-10 06:01:56 -07:00
}
}
}
static const char * action2String(le_action_e action) {
2016-08-09 21:04:24 -07:00
static char buffer[_MAX_FILLER];
2015-07-10 06:01:56 -07:00
switch(action) {
case LE_METHOD_RPM:
return "RPM";
2017-06-14 02:39:00 -07:00
case LE_METHOD_CRANKING_RPM:
return "cranking_rpm";
2015-07-10 06:01:56 -07:00
case LE_METHOD_COOLANT:
return "CLT";
case LE_METHOD_FAN:
return "fan";
case LE_METHOD_STARTUP_FUEL_PUMP_DURATION:
2021-01-10 20:46:50 -08:00
return leStartupFuelPumpDuration.name;
case LE_METHOD_IN_SHUTDOWN:
2021-01-10 20:46:50 -08:00
return leInShutdown.name;
case LE_METHOD_IN_MR_BENCH:
return leInMrBench.name;
2019-09-11 16:30:36 -07:00
#include "fsio_strings.def"
2015-07-10 06:01:56 -07:00
default: {
// this is here to make compiler happy
}
}
itoa10(buffer, (int)action);
return buffer;
}
2018-12-24 05:37:25 -08:00
static void setPinState(const char * msg, OutputPin *pin, LEElement *element DECLARE_ENGINE_PARAMETER_SUFFIX) {
#if EFI_PROD_CODE
if (isRunningBenchTest()) {
return; // let's not mess with bench testing
}
2018-12-24 05:37:25 -08:00
#endif /* EFI_PROD_CODE */
if (!element) {
2017-07-24 16:38:22 -07:00
warning(CUSTOM_FSIO_INVALID_EXPRESSION, "invalid expression for %s", msg);
2015-07-10 06:01:56 -07:00
} else {
int value = (int)calc.evaluate(msg, pin->getLogicValue(), element PASS_ENGINE_PARAMETER_SUFFIX);
2015-07-10 06:01:56 -07:00
if (pin->isInitialized() && value != pin->getLogicValue()) {
for (int i = 0;i < calc.currentCalculationLogPosition;i++) {
efiPrintf("calc %d: action %s value %.2f", i, action2String(calc.calcLogAction[i]), calc.calcLogValue[i]);
2015-07-10 06:01:56 -07:00
}
efiPrintf("setPin %s %s", msg, value ? "on" : "off");
2015-07-10 06:01:56 -07:00
pin->setValue(value);
}
}
}
2018-12-24 05:37:25 -08:00
2019-04-12 19:07:03 -07:00
#if EFI_PROD_CODE
2016-01-12 07:04:06 -08:00
static void setFsioFrequency(int index, int frequency) {
index--;
2017-06-25 23:14:31 -07:00
if (index < 0 || index >= FSIO_COMMAND_COUNT) {
efiPrintf("invalid FSIO index: %d", index);
2016-01-12 07:04:06 -08:00
return;
}
CONFIG(fsioFrequency)[index] = frequency;
2017-03-12 11:47:21 -07:00
if (frequency == 0) {
efiPrintf("FSIO output #%d@%s set to on/off mode", index + 1, hwPortname(CONFIG(fsioOutputPins)[index]));
2017-03-12 11:47:21 -07:00
} else {
efiPrintf("Setting FSIO frequency %dHz on #%d@%s", frequency, index + 1, hwPortname(CONFIG(fsioOutputPins)[index]));
2017-03-12 11:47:21 -07:00
}
2016-01-12 07:04:06 -08:00
}
2018-12-24 05:37:25 -08:00
#endif /* EFI_PROD_CODE */
2016-01-12 07:04:06 -08:00
/**
* @param out param! current and new value as long as element is not NULL
* @return 'true' if value has changed
*/
static bool updateValueOrWarning(int humanIndex, const char *msg, float *value DECLARE_ENGINE_PARAMETER_SUFFIX) {
int fsioIndex = humanIndex - 1;
LEElement * element = state.fsioLogics[fsioIndex];
2018-03-18 09:15:51 -07:00
if (element == NULL) {
warning(CUSTOM_FSIO_INVALID_EXPRESSION, "invalid expression for %s", msg);
return false;
2018-03-18 09:15:51 -07:00
} else {
float beforeValue = *value;
*value = calc.evaluate(msg, beforeValue, element PASS_ENGINE_PARAMETER_SUFFIX);
// floating '==' comparison without EPS seems fine here
return (beforeValue != *value);
2018-03-18 09:15:51 -07:00
}
}
2017-12-16 21:03:26 -08:00
/**
* this method should be invoked periodically to calculate FSIO and toggle corresponding FSIO outputs
*/
void runFsio(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
for (int index = 0; index < FSIO_COMMAND_COUNT; index++) {
runFsioCalculation(index PASS_ENGINE_PARAMETER_SUFFIX);
2016-01-12 07:04:06 -08:00
}
2019-04-12 19:07:03 -07:00
#if EFI_FUEL_PUMP
if (isBrainPinValid(CONFIG(fuelPumpPin))) {
2018-12-24 05:37:25 -08:00
setPinState("pump", &enginePins.fuelPumpRelay, fuelPumpLogic PASS_ENGINE_PARAMETER_SUFFIX);
2016-01-12 07:04:06 -08:00
}
#endif /* EFI_FUEL_PUMP */
2019-04-12 19:07:03 -07:00
#if EFI_MAIN_RELAY_CONTROL
if (isBrainPinValid(CONFIG(mainRelayPin)))
// the MAIN_RELAY_LOGIC calls engine->isInShutdownMode()
2018-12-24 05:37:25 -08:00
setPinState("main_relay", &enginePins.mainRelay, mainRelayLogic PASS_ENGINE_PARAMETER_SUFFIX);
2017-06-12 15:14:39 -07:00
#else /* EFI_MAIN_RELAY_CONTROL */
2016-01-12 07:04:06 -08:00
/**
* main relay is always on if ECU is on, that's a good enough initial implementation
*/
if (isBrainPinValid(CONFIG(mainRelayPin)))
2021-01-11 17:01:20 -08:00
enginePins.mainRelay.setValue(!engine->isInMainRelayBench(PASS_ENGINE_PARAMETER_SIGNATURE));
2017-06-12 15:14:39 -07:00
#endif /* EFI_MAIN_RELAY_CONTROL */
2016-01-12 07:04:06 -08:00
if (isBrainPinValid(CONFIG(starterRelayDisablePin)))
2020-03-18 13:32:03 -07:00
setPinState("starter_relay", &enginePins.starterRelayDisable, starterRelayDisableLogic PASS_ENGINE_PARAMETER_SUFFIX);
2017-07-06 18:26:35 -07:00
/**
* o2 heater is off during cranking
2017-07-08 12:46:34 -07:00
* todo: convert to FSIO?
* open question if heater should be ON during cranking
2017-07-06 18:26:35 -07:00
*/
enginePins.o2heater.setValue(engine->rpmCalculator.isRunning());
2016-01-12 07:04:06 -08:00
#if EFI_ENABLE_ENGINE_WARNING
if (engineConfiguration->useFSIO4ForSeriousEngineWarning) {
updateValueOrWarning(MAGIC_OFFSET_FOR_ENGINE_WARNING, "eng warning", &ENGINE(fsioState.isEngineWarning) PASS_ENGINE_PARAMETER_SUFFIX);
}
2019-01-06 04:37:29 -08:00
#endif /* EFI_ENABLE_ENGINE_WARNING */
#if EFI_ENABLE_CRITICAL_ENGINE_STOP
if (engineConfiguration->useFSIO5ForCriticalIssueEngineStop) {
bool changed = updateValueOrWarning(MAGIC_OFFSET_FOR_CRITICAL_ENGINE, "eng critical", &ENGINE(fsioState.isCriticalEngineCondition) PASS_ENGINE_PARAMETER_SUFFIX);
if (changed && float2bool(ENGINE(fsioState.isCriticalEngineCondition))) {
doScheduleStopEngine(PASS_ENGINE_PARAMETER_SIGNATURE);
}
}
2019-01-06 04:37:29 -08:00
#endif /* EFI_ENABLE_CRITICAL_ENGINE_STOP */
2016-01-12 07:04:06 -08:00
}
2015-07-10 06:01:56 -07:00
static void showFsio(const char *msg, LEElement *element) {
2016-01-12 09:01:43 -08:00
#if EFI_PROD_CODE || EFI_SIMULATOR
2015-07-10 06:01:56 -07:00
if (msg != NULL)
efiPrintf("%s:", msg);
while (element->action != LE_METHOD_RETURN) {
efiPrintf("action %d: fValue=%.2f", element->action, element->fValue);
element++;
2015-07-10 06:01:56 -07:00
}
efiPrintf("<end>");
2016-01-12 09:01:43 -08:00
#endif
2015-07-10 06:01:56 -07:00
}
static void showFsioInfo(void) {
2016-01-12 09:01:43 -08:00
#if EFI_PROD_CODE || EFI_SIMULATOR
efiPrintf("sys used %d/user used %d", sysPool.getSize(), userPool.getSize());
2015-07-10 06:01:56 -07:00
showFsio("fuel", fuelPumpLogic);
2021-02-10 16:51:14 -08:00
for (int i = 0; i < CAM_INPUTS_COUNT ; i++) {
2016-12-27 21:02:03 -08:00
brain_pin_e pin = engineConfiguration->auxPidPins[i];
if (isBrainPinValid(pin)) {
efiPrintf("VVT pid #%d [%s]", (i + 1),
2016-12-27 21:02:03 -08:00
hwPortname(pin));
}
}
2017-06-25 23:14:31 -07:00
for (int i = 0; i < FSIO_COMMAND_COUNT; i++) {
2017-06-25 23:23:26 -07:00
char * exp = config->fsioFormulas[i];
2015-07-10 06:01:56 -07:00
if (exp[0] != 0) {
/**
* in case of FSIO user interface indexes are starting with 0, the argument for that
* is the fact that the target audience is more software developers
*/
2020-04-10 12:49:44 -07:00
int freq = CONFIG(fsioFrequency)[i];
const char *modeMessage = freq == 0 ? " (on/off mode)" : "";
efiPrintf("FSIO #%d [%s] at %s@%dHz%s value=%.2f", (i + 1), exp,
2020-04-10 12:49:44 -07:00
hwPortname(CONFIG(fsioOutputPins)[i]),
freq, modeMessage,
engine->fsioState.fsioLastValue[i]);
// efiPrintf("user-defined #%d value=%.2f", i, engine->engineConfigurationPtr2->fsioLastValue[i]);
showFsio(NULL, state.fsioLogics[i]);
2015-07-10 06:01:56 -07:00
}
}
2017-06-25 23:14:31 -07:00
for (int i = 0; i < FSIO_COMMAND_COUNT; i++) {
float v = CONFIG(fsio_setting)[i];
2015-07-10 06:01:56 -07:00
if (!cisnan(v)) {
efiPrintf("user property #%d: %.2f", i + 1, v);
2015-07-10 06:01:56 -07:00
}
}
2017-06-25 23:14:31 -07:00
for (int i = 0; i < FSIO_COMMAND_COUNT; i++) {
brain_pin_e inputPin = CONFIG(fsioDigitalInputs)[i];
if (isBrainPinValid(inputPin)) {
efiPrintf("FSIO digital input #%d: %s", i, hwPortname(inputPin));
2015-07-10 06:01:56 -07:00
}
}
2016-01-12 09:01:43 -08:00
#endif
2015-07-10 06:01:56 -07:00
}
/**
2017-03-12 11:47:21 -07:00
* set_fsio_setting 1 0.11
2015-07-10 06:01:56 -07:00
*/
2017-03-12 12:22:07 -07:00
static void setFsioSetting(float humanIndexF, float value) {
2016-01-12 09:01:43 -08:00
#if EFI_PROD_CODE || EFI_SIMULATOR
2017-03-12 12:22:07 -07:00
int index = (int)humanIndexF - 1;
2017-06-25 23:14:31 -07:00
if (index < 0 || index >= FSIO_COMMAND_COUNT) {
efiPrintf("invalid FSIO index: %d", (int)humanIndexF);
2015-07-10 06:01:56 -07:00
return;
}
engineConfiguration->fsio_setting[index] = value;
2015-07-10 06:01:56 -07:00
showFsioInfo();
2016-01-12 09:01:43 -08:00
#endif
2015-07-10 06:01:56 -07:00
}
2020-07-29 19:48:41 -07:00
void setFsioExpression(const char *indexStr, const char *quotedLine DECLARE_CONFIG_PARAMETER_SUFFIX) {
2015-07-10 06:01:56 -07:00
int index = atoi(indexStr) - 1;
2017-06-25 23:14:31 -07:00
if (index < 0 || index >= FSIO_COMMAND_COUNT) {
efiPrintf("invalid FSIO index: %d", index);
2015-07-10 06:01:56 -07:00
return;
}
char * l = unquote((char*) quotedLine);
if (strlen(l) > LE_COMMAND_LENGTH - 1) {
efiPrintf("Too long %d", strlen(l));
2015-07-10 06:01:56 -07:00
return;
}
efiPrintf("setting user out #%d to [%s]", index + 1, l);
2017-11-26 16:35:08 -08:00
strcpy(config->fsioFormulas[index], l);
2020-07-29 19:48:41 -07:00
}
void applyFsioExpression(const char *indexStr, const char *quotedLine DECLARE_ENGINE_PARAMETER_SUFFIX) {
setFsioExpression(indexStr, quotedLine PASS_CONFIG_PARAMETER_SUFFIX);
2015-07-10 06:01:56 -07:00
// this would apply the changes
2017-05-15 20:28:49 -07:00
applyFsioConfiguration(PASS_ENGINE_PARAMETER_SIGNATURE);
2015-07-10 06:01:56 -07:00
showFsioInfo();
}
2019-07-12 05:31:38 -07:00
ValueProvider3D *getFSIOTable(int index) {
switch (index) {
default:
return &fsioTable1;
case 1:
return &fsioTable2;
case 2:
return &fsioTable3;
case 3:
return &fsioTable4;
}
}
void initFsioImpl(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
#if EFI_UNIT_TEST
2019-05-12 17:31:28 -07:00
// only unit test needs this
sysPool.reset();
2016-01-12 09:01:43 -08:00
#endif
2015-07-10 06:01:56 -07:00
2019-04-12 19:07:03 -07:00
#if EFI_FUEL_PUMP
2015-07-10 06:01:56 -07:00
fuelPumpLogic = sysPool.parseExpression(FUEL_PUMP_LOGIC);
2016-01-12 07:04:06 -08:00
#endif /* EFI_FUEL_PUMP */
2015-07-10 06:01:56 -07:00
2019-04-12 19:07:03 -07:00
#if EFI_MAIN_RELAY_CONTROL
if (isBrainPinValid(CONFIG(mainRelayPin)))
2017-06-12 15:14:39 -07:00
mainRelayLogic = sysPool.parseExpression(MAIN_RELAY_LOGIC);
#endif /* EFI_MAIN_RELAY_CONTROL */
if (isBrainPinValid(CONFIG(starterRelayDisablePin)))
2020-03-18 13:32:03 -07:00
starterRelayDisableLogic = sysPool.parseExpression(STARTER_RELAY_LOGIC);
2015-07-10 06:01:56 -07:00
2019-04-12 19:07:03 -07:00
#if EFI_PROD_CODE
2017-06-25 23:14:31 -07:00
for (int i = 0; i < FSIO_COMMAND_COUNT; i++) {
brain_pin_e brainPin = CONFIG(fsioOutputPins)[i];
2015-07-10 06:01:56 -07:00
if (isBrainPinValid(brainPin)) {
int frequency = CONFIG(fsioFrequency)[i];
2015-07-10 06:01:56 -07:00
if (frequency == 0) {
2020-04-04 12:59:13 -07:00
enginePins.fsioOutputs[i].initPin(getGpioPinName(i), CONFIG(fsioOutputPins)[i]);
2015-07-10 06:01:56 -07:00
} else {
startSimplePwmExt(&fsioPwm[i], "FSIOpwm",
&engine->executor,
brainPin, &enginePins.fsioOutputs[i], frequency, 0.5f);
2015-07-10 06:01:56 -07:00
}
}
}
2017-06-25 23:14:31 -07:00
for (int i = 0; i < FSIO_COMMAND_COUNT; i++) {
brain_pin_e inputPin = CONFIG(fsioDigitalInputs)[i];
2015-07-10 06:01:56 -07:00
if (isBrainPinValid(inputPin)) {
2017-05-15 05:40:54 -07:00
efiSetPadMode("FSIO input", inputPin, getInputMode(engineConfiguration->fsioInputModes[i]));
2015-07-10 06:01:56 -07:00
}
}
2016-12-27 21:02:03 -08:00
addConsoleActionSS("set_fsio_pid_output_pin", (VoidCharPtrCharPtr) setFsioPidOutputPin);
2016-01-12 07:04:06 -08:00
addConsoleActionSS("set_fsio_output_pin", (VoidCharPtrCharPtr) setFsioOutputPin);
addConsoleActionII("set_fsio_output_frequency", (VoidIntInt) setFsioFrequency);
addConsoleActionSS("set_fsio_digital_input_pin", (VoidCharPtrCharPtr) setFsioDigitalInputPin);
2018-08-01 20:27:22 -07:00
addConsoleActionSS("set_fsio_analog_input_pin", (VoidCharPtrCharPtr) setFsioAnalogInputPin);
2016-01-12 07:04:06 -08:00
2015-07-10 06:01:56 -07:00
#endif /* EFI_PROD_CODE */
2016-01-12 09:01:43 -08:00
#if EFI_PROD_CODE || EFI_SIMULATOR
2020-07-29 19:48:41 -07:00
addConsoleActionSS("set_rpn_expression", applyFsioExpression);
2015-07-10 06:01:56 -07:00
addConsoleActionFF("set_fsio_setting", setFsioSetting);
addConsoleAction("fsioinfo", showFsioInfo);
2017-06-04 12:25:37 -07:00
#endif /* EFI_PROD_CODE || EFI_SIMULATOR */
2016-04-04 07:01:43 -07:00
fsioTable1.init(config->fsioTable1, config->fsioTable1LoadBins,
config->fsioTable1RpmBins);
fsioTable2.init(config->fsioTable2, config->fsioTable2LoadBins,
config->fsioTable2RpmBins);
2016-07-01 20:01:22 -07:00
fsioTable3.init(config->fsioTable3, config->fsioTable3LoadBins,
config->fsioTable3RpmBins);
fsioTable4.init(config->fsioTable4, config->fsioTable4LoadBins,
config->fsioTable4RpmBins);
2016-04-04 07:01:43 -07:00
2015-07-10 06:01:56 -07:00
}
#else /* !EFI_FSIO */
// "Limp-mode" implementation for some RAM-limited configs without FSIO
void runHardcodedFsio(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
#if EFI_PROD_CODE
if (isRunningBenchTest()) {
return; // let's not mess with bench testing
}
#endif /* EFI_PROD_CODE */
// see MAIN_RELAY_LOGIC
if (isBrainPinValid(CONFIG(mainRelayPin))) {
2021-10-05 16:59:07 -07:00
enginePins.mainRelay.setValue((getTimeNowSeconds() < 2) || (Sensor::getOrZero(SensorType::BatteryVoltage) > LOW_VBATT) || engine->isInShutdownMode());
}
// see STARTER_RELAY_LOGIC
if (isBrainPinValid(CONFIG(starterRelayDisablePin))) {
2020-03-18 16:41:12 -07:00
enginePins.starterRelayDisable.setValue(engine->rpmCalculator.getRpm() < engineConfiguration->cranking.rpm);
}
// see FUEL_PUMP_LOGIC
if (isBrainPinValid(CONFIG(fuelPumpPin))) {
enginePins.fuelPumpRelay.setValue((getTimeNowSeconds() < engine->triggerActivitySecond + engineConfiguration->startUpFuelPumpDuration) || (engine->rpmCalculator.getRpm() > 0));
}
enginePins.o2heater.setValue(engine->rpmCalculator.isRunning());
}
2015-07-10 06:01:56 -07:00
#endif /* EFI_FSIO */