diff options
author | Christopher Peplin <chris.peplin@rhubarbtech.com> | 2014-01-04 10:51:16 -0500 |
---|---|---|
committer | Christopher Peplin <chris.peplin@rhubarbtech.com> | 2014-01-04 10:52:42 -0500 |
commit | 08db5c9eb826f7aa0dba36cbef8011d7bc6b55a5 (patch) | |
tree | b2875552387f00191c772bc6da08dcaa7e6d2e87 /src | |
parent | 6f3a81ed8287357b54aad16bff27495c6eaca6df (diff) |
Add a get_bitfield function for byte arrays.
Diffstat (limited to 'src')
-rw-r--r-- | src/bitfield/8byte.c | 10 | ||||
-rw-r--r-- | src/bitfield/8byte.h | 4 | ||||
-rw-r--r-- | src/bitfield/bitfield.c | 18 | ||||
-rw-r--r-- | src/bitfield/bitfield.h | 34 | ||||
-rw-r--r-- | src/canutil/read.c | 18 | ||||
-rw-r--r-- | src/canutil/read.h | 42 |
6 files changed, 110 insertions, 16 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); diff --git a/src/canutil/read.c b/src/canutil/read.c index 4864a60f..3931721a 100644 --- a/src/canutil/read.c +++ b/src/canutil/read.c @@ -4,7 +4,7 @@ float eightbyte_parse_float(uint64_t data, uint8_t bit_offset, uint8_t bit_size, float factor, float offset) { - uint64_t raw = eightbyte_get_bit_field(data, bit_offset, bit_size, true); + uint64_t raw = eightbyte_get_bitfield(data, bit_offset, bit_size, true); return raw * factor + offset; } @@ -14,9 +14,19 @@ bool eightbyte_parse_bool(uint64_t data, uint8_t bit_offset, uint8_t bit_size, return value == 0.0 ? false : true; } -float bitfield_parse_float(const uint8_t data[], const uint16_t size, +float bitfield_parse_float(const uint8_t source[], const uint16_t source_length, const uint8_t bit_offset, const uint8_t bit_size, const float factor, const float offset) { - //TODO - return 0; + uint64_t raw = get_bitfield(source, source_length, bit_offset, bit_size); + // TODO seems dumb that this is repeated from eightbyte_parse_float - is it + // really worth keeping around these two implementations? + return raw * factor + offset; +} + +float bitfield_parse_bool(const uint8_t source[], const uint16_t source_length, + const uint8_t bit_offset, const uint8_t bit_size, const float factor, + const float offset) { + float value = bitfield_parse_float(source, source_length, bit_offset, + bit_size, factor, offset); + return value == 0.0 ? false : true; } diff --git a/src/canutil/read.h b/src/canutil/read.h index bf6c0ade..733e3509 100644 --- a/src/canutil/read.h +++ b/src/canutil/read.h @@ -10,7 +10,7 @@ extern "C" { /* Public: Parse a CAN signal from a message and apply required transformation. * - * data - the payload containing the signal. + * source - the payload containing the signal. * bit_offset - the starting bit for the signal. * bit_size - the width of the signal. * factor - the transformation factor for the signal value, applied after @@ -20,16 +20,30 @@ extern "C" { * * Returns the decoded and transformed value of the signal. */ -float eightbyte_parse_float(const uint64_t data, const uint8_t bit_offset, +float eightbyte_parse_float(const uint64_t source, const uint8_t bit_offset, const uint8_t bit_size, const float factor, const float offset); -float bitfield_parse_float(const uint8_t data[], const uint16_t size, +/* Public: Parse a CAN signal from a message storage as a byte array and apply + * required transformation. + * + * source - the payload containing the signal. + * source_size - the size of the payload in bytes. + * bit_offset - the starting bit for the signal. + * bit_size - the width of the signal. + * factor - the transformation factor for the signal value, applied after + * pulling out the bit field. Use 1.0 for no factor. + * offset - the transformation offset for the signal value, applied after + * pulling out the bit field. Use 0 for no offset. + * + * Returns the decoded and transformed value of the signal. + */ +float bitfield_parse_float(const uint8_t source[], const uint16_t source_size, const uint8_t bit_offset, const uint8_t bit_size, const float factor, const float offset); /* Public: Parse a CAN signal from a message and interpret it as a boolean. * - * data - the payload containing the signal. + * source - the payload containing the signal. * bit_offset - the starting bit for the signal. * bit_size - the width of the signal. * factor - the transformation factor for the signal value, applied after @@ -39,9 +53,27 @@ float bitfield_parse_float(const uint8_t data[], const uint16_t size, * * Returns false if the value was 0, otherwise true. */ -bool eightbyte_parse_bool(uint64_t data, uint8_t bit_offset, uint8_t bit_size, +bool eightbyte_parse_bool(uint64_t source, uint8_t bit_offset, uint8_t bit_size, float factor, float offset); +/* Public: Parse a CAN signal from a message storage as a byte array and + * interpret it as a boolean. + * + * source - the payload containing the signal. + * source_size - the size of the payload in bytes. + * bit_offset - the starting bit for the signal. + * bit_size - the width of the signal. + * factor - the transformation factor for the signal value, applied after + * pulling out the bit field. Use 1.0 for no factor. + * offset - the transformation offset for the signal value, applied after + * pulling out the bit field. Use 0 for no offset. + * + * Returns false if the value was 0, otherwise true. + */ +float bitfield_parse_float(const uint8_t source[], const uint16_t source_size, + const uint8_t bit_offset, const uint8_t bit_size, const float factor, + const float offset); + #ifdef __cplusplus } #endif |