Documentation
¶
Overview ¶
Package journal provides the block-based binary journal format (.lpj files) for recording and replaying NMEA 2000 CAN frames.
Index ¶
- Constants
- Variables
- func PutLenPrefixedString(buf []byte, s string) int
- func ReadLenPrefixedString(block []byte, off int) (string, int, error)
- func UvarintSize(v uint64) int
- type BlockInfo
- type CompressionType
- type CorruptError
- type Device
- type Entry
- type Reader
- func (jr *Reader) BlockCount() int
- func (jr *Reader) BlockDevices() []Device
- func (jr *Reader) BlockDevicesAt(frameIdx int) []Device
- func (jr *Reader) BlockSize() int
- func (jr *Reader) Close()
- func (jr *Reader) Compression() CompressionType
- func (jr *Reader) CurrentBlock() int
- func (jr *Reader) EnablePrefetch()
- func (jr *Reader) Err() error
- func (jr *Reader) Frame() Entry
- func (jr *Reader) FrameSeq() uint64
- func (jr *Reader) HasBlockIndex() bool
- func (jr *Reader) InspectBlock(n int) (BlockInfo, error)
- func (jr *Reader) Next() bool
- func (jr *Reader) SeekBlock(n int) error
- func (jr *Reader) SeekToSeq(seq uint64) error
- func (jr *Reader) SeekToTime(t time.Time) error
- func (jr *Reader) Version() byte
Constants ¶
const DeviceEntryMaxSize = 1 + 8 + 4 + 2 + 4 + 128 // = 147
DeviceEntryMaxSize is the worst-case size of a single device table entry: Source(1) + NAME(8) + ActiveFrom(4) + ProductCode(2) + 4 length-prefixed strings at max lengths (32+40+24+32 = 128 bytes + 4 length bytes).
Variables ¶
var ( Magic = [3]byte{'L', 'P', 'J'} Version = byte(0x01) Version2 = byte(0x02) CRC32cTable = crc32.MakeTable(crc32.Castagnoli) FileHeaderSize = 16 BlockTrailerLen = 10 // DeviceTableSize(2) + FrameCount(4) + Checksum(4) BlockIndexMagic = [4]byte{'L', 'P', 'J', 'I'} // v1 compressed block headers BlockHeaderLen = 12 // BaseTime(8) + CompressedLen(4) BlockHeaderLenDict = 16 // BaseTime(8) + DictLen(4) + CompressedLen(4) // Block data offsets within uncompressed blocks BlockDataOffsetV1 = 8 // frame data starts after BaseTime BlockDataOffsetV2 = 16 // frame data starts after BaseTime + BaseSeq )
Functions ¶
func PutLenPrefixedString ¶
PutLenPrefixedString writes a length-prefixed string (1-byte length + data) into buf at offset 0. Returns the number of bytes written. Truncates to 255 bytes if needed.
func ReadLenPrefixedString ¶
ReadLenPrefixedString reads a length-prefixed string from block at offset off. Returns the string, number of bytes consumed, and any error.
func UvarintSize ¶
UvarintSize returns the number of bytes needed to encode v as a uvarint.
Types ¶
type BlockInfo ¶
type BlockInfo struct {
Index int
Offset int64 // file offset
BaseTime time.Time
BaseSeq uint64 // v2 only; 0 for v1
FrameCount int
DeviceCount int
CompressedLen int // 0 for uncompressed blocks
DictLen int // 0 unless CompressionZstdDict
}
BlockInfo holds metadata about a single block for inspection.
type CompressionType ¶
type CompressionType uint8
CompressionType identifies the block compression algorithm.
const ( CompressionNone CompressionType = 0 CompressionZstd CompressionType = 1 CompressionZstdDict CompressionType = 2 )
type CorruptError ¶ added in v0.4.0
type CorruptError struct {
Path string // file path, if known
BlockIdx int // block index, -1 if header-level
Offset int64 // byte offset in file, -1 if unknown
Reason string // short description (e.g. "bad_magic", "checksum_mismatch")
Detail string // human-readable detail
Err error // underlying error, if any
}
CorruptError indicates that a journal file has invalid or corrupted data. It carries diagnostic context about where the corruption was detected.
func (*CorruptError) Error ¶ added in v0.4.0
func (e *CorruptError) Error() string
func (*CorruptError) Unwrap ¶ added in v0.4.0
func (e *CorruptError) Unwrap() error
type Device ¶
type Device struct {
Source uint8
NAME uint64
ProductCode uint16
ModelID string
SoftwareVersion string
ModelVersion string
ModelSerial string
}
Device is a NAME-to-Source binding from the journal device table, optionally carrying PGN 126996 product info.
type Reader ¶
type Reader struct {
// contains filtered or unexported fields
}
Reader reads frames from a block-based journal file.
func NewReader ¶
func NewReader(r io.ReadSeeker) (*Reader, error)
NewReader opens a journal for reading. Validates the file header.
func (*Reader) BlockCount ¶
BlockCount returns the number of complete blocks in the file.
func (*Reader) BlockDevices ¶
BlockDevices returns all device table entries for the current block.
func (*Reader) BlockDevicesAt ¶
BlockDevicesAt returns the resolved device table at the given frame index. For each source, the entry with the largest ActiveFrom <= frameIdx wins.
func (*Reader) Close ¶ added in v0.4.0
func (jr *Reader) Close()
Close releases resources held by the reader, including any in-flight prefetch goroutine and zstd decoders.
func (*Reader) Compression ¶
func (jr *Reader) Compression() CompressionType
Compression returns the compression type used by this journal file.
func (*Reader) CurrentBlock ¶
CurrentBlock returns the current block index, or -1 if before the first block.
func (*Reader) EnablePrefetch ¶ added in v0.4.0
func (jr *Reader) EnablePrefetch()
EnablePrefetch enables read-ahead for sequential iteration. After loading each block, the reader eagerly reads the next block's data from disk and (for compressed files) decompresses it in a background goroutine, so the work overlaps with frame processing in the caller.
func (*Reader) FrameSeq ¶
FrameSeq returns the sequence number of the current frame. Only valid after Next returns true. Returns 0 for v1 files (no seq info).
func (*Reader) HasBlockIndex ¶
HasBlockIndex reports whether the file had a valid block index footer. Only meaningful for compressed files.
func (*Reader) InspectBlock ¶
InspectBlock loads block n and returns its metadata without iterating frames.
func (*Reader) Next ¶
Next advances to the next frame. Returns false when done or on error. If a frame within a block is corrupt, the remaining frames in that block are skipped and iteration continues with the next block.
func (*Reader) SeekToSeq ¶
SeekToSeq positions the reader at the block containing the given sequence number via binary search on BaseSeq. Only works for v2 files. Returns an error for v1 files or if the seq is not found.
func (*Reader) SeekToTime ¶
SeekToTime finds the block containing the given timestamp via binary search and positions the reader at the start of that block.