github.com/jordan-bonecutter/can-go@v0.0.0-20230901155856-d83995b18e50/data.go (about)

     1  package can
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"go.einride.tech/can/internal/reinterpret"
     7  )
     8  
     9  const MaxDataLength = 8
    10  
    11  // Data holds the data in a CAN frame.
    12  //
    13  // # Layout
    14  //
    15  // Individual bits in the data are numbered according to the following scheme:
    16  //
    17  //	         BIT
    18  //	         NUMBER
    19  //	         +------+------+------+------+------+------+------+------+
    20  //	         |   7  |   6  |   5  |   4  |   3  |   2  |   1  |   0  |
    21  //	BYTE     +------+------+------+------+------+------+------+------+
    22  //	NUMBER
    23  //	+-----+  +------+------+------+------+------+------+------+------+
    24  //	|  0  |  |   7  |   6  |   5  |   4  |   3  |   2  |   1  |   0  |
    25  //	+-----+  +------+------+------+------+------+------+------+------+
    26  //	|  1  |  |  15  |  14  |  13  |  12  |  11  |  10  |   9  |   8  |
    27  //	+-----+  +------+------+------+------+------+------+------+------+
    28  //	|  2  |  |  23  |  22  |  21  |  20  |  19  |  18  |  17  |  16  |
    29  //	+-----+  +------+------+------+------+------+------+------+------+
    30  //	|  3  |  |  31  |  30  |  29  |  28  |  27  |  26  |  25  |  24  |
    31  //	+-----+  +------+------+------+------+------+------+------+------+
    32  //	|  4  |  |  39  |  38  |  37  |  36  |  35  |  34  |  33  |  32  |
    33  //	+-----+  +------+------+------+------+------+------+------+------+
    34  //	|  5  |  |  47  |  46  |  45  |  44  |  43  |  42  |  41  |  40  |
    35  //	+-----+  +------+------+------+------+------+------+------+------+
    36  //	|  6  |  |  55  |  54  |  53  |  52  |  51  |  50  |  49  |  48  |
    37  //	+-----+  +------+------+------+------+------+------+------+------+
    38  //	|  7  |  |  63  |  62  |  61  |  60  |  59  |  58  |  57  |  56  |
    39  //	+-----+  +------+------+------+------+------+------+------+------+
    40  //
    41  // Bit ranges can be manipulated using little-endian and big-endian bit ordering.
    42  //
    43  // # Little-endian bit ranges
    44  //
    45  // Example range of length 32 starting at bit 29:
    46  //
    47  //	         BIT
    48  //	         NUMBER
    49  //	         +------+------+------+------+------+------+------+------+
    50  //	         |   7  |   6  |   5  |   4  |   3  |   2  |   1  |   0  |
    51  //	BYTE     +------+------+------+------+------+------+------+------+
    52  //	NUMBER
    53  //	+-----+  +------+------+------+------+------+------+------+------+
    54  //	|  0  |  |   7  |   6  |   5  |   4  |   3  |   2  |   1  |   0  |
    55  //	+-----+  +------+------+------+------+------+------+------+------+
    56  //	|  1  |  |  15  |  14  |  13  |  12  |  11  |  10  |   9  |   8  |
    57  //	+-----+  +------+------+------+------+------+------+------+------+
    58  //	|  2  |  |  23  |  22  |  21  |  20  |  19  |  18  |  17  |  16  |
    59  //	+-----+  +------+------+------+------+------+------+------+------+
    60  //	|  3  |  |  <-------------LSb |  28  |  27  |  26  |  25  |  24  |
    61  //	+-----+  +------+------+------+------+------+------+------+------+
    62  //	|  4  |  |  <--------------------------------------------------  |
    63  //	+-----+  +------+------+------+------+------+------+------+------+
    64  //	|  5  |  |  <--------------------------------------------------  |
    65  //	+-----+  +------+------+------+------+------+------+------+------+
    66  //	|  6  |  |  <--------------------------------------------------  |
    67  //	+-----+  +------+------+------+------+------+------+------+------+
    68  //	|  7  |  |  63  |  62  |  61  | <-MSb--------------------------- |
    69  //	+-----+  +------+------+------+------+------+------+------+------+
    70  //
    71  // # Big-endian bit ranges
    72  //
    73  // Example range of length 32 starting at bit 29:
    74  //
    75  //	         BIT
    76  //	         NUMBER
    77  //	         +------+------+------+------+------+------+------+------+
    78  //	         |   7  |   6  |   5  |   4  |   3  |   2  |   1  |   0  |
    79  //	BYTE     +------+------+------+------+------+------+------+------+
    80  //	NUMBER
    81  //	+-----+  +------+------+------+------+------+------+------+------+
    82  //	|  0  |  |   7  |   6  |   5  |   4  |   3  |   2  |   1  |   0  |
    83  //	+-----+  +------+------+------+------+------+------+------+------+
    84  //	|  1  |  |  15  |  14  |  13  |  12  |  11  |  10  |   9  |   8  |
    85  //	+-----+  +------+------+------+------+------+------+------+------+
    86  //	|  2  |  |  23  |  22  |  21  |  20  |  19  |  18  |  17  |  16  |
    87  //	+-----+  +------+------+------+------+------+------+------+------+
    88  //	|  3  |  |  31  |  30  | <-MSb---------------------------------  |
    89  //	+-----+  +------+------+------+------+------+------+------+------+
    90  //	|  4  |  |  <--------------------------------------------------  |
    91  //	+-----+  +------+------+------+------+------+------+------+------+
    92  //	|  5  |  |  <--------------------------------------------------  |
    93  //	+-----+  +------+------+------+------+------+------+------+------+
    94  //	|  6  |  |  <--------------------------------------------------  |
    95  //	+-----+  +------+------+------+------+------+------+------+------+
    96  //	|  7  |  |  <------LSb |  61  |  60  |  59  |  58  |  57  |  56  |
    97  //	+-----+  +------+------+------+------+------+------+------+------+
    98  type Data [MaxDataLength]byte
    99  
   100  // UnsignedBitsLittleEndian returns the little-endian bit range [start, start+length) as an unsigned value.
   101  func (d *Data) UnsignedBitsLittleEndian(start, length uint8) uint64 {
   102  	// pack bits into one continuous value
   103  	packed := d.PackLittleEndian()
   104  	// lsb index in the packed value is the start bit
   105  	lsbIndex := start
   106  	// shift away lower bits
   107  	shifted := packed >> lsbIndex
   108  	// mask away higher bits
   109  	masked := shifted & ((1 << length) - 1)
   110  	// done
   111  	return masked
   112  }
   113  
   114  // UnsignedBitsBigEndian returns the big-endian bit range [start, start+length) as an unsigned value.
   115  func (d *Data) UnsignedBitsBigEndian(start, length uint8) uint64 {
   116  	// pack bits into one continuous value
   117  	packed := d.PackBigEndian()
   118  	// calculate msb index in the packed value
   119  	msbIndex := invertEndian(start)
   120  	// calculate lsb index in the packed value
   121  	lsbIndex := msbIndex - length + 1
   122  	// shift away lower bits
   123  	shifted := packed >> lsbIndex
   124  	// mask away higher bits
   125  	masked := shifted & ((1 << length) - 1)
   126  	// done
   127  	return masked
   128  }
   129  
   130  // SignedBitsLittleEndian returns little-endian bit range [start, start+length) as a signed value.
   131  func (d *Data) SignedBitsLittleEndian(start, length uint8) int64 {
   132  	unsigned := d.UnsignedBitsLittleEndian(start, length)
   133  	return reinterpret.AsSigned(unsigned, length)
   134  }
   135  
   136  // SignedBitsBigEndian returns little-endian bit range [start, start+length) as a signed value.
   137  func (d *Data) SignedBitsBigEndian(start, length uint8) int64 {
   138  	unsigned := d.UnsignedBitsBigEndian(start, length)
   139  	return reinterpret.AsSigned(unsigned, length)
   140  }
   141  
   142  // SetUnsignedBitsBigEndian sets the little-endian bit range [start, start+length) to the provided unsigned value.
   143  func (d *Data) SetUnsignedBitsLittleEndian(start, length uint8, value uint64) {
   144  	// pack bits into one continuous value
   145  	packed := d.PackLittleEndian()
   146  	// lsb index in the packed value is the start bit
   147  	lsbIndex := start
   148  	// calculate bit mask for zeroing the bit range to set
   149  	unsetMask := ^uint64(((1 << length) - 1) << lsbIndex)
   150  	// calculate bit mask for setting the new value
   151  	setMask := value << lsbIndex
   152  	// calculate the new packed value
   153  	newPacked := packed&unsetMask | setMask
   154  	// unpack the new packed value into the data
   155  	d.UnpackLittleEndian(newPacked)
   156  }
   157  
   158  // SetUnsignedBitsBigEndian sets the big-endian bit range [start, start+length) to the provided unsigned value.
   159  func (d *Data) SetUnsignedBitsBigEndian(start, length uint8, value uint64) {
   160  	// pack bits into one continuous value
   161  	packed := d.PackBigEndian()
   162  	// calculate msb index in the packed value
   163  	msbIndex := invertEndian(start)
   164  	// calculate lsb index in the packed value
   165  	lsbIndex := msbIndex - length + 1
   166  	// calculate bit mask for zeroing the bit range to set
   167  	unsetMask := ^uint64(((1 << length) - 1) << lsbIndex)
   168  	// calculate bit mask for setting the new value
   169  	setMask := value << lsbIndex
   170  	// calculate the new packed value
   171  	newPacked := packed&unsetMask | setMask
   172  	// unpack the new packed value into the data
   173  	d.UnpackBigEndian(newPacked)
   174  }
   175  
   176  // SetSignedBitsLittleEndian sets the little-endian bit range [start, start+length) to the provided signed value.
   177  func (d *Data) SetSignedBitsLittleEndian(start, length uint8, value int64) {
   178  	d.SetUnsignedBitsLittleEndian(start, length, reinterpret.AsUnsigned(value, length))
   179  }
   180  
   181  // SetSignedBitsBigEndian sets the big-endian bit range [start, start+length) to the provided signed value.
   182  func (d *Data) SetSignedBitsBigEndian(start, length uint8, value int64) {
   183  	d.SetUnsignedBitsBigEndian(start, length, reinterpret.AsUnsigned(value, length))
   184  }
   185  
   186  // Bit returns the value of the i:th bit in the data as a bool.
   187  func (d *Data) Bit(i uint8) bool {
   188  	if i > 63 {
   189  		return false
   190  	}
   191  	// calculate which byte the bit belongs to
   192  	byteIndex := i / 8
   193  	// calculate bit mask for extracting the bit
   194  	bitMask := uint8(1 << (i % 8))
   195  	// mocks the bit
   196  	bit := d[byteIndex]&bitMask > 0
   197  	// done
   198  	return bit
   199  }
   200  
   201  // SetBit sets the value of the i:th bit in the data.
   202  func (d *Data) SetBit(i uint8, value bool) {
   203  	if i > 63 {
   204  		return
   205  	}
   206  	byteIndex := i / 8
   207  	bitIndex := i % 8
   208  	if value {
   209  		d[byteIndex] |= uint8(1 << bitIndex)
   210  	} else {
   211  		d[byteIndex] &= ^uint8(1 << bitIndex)
   212  	}
   213  }
   214  
   215  // PackLittleEndian packs the data into a contiguous uint64 value for little-endian signals.
   216  func (d *Data) PackLittleEndian() uint64 {
   217  	var packed uint64
   218  	packed |= uint64(d[0]) << (0 * 8)
   219  	packed |= uint64(d[1]) << (1 * 8)
   220  	packed |= uint64(d[2]) << (2 * 8)
   221  	packed |= uint64(d[3]) << (3 * 8)
   222  	packed |= uint64(d[4]) << (4 * 8)
   223  	packed |= uint64(d[5]) << (5 * 8)
   224  	packed |= uint64(d[6]) << (6 * 8)
   225  	packed |= uint64(d[7]) << (7 * 8)
   226  	return packed
   227  }
   228  
   229  // PackBigEndian packs the data into a contiguous uint64 value for big-endian signals.
   230  func (d *Data) PackBigEndian() uint64 {
   231  	var packed uint64
   232  	packed |= uint64(d[0]) << (7 * 8)
   233  	packed |= uint64(d[1]) << (6 * 8)
   234  	packed |= uint64(d[2]) << (5 * 8)
   235  	packed |= uint64(d[3]) << (4 * 8)
   236  	packed |= uint64(d[4]) << (3 * 8)
   237  	packed |= uint64(d[5]) << (2 * 8)
   238  	packed |= uint64(d[6]) << (1 * 8)
   239  	packed |= uint64(d[7]) << (0 * 8)
   240  	return packed
   241  }
   242  
   243  // UnpackLittleEndian sets the value of d.Bytes by unpacking the provided value as sequential little-endian bits.
   244  func (d *Data) UnpackLittleEndian(packed uint64) {
   245  	d[0] = uint8(packed >> (0 * 8))
   246  	d[1] = uint8(packed >> (1 * 8))
   247  	d[2] = uint8(packed >> (2 * 8))
   248  	d[3] = uint8(packed >> (3 * 8))
   249  	d[4] = uint8(packed >> (4 * 8))
   250  	d[5] = uint8(packed >> (5 * 8))
   251  	d[6] = uint8(packed >> (6 * 8))
   252  	d[7] = uint8(packed >> (7 * 8))
   253  }
   254  
   255  // UnpackBigEndian sets the value of d.Bytes by unpacking the provided value as sequential big-endian bits.
   256  func (d *Data) UnpackBigEndian(packed uint64) {
   257  	d[0] = uint8(packed >> (7 * 8))
   258  	d[1] = uint8(packed >> (6 * 8))
   259  	d[2] = uint8(packed >> (5 * 8))
   260  	d[3] = uint8(packed >> (4 * 8))
   261  	d[4] = uint8(packed >> (3 * 8))
   262  	d[5] = uint8(packed >> (2 * 8))
   263  	d[6] = uint8(packed >> (1 * 8))
   264  	d[7] = uint8(packed >> (0 * 8))
   265  }
   266  
   267  // invertEndian converts from big-endian to little-endian bit indexing and vice versa.
   268  func invertEndian(i uint8) uint8 {
   269  	row := i / 8
   270  	col := i % 8
   271  	oppositeRow := 7 - row
   272  	bitIndex := (oppositeRow * 8) + col
   273  	return bitIndex
   274  }
   275  
   276  // CheckBitRangeLittleEndian checks that a little-endian bit range fits in the data.
   277  func CheckBitRangeLittleEndian(frameLength, rangeStart, rangeLength uint8) error {
   278  	lsbIndex := rangeStart
   279  	msbIndex := rangeStart + rangeLength - 1
   280  	upperBound := frameLength * 8
   281  	if msbIndex >= upperBound {
   282  		return fmt.Errorf("bit range out of bounds [0, %v): [%v, %v]", upperBound, lsbIndex, msbIndex)
   283  	}
   284  	return nil
   285  }
   286  
   287  // CheckBitRangeBigEndian checks that a big-endian bit range fits in the data.
   288  func CheckBitRangeBigEndian(frameLength, rangeStart, rangeLength uint8) error {
   289  	upperBound := frameLength * 8
   290  	if rangeStart >= upperBound {
   291  		return fmt.Errorf("bit range starts out of bounds [0, %v): %v", upperBound, rangeStart)
   292  	}
   293  	msbIndex := invertEndian(rangeStart)
   294  	lsbIndex := msbIndex - rangeLength + 1
   295  	end := invertEndian(lsbIndex)
   296  	if end >= upperBound {
   297  		return fmt.Errorf("bit range ends out of bounds [0, %v): %v", upperBound, end)
   298  	}
   299  	return nil
   300  }
   301  
   302  // CheckValue checks that a value fits in a number of bits.
   303  func CheckValue(value uint64, bits uint8) error {
   304  	upperBound := uint64(1 << bits)
   305  	if value >= upperBound {
   306  		return fmt.Errorf("value out of bounds [0, %v): %v", upperBound, value)
   307  	}
   308  	return nil
   309  }