From ba2c675ffaed407f21d966ce1a5f6408161336d6 Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Sun, 27 Dec 2020 14:22:11 -0800 Subject: [PATCH] progress to fsio type safety (#2137) * rename * packed type safe fsio value * comment * rename Co-authored-by: Matthew Kennedy --- firmware/controllers/core/fsio_core.cpp | 38 ++++++++++++++++++++++ firmware/controllers/core/fsio_core.h | 25 ++++++++++++++ unit_tests/tests/test_logic_expression.cpp | 36 ++++++++++++++++++++ 3 files changed, 99 insertions(+) diff --git a/firmware/controllers/core/fsio_core.cpp b/firmware/controllers/core/fsio_core.cpp index ad8e2fa9a2..216762e8fc 100644 --- a/firmware/controllers/core/fsio_core.cpp +++ b/firmware/controllers/core/fsio_core.cpp @@ -442,4 +442,42 @@ LEElement *LEElementPool::parseExpression(const char * line) { } } +FsioValue::FsioValue(float f) +{ + u.f32 = f; + + // The low bit represents whether this is a bool or not, clear it for float + u.u32 &= 0xFFFFFFFE; +} + +FsioValue::FsioValue(bool b) +{ + u.u32 = (b ? 2 : 0); // second bit is the actual value of the bool + + // Low bit indicates this is a bool + u.u32 |= 0x1; +} + +bool FsioValue::isFloat() const { + uint32_t typeBit = u.u32 & 0x1; + + return typeBit == 0; +} + +float FsioValue::asFloat() const { + return u.f32; +} + +bool FsioValue::isBool() const { + uint32_t typeBit = u.u32 & 0x1; + + return typeBit == 1; +} + +bool FsioValue::asBool() const { + uint32_t boolBit = u.u32 & 0x2; + + return boolBit != 0; +} + #endif /* EFI_FSIO */ diff --git a/firmware/controllers/core/fsio_core.h b/firmware/controllers/core/fsio_core.h index bf17de6759..b220517aaa 100644 --- a/firmware/controllers/core/fsio_core.h +++ b/firmware/controllers/core/fsio_core.h @@ -64,6 +64,31 @@ typedef enum { } le_action_e; +// This type borrows the least significant bit of a float and uses it to indicate +// whether it's actually a boolean hiding inside that float +class FsioValue +{ +public: + /*implicit*/ FsioValue(float f); + /*implicit*/ FsioValue(bool b); + + bool isFloat() const; + float asFloat() const; + + bool isBool() const; + bool asBool() const; + +private: + // These must match for this trick to work! + static_assert(sizeof(float) == sizeof(uint32_t)); + + union + { + uint32_t u32; + float f32; + } u; +}; + using FsioResult = expected; class LEElement { diff --git a/unit_tests/tests/test_logic_expression.cpp b/unit_tests/tests/test_logic_expression.cpp index 5380140f6d..25e444c071 100644 --- a/unit_tests/tests/test_logic_expression.cpp +++ b/unit_tests/tests/test_logic_expression.cpp @@ -342,3 +342,39 @@ TEST(fsio, fuelPump) { // Pump should be on! EXPECT_TRUE(efiReadPin(GPIOA_0)); } + +TEST(fsio, fsioValueFloat) { + FsioValue floatVal(3.5f); + + EXPECT_TRUE(floatVal.isFloat()); + EXPECT_FALSE(floatVal.isBool()); + + EXPECT_FLOAT_EQ(floatVal.asFloat(), 3.5f); +} + +TEST(fsio, fsioValueFloatZero) { + FsioValue floatVal(0.0f); + + EXPECT_TRUE(floatVal.isFloat()); + EXPECT_FALSE(floatVal.isBool()); + + EXPECT_FLOAT_EQ(floatVal.asFloat(), 0); +} + +TEST(fsio, fsioValueBoolTrue) { + FsioValue boolVal(true); + + EXPECT_TRUE(boolVal.isBool()); + EXPECT_FALSE(boolVal.isFloat()); + + EXPECT_TRUE(boolVal.asBool()); +} + +TEST(fsio, fsioValueBoolFalse) { + FsioValue boolVal(false); + + EXPECT_TRUE(boolVal.isBool()); + EXPECT_FALSE(boolVal.isFloat()); + + EXPECT_FALSE(boolVal.asBool()); +}