Skip to content

Commit b99c289

Browse files
committed
Implement Activation RPM, Deactivation RPM and Deactivation RPM Window settings rusefi#6783
1 parent f6d333b commit b99c289

14 files changed

+239
-6
lines changed

firmware/controllers/algo/engine_configuration_defaults.h

+3
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,7 @@ namespace engine_configuration_defaults {
6363
constexpr uint8_t NITROUS_MINIMUM_CLT = 0;
6464
constexpr uint16_t NITROUS_MAXIMUM_MAP = 0;
6565
constexpr float NITROUS_MAXIMUM_AFR = 0.0f;
66+
constexpr uint16_t NITROUS_ACTIVATION_RPM = 0;
67+
constexpr uint16_t NITROUS_DEACTIVATION_RPM = 0;
68+
constexpr uint16_t NITROUS_DEACTIVATION_RPM_WINDOW = 0;
6669
}

firmware/controllers/algo/nitrous_control_state.txt

+1
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ bit isTpsConditionSatisfied
55
bit isCltConditionSatisfied
66
bit isMapConditionSatisfied
77
bit isAfrConditionSatisfied
8+
bit isNitrousRpmConditionSatisfied
89

910
end_struct

firmware/controllers/algo/nitrous_controller.cpp

+23
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ void NitrousController::update() {
1414
updateCltConditionSatisfied();
1515
updateMapConditionSatisfied();
1616
updateAfrConditionSatisfied();
17+
updateRpmConditionSatisfied();
1718
}
1819
}
1920

@@ -75,6 +76,28 @@ void NitrousController::updateAfrConditionSatisfied() {
7576
}
7677
}
7778

79+
namespace {
80+
MaxLimitWithHysteresis rpmHysteresis;
81+
}
82+
83+
void NitrousController::updateRpmConditionSatisfied() {
84+
const expected<float> rpmSensorReading = Sensor::get(SensorType::Rpm);
85+
if (rpmSensorReading.Valid) {
86+
const float rpm = rpmSensorReading.Value;
87+
if (rpmHysteresis.checkIfLimitIsExceeded(
88+
rpm,
89+
engineConfiguration->nitrousDeactivationRpm - 1,
90+
engineConfiguration->nitrousDeactivationRpmWindow - 1
91+
)) {
92+
isNitrousRpmConditionSatisfied = false;
93+
} else {
94+
isNitrousRpmConditionSatisfied = (engineConfiguration->nitrousActivationRpm <= rpm);
95+
}
96+
} else {
97+
isNitrousRpmConditionSatisfied = false;
98+
}
99+
}
100+
78101
bool NitrousController::checkTriggerPinState() const {
79102
bool result = false;
80103
#if !EFI_SIMULATOR

firmware/controllers/algo/nitrous_controller.h

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class NitrousController : public nitrous_control_state_s {
1515
void updateCltConditionSatisfied();
1616
void updateMapConditionSatisfied();
1717
void updateAfrConditionSatisfied();
18+
void updateRpmConditionSatisfied();
1819

1920
bool checkTriggerPinState() const;
2021
bool checkLuaGauge() const;

firmware/integration/rusefi_config.txt

+5-1
Original file line numberDiff line numberDiff line change
@@ -1789,7 +1789,11 @@ uint8_t autoscale knockFuelTrim;Fuel trim when knock, max 30%;"%", 1, 0, 0, 30,
17891789
int16_t nitrousMaximumMap;;"kPa", 1, 0, 0, @@MAP_UPPER_LIMIT@@, 0
17901790
uint8_t autoscale nitrousMaximumAfr;;"afr", 0.1, 0, 10, 20, 1
17911791

1792-
#define END_OF_CALIBRATION_PADDING 86
1792+
uint16_t nitrousActivationRpm;;"rpm", 1, 0, 0, 20000, 0
1793+
uint16_t nitrousDeactivationRpm;;"rpm", 1, 0, 0, 20000, 0
1794+
uint16_t nitrousDeactivationRpmWindow;;"rpm", 1, 0, 0, 20000, 0
1795+
1796+
#define END_OF_CALIBRATION_PADDING 80
17931797
uint8_t[END_OF_CALIBRATION_PADDING] unusedOftenChangesDuringFirmwareUpdate;;"units", 1, 0, 0, 1, 0
17941798

17951799
! end of engine_configuration_s

firmware/tunerstudio/tunerstudio.template.ini

+7-4
Original file line numberDiff line numberDiff line change
@@ -4990,10 +4990,13 @@ dialog = tcuControls, "Transmission Settings"
49904990
panel = NitrousControlLuaGaugeDialog, {nitrousControlArmingMethod == @@nitrous_arming_method_e_LUA_GAUGE@@}
49914991

49924992
dialog = NitrousControlSettings, "Settings"
4993-
field = "Minimum TPS", nitrousMinimumTps
4994-
field = "Minimum CLT", nitrousMinimumClt
4995-
field = "Maximum MAP", nitrousMaximumMap
4996-
field = "Maximum AFR", nitrousMaximumAfr
4993+
field = "Minimum TPS", nitrousMinimumTps
4994+
field = "Minimum CLT", nitrousMinimumClt
4995+
field = "Maximum MAP", nitrousMaximumMap
4996+
field = "Maximum AFR", nitrousMaximumAfr
4997+
field = "Activation RPM", nitrousActivationRpm
4998+
field = "Dectivation RPM", nitrousDeactivationRpm
4999+
field = "Dectivation RPM Window", nitrousDeactivationRpmWindow
49975000

49985001
dialog = NitrousControlSettingsDialog, "", yAxis
49995002
field = "Enable Nitrous Control", nitrousControlEnabled
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
//
2+
// Created by kifir on 12/1/24.
3+
//
4+
5+
#include "pch.h"
6+
7+
#include "util/test_base.h"
8+
9+
namespace {
10+
struct RpmConditionTestData {
11+
const std::optional<float> rpm;
12+
const bool expectedRpmCondition;
13+
const char* const context;
14+
};
15+
16+
class NitrousRpmConditionTest : public TestBase {
17+
protected:
18+
static constexpr uint16_t TEST_ACTIVATION_RPM = 239;
19+
static constexpr uint16_t TEST_DEACTIVATION_RPM = 932;
20+
static constexpr uint16_t TEST_DEACTIVATION_RPM_WINDOW = 17;
21+
22+
void checkRpmCondition(const std::vector<RpmConditionTestData>& testData);
23+
void checkRpmConditionIsAlwaysUnsatisfied();
24+
};
25+
26+
void NitrousRpmConditionTest::checkRpmCondition(const std::vector<RpmConditionTestData>& testData) {
27+
for (const RpmConditionTestData& item: testData) {
28+
updateRpm(item.rpm);
29+
EXPECT_EQ(engine->nitrousController.isNitrousRpmConditionSatisfied, item.expectedRpmCondition)
30+
<< item.context;
31+
}
32+
}
33+
34+
void NitrousRpmConditionTest::checkRpmConditionIsAlwaysUnsatisfied() {
35+
checkRpmCondition({
36+
{ {0}, false, "rpm = 0" },
37+
{ { TEST_ACTIVATION_RPM - 1 }, false, "rpm = TEST_ACTIVATION_RPM - 1" },
38+
{ { TEST_ACTIVATION_RPM }, false, "rpm = TEST_ACTIVATION_RPM" },
39+
{ { TEST_DEACTIVATION_RPM - 1 }, false, "rpm = TEST_DEACTIVATION_RPM - 1" },
40+
{ { TEST_DEACTIVATION_RPM }, false, "rpm = TEST_DEACTIVATION_RPM" },
41+
{
42+
{ TEST_DEACTIVATION_RPM - TEST_DEACTIVATION_RPM_WINDOW },
43+
false,
44+
"rpm = TEST_DEACTIVATION_RPM - TEST_DEACTIVATION_RPM_WINDOW"
45+
},
46+
{
47+
{ TEST_DEACTIVATION_RPM - TEST_DEACTIVATION_RPM_WINDOW - 1 },
48+
false,
49+
"rpm = TEST_DEACTIVATION_RPM - TEST_DEACTIVATION_RPM_WINDOW - 1"
50+
},
51+
{
52+
{ TEST_DEACTIVATION_RPM - TEST_DEACTIVATION_RPM_WINDOW },
53+
false,
54+
"rpm = TEST_DEACTIVATION_RPM - TEST_DEACTIVATION_RPM_WINDOW (again)"
55+
},
56+
{
57+
{ TEST_DEACTIVATION_RPM - 1 },
58+
false,
59+
"rpm = TEST_DEACTIVATION_RPM - 1 (again)"
60+
},
61+
{
62+
{ TEST_DEACTIVATION_RPM },
63+
false,
64+
"rpm = TEST_DEACTIVATION_RPM (again)"
65+
},
66+
});
67+
}
68+
69+
TEST_F(NitrousRpmConditionTest, checkDefault) {
70+
checkRpmConditionIsAlwaysUnsatisfied();
71+
}
72+
73+
TEST_F(NitrousRpmConditionTest, checkDefaultWithDisabledNitrousControl) {
74+
setUpEngineConfiguration(EngineConfig().setNitrousControlEnabled({ false }));
75+
checkRpmConditionIsAlwaysUnsatisfied();
76+
}
77+
78+
TEST_F(NitrousRpmConditionTest, checkDefaultWithEnabledNitrousControl) {
79+
setUpEngineConfiguration(EngineConfig().setNitrousControlEnabled({ true }));
80+
checkRpmConditionIsAlwaysUnsatisfied();
81+
}
82+
83+
TEST_F(NitrousRpmConditionTest, checkActivationAndDeactivation) {
84+
setUpEngineConfiguration(
85+
EngineConfig()
86+
.setNitrousControlEnabled({ true })
87+
.setNitrousActivationRpm({ TEST_ACTIVATION_RPM })
88+
.setNitrousDeactivationRpm({ TEST_DEACTIVATION_RPM })
89+
.setNitrousDeactivationRpmWindow({ TEST_DEACTIVATION_RPM_WINDOW })
90+
);
91+
92+
checkRpmCondition({
93+
{ { 0 }, false, "rpm = 0" },
94+
{ { TEST_ACTIVATION_RPM - 1 }, false, "rpm = TEST_ACTIVATION_RPM - 1" },
95+
{ { TEST_ACTIVATION_RPM }, true, "rpm = TEST_ACTIVATION_RPM" },
96+
{ { TEST_DEACTIVATION_RPM - 1 }, true, "rpm = TEST_DEACTIVATION_RPM - 1" },
97+
{ { TEST_DEACTIVATION_RPM }, false, "rpm = TEST_DEACTIVATION_RPM" },
98+
{
99+
{ TEST_DEACTIVATION_RPM - TEST_DEACTIVATION_RPM_WINDOW },
100+
false,
101+
"rpm = TEST_DEACTIVATION_RPM - TEST_DEACTIVATION_RPM_WINDOW (still in window)"
102+
},
103+
{
104+
{ TEST_DEACTIVATION_RPM - TEST_DEACTIVATION_RPM_WINDOW - 1 },
105+
true,
106+
"rpm = TEST_DEACTIVATION_RPM - TEST_DEACTIVATION_RPM_WINDOW - 1"
107+
},
108+
{
109+
{ TEST_DEACTIVATION_RPM - TEST_DEACTIVATION_RPM_WINDOW },
110+
true,
111+
"rpm = TEST_DEACTIVATION_RPM - TEST_DEACTIVATION_RPM_WINDOW (returning to the window)"
112+
},
113+
{
114+
{ TEST_DEACTIVATION_RPM - 1 },
115+
true,
116+
"rpm = TEST_DEACTIVATION_RPM - 1 (again)"
117+
},
118+
{
119+
{ TEST_DEACTIVATION_RPM },
120+
false,
121+
"rpm = TEST_DEACTIVATION_RPM (again)"
122+
},
123+
});
124+
}
125+
}

unit_tests/tests/tests.mk

+1
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ TESTS_SRC_CPP = \
7676
tests/nitrous_control/test_nitrous_clt_condition.cpp \
7777
tests/nitrous_control/test_nitrous_map_condition.cpp \
7878
tests/nitrous_control/test_nitrous_afr_condition.cpp \
79+
tests/nitrous_control/test_nitrous_rpm_condition.cpp \
7980
tests/test_fft.cpp \
8081
tests/lua/test_lua_basic.cpp \
8182
tests/lua/test_bit_range_msb.cpp \

unit_tests/tests/util/engine_config.cpp

+16-1
Original file line numberDiff line numberDiff line change
@@ -237,4 +237,19 @@ EngineConfig EngineConfig::setNitrousMaximumMap(const std::optional<uint16_t> va
237237
EngineConfig EngineConfig::setNitrousMaximumAfr(const std::optional<float> value) {
238238
m_nitrousMaximumAfr = value;
239239
return *this;
240-
}
240+
}
241+
242+
EngineConfig EngineConfig::setNitrousActivationRpm(const std::optional<uint16_t> value) {
243+
m_nitrousActivationRpm = value;
244+
return *this;
245+
}
246+
247+
EngineConfig EngineConfig::setNitrousDeactivationRpm(const std::optional<uint16_t> value) {
248+
m_nitrousDeactivationRpm = value;
249+
return *this;
250+
}
251+
252+
EngineConfig EngineConfig::setNitrousDeactivationRpmWindow(const std::optional<uint16_t> value) {
253+
m_nitrousDeactivationRpmWindow = value;
254+
return *this;
255+
}

unit_tests/tests/util/engine_config.h

+9
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ class EngineConfig {
7373
std::optional<uint8_t> getNitrousMinimumClt() const { return m_nitrousMinimumClt; }
7474
std::optional<uint16_t> getNitrousMaximumMap() const { return m_nitrousMaximumMap; }
7575
std::optional<float> getNitrousMaximumAfr() const { return m_nitrousMaximumAfr; }
76+
std::optional<uint16_t> getNitrousActivationRpm() const { return m_nitrousActivationRpm; }
77+
std::optional<uint16_t> getNitrousDeactivationRpm() const { return m_nitrousDeactivationRpm; }
78+
std::optional<uint16_t> getNitrousDeactivationRpmWindow() const { return m_nitrousDeactivationRpmWindow; }
7679

7780
// We do not core about performance in tests, but we want to use builder-like style, so setters return new instance
7881
// of configuration:
@@ -135,6 +138,9 @@ class EngineConfig {
135138
EngineConfig setNitrousMinimumClt(std::optional<uint8_t> value);
136139
EngineConfig setNitrousMaximumMap(std::optional<uint16_t> value);
137140
EngineConfig setNitrousMaximumAfr(std::optional<float> value);
141+
EngineConfig setNitrousActivationRpm(std::optional<uint16_t> value);
142+
EngineConfig setNitrousDeactivationRpm(std::optional<uint16_t> value);
143+
EngineConfig setNitrousDeactivationRpmWindow(std::optional<uint16_t> value);
138144
private:
139145
// Launch Control
140146
std::optional<switch_input_pin_e> m_launchActivatePin;
@@ -194,4 +200,7 @@ class EngineConfig {
194200
std::optional<uint8_t> m_nitrousMinimumClt;
195201
std::optional<uint16_t> m_nitrousMaximumMap;
196202
std::optional<float> m_nitrousMaximumAfr;
203+
std::optional<uint16_t> m_nitrousActivationRpm;
204+
std::optional<uint16_t> m_nitrousDeactivationRpm;
205+
std::optional<uint16_t> m_nitrousDeactivationRpmWindow;
197206
};

unit_tests/tests/util/test_base.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,11 @@ void TestBase::setUpEngineConfiguration(const EngineConfig& config) {
9191
getTestEngineConfiguration().configureNitrousMinimumClt(config.getNitrousMinimumClt());
9292
getTestEngineConfiguration().configureNitrousMaximumMap(config.getNitrousMaximumMap());
9393
getTestEngineConfiguration().configureNitrousMaximumAfr(config.getNitrousMaximumAfr());
94+
getTestEngineConfiguration().configureNitrousActivationRpm(config.getNitrousActivationRpm());
95+
getTestEngineConfiguration().configureNitrousDeactivationRpm(config.getNitrousDeactivationRpm());
96+
getTestEngineConfiguration().configureNitrousDeactivationRpmWindow(
97+
config.getNitrousDeactivationRpmWindow()
98+
);
9499
}
95100

96101
void TestBase::periodicFastCallback() {
@@ -107,6 +112,10 @@ void TestBase::updateRpm(const float rpm) {
107112
periodicFastCallback();
108113
}
109114

115+
void TestBase::updateRpm(const std::optional<float> rpm) {
116+
updateSensor(SensorType::Rpm, rpm);
117+
}
118+
110119
void TestBase::updateApp(const std::optional<float> app) {
111120
updateSensor(SensorType::DriverThrottleIntent, app);
112121
}

unit_tests/tests/util/test_base.h

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class TestBase : public testing::Test {
2424
void periodicSlowCallback();
2525

2626
void updateRpm(float rpm);
27+
void updateRpm(std::optional<float> rpm);
2728
void updateApp(std::optional<float> app);
2829
void updateClt(std::optional<float> clt);
2930
void updateMap(std::optional<float> map);

unit_tests/tests/util/test_engine_configuration.cpp

+35
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,41 @@ void TestEngineConfiguration::configureNitrousMaximumAfr(const std::optional<flo
521521
}
522522
}
523523

524+
void TestEngineConfiguration::configureNitrousActivationRpm(const std::optional<uint16_t> nitrousActivationRpm) {
525+
if (nitrousActivationRpm.has_value()) {
526+
engineConfiguration->nitrousActivationRpm = nitrousActivationRpm.value();
527+
} else {
528+
ASSERT_EQ(
529+
engineConfiguration->nitrousActivationRpm,
530+
engine_configuration_defaults::NITROUS_ACTIVATION_RPM
531+
); // check default value
532+
}
533+
}
534+
535+
void TestEngineConfiguration::configureNitrousDeactivationRpm(const std::optional<uint16_t> nitrousDeactivationRpm) {
536+
if (nitrousDeactivationRpm.has_value()) {
537+
engineConfiguration->nitrousDeactivationRpm = nitrousDeactivationRpm.value();
538+
} else {
539+
ASSERT_EQ(
540+
engineConfiguration->nitrousDeactivationRpm,
541+
engine_configuration_defaults::NITROUS_DEACTIVATION_RPM
542+
); // check default value
543+
}
544+
}
545+
546+
void TestEngineConfiguration::configureNitrousDeactivationRpmWindow(
547+
const std::optional<uint16_t> nitrousDeactivationRpmWindow
548+
) {
549+
if (nitrousDeactivationRpmWindow.has_value()) {
550+
engineConfiguration->nitrousDeactivationRpmWindow = nitrousDeactivationRpmWindow.value();
551+
} else {
552+
ASSERT_EQ(
553+
engineConfiguration->nitrousDeactivationRpmWindow,
554+
engine_configuration_defaults::NITROUS_DEACTIVATION_RPM_WINDOW
555+
); // check default value
556+
}
557+
}
558+
524559
TestEngineConfiguration::TestEngineConfiguration() {
525560
}
526561

unit_tests/tests/util/test_engine_configuration.h

+3
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ class TestEngineConfiguration {
7676
void configureNitrousMinimumClt(std::optional<uint8_t> nitrousMinimumClt);
7777
void configureNitrousMaximumMap(std::optional<uint16_t> nitrousMaximumMap);
7878
void configureNitrousMaximumAfr(std::optional<float> nitrousMaximumAfr);
79+
void configureNitrousActivationRpm(std::optional<uint16_t> nitrousActivationRpm);
80+
void configureNitrousDeactivationRpm(std::optional<uint16_t> nitrousDeactivationRpm);
81+
void configureNitrousDeactivationRpmWindow(std::optional<uint16_t> nitrousDeactivationRpmWindow);
7982
private:
8083
TestEngineConfiguration();
8184
static TestEngineConfiguration instance;

0 commit comments

Comments
 (0)