2015-07-10 06:01:56 -07:00
|
|
|
/**
|
|
|
|
* @file engine_math.cpp
|
|
|
|
* @brief
|
|
|
|
*
|
|
|
|
* @date Jul 13, 2013
|
2020-01-13 18:57:43 -08:00
|
|
|
* @author Andrey Belomutskiy, (c) 2012-2020
|
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/>.
|
|
|
|
*/
|
|
|
|
|
2021-07-25 22:05:17 -07:00
|
|
|
#include "pch.h"
|
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
#include "event_registry.h"
|
|
|
|
#include "fuel_math.h"
|
2016-01-08 12:01:38 -08:00
|
|
|
#include "advance_map.h"
|
2024-05-15 08:45:59 -07:00
|
|
|
#include "gppwm_channel_reader.h"
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2019-08-24 22:15:18 -07:00
|
|
|
#if EFI_UNIT_TEST
|
|
|
|
extern bool verboseMode;
|
|
|
|
#endif /* EFI_UNIT_TEST */
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
floatms_t getEngineCycleDuration(int rpm) {
|
2022-09-13 22:34:52 -07:00
|
|
|
return getCrankshaftRevolutionTimeMs(rpm) * (getEngineRotationState()->getOperationMode() == TWO_STROKE ? 1 : 2);
|
2017-03-08 21:51:27 -08:00
|
|
|
}
|
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
/**
|
2016-01-08 12:01:38 -08:00
|
|
|
* @return number of milliseconds in one crank shaft revolution
|
2015-07-10 06:01:56 -07:00
|
|
|
*/
|
2015-09-07 06:03:24 -07:00
|
|
|
floatms_t getCrankshaftRevolutionTimeMs(int rpm) {
|
2016-08-30 19:02:21 -07:00
|
|
|
if (rpm == 0) {
|
|
|
|
return NAN;
|
|
|
|
}
|
2015-07-10 06:01:56 -07:00
|
|
|
return 360 * getOneDegreeTimeMs(rpm);
|
|
|
|
}
|
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
float getFuelingLoad() {
|
2022-09-13 22:09:32 -07:00
|
|
|
return getEngineState()->fuelingLoad;
|
2020-07-05 13:25:19 -07:00
|
|
|
}
|
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
float getIgnitionLoad() {
|
2022-09-13 22:09:32 -07:00
|
|
|
return getEngineState()->ignitionLoad;
|
2020-07-05 13:25:19 -07:00
|
|
|
}
|
|
|
|
|
2019-11-05 20:17:44 -08:00
|
|
|
/**
|
|
|
|
* see also setConstantDwell
|
|
|
|
*/
|
2021-11-16 01:15:29 -08:00
|
|
|
void setSingleCoilDwell() {
|
2015-07-10 06:01:56 -07:00
|
|
|
for (int i = 0; i < DWELL_CURVE_SIZE; i++) {
|
2022-05-01 20:43:43 -07:00
|
|
|
config->sparkDwellRpmBins[i] = (i + 1) * 50;
|
|
|
|
config->sparkDwellValues[i] = 4;
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2022-05-01 20:43:43 -07:00
|
|
|
config->sparkDwellRpmBins[5] = 500;
|
|
|
|
config->sparkDwellValues[5] = 4;
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2022-05-01 20:43:43 -07:00
|
|
|
config->sparkDwellRpmBins[6] = 4500;
|
|
|
|
config->sparkDwellValues[6] = 4;
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2022-05-01 20:43:43 -07:00
|
|
|
config->sparkDwellRpmBins[7] = 12500;
|
|
|
|
config->sparkDwellValues[7] = 0;
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-04-18 05:16:53 -07:00
|
|
|
* @return Spark dwell time, in milliseconds. 0 if tables are not ready.
|
2015-07-10 06:01:56 -07:00
|
|
|
*/
|
2022-04-13 13:39:59 -07:00
|
|
|
floatms_t IgnitionState::getSparkDwell(int rpm) {
|
2019-04-12 19:07:03 -07:00
|
|
|
#if EFI_ENGINE_CONTROL && EFI_SHAFT_POSITION_INPUT
|
2016-11-30 12:02:43 -08:00
|
|
|
float dwellMs;
|
2021-11-17 00:54:21 -08:00
|
|
|
if (engine->rpmCalculator.isCranking()) {
|
|
|
|
dwellMs = engineConfiguration->ignitionDwellForCrankingMs;
|
2016-11-30 12:02:43 -08:00
|
|
|
} else {
|
2024-07-22 12:05:17 -07:00
|
|
|
efiAssert(ObdCode::CUSTOM_ERR_ASSERT, !std::isnan(rpm), "invalid rpm", NAN);
|
2016-11-30 12:02:43 -08:00
|
|
|
|
2022-05-01 20:43:43 -07:00
|
|
|
baseDwell = interpolate2d(rpm, config->sparkDwellRpmBins, config->sparkDwellValues);
|
2022-04-28 05:16:02 -07:00
|
|
|
dwellVoltageCorrection = interpolate2d(
|
|
|
|
Sensor::getOrZero(SensorType::BatteryVoltage),
|
2024-03-17 12:06:14 -07:00
|
|
|
config->dwellVoltageCorrVoltBins,
|
|
|
|
config->dwellVoltageCorrValues
|
2022-04-28 05:16:02 -07:00
|
|
|
);
|
2021-09-15 05:07:33 -07:00
|
|
|
|
|
|
|
// for compat (table full of zeroes)
|
2022-04-13 13:39:59 -07:00
|
|
|
if (dwellVoltageCorrection < 0.1f) {
|
|
|
|
dwellVoltageCorrection = 1;
|
2021-09-15 05:07:33 -07:00
|
|
|
}
|
|
|
|
|
2022-04-13 13:39:59 -07:00
|
|
|
dwellMs = baseDwell * dwellVoltageCorrection;
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2024-07-22 12:05:17 -07:00
|
|
|
if (std::isnan(dwellMs) || dwellMs <= 0) {
|
2017-04-18 05:16:53 -07:00
|
|
|
// this could happen during engine configuration reset
|
2023-04-28 21:13:13 -07:00
|
|
|
warning(ObdCode::CUSTOM_ERR_DWELL_DURATION, "invalid dwell: %.2f at rpm=%d", dwellMs, rpm);
|
2017-04-18 05:16:53 -07:00
|
|
|
return 0;
|
2016-11-30 12:02:43 -08:00
|
|
|
}
|
|
|
|
return dwellMs;
|
2019-01-31 14:55:23 -08:00
|
|
|
#else
|
|
|
|
return 0;
|
|
|
|
#endif
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2022-03-22 13:53:24 -07:00
|
|
|
static const uint8_t order_1[] = {1};
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2022-03-22 13:53:24 -07:00
|
|
|
static const uint8_t order_1_2[] = {1, 2};
|
2017-02-07 22:03:36 -08:00
|
|
|
|
2022-03-22 13:53:24 -07:00
|
|
|
static const uint8_t order_1_2_3[] = {1, 2, 3};
|
|
|
|
static const uint8_t order_1_3_2[] = {1, 3, 2};
|
2017-02-07 22:03:36 -08:00
|
|
|
// 4 cylinder
|
|
|
|
|
2022-03-22 13:53:24 -07:00
|
|
|
static const uint8_t order_1_THEN_3_THEN_4_THEN2[] = { 1, 3, 4, 2 };
|
|
|
|
static const uint8_t order_1_THEN_2_THEN_4_THEN3[] = { 1, 2, 4, 3 };
|
|
|
|
static const uint8_t order_1_THEN_3_THEN_2_THEN4[] = { 1, 3, 2, 4 };
|
|
|
|
static const uint8_t order_1_THEN_4_THEN_3_THEN2[] = { 1, 4, 3, 2 };
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2017-02-07 22:03:36 -08:00
|
|
|
// 5 cylinder
|
2022-03-22 13:53:24 -07:00
|
|
|
static const uint8_t order_1_2_4_5_3[] = {1, 2, 4, 5, 3};
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2017-02-07 22:03:36 -08:00
|
|
|
// 6 cylinder
|
2022-03-22 13:53:24 -07:00
|
|
|
static const uint8_t order_1_THEN_5_THEN_3_THEN_6_THEN_2_THEN_4[] = { 1, 5, 3, 6, 2, 4 };
|
|
|
|
static const uint8_t order_1_THEN_4_THEN_2_THEN_5_THEN_3_THEN_6[] = { 1, 4, 2, 5, 3, 6 };
|
|
|
|
static const uint8_t order_1_THEN_2_THEN_3_THEN_4_THEN_5_THEN_6[] = { 1, 2, 3, 4, 5, 6 };
|
|
|
|
static const uint8_t order_1_6_3_2_5_4[] = {1, 6, 3, 2, 5, 4};
|
|
|
|
static const uint8_t order_1_4_3_6_2_5[] = {1, 4, 3, 6, 2, 5};
|
|
|
|
static const uint8_t order_1_6_2_4_3_5[] = {1, 6, 2, 4, 3, 5};
|
|
|
|
static const uint8_t order_1_6_5_4_3_2[] = {1, 6, 5, 4, 3, 2};
|
|
|
|
static const uint8_t order_1_4_5_2_3_6[] = {1, 4, 5, 2, 3, 6};
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2017-02-07 22:03:36 -08:00
|
|
|
// 8 cylinder
|
2022-03-22 13:53:24 -07:00
|
|
|
static const uint8_t order_1_8_4_3_6_5_7_2[] = { 1, 8, 4, 3, 6, 5, 7, 2 };
|
|
|
|
static const uint8_t order_1_8_7_2_6_5_4_3[] = { 1, 8, 7, 2, 6, 5, 4, 3 };
|
|
|
|
static const uint8_t order_1_5_4_2_6_3_7_8[] = { 1, 5, 4, 2, 6, 3, 7, 8 };
|
|
|
|
static const uint8_t order_1_2_7_8_4_5_6_3[] = { 1, 2, 7, 8, 4, 5, 6, 3 };
|
|
|
|
static const uint8_t order_1_3_7_2_6_5_4_8[] = { 1, 3, 7, 2, 6, 5, 4, 8 };
|
|
|
|
static const uint8_t order_1_2_3_4_5_6_7_8[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
|
|
|
|
static const uint8_t order_1_5_4_8_6_3_7_2[] = { 1, 5, 4, 8, 6, 3, 7, 2 };
|
|
|
|
static const uint8_t order_1_8_7_3_6_5_4_2[] = { 1, 8, 7, 3, 6, 5, 4, 2 };
|
2024-01-11 09:49:49 -08:00
|
|
|
static const uint8_t order_1_5_4_8_3_7_2_6[] = { 1, 5, 4, 8, 3, 7, 2, 6 };
|
2024-04-11 08:19:09 -07:00
|
|
|
static const uint8_t order_1_8_6_2_7_3_4_5[] = { 1, 8, 6, 2, 7, 3, 4, 5 };
|
2020-04-29 13:46:59 -07:00
|
|
|
|
|
|
|
// 9 cylinder
|
2022-03-22 13:53:24 -07:00
|
|
|
static const uint8_t order_1_2_3_4_5_6_7_8_9[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
2016-05-22 10:07:12 -07:00
|
|
|
|
2017-02-07 22:03:36 -08:00
|
|
|
// 10 cylinder
|
2022-03-22 13:53:24 -07:00
|
|
|
static const uint8_t order_1_10_9_4_3_6_5_8_7_2[] = {1, 10, 9, 4, 3, 6, 5, 8, 7, 2};
|
2024-04-01 09:16:45 -07:00
|
|
|
static const uint8_t order_1_6_5_10_2_7_3_8_4_9[] = {1, 6, 5, 10, 2, 7, 3, 8, 4, 9};
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2017-02-07 22:03:36 -08:00
|
|
|
// 12 cyliner
|
2022-03-22 13:53:24 -07:00
|
|
|
static const uint8_t order_1_7_5_11_3_9_6_12_2_8_4_10[] = {1, 7, 5, 11, 3, 9, 6, 12, 2, 8, 4, 10};
|
|
|
|
static const uint8_t order_1_7_4_10_2_8_6_12_3_9_5_11[] = {1, 7, 4, 10, 2, 8, 6, 12, 3, 9, 5, 11};
|
|
|
|
static const uint8_t order_1_12_5_8_3_10_6_7_2_11_4_9[] = {1, 12, 5, 8, 3, 10, 6, 7, 2, 11, 4, 9};
|
|
|
|
static const uint8_t order_1_2_3_4_5_6_7_8_9_10_11_12[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
|
2015-09-10 16:01:32 -07:00
|
|
|
|
2020-05-21 15:28:35 -07:00
|
|
|
// no comments
|
2022-03-22 13:53:24 -07:00
|
|
|
static const uint8_t order_1_14_9_4_7_12_15_6_13_8_3_16_11_2_5_10[] = {1, 14, 9, 4, 7, 12, 15, 6, 13, 8, 3, 16, 11, 2, 5, 10};
|
2020-05-21 15:28:35 -07:00
|
|
|
|
2022-03-22 13:53:24 -07:00
|
|
|
static size_t getFiringOrderLength() {
|
2017-03-23 19:01:10 -07:00
|
|
|
|
2023-04-28 18:01:08 -07:00
|
|
|
switch (engineConfiguration->firingOrder) {
|
2017-03-23 19:01:10 -07:00
|
|
|
case FO_1:
|
|
|
|
return 1;
|
|
|
|
// 2 cylinder
|
|
|
|
case FO_1_2:
|
|
|
|
return 2;
|
|
|
|
// 3 cylinder
|
|
|
|
case FO_1_2_3:
|
2020-06-26 06:07:43 -07:00
|
|
|
case FO_1_3_2:
|
2017-03-23 19:01:10 -07:00
|
|
|
return 3;
|
|
|
|
// 4 cylinder
|
|
|
|
case FO_1_3_4_2:
|
|
|
|
case FO_1_2_4_3:
|
|
|
|
case FO_1_3_2_4:
|
2019-08-15 16:36:16 -07:00
|
|
|
case FO_1_4_3_2:
|
2017-03-23 19:01:10 -07:00
|
|
|
return 4;
|
|
|
|
// 5 cylinder
|
|
|
|
case FO_1_2_4_5_3:
|
|
|
|
return 5;
|
|
|
|
|
|
|
|
// 6 cylinder
|
|
|
|
case FO_1_5_3_6_2_4:
|
|
|
|
case FO_1_4_2_5_3_6:
|
|
|
|
case FO_1_2_3_4_5_6:
|
|
|
|
case FO_1_6_3_2_5_4:
|
2021-07-08 17:42:35 -07:00
|
|
|
case FO_1_4_3_6_2_5:
|
2021-08-24 04:28:56 -07:00
|
|
|
case FO_1_6_2_4_3_5:
|
2021-09-17 21:18:06 -07:00
|
|
|
case FO_1_6_5_4_3_2:
|
|
|
|
case FO_1_4_5_2_3_6:
|
2017-03-23 19:01:10 -07:00
|
|
|
return 6;
|
|
|
|
|
|
|
|
// 8 cylinder
|
|
|
|
case FO_1_8_4_3_6_5_7_2:
|
|
|
|
case FO_1_8_7_2_6_5_4_3:
|
|
|
|
case FO_1_5_4_2_6_3_7_8:
|
2019-09-28 07:25:57 -07:00
|
|
|
case FO_1_2_7_8_4_5_6_3:
|
2020-04-29 13:46:59 -07:00
|
|
|
case FO_1_3_7_2_6_5_4_8:
|
2021-03-05 16:28:17 -08:00
|
|
|
case FO_1_2_3_4_5_6_7_8:
|
|
|
|
case FO_1_5_4_8_6_3_7_2:
|
2021-07-20 18:16:51 -07:00
|
|
|
case FO_1_8_7_3_6_5_4_2:
|
2024-01-11 09:49:49 -08:00
|
|
|
case FO_1_5_4_8_3_7_2_6:
|
2024-04-11 08:19:09 -07:00
|
|
|
case FO_1_8_6_2_7_3_4_5:
|
2017-03-23 19:01:10 -07:00
|
|
|
return 8;
|
|
|
|
|
2020-04-29 13:46:59 -07:00
|
|
|
// 9 cylinder radial
|
|
|
|
case FO_1_2_3_4_5_6_7_8_9:
|
|
|
|
return 9;
|
|
|
|
|
2017-03-23 19:01:10 -07:00
|
|
|
// 10 cylinder
|
|
|
|
case FO_1_10_9_4_3_6_5_8_7_2:
|
2024-04-01 09:16:45 -07:00
|
|
|
case FO_1_6_5_10_2_7_3_8_4_9:
|
2017-03-23 19:01:10 -07:00
|
|
|
return 10;
|
|
|
|
|
|
|
|
// 12 cylinder
|
|
|
|
case FO_1_7_5_11_3_9_6_12_2_8_4_10:
|
2017-06-08 17:35:42 -07:00
|
|
|
case FO_1_7_4_10_2_8_6_12_3_9_5_11:
|
2019-09-14 11:47:22 -07:00
|
|
|
case FO_1_12_5_8_3_10_6_7_2_11_4_9:
|
2020-05-21 17:44:14 -07:00
|
|
|
case FO_1_2_3_4_5_6_7_8_9_10_11_12:
|
2017-03-23 19:01:10 -07:00
|
|
|
return 12;
|
|
|
|
|
2020-05-21 15:28:35 -07:00
|
|
|
case FO_1_14_9_4_7_12_15_6_13_8_3_16_11_2_5_10:
|
|
|
|
return 16;
|
|
|
|
|
2017-03-23 19:01:10 -07:00
|
|
|
default:
|
2023-04-28 21:13:13 -07:00
|
|
|
firmwareError(ObdCode::CUSTOM_OBD_UNKNOWN_FIRING_ORDER, "Invalid firing order: %d", engineConfiguration->firingOrder);
|
2017-03-23 19:01:10 -07:00
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2023-06-25 14:24:39 -07:00
|
|
|
static const uint8_t* getFiringOrderTable() {
|
2023-04-28 18:01:08 -07:00
|
|
|
switch (engineConfiguration->firingOrder) {
|
2016-07-20 16:04:27 -07:00
|
|
|
case FO_1:
|
2021-04-04 15:13:21 -07:00
|
|
|
return order_1;
|
2015-09-10 16:01:32 -07:00
|
|
|
// 2 cylinder
|
2016-07-20 16:04:27 -07:00
|
|
|
case FO_1_2:
|
2021-04-04 15:13:21 -07:00
|
|
|
return order_1_2;
|
2015-09-10 16:01:32 -07:00
|
|
|
// 3 cylinder
|
|
|
|
case FO_1_2_3:
|
2021-04-04 15:13:21 -07:00
|
|
|
return order_1_2_3;
|
2020-06-26 06:07:43 -07:00
|
|
|
case FO_1_3_2:
|
2021-04-04 15:13:21 -07:00
|
|
|
return order_1_3_2;
|
2015-07-10 06:01:56 -07:00
|
|
|
// 4 cylinder
|
2016-07-20 16:04:27 -07:00
|
|
|
case FO_1_3_4_2:
|
2021-04-04 15:13:21 -07:00
|
|
|
return order_1_THEN_3_THEN_4_THEN2;
|
2016-07-20 16:04:27 -07:00
|
|
|
case FO_1_2_4_3:
|
2021-04-04 15:13:21 -07:00
|
|
|
return order_1_THEN_2_THEN_4_THEN3;
|
2016-07-20 16:04:27 -07:00
|
|
|
case FO_1_3_2_4:
|
2021-04-04 15:13:21 -07:00
|
|
|
return order_1_THEN_3_THEN_2_THEN4;
|
2019-08-15 16:36:16 -07:00
|
|
|
case FO_1_4_3_2:
|
2021-04-04 15:13:21 -07:00
|
|
|
return order_1_THEN_4_THEN_3_THEN2;
|
2015-07-10 06:01:56 -07:00
|
|
|
// 5 cylinder
|
|
|
|
case FO_1_2_4_5_3:
|
2021-04-04 15:13:21 -07:00
|
|
|
return order_1_2_4_5_3;
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
// 6 cylinder
|
2016-07-20 16:04:27 -07:00
|
|
|
case FO_1_5_3_6_2_4:
|
2021-04-04 15:13:21 -07:00
|
|
|
return order_1_THEN_5_THEN_3_THEN_6_THEN_2_THEN_4;
|
2016-07-20 16:04:27 -07:00
|
|
|
case FO_1_4_2_5_3_6:
|
2021-04-04 15:13:21 -07:00
|
|
|
return order_1_THEN_4_THEN_2_THEN_5_THEN_3_THEN_6;
|
2016-07-20 16:04:27 -07:00
|
|
|
case FO_1_2_3_4_5_6:
|
2021-04-04 15:13:21 -07:00
|
|
|
return order_1_THEN_2_THEN_3_THEN_4_THEN_5_THEN_6;
|
2017-01-12 21:03:30 -08:00
|
|
|
case FO_1_6_3_2_5_4:
|
2021-04-04 15:13:21 -07:00
|
|
|
return order_1_6_3_2_5_4;
|
2021-07-08 17:42:35 -07:00
|
|
|
case FO_1_4_3_6_2_5:
|
|
|
|
return order_1_4_3_6_2_5;
|
2021-08-24 04:28:56 -07:00
|
|
|
case FO_1_6_2_4_3_5:
|
2021-08-24 04:31:55 -07:00
|
|
|
return order_1_6_2_4_3_5;
|
2021-09-17 21:18:06 -07:00
|
|
|
case FO_1_6_5_4_3_2:
|
|
|
|
return order_1_6_5_4_3_2;
|
|
|
|
case FO_1_4_5_2_3_6:
|
|
|
|
return order_1_4_5_2_3_6;
|
2015-09-05 20:02:46 -07:00
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
// 8 cylinder
|
|
|
|
case FO_1_8_4_3_6_5_7_2:
|
2021-04-04 15:13:21 -07:00
|
|
|
return order_1_8_4_3_6_5_7_2;
|
2016-05-22 10:07:12 -07:00
|
|
|
case FO_1_8_7_2_6_5_4_3:
|
2021-04-04 15:13:21 -07:00
|
|
|
return order_1_8_7_2_6_5_4_3;
|
2016-06-05 17:03:16 -07:00
|
|
|
case FO_1_5_4_2_6_3_7_8:
|
2021-04-04 15:13:21 -07:00
|
|
|
return order_1_5_4_2_6_3_7_8;
|
2019-09-28 07:25:57 -07:00
|
|
|
case FO_1_2_7_8_4_5_6_3:
|
2021-04-04 15:13:21 -07:00
|
|
|
return order_1_2_7_8_4_5_6_3;
|
2020-04-29 13:46:59 -07:00
|
|
|
case FO_1_3_7_2_6_5_4_8:
|
2021-04-04 15:13:21 -07:00
|
|
|
return order_1_3_7_2_6_5_4_8;
|
2021-03-05 16:28:17 -08:00
|
|
|
case FO_1_2_3_4_5_6_7_8:
|
2021-04-04 15:13:21 -07:00
|
|
|
return order_1_2_3_4_5_6_7_8;
|
2021-03-05 16:28:17 -08:00
|
|
|
case FO_1_5_4_8_6_3_7_2:
|
2021-04-04 15:13:21 -07:00
|
|
|
return order_1_5_4_8_6_3_7_2;
|
2021-07-20 18:16:51 -07:00
|
|
|
case FO_1_8_7_3_6_5_4_2:
|
|
|
|
return order_1_8_7_3_6_5_4_2;
|
2024-01-11 09:49:49 -08:00
|
|
|
case FO_1_5_4_8_3_7_2_6:
|
|
|
|
return order_1_5_4_8_3_7_2_6;
|
2024-04-11 08:19:09 -07:00
|
|
|
case FO_1_8_6_2_7_3_4_5:
|
|
|
|
return order_1_5_4_8_3_7_2_6;
|
2020-04-29 13:46:59 -07:00
|
|
|
|
2021-03-05 16:28:17 -08:00
|
|
|
// 9 cylinder
|
2020-04-29 13:46:59 -07:00
|
|
|
case FO_1_2_3_4_5_6_7_8_9:
|
2021-04-04 15:13:21 -07:00
|
|
|
return order_1_2_3_4_5_6_7_8_9;
|
2020-04-29 13:46:59 -07:00
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2017-02-07 22:03:36 -08:00
|
|
|
// 10 cylinder
|
|
|
|
case FO_1_10_9_4_3_6_5_8_7_2:
|
2021-04-04 15:13:21 -07:00
|
|
|
return order_1_10_9_4_3_6_5_8_7_2;
|
2024-04-01 09:16:45 -07:00
|
|
|
case FO_1_6_5_10_2_7_3_8_4_9:
|
|
|
|
return order_1_6_5_10_2_7_3_8_4_9;
|
2017-02-07 22:03:36 -08:00
|
|
|
|
|
|
|
// 12 cylinder
|
|
|
|
case FO_1_7_5_11_3_9_6_12_2_8_4_10:
|
2021-04-04 15:13:21 -07:00
|
|
|
return order_1_7_5_11_3_9_6_12_2_8_4_10;
|
2017-06-08 17:35:42 -07:00
|
|
|
case FO_1_7_4_10_2_8_6_12_3_9_5_11:
|
2021-04-04 15:13:21 -07:00
|
|
|
return order_1_7_4_10_2_8_6_12_3_9_5_11;
|
2019-09-14 11:47:22 -07:00
|
|
|
case FO_1_12_5_8_3_10_6_7_2_11_4_9:
|
2021-04-04 15:13:21 -07:00
|
|
|
return order_1_12_5_8_3_10_6_7_2_11_4_9;
|
2020-05-21 17:44:14 -07:00
|
|
|
case FO_1_2_3_4_5_6_7_8_9_10_11_12:
|
2021-04-04 15:13:21 -07:00
|
|
|
return order_1_2_3_4_5_6_7_8_9_10_11_12;
|
2017-02-07 22:03:36 -08:00
|
|
|
|
2020-05-21 15:28:35 -07:00
|
|
|
// do not ask
|
|
|
|
case FO_1_14_9_4_7_12_15_6_13_8_3_16_11_2_5_10:
|
2021-04-04 15:13:21 -07:00
|
|
|
return order_1_14_9_4_7_12_15_6_13_8_3_16_11_2_5_10;
|
2020-05-21 15:28:35 -07:00
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
default:
|
2023-04-28 21:13:13 -07:00
|
|
|
firmwareError(ObdCode::CUSTOM_OBD_UNKNOWN_FIRING_ORDER, "Invalid firing order: %d", engineConfiguration->firingOrder);
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
2021-04-04 15:13:21 -07:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param index from zero to cylindersCount - 1
|
|
|
|
* @return cylinderId from one to cylindersCount
|
|
|
|
*/
|
2024-02-28 21:26:07 -08:00
|
|
|
size_t getFiringOrderCylinderId(size_t index) {
|
2022-03-22 13:53:24 -07:00
|
|
|
const size_t firingOrderLength = getFiringOrderLength();
|
2021-04-04 15:13:21 -07:00
|
|
|
|
2021-07-06 17:14:08 -07:00
|
|
|
if (firingOrderLength < 1 || firingOrderLength > MAX_CYLINDER_COUNT) {
|
2023-04-28 21:13:13 -07:00
|
|
|
firmwareError(ObdCode::CUSTOM_FIRING_LENGTH, "fol %d", firingOrderLength);
|
2021-04-04 15:13:21 -07:00
|
|
|
return 1;
|
|
|
|
}
|
2023-04-28 18:01:08 -07:00
|
|
|
if (engineConfiguration->cylindersCount != firingOrderLength) {
|
2021-04-04 15:13:21 -07:00
|
|
|
// May 2020 this somehow still happens with functional tests, maybe race condition?
|
2023-04-28 21:13:13 -07:00
|
|
|
firmwareError(ObdCode::CUSTOM_OBD_WRONG_FIRING_ORDER, "Wrong cyl count for firing order, expected %d cylinders", firingOrderLength);
|
2021-04-04 15:13:21 -07:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2022-03-22 13:53:24 -07:00
|
|
|
if (index >= firingOrderLength) {
|
2021-04-04 15:13:21 -07:00
|
|
|
// May 2020 this somehow still happens with functional tests, maybe race condition?
|
2023-04-28 21:13:13 -07:00
|
|
|
warning(ObdCode::CUSTOM_ERR_6686, "firing order index %d", index);
|
2021-04-04 15:13:21 -07:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2022-03-22 13:53:24 -07:00
|
|
|
if (auto firingOrderTable = getFiringOrderTable()) {
|
2021-04-04 15:13:21 -07:00
|
|
|
return firingOrderTable[index];
|
2022-03-22 13:53:24 -07:00
|
|
|
} else {
|
|
|
|
// error already reported
|
|
|
|
return 1;
|
|
|
|
}
|
2021-04-04 15:13:21 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param prevCylinderId from one to cylindersCount
|
|
|
|
* @return cylinderId from one to cylindersCount
|
|
|
|
*/
|
2022-03-22 13:53:24 -07:00
|
|
|
size_t getNextFiringCylinderId(size_t prevCylinderId) {
|
|
|
|
const size_t firingOrderLength = getFiringOrderLength();
|
|
|
|
auto firingOrderTable = getFiringOrderTable();
|
2021-04-04 15:13:21 -07:00
|
|
|
|
|
|
|
if (firingOrderTable) {
|
2022-03-22 13:53:24 -07:00
|
|
|
for (size_t i = 0; i < firingOrderLength; i++) {
|
|
|
|
if (firingOrderTable[i] == prevCylinderId) {
|
2021-04-04 15:13:21 -07:00
|
|
|
return firingOrderTable[(i + 1) % firingOrderLength];
|
2022-03-22 13:53:24 -07:00
|
|
|
}
|
|
|
|
}
|
2021-04-04 15:13:21 -07:00
|
|
|
}
|
2022-03-22 13:53:24 -07:00
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2019-01-20 08:33:40 -08:00
|
|
|
/**
|
|
|
|
* @return IM_WASTED_SPARK if in SPINNING mode and IM_INDIVIDUAL_COILS setting
|
2021-11-17 00:54:21 -08:00
|
|
|
* @return engineConfiguration->ignitionMode otherwise
|
2019-01-20 08:33:40 -08:00
|
|
|
*/
|
2021-11-16 01:15:29 -08:00
|
|
|
ignition_mode_e getCurrentIgnitionMode() {
|
2021-11-17 00:54:21 -08:00
|
|
|
ignition_mode_e ignitionMode = engineConfiguration->ignitionMode;
|
2019-04-12 19:07:03 -07:00
|
|
|
#if EFI_SHAFT_POSITION_INPUT
|
2022-06-09 14:21:22 -07:00
|
|
|
// In spin-up cranking mode we don't have full phase sync info yet, so wasted spark mode is better
|
2024-08-31 11:26:12 -07:00
|
|
|
if (ignitionMode == IM_INDIVIDUAL_COILS) {
|
2024-01-11 09:49:49 -08:00
|
|
|
bool missingPhaseInfoForSequential =
|
2022-06-09 14:21:22 -07:00
|
|
|
!engine->triggerCentral.triggerState.hasSynchronizedPhase();
|
|
|
|
|
2023-11-12 22:58:25 -08:00
|
|
|
if (!engineConfiguration->oddFireEngine && (engine->rpmCalculator.isSpinningUp() || missingPhaseInfoForSequential)) {
|
2022-06-09 14:21:22 -07:00
|
|
|
ignitionMode = IM_WASTED_SPARK;
|
|
|
|
}
|
|
|
|
}
|
2019-01-31 14:55:23 -08:00
|
|
|
#endif /* EFI_SHAFT_POSITION_INPUT */
|
2018-03-10 17:58:51 -08:00
|
|
|
return ignitionMode;
|
|
|
|
}
|
|
|
|
|
2019-04-12 19:07:03 -07:00
|
|
|
#if EFI_ENGINE_CONTROL
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2016-01-14 21:01:42 -08:00
|
|
|
/**
|
|
|
|
* This heavy method is only invoked in case of a configuration change or initialization.
|
|
|
|
*/
|
2021-11-16 01:15:29 -08:00
|
|
|
void prepareOutputSignals() {
|
2024-08-31 11:26:12 -07:00
|
|
|
auto operationMode = getEngineRotationState()->getOperationMode();
|
|
|
|
getEngineState()->engineCycle = getEngineCycle(operationMode);
|
|
|
|
|
|
|
|
bool isOddFire = false;
|
|
|
|
for (size_t i = 0; i < engineConfiguration->cylindersCount; i++) {
|
|
|
|
if (engineConfiguration->timing_offset_cylinder[i] != 0) {
|
|
|
|
isOddFire = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Use odd fire wasted spark logic if not two stroke, and an odd fire or odd cylinder # engine
|
|
|
|
getEngineState()->useOddFireWastedSpark = operationMode != TWO_STROKE
|
|
|
|
&& (isOddFire | (engineConfiguration->cylindersCount % 2 == 1));
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2016-10-31 19:02:12 -07:00
|
|
|
#if EFI_UNIT_TEST
|
2019-08-24 22:15:18 -07:00
|
|
|
if (verboseMode) {
|
2022-11-08 18:48:39 -08:00
|
|
|
printf("prepareOutputSignals %d %s\r\n", engineConfiguration->trigger.type, getIgnition_mode_e(engineConfiguration->ignitionMode));
|
2019-08-24 22:15:18 -07:00
|
|
|
}
|
2018-03-03 06:11:49 -08:00
|
|
|
#endif /* EFI_UNIT_TEST */
|
2016-10-31 19:02:12 -07:00
|
|
|
|
2022-12-17 11:36:27 -08:00
|
|
|
#if EFI_SHAFT_POSITION_INPUT
|
2022-11-05 19:30:08 -07:00
|
|
|
engine->triggerCentral.prepareTriggerShape();
|
2022-12-17 11:36:27 -08:00
|
|
|
#endif // EFI_SHAFT_POSITION_INPUT
|
2021-01-11 05:01:54 -08:00
|
|
|
|
|
|
|
// Fuel schedule may now be completely wrong, force a reset
|
2021-11-17 00:54:21 -08:00
|
|
|
engine->injectionEvents.invalidate();
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2023-04-12 12:04:04 -07:00
|
|
|
angle_t getPerCylinderFiringOrderOffset(uint8_t cylinderIndex, uint8_t cylinderNumber) {
|
2021-12-05 07:46:35 -08:00
|
|
|
// base = position of this cylinder in the firing order.
|
|
|
|
// We get a cylinder every n-th of an engine cycle where N is the number of cylinders
|
2023-04-28 18:01:08 -07:00
|
|
|
auto firingOrderOffset = engine->engineState.engineCycle * cylinderIndex / engineConfiguration->cylindersCount;
|
2021-12-05 07:46:35 -08:00
|
|
|
|
2024-03-24 18:45:03 -07:00
|
|
|
// Plus or minus any adjustment if this is an odd-fire engine
|
|
|
|
auto adjustment = engineConfiguration->timing_offset_cylinder[cylinderNumber];
|
2021-12-05 07:46:35 -08:00
|
|
|
|
2024-03-24 18:45:03 -07:00
|
|
|
auto result = firingOrderOffset + adjustment;
|
|
|
|
|
|
|
|
assertAngleRange(result, "getCylinderAngle", ObdCode::CUSTOM_ERR_CYL_ANGLE);
|
|
|
|
|
|
|
|
return result;
|
2021-12-05 07:46:35 -08:00
|
|
|
}
|
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
void setTimingRpmBin(float from, float to) {
|
2016-01-21 19:01:31 -08:00
|
|
|
setRpmBin(config->ignitionRpmBins, IGN_RPM_COUNT, from, to);
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* this method sets algorithm and ignition table scale
|
|
|
|
*/
|
2021-11-16 01:15:29 -08:00
|
|
|
void setAlgorithm(engine_load_mode_e algo) {
|
2016-08-28 13:02:34 -07:00
|
|
|
engineConfiguration->fuelAlgorithm = algo;
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
2016-07-24 20:02:52 -07:00
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
void setFlatInjectorLag(float value) {
|
2019-11-22 20:27:24 -08:00
|
|
|
setArrayValues(engineConfiguration->injector.battLagCorr, value);
|
2016-07-24 20:02:52 -07:00
|
|
|
}
|
2020-02-26 15:16:35 -08:00
|
|
|
|
2022-10-19 03:42:22 -07:00
|
|
|
BlendResult calculateBlend(blend_table_s& cfg, float rpm, float load) {
|
|
|
|
// If set to 0, skip the math as its disabled
|
|
|
|
if (cfg.blendParameter == GPPWM_Zero) {
|
2023-04-29 23:01:00 -07:00
|
|
|
return { 0, 0, 0 };
|
2022-10-19 03:42:22 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
auto value = readGppwmChannel(cfg.blendParameter);
|
|
|
|
|
|
|
|
if (!value) {
|
2023-04-02 13:50:34 -07:00
|
|
|
return { 0, 0, 0 };
|
2022-10-19 03:42:22 -07:00
|
|
|
}
|
|
|
|
|
2024-01-17 02:43:04 -08:00
|
|
|
// Override Y axis value (if necessary)
|
|
|
|
if (cfg.yAxisOverride != GPPWM_Zero) {
|
|
|
|
// TODO: is this value_or(0) correct or even reasonable?
|
|
|
|
load = readGppwmChannel(cfg.yAxisOverride).value_or(0);
|
|
|
|
}
|
|
|
|
|
2022-10-19 03:42:22 -07:00
|
|
|
float tableValue = interpolate3d(
|
|
|
|
cfg.table,
|
|
|
|
cfg.loadBins, load,
|
|
|
|
cfg.rpmBins, rpm
|
|
|
|
);
|
|
|
|
|
|
|
|
float blendFactor = interpolate2d(value.Value, cfg.blendBins, cfg.blendValues);
|
|
|
|
|
2023-04-02 13:50:34 -07:00
|
|
|
return { value.Value, blendFactor, 0.01f * blendFactor * tableValue };
|
2022-10-19 03:42:22 -07:00
|
|
|
}
|
|
|
|
|
2020-02-26 15:16:35 -08:00
|
|
|
#endif /* EFI_ENGINE_CONTROL */
|