diff options
author | Max <msuraev@sysmocom.de> | 2016-06-17 17:58:52 +0200 |
---|---|---|
committer | Max <msuraev@sysmocom.de> | 2016-06-20 19:02:56 +0200 |
commit | e0a7d9e2c220e5544ee8982c78851ff40ac425bc (patch) | |
tree | 5b3c65a05ef3ab52f4808dae5f3632f8fdebe960 | |
parent | 136e73764e7f58e52ffb13d01304fef30eb7d291 (diff) |
Add octet-aligned/unaligned shift functions
The actual code is from OsmoBTS' tch.c by Harald Welte. Add unit tests,
doxygen annotation and extra memory safety check. Those functions are
used in several BTS implementations but seems generic enough to be
generally useful.
Change-Id: I2b1901c4161e8035f059585901dca593b661556d
-rw-r--r-- | include/osmocom/core/bits.h | 5 | ||||
-rw-r--r-- | src/bits.c | 48 | ||||
-rw-r--r-- | tests/bits/bitrev_test.c | 25 | ||||
-rw-r--r-- | tests/bits/bitrev_test.ok | 105 |
4 files changed, 183 insertions, 0 deletions
diff --git a/include/osmocom/core/bits.h b/include/osmocom/core/bits.h index 3218330b..5535920e 100644 --- a/include/osmocom/core/bits.h +++ b/include/osmocom/core/bits.h @@ -41,6 +41,11 @@ int osmo_ubit2pbit(pbit_t *out, const ubit_t *in, unsigned int num_bits); int osmo_pbit2ubit(ubit_t *out, const pbit_t *in, unsigned int num_bits); +void osmo_nibble_shift_right(uint8_t *out, const uint8_t *in, + unsigned int num_nibbles); +void osmo_nibble_shift_left_unal(uint8_t *out, const uint8_t *in, + unsigned int num_nibbles); + void osmo_ubit2sbit(sbit_t *out, const ubit_t *in, unsigned int num_bits); void osmo_sbit2ubit(ubit_t *out, const sbit_t *in, unsigned int num_bits); @@ -61,6 +61,54 @@ int osmo_ubit2pbit(pbit_t *out, const ubit_t *in, unsigned int num_bits) return outptr - out; } +/*! \brief Shift unaligned input to octet-aligned output + * \param[out] out output buffer, unaligned + * \param[in] in input buffer, octet-aligned + * \param[in] num_nibbles number of nibbles + */ +void osmo_nibble_shift_right(uint8_t *out, const uint8_t *in, + unsigned int num_nibbles) +{ + unsigned int i, num_whole_bytes = num_nibbles / 2; + if (!num_whole_bytes) + return; + + /* first byte: upper nibble empty, lower nibble from src */ + out[0] = (in[0] >> 4); + + /* bytes 1.. */ + for (i = 1; i < num_whole_bytes; i++) + out[i] = ((in[i - 1] & 0xF) << 4) | (in[i] >> 4); + + /* shift the last nibble, in case there's an odd count */ + i = num_whole_bytes; + if (num_nibbles & 1) + out[i] = ((in[i - 1] & 0xF) << 4) | (in[i] >> 4); + else + out[i] = (in[i - 1] & 0xF) << 4; +} + +/*! \brief Shift unaligned input to octet-aligned output + * \param[out] out output buffer, octet-aligned + * \param[in] in input buffer, unaligned + * \param[in] num_nibbles number of nibbles + */ +void osmo_nibble_shift_left_unal(uint8_t *out, const uint8_t *in, + unsigned int num_nibbles) +{ + unsigned int i, num_whole_bytes = num_nibbles / 2; + if (!num_whole_bytes) + return; + + for (i = 0; i < num_whole_bytes; i++) + out[i] = ((in[i] & 0xF) << 4) | (in[i + 1] >> 4); + + /* shift the last nibble, in case there's an odd count */ + i = num_whole_bytes; + if (num_nibbles & 1) + out[i] = (in[i] & 0xF) << 4; +} + /*! \brief convert unpacked bits to soft bits * \param[out] out output buffer of soft bits * \param[in] in input buffer of unpacked bits diff --git a/tests/bits/bitrev_test.c b/tests/bits/bitrev_test.c index 987f4d51..08f08278 100644 --- a/tests/bits/bitrev_test.c +++ b/tests/bits/bitrev_test.c @@ -205,6 +205,20 @@ check16(uint16_t test, enum END e) printcheck16(e, test, test, (BE == e) ? s : NULL, print); } +static void sh_chk(const uint8_t *in, uint8_t len, unsigned int nib, bool r) +{ + uint8_t x[len]; + if (r) + osmo_nibble_shift_right(x, in, nib); + else + osmo_nibble_shift_left_unal(x, in, nib); + + printf("[%u] %s IN: %s, nibble %u:", len, r ? "R" : "L", + osmo_hexdump_nospc(in, len), nib); + /* do NOT combine those printfs: osmo_hexdump* use static buffer which + WILL screw things up in that case */ + printf("\n OUT: %s\n", osmo_hexdump_nospc(x, nib/2)); +} int main(int argc, char **argv) { @@ -274,5 +288,16 @@ int main(int argc, char **argv) check16(0, BE); check16(0, LE); + printf("running nibble tests...\n"); + + const uint8_t in1[] = { 0xF0, 0x0D, 0xCA, 0xFE, 0xDE, 0xAD, 0xBE, 0xEF }, + in2[] = { 0xB0, 0x0B, 0xBA, 0xBE, 0xFA, 0xCE }; + + for (offs = 0; offs < 13; offs++) { + sh_chk(in1, ARRAY_SIZE(in1), offs, true); + sh_chk(in1, ARRAY_SIZE(in1), offs, false); + sh_chk(in2, ARRAY_SIZE(in2), offs, true); + sh_chk(in2, ARRAY_SIZE(in2), offs, false); + } return 0; } diff --git a/tests/bits/bitrev_test.ok b/tests/bits/bitrev_test.ok index 90cb295f..9fbb4d9c 100644 --- a/tests/bits/bitrev_test.ok +++ b/tests/bits/bitrev_test.ok @@ -53,3 +53,108 @@ running random tests... 24 LE OK 16 BE OK, storage OK 16 LE OK +running nibble tests... +[8] R IN: f00dcafedeadbeef, nibble 0: + OUT: +[8] L IN: f00dcafedeadbeef, nibble 0: + OUT: +[6] R IN: b00bbabeface, nibble 0: + OUT: +[6] L IN: b00bbabeface, nibble 0: + OUT: +[8] R IN: f00dcafedeadbeef, nibble 1: + OUT: +[8] L IN: f00dcafedeadbeef, nibble 1: + OUT: +[6] R IN: b00bbabeface, nibble 1: + OUT: +[6] L IN: b00bbabeface, nibble 1: + OUT: +[8] R IN: f00dcafedeadbeef, nibble 2: + OUT: 0f +[8] L IN: f00dcafedeadbeef, nibble 2: + OUT: 00 +[6] R IN: b00bbabeface, nibble 2: + OUT: 0b +[6] L IN: b00bbabeface, nibble 2: + OUT: 00 +[8] R IN: f00dcafedeadbeef, nibble 3: + OUT: 0f +[8] L IN: f00dcafedeadbeef, nibble 3: + OUT: 00 +[6] R IN: b00bbabeface, nibble 3: + OUT: 0b +[6] L IN: b00bbabeface, nibble 3: + OUT: 00 +[8] R IN: f00dcafedeadbeef, nibble 4: + OUT: 0f00 +[8] L IN: f00dcafedeadbeef, nibble 4: + OUT: 00dc +[6] R IN: b00bbabeface, nibble 4: + OUT: 0b00 +[6] L IN: b00bbabeface, nibble 4: + OUT: 00bb +[8] R IN: f00dcafedeadbeef, nibble 5: + OUT: 0f00 +[8] L IN: f00dcafedeadbeef, nibble 5: + OUT: 00dc +[6] R IN: b00bbabeface, nibble 5: + OUT: 0b00 +[6] L IN: b00bbabeface, nibble 5: + OUT: 00bb +[8] R IN: f00dcafedeadbeef, nibble 6: + OUT: 0f00dc +[8] L IN: f00dcafedeadbeef, nibble 6: + OUT: 00dcaf +[6] R IN: b00bbabeface, nibble 6: + OUT: 0b00bb +[6] L IN: b00bbabeface, nibble 6: + OUT: 00bbab +[8] R IN: f00dcafedeadbeef, nibble 7: + OUT: 0f00dc +[8] L IN: f00dcafedeadbeef, nibble 7: + OUT: 00dcaf +[6] R IN: b00bbabeface, nibble 7: + OUT: 0b00bb +[6] L IN: b00bbabeface, nibble 7: + OUT: 00bbab +[8] R IN: f00dcafedeadbeef, nibble 8: + OUT: 0f00dcaf +[8] L IN: f00dcafedeadbeef, nibble 8: + OUT: 00dcafed +[6] R IN: b00bbabeface, nibble 8: + OUT: 0b00bbab +[6] L IN: b00bbabeface, nibble 8: + OUT: 00bbabef +[8] R IN: f00dcafedeadbeef, nibble 9: + OUT: 0f00dcaf +[8] L IN: f00dcafedeadbeef, nibble 9: + OUT: 00dcafed +[6] R IN: b00bbabeface, nibble 9: + OUT: 0b00bbab +[6] L IN: b00bbabeface, nibble 9: + OUT: 00bbabef +[8] R IN: f00dcafedeadbeef, nibble 10: + OUT: 0f00dcafed +[8] L IN: f00dcafedeadbeef, nibble 10: + OUT: 00dcafedea +[6] R IN: b00bbabeface, nibble 10: + OUT: 0b00bbabef +[6] L IN: b00bbabeface, nibble 10: + OUT: 00bbabefac +[8] R IN: f00dcafedeadbeef, nibble 11: + OUT: 0f00dcafed +[8] L IN: f00dcafedeadbeef, nibble 11: + OUT: 00dcafedea +[6] R IN: b00bbabeface, nibble 11: + OUT: 0b00bbabef +[6] L IN: b00bbabeface, nibble 11: + OUT: 00bbabefac +[8] R IN: f00dcafedeadbeef, nibble 12: + OUT: 0f00dcafedea +[8] L IN: f00dcafedeadbeef, nibble 12: + OUT: 00dcafedeadb +[6] R IN: b00bbabeface, nibble 12: + OUT: 0b00bbabefac +[6] L IN: b00bbabeface, nibble 12: + OUT: 00bbabeface0 |