Refactor kafka to pure Go (franz-go), fix DBC stubs, update Dockerfile
This commit is contained in:
332
pkg/can-go/payload.go
Normal file
332
pkg/can-go/payload.go
Normal file
@@ -0,0 +1,332 @@
|
||||
package can
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// Data holds the data in a CAN frame.
|
||||
//
|
||||
// Layout
|
||||
//
|
||||
// Individual bits in the data are numbered according to the following scheme:
|
||||
//
|
||||
// BIT
|
||||
// NUMBER
|
||||
// +------+------+------+------+------+------+------+------+
|
||||
// | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||||
// BYTE +------+------+------+------+------+------+------+------+
|
||||
// NUMBER
|
||||
// +-----+ +------+------+------+------+------+------+------+------+
|
||||
// | 0 | | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||||
// +-----+ +------+------+------+------+------+------+------+------+
|
||||
// | 1 | | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 |
|
||||
// +-----+ +------+------+------+------+------+------+------+------+
|
||||
// | 2 | | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
|
||||
// +-----+ +------+------+------+------+------+------+------+------+
|
||||
// | 3 | | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 |
|
||||
// +-----+ +------+------+------+------+------+------+------+------+
|
||||
// | 4 | | 39 | 38 | 37 | 36 | 35 | 34 | 33 | 32 |
|
||||
// +-----+ +------+------+------+------+------+------+------+------+
|
||||
// | 5 | | 47 | 46 | 45 | 44 | 43 | 42 | 41 | 40 |
|
||||
// +-----+ +------+------+------+------+------+------+------+------+
|
||||
// | 6 | | 55 | 54 | 53 | 52 | 51 | 50 | 49 | 48 |
|
||||
// +-----+ +------+------+------+------+------+------+------+------+
|
||||
// | 7 | | 63 | 62 | 61 | 60 | 59 | 58 | 57 | 56 |
|
||||
// +-----+ +------+------+------+------+------+------+------+------+
|
||||
//
|
||||
// Bit ranges can be manipulated using little-endian and big-endian bit ordering.
|
||||
//
|
||||
// Little-endian bit ranges
|
||||
//
|
||||
// Example range of length 32 starting at bit 29:
|
||||
//
|
||||
// BIT
|
||||
// NUMBER
|
||||
// +------+------+------+------+------+------+------+------+
|
||||
// | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||||
// BYTE +------+------+------+------+------+------+------+------+
|
||||
// NUMBER
|
||||
// +-----+ +------+------+------+------+------+------+------+------+
|
||||
// | 0 | | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||||
// +-----+ +------+------+------+------+------+------+------+------+
|
||||
// | 1 | | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 |
|
||||
// +-----+ +------+------+------+------+------+------+------+------+
|
||||
// | 2 | | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
|
||||
// +-----+ +------+------+------+------+------+------+------+------+
|
||||
// | 3 | | <-------------LSb | 28 | 27 | 26 | 25 | 24 |
|
||||
// +-----+ +------+------+------+------+------+------+------+------+
|
||||
// | 4 | | <-------------------------------------------------- |
|
||||
// +-----+ +------+------+------+------+------+------+------+------+
|
||||
// | 5 | | <-------------------------------------------------- |
|
||||
// +-----+ +------+------+------+------+------+------+------+------+
|
||||
// | 6 | | <-------------------------------------------------- |
|
||||
// +-----+ +------+------+------+------+------+------+------+------+
|
||||
// | 7 | | 63 | 62 | 61 | <-MSb--------------------------- |
|
||||
// +-----+ +------+------+------+------+------+------+------+------+
|
||||
//
|
||||
// Big-endian bit ranges
|
||||
//
|
||||
// Example range of length 32 starting at bit 29:
|
||||
//
|
||||
// BIT
|
||||
// NUMBER
|
||||
// +------+------+------+------+------+------+------+------+
|
||||
// | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||||
// BYTE +------+------+------+------+------+------+------+------+
|
||||
// NUMBER
|
||||
// +-----+ +------+------+------+------+------+------+------+------+
|
||||
// | 0 | | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||||
// +-----+ +------+------+------+------+------+------+------+------+
|
||||
// | 1 | | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 |
|
||||
// +-----+ +------+------+------+------+------+------+------+------+
|
||||
// | 2 | | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
|
||||
// +-----+ +------+------+------+------+------+------+------+------+
|
||||
// | 3 | | 31 | 30 | <-MSb--------------------------------- |
|
||||
// +-----+ +------+------+------+------+------+------+------+------+
|
||||
// | 4 | | <-------------------------------------------------- |
|
||||
// +-----+ +------+------+------+------+------+------+------+------+
|
||||
// | 5 | | <-------------------------------------------------- |
|
||||
// +-----+ +------+------+------+------+------+------+------+------+
|
||||
// | 6 | | <-------------------------------------------------- |
|
||||
// +-----+ +------+------+------+------+------+------+------+------+
|
||||
// | 7 | | <------LSb | 61 | 60 | 59 | 58 | 57 | 56 |
|
||||
// +-----+ +------+------+------+------+------+------+------+------+
|
||||
|
||||
type Payload struct {
|
||||
// Binary data
|
||||
Data []byte
|
||||
|
||||
// Packed little endian
|
||||
PackedLittleEndian *big.Int
|
||||
|
||||
// Packed big endian
|
||||
PackedBigEndian *big.Int
|
||||
}
|
||||
|
||||
// Hex returns the hexadecimal representation of the byte array in a Payload.
|
||||
func (p *Payload) Hex() string {
|
||||
h := hex.EncodeToString(p.Data)
|
||||
return h
|
||||
}
|
||||
|
||||
// PayloadFromHex generates a Payload from a hexadecimal string.
|
||||
func PayloadFromHex(hexString string) (Payload, error) {
|
||||
b, err := hex.DecodeString(hexString)
|
||||
var p Payload
|
||||
if err != nil {
|
||||
return p, err
|
||||
}
|
||||
p = Payload{Data: b}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// UnsignedBitsLittleEndian returns the little-endian bit range [start, start+length) as an unsigned value.
|
||||
func (p *Payload) UnsignedBitsLittleEndian(start, length uint16) uint64 {
|
||||
// pack bits into one continuous value
|
||||
packed := p.PackLittleEndian()
|
||||
// lsb index in the packed value is the start bit
|
||||
lsbIndex := uint(start)
|
||||
// shift away lower bits
|
||||
shifted := packed.Rsh(packed, lsbIndex)
|
||||
// mask away higher bits
|
||||
masked := shifted.And(shifted, big.NewInt((1<<length)-1))
|
||||
// done
|
||||
return masked.Uint64()
|
||||
}
|
||||
|
||||
// UnsignedBitsBigEndian returns the big-endian bit range [start, start+length) as an unsigned value.
|
||||
func (p *Payload) UnsignedBitsBigEndian(start, length uint16) uint64 {
|
||||
// pack bits into one continuous value
|
||||
packed := p.PackBigEndian()
|
||||
// calculate msb index in the packed value
|
||||
msbIndex := p.invertEndian(start)
|
||||
// calculate lsb index in the packed value
|
||||
lsbIndex := uint(msbIndex - length + 1)
|
||||
// shift away lower bits
|
||||
shifted := packed.Rsh(packed, lsbIndex)
|
||||
// mask away higher bits
|
||||
masked := shifted.And(shifted, big.NewInt((1<<length)-1))
|
||||
// done
|
||||
return masked.Uint64()
|
||||
}
|
||||
|
||||
// SignedBitsLittleEndian returns little-endian bit range [start, start+length) as a signed value.
|
||||
func (p *Payload) SignedBitsLittleEndian(start, length uint16) int64 {
|
||||
unsigned := p.UnsignedBitsLittleEndian(start, length)
|
||||
return AsSigned(unsigned, length)
|
||||
}
|
||||
|
||||
// SignedBitsBigEndian returns little-endian bit range [start, start+length) as a signed value.
|
||||
func (p *Payload) SignedBitsBigEndian(start, length uint16) int64 {
|
||||
unsigned := p.UnsignedBitsBigEndian(start, length)
|
||||
return AsSigned(unsigned, length)
|
||||
}
|
||||
|
||||
// TODO: Implement SetUnsignedBitsLittleEndian for Payload.
|
||||
// SetUnsignedBitsLittleEndian sets the little-endian bit range [start, start+length) to the provided unsigned value.
|
||||
// func (d *Data) SetUnsignedBitsLittleEndian(start, length uint8, value uint64) {
|
||||
// // pack bits into one continuous value
|
||||
// packed := d.PackLittleEndian()
|
||||
// // lsb index in the packed value is the start bit
|
||||
// lsbIndex := start
|
||||
// // calculate bit mask for zeroing the bit range to set
|
||||
// unsetMask := ^uint64(((1 << length) - 1) << lsbIndex)
|
||||
// // calculate bit mask for setting the new value
|
||||
// setMask := value << lsbIndex
|
||||
// // calculate the new packed value
|
||||
// newPacked := packed&unsetMask | setMask
|
||||
// // unpack the new packed value into the data
|
||||
// d.UnpackLittleEndian(newPacked)
|
||||
// }
|
||||
|
||||
// TODO: Implement SetUnsignedBitsBigEndian for Payload.
|
||||
// SetUnsignedBitsBigEndian sets the big-endian bit range [start, start+length) to the provided unsigned value.
|
||||
// func (d *Data) SetUnsignedBitsBigEndian(start, length uint8, value uint64) {
|
||||
// // pack bits into one continuous value
|
||||
// packed := d.PackBigEndian()
|
||||
// // calculate msb index in the packed value
|
||||
// msbIndex := invertEndian(start)
|
||||
// // calculate lsb index in the packed value
|
||||
// lsbIndex := msbIndex - length + 1
|
||||
// // calculate bit mask for zeroing the bit range to set
|
||||
// unsetMask := ^uint64(((1 << length) - 1) << lsbIndex)
|
||||
// // calculate bit mask for setting the new value
|
||||
// setMask := value << lsbIndex
|
||||
// // calculate the new packed value
|
||||
// newPacked := packed&unsetMask | setMask
|
||||
// // unpack the new packed value into the data
|
||||
// d.UnpackBigEndian(newPacked)
|
||||
// }
|
||||
|
||||
// TODO: Implement SetSignedBitsLittleEndian for Payload.
|
||||
// SetSignedBitsLittleEndian sets the little-endian bit range [start, start+length) to the provided signed value.
|
||||
// func (d *Data) SetSignedBitsLittleEndian(start, length uint8, value int64) {
|
||||
// d.SetUnsignedBitsLittleEndian(start, length, reinterpret.AsUnsigned(value, length))
|
||||
// }
|
||||
|
||||
// TODO: Implement SetSignedBitsBigEndian for Payload.
|
||||
// SetSignedBitsBigEndian sets the big-endian bit range [start, start+length) to the provided signed value.
|
||||
// func (d *Data) SetSignedBitsBigEndian(start, length uint8, value int64) {
|
||||
// d.SetUnsignedBitsBigEndian(start, length, reinterpret.AsUnsigned(value, length))
|
||||
// }
|
||||
|
||||
// Bit returns the value of the i:th bit in the data as a bool.
|
||||
func (p *Payload) Bit(i uint16) bool {
|
||||
if int(i) > 8*len(p.Data)-1 {
|
||||
return false
|
||||
}
|
||||
// calculate which byte the bit belongs to
|
||||
byteIndex := i / 8
|
||||
// calculate bit mask for extracting the bit
|
||||
bitMask := uint8(1 << (i % 8))
|
||||
// mocks the bit
|
||||
bit := p.Data[byteIndex]&bitMask > 0
|
||||
// done
|
||||
return bit
|
||||
}
|
||||
|
||||
// SetBit sets the value of the i:th bit in the data.
|
||||
func (p *Payload) SetBit(i uint16, value bool) {
|
||||
if int(i) > 8*len(p.Data)-1 {
|
||||
return
|
||||
}
|
||||
byteIndex := i / 8
|
||||
bitIndex := i % 8
|
||||
if value {
|
||||
p.Data[byteIndex] |= uint8(1 << bitIndex)
|
||||
} else {
|
||||
p.Data[byteIndex] &= ^uint8(1 << bitIndex)
|
||||
}
|
||||
}
|
||||
|
||||
// PackLittleEndian packs the byte array into a continuous little endian big.Int.
|
||||
func (p *Payload) PackLittleEndian() *big.Int {
|
||||
if p.PackedLittleEndian == nil {
|
||||
packed := new(big.Int).SetBytes(reverse(p.Data))
|
||||
p.PackedLittleEndian = packed
|
||||
}
|
||||
return new(big.Int).Set(p.PackedLittleEndian)
|
||||
}
|
||||
|
||||
// Reverse byte array for little endian signals.
|
||||
func reverse(data []byte) []byte {
|
||||
reversedArray := make([]byte, len(data))
|
||||
for i, j := 0, len(data)-1; i < j; i, j = i+1, j-1 {
|
||||
reversedArray[i], reversedArray[j] = data[j], data[i]
|
||||
}
|
||||
return reversedArray
|
||||
}
|
||||
|
||||
// PackBigEndian packs the byte array into a continuous big endian big.Int.
|
||||
func (p *Payload) PackBigEndian() *big.Int {
|
||||
if p.PackedBigEndian == nil {
|
||||
packed := new(big.Int).SetBytes(p.Data)
|
||||
p.PackedBigEndian = packed
|
||||
}
|
||||
return new(big.Int).Set(p.PackedBigEndian)
|
||||
}
|
||||
|
||||
// TODO: Implement UnpackLittleEndian for Payload.
|
||||
// UnpackLittleEndian sets the value of d.Bytes by unpacking the provided value as sequential little-endian bits.
|
||||
// func (d *Data) UnpackLittleEndian(packed uint64) {
|
||||
// d[0] = uint8(packed >> (0 * 8))
|
||||
// d[1] = uint8(packed >> (1 * 8))
|
||||
// d[2] = uint8(packed >> (2 * 8))
|
||||
// d[3] = uint8(packed >> (3 * 8))
|
||||
// d[4] = uint8(packed >> (4 * 8))
|
||||
// d[5] = uint8(packed >> (5 * 8))
|
||||
// d[6] = uint8(packed >> (6 * 8))
|
||||
// d[7] = uint8(packed >> (7 * 8))
|
||||
// }
|
||||
|
||||
// TODO: Implement UnpackBigEndian for Payload.
|
||||
// UnpackBigEndian sets the value of d.Bytes by unpacking the provided value as sequential big-endian bits.
|
||||
// func (d *Data) UnpackBigEndian(packed uint64) {
|
||||
// d[0] = uint8(packed >> (7 * 8))
|
||||
// d[1] = uint8(packed >> (6 * 8))
|
||||
// d[2] = uint8(packed >> (5 * 8))
|
||||
// d[3] = uint8(packed >> (4 * 8))
|
||||
// d[4] = uint8(packed >> (3 * 8))
|
||||
// d[5] = uint8(packed >> (2 * 8))
|
||||
// d[6] = uint8(packed >> (1 * 8))
|
||||
// d[7] = uint8(packed >> (0 * 8))
|
||||
// }
|
||||
|
||||
// invertEndian converts from big-endian to little-endian bit indexing and vice versa.
|
||||
func (p *Payload) invertEndian(i uint16) uint16 {
|
||||
row := i / 8
|
||||
col := i % 8
|
||||
oppositeRow := uint16(len(p.Data)) - row - 1
|
||||
bitIndex := (oppositeRow * 8) + col
|
||||
return bitIndex
|
||||
}
|
||||
|
||||
// AsSigned reinterprets the provided unsigned value as a signed value.
|
||||
func AsSigned(unsigned uint64, bits uint16) int64 {
|
||||
switch bits {
|
||||
case 8:
|
||||
return int64(int8(uint8(unsigned)))
|
||||
case 16:
|
||||
return int64(int16(uint16(unsigned)))
|
||||
case 32:
|
||||
return int64(int32(uint32(unsigned)))
|
||||
case 64:
|
||||
return int64(unsigned)
|
||||
default:
|
||||
// calculate bit mask for sign bit
|
||||
signBitMask := uint64(1 << (bits - 1))
|
||||
// check if sign bit is set
|
||||
isNegative := unsigned&signBitMask > 0
|
||||
if !isNegative {
|
||||
// sign bit not set means we can reinterpret the value as-is
|
||||
return int64(unsigned)
|
||||
}
|
||||
// calculate bit mask for extracting value bits (all bits except the sign bit)
|
||||
valueBitMask := signBitMask - 1
|
||||
// calculate two's complement of the value bits
|
||||
value := ((^unsigned) & valueBitMask) + 1
|
||||
// result is the negative value of the two's complement
|
||||
return -1 * int64(value)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user