serialmux

package
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: Mar 25, 2026 License: Apache-2.0 Imports: 20 Imported by: 0

Documentation

Overview

Serialmux provides an abstraction over a serial port with the ability for multiple clients to subscribe to events from the serial port and send commands to a single serial port device.

Index

Constants

View Source
const (
	EventTypeRadarObject = "radar_object"
	EventTypeRawData     = "raw_data"
	EventTypeConfig      = "config"
	EventTypeUnknown     = "unknown"
)

Variables

View Source
var ErrWriteFailed = fmt.Errorf("failed to write to serial port")

Functions

func ClassifyPayload

func ClassifyPayload(payload string) string

ClassifyPayload inspects a payload string and returns a simple event type token. The classification is intentionally conservative and mirrors the previous logic used in handlers.

func CurrentStateSnapshot added in v0.5.0

func CurrentStateSnapshot() map[string]any

CurrentStateSnapshot returns a shallow copy of the latest config values received from the device. Returns nil if no config has been received yet. Callers must treat the returned map and all nested values (maps, slices, etc.) as read-only. Code that needs to modify the data should first deep-copy it.

func HandleConfigResponse

func HandleConfigResponse(payload string) error

func HandleEvent

func HandleEvent(d *db.DB, payload string) error

func HandleRadarObject

func HandleRadarObject(d *db.DB, payload string) error

func HandleRawData

func HandleRawData(d *db.DB, payload string) error

Types

type DisabledSerialMux

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

DisabledSerialMux is a no-op SerialMux implementation used when the radar hardware is absent (for --disable-radar). It allows the server and admin routes to run without a real device. Unlike the previous simple implementation, this version tracks subscribers so their channels can be deterministically closed on Unsubscribe() or Close(), allowing readers to unblock predictably during shutdown.

func NewDisabledSerialMux

func NewDisabledSerialMux() *DisabledSerialMux

func (*DisabledSerialMux) AttachAdminRoutes

func (d *DisabledSerialMux) AttachAdminRoutes(mux *http.ServeMux)

func (*DisabledSerialMux) Close

func (d *DisabledSerialMux) Close() error

func (*DisabledSerialMux) Initialise

func (d *DisabledSerialMux) Initialise() error

func (*DisabledSerialMux) Monitor

func (d *DisabledSerialMux) Monitor(ctx context.Context) error

func (*DisabledSerialMux) SendCommand

func (d *DisabledSerialMux) SendCommand(string) error

func (*DisabledSerialMux) Subscribe

func (d *DisabledSerialMux) Subscribe() (string, chan string)

func (*DisabledSerialMux) Unsubscribe

func (d *DisabledSerialMux) Unsubscribe(id string)

type MockOpenCall added in v0.5.0

type MockOpenCall struct {
	Path string
	Mode *SerialPortMode
}

MockOpenCall records details of an Open call.

type MockSerialPort

type MockSerialPort struct {
	io.Reader
	io.WriteCloser
}

MockSerialPort implements SerialPorter for testing

func (*MockSerialPort) SyncClock

func (m *MockSerialPort) SyncClock() error

func (*MockSerialPort) Write

func (m *MockSerialPort) Write(p []byte) (n int, err error)

type MockSerialPortFactory added in v0.5.0

type MockSerialPortFactory struct {

	// Port is the port to return from Open
	Port SerialPorter

	// Error is returned by Open if set
	Error error

	// OpenCalls records all Open calls
	OpenCalls []MockOpenCall
	// contains filtered or unexported fields
}

MockSerialPortFactory implements SerialPortFactory for testing.

func NewMockSerialPortFactory added in v0.5.0

func NewMockSerialPortFactory(port SerialPorter) *MockSerialPortFactory

NewMockSerialPortFactory creates a new MockSerialPortFactory.

func (*MockSerialPortFactory) LastCall added in v0.5.0

func (f *MockSerialPortFactory) LastCall() *MockOpenCall

LastCall returns the most recent Open call, or nil if none.

func (*MockSerialPortFactory) Open added in v0.5.0

Open returns the configured port or error.

func (*MockSerialPortFactory) Reset added in v0.5.0

func (f *MockSerialPortFactory) Reset()

Reset clears all recorded calls.

type Parity added in v0.5.0

type Parity int

Parity defines serial port parity options.

const (
	NoParity Parity = iota
	OddParity
	EvenParity
)

type RealSerialPortFactory added in v0.5.0

type RealSerialPortFactory struct{}

RealSerialPortFactory implements SerialPortFactory using the go.bug.st/serial library.

func NewRealSerialPortFactory added in v0.5.0

func NewRealSerialPortFactory() *RealSerialPortFactory

NewRealSerialPortFactory creates a new RealSerialPortFactory.

func (*RealSerialPortFactory) Open added in v0.5.0

Open opens a real serial port at the specified path.

type SerialMux

type SerialMux[T SerialPorter] struct {
	// contains filtered or unexported fields
}

SerialMux is a generic serial port multiplexer that allows multiple clients to subscribe to events from a single serial port.

func NewMockSerialMux

func NewMockSerialMux(mockLine []byte) *SerialMux[*MockSerialPort]

NewMockSerialMux creates a SerialMux instance backed by a mock serial port

func NewRealSerialMux

func NewRealSerialMux(path string) (*SerialMux[serial.Port], error)

NewRealSerialMux creates a SerialMux instance backed by a real serial port at the given path.

func NewSerialMux

func NewSerialMux[T SerialPorter](port T) *SerialMux[T]

NewSerialMux creates a SerialMux instance backed by a serial port at the given path.

func (*SerialMux[T]) AttachAdminRoutes

func (s *SerialMux[T]) AttachAdminRoutes(mux *http.ServeMux)

func (*SerialMux[T]) Close

func (s *SerialMux[T]) Close() error

func (*SerialMux[T]) Initialise

func (s *SerialMux[T]) Initialise() error

Initialise syncs the clock and TZ offset to the device and sets some default output modes to ensure that we can parse the results.

func (*SerialMux[T]) Monitor

func (s *SerialMux[T]) Monitor(ctx context.Context) error

Monitor monitors the serial port for events and sends them to subscribers

func (*SerialMux[T]) SendCommand

func (s *SerialMux[T]) SendCommand(command string) error

SendCommand sends a command to the serial port.

func (*SerialMux[T]) Subscribe

func (s *SerialMux[T]) Subscribe() (string, chan string)

func (*SerialMux[T]) Unsubscribe

func (s *SerialMux[T]) Unsubscribe(id string)

Unsubscribe removes a subscriber from the serial mux.

type SerialMuxInterface

type SerialMuxInterface interface {
	// Subscribe creates a new channel for receiving line events from the serial
	// port. The channel ID is used to identify the unique channel when
	// unsubscribing.
	Subscribe() (string, chan string)
	// Unsubscribe removes a channel from the list of subscribers.
	Unsubscribe(string)
	// SendCommand writes the provided command to the serial port.
	SendCommand(string) error
	// Monitor reads lines from the serial port and sends them to the
	// appropriate channels.
	Monitor(context.Context) error
	// Close closes all subscribed channels and closes the serial port.
	Close() error

	Initialise() error

	// AttachAdminRoutes attaches admin debugging endpoints to the given HTTP
	// mux served at /debug/. These routes are accessible only over
	// localhost/via Tailscale and are not publicly accessible.
	AttachAdminRoutes(*http.ServeMux)
}

SerialMuxInterface defines the interface for the SerialMux type.

type SerialPortFactory added in v0.5.0

type SerialPortFactory interface {
	// Open opens a serial port at the specified path with the given mode.
	Open(path string, mode *SerialPortMode) (SerialPorter, error)
}

SerialPortFactory defines an interface for creating serial ports. This abstraction enables dependency injection of serial port creation.

type SerialPortMode added in v0.5.0

type SerialPortMode struct {
	BaudRate int
	DataBits int
	Parity   Parity
	StopBits StopBits
}

SerialPortMode defines serial port configuration parameters.

func DefaultSerialPortMode added in v0.5.0

func DefaultSerialPortMode() *SerialPortMode

DefaultSerialPortMode returns the default mode for radar sensors.

type SerialPortOpener added in v0.5.0

type SerialPortOpener func(path string, mode *SerialPortMode) (SerialPorter, error)

SerialPortOpener is a function type for opening serial ports. This allows for easier testing by replacing the opener function.

type SerialPorter

type SerialPorter interface {
	io.ReadWriter
	io.Closer
}

SerialPorter defines the minimal interface needed for a serial port. This abstraction enables unit testing without real serial hardware.

type StopBits added in v0.5.0

type StopBits int

StopBits defines serial port stop bit options.

const (
	OneStopBit StopBits = iota
	TwoStopBits
)

type TestableSerialPort added in v0.5.0

type TestableSerialPort struct {

	// ReadBuffer holds data to be returned by Read calls
	ReadBuffer *bytes.Buffer

	// WriteBuffer captures data written to the port
	WriteBuffer *bytes.Buffer

	// ReadLatency adds a delay to each Read call
	ReadLatency time.Duration

	// WriteLatency adds a delay to each Write call
	WriteLatency time.Duration

	// ReadError is returned by the next Read call if set
	ReadError error

	// WriteError is returned by the next Write call if set
	WriteError error

	// CloseError is returned by Close if set
	CloseError error

	// Closed indicates whether Close was called
	Closed bool

	// ReadCalls records the number of Read calls
	ReadCalls int

	// WriteCalls records the number of Write calls
	WriteCalls int

	// ReadTimeout is the current read timeout
	ReadTimeout time.Duration

	// BlockReads causes Read to block until data is added or Close is called
	BlockReads bool
	// contains filtered or unexported fields
}

TestableSerialPort implements SerialPorter with configurable behaviour for testing. It provides fine-grained control over reads, writes, errors, and latency.

func NewTestableSerialPort added in v0.5.0

func NewTestableSerialPort() *TestableSerialPort

NewTestableSerialPort creates a new TestableSerialPort for testing.

func (*TestableSerialPort) AddReadData added in v0.5.0

func (t *TestableSerialPort) AddReadData(data []byte)

AddReadData adds data to be returned by subsequent Read calls.

func (*TestableSerialPort) Close added in v0.5.0

func (t *TestableSerialPort) Close() error

Close marks the port as closed.

func (*TestableSerialPort) GetWrittenData added in v0.5.0

func (t *TestableSerialPort) GetWrittenData() []byte

GetWrittenData returns all data written to the port.

func (*TestableSerialPort) Read added in v0.5.0

func (t *TestableSerialPort) Read(p []byte) (n int, err error)

Read reads from the read buffer, optionally simulating latency and errors.

func (*TestableSerialPort) Reset added in v0.5.0

func (t *TestableSerialPort) Reset()

Reset clears all buffers and resets state.

func (*TestableSerialPort) SetReadTimeout added in v0.5.0

func (t *TestableSerialPort) SetReadTimeout(timeout time.Duration) error

SetReadTimeout implements TimeoutSerialPorter.

func (*TestableSerialPort) Write added in v0.5.0

func (t *TestableSerialPort) Write(p []byte) (n int, err error)

Write writes to the write buffer, optionally simulating latency and errors.

type TimeoutSerialPorter added in v0.5.0

type TimeoutSerialPorter interface {
	SerialPorter
	// SetReadTimeout sets the read timeout for the serial port.
	SetReadTimeout(timeout time.Duration) error
}

TimeoutSerialPorter extends SerialPorter with timeout capabilities. This is an optional interface that serial ports may implement.

Jump to

Keyboard shortcuts

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