summaryrefslogtreecommitdiffstats
path: root/src/bitfield
diff options
context:
space:
mode:
Diffstat (limited to 'src/bitfield')
-rw-r--r--src/bitfield/8byte.c10
-rw-r--r--src/bitfield/8byte.h4
-rw-r--r--src/bitfield/bitfield.c18
-rw-r--r--src/bitfield/bitfield.h34
4 files changed, 59 insertions, 7 deletions
diff --git a/src/bitfield/8byte.c b/src/bitfield/8byte.c
index 76dccc75..3c555f08 100644
--- a/src/bitfield/8byte.c
+++ b/src/bitfield/8byte.c
@@ -8,7 +8,7 @@
uint8_t eightbyte_get_nibble(const uint64_t source, const uint8_t nibble_index,
const bool data_is_big_endian) {
- return eightbyte_get_bit_field(source, NIBBLE_SIZE * nibble_index, NIBBLE_SIZE,
+ return eightbyte_get_bitfield(source, NIBBLE_SIZE * nibble_index, NIBBLE_SIZE,
data_is_big_endian);
}
@@ -20,7 +20,10 @@ uint8_t eightbyte_get_byte(uint64_t source, const uint8_t byte_index,
return (source >> (EIGHTBYTE_BIT - ((byte_index + 1) * CHAR_BIT))) & 0xFF;
}
-uint64_t eightbyte_get_bit_field(uint64_t source, const uint16_t offset,
+// TODO is this funciton necessary anymore? is it any faster for uint64_t than
+// get_bitfield(data[], ...)? is the performance better on a 32 bit platform
+// like the PIC32?
+uint64_t eightbyte_get_bitfield(uint64_t source, const uint16_t offset,
const uint16_t bit_count, const bool data_is_big_endian) {
int startByte = offset / CHAR_BIT;
int endByte = (offset + bit_count - 1) / CHAR_BIT;
@@ -33,8 +36,7 @@ uint64_t eightbyte_get_bit_field(uint64_t source, const uint16_t offset,
uint64_t ret = bytes[startByte];
if(startByte != endByte) {
// The lowest byte address contains the most significant bit.
- int i;
- for(i = startByte + 1; i <= endByte; i++) {
+ for(uint8_t i = startByte + 1; i <= endByte; i++) {
ret = ret << 8;
ret = ret | bytes[i];
}
diff --git a/src/bitfield/8byte.h b/src/bitfield/8byte.h
index 194007c8..ab775caa 100644
--- a/src/bitfield/8byte.h
+++ b/src/bitfield/8byte.h
@@ -32,11 +32,11 @@ extern "C" {
*
* Examples
*
- * uint64_t value = get_bit_field(data, 2, 4);
+ * uint64_t value = get_bitfield(data, 2, 4);
*
* Returns the value of the requested bit field, right aligned in a uint64_t.
*/
-uint64_t eightbyte_get_bit_field(uint64_t source, const uint16_t offset,
+uint64_t eightbyte_get_bitfield(uint64_t source, const uint16_t offset,
const uint16_t bit_count, const bool data_is_big_endian);
/* Public: Return a single nibble from the payload, with range checking.
diff --git a/src/bitfield/bitfield.c b/src/bitfield/bitfield.c
index 3b0c5fdd..52f368f5 100644
--- a/src/bitfield/bitfield.c
+++ b/src/bitfield/bitfield.c
@@ -2,6 +2,7 @@
#include <limits.h>
#include <string.h>
#include <stddef.h>
+#include <endian.h>
uint64_t bitmask(const uint8_t bit_count) {
return (((uint64_t)0x1) << bit_count) - 1;
@@ -26,8 +27,25 @@ uint8_t get_byte(const uint8_t source[], const uint8_t source_length,
return 0;
}
+uint64_t get_bitfield(const uint8_t source[], const uint8_t source_length,
+ const uint16_t offset, const uint16_t bit_count) {
+ if(bit_count > 64 || bit_count < 1) {
+ // TODO error reporting?
+ return 0;
+ }
+
+ union {
+ uint64_t whole;
+ uint8_t bytes[sizeof(uint64_t)];
+ } combined;
+ copy_bits_right_aligned(source, source_length, offset, bit_count,
+ combined.bytes, sizeof(combined.bytes));
+ return htobe64(combined.whole);
+}
+
bool set_nibble(const uint16_t nibble_index, const uint8_t value,
uint8_t* destination, const uint16_t destination_length) {
return copy_bits(&value, CHAR_BIT, NIBBLE_SIZE, NIBBLE_SIZE, destination,
destination_length, nibble_index * NIBBLE_SIZE);
}
+
diff --git a/src/bitfield/bitfield.h b/src/bitfield/bitfield.h
index 5dd976f0..80f31243 100644
--- a/src/bitfield/bitfield.h
+++ b/src/bitfield/bitfield.h
@@ -10,6 +10,36 @@
extern "C" {
#endif
+/* Public: Reads a subset of bits into a uint64_t, right aligned so they may be
+ * interpreted as a number.
+ *
+ * source - the bytes in question.
+ * source_size - the number of bytes in the source.
+ * offset - the starting index of the bit field (beginning from 0).
+ * bit_count - the width of the bit field to extract. This must be less than or
+ * equal to 64.
+ *
+ * Bit fields are positioned according to big-endian bit layout and the data is
+ * swapped automatically as necessary depending on the compiled architecture.
+ *
+ * For example, the bit layout of the value "42" (i.e. 00101010 set at position
+ * 14 with length 6 is:
+ *
+ * 000000000000001010100000000000000000000000000000000000000000000
+ *
+ * and the same value and position but with length 8 is:
+ *
+ * 000000000000000010101000000000000000000000000000000000000000000
+ *
+ * Examples
+ *
+ * uint64_t value = get_bitfield(data, data_size, 2, 4);
+ *
+ * Returns the value of the requested bit field, right aligned in a uint64_t.
+ */
+uint64_t get_bits(const uint8_t source[], const uint8_t source_length,
+ const uint16_t offset, const uint16_t bit_count);
+
/* Public: Return a single nibble from the byte array, with range checking.
*
* source - the source byte array.
@@ -142,7 +172,9 @@ bool set_nibble(const uint16_t nibble_index, const uint8_t value,
*/
uint16_t bits_to_bytes(uint32_t bits);
-/* Private:
+/* Public: Return a right aligned bitmask for a uint64_t.
+ *
+ * bit_count - the number of bits to mask, right aligned.
*/
uint64_t bitmask(const uint8_t bit_count);