From 22203c795e11e1e4269f3677c39509abd2ecb601 Mon Sep 17 00:00:00 2001 From: Tao Date: Mon, 11 Nov 2024 08:20:56 +0000 Subject: [PATCH] sbus_output: handle reversed min/max config Deal with min > max in config. Althought this is not intended (i.e., the module should only "mirror" the outputs), we should still handle this gracefully. There isn't any bug in the code! So let's just add some test cases. --- src/test/unit/sbus_output_unittest.cc | 109 ++++++++++++++++++++++---- 1 file changed, 94 insertions(+), 15 deletions(-) diff --git a/src/test/unit/sbus_output_unittest.cc b/src/test/unit/sbus_output_unittest.cc index fd292c2c2..7a04d42c8 100644 --- a/src/test/unit/sbus_output_unittest.cc +++ b/src/test/unit/sbus_output_unittest.cc @@ -353,18 +353,52 @@ TEST_F(SBusOutPWMToSBusTest, OutOfBoundValues) { EXPECT_EQ(sbus, 1); } +// When config min/max is reversed (min>max) +TEST_F(SBusOutPWMToSBusTest, ReversedOutOfBoundValues) { + // Reversed min/max + sbusOutConfigMutable()->min[4] = 500; + sbusOutConfigMutable()->max[4] = -500; + sbusOutConfigMutable()->min[16] = 500; + sbusOutConfigMutable()->max[16] = -500; + + uint16_t sbus; + sbus = sbusOutConvertToSbus(4, 4000); + EXPECT_EQ(sbus, 0); + sbus = sbusOutConvertToSbus(4, -4000); + EXPECT_EQ(sbus, (1 << 11) - 1); + sbus = sbusOutConvertToSbus(16, 4000); + EXPECT_EQ(sbus, 0); + sbus = sbusOutConvertToSbus(16, -4000); + EXPECT_EQ(sbus, 1); +} + +// Test PWM [1000, 2000] convert to SBus value // Test param = PWM value class SBusOutPWMToSBusSweep : public SBusOutPWMToSBusTest, - public testing::WithParamInterface {}; + public testing::WithParamInterface { + public: + // Second source of values + // Convert value to a float between [0, 1] + static float ValueMinMaxToFloat(int value, int min, int max) { + return static_cast(value - min) / (max - min); + } + static float SBusToFloat(int sbus) { + return ValueMinMaxToFloat(sbus, 192, 1792); + } + static float Resolution(int min, int max) { + return 1.0f / (max - min); + } +}; TEST_P(SBusOutPWMToSBusSweep, FullScaleChannel) { const uint16_t pwm = GetParam(); uint16_t sbus = sbusOutConvertToSbus(3, pwm); - // sbus: [192, 1792] + + // Validate: + float sbusf = SBusToFloat(sbus); // pwm: [1000, 2000] - float sbusf = (sbus - 192.0f) / (1792 - 192 + 1); - float pwmf = (pwm - 1000.0f) / (2000 - 1000 + 1); - const float resolution = 1.0f / (2000 - 1000 + 1); + float pwmf = ValueMinMaxToFloat(pwm, 1000, 2000); + const float resolution = Resolution(1000, 2000); EXPECT_NEAR(sbusf, pwmf, resolution); } @@ -381,20 +415,22 @@ TEST_P(SBusOutPWMToSBusSweep, OnOffConversion) { INSTANTIATE_TEST_SUITE_P(PWMConversionSweep, SBusOutPWMToSBusSweep, testing::Range(1000, 2001)); +// Test Narrow PWM [500, 1000] convert to SBus value // Test param = PWM value class SBusOutNarrowbandPWMToSBusSweep : public SBusOutPWMToSBusSweep {}; TEST_P(SBusOutNarrowbandPWMToSBusSweep, FullScaleChannel) { sbusOutConfigMutable()->min[4] = 500; sbusOutConfigMutable()->max[4] = 1000; - // sbus: [192, 1792] - // pwm: [500, 1000] const uint16_t pwm = GetParam(); uint16_t sbus = sbusOutConvertToSbus(4, pwm); - float sbusf = (sbus - 192.0f) / (1792 - 192 + 1); - float pwmf = (pwm - 500.0f) / (1000 - 500 + 1); - const float resolution = 1.0f / (1000 - 500 + 1); + + // Validate: + float sbusf = SBusToFloat(sbus); + // pwm: [500, 1000] + float pwmf = ValueMinMaxToFloat(pwm, 500, 1000); + const float resolution = Resolution(500, 1000); EXPECT_NEAR(sbusf, pwmf, resolution); } @@ -415,20 +451,22 @@ INSTANTIATE_TEST_SUITE_P(NarrowbandPWMConversionSweep, SBusOutNarrowbandPWMToSBusSweep, testing::Range(500, 1001)); +// Test Mixer value [-1000, 1000] convert to SBus value // Test param = Mixer rule value class SBusOutMixerValueToSBusSweep : public SBusOutPWMToSBusSweep {}; TEST_P(SBusOutMixerValueToSBusSweep, FullScaleChannel) { sbusOutConfigMutable()->min[4] = -1000; sbusOutConfigMutable()->max[4] = 1000; - // sbus: [192, 1792] - // value: [-1000, 1000] const int16_t value = GetParam(); uint16_t sbus = sbusOutConvertToSbus(4, value); - float sbusf = (sbus - 192.0f) / (1792 - 192 + 1); - float valuef = (value - -1000.0f) / (1000 - -1000 + 1); - const float resolution = 1.0f / (1000 - -1000 + 1); + + // Validate: + float sbusf = SBusToFloat(sbus); + // value: [-1000, 1000] + float valuef = ValueMinMaxToFloat(value, -1000, 1000); + const float resolution = Resolution(-1000, 1000); EXPECT_NEAR(sbusf, valuef, resolution); } @@ -446,6 +484,47 @@ INSTANTIATE_TEST_SUITE_P(MixerValueConversionSweep, SBusOutMixerValueToSBusSweep, testing::Range(-1000, 1001)); +// Test SBus conversion when min/max is reversed in the config +// Test param = value between [-500, 1000] (more generic) +class SBusOutToSBusReversedSweep : public SBusOutPWMToSBusSweep {}; + +TEST_P(SBusOutToSBusReversedSweep, FullScaleChannel) { + // Reversed min/max + sbusOutConfigMutable()->min[4] = 1000; + sbusOutConfigMutable()->max[4] = -500; + + const int16_t value = GetParam(); + std::cout << "value = " << value << std::endl; + uint16_t sbus = sbusOutConvertToSbus(4, value); + std::cout << "sbus = " << sbus; + + float sbusf = SBusToFloat(sbus); + // value: [1000, -500] + float valuef = ValueMinMaxToFloat(value, 1000, -500); + const float resolution = Resolution(-500, 1000); + EXPECT_NEAR(sbusf, valuef, resolution); +} + +TEST_P(SBusOutToSBusReversedSweep, OnOffConversion) { + sbusOutConfigMutable()->min[16] = 1000; + sbusOutConfigMutable()->max[16] = -500; + + const int16_t value = GetParam(); + uint16_t sbus = sbusOutConvertToSbus(16, value); + + const int16_t midpoint = (1000 + -500)/2; + if ((1000 + -500)%2 == 0 && value == midpoint) + GTEST_SKIP(); + + // Note: reversed + float valuef = ValueMinMaxToFloat(value, 1000, -500); + EXPECT_EQ(sbus, valuef > 0.5 ? 1 : 0); +} + +INSTANTIATE_TEST_SUITE_P(ReversedMinMaxConversionSweep, + SBusOutToSBusReversedSweep, + testing::Range(-500, 1001)); + class SBusOutSerialTest : public SBusOutTestBase {}; TEST_F(SBusOutSerialTest, NoFreeBuffer) {