can

package module
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 25, 2023 License: MIT Imports: 7 Imported by: 0

README

🔌 CAN Go

PkgGoDev GoReportCard Codecov

CAN toolkit for Go programmers.

can-go makes use of the Linux SocketCAN abstraction for CAN communication. (See the SocketCAN documentation for more details).

Examples

Decoding CAN messages

Decoding CAN messages from byte arrays can be done using can.Payload

func main() {
	// DBC file
	var dbcFile = []byte(`
	VERSION ""
    NS_ :
    BS_:
    BU_: DBG DRIVER IO MOTOR SENSOR
    
    BO_ 400 MOTOR_STATUS: 3 MOTOR
	  SG_ MOTOR_STATUS_wheel_error : 0|1@1+ (1,0) [0|0] "" DRIVER,IO
	  SG_ MOTOR_STATUS_speed_kph : 8|16@1+ (0.001,0) [0|0] "kph" DRIVER,IO

	BO_ 200 SENSOR_SONARS: 8 SENSOR
	  SG_ SENSOR_SONARS_mux M : 0|4@1+ (1,0) [0|0] "" DRIVER,IO
	  SG_ SENSOR_SONARS_err_count : 4|12@1+ (1,0) [0|0] "" DRIVER,IO
	  SG_ SENSOR_SONARS_left m0 : 16|12@1+ (0.1,0) [0|0] "" DRIVER,IO
	  SG_ SENSOR_SONARS_middle m0 : 28|12@1+ (0.1,0) [0|0] "" DRIVER,IO
	  SG_ SENSOR_SONARS_right m0 : 40|12@1+ (0.1,0) [0|0] "" DRIVER,IO
	  SG_ SENSOR_SONARS_rear m0 : 52|12@1+ (0.1,0) [0|0] "" DRIVER,IO
	  SG_ SENSOR_SONARS_no_filt_left m1 : 16|12@1+ (0.1,0) [0|0] "" DBG
	  SG_ SENSOR_SONARS_no_filt_middle m1 : 28|12@1+ (0.1,0) [0|0] "" DBG
	  SG_ SENSOR_SONARS_no_filt_right m1 : 40|12@1+ (0.1,0) [0|0] "" DBG
	  SG_ SENSOR_SONARS_no_filt_rear m1 : 52|12@1+ (0.1,0) [0|0] "" DBG
    `)

	// Create payload from hex string
	byteStringHex := "004faf"
	p, _ := can.PayloadFromHex(byteStringHex)

	// Load example dbc file
	c, _ := generate.Compile("test.dbc", dbcFile)
	db := *c.Database

	// Decode message frame ID 400
	message, _ := db.Message(uint32(400))
	decodedSignals := message.Decode(&p)
	for _, signal := range decodedSignals {
		fmt.Printf("Signal: %s, Value: %f, Description: %s\n", signal.Signal.Name, signal.Value, signal.Description)
	}
}
Signal: MOTOR_STATUS_wheel_error, Value: 0.000000, Description: 
Signal: MOTOR_STATUS_speed_kph, Value: 44.879000, Description: 
Multiplexed Signals
func main() {
	// DBC file
	var dbcFile = []byte(`
	VERSION ""
    NS_ :
    BS_:
    BU_: DBG DRIVER IO MOTOR SENSOR
    
    BO_ 400 MOTOR_STATUS: 3 MOTOR
	  SG_ MOTOR_STATUS_wheel_error : 0|1@1+ (1,0) [0|0] "" DRIVER,IO
	  SG_ MOTOR_STATUS_speed_kph : 8|16@1+ (0.001,0) [0|0] "kph" DRIVER,IO

	BO_ 200 SENSOR_SONARS: 8 SENSOR
	  SG_ SENSOR_SONARS_mux M : 0|4@1+ (1,0) [0|0] "" DRIVER,IO
	  SG_ SENSOR_SONARS_err_count : 4|12@1+ (1,0) [0|0] "" DRIVER,IO
	  SG_ SENSOR_SONARS_left m0 : 16|12@1+ (0.1,0) [0|0] "" DRIVER,IO
	  SG_ SENSOR_SONARS_middle m0 : 28|12@1+ (0.1,0) [0|0] "" DRIVER,IO
	  SG_ SENSOR_SONARS_right m0 : 40|12@1+ (0.1,0) [0|0] "" DRIVER,IO
	  SG_ SENSOR_SONARS_rear m0 : 52|12@1+ (0.1,0) [0|0] "" DRIVER,IO
	  SG_ SENSOR_SONARS_no_filt_left m1 : 16|12@1+ (0.1,0) [0|0] "" DBG
	  SG_ SENSOR_SONARS_no_filt_middle m1 : 28|12@1+ (0.1,0) [0|0] "" DBG
	  SG_ SENSOR_SONARS_no_filt_right m1 : 40|12@1+ (0.1,0) [0|0] "" DBG
	  SG_ SENSOR_SONARS_no_filt_rear m1 : 52|12@1+ (0.1,0) [0|0] "" DBG
    `)

	// Create payload from hex string
	byteStringHex := "01af79f4aa3b459f"
	p, _ := can.PayloadFromHex(byteStringHex)

	// Load example dbc file
	c, _ := generate.Compile("test.dbc", dbcFile)
	db := *c.Database

	// Decode message frame ID 200
	message, _ := db.Message(uint32(200))
	decodedSignals := message.Decode(&p)
	for _, signal := range decodedSignals {
		fmt.Printf("Signal: %s, Value: %f, Description: %s\n", signal.Signal.Name, signal.Value, signal.Description)
	}
}
Signal: SENSOR_SONARS_mux, Value: 1.000000, Description: 
Signal: SENSOR_SONARS_err_count, Value: 2800.000000, Description: 
Signal: SENSOR_SONARS_no_filt_left, Value: 114.500000, Description: 
Signal: SENSOR_SONARS_no_filt_middle, Value: 273.500000, Description: 
Signal: SENSOR_SONARS_no_filt_right, Value: 133.900000, Description: 
Signal: SENSOR_SONARS_no_filt_rear, Value: 254.800000, Description: 
Receiving CAN frames

Receiving CAN frames from a socketcan interface.

func main() {
	// Error handling omitted to keep example simple
	conn, _ := socketcan.DialContext(context.Background(), "can", "can0")

	recv := socketcan.NewReceiver(conn)
	for recv.Receive() {
		frame := recv.Frame()
		fmt.Println(frame.String())
	}
}
Sending CAN frames/messages

Sending CAN frames to a socketcan interface.

func main() {
	// Error handling omitted to keep example simple

	conn, _ := socketcan.DialContext(context.Background(), "can", "can0")

	frame := can.Frame{}
	tx := socketcan.NewTransmitter(conn)
	_ = tx.TransmitFrame(context.Background(), frame)
}
Generating Go code from a DBC file

It is possible to generate Go code from a .dbc file.

$ go run github.com/ngjaying/can/cmd/cantool generate <dbc file root folder> <output folder>

In order to generate Go code that makes sense, we currently perform some validations when parsing the DBC file so there may need to be some changes on the DBC file to make it work

After generating Go code we can marshal a message to a frame:

// import etruckcan "github.com/myproject/myrepo/gen"

auxMsg := etruckcan.NewAuxiliary().SetHeadLights(etruckcan.Auxiliary_HeadLights_LowBeam)
frame := auxMsg.Frame()

Or unmarshal a frame to a message:

// import etruckcan "github.com/myproject/myrepo/gen"

// Error handling omitted for simplicity
_ := recv.Receive()
frame := recv.Frame()

var auxMsg *etruckcan.Auxiliary
_ = auxMsg.UnmarshalFrame(frame)

Running integration tests

Building the tests:

$ make build-integration-tests

Built tests are placed in build/tests.

The candevice test requires access to physical HW, so run it using sudo. Example:

$ ./build/tests/candevice.test
> PASS

Documentation

Overview

Package can provides primitives for working with CAN.

See: https://en.wikipedia.org/wiki/CAN_bus

Index

Constants

View Source
const (
	MaxID         = 0x7ff
	MaxExtendedID = 0x1fffffff
)

CAN format constants.

View Source
const MaxDataLength = 8

Variables

This section is empty.

Functions

func AsSigned

func AsSigned(unsigned uint64, bits uint16) int64

AsSigned reinterprets the provided unsigned value as a signed value.

func CheckBitRangeBigEndian

func CheckBitRangeBigEndian(frameLength, rangeStart, rangeLength uint8) error

CheckBitRangeBigEndian checks that a big-endian bit range fits in the data.

func CheckBitRangeLittleEndian

func CheckBitRangeLittleEndian(frameLength, rangeStart, rangeLength uint8) error

CheckBitRangeLittleEndian checks that a little-endian bit range fits in the data.

func CheckValue

func CheckValue(value uint64, bits uint8) error

CheckValue checks that a value fits in a number of bits.

Types

type Data

type Data [MaxDataLength]byte

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  |
+-----+  +------+------+------+------+------+------+------+------+

func (*Data) Bit

func (d *Data) Bit(i uint8) bool

Bit returns the value of the i:th bit in the data as a bool.

func (*Data) PackBigEndian

func (d *Data) PackBigEndian() uint64

PackBigEndian packs the data into a contiguous uint64 value for big-endian signals.

func (*Data) PackLittleEndian

func (d *Data) PackLittleEndian() uint64

PackLittleEndian packs the data into a contiguous uint64 value for little-endian signals.

func (*Data) SetBit

func (d *Data) SetBit(i uint8, value bool)

SetBit sets the value of the i:th bit in the data.

func (*Data) SetSignedBitsBigEndian

func (d *Data) SetSignedBitsBigEndian(start, length uint8, value int64)

SetSignedBitsBigEndian sets the big-endian bit range [start, start+length) to the provided signed value.

func (*Data) SetSignedBitsLittleEndian

func (d *Data) SetSignedBitsLittleEndian(start, length uint8, value int64)

SetSignedBitsLittleEndian sets the little-endian bit range [start, start+length) to the provided signed value.

func (*Data) SetUnsignedBitsBigEndian

func (d *Data) SetUnsignedBitsBigEndian(start, length uint8, value uint64)

SetUnsignedBitsBigEndian sets the big-endian bit range [start, start+length) to the provided unsigned value.

func (*Data) SetUnsignedBitsLittleEndian

func (d *Data) SetUnsignedBitsLittleEndian(start, length uint8, value uint64)

SetUnsignedBitsBigEndian sets the little-endian bit range [start, start+length) to the provided unsigned value.

func (*Data) SignedBitsBigEndian

func (d *Data) SignedBitsBigEndian(start, length uint8) int64

SignedBitsBigEndian returns little-endian bit range [start, start+length) as a signed value.

func (*Data) SignedBitsLittleEndian

func (d *Data) SignedBitsLittleEndian(start, length uint8) int64

SignedBitsLittleEndian returns little-endian bit range [start, start+length) as a signed value.

func (*Data) UnpackBigEndian

func (d *Data) UnpackBigEndian(packed uint64)

UnpackBigEndian sets the value of d.Bytes by unpacking the provided value as sequential big-endian bits.

func (*Data) UnpackLittleEndian

func (d *Data) UnpackLittleEndian(packed uint64)

UnpackLittleEndian sets the value of d.Bytes by unpacking the provided value as sequential little-endian bits.

func (*Data) UnsignedBitsBigEndian

func (d *Data) UnsignedBitsBigEndian(start, length uint8) uint64

UnsignedBitsBigEndian returns the big-endian bit range [start, start+length) as an unsigned value.

func (*Data) UnsignedBitsLittleEndian

func (d *Data) UnsignedBitsLittleEndian(start, length uint8) uint64

UnsignedBitsLittleEndian returns the little-endian bit range [start, start+length) as an unsigned value.

type Frame

type Frame struct {
	// ID is the CAN ID
	ID uint32
	// Length is the number of bytes of data in the frame.
	Length uint16
	// Data is the frame data.
	Data Data
	// IsRemote is true for remote frames.
	IsRemote bool
	// IsExtended is true for extended frames, i.e. frames with 29-bit IDs.
	IsExtended bool
}

Frame represents a CAN frame.

A Frame is intentionally designed to fit into 16 bytes on common architectures and is therefore amenable to pass-by-value and judicious copying.

func (Frame) JSON

func (f Frame) JSON() string

JSON returns the JSON-encoding of f, using hex-encoding for the data.

Examples:

{"id":32,"data":"0102030405060708"}
{"id":32,"extended":true,"remote":true,"length":4}

func (Frame) MarshalJSON

func (f Frame) MarshalJSON() ([]byte, error)

MarshalJSON returns the JSON-encoding of f, using hex-encoding for the data.

See JSON for an example of the JSON schema.

func (Frame) String

func (f Frame) String() string

String returns an ASCII representation the CAN frame.

Format:

([0-9A-F]{3}|[0-9A-F]{3})#(R[0-8]?|[0-9A-F]{0,16})

The format is compatible with the candump(1) log file format.

func (*Frame) UnmarshalJSON

func (f *Frame) UnmarshalJSON(jsonData []byte) error

UnmarshalJSON sets *f using the provided JSON-encoded values.

See MarshalJSON for an example of the expected JSON schema.

The result should be checked with Validate to guard against invalid JSON data.

func (*Frame) UnmarshalString

func (f *Frame) UnmarshalString(s string) error

UnmarshalString sets *f using the provided ASCII representation of a Frame.

func (*Frame) Validate

func (f *Frame) Validate() error

Validate returns an error if the Frame is not a valid CAN frame.

type FrameMarshaler

type FrameMarshaler interface {
	MarshalFrame() (Frame, error)
}

FrameMarshaler can marshal itself to a CAN frame.

type FrameUnmarshaler

type FrameUnmarshaler interface {
	UnmarshalFrame(Frame) error
}

FrameUnmarshaler can unmarshal itself from a CAN frame.

type Message

type Message interface {
	FrameMarshaler
	FrameUnmarshaler
}

Message is anything that can marshal and unmarshal itself to/from a CAN frame.

type Payload

type Payload struct {
	// Binary data
	Data []byte

	// Packed little endian
	PackedLittleEndian *big.Int

	// Packed big endian
	PackedBigEndian *big.Int
}

func PayloadFromHex

func PayloadFromHex(hexString string) (Payload, error)

PayloadFromHex generates a Payload from a hexadecimal string.

func (*Payload) Bit

func (p *Payload) Bit(i uint16) bool

Bit returns the value of the i:th bit in the data as a bool.

func (*Payload) Hex

func (p *Payload) Hex() string

Hex returns the hexadecimal representation of the byte array in a Payload.

func (*Payload) PackBigEndian

func (p *Payload) PackBigEndian() *big.Int

PackBigEndian packs the byte array into a continuous big endian big.Int.

func (*Payload) PackLittleEndian

func (p *Payload) PackLittleEndian() *big.Int

PackLittleEndian packs the byte array into a continuous little endian big.Int.

func (*Payload) SetBit

func (p *Payload) SetBit(i uint16, value bool)

SetBit sets the value of the i:th bit in the data.

func (*Payload) SignedBitsBigEndian

func (p *Payload) SignedBitsBigEndian(start, length uint16) int64

SignedBitsBigEndian returns little-endian bit range [start, start+length) as a signed value.

func (*Payload) SignedBitsLittleEndian

func (p *Payload) SignedBitsLittleEndian(start, length uint16) int64

SignedBitsLittleEndian returns little-endian bit range [start, start+length) as a signed value.

func (*Payload) UnsignedBitsBigEndian

func (p *Payload) UnsignedBitsBigEndian(start, length uint16) uint64

UnsignedBitsBigEndian returns the big-endian bit range [start, start+length) as an unsigned value.

func (*Payload) UnsignedBitsLittleEndian

func (p *Payload) UnsignedBitsLittleEndian(start, length uint16) uint64

UnsignedBitsLittleEndian returns the little-endian bit range [start, start+length) as an unsigned value.

Directories

Path Synopsis
cmd
example
internal
clock
Package clock provides primitives for mocking time.
Package clock provides primitives for mocking time.
mocks/gen/mockcanrunner
Package mockcanrunner is a generated GoMock package.
Package mockcanrunner is a generated GoMock package.
mocks/gen/mockclock
Package mockclock is a generated GoMock package.
Package mockclock is a generated GoMock package.
mocks/gen/mocksocketcan
Package mocksocketcan is a generated GoMock package.
Package mocksocketcan is a generated GoMock package.
reinterpret
Package reinterpret provides primitives for reinterpreting arbitrary-length values as signed or unsigned.
Package reinterpret provides primitives for reinterpreting arbitrary-length values as signed or unsigned.
pkg
dbc
Package dbc provides primitives for parsing, formatting and linting DBC files.
Package dbc provides primitives for parsing, formatting and linting DBC files.
generated
Package generated provides primitives for working with code-generated CAN messages.
Package generated provides primitives for working with code-generated CAN messages.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL