changetracker

package
v0.4.1 Latest Latest
Warning

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

Go to latest
Published: Mar 25, 2026 License: MIT Imports: 7 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ByteMaskDiff

type ByteMaskDiff struct{}

ByteMaskDiff is the default diff method. Any byte-level change is significant.

Short format (packets <= 8 bytes):

[mask:1] [changed bytes...]

Extended format (packets > 8 bytes):

[maskLen:2 LE] [mask bytes...] [changed bytes...]

func (ByteMaskDiff) Apply

func (ByteMaskDiff) Apply(prev, diff []byte) []byte

func (ByteMaskDiff) Diff

func (ByteMaskDiff) Diff(prev, curr []byte) (bool, []byte)

type ChangeEvent

type ChangeEvent struct {
	Type      ChangeEventType
	Timestamp time.Time
	Source    uint8
	PGN       uint32
	SubKey    uint64
	Seq       uint64
	Data      []byte // Full data for Snapshot, diff for Delta, nil for Idle.
}

ChangeEvent is emitted by the ChangeTracker when a meaningful state change (or silence) is detected for a (source, PGN, subkey) tracking key.

type ChangeEventType

type ChangeEventType uint8

ChangeEventType identifies the kind of change event.

const (
	// Snapshot is the first observation for a key. Contains full packet data.
	Snapshot ChangeEventType = 1
	// Delta means a significant change was detected. Contains a compact diff.
	Delta ChangeEventType = 2
	// Idle means a source stopped producing for this key.
	Idle ChangeEventType = 3
)

func (ChangeEventType) String

func (t ChangeEventType) String() string

type ChangeReplayer

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

ChangeReplayer reconstructs full packet data from a stream of ChangeEvents. Maintains per-key state and applies diffs to recover the original packets.

func NewChangeReplayer

func NewChangeReplayer(methods map[uint32]DiffMethod, subKeys map[uint32]SubKeyFunc) *ChangeReplayer

NewChangeReplayer creates a replayer. Pass the same methods and subkeys config used by the tracker that produced the events.

func (*ChangeReplayer) Apply

func (r *ChangeReplayer) Apply(event ChangeEvent) ([]byte, error)

Apply processes a ChangeEvent and returns the reconstructed full packet data. Returns nil for Idle events (state is preserved but no data emitted). Returns an error if a Delta arrives without a prior Snapshot.

func (*ChangeReplayer) State

func (r *ChangeReplayer) State(source uint8, pgnID uint32, subKey uint64) []byte

State returns the last known full packet data for a key, or nil if unknown.

type ChangeTracker

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

ChangeTracker tracks per-(source, PGN, subkey) state and emits compact change events. Not goroutine-safe; designed for single-goroutine callers (like the broker's handleFrame).

func NewChangeTracker

func NewChangeTracker(cfg Config) *ChangeTracker

NewChangeTracker creates a ChangeTracker with the given configuration. Automatically wires FieldToleranceDiff for any PGN in the registry that declares field-level tolerances, unless an explicit method is already set.

func (*ChangeTracker) Process

func (ct *ChangeTracker) Process(ts time.Time, source uint8, pgnID uint32, data []byte, seq uint64) *ChangeEvent

Process handles an incoming frame and returns a ChangeEvent if the frame represents a meaningful state change. Returns nil for no-ops (unchanged data within tolerance).

func (*ChangeTracker) Remove

func (ct *ChangeTracker) Remove(source uint8, pgnID uint32, subKey uint64)

Remove removes tracking state for a specific key.

func (*ChangeTracker) Reset

func (ct *ChangeTracker) Reset()

Reset clears all tracked state.

func (*ChangeTracker) Tick

func (ct *ChangeTracker) Tick(now time.Time) []ChangeEvent

Tick checks all tracked pairs for idle timeouts and returns Idle events for any that have exceeded their timeout. Call this periodically.

func (*ChangeTracker) TrackedPairs

func (ct *ChangeTracker) TrackedPairs() int

TrackedPairs returns the number of actively tracked (source, PGN, subkey) pairs.

type Config

type Config struct {
	// DefaultMethod is the diff method used for PGNs without a specific override.
	// Nil defaults to ByteMaskDiff.
	DefaultMethod DiffMethod

	// Methods maps specific PGNs to custom diff methods.
	Methods map[uint32]DiffMethod

	// SubKeys maps specific PGNs to sub-key extractor functions for
	// multiplexed PGNs (e.g., Victron registers on PGN 61184).
	SubKeys map[uint32]SubKeyFunc

	// DefaultIdleTimeout is the fallback idle timeout when no PGN-specific
	// timeout can be resolved. Defaults to 5s.
	DefaultIdleTimeout time.Duration

	// IdleMultiplier is applied to the PGN registry interval to compute
	// the idle timeout. Defaults to 3.
	IdleMultiplier int

	// IdleTimeouts maps specific PGNs to explicit idle timeout overrides.
	IdleTimeouts map[uint32]time.Duration
}

Config configures the ChangeTracker.

type DiffMethod

type DiffMethod interface {
	// Diff compares prev and curr, returning whether the change is significant
	// and a compact diff encoding. If not significant, diff is nil.
	Diff(prev, curr []byte) (significant bool, diff []byte)

	// Apply reconstructs curr from prev and a diff produced by Diff.
	Apply(prev, diff []byte) []byte
}

DiffMethod computes and applies compact binary diffs between packet payloads.

type FieldTolerance

type FieldTolerance struct {
	Field     string
	Tolerance float64
}

FieldTolerance defines a tolerance threshold for a named field. Changes within the tolerance are suppressed (not emitted as significant).

type FieldToleranceDiff

type FieldToleranceDiff struct {
	Inner      DiffMethod
	PGN        uint32
	Decode     func([]byte) (any, error)
	Tolerances []FieldTolerance
}

FieldToleranceDiff wraps an inner DiffMethod and uses PGN decode functions plus reflection to check field-level tolerances. If all changed fields are within their tolerance, the change is suppressed. The encoding is always delegated to the inner method (tolerances only gate significance).

The baseline is NOT updated when a change is suppressed, preventing tolerance drift over time.

func (*FieldToleranceDiff) Apply

func (f *FieldToleranceDiff) Apply(prev, diff []byte) []byte

func (*FieldToleranceDiff) Diff

func (f *FieldToleranceDiff) Diff(prev, curr []byte) (bool, []byte)

type SubKeyFunc

type SubKeyFunc func(data []byte) uint64

SubKeyFunc extracts a sub-discriminator from raw packet data for multiplexed PGNs. Returns 0 for non-multiplexed PGNs (i.e., no sub-key extractor configured).

Jump to

Keyboard shortcuts

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