X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fbitfield%2Fbitfield.c;h=934d5a6aaf3306f7ca7508c38808ca1f71bb78f5;hb=a855335e3ad18a9d0094357eb39622448f8649a9;hp=d383db04a047dd79158e80f838e0c62e175ee018;hpb=bc1baf25a0844861713829c0e9e69e4a2d447cc6;p=apps%2Fagl-service-can-low-level.git diff --git a/src/bitfield/bitfield.c b/src/bitfield/bitfield.c index d383db04..934d5a6a 100644 --- a/src/bitfield/bitfield.c +++ b/src/bitfield/bitfield.c @@ -1,60 +1,75 @@ #include +#include +#include +#include -/** - * Find the ending bit of a bitfield within the final byte. - * - * Returns: a bit position from 0 to 7. - */ -int findEndBit(int startBit, int numBits) { - int endBit = (startBit + numBits) % 8; - return endBit == 0 ? 8 : endBit; -} +#define NIBBLE_SIZE (CHAR_BIT / 2) -uint64_t bitmask(int numBits) { +uint64_t bitmask(const uint8_t numBits) { return (((uint64_t)0x1) << numBits) - 1; } -int startingByte(int startBit) { - return startBit / 8; -} - -int endingByte(int startBit, int numBits) { - return (startBit + numBits - 1) / 8; +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, int startBit, int numBits, bool bigEndian) { - int startByte = startingByte(startBit); - int endByte = endingByte(startBit, numBits); - +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); } - uint8_t* bytes = (uint8_t*)&data; - 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++) { - ret = ret << 8; - ret = ret | bytes[i]; + 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; } - - ret >>= 8 - findEndBit(startBit, numBits); - return ret & bitmask(numBits); + 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, int startBit, int numBits) { - int shiftDistance = 64 - startBit - numBits; +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(uint64_t source, int byteNum) { - return (source >> (64 - ((byteNum + 1) * 8))) & 0xFF; +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; + uint8_t result = getByte(source, source_length, byte_index); + if(nibble_index % 2 == 0) { + result >>= NIBBLE_SIZE; + } + result &= bitmask(NIBBLE_SIZE); + return result; +} + +uint8_t getByte(const uint8_t source[], const uint8_t source_length, + const uint8_t byte_index) { + if(byte_index < source_length) { + return source[byte_index]; + } + return 0; }