Skip to content

Commit a862dc6

Browse files
authored
Merge pull request #21428 from benpicco/sys/bcd_buf_from_str
sys/bcd: add `bcd_buf_to_u32()` and `bcd_buf_from_str()`
2 parents ab921f5 + 444fc84 commit a862dc6

File tree

3 files changed

+136
-1
lines changed

3 files changed

+136
-1
lines changed

sys/bcd/bcd.c

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,61 @@ int bcd_buf_from_u32(uint32_t val, void *dst, size_t len)
5656

5757
return (uintptr_t)tgt - (uintptr_t)dst;
5858
}
59+
60+
/* Use the same code for 32 bit and 64 bit sum */
61+
#define _BCD_CONVERT(sum, len) \
62+
for (int i = len * 2 - 1; i >= 0; --i) { \
63+
uint8_t digit = i & 1 \
64+
? bcd[i >> 1] >> 4 \
65+
: bcd[i >> 1] & 0xF; \
66+
sum = sum * 10 + digit; \
67+
}
68+
69+
uint32_t bcd_buf_to_u32(const void *src, size_t len)
70+
{
71+
const uint8_t *bcd = src;
72+
uint32_t sum = 0;
73+
74+
_BCD_CONVERT(sum, len);
75+
76+
return sum;
77+
}
78+
79+
uint64_t bcd_buf_to_u64(const void *src, size_t len)
80+
{
81+
const uint8_t *bcd = src;
82+
uint64_t sum = 0;
83+
84+
_BCD_CONVERT(sum, len);
85+
86+
return sum;
87+
}
88+
89+
static bool _is_digit(char c)
90+
{
91+
return c >= '0' && c <= '9';
92+
}
93+
94+
int bcd_buf_from_str(const char *str, size_t len, void *dst, size_t dst_len)
95+
{
96+
uint8_t *bcd = dst;
97+
memset(dst, 0, dst_len);
98+
dst_len *= 2;
99+
100+
uint8_t i = 0;
101+
for (int j = len; j >= 0; --j) {
102+
if (i == dst_len) {
103+
return -ENOBUFS;
104+
}
105+
if (!_is_digit(str[j])) {
106+
continue;
107+
}
108+
uint8_t d = str[j] & 0xF;
109+
bcd[i >> 1] |= i & 1
110+
? d << 4
111+
: d;
112+
++i;
113+
}
114+
115+
return (i & 1) + (i >> 1);
116+
}

sys/include/bcd.h

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@
1616
* @brief BCD definitions
1717
*
1818
* @author Martine Lenders <[email protected]>
19+
* @author Benjamin Valentin <[email protected]>
1920
*/
2021
#ifndef BCD_H
2122
#define BCD_H
2223

24+
#include <stdbool.h>
2325
#include <stddef.h>
2426
#include <stdint.h>
2527

@@ -64,11 +66,48 @@ static inline uint8_t bcd_to_byte(uint8_t bcd)
6466
* @param[in] len Size of the destination buffer
6567
*
6668
* @return number of bytes written
67-
* @return -ENOBUFS if @p dst is not large enough
69+
* @retval -ENOBUFS if @p dst is not large enough
6870
* In that case the state of @p dst is undefined.
6971
*/
7072
int bcd_buf_from_u32(uint32_t val, void *dst, size_t len);
7173

74+
/**
75+
* @brief Convert a BCD buffer into it's binary representation
76+
* (This will reverse @ref bcd_buf_from_u32)
77+
*
78+
* @param[in] src The BCD buffer to convert
79+
* @param[in] len Bytes in @p src
80+
*
81+
* @returns decimal representation of @p src
82+
*/
83+
uint32_t bcd_buf_to_u32(const void *src, size_t len);
84+
85+
/**
86+
* @brief Convert a BCD buffer into it's binary representation
87+
*
88+
* @param[in] src The BCD buffer to convert
89+
* @param[in] len Bytes in @p src
90+
*
91+
* @returns decimal representation of @p src
92+
*/
93+
uint64_t bcd_buf_to_u64(const void *src, size_t len);
94+
95+
/**
96+
* @brief Convert a string into a BCD buffer
97+
* Digits may be separated by any character.
98+
*
99+
* @param[in] str Input string
100+
* @param[in] str_len Length of the input string
101+
* @param[out] dst Destination buffer
102+
* @param[in] dst_len Size of the destination buffer
103+
*
104+
* @return number of bytes written
105+
* @retval -ENOBUFS if @p dst is not large enough
106+
* In that case the state of @p dst is undefined.
107+
*/
108+
int bcd_buf_from_str(const char *str, size_t str_len,
109+
void *dst, size_t dst_len);
110+
72111
#ifdef __cplusplus
73112
}
74113
#endif

tests/unittests/tests-bcd/tests-bcd.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,42 @@ static void test_bcd_buf_from_u32(void)
8585
TEST_ASSERT_EQUAL_INT(-ENOBUFS, bcd_buf_from_u32(0, NULL, 0));
8686
}
8787

88+
static void test_bcd_buf_to_u32(void)
89+
{
90+
char buf[4];
91+
92+
bcd_buf_from_u32(1, buf, sizeof(buf));
93+
TEST_ASSERT_EQUAL_INT(1, bcd_buf_to_u32(buf, sizeof(buf)));
94+
95+
bcd_buf_from_u32(12, buf, sizeof(buf));
96+
TEST_ASSERT_EQUAL_INT(12, bcd_buf_to_u32(buf, sizeof(buf)));
97+
98+
bcd_buf_from_u32(123, buf, sizeof(buf));
99+
TEST_ASSERT_EQUAL_INT(123, bcd_buf_to_u32(buf, sizeof(buf)));
100+
101+
bcd_buf_from_u32(1234, buf, sizeof(buf));
102+
TEST_ASSERT_EQUAL_INT(1234, bcd_buf_to_u32(buf, sizeof(buf)));
103+
}
104+
105+
static void test_bcd_buf_from_str(void)
106+
{
107+
uint8_t buf[4];
108+
109+
TEST_ASSERT_EQUAL_INT(1, bcd_buf_from_str("1", 1, buf, sizeof(buf)));
110+
TEST_ASSERT_EQUAL_INT(1, bcd_buf_to_u32(buf, sizeof(buf)));
111+
112+
TEST_ASSERT_EQUAL_INT(1, bcd_buf_from_str("12", 2, buf, sizeof(buf)));
113+
TEST_ASSERT_EQUAL_INT(12, bcd_buf_to_u32(buf, sizeof(buf)));
114+
115+
TEST_ASSERT_EQUAL_INT(2, bcd_buf_from_str("123", 3, buf, sizeof(buf)));
116+
TEST_ASSERT_EQUAL_INT(123, bcd_buf_to_u32(buf, sizeof(buf)));
117+
118+
TEST_ASSERT_EQUAL_INT(2, bcd_buf_from_str("1234", 4, buf, sizeof(buf)));
119+
TEST_ASSERT_EQUAL_INT(1234, bcd_buf_to_u32(buf, sizeof(buf)));
120+
121+
TEST_ASSERT_EQUAL_INT(-ENOBUFS, bcd_buf_from_str("1234567890", 10, buf, sizeof(buf)));
122+
}
123+
88124
Test *tests_bcd_tests(void)
89125
{
90126
EMB_UNIT_TESTFIXTURES(fixtures) {
@@ -95,6 +131,8 @@ Test *tests_bcd_tests(void)
95131
new_TestFixture(test_bcd_to_byte__greater_0x99),
96132
new_TestFixture(test_bcd_to_byte),
97133
new_TestFixture(test_bcd_buf_from_u32),
134+
new_TestFixture(test_bcd_buf_to_u32),
135+
new_TestFixture(test_bcd_buf_from_str),
98136
};
99137

100138
EMB_UNIT_TESTCALLER(bcd_tests, NULL, NULL, fixtures);

0 commit comments

Comments
 (0)