bf5c9b7d2795f659ab223c15d991c297b53038f4
[apps/low-level-can-service.git] / src / bitfield / bitfield.h
1 #ifndef __BITFIELD_H__
2 #define __BITFIELD_H__
3
4 #include <stdint.h>
5 #include <stdbool.h>
6
7 #ifdef __cplusplus
8 extern "C" {
9 #endif
10
11 uint8_t getNibble(const uint8_t nibble_index, const uint8_t data[],
12         const uint8_t length);
13
14 uint8_t getByte(const uint8_t byte_index, const uint8_t data[],
15         const uint8_t length);
16
17 /* Public: Copy a range of bits from one bit array to another.
18  *
19  * The range does not need to be byte aligned, and the source and destination do
20  * not have to be the same size (as long as the desitnation has enough room to
21  * fit the range).
22  *
23  * A bit array with regards to this function always has the leftmost bit in byte
24  * 0, i.e. bit index is the leftmost bit of byte 0. Endianness does not matter.
25  *
26  * Thanks to
27  * http://stackoverflow.com/questions/3534535/whats-a-time-efficient-algorithm-to-copy-unaligned-bit-arrays
28  * for the implementation of the algorithm.
29  *
30  * source_origin - the source array.
31  * source_length - the total length of the source array in bytes,
32  *      for range checking.
33  * source_offset - an offset in bits to start the copy from the source array.
34  *      Specify 0 to start from source_origin.
35  * bit_count - the number of bits to copy.
36  * destination_origin - the destination array.
37  * desitnation_length - the total length of the destination array in bytes,
38  *      for range checking.
39  * destination_offset - an offset in bits to start placing the copied range into
40  *      the destination array. Specify 0 to start from the beginning of the
41  *      destination. If you are copying a range not aligned on a byte, you
42  *      probably want to set this to a positive offset to right the resulting
43  *      bits in the destination.
44  *
45  * Returns true if the copy was successful and false if the range exceeded the
46  * size of the source or destination, or if the range size negative or 0.
47  */
48 bool copyBits(const uint8_t* source_origin, const uint16_t source_length,
49         const uint16_t source_offset, uint16_t bit_count,
50         uint8_t* destination_origin, const uint16_t destination_length,
51         const uint16_t destination_offset);
52
53 bool copyBitsRightAligned(const uint8_t source[], const uint16_t source_length,
54                 const uint16_t offset, const uint16_t bit_count,
55                 uint8_t* destination, const uint16_t destination_length);
56
57 // TODO using uint64_t everywhere for CAN message payload is kind of cute, but
58 // in actuality a CAN message may have a smaller payload, and it makes all of
59 // these functions not applicable to other data sizes. It's also fairly
60 // inefficient on 32-bit platforms. how much work is it to switch vi-firmware
61 // to using uint8_t*?
62
63 /* Public: Reads a subset of bits from a byte array.
64  *
65  * data - the bytes in question.
66  * startPos - the starting index of the bit field (beginning from 0).
67  * numBits - the width of the bit field to extract.
68  * bigEndian - if the data passed in is little endian, set this to false and it
69  *      will be flipped before grabbing the bit field.
70  *
71  * Bit fields are positioned according to big-endian bit layout, but inside the
72  * bit field, values are represented as little-endian. Therefore, to get the bit
73  * field, we swap the overall byte order if bigEndian == false and
74  * use the value we find in the field (assuming the embedded platform is little
75  * endian).
76  *
77  * For example, the bit layout of the value "42" (i.e. 00101010 set at position
78  * 14 with length 6 is:
79  *
80  *     000000000000001010100000000000000000000000000000000000000000000
81  *
82  * and the same value and position but with length 8 is:
83  *
84  *     000000000000000010101000000000000000000000000000000000000000000
85  *
86  * If the architecture where is code is running is little-endian, the input data
87  * will be swapped before grabbing the bit field.
88  *
89  * Examples
90  *
91  *  uint64_t value = getBitField(data, 2, 4);
92  *
93  * Returns the value of the requested bit field.
94  */
95 uint64_t getBitField(uint64_t data, const uint16_t startPos,
96         const uint16_t numBits, bool bigEndian);
97
98 /* Public: Set the bit field in the given data array to the new value.
99  *
100  * data - a byte array with size at least startPos + numBits.
101  * value - the value to set in the bit field.
102  * startPos - the starting index of the bit field (beginning from 0).
103  */
104 void setBitField(uint64_t* data, uint64_t value, const uint16_t startPos,
105         const uint16_t numBits);
106
107 /* Public: Retreive the nth byte out of 8 bytes in a uint64_t.
108  *
109  * source - the source data to retreive the byte from.
110  * byteNum - the index of the byte, starting at 0 and assuming big-endian order.
111  *
112  * Returns the requested byte from the source bytes.
113  */
114 uint8_t nthByte(const uint64_t source, const uint16_t byteNum);
115
116 #ifdef __cplusplus
117 }
118 #endif
119
120 #endif // __BITFIELD_H__