gateway

package
v1.6.0 Latest Latest
Warning

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

Go to latest
Published: Sep 11, 2026 License: MIT Imports: 20 Imported by: 0

Documentation

Overview

Package gateway parses the wire formats spoken by NMEA 2000 network gateways: the Yacht Devices RAW ASCII line protocol and the Actisense binary stream protocol.

Index

Constants

This section is empty.

Variables

View Source
var ErrActisenseNotReady = errors.New("actisense: gateway session is not ready")

Functions

func EncodeSend

func EncodeSend(m N2KMessage) ([]byte, error)

EncodeSend renders an assembled N2K message as an Actisense transmit command (0x94). The payload layout is priority (1), PGN (3, little-endian), destination (1), data length (1), data. There is no source-address byte: the gateway transmits under its own claimed bus address, so m.Source is not carried on the wire. The gateway also performs fast-packet fragmentation itself, which is why sends are whole messages rather than CAN frames.

func EncodeStartup

func EncodeStartup() []byte

EncodeStartup renders the historical unacknowledged mode-2 command. Mode 2 disables the receive PGN list only; the transmit list remains active. New session adapters use an acknowledged BEM handshake instead.

func FormatActisenseCANASCII added in v1.2.0

func FormatActisenseCANASCII(frame can.Frame, direction raw.Direction, timestamp time.Duration) ([]byte, error)

FormatActisenseCANASCII renders a mode-6 CAN frame. A zero timestamp is represented as 00:00:00.000, which is suitable for host-to-gateway writes.

func FormatActisenseN2KASCII added in v1.2.0

func FormatActisenseN2KASCII(pgn uint32, priority, source, destination uint8, payload []byte, timestamp time.Duration) ([]byte, error)

FormatActisenseN2KASCII renders one assembled message in the documented Type-A representation.

func FormatYDRawTX

func FormatYDRawTX(frame can.Frame) []byte

FormatYDRawTX renders a CAN frame as a Yacht Devices RAW transmit line. Application-to-gateway lines carry no time or direction field — just the 29-bit identifier and the data bytes, CRLF-terminated:

19F51323 01 02<CR><LF>

Once the gateway transmits the frame onto the bus it echoes the line back with a timestamp and direction T, which ParseYDRaw accepts like any other frame. Filtered or malformed lines get no echo.

func ParseActisenseCANASCIIObservation added in v1.2.0

func ParseActisenseCANASCIIObservation(line string) (raw.Observation, error)

ParseActisenseCANASCIIObservation parses the Actisense CAN-frame ASCII representation used by operating mode 6. Zero-to-eight-byte frames and timestamps with or without fractional seconds are accepted.

func ParseActisenseN2KASCIIObservation added in v1.2.0

func ParseActisenseN2KASCIIObservation(line string) (raw.Observation, error)

ParseActisenseN2KASCIIObservation parses one gateway-assembled N2K ASCII message. It preserves source, destination, priority, PGN, and up to the complete 1785-byte NMEA 2000 transport payload.

func ParseYDRaw

func ParseYDRaw(line string) (can.Frame, bool)

ParseYDRaw parses one line of the Yacht Devices RAW protocol (YDWG-02 and compatible gateways), e.g.

17:33:21.107 R 09F11201 01 5C 3D FF 7F FF 7F FC

The direction field is R (received from the bus) or T (transmitted to the bus); both carry frames. Returns ok=false for service messages, blank lines, and anything else that does not carry a CAN data frame.

func ParseYDRawObservation added in v1.0.0

func ParseYDRawObservation(line string) (raw.Observation, bool)

ParseYDRawObservation preserves the gateway's relative timestamp and receive/transmit direction in addition to the CAN frame.

func ReadActisense added in v0.2.0

func ReadActisense(r io.Reader, handler func(can.Frame)) error

ReadActisense reassembles Actisense messages from r and emits CAN frames. Message-level D0 records and gateway diagnostics require the Observation Interface and are intentionally omitted by this compatibility helper.

func ReadActisenseCANASCIIObservations added in v1.2.0

func ReadActisenseCANASCIIObservations(reader io.Reader, handler func(raw.Observation)) error

func ReadActisenseN2KASCIIObservations added in v1.2.0

func ReadActisenseN2KASCIIObservations(reader io.Reader, handler func(raw.Observation)) error

func ReadActisenseObservations added in v1.0.0

func ReadActisenseObservations(r io.Reader, handler func(raw.Observation)) error

ReadActisenseObservations decodes all supported BDTP/BST datagrams until EOF.

func ReadYDRaw added in v0.2.0

func ReadYDRaw(r io.Reader, handler func(can.Frame)) error

ReadYDRaw delivers Yacht Devices RAW lines from r as CAN frames until EOF or a read error. It is the single reader for the RAW protocol, shared by the TCP bus and the read-only network sources.

func ReadYDRawObservations added in v1.0.0

func ReadYDRawObservations(r io.Reader, handler func(raw.Observation)) error

ReadYDRawObservations preserves direction and gateway-relative timestamps.

func Reframe

func Reframe(m N2KMessage, seq uint8) ([]can.Frame, error)

Reframe converts an assembled N2K message back into wire CAN frames: a single frame for non-fast PGNs up to 8 bytes, fast-packet frames for fast PGNs up to 223 bytes. PGNs absent from the metadata tables are framed by size (fast iff the payload exceeds 8 bytes). seq is the fast-packet sequence ID (0-7).

func ReframeEmitter

func ReframeEmitter(handler func(can.Frame)) func(N2KMessage)

ReframeEmitter adapts a CAN-frame handler into an assembled-message consumer: each message is re-framed into wire CAN frames (rotating the fast-packet sequence ID per message) and fed to the handler. Messages that cannot be re-framed are dropped.

func RunPassiveActisenseN2KASCIISerialObservations added in v1.2.0

func RunPassiveActisenseN2KASCIISerialObservations(ctx context.Context, port string, settings ActisenseSerialSettings, handler func(raw.Observation)) error

RunPassiveActisenseN2KASCIISerialObservations reads an already-configured assembled N2K ASCII output without a BEM mode mutation.

func RunPassiveActisenseSerialObservations added in v1.2.0

func RunPassiveActisenseSerialObservations(ctx context.Context, port string, settings ActisenseSerialSettings, handler func(raw.Observation)) error

RunPassiveActisenseSerialObservations reads binary BST without changing the device's operating mode.

Types

type ActisenseCANASCIISerialBus added in v1.2.0

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

ActisenseCANASCIISerialBus is a source-authoritative mode-6 CAN ASCII Bus.

func NewActisenseCANASCIISerialBus added in v1.2.0

func NewActisenseCANASCIISerialBus(log *slog.Logger, port string, settings ...ActisenseSerialSettings) *ActisenseCANASCIISerialBus

func (*ActisenseCANASCIISerialBus) Close added in v1.2.0

func (b *ActisenseCANASCIISerialBus) Close() error

func (*ActisenseCANASCIISerialBus) Metrics added in v1.2.0

func (*ActisenseCANASCIISerialBus) Ready added in v1.2.0

func (b *ActisenseCANASCIISerialBus) Ready() <-chan struct{}

func (*ActisenseCANASCIISerialBus) Run added in v1.2.0

func (b *ActisenseCANASCIISerialBus) Run(ctx context.Context, handler func(can.Frame)) error

func (*ActisenseCANASCIISerialBus) RunObservations added in v1.2.0

func (b *ActisenseCANASCIISerialBus) RunObservations(ctx context.Context, handler func(raw.Observation)) error

func (*ActisenseCANASCIISerialBus) WriteFrame added in v1.2.0

func (b *ActisenseCANASCIISerialBus) WriteFrame(frame can.Frame) error

func (*ActisenseCANASCIISerialBus) WriteFrameContext added in v1.3.0

func (b *ActisenseCANASCIISerialBus) WriteFrameContext(ctx context.Context, frame can.Frame) error

type ActisenseCANASCIITCPBus added in v1.2.0

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

ActisenseCANASCIITCPBus is a source-authoritative mode-6 CAN ASCII Bus. Binary BEM control replies are demultiplexed from ASCII frame lines.

func NewActisenseCANASCIITCPBus added in v1.2.0

func NewActisenseCANASCIITCPBus(log *slog.Logger, addr string, reconnect *ReconnectPolicy) *ActisenseCANASCIITCPBus

func (*ActisenseCANASCIITCPBus) Close added in v1.2.0

func (b *ActisenseCANASCIITCPBus) Close() error

func (*ActisenseCANASCIITCPBus) Metrics added in v1.2.0

func (*ActisenseCANASCIITCPBus) Ready added in v1.2.0

func (b *ActisenseCANASCIITCPBus) Ready() <-chan struct{}

func (*ActisenseCANASCIITCPBus) Run added in v1.2.0

func (b *ActisenseCANASCIITCPBus) Run(ctx context.Context, handler func(can.Frame)) error

func (*ActisenseCANASCIITCPBus) RunObservations added in v1.2.0

func (b *ActisenseCANASCIITCPBus) RunObservations(ctx context.Context, handler func(raw.Observation)) error

func (*ActisenseCANASCIITCPBus) SetConnectionObserver added in v1.2.0

func (b *ActisenseCANASCIITCPBus) SetConnectionObserver(observer func(bool, uint64))

func (*ActisenseCANASCIITCPBus) WriteFrame added in v1.2.0

func (b *ActisenseCANASCIITCPBus) WriteFrame(frame can.Frame) error

func (*ActisenseCANASCIITCPBus) WriteFrameContext added in v1.3.0

func (b *ActisenseCANASCIITCPBus) WriteFrameContext(ctx context.Context, frame can.Frame) error

type ActisenseConnection added in v1.2.0

type ActisenseConnection interface {
	io.Reader
	io.Writer
	io.Closer
}

ActisenseConnection is the public package's byte-stream seam for a custom gateway transport. Close must promptly unblock Read and Write and may run concurrently with either operation.

type ActisenseGatewayMetrics added in v1.2.0

type ActisenseGatewayMetrics struct {
	ConnectionEpochs uint64
	Reconnects       uint64
	GatewayResets    uint64
	Protocol         actisense.SessionMetrics
}

ActisenseGatewayMetrics combines protocol-session counters across reconnect epochs with gateway lifecycle events.

type ActisenseGatewaySession added in v1.2.0

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

ActisenseGatewaySession exposes the gateway-owned BST-93/94 and BEM session without claiming that it is a source-authoritative CAN Bus.

func NewActisenseCustomGatewaySession added in v1.2.0

func NewActisenseCustomGatewaySession(log *slog.Logger, endpoint, adapterID string, open ActisenseOpen, reconnect *ReconnectPolicy, mode actisense.OperatingMode) *ActisenseGatewaySession

func NewActisenseSerialGatewaySession added in v1.2.0

func NewActisenseSerialGatewaySession(log *slog.Logger, port string, settings ActisenseSerialSettings, mode actisense.OperatingMode) *ActisenseGatewaySession

func NewActisenseTCPGatewaySession added in v1.2.0

func NewActisenseTCPGatewaySession(log *slog.Logger, address string, reconnect *ReconnectPolicy, mode actisense.OperatingMode) *ActisenseGatewaySession

func (*ActisenseGatewaySession) Close added in v1.2.0

func (s *ActisenseGatewaySession) Close() error

func (*ActisenseGatewaySession) EpochRequester added in v1.3.0

func (s *ActisenseGatewaySession) EpochRequester(epoch uint64) (actisense.Requester, error)

EpochRequester binds a transaction to one acknowledged connection. Its requests fail with that session rather than moving onto a reconnect.

func (*ActisenseGatewaySession) Metrics added in v1.2.0

func (*ActisenseGatewaySession) PreserveOperatingMode added in v1.4.0

func (s *ActisenseGatewaySession) PreserveOperatingMode()

These hooks are installed before Run. They execute on the sole reader.

func (*ActisenseGatewaySession) Ready added in v1.2.0

func (s *ActisenseGatewaySession) Ready() <-chan struct{}

func (*ActisenseGatewaySession) Request added in v1.2.0

func (s *ActisenseGatewaySession) Request(ctx context.Context, command byte, data []byte) (actisense.BEMResponse, error)

func (*ActisenseGatewaySession) RequestMulti added in v1.2.0

func (s *ActisenseGatewaySession) RequestMulti(ctx context.Context, command byte, data []byte, inactivity time.Duration, complete func([]actisense.BEMResponse) (bool, error)) ([]actisense.BEMResponse, error)

func (*ActisenseGatewaySession) Run added in v1.2.0

func (s *ActisenseGatewaySession) Run(ctx context.Context, handler func(can.Frame)) error

func (*ActisenseGatewaySession) RunObservations added in v1.2.0

func (s *ActisenseGatewaySession) RunObservations(ctx context.Context, handler func(raw.Observation)) error

func (*ActisenseGatewaySession) SetCommandTimeout added in v1.2.0

func (s *ActisenseGatewaySession) SetCommandTimeout(timeout time.Duration) error

func (*ActisenseGatewaySession) SetConnectionObserver added in v1.2.0

func (s *ActisenseGatewaySession) SetConnectionObserver(observer func(bool, uint64))

func (*ActisenseGatewaySession) SetDiagnosticObserver added in v1.2.0

func (s *ActisenseGatewaySession) SetDiagnosticObserver(observer func(actisense.Diagnostic))

func (*ActisenseGatewaySession) SetMessageObserver added in v1.4.0

func (s *ActisenseGatewaySession) SetMessageObserver(observer func(actisense.Message))

func (*ActisenseGatewaySession) SetModeObserver added in v1.4.0

func (s *ActisenseGatewaySession) SetModeObserver(observer func(actisense.OperatingMode))

func (*ActisenseGatewaySession) SetReconnectPolicy added in v1.4.0

func (s *ActisenseGatewaySession) SetReconnectPolicy(policy *ReconnectPolicy)

func (*ActisenseGatewaySession) SetWireObserver added in v1.2.0

func (s *ActisenseGatewaySession) SetWireObserver(observer func(actisense.WireDirection, time.Time, []byte))

func (*ActisenseGatewaySession) WriteContext added in v1.4.0

func (s *ActisenseGatewaySession) WriteContext(ctx context.Context, wire []byte) error

WriteContext captures the current connection once and never waits for or retries on a reconnect. The public caller owns and bounds the wire snapshot.

func (*ActisenseGatewaySession) WriteMessage added in v1.2.0

func (s *ActisenseGatewaySession) WriteMessage(pgn uint32, priority, destination uint8, payload []byte) error

func (*ActisenseGatewaySession) WriteMessageContext added in v1.2.0

func (s *ActisenseGatewaySession) WriteMessageContext(ctx context.Context, pgn uint32, priority, destination uint8, payload []byte) error

func (*ActisenseGatewaySession) WriteMessageEpoch added in v1.4.0

func (s *ActisenseGatewaySession) WriteMessageEpoch(ctx context.Context, number uint64, pgn uint32, priority, destination uint8, payload []byte) error

type ActisenseModeSetupError added in v1.1.0

type ActisenseModeSetupError struct {
	RequestedMode actisense.OperatingMode
	Err           error
}

ActisenseModeSetupError reports a failed acknowledged operating-mode setup. The public package translates it into ActisenseModeError.

func (*ActisenseModeSetupError) Error added in v1.1.0

func (e *ActisenseModeSetupError) Error() string

func (*ActisenseModeSetupError) Unwrap added in v1.1.0

func (e *ActisenseModeSetupError) Unwrap() error

type ActisenseObservationAdapter added in v1.1.0

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

ActisenseObservationAdapter exposes the transport-neutral BST-to-Observation Adapter to capture readers without exporting protocol state from this internal package.

func NewActisenseObservationAdapter added in v1.1.0

func NewActisenseObservationAdapter() *ActisenseObservationAdapter

func (*ActisenseObservationAdapter) HandleDatagram added in v1.1.0

func (a *ActisenseObservationAdapter) HandleDatagram(datagram actisense.Datagram, handler func(raw.Observation))

func (*ActisenseObservationAdapter) HandleDecodeError added in v1.1.0

func (a *ActisenseObservationAdapter) HandleDecodeError(err actisense.DecodeError, handler func(raw.Observation))

type ActisenseOpen added in v1.2.0

type ActisenseOpen func(context.Context) (ActisenseConnection, error)

ActisenseOpen opens one connection epoch for a custom byte transport.

type ActisenseRawSerialBus added in v1.1.0

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

ActisenseRawSerialBus is a source-authoritative BST-95 raw CAN Bus over a direct 115200 8N1 serial connection.

func NewActisenseRawSerialBus added in v1.1.0

func NewActisenseRawSerialBus(log *slog.Logger, port string, settings ...ActisenseSerialSettings) *ActisenseRawSerialBus

func (*ActisenseRawSerialBus) Close added in v1.1.0

func (b *ActisenseRawSerialBus) Close() error

func (*ActisenseRawSerialBus) Metrics added in v1.2.0

func (*ActisenseRawSerialBus) Ready added in v1.1.0

func (b *ActisenseRawSerialBus) Ready() <-chan struct{}

func (*ActisenseRawSerialBus) Run added in v1.1.0

func (b *ActisenseRawSerialBus) Run(ctx context.Context, handler func(can.Frame)) error

func (*ActisenseRawSerialBus) RunObservations added in v1.1.0

func (b *ActisenseRawSerialBus) RunObservations(ctx context.Context, handler func(raw.Observation)) error

func (*ActisenseRawSerialBus) WriteFrame added in v1.1.0

func (b *ActisenseRawSerialBus) WriteFrame(frame can.Frame) error

func (*ActisenseRawSerialBus) WriteFrameContext added in v1.3.0

func (b *ActisenseRawSerialBus) WriteFrameContext(ctx context.Context, frame can.Frame) error

type ActisenseRawTCPBus added in v1.1.0

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

ActisenseRawTCPBus is a source-authoritative BST-95 raw CAN Bus.

func NewActisenseRawTCPBus added in v1.1.0

func NewActisenseRawTCPBus(log *slog.Logger, addr string, reconnect *ReconnectPolicy) *ActisenseRawTCPBus

func (*ActisenseRawTCPBus) Close added in v1.1.0

func (b *ActisenseRawTCPBus) Close() error

func (*ActisenseRawTCPBus) Metrics added in v1.2.0

func (*ActisenseRawTCPBus) Ready added in v1.1.0

func (b *ActisenseRawTCPBus) Ready() <-chan struct{}

func (*ActisenseRawTCPBus) Run added in v1.1.0

func (b *ActisenseRawTCPBus) Run(ctx context.Context, handler func(can.Frame)) error

func (*ActisenseRawTCPBus) RunObservations added in v1.1.0

func (b *ActisenseRawTCPBus) RunObservations(ctx context.Context, handler func(raw.Observation)) error

func (*ActisenseRawTCPBus) SetConnectionObserver added in v1.1.0

func (b *ActisenseRawTCPBus) SetConnectionObserver(observer func(bool, uint64))

func (*ActisenseRawTCPBus) WriteFrame added in v1.1.0

func (b *ActisenseRawTCPBus) WriteFrame(frame can.Frame) error

func (*ActisenseRawTCPBus) WriteFrameContext added in v1.3.0

func (b *ActisenseRawTCPBus) WriteFrameContext(ctx context.Context, frame can.Frame) error

type ActisenseReader

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

ActisenseReader is an incremental decoder for the Actisense binary stream protocol. It tolerates arbitrary buffer boundaries: bytes are fed as they arrive and complete messages are emitted as they are recognized.

func NewActisenseReader

func NewActisenseReader() *ActisenseReader

NewActisenseReader returns a reader ready to consume stream bytes.

func (*ActisenseReader) Feed

func (r *ActisenseReader) Feed(buf []byte, emit func(N2KMessage))

Feed consumes raw stream bytes; emit is called once per complete, checksum-valid N2K message (command 0x93). Garbage between messages is skipped and messages that fail their checksum are dropped silently.

type ActisenseSerialSettings added in v1.2.0

type ActisenseSerialSettings struct {
	BaudRate int
	DataBits int
	Parity   uint8
	StopBits uint8
}

ActisenseSerialSettings is the transport-neutral serial configuration passed by the public Adapter.

type Backoff added in v0.2.0

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

Backoff is a re-armable exponential backoff sequencer. It is not safe for concurrent use; a single reconnect loop owns one Backoff.

func NewBackoff added in v0.2.0

func NewBackoff(policy ReconnectPolicy) *Backoff

NewBackoff returns a Backoff seeded from policy, substituting defaults for any non-positive field.

func (*Backoff) Reset added in v0.2.0

func (b *Backoff) Reset()

Reset returns the sequencer to its initial delay, so the next Wait sleeps for InitialBackoff again. Call it after a connection is successfully established so a brief reconnect does not inherit a long prior backoff.

func (*Backoff) Wait added in v0.2.0

func (b *Backoff) Wait(ctx context.Context) bool

Wait sleeps for the next backoff interval, doubling it up to MaxBackoff on each successive call, and returns true. It returns false immediately if ctx is cancelled before the interval elapses.

type N2KMessage

type N2KMessage = actisense.Message

N2KMessage is one NMEA 2000 message carried by an Actisense stream. Data is the assembled PGN payload (fast-packet PGNs arrive already assembled).

type ReconnectPolicy added in v0.2.0

type ReconnectPolicy struct {
	// InitialBackoff is the delay before the first reconnect attempt after a
	// drop, and the delay restored after any successful connection.
	InitialBackoff time.Duration
	// MaxBackoff caps the exponentially growing delay between attempts while a
	// connection cannot be re-established.
	MaxBackoff time.Duration
}

ReconnectPolicy configures automatic re-dialing of a dropped gateway connection. A nil *ReconnectPolicy means reconnection is disabled: a dropped connection ends the read loop (the historical behavior).

type YDRawTCPBus

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

YDRawTCPBus is a read/write bus over a TCP gateway speaking the Yacht Devices RAW line protocol (YDWG-02 RAW server mode and compatibles). RAW mode is frame-level in both directions, so the full client stack — address claiming included — works exactly as it does on CAN hardware. The gateway echoes transmitted frames back with direction T, so the client also observes its own traffic.

func NewYDRawTCPBus

func NewYDRawTCPBus(log *slog.Logger, addr string, reconnect *ReconnectPolicy) *YDRawTCPBus

NewYDRawTCPBus returns an unconnected bus; Run dials. A non-nil reconnect policy makes Run re-dial dropped connections.

func (*YDRawTCPBus) Close

func (b *YDRawTCPBus) Close() error

Close releases the connection.

func (*YDRawTCPBus) Run

func (b *YDRawTCPBus) Run(ctx context.Context, handler func(can.Frame)) error

Run connects and delivers incoming frames to handler until ctx is cancelled or (without a reconnect policy) the connection fails.

func (*YDRawTCPBus) RunObservations added in v1.0.0

func (b *YDRawTCPBus) RunObservations(ctx context.Context, handler func(raw.Observation)) error

RunObservations preserves gateway transport context.

func (*YDRawTCPBus) SetConnectionObserver added in v1.0.0

func (b *YDRawTCPBus) SetConnectionObserver(observer func(bool, uint64))

SetConnectionObserver installs reconnect lifecycle observation for Client.

func (*YDRawTCPBus) WriteFrame

func (b *YDRawTCPBus) WriteFrame(frame can.Frame) error

WriteFrame transmits one CAN frame as a RAW line.

func (*YDRawTCPBus) WriteFrameContext added in v1.3.0

func (b *YDRawTCPBus) WriteFrameContext(ctx context.Context, frame can.Frame) error

WriteFrameContext sends one frame without replaying it after reconnect.

Jump to

Keyboard shortcuts

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