diff --git a/sys/fmt/fmt.c b/sys/fmt/fmt.c index ab2d594ad5b6bdfda7c440f9c8929774acd1c6a5..0c169e62111e92c8a52e01cf53a93cd99a26b3fe 100644 --- a/sys/fmt/fmt.c +++ b/sys/fmt/fmt.c @@ -22,6 +22,7 @@ #include <stdarg.h> #include <stdint.h> #include <unistd.h> +#include <string.h> #ifdef __WITH_AVRLIBC__ #include <stdio.h> /* for fwrite() */ @@ -102,6 +103,60 @@ size_t fmt_u64_hex(char *out, uint64_t val) return fmt_bytes_hex_reverse(out, (uint8_t*) &val, 8); } +size_t fmt_u64_dec(char *out, uint64_t val) +{ + uint32_t d[5]; + uint32_t q; + size_t len = 0; + + d[0] = val & 0xFFFF; + d[1] = (val>>16) & 0xFFFF; + d[2] = (val>>32) & 0xFFFF; + d[3] = (val>>48) & 0xFFFF; + + d[0] = 656 * d[3] + 7296 * d[2] + 5536 * d[1] + d[0]; + q = d[0] / 10000; + d[0] = d[0] % 10000; + + d[1] = q + 7671 * d[3] + 9496 * d[2] + 6 * d[1]; + q = d[1] / 10000; + d[1] = d[1] % 10000; + + d[2] = q + 4749 * d[3] + 42 * d[2]; + q = d[2] / 10000; + d[2] = d[2] % 10000; + + d[3] = q + 281 * d[3]; + q = d[3] / 10000; + d[3] = d[3] % 10000; + + d[4] = q; + + int first = 4; + + while (!d[first] && first) { + first--; + } + + len = fmt_u32_dec(out, d[first]); + int total_len = len + (first * 4); + + if (out) { + out += len; + memset(out, '0', total_len - len); + while(first) { + first--; + if (d[first]) { + size_t tmp = fmt_u32_dec(NULL, d[first]); + fmt_u32_dec(out+(4-tmp), d[first]); + } + out += 4; + } + } + + return total_len; +} + size_t fmt_u32_dec(char *out, uint32_t val) { size_t len = 1; @@ -248,6 +303,13 @@ void print_u64_hex(uint64_t val) print_u32_hex(val); } +void print_u64_dec(uint64_t val) +{ + char buf[18]; + size_t len = fmt_u64_dec(buf, val); + print(buf, len); +} + void print_str(const char* str) { print(str, fmt_strlen(str)); diff --git a/sys/include/fmt.h b/sys/include/fmt.h index 02162504d9d033d6aeb18b8d3caad05b7e3bfcd3..09ce0024822df757c4a1e6465fed1230c98ca4b1 100644 --- a/sys/include/fmt.h +++ b/sys/include/fmt.h @@ -101,6 +101,21 @@ size_t fmt_u64_hex(char *out, uint64_t val); */ size_t fmt_u32_dec(char *out, uint32_t val); +/** + * @brief Convert a uint64 value to decimal string. + * + * If @p out is NULL, will only return the number of bytes that would have + * been written. + * + * @note This adds ~400b of code when used. + * + * @param[out] out Pointer to output buffer, or NULL + * @param[in] val Value to convert + * + * @return nr of digits written to (or needed in) @p out + */ +size_t fmt_u64_dec(char *out, uint64_t val); + /** * @brief Convert a uint16 value to decimal string. * @@ -244,6 +259,15 @@ void print_u32_hex(uint32_t val); */ void print_u64_hex(uint64_t val); +/** + * @brief Print uint64 value as decimal to stdout + * + * @note This used fmt_u64_dec(), which uses ~400b of code. + * + * @param[in] val Value to print + */ +void print_u64_dec(uint64_t val); + /** * @brief Print null-terminated string to stdout * diff --git a/tests/unittests/tests-fmt/tests-fmt.c b/tests/unittests/tests-fmt/tests-fmt.c index 6e9a4f1f9b71a92be6712a15616977ed9f58bf88..ad5cb4a178ac797afd0d23a10b395c4cf4359e31 100644 --- a/tests/unittests/tests-fmt/tests-fmt.c +++ b/tests/unittests/tests-fmt/tests-fmt.c @@ -120,6 +120,42 @@ static void test_fmt_s32_dec(void) TEST_ASSERT_EQUAL_STRING("-9876", (char *) out); } +static void test_fmt_u64_dec_a(void) +{ + char out[21] = "------------------"; + uint64_t val = 0; + uint8_t chars = 0; + + chars = fmt_u64_dec(out, val); + TEST_ASSERT_EQUAL_INT(1, chars); + out[chars] = '\0'; + TEST_ASSERT_EQUAL_STRING("0", (char *) out); +} + +static void test_fmt_u64_dec_b(void) +{ + char out[21] = "--------------------"; + uint64_t val = 18446744073709551615LLU; + uint8_t chars = 0; + + chars = fmt_u64_dec(out, val); + TEST_ASSERT_EQUAL_INT(20, chars); + out[chars] = '\0'; + TEST_ASSERT_EQUAL_STRING("18446744073709551615", (char *) out); +} + +static void test_fmt_u64_dec_c(void) +{ + char out[21] = "--------------------"; + uint64_t val = 1234567890123456789LLU; + uint8_t chars = 0; + + chars = fmt_u64_dec(out, val); + TEST_ASSERT_EQUAL_INT(19, chars); + out[chars] = '\0'; + TEST_ASSERT_EQUAL_STRING("1234567890123456789", (char *) out); +} + static void test_rmt_s16_dec(void) { char out[7] = "-------"; @@ -247,6 +283,9 @@ Test *tests_fmt_tests(void) new_TestFixture(test_fmt_u32_hex), new_TestFixture(test_fmt_u64_hex), new_TestFixture(test_fmt_u32_dec), + new_TestFixture(test_fmt_u64_dec_a), + new_TestFixture(test_fmt_u64_dec_b), + new_TestFixture(test_fmt_u64_dec_c), new_TestFixture(test_fmt_u16_dec), new_TestFixture(test_fmt_s32_dec), new_TestFixture(test_rmt_s16_dec),