Allow scaled_channel to have both multiplier and divisor (#3468)
Disallow scaled_channel for float. I can't think of a reason to allow it, and it gets in the way of rounding. Add separate template param to setTable; let the compiler sort out whether assignment can happen between TElement and VElement without forcing them to be the same at function call time.
This commit is contained in:
parent
818e0057c9
commit
fcac26c032
|
@ -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<float, 1>[FUEL_LOAD_COUNT][FUEL_RPM_COUNT];
|
||||
using ve_table_t = float[FUEL_LOAD_COUNT][FUEL_RPM_COUNT];
|
||||
using lambda_table_t = scaled_channel<uint8_t, PACK_MULT_LAMBDA_CFG>[FUEL_LOAD_COUNT][FUEL_RPM_COUNT];
|
||||
#endif
|
||||
|
||||
|
|
|
@ -152,17 +152,8 @@ void setArrayValues(TValue (&array)[TSize], TValue value) {
|
|||
}
|
||||
}
|
||||
|
||||
template <typename TElement, size_t N, size_t M>
|
||||
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 <typename TElement, size_t N, size_t M, int mult = 1>
|
||||
constexpr void setTable(scaled_channel<TElement, mult> (&dest)[N][M], float value) {
|
||||
template <typename TElement, typename VElement, size_t N, size_t M>
|
||||
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;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
|
||||
|
@ -26,29 +27,36 @@ static constexpr bool is_scaled_channel = std::is_base_of_v<scaled_channel_base,
|
|||
// scaled_channel<uint8_t, 10> myVar;
|
||||
// myVar = 2.4f; // converts to an int, stores 24
|
||||
// float x = myVar; // converts back to float, returns 2.4f
|
||||
template <typename T, int mult = 1>
|
||||
template <typename T, int mul = 1, int div = 1>
|
||||
class scaled_channel : scaled_channel_base {
|
||||
using TSelf = scaled_channel<T, mult>;
|
||||
using TSelf = scaled_channel<T, mul, div>;
|
||||
|
||||
public:
|
||||
constexpr scaled_channel() : m_value(static_cast<T>(0)) { }
|
||||
constexpr scaled_channel(float val)
|
||||
: m_value(val * mult)
|
||||
{
|
||||
val *= float(mul) / div;
|
||||
if (std::is_integral_v<T>) {
|
||||
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<T>, "Increment operator only supported for non-scaled integer types");
|
||||
|
||||
|
||||
m_value++;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
#include "pch.h"
|
||||
|
||||
#include "boost_control.h"
|
||||
|
||||
using ::testing::_;
|
||||
using ::testing::StrictMock;
|
||||
|
||||
TEST(ScaledChannel, Basic) {
|
||||
{
|
||||
scaled_channel<int16_t, 10> 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<int16_t, 1, 10> 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
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue