Help us shape the future of Go! Take the 2026 Go Developer Survey

canbus

package module
v0.7.2 Latest Latest
Warning

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

Go to latest
Published: Oct 31, 2026 License: MIT Imports: 10 Imported by: 0

README

go-canbus - CAN, CAN FD, ISO-TP and CAN Databases for Go

Go Version Go Reference CI Status Interop Kernels Code Coverage Latest Release

A pure Go library for Controller Area Network: classical CAN, CAN FD and CAN XL frames, Linux SocketCAN, serial-line (slcan) adapters on every OS, a deterministic virtual bus, ISO-TP (ISO 15765-2), capture and replay, and DBC/KCD/ARXML message databases with a signal codec and a Go code generator. No cgo; the one dependency outside the standard library is go-serial (pure Go), for serial ports.

Package What it does
canbus Frames (11/29-bit IDs, CAN FD with BRS/ESI, remote, error frames, DLC 9..15), the CAN FD DLC table, filters with exact Linux CAN_RAW_FILTER semantics, error-frame decoding, CAN XL frames, the Transport interface and Bus (one transport shared by many subscriptions with bounded queues), slog logging and metrics hooks
socketcan Linux CAN_RAW sockets: CAN FD, kernel filters, error frames, loopback and receive-own, kernel timestamps, drop accounting, context cancellation, allocation-free send/receive; kernel ISO-TP sockets (DialISOTP)
socketcan/link rtnetlink administration, kept apart from the transport: list and inspect CAN interfaces (state, bit timing, error counters), up/down, bit rates, CAN FD, restart, vcan/vxcan create/delete
slcan Serial-line CAN (LAWICEL ASCII) adapters such as CANable, CANtact and USBtin on every OS, without the Linux slcan driver: bit rates, listen-only, CAN FD (CANable 2.0), over a serial port (go-serial), a pseudo-terminal or TCP
virtual An in-memory bus for tests and simulation on every OS: SocketCAN delivery rules, queue policies, seeded fault injection (drop, duplicate, delay, corrupt, error frames, interface down); CAN XL ports
isotp ISO-TP in userspace: normal, extended and mixed addressing, flow control with block size, STmin, WAIT and OVERFLOW, timeouts, padding, CAN FD and messages above 4095 bytes
capture candump logs, lossless JSON Lines, pcap and pcapng (LINKTYPE_CAN_SOCKETCAN, read and written, CAN XL included; checked against tcpdump and Wireshark), Vector ASC and BLF, PEAK TRC (1.0–2.1 read, 2.1 written); streaming replay with original, scaled or maximum timing, filters and limits
candb The format-independent message model and signal codec: Intel and Motorola, signed, float, scaling, value tables, simple and extended multiplexing, CAN FD; exact 64-bit raw values
dbc, kcd, arxml DBC parser and writer, KCD parser and writer, AUTOSAR 4.x ARXML reader (CAN clusters, frames, I-PDUs, multiplexed I-PDUs, signals, compu methods); every unsupported construct yields a diagnostic
codegen Deterministic Go generation: typed message structs, enums, constants, physical accessors, multiplexer-aware encode/decode
chaos A fault-injecting bridge between two transports (drop, duplicate, delay, reorder, corrupt; seeded): tests real stacks and devices under faults

The command-line tool built on it is canbusctl; the independent reference implementations it is tested against are in canbus-interop.

Install

go get github.com/otfabric/go-canbus

Quick start

Receive frames from a SocketCAN interface (Linux):

conn, err := socketcan.Open("can0", socketcan.WithFD())
if err != nil {
	log.Fatal(err)
}
bus, _ := canbus.NewBus(conn, canbus.WithStartOnSubscribe()) // read from the first Subscribe on
defer bus.Close()

sub, _ := bus.Subscribe(canbus.WithFilters(canbus.FilterSet{
	Filters: []canbus.Filter{canbus.ExactStandard(0x123)},
}))
for {
	f, err := sub.Receive(ctx)
	if err != nil {
		return
	}
	fmt.Println(f) // 123#DEADBEEF
}

Send, on any transport (a virtual port works the same way):

f, _ := canbus.NewFD(0x18DA10F1, true, true, payload) // 29-bit, CAN FD, BRS
err := bus.Send(ctx, &f)

Decode with a DBC file:

db, diags, err := dbc.ParseFile("vehicle.dbc")
msg, signals, err := db.DecodeFrame(&f)
for _, s := range signals {
	fmt.Println(s.Signal.Name, s.Signal.RawString(s.Value), s.Physical, s.Signal.Unit)
}

ISO-TP over a bus:

conn, _ := isotp.Dial(bus, isotp.Config{TxID: 0x7E0, RxID: 0x7E8, Padding: true})
err := conn.Send(ctx, request)
response, err := conn.Receive(ctx)

More in examples/: passive monitoring, sending classical and CAN FD frames, DBC decoding, code generation, an ISO-TP exchange, virtual simulation with faults, capture and replay, and two processes on vcan.

What is in scope

Layer Scope
Physical interface, bit rate Configured explicitly through socketcan/link; opening a socket never changes an interface
Data link (ISO 11898-1 framing concepts) Classical CAN 2.0A/B, CAN FD, CAN XL (SocketCAN on Linux ≥ 6.2, the virtual bus, canbus.Bus, candump/JSON Lines/pcap/pcapng traces)
Transport ISO-TP (ISO 15765-2), userspace and Linux kernel
Message definitions DBC (read/write), KCD (read/write), AUTOSAR 4.x ARXML (read, CAN subset: see LIMITATIONS.md)
Application protocols None: CANopen, J1939, UDS, NMEA 2000, ISOBUS and DroneCAN belong in their own modules on top of canbus.Bus and isotp

A CAN identifier names a message, not a device. Nothing here identifies a physical node from traffic.

Platforms

Linux (amd64, arm64, armv7) macOS, Windows (amd64, arm64)
Frames, filters, virtual bus, ISO-TP, capture/replay, candb/dbc/kcd/codegen Yes Yes
slcan serial adapters Yes Yes
SocketCAN, kernel ISO-TP, netlink administration Yes No: ErrUnsupported

Other hardware adapters (PEAK, Kvaser, Vector) are not implemented; they plug in through the canbus.Transport interface.

Documentation

API.md · ARCHITECTURE.md · ERRORS.md · OBSERVABILITY.md · INTEROPERABILITY.md · TESTING.md · LIMITATIONS.md · ROADMAP.md (gaps and follow-ups) · SECURITY.md · REQUIREMENTS.md · CHANGELOG.md · RELEASE.md · CONTRIBUTING.md

Standards

ISO 11898-1 and ISO 15765-2 are not publicly available. This library is implemented from public material (the Linux SocketCAN documentation and headers, the Bosch CAN 2.0 and CAN FD 1.0 specifications, public protocol descriptions) and tested against independent implementations. It makes no claim of ISO or CiA conformance.

License

MIT, see LICENSE.

Documentation

Overview

Package canbus is the transport-neutral core of go-canbus: CAN and CAN FD frames, identifiers, data length codes, filters, error frames, the Transport interface and the Bus, which shares one transport among many subscribers.

Transports live in subpackages: socketcan (Linux SocketCAN raw sockets) and virtual (a deterministic in-memory bus for tests and simulation). Higher layers build on a Bus: isotp (ISO 15765-2), capture (candump, JSON Lines and pcap traces, replay), and candb with dbc, kcd and codegen (message and signal databases).

A CAN identifier names a message, not a device: nothing in this module infers which physical node sent a frame.

Index

Constants

View Source
const (
	MaxClassicalLen = 8  // largest classical CAN payload
	MaxFDLen        = 64 // largest CAN FD payload
)

Payload size limits.

View Source
const (
	MaxXLPriority = 0x7FF // largest 11-bit CAN XL priority
	MinXLLen      = 1     // smallest CAN XL payload
	MaxXLLen      = 2048  // largest CAN XL payload
)

CAN XL limits.

View Source
const DefaultQueueSize = 1024

DefaultQueueSize is the queue capacity of a subscription that does not set one.

Variables

View Source
var (
	// ErrClosed reports an operation on a bus, subscription or transport
	// that was closed.
	ErrClosed = errors.New("canbus: closed")

	// ErrTimeout reports an operation that did not complete in time. A
	// context deadline is reported as the context's error instead.
	ErrTimeout = errors.New("canbus: timeout")

	// ErrInvalidFrame reports a frame that cannot be represented or sent:
	// see [Frame.Validate]. A *[FrameError] carries the detail.
	ErrInvalidFrame = errors.New("canbus: invalid frame")

	// ErrUnsupported reports an operation or frame type the transport
	// does not support: SocketCAN on a system other than Linux, a CAN FD
	// frame on a socket not opened for CAN FD, a kernel filter on a
	// virtual port.
	ErrUnsupported = errors.New("canbus: unsupported")

	// ErrQueueFull reports a frame that could not be queued because a
	// bounded queue was full and its policy is to reject.
	ErrQueueFull = errors.New("canbus: queue full")

	// ErrInvalidOption reports an option value a bus, transport or
	// connection cannot be constructed with.
	ErrInvalidOption = errors.New("canbus: invalid option")

	// ErrInterfaceDown reports an interface that is down or does not
	// exist.
	ErrInterfaceDown = errors.New("canbus: interface down")

	// ErrBufferOverflow reports frames lost because a receive buffer
	// overflowed (the kernel's socket queue, a transmit queue that is
	// full: ENOBUFS).
	ErrBufferOverflow = errors.New("canbus: buffer overflow")
)

Sentinel errors. They are usually wrapped with detail; test with errors.Is.

Functions

func DLCToLen

func DLCToLen(dlc uint8, fd bool) int

DLCToLen returns the payload length of a data length code (only its low 4 bits are used). fd selects the CAN FD table: codes 9..15 mean 12, 16, 20, 24, 32, 48 and 64 bytes. For classical CAN they all mean 8 bytes.

func IsXLText added in v0.5.0

func IsXLText(s string) bool

IsXLText reports whether s looks like a CAN XL frame in can-utils notation (a CAN XL header after the first "#"), as opposed to a classical or CAN FD frame.

func KernelID

func KernelID(fr *Frame) uint32

KernelID returns the Linux can_id of a frame: the identifier with CAN_EFF_FLAG, CAN_RTR_FLAG and CAN_ERR_FLAG.

func LenToDLC

func LenToDLC(n int) uint8

LenToDLC returns the smallest data length code whose CAN FD length holds n bytes: 0..8 map to themselves, 9..12 to 9, ..., 49..64 to 15. Lengths above 64 return 15.

func PadFD

func PadFD(data []byte, pad byte) []byte

PadFD returns data padded with pad to the next valid CAN FD length. data is returned unchanged when its length is already valid.

func RoundUpFDLen

func RoundUpFDLen(n int) int

RoundUpFDLen returns the smallest valid CAN FD length of at least n bytes, or 64 when n exceeds 64.

func ValidFDLen

func ValidFDLen(n int) bool

ValidFDLen reports whether n is a payload length a CAN FD frame can carry: 0..8, 12, 16, 20, 24, 32, 48 or 64.

func XLKernelID added in v0.7.0

func XLKernelID(x *XLFrame) uint32

XLKernelID returns the identifier Linux's CAN_RAW_FILTER matches for a CAN XL frame: the priority with the VCID in bits 16..23, without any flag (a standard data frame identifier).

Types

type Bus

type Bus struct {
	// contains filtered or unexported fields
}

Bus shares one Transport between many users. A single reader goroutine receives every frame and hands a copy to each Subscription whose filters it passes; Send may be called from any goroutine.

The Bus owns the transport: Close closes it. Subscriptions can be added and closed at any time, also while frames arrive. A frame read while no subscription exists reaches nobody: to receive from the first frame on, create the bus with WithStartOnSubscribe.

On an XLTransport the bus also carries CAN XL frames: Bus.SendXL sends them and subscriptions opened WithXL receive them.

func NewBus

func NewBus(t Transport, opts ...Option) (*Bus, error)

NewBus starts a bus on t. The reader goroutine starts at once and keeps draining the transport even while there are no subscriptions, so that a transport's own receive queue does not overflow.

func (*Bus) Close

func (b *Bus) Close() error

Close stops the reader, closes every subscription and the transport. It waits for the reader to stop and is safe to call more than once.

func (*Bus) Done

func (b *Bus) Done() <-chan struct{}

Done returns a channel closed when the bus reader has stopped.

func (*Bus) Err

func (b *Bus) Err() error

Err returns why the reader stopped: nil while it runs, ErrClosed after Close, or the transport error that ended it.

func (*Bus) Name

func (b *Bus) Name() string

Name returns the interface name of the bus, possibly "".

func (*Bus) Send

func (b *Bus) Send(ctx context.Context, f *Frame) error

Send validates the frame and transmits it. It is safe for concurrent use.

func (*Bus) SendXL added in v0.7.0

func (b *Bus) SendXL(ctx context.Context, x *XLFrame) error

SendXL validates a CAN XL frame and transmits it. It fails with ErrUnsupported when the transport does not carry CAN XL (is not an XLTransport). It is safe for concurrent use.

func (*Bus) State

func (b *Bus) State() State

State returns the current bus state.

func (*Bus) Stats

func (b *Bus) Stats() Stats

Stats returns the bus counters.

func (*Bus) Subscribe

func (b *Bus) Subscribe(opts ...SubscribeOption) (*Subscription, error)

Subscribe adds a subscription. It returns ErrClosed when the bus is closed.

func (*Bus) Transport

func (b *Bus) Transport() Transport

Transport returns the transport of the bus. Do not call its Receive: the bus reader does.

type Capabilitier

type Capabilitier interface {
	Capabilities() Capabilities
}

Capabilitier is implemented by transports that describe themselves.

type Capabilities

type Capabilities struct {
	FD            bool // sends and receives CAN FD frames
	XL            bool // sends and receives CAN XL frames ([XLFrame])
	ErrorFrames   bool // can deliver error frames
	KernelFilters bool // filters before delivery (Filterer)
	Timestamps    bool // frames carry receive timestamps
	RecvOwn       bool // can deliver its own transmissions
	Physical      bool // attached to a real or virtual network device, not simulated in process
}

Capabilities describes what a transport supports.

type ControllerStatus

type ControllerStatus uint8

ControllerStatus is Data[1] of a controller error frame.

const (
	CtrlRxOverflow ControllerStatus = 0x01 // RX buffer overflow
	CtrlTxOverflow ControllerStatus = 0x02 // TX buffer overflow
	CtrlRxWarning  ControllerStatus = 0x04 // reached warning level for RX errors
	CtrlTxWarning  ControllerStatus = 0x08 // reached warning level for TX errors
	CtrlRxPassive  ControllerStatus = 0x10 // reached error passive status RX
	CtrlTxPassive  ControllerStatus = 0x20 // reached error passive status TX
	CtrlActive     ControllerStatus = 0x40 // recovered to error active state
)

Controller status bits.

func (ControllerStatus) String

func (s ControllerStatus) String() string

String lists the status bits.

type DropCounter

type DropCounter interface {
	Drops() (total uint64, reason DropReason)
}

DropCounter is implemented by transports that lose frames before Receive returns them, for example to a kernel receive queue overflow. Drops returns the running total and the reason; a Bus reports the increments to its Metrics.

type DropReason

type DropReason uint8

DropReason says why frames were lost.

const (
	DropQueueFull      DropReason = iota + 1 // a subscription's queue was full
	DropKernelOverflow                       // the kernel's socket receive queue overflowed
	DropFault                                // an injected fault (virtual bus)
	DropFiltered                             // not delivered because of the port's format (FD frame to a classical port)
)

Drop reasons.

func (DropReason) String

func (r DropReason) String() string

String names the reason.

type ErrorClass

type ErrorClass uint32

ErrorClass is the class bit set of an error frame: the identifier of a frame with FlagError, with the values of Linux's can/error.h. It is also the mask that selects which error frames a socket receives.

const (
	ErrClassTxTimeout       ErrorClass = 0x001 // TX timeout (by netdevice driver)
	ErrClassLostArbitration ErrorClass = 0x002 // lost arbitration; bit in Data[0]
	ErrClassController      ErrorClass = 0x004 // controller problems; Data[1]
	ErrClassProtocol        ErrorClass = 0x008 // protocol violation; Data[2], Data[3]
	ErrClassTransceiver     ErrorClass = 0x010 // transceiver status; Data[4]
	ErrClassNoAck           ErrorClass = 0x020 // no acknowledgement on transmission
	ErrClassBusOff          ErrorClass = 0x040 // bus off
	ErrClassBusError        ErrorClass = 0x080 // bus error (may flood)
	ErrClassRestarted       ErrorClass = 0x100 // controller restarted
	ErrClassCounters        ErrorClass = 0x200 // TX/RX error counters in Data[6], Data[7]

	// ErrClassAll selects every error class.
	ErrClassAll ErrorClass = 0x1FFFFFFF
)

Error classes.

func (ErrorClass) String

func (c ErrorClass) String() string

String lists the classes, for example "controller|bus-off".

type ErrorInfo

type ErrorInfo struct {
	Class ErrorClass
	// ArbitrationBit is the bit in which arbitration was lost (0 =
	// unspecified), for ErrClassLostArbitration.
	ArbitrationBit uint8
	// Controller is the controller status, for ErrClassController.
	Controller ControllerStatus
	// Protocol and ProtocolLocation describe a protocol violation, for
	// ErrClassProtocol. The location is the Linux CAN_ERR_PROT_LOC_*
	// code (for example 0x08 = data section).
	Protocol         ProtocolViolation
	ProtocolLocation uint8
	// Transceiver is the Linux CAN_ERR_TRX_* status, for
	// ErrClassTransceiver.
	Transceiver uint8
	// ControllerSpecific is Data[5], whose meaning depends on the driver.
	ControllerSpecific uint8
	// TxErrors and RxErrors are the error counters, valid when
	// CountersValid (ErrClassCounters) is set.
	TxErrors, RxErrors uint8
	CountersValid      bool
}

ErrorInfo is the decoded content of an error frame.

func ParseError

func ParseError(f *Frame) (ErrorInfo, bool)

ParseError decodes an error frame. It reports false for a frame without FlagError.

func (ErrorInfo) String

func (e ErrorInfo) String() string

String summarizes the error, for example "controller|counters controller=rx-passive tx=0 rx=128".

type Filter

type Filter struct {
	ID     ID
	Mask   ID
	Format Format
	Remote RemoteMatch
	Invert bool
}

Filter selects frames by identifier: a frame matches when (frameID & Mask) == (ID & Mask), restricted by Format and Remote, and negated by Invert.

The semantics are those of Linux's CAN_RAW_FILTER: Filter.Kernel returns the can_filter the kernel would be given, and the software matcher evaluates exactly that expression on the kernel's flag-encoded identifier. In particular, with FormatAny a mask of 0x7FF also matches extended identifiers whose low 11 bits agree, as in the kernel.

func ExactExtended

func ExactExtended(id ID) Filter

ExactExtended returns a filter for one 29-bit identifier.

func ExactStandard

func ExactStandard(id ID) Filter

ExactStandard returns a filter for one 11-bit identifier.

func ParseFilter

func ParseFilter(s string) (Filter, error)

ParseFilter parses the notation of Filter.String and candump's: "<id>:<mask>" or "<id>~<mask>" (inverted), hexadecimal; an identifier of more than 3 digits selects extended identifiers. Suffixes ",std", ",ext", ",any", ",data" and ",rtr" set Format and Remote explicitly.

func (Filter) Kernel

func (f Filter) Kernel() (id, mask uint32)

Kernel returns the Linux can_filter values (can_id, can_mask) of f.

func (Filter) Match

func (f Filter) Match(fr *Frame) bool

Match reports whether a data or remote frame passes the filter. Error frames are selected by an error mask instead; Match reports false for them.

func (Filter) MatchXL added in v0.7.0

func (f Filter) MatchXL(x *XLFrame) bool

MatchXL reports whether a CAN XL frame passes the filter, as the kernel decides it: on XLKernelID, so a filter for a standard identifier selects the CAN XL frames of that priority (and any VCID unless the mask covers bits 16..23), and a filter for an extended identifier selects none.

func (Filter) String

func (f Filter) String() string

String formats the filter as candump does: "123:7FF", "12345678:1FFFFFFF" for extended (with an 8-digit identifier), "123~7FF" when inverted, with ",std" / ",any" / ",data" / ",rtr" for what candump's notation cannot spell. ParseFilter reads it back unchanged.

type FilterSet

type FilterSet struct {
	Filters   []Filter
	Join      bool
	ErrorMask ErrorClass
}

FilterSet is a list of filters with the combination rule of CAN_RAW_FILTER: a frame passes when it matches any filter, or, with Join (CAN_RAW_JOIN_FILTERS), all of them. An empty set passes every data and remote frame. ErrorMask selects the error frames that pass (CAN_RAW_ERR_FILTER); zero passes none.

func (*FilterSet) Match

func (s *FilterSet) Match(fr *Frame) bool

Match reports whether the frame passes the set.

func (*FilterSet) MatchXL added in v0.7.0

func (s *FilterSet) MatchXL(x *XLFrame) bool

MatchXL reports whether a CAN XL frame passes the set (Filter.MatchXL).

type Filterer

type Filterer interface {
	SetFilters(FilterSet) error
}

Filterer is implemented by transports that filter in the kernel, in hardware or as frames arrive. Frames that do not pass are never delivered to Receive.

type Flags

type Flags uint8

Flags carries the frame format bits of a Frame.

const (
	// FlagExtended marks a 29-bit (CAN 2.0B) identifier.
	FlagExtended Flags = 1 << iota
	// FlagRemote marks a remote transmission request (classical CAN only).
	FlagRemote
	// FlagFD marks a CAN FD frame.
	FlagFD
	// FlagBRS marks a CAN FD frame sent with bit rate switching.
	FlagBRS
	// FlagESI marks a CAN FD frame whose transmitter was error passive.
	FlagESI
	// FlagError marks an error frame: a report of the local controller or
	// driver, never sent on the bus. See [ParseError].
	FlagError
)

Frame flags.

func (Flags) String

func (f Flags) String() string

String lists the set flags, for example "EXT|FD|BRS".

type Format

type Format uint8

Format selects identifier formats in a Filter.

const (
	FormatAny      Format = iota // standard and extended identifiers
	FormatStandard               // 11-bit identifiers only
	FormatExtended               // 29-bit identifiers only
)

Identifier formats.

type Frame

type Frame struct {
	// ID is the identifier without flag bits. For error frames it holds
	// the Linux error class bits (CAN_ERR_*).
	ID ID
	// Flags holds the format bits.
	Flags Flags
	// Len is the payload length in bytes: 0..8 for classical frames, one
	// of 0..8, 12, 16, 20, 24, 32, 48, 64 for CAN FD frames. For remote
	// frames it is the requested data length (the DLC), and no data is
	// carried.
	Len uint8
	// Len8DLC preserves a classical frame's raw DLC of 9..15, which also
	// means 8 data bytes. It is 0 otherwise.
	Len8DLC uint8
	// Data is the payload; only the first Len bytes are meaningful.
	Data [MaxFDLen]byte
	// Timestamp is the receive time reported by the transport (the
	// kernel's for SocketCAN), or the zero time.
	Timestamp time.Time
	// Interface names the interface the frame was received on, if known.
	Interface string
	// Echo reports that the frame is the receiving socket's own
	// transmission, delivered back because receive-own-messages is on.
	Echo bool
}

Frame is one CAN or CAN FD frame with its receive metadata.

The payload is a fixed array so that a Frame is a plain value: sending and receiving frames does not allocate. Bytes of Data beyond Len are zero in frames produced by this module. Use Frame.Payload for the valid bytes.

func NewErrorFrame

func NewErrorFrame(info ErrorInfo) Frame

NewErrorFrame builds an error frame from info, as a driver would report it. Virtual transports use it to inject controller errors.

func NewExtended

func NewExtended(id ID, data []byte) (Frame, error)

NewExtended returns a classical data frame with a 29-bit identifier.

func NewFD

func NewFD(id ID, extended, brs bool, data []byte) (Frame, error)

NewFD returns a CAN FD frame. extended selects a 29-bit identifier, brs bit rate switching. A payload whose length is not a valid CAN FD length is rejected: pad it with PadFD first.

func NewRemote

func NewRemote(id ID, extended bool, dlc uint8) (Frame, error)

NewRemote returns a remote transmission request for dlc bytes (0..8).

func NewStandard

func NewStandard(id ID, data []byte) (Frame, error)

NewStandard returns a classical data frame with an 11-bit identifier.

func (*Frame) DLC

func (f *Frame) DLC() uint8

DLC returns the data length code of the frame as transmitted on the bus: for classical frames Len, or Len8DLC when set; for CAN FD frames the code of Len (see LenToDLC).

func (*Frame) IsError

func (f *Frame) IsError() bool

IsError reports an error frame.

func (*Frame) IsExtended

func (f *Frame) IsExtended() bool

IsExtended reports a 29-bit identifier.

func (*Frame) IsFD

func (f *Frame) IsFD() bool

IsFD reports a CAN FD frame.

func (*Frame) IsRemote

func (f *Frame) IsRemote() bool

IsRemote reports a remote transmission request.

func (*Frame) Payload

func (f *Frame) Payload() []byte

Payload returns the valid payload bytes, a slice of f.Data. A remote frame carries no data: its payload is empty whatever its Len.

func (*Frame) SetPayload

func (f *Frame) SetPayload(data []byte)

SetPayload copies data into the frame, sets Len and clears the bytes beyond it. It does not validate the length against the frame type.

func (Frame) String

func (f Frame) String() string

String formats the frame in candump's compact notation: "123#A1B2C3", "12345678#" for extended identifiers, "123#R" (remote), "123##1A1B2" (CAN FD with its flags nibble).

func (*Frame) Validate

func (f *Frame) Validate() error

Validate checks that the frame can be transmitted or represented: the identifier fits its format, the length is valid for the frame type, the flags are consistent (no remote CAN FD frame, no BRS/ESI without FD, Len8DLC only with Len 8) and the bytes beyond Len are zero. Error frames are only checked for their length. The returned error is a *FrameError wrapping ErrInvalidFrame.

type FrameError

type FrameError struct {
	Frame  Frame  // the offending frame
	Reason string // what is wrong
}

FrameError reports a frame that failed validation. It wraps ErrInvalidFrame.

func (*FrameError) Error

func (e *FrameError) Error() string

Error describes the problem, for example "canbus: invalid frame 800#: standard identifier 0x800 exceeds 11 bits".

func (*FrameError) Unwrap

func (e *FrameError) Unwrap() error

Unwrap returns ErrInvalidFrame.

type ID

type ID uint32

ID is a CAN identifier without flag bits: 11 bits for a standard frame, 29 bits for an extended frame. Whether an identifier is standard or extended is recorded in Frame.Flags, not in the ID, because 0x123 as a standard and as an extended identifier are different identifiers on the bus.

const (
	MaxStandardID ID = 0x7FF      // largest 11-bit identifier
	MaxExtendedID ID = 0x1FFFFFFF // largest 29-bit identifier
)

Identifier ranges.

type Metrics

type Metrics interface {
	// OnFrameSent is called after a frame was handed to the transport.
	OnFrameSent(iface string, f *Frame)
	// OnFrameReceived is called for every frame read from the transport,
	// before filtering by subscriptions.
	OnFrameReceived(iface string, f *Frame)
	// OnDrop is called when n frames were lost.
	OnDrop(iface string, reason DropReason, n uint64)
	// OnError is called when a send or receive failed.
	OnError(iface, op string, err error)
	// OnQueue is called after a frame was queued for a subscription with
	// the queue's depth and capacity.
	OnQueue(iface string, depth, capacity int)
	// OnStateChange is called when the bus state changes.
	OnStateChange(iface string, from, to State)
}

Metrics is an optional callback interface for observing a Bus. A nil Metrics disables collection.

The methods are called synchronously, possibly from several goroutines at once; implementations must be safe for concurrent use and must not block. Frames passed to them must not be retained or modified. Embed NopMetrics to implement only some callbacks and to stay compatible when methods are added.

type Namer

type Namer interface {
	Name() string
}

Namer is implemented by transports bound to a named interface.

type NopMetrics

type NopMetrics struct{}

NopMetrics is a Metrics that does nothing. Embed it in your own type.

func (NopMetrics) OnDrop

func (NopMetrics) OnDrop(string, DropReason, uint64)

OnDrop does nothing.

func (NopMetrics) OnError

func (NopMetrics) OnError(string, string, error)

OnError does nothing.

func (NopMetrics) OnFrameReceived

func (NopMetrics) OnFrameReceived(string, *Frame)

OnFrameReceived does nothing.

func (NopMetrics) OnFrameSent

func (NopMetrics) OnFrameSent(string, *Frame)

OnFrameSent does nothing.

func (NopMetrics) OnQueue

func (NopMetrics) OnQueue(string, int, int)

OnQueue does nothing.

func (NopMetrics) OnStateChange

func (NopMetrics) OnStateChange(string, State, State)

OnStateChange does nothing.

func (NopMetrics) OnXLFrameReceived added in v0.7.0

func (NopMetrics) OnXLFrameReceived(string, *XLFrame)

OnXLFrameReceived does nothing.

func (NopMetrics) OnXLFrameSent added in v0.7.0

func (NopMetrics) OnXLFrameSent(string, *XLFrame)

OnXLFrameSent does nothing.

type OpError

type OpError struct {
	Op        string // "open", "send", "receive", "close", "filter", ...
	Interface string // interface name, or "" when unknown
	Err       error  // underlying error
}

OpError reports a failed transport operation with the interface it was performed on.

func (*OpError) Error

func (e *OpError) Error() string

Error formats the operation, interface and cause.

func (*OpError) Unwrap

func (e *OpError) Unwrap() error

Unwrap returns the underlying error.

type Option

type Option func(*Bus) error

Option configures a Bus.

func WithInterfaceName

func WithInterfaceName(name string) Option

WithInterfaceName sets the name reported to logs and metrics. By default it is the transport's Namer name, if any.

func WithLogger

func WithLogger(l *slog.Logger) Option

WithLogger logs bus events (state changes, receive errors, drops) to l. A nil logger, the default, logs nothing.

func WithMetrics

func WithMetrics(m Metrics) Option

WithMetrics reports frames, drops, errors and state changes to m.

func WithStartOnSubscribe added in v0.2.2

func WithStartOnSubscribe() Option

WithStartOnSubscribe defers the bus's reader until the first Bus.Subscribe (or Bus.Close). Until then frames wait in the transport (a SocketCAN socket's receive buffer), so the first subscription sees them all; without this option the reader starts in NewBus and frames that arrive before the first subscription are lost. Error state (Bus.State) is tracked once the reader runs.

type Overflow

type Overflow uint8

Overflow is the policy of a subscription whose queue is full.

const (
	// DropNewest discards the frame that does not fit (the default). The
	// reader never waits for a slow subscriber.
	DropNewest Overflow = iota
	// DropOldest discards the oldest queued frame to make room.
	DropOldest
	// Block makes the bus reader wait until the subscriber takes the
	// frame. A slow subscriber then delays every other subscription and
	// lets the transport's own queue overflow instead: use it only when
	// losing frames in this process is worse.
	Block
)

Overflow policies.

type ProtocolViolation

type ProtocolViolation uint8

ProtocolViolation is Data[2] of a protocol error frame.

const (
	ProtBit      ProtocolViolation = 0x01 // single bit error
	ProtForm     ProtocolViolation = 0x02 // frame format error
	ProtStuff    ProtocolViolation = 0x04 // bit stuffing error
	ProtBit0     ProtocolViolation = 0x08 // unable to send dominant bit
	ProtBit1     ProtocolViolation = 0x10 // unable to send recessive bit
	ProtOverload ProtocolViolation = 0x20 // bus overload
	ProtActive   ProtocolViolation = 0x40 // active error announcement
	ProtTx       ProtocolViolation = 0x80 // error occurred on transmission
)

Protocol violation types.

func (ProtocolViolation) String

func (p ProtocolViolation) String() string

String lists the violation bits.

type RemoteMatch

type RemoteMatch uint8

RemoteMatch selects data or remote frames in a Filter.

const (
	RemoteAny      RemoteMatch = iota // data and remote frames
	RemoteDataOnly                    // data frames only
	RemoteOnly                        // remote frames only
)

Remote frame selection.

type State

type State uint8

State is the state of a bus as far as the library can tell: whether it runs, and the controller's error state reported by error frames.

const (
	StateUnknown State = iota
	StateActive        // running; controller error active (or no report)
	StateWarning       // error warning (an error counter reached 96)
	StatePassive       // error passive (an error counter reached 128)
	StateBusOff        // bus off
	StateDown          // the interface is down
	StateClosed        // closed by the application
)

Bus states.

func (State) String

func (s State) String() string

String names the state.

type Stats

type Stats struct {
	TxFrames  uint64 // frames sent
	TxBytes   uint64 // payload bytes sent
	RxFrames  uint64 // frames received
	RxBytes   uint64 // payload bytes received
	RxErrors  uint64 // error frames received
	Dropped   uint64 // frames lost: kernel receive queue overflow, full subscription queues, injected faults
	TxErrors  uint64 // failed send attempts
	RxFailure uint64 // failed receive attempts other than cancellation
}

Stats are frame counters of a transport or bus.

type Statser

type Statser interface {
	Stats() Stats
}

Statser is implemented by transports that keep counters.

type SubscribeOption

type SubscribeOption func(*Subscription)

SubscribeOption configures a Subscription.

func WithFilters

func WithFilters(fs FilterSet) SubscribeOption

WithFilters selects the frames the subscription receives. Without it, every data and remote frame is received and no error frame.

func WithOverflow

func WithOverflow(o Overflow) SubscribeOption

WithOverflow sets the policy when the queue is full (default DropNewest).

func WithQueueSize

func WithQueueSize(n int) SubscribeOption

WithQueueSize sets the queue capacity (default DefaultQueueSize).

func WithXL added in v0.7.0

func WithXL() SubscribeOption

WithXL makes the subscription receive CAN XL frames too: CAN, CAN FD and CAN XL frames share its queue in arrival order and are read with Subscription.ReceiveAny (Subscription.Receive and Subscription.ReceiveXL skip the other kind; Subscription.Frames is nil). The subscription's filters select CAN XL frames as Linux's CAN_RAW_FILTER does (FilterSet.MatchXL). Without it, CAN XL frames are not delivered, as to a SocketCAN socket without CAN_RAW_XL_FRAMES.

func WithoutEcho

func WithoutEcho() SubscribeOption

WithoutEcho drops frames the transport marks as this socket's own transmissions (Frame.Echo).

type Subscription

type Subscription struct {
	// contains filtered or unexported fields
}

Subscription receives the frames of a Bus that pass its filters, through a bounded queue. Its receive methods and Frames may be used from one goroutine at a time; Close and the counters from any.

func (*Subscription) Close

func (s *Subscription) Close() error

Close ends the subscription. Frames still queued can be read with Receive until it returns ErrClosed.

func (*Subscription) Done

func (s *Subscription) Done() <-chan struct{}

Done returns a channel closed when the subscription ends.

func (*Subscription) Dropped

func (s *Subscription) Dropped() uint64

Dropped returns the number of frames lost because the queue was full.

func (*Subscription) Err

func (s *Subscription) Err() error

Err returns why the subscription ended, or nil while it is open.

func (*Subscription) Frames

func (s *Subscription) Frames() <-chan Frame

Frames returns the queue as a channel, for use in select statements together with Subscription.Done. The channel is never closed. A subscription opened WithXL has none (nil): use Subscription.ReceiveAny.

func (*Subscription) Receive

func (s *Subscription) Receive(ctx context.Context) (Frame, error)

Receive returns the next frame. It returns the context's error when ctx ends first, and, once the queue is empty, ErrClosed after Close or the error that stopped the bus. On a subscription opened WithXL it skips CAN XL frames: use Subscription.ReceiveAny.

func (*Subscription) ReceiveAny added in v0.7.0

func (s *Subscription) ReceiveAny(ctx context.Context, f *Frame, x *XLFrame) (xl bool, err error)

ReceiveAny returns the next frame of any kind, in the order the bus received them: a CAN or CAN FD frame in f (xl false) or a CAN XL frame in x (xl true; x.Data is the subscription's copy, owned by the caller afterwards). Without WithXL it is Subscription.Receive into f.

func (*Subscription) ReceiveXL added in v0.7.0

func (s *Subscription) ReceiveXL(ctx context.Context) (XLFrame, error)

ReceiveXL returns the next CAN XL frame of a subscription opened WithXL, like Subscription.Receive, skipping CAN and CAN FD frames. Without WithXL it returns ErrUnsupported.

func (*Subscription) Received

func (s *Subscription) Received() uint64

Received returns the number of frames queued so far.

type Transport

type Transport interface {
	Send(ctx context.Context, f *Frame) error
	Receive(ctx context.Context, f *Frame) error
	Close() error
}

Transport is one endpoint on a CAN bus: a SocketCAN socket, a port of a virtual bus, or a future hardware adapter.

Send transmits a frame and Receive waits for the next one; neither retains the frame after it returns. Implementations allow Send from several goroutines at once and one Receive at a time. Both honour the context: a cancelled or expired context ends a blocked call with the context's error. Close ends blocked calls with ErrClosed; later calls return ErrClosed too.

type XLFlags added in v0.5.0

type XLFlags uint8

XLFlags are the flags of a CAN XL frame (struct canxl_frame's flags without CANXL_XLF, which every CAN XL frame carries).

const (
	// XLSEC is the simple extended content bit (security, segmentation).
	XLSEC XLFlags = 0x01
	// XLRRS is the remote request substitution bit (Linux ≥ 6.18 names
	// it; older kernels pass it through as a reserved bit).
	XLRRS XLFlags = 0x02
)

CAN XL flags.

func (XLFlags) String added in v0.5.0

func (f XLFlags) String() string

String lists the set flags, for example "SEC|RRS".

type XLFrame added in v0.5.0

type XLFrame struct {
	// Priority is the 11-bit arbitration priority.
	Priority uint16
	// VCID is the virtual CAN network identifier (0 = none).
	VCID uint8
	// Flags are the frame's flags other than the XL format bit.
	Flags XLFlags
	// SDT is the SDU (service data unit) type of the payload.
	SDT uint8
	// AF is the 32-bit acceptance field.
	AF uint32
	// Data is the payload, 1..2048 bytes.
	Data []byte
	// Timestamp is the receive time reported by the transport, or the
	// zero time.
	Timestamp time.Time
	// Interface names the interface the frame was received on, if known.
	Interface string
	// Echo reports that the frame is the receiving socket's own
	// transmission.
	Echo bool
}

XLFrame is one CAN XL frame (ISO 11898-1:2024) with its receive metadata, laid out like Linux's struct canxl_frame.

Unlike Frame, the payload is a slice: it holds up to 2048 bytes. Transports copy it; they do not keep it after Send returns.

func ParseXLFrame added in v0.5.0

func ParseXLFrame(s string) (XLFrame, error)

ParseXLFrame parses a CAN XL frame in can-utils notation: "<vcid><prio>#<flags>:<sdt>:<af>#<data>" (five hex digits before the first "#") or "<prio>#<flags>:<sdt>:<af>#<data>" (three digits, VCID 0). Data bytes may be separated by dots. The XL format bit 0x80 in the flags is implied, as cansend implies it.

func (*XLFrame) Clone added in v0.7.0

func (f *XLFrame) Clone() XLFrame

Clone returns a copy of f with its own payload storage.

func (XLFrame) String added in v0.5.0

func (f XLFrame) String() string

String formats the frame as can-utils does (cansend, candump): "<vcid><prio>#<flags>:<sdt>:<af>#<data>" with a two-digit VCID, a three-digit priority and the flags byte including the XL format bit 0x80, for example "00242#80:01:00000000#AABBCC".

func (*XLFrame) Validate added in v0.5.0

func (f *XLFrame) Validate() error

Validate checks the priority, the payload length and the flags.

type XLMetrics added in v0.7.0

type XLMetrics interface {
	// OnXLFrameSent is called after a CAN XL frame was handed to the
	// transport.
	OnXLFrameSent(iface string, x *XLFrame)
	// OnXLFrameReceived is called for every CAN XL frame read from the
	// transport, before filtering by subscriptions.
	OnXLFrameReceived(iface string, x *XLFrame)
}

XLMetrics is implemented by Metrics that also observe CAN XL frames. A Bus calls these instead of OnFrameSent and OnFrameReceived for CAN XL frames; Metrics without them see CAN XL frames only in the counters of Bus.Stats. NopMetrics implements it.

type XLTransport added in v0.7.0

type XLTransport interface {
	Transport
	SendXL(ctx context.Context, x *XLFrame) error
	ReceiveAny(ctx context.Context, f *Frame, x *XLFrame) (xl bool, err error)
}

XLTransport is implemented by transports that carry CAN XL frames: a SocketCAN socket opened with CAN XL, a virtual bus port. SendXL transmits a CAN XL frame (copying its payload). ReceiveAny waits for the next frame of any kind, a CAN or CAN FD frame in f (xl false) or a CAN XL frame in x (xl true), reusing x.Data's storage; Receive skips CAN XL frames. A Bus on an XLTransport receives with ReceiveAny.

Directories

Path Synopsis
Package arxml reads the CAN part of AUTOSAR 4.x system descriptions (ARXML) into the format-independent model of package candb.
Package arxml reads the CAN part of AUTOSAR 4.x system descriptions (ARXML) into the format-independent model of package candb.
Package candb is the format-independent model of a CAN message database and its signal codec.
Package candb is the format-independent model of a CAN message database and its signal codec.
bits
Package bits extracts and inserts bit fields of CAN payloads in the two layouts of CAN databases.
Package bits extracts and inserts bit fields of CAN payloads in the two layouts of CAN databases.
Package capture reads and writes CAN traces and replays them.
Package capture reads and writes CAN traces and replays them.
Package chaos injects faults between two CAN transports.
Package chaos injects faults between two CAN transports.
Package codegen generates Go code from a candb.Database: one struct per message with typed raw fields, identifier and length constants, enum types for value descriptions, physical-value accessors, and multiplexer-aware Encode, Decode and Frame methods.
Package codegen generates Go code from a candb.Database: one struct per message with typed raw fields, identifier and length constants, enum types for value descriptions, physical-value accessors, and multiplexer-aware Encode, Decode and Frame methods.
Package dbc reads and writes DBC files into the format-independent model of package candb.
Package dbc reads and writes DBC files into the format-independent model of package candb.
Package e2e holds end-to-end tests that combine the packages of go-canbus the way an application does: simulated ECUs from generated code, a gateway decoding with a database, recording into every trace format, replaying and decoding again, ISO-TP diagnostics alongside, on the virtual bus everywhere and on vcan with the kernel on Linux; code generated from DBC, KCD and ARXML compiled and exercised in a separate module; several processes on vcan.
Package e2e holds end-to-end tests that combine the packages of go-canbus the way an application does: simulated ECUs from generated code, a gateway decoding with a database, recording into every trace format, replaying and decoding again, ISO-TP diagnostics alongside, on the virtual bus everywhere and on vcan with the kernel on Linux; code generated from DBC, KCD and ARXML compiled and exercised in a separate module; several processes on vcan.
examples
canxl command
Command canxl sends a 512-byte CAN XL frame and prints every frame on the interface, CAN, CAN FD and CAN XL alike, in can-utils notation.
Command canxl sends a 512-byte CAN XL frame and prints every frame on the interface, CAN, CAN FD and CAN XL alike, in can-utils notation.
capture-replay command
Command capture-replay records traffic of a virtual bus into a candump log, replays it at double speed onto another bus and compares.
Command capture-replay records traffic of a virtual bus into a candump log, replays it at double speed onto another bus and compares.
dbc-decode command
Command dbc-decode parses a DBC database and decodes and encodes a frame with it.
Command dbc-decode parses a DBC database and decodes and encodes a frame with it.
dbc-generate command
Command dbc-generate generates typed Go from a DBC database and shows the generated API, using the package generated from the repository's test database (internal/golden/full).
Command dbc-generate generates typed Go from a DBC database and shows the generated API, using the package generated from the repository's test database (internal/golden/full).
isotp-exchange command
Command isotp-exchange sends a 1000-byte ISO-TP message between two endpoints on a virtual bus, with block size and STmin, and prints the frames on the bus.
Command isotp-exchange sends a 1000-byte ISO-TP message between two endpoints on a virtual bus, with block size and STmin, and prints the frames on the bus.
monitor command
Command monitor prints every frame on a SocketCAN interface (Linux), passively: it never transmits.
Command monitor prints every frame on a SocketCAN interface (Linux), passively: it never transmits.
send command
Command send transmits one classical CAN frame on a SocketCAN interface (Linux).
Command send transmits one classical CAN frame on a SocketCAN interface (Linux).
send-fd command
Command send-fd transmits a 64-byte CAN FD frame with bit rate switching on a SocketCAN interface with the CAN FD MTU (Linux).
Command send-fd transmits a 64-byte CAN FD frame with bit rate switching on a SocketCAN interface with the CAN FD MTU (Linux).
slcan command
Command slcan prints every frame received by a serial-line CAN adapter (CANable, CANtact, USBtin, LAWICEL CANUSB) on any operating system, listen-only: the adapter neither transmits nor acknowledges frames.
Command slcan prints every frame received by a serial-line CAN adapter (CANable, CANtact, USBtin, LAWICEL CANUSB) on any operating system, listen-only: the adapter neither transmits nor acknowledges frames.
vcan-pingpong command
Command vcan-pingpong shows two processes talking over a Linux vcan interface: start the responder, then the requester.
Command vcan-pingpong shows two processes talking over a Linux vcan interface: start the responder, then the requester.
virtual-bus command
Command virtual-bus simulates two nodes on an in-memory bus with injected faults and shows how a receiver detects loss with sequence numbers.
Command virtual-bus simulates two nodes on an in-memory bus with injected faults and shows how a receiver detects loss with sequence numbers.
internal
cmd/gengolden command
Command gengolden regenerates the code generator's golden output, internal/golden/*, from the DBC fixtures (go generate ./...).
Command gengolden regenerates the code generator's golden output, internal/golden/*, from the DBC fixtures (go generate ./...).
golden/full
Package full encodes and decodes the messages of full.dbc.
Package full encodes and decodes the messages of full.dbc.
leakcheck
Package leakcheck checks tests for goroutines they leave behind.
Package leakcheck checks tests for goroutines they leave behind.
Package isotp implements ISO 15765-2 (ISO-TP), the transport protocol that carries messages of up to 4095 bytes (or 4 GiB with the escape sequence) over CAN frames, in userspace on top of a canbus.Bus.
Package isotp implements ISO 15765-2 (ISO-TP), the transport protocol that carries messages of up to 4095 bytes (or 4 GiB with the escape sequence) over CAN frames, in userspace on top of a canbus.Bus.
Package kcd reads KCD files, the XML CAN database format of the Kayak project (namespace http://kayak.2codeornot2code.org/1.0), into the format-independent model of package candb.
Package kcd reads KCD files, the XML CAN database format of the Kayak project (namespace http://kayak.2codeornot2code.org/1.0), into the format-independent model of package candb.
Package slcan is a CAN transport over the serial-line CAN protocol (LAWICEL ASCII, "slcan") of USB-to-CAN adapters such as the CANable, CANtact, USBtin and LAWICEL CANUSB, without the Linux slcan driver: it works on every operating system go-serial supports and over any byte stream (a pseudo-terminal, a TCP connection to a serial server).
Package slcan is a CAN transport over the serial-line CAN protocol (LAWICEL ASCII, "slcan") of USB-to-CAN adapters such as the CANable, CANtact, USBtin and LAWICEL CANUSB, without the Linux slcan driver: it works on every operating system go-serial supports and over any byte stream (a pseudo-terminal, a TCP connection to a serial server).
Package socketcan is the Linux SocketCAN transport: CAN_RAW sockets with CAN FD, kernel filters, error frames, loopback control, kernel timestamps and drop accounting, and kernel ISO-TP sockets (CAN_ISOTP).
Package socketcan is the Linux SocketCAN transport: CAN_RAW sockets with CAN FD, kernel filters, error frames, loopback control, kernel timestamps and drop accounting, and kernel ISO-TP sockets (CAN_ISOTP).
link
Package link reads and changes the configuration of Linux CAN network interfaces through rtnetlink, the interface ip-link(8) uses: listing CAN interfaces, their state, bit timing, CAN FD data bit timing, control modes, error counters and statistics; bringing them up and down; setting bit rates, CAN FD mode, restart-ms and MTU; restarting a bus-off controller; creating and deleting vcan and vxcan interfaces.
Package link reads and changes the configuration of Linux CAN network interfaces through rtnetlink, the interface ip-link(8) uses: listing CAN interfaces, their state, bit timing, CAN FD data bit timing, control modes, error counters and statistics; bringing them up and down; setting bit rates, CAN FD mode, restart-ms and MTU; restarting a bus-off controller; creating and deleting vcan and vxcan interfaces.
Package virtual is a deterministic in-memory CAN bus for tests and simulation, on every operating system.
Package virtual is a deterministic in-memory CAN bus for tests and simulation, on every operating system.

Jump to

Keyboard shortcuts

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