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< 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) } }