diff --git a/Makefile b/Makefile index f3f29edd4..68f2ee1be 100644 --- a/Makefile +++ b/Makefile @@ -199,6 +199,7 @@ COMMON_SRC = build_config.c \ common/maths.c \ common/printf.c \ common/typeconversion.c \ + common/encoding.c \ main.c \ mw.c \ flight/altitudehold.c \ diff --git a/src/main/blackbox/blackbox.c b/src/main/blackbox/blackbox.c index 0461dac74..ae9476297 100644 --- a/src/main/blackbox/blackbox.c +++ b/src/main/blackbox/blackbox.c @@ -26,6 +26,7 @@ #include "common/maths.h" #include "common/axis.h" #include "common/color.h" +#include "common/encoding.h" #include "drivers/gpio.h" #include "drivers/sensor.h" @@ -878,11 +879,6 @@ static bool sendFieldDefinition(const char * const *headerNames, unsigned int he */ static bool blackboxWriteSysinfo() { - union floatConvert_t { - float f; - uint32_t u; - } floatConvert; - if (xmitState.headerIndex == 0) { xmitState.u.serialBudget = 0; xmitState.headerIndex = 1; @@ -937,8 +933,7 @@ static bool blackboxWriteSysinfo() xmitState.u.serialBudget -= strlen("H maxthrottle:%d\n"); break; case 8: - floatConvert.f = gyro.scale; - blackboxPrintf("H gyro.scale:0x%x\n", floatConvert.u); + blackboxPrintf("H gyro.scale:0x%x\n", castFloatBytesToInt(gyro.scale)); xmitState.u.serialBudget -= strlen("H gyro.scale:0x\n") + 6; break; diff --git a/src/main/blackbox/blackbox_io.c b/src/main/blackbox/blackbox_io.c index fa6f66d6d..ac8bf5ef4 100644 --- a/src/main/blackbox/blackbox_io.c +++ b/src/main/blackbox/blackbox_io.c @@ -4,12 +4,13 @@ #include "blackbox_io.h" -#include "platform.h" #include "version.h" +#include "build_config.h" #include "common/maths.h" #include "common/axis.h" #include "common/color.h" +#include "common/encoding.h" #include "drivers/gpio.h" #include "drivers/sensor.h" @@ -144,18 +145,6 @@ void blackboxWriteUnsignedVB(uint32_t value) blackboxWrite(value); } -/** - * ZigZag encoding maps all values of a signed integer into those of an unsigned integer in such - * a way that numbers of small absolute value correspond to small integers in the result. - * - * (Compared to just casting a signed to an unsigned which creates huge resulting numbers for - * small negative integers). - */ -static uint32_t zigzagEncode(int32_t value) -{ - return (uint32_t)((value << 1) ^ (value >> 31)); -} - /** * Write a signed integer to the blackbox serial port using ZigZig and variable byte encoding. */ diff --git a/src/main/blackbox/blackbox_io.h b/src/main/blackbox/blackbox_io.h index 62d590998..547850739 100644 --- a/src/main/blackbox/blackbox_io.h +++ b/src/main/blackbox/blackbox_io.h @@ -20,7 +20,7 @@ #include #include -#include "target.h" +#include "platform.h" typedef enum BlackboxDevice { BLACKBOX_DEVICE_SERIAL = 0, diff --git a/src/main/common/encoding.c b/src/main/common/encoding.c new file mode 100644 index 000000000..3823e862a --- /dev/null +++ b/src/main/common/encoding.c @@ -0,0 +1,31 @@ +#include "encoding.h" + +/** + * Cast the in-memory representation of the given float directly to an int. + * + * This is useful for printing the hex representation of a float number (which is considerably cheaper + * than a full decimal float formatter, in both code size and output length). + */ +uint32_t castFloatBytesToInt(float f) +{ + union floatConvert_t { + float f; + uint32_t u; + } floatConvert; + + floatConvert.f = f; + + return floatConvert.u; +} + +/** + * ZigZag encoding maps all values of a signed integer into those of an unsigned integer in such + * a way that numbers of small absolute value correspond to small integers in the result. + * + * (Compared to just casting a signed to an unsigned which creates huge resulting numbers for + * small negative integers). + */ +uint32_t zigzagEncode(int32_t value) +{ + return (uint32_t)((value << 1) ^ (value >> 31)); +} diff --git a/src/main/common/encoding.h b/src/main/common/encoding.h new file mode 100644 index 000000000..e0681ed2a --- /dev/null +++ b/src/main/common/encoding.h @@ -0,0 +1,23 @@ +/* + * This file is part of Cleanflight. + * + * Cleanflight is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Cleanflight is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Cleanflight. If not, see . + */ + +#pragma once + +#include + +uint32_t castFloatBytesToInt(float f); +uint32_t zigzagEncode(int32_t value); diff --git a/src/test/Makefile b/src/test/Makefile index 5ea38fe9f..6575c48a1 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -53,6 +53,7 @@ TESTS = \ rc_controls_unittest \ ledstrip_unittest \ ws2811_unittest \ + encoding_unittest \ lowpass_unittest # All Google Test headers. Usually you shouldn't change this @@ -130,6 +131,25 @@ battery_unittest : \ $(OBJECT_DIR)/gtest_main.a $(CXX) $(CXX_FLAGS) -lpthread $^ -o $(OBJECT_DIR)/$@ + +$(OBJECT_DIR)/common/encoding.o : $(USER_DIR)/common/encoding.c $(USER_DIR)/common/encoding.h $(GTEST_HEADERS) + @mkdir -p $(dir $@) + $(CC) $(C_FLAGS) $(TEST_CFLAGS) -c $(USER_DIR)/common/encoding.c -o $@ + +$(OBJECT_DIR)/encoding_unittest.o : \ + $(TEST_DIR)/encoding_unittest.cc \ + $(USER_DIR)/common/encoding.h \ + $(GTEST_HEADERS) + + @mkdir -p $(dir $@) + $(CXX) $(CXX_FLAGS) $(TEST_CFLAGS) -c $(TEST_DIR)/encoding_unittest.cc -o $@ + +encoding_unittest : \ + $(OBJECT_DIR)/common/encoding.o \ + $(OBJECT_DIR)/encoding_unittest.o \ + $(OBJECT_DIR)/gtest_main.a + + $(CXX) $(CXX_FLAGS) -lpthread $^ -o $(OBJECT_DIR)/$@ $(OBJECT_DIR)/flight/imu.o : \ $(USER_DIR)/flight/imu.c \ diff --git a/src/test/unit/encoding_unittest.cc b/src/test/unit/encoding_unittest.cc new file mode 100644 index 000000000..bf2c70b91 --- /dev/null +++ b/src/test/unit/encoding_unittest.cc @@ -0,0 +1,84 @@ +/* + * This file is part of Cleanflight. + * + * Cleanflight is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Cleanflight is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Cleanflight. If not, see . + */ +#include + +extern "C" { + #include "common/encoding.h" +} + +#include "unittest_macros.h" +#include "gtest/gtest.h" + +typedef struct zigzagEncodingExpectation_t { + int32_t input; + uint32_t expected; +} zigzagEncodingExpectation_t; + +typedef struct floatToIntEncodingExpectation_t { + float input; + uint32_t expected; +} floatToIntEncodingExpectation_t; + +TEST(EncodingTest, ZigzagEncodingTest) +{ + // given + zigzagEncodingExpectation_t expectations[] = { + { 0, 0}, + {-1, 1}, + { 1, 2}, + {-2, 3}, + { 2, 4}, + + { 2147483646, 4294967292}, + {-2147483647, 4294967293}, + { 2147483647, 4294967294}, + {-2147483648, 4294967295}, + }; + int expectationCount = sizeof(expectations) / sizeof(expectations[0]); + + // expect + + for (int i = 0; i < expectationCount; i++) { + zigzagEncodingExpectation_t *expectation = &expectations[i]; + + EXPECT_EQ(expectation->expected, zigzagEncode(expectation->input)); + } +} + +TEST(EncodingTest, FloatToIntEncodingTest) +{ + // given + floatToIntEncodingExpectation_t expectations[] = { + {0.0, 0x00000000}, + {2.0, 0x40000000}, // Exponent should be in the top bits + {4.5, 0x40900000} + }; + int expectationCount = sizeof(expectations) / sizeof(expectations[0]); + + // expect + + for (int i = 0; i < expectationCount; i++) { + floatToIntEncodingExpectation_t *expectation = &expectations[i]; + + EXPECT_EQ(expectation->expected, castFloatBytesToInt(expectation->input)); + } +} + +// STUBS + +extern "C" { +}