diff options
Diffstat (limited to 'src/bitfield')
-rw-r--r-- | src/bitfield/8byte.c | 56 | ||||
-rw-r--r-- | src/bitfield/8byte.h | 74 | ||||
-rw-r--r-- | src/bitfield/bitfield.c | 50 | ||||
-rw-r--r-- | src/bitfield/bitfield.h | 59 |
4 files changed, 130 insertions, 109 deletions
diff --git a/src/bitfield/8byte.c b/src/bitfield/8byte.c new file mode 100644 index 00000000..0f249d93 --- /dev/null +++ b/src/bitfield/8byte.c @@ -0,0 +1,56 @@ +#include <bitfield/bitfield.h> +#include <bitfield/8byte.h> +#include <stddef.h> +#include <limits.h> +#include <string.h> + +uint64_t bitmask(const uint8_t numBits) { + return (((uint64_t)0x1) << numBits) - 1; +} + +static uint16_t bitsToBytes(uint32_t bits) { + uint8_t byte_count = bits / CHAR_BIT; + if(bits % CHAR_BIT != 0) { + ++byte_count; + } + return byte_count; +} + +uint64_t getBitField(uint64_t data, const uint16_t startBit, + const uint16_t numBits, bool bigEndian) { + uint8_t result[8] = {0}; + if(!bigEndian) { + data = __builtin_bswap64(data); + } + copyBitsRightAligned((const uint8_t*)&data, sizeof(data), startBit, numBits, + result, sizeof(result)); + uint64_t int_result = 0; + + if(!bigEndian) { + // we need to swap the byte order of the array to get it into a + // uint64_t, but it's been right aligned so we have to be more careful + for(int i = 0; i < bitsToBytes(numBits); i++) { + int_result |= result[bitsToBytes(numBits) - i - 1] << (CHAR_BIT * i); + } + } else { + int_result = *(uint64_t*)result; + } + return int_result; +} + +/** + * TODO it would be nice to have a warning if you call with this a value that + * won't fit in the number of bits you've specified it should use. + */ +void setBitField(uint64_t* data, uint64_t value, const uint16_t startPos, + const uint16_t numBits) { + int shiftDistance = 64 - startPos - numBits; + value <<= shiftDistance; + *data &= ~(bitmask(numBits) << shiftDistance); + *data |= value; +} + +uint8_t nthByte(const uint64_t source, const uint16_t byteNum) { + return (source >> (64 - ((byteNum + 1) * CHAR_BIT))) & 0xFF; +} + diff --git a/src/bitfield/8byte.h b/src/bitfield/8byte.h new file mode 100644 index 00000000..13b6aff3 --- /dev/null +++ b/src/bitfield/8byte.h @@ -0,0 +1,74 @@ +#ifndef __8BYTE_H__ +#define __8BYTE_H__ + +#include <stdint.h> +#include <stdbool.h> + +#ifdef __cplusplus +extern "C" { +#endif + +// TODO using uint64_t everywhere for CAN message payload is kind of cute, but +// in actuality a CAN message may have a smaller payload, and it makes all of +// these functions not applicable to other data sizes. It's also fairly +// inefficient on 32-bit platforms. how much work is it to switch vi-firmware +// to using uint8_t*? + +/* Public: Reads a subset of bits from a byte array. + * + * data - the bytes in question. + * startPos - the starting index of the bit field (beginning from 0). + * numBits - the width of the bit field to extract. + * bigEndian - if the data passed in is little endian, set this to false and it + * will be flipped before grabbing the bit field. + * + * Bit fields are positioned according to big-endian bit layout, but inside the + * bit field, values are represented as little-endian. Therefore, to get the bit + * field, we swap the overall byte order if bigEndian == false and + * use the value we find in the field (assuming the embedded platform is little + * endian). + * + * 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 + * + * If the architecture where is code is running is little-endian, the input data + * will be swapped before grabbing the bit field. + * + * Examples + * + * uint64_t value = getBitField(data, 2, 4); + * + * Returns the value of the requested bit field. + */ +uint64_t getBitField(uint64_t data, const uint16_t startPos, + const uint16_t numBits, bool bigEndian); + +/* Public: Set the bit field in the given data array to the new value. + * + * data - a byte array with size at least startPos + numBits. + * value - the value to set in the bit field. + * startPos - the starting index of the bit field (beginning from 0). + */ +void setBitField(uint64_t* data, uint64_t value, const uint16_t startPos, + const uint16_t numBits); + +/* Public: Retreive the nth byte out of 8 bytes in a uint64_t. + * + * source - the source data to retreive the byte from. + * byteNum - the index of the byte, starting at 0 and assuming big-endian order. + * + * Returns the requested byte from the source bytes. + */ +uint8_t nthByte(const uint64_t source, const uint16_t byteNum); + +#ifdef __cplusplus +} +#endif + +#endif // __8BYTE_H__ diff --git a/src/bitfield/bitfield.c b/src/bitfield/bitfield.c index 934d5a6a..3bf00ac0 100644 --- a/src/bitfield/bitfield.c +++ b/src/bitfield/bitfield.c @@ -5,56 +5,6 @@ #define NIBBLE_SIZE (CHAR_BIT / 2) -uint64_t bitmask(const uint8_t numBits) { - return (((uint64_t)0x1) << numBits) - 1; -} - -static uint16_t bitsToBytes(uint32_t bits) { - uint8_t byte_count = bits / CHAR_BIT; - if(bits % CHAR_BIT != 0) { - ++byte_count; - } - return byte_count; -} - -uint64_t getBitField(uint64_t data, const uint16_t startBit, - const uint16_t numBits, bool bigEndian) { - uint8_t result[8] = {0}; - if(!bigEndian) { - data = __builtin_bswap64(data); - } - copyBitsRightAligned((const uint8_t*)&data, sizeof(data), startBit, numBits, - result, sizeof(result)); - uint64_t int_result = 0; - - if(!bigEndian) { - // we need to swap the byte order of the array to get it into a - // uint64_t, but it's been right aligned so we have to be more careful - for(int i = 0; i < bitsToBytes(numBits); i++) { - int_result |= result[bitsToBytes(numBits) - i - 1] << (CHAR_BIT * i); - } - } else { - int_result = *(uint64_t*)result; - } - return int_result; -} - -/** - * TODO it would be nice to have a warning if you call with this a value that - * won't fit in the number of bits you've specified it should use. - */ -void setBitField(uint64_t* data, uint64_t value, const uint16_t startPos, - const uint16_t numBits) { - int shiftDistance = 64 - startPos - numBits; - value <<= shiftDistance; - *data &= ~(bitmask(numBits) << shiftDistance); - *data |= value; -} - -uint8_t nthByte(const uint64_t source, const uint16_t byteNum) { - return (source >> (64 - ((byteNum + 1) * CHAR_BIT))) & 0xFF; -} - uint8_t getNibble(const uint8_t source[], const uint8_t source_length, const uint8_t nibble_index) { uint8_t byte_index = nibble_index / 2; diff --git a/src/bitfield/bitfield.h b/src/bitfield/bitfield.h index 45e3ba26..6f5f1c18 100644 --- a/src/bitfield/bitfield.h +++ b/src/bitfield/bitfield.h @@ -108,65 +108,6 @@ bool copyBitsRightAligned(const uint8_t source[], const uint16_t source_length, const uint16_t offset, const uint16_t bit_count, uint8_t* destination, const uint16_t destination_length); -// TODO using uint64_t everywhere for CAN message payload is kind of cute, but -// in actuality a CAN message may have a smaller payload, and it makes all of -// these functions not applicable to other data sizes. It's also fairly -// inefficient on 32-bit platforms. how much work is it to switch vi-firmware -// to using uint8_t*? - -/* Public: Reads a subset of bits from a byte array. - * - * data - the bytes in question. - * startPos - the starting index of the bit field (beginning from 0). - * numBits - the width of the bit field to extract. - * bigEndian - if the data passed in is little endian, set this to false and it - * will be flipped before grabbing the bit field. - * - * Bit fields are positioned according to big-endian bit layout, but inside the - * bit field, values are represented as little-endian. Therefore, to get the bit - * field, we swap the overall byte order if bigEndian == false and - * use the value we find in the field (assuming the embedded platform is little - * endian). - * - * 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 - * - * If the architecture where is code is running is little-endian, the input data - * will be swapped before grabbing the bit field. - * - * Examples - * - * uint64_t value = getBitField(data, 2, 4); - * - * Returns the value of the requested bit field. - */ -uint64_t getBitField(uint64_t data, const uint16_t startPos, - const uint16_t numBits, bool bigEndian); - -/* Public: Set the bit field in the given data array to the new value. - * - * data - a byte array with size at least startPos + numBits. - * value - the value to set in the bit field. - * startPos - the starting index of the bit field (beginning from 0). - */ -void setBitField(uint64_t* data, uint64_t value, const uint16_t startPos, - const uint16_t numBits); - -/* Public: Retreive the nth byte out of 8 bytes in a uint64_t. - * - * source - the source data to retreive the byte from. - * byteNum - the index of the byte, starting at 0 and assuming big-endian order. - * - * Returns the requested byte from the source bytes. - */ -uint8_t nthByte(const uint64_t source, const uint16_t byteNum); - #ifdef __cplusplus } #endif |