diff --git a/firmware/controllers/algo/rusefi_types.h b/firmware/controllers/algo/rusefi_types.h index 4b92e6a9e0..990a6dc5c5 100644 --- a/firmware/controllers/algo/rusefi_types.h +++ b/firmware/controllers/algo/rusefi_types.h @@ -96,7 +96,7 @@ typedef brain_pin_e egt_cs_array_t[EGT_CHANNEL_COUNT]; #if __cplusplus #include "scaled_channel.h" -using ve_table_t = scaled_channel[FUEL_LOAD_COUNT][FUEL_RPM_COUNT]; +using ve_table_t = float[FUEL_LOAD_COUNT][FUEL_RPM_COUNT]; using lambda_table_t = scaled_channel[FUEL_LOAD_COUNT][FUEL_RPM_COUNT]; #endif diff --git a/firmware/util/containers/table_helper.h b/firmware/util/containers/table_helper.h index 786d9a1ecd..2d9da8c9c9 100644 --- a/firmware/util/containers/table_helper.h +++ b/firmware/util/containers/table_helper.h @@ -152,17 +152,8 @@ void setArrayValues(TValue (&array)[TSize], TValue value) { } } -template -constexpr void setTable(TElement (&dest)[N][M], const TElement value) { - for (size_t n = 0; n < N; n++) { - for (size_t m = 0; m < M; m++) { - dest[n][m] = value; - } - } -} - -template -constexpr void setTable(scaled_channel (&dest)[N][M], float value) { +template +constexpr void setTable(TElement (&dest)[N][M], const VElement value) { for (size_t n = 0; n < N; n++) { for (size_t m = 0; m < M; m++) { dest[n][m] = value; diff --git a/firmware/util/scaled_channel.h b/firmware/util/scaled_channel.h index cec212f00b..d8219defd9 100644 --- a/firmware/util/scaled_channel.h +++ b/firmware/util/scaled_channel.h @@ -11,6 +11,7 @@ #pragma once +#include #include #include @@ -26,29 +27,36 @@ static constexpr bool is_scaled_channel = std::is_base_of_v myVar; // myVar = 2.4f; // converts to an int, stores 24 // float x = myVar; // converts back to float, returns 2.4f -template +template class scaled_channel : scaled_channel_base { - using TSelf = scaled_channel; + using TSelf = scaled_channel; public: constexpr scaled_channel() : m_value(static_cast(0)) { } constexpr scaled_channel(float val) - : m_value(val * mult) { + val *= float(mul) / div; + if (std::is_integral_v) { + m_value = std::roundf(val); + } else { + m_value = val; + } } // Allow reading back out as a float (note: this may be lossy!) constexpr operator float() const { - return m_value / (float)mult; + return m_value * (float(div) / mul); } - // Postfix increment operator + // Postfix increment operator // only enable if: // - base type T is an integral type (integer) // - multiplier is equal to 1 void operator++(int) { - static_assert(mult == 1, "Increment operator only supported for non-scaled integer types"); + static_assert(mul == 1 && div == 1, + "Increment operator only supported for non-scaled integer types"); static_assert(std::is_integral_v, "Increment operator only supported for non-scaled integer types"); + m_value++; } diff --git a/unit_tests/tests/tests.mk b/unit_tests/tests/tests.mk index 02bbb94854..c767160fca 100644 --- a/unit_tests/tests/tests.mk +++ b/unit_tests/tests/tests.mk @@ -28,6 +28,7 @@ TESTS_SRC_CPP = \ tests/lua/test_lua_hooks.cpp \ tests/sensor/test_cj125.cpp \ tests/test_change_engine_type.cpp \ + tests/util/test_scaled_channel.cpp \ tests/util/test_timer.cpp \ tests/system/test_periodic_thread_controller.cpp \ tests/test_util.cpp \ @@ -89,6 +90,3 @@ TESTS_SRC_CPP = \ tests/sensor/test_frequency_sensor.cpp \ tests/sensor/test_turbocharger_speed_converter.cpp \ tests/sensor/test_vehicle_speed_converter.cpp - - - diff --git a/unit_tests/tests/util/test_scaled_channel.cpp b/unit_tests/tests/util/test_scaled_channel.cpp new file mode 100644 index 0000000000..af199d0fac --- /dev/null +++ b/unit_tests/tests/util/test_scaled_channel.cpp @@ -0,0 +1,34 @@ +#include "pch.h" + +#include "boost_control.h" + +using ::testing::_; +using ::testing::StrictMock; + +TEST(ScaledChannel, Basic) { + { + scaled_channel i1; + i1 = 10; EXPECT_FLOAT_EQ(i1, 10); + i1 = 1; EXPECT_FLOAT_EQ(i1, 1); + i1 = 0.11; EXPECT_FLOAT_EQ(i1, 0.1); // round + i1 = 0.1; EXPECT_FLOAT_EQ(i1, 0.1); + i1 = 0.09; EXPECT_FLOAT_EQ(i1, 0.1); // round + i1 = 0.01; EXPECT_FLOAT_EQ(i1, 0.); // out of range + i1 = -0.09; EXPECT_FLOAT_EQ(i1, -0.1); // round + i1 = -0.1; EXPECT_FLOAT_EQ(i1, -0.1); + i1 = -0.11; EXPECT_FLOAT_EQ(i1, -0.1); // round + } + + { + scaled_channel i2; + i2 = 1000; EXPECT_FLOAT_EQ(i2, 1000); + i2 = 100; EXPECT_FLOAT_EQ(i2, 100); + i2 = 11; EXPECT_FLOAT_EQ(i2, 10); // round + i2 = 10; EXPECT_FLOAT_EQ(i2, 10); + i2 = 9; EXPECT_FLOAT_EQ(i2, 10); // round + i2 = 1; EXPECT_FLOAT_EQ(i2, 0); // out of range + i2 = -9; EXPECT_FLOAT_EQ(i2, -10); // round + i2 = -10; EXPECT_FLOAT_EQ(i2, -10); + i2 = -11; EXPECT_FLOAT_EQ(i2, -10); // round + } +}