3b6b5466d76bdbba32bfa5829df66761acd06797
[apps/agl-service-can-low-level.git] / src / bitfield / 8byte.c
1 #include <bitfield/bitfield.h>
2 #include <bitfield/8byte.h>
3 #include <stddef.h>
4 #include <limits.h>
5 #include <string.h>
6
7 #define EIGHTBYTE_BIT (8 * sizeof(uint64_t))
8
9 uint64_t bitmask(const uint8_t bit_count) {
10     return (((uint64_t)0x1) << bit_count) - 1;
11 }
12
13 static uint16_t bits_to_bytes(uint32_t bits) {
14     uint8_t byte_count = bits / CHAR_BIT;
15     if(bits % CHAR_BIT != 0) {
16         ++byte_count;
17     }
18     return byte_count;
19 }
20
21 uint64_t get_bit_field(uint64_t source, const uint16_t startBit,
22         const uint16_t bit_count, bool big_endian) {
23     uint8_t result[8] = {0};
24     if(!big_endian) {
25         source = __builtin_bswap64(source);
26     }
27     copyBitsRightAligned((const uint8_t*)&source, sizeof(source), startBit,
28             bit_count, result, sizeof(result));
29     uint64_t int_result = 0;
30
31     if(!big_endian) {
32         // we need to swap the byte order of the array to get it into a
33         // uint64_t, but it's been right aligned so we have to be more careful
34         for(int i = 0; i < bits_to_bytes(bit_count); i++) {
35             int_result |= result[bits_to_bytes(bit_count) - i - 1] << (CHAR_BIT * i);
36         }
37     } else {
38         int_result = *(uint64_t*)result;
39     }
40     return int_result;
41 }
42
43 bool set_bit_field(uint64_t* destination, uint64_t value, const uint16_t offset,
44         const uint16_t bit_count) {
45     if(value > bitmask(bit_count)) {
46         return false;
47     }
48
49     int shiftDistance = EIGHTBYTE_BIT - offset - bit_count;
50     value <<= shiftDistance;
51     *destination &= ~(bitmask(bit_count) << shiftDistance);
52     *destination |= value;
53     return true;
54 }
55
56 uint8_t nth_byte(const uint64_t source, const uint16_t byte_index) {
57     return (source >> (EIGHTBYTE_BIT - ((byte_index + 1) * CHAR_BIT))) & 0xFF;
58 }
59