Skip to content

Commit

Permalink
sbus_output: handle reversed min/max config
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
gongtao0607 committed Nov 11, 2024
1 parent 399eeb9 commit 22203c7
Showing 1 changed file with 94 additions and 15 deletions.
109 changes: 94 additions & 15 deletions src/test/unit/sbus_output_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<int> {};
public testing::WithParamInterface<int> {
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<float>(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);
}

Expand All @@ -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);
}

Expand All @@ -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);
}

Expand All @@ -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) {
Expand Down

0 comments on commit 22203c7

Please sign in to comment.