diff --git a/firmware/application/string_format.cpp b/firmware/application/string_format.cpp index a2fdb56ed..aac7add7c 100644 --- a/firmware/application/string_format.cpp +++ b/firmware/application/string_format.cpp @@ -162,13 +162,47 @@ std::string to_string_decimal(float decimal, int8_t precision) { return result; } +// right-justified frequency in Hz, always 10 characters std::string to_string_freq(const uint64_t f) { - auto final_str = to_string_dec_int(f / 1000000, 4) + to_string_dec_int(f % 1000000, 6, '0'); + std::string final_str{""}; + + if (f < 1000000) + final_str = to_string_dec_int(f, 10, ' '); + else + final_str = to_string_dec_int(f / 1000000, 4) + to_string_dec_int(f % 1000000, 6, '0'); + return final_str; } +// right-justified frequency in MHz, rounded to 4 decimal places, always 9 characters std::string to_string_short_freq(const uint64_t f) { - auto final_str = to_string_dec_int(f / 1000000, 4) + "." + to_string_dec_int((f / 100) % 10000, 4, '0'); + auto final_str = to_string_dec_int(f / 1000000, 4) + "." + to_string_dec_int(((f + 50) / 100) % 10000, 4, '0'); + return final_str; +} + +// non-justified non-padded frequency in MHz, rounded to specified number of decimal places +std::string to_string_rounded_freq(const uint64_t f, int8_t precision) { + std::string final_str{""}; + static constexpr uint32_t pow10[7] = { + 1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + }; + + if (precision < 1) { + final_str = to_string_dec_uint64(f / 1000000); + } else { + if (precision > 6) + precision = 6; + + uint32_t divisor = pow10[6 - precision]; + + final_str = to_string_dec_uint64(f / 1000000) + "." + to_string_dec_int(((f + (divisor / 2)) / divisor) % pow10[precision], precision, '0'); + } return final_str; } diff --git a/firmware/application/string_format.hpp b/firmware/application/string_format.hpp index c3f8e912e..a5f265013 100644 --- a/firmware/application/string_format.hpp +++ b/firmware/application/string_format.hpp @@ -59,9 +59,9 @@ std::string to_string_decimal(float decimal, int8_t precision); std::string to_string_hex(const uint64_t n, const int32_t l = 0); std::string to_string_hex_array(uint8_t* const array, const int32_t l = 0); -// NB: These pad-left and don't work correctly for values less than 1M. std::string to_string_freq(const uint64_t f); std::string to_string_short_freq(const uint64_t f); +std::string to_string_rounded_freq(const uint64_t f, int8_t precision); std::string to_string_time_ms(const uint32_t ms); std::string to_string_datetime(const rtc::RTC& value, const TimeFormat format = YMDHMS); diff --git a/firmware/test/application/CMakeLists.txt b/firmware/test/application/CMakeLists.txt index ffe37765d..fbbe78643 100644 --- a/firmware/test/application/CMakeLists.txt +++ b/firmware/test/application/CMakeLists.txt @@ -71,6 +71,7 @@ target_include_directories(application_test PRIVATE ) target_compile_options(application_test PRIVATE + -std=c++17 -DLPC43XX -DLPC43XX_M0 -D__NEWLIB__ diff --git a/firmware/test/application/test_string_format.cpp b/firmware/test/application/test_string_format.cpp index 898f731a2..a9ac8e502 100644 --- a/firmware/test/application/test_string_format.cpp +++ b/firmware/test/application/test_string_format.cpp @@ -32,13 +32,41 @@ TEST_CASE("to_string_dec_uint64 returns correct value.") { CHECK_EQ(to_string_dec_uint64(1'234'567'891), "1234567891"); } -/*TEST_CASE("to_string_freq returns correct value.") { - CHECK_EQ(to_string_freq(0), "0"); - CHECK_EQ(to_string_freq(1), "1"); - CHECK_EQ(to_string_freq(1'000'000), "1000000"); +TEST_CASE("to_string_freq returns correct value.") { + CHECK_EQ(to_string_freq(0), " 0"); + CHECK_EQ(to_string_freq(1), " 1"); + CHECK_EQ(to_string_freq(1'000'000), " 1000000"); CHECK_EQ(to_string_freq(1'234'567'890), "1234567890"); CHECK_EQ(to_string_freq(1'234'567'891), "1234567891"); -}*/ +} + +TEST_CASE("to_string_short_freq returns correct value.") { + CHECK_EQ(to_string_short_freq(0), " 0.0000"); + CHECK_EQ(to_string_short_freq(49), " 0.0000"); + CHECK_EQ(to_string_short_freq(50), " 0.0001"); + CHECK_EQ(to_string_short_freq(1'000'049), " 1.0000"); + CHECK_EQ(to_string_short_freq(1'000'050), " 1.0001"); + CHECK_EQ(to_string_short_freq(1'234'567'850), "1234.5679"); + CHECK_EQ(to_string_short_freq(1'234'567'849), "1234.5678"); +} + +TEST_CASE("to_string_rounded_freq returns correct value.") { + CHECK_EQ(to_string_rounded_freq(0, 0), "0"); + CHECK_EQ(to_string_rounded_freq(0, 2), "0.00"); + CHECK_EQ(to_string_rounded_freq(49, 4), "0.0000"); + CHECK_EQ(to_string_rounded_freq(50, 4), "0.0001"); + CHECK_EQ(to_string_rounded_freq(23'456, 4), "0.0235"); + CHECK_EQ(to_string_rounded_freq(1'000'000, 4), "1.0000"); + CHECK_EQ(to_string_rounded_freq(1'000'567'849, 4), "1000.5678"); + CHECK_EQ(to_string_rounded_freq(1'234'567'891, 0), "1234"); + CHECK_EQ(to_string_rounded_freq(1'234'567'891, 1), "1234.6"); + CHECK_EQ(to_string_rounded_freq(1'234'567'891, 2), "1234.57"); + CHECK_EQ(to_string_rounded_freq(1'234'567'891, 3), "1234.568"); + CHECK_EQ(to_string_rounded_freq(1'234'567'891, 4), "1234.5679"); + CHECK_EQ(to_string_rounded_freq(1'234'567'891, 5), "1234.56789"); + CHECK_EQ(to_string_rounded_freq(1'234'567'891, 6), "1234.567891"); + CHECK_EQ(to_string_rounded_freq(1'234'567'891, 9), "1234.567891"); +} TEST_CASE("trim removes whitespace.") { CHECK(trim(" foo\n") == "foo");