nmeais

package
v0.0.0-...-61ccda9 Latest Latest
Warning

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

Go to latest
Published: Feb 21, 2022 License: AGPL-3.0 Imports: 4 Imported by: 2

Documentation

Overview

Package nmeais is a library for quickly parsing AIS messages from network packets, and merging streams from multiple sources.

Index

Constants

View Source
const (
	ChecksumPassed = ChecksumResult('t') // The sentence has a chacksum that matches
	ChecksumFailed = ChecksumResult('f') // The sentence has a checksum that doesn't match
	ChecksumAbsent = ChecksumResult('N') // The sentence has no checksum
)

The three valid values of ChecksumResult

Variables

This section is empty.

Functions

func FirstSentenceInBuffer

func FirstSentenceInBuffer(incomplete, bufferSlice []byte) (copiedSentence []byte, next int)

FirstSentenceInBuffer extracts the text of what looks like the first AIS NMEA0183 sentence in an (IO) buffer. `next` is the index of the first byte that wasn't copied, it is len(bufferSlice) if the entire input was used. Otherwise it's ensured that `copiedSentence“ ends with a "\r\n" line delimiter. Bytes before the first '!' are considered noise and skipped. This newline fixing and '!'-seeking means that `next` might be different from len(copiedSentence)-len(incomplete). The sentence is always copied so that the input buffer can be reused immediately. If the buffer doesn't contain a complete sentence, a copy of the input is returned as `copiedSentence` and `next` is -1. If the buffer doesn't even contain the start of a sentence, `"",-1` is returned to not create an edge case where `used` is positive but `copiedSentence` is empty. `incomplete` is a receptacle for that copy: if it's non-empty it's prepended to `copiedSentence` and the search for a starting '!' is dropped.

Types

type ChecksumResult

type ChecksumResult byte

ChecksumResult says whether a sentence has a checksum and if it matches

type DuplicateTester

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

DuplicateTester is a tool for filtering out messages received from multiple AIS ssources. It does this by comparing new message against all recently checked messages. This means identical messages from the same source will also be filtered. What's considered recent is controlled by a parmater to the constructor, and a package might be comparaed against all received within the double of that. It uses internal locking, which makes it safe to share instances between goroutines.

func NewDuplicateTester

func NewDuplicateTester(minKeepAlive time.Duration) *DuplicateTester

NewDuplicateTester creates a new DuplicateTester and starts a goroutine that periodically removes old messages.

input:

minKeepAlive - How long the messages should at least be kept in the map
			   E.g. 5 seconds -> a new message is tested for duplicates
			   among all the messages recieved within the last 5 to 10 seconds

func (*DuplicateTester) Close

func (dt *DuplicateTester) Close()

Close tells the internal goroutine to stop.

func (*DuplicateTester) IsDuplicate

func (dt *DuplicateTester) IsDuplicate(msg *Message) bool

IsDuplicate compares msg against all messages passed to IsDuplicate within the last 1x to 20 minKeepAlive.

Input: msg - Only the raw text of the first sentence is used. (for speed and simplicity) Output: exists - true if the message is previously known

  • false if the message is new

type Message

type Message struct {
	SourceName string // alias of the AIS listener the message came from
	// contains filtered or unexported fields
}

Message is an AIS message stored as decoded NMEA 0183 sentences. It also stores the alias of the source it came from and the time the last part was received.

func (*Message) ArmoredPayload

func (m *Message) ArmoredPayload() string

ArmoredPayload joins together the payload part of the sentences the message was parsed from.

func (*Message) DearmoredPayload

func (m *Message) DearmoredPayload() []byte

DearmoredPayload undoes the siz-bit ASCII encoding of the payload. This function is completely untested.

func (*Message) Sentences

func (m *Message) Sentences() []Sentence

Sentences returns a slice containing the sentences the message is made up of.

func (*Message) Text

func (m *Message) Text() string

Text joins together the sentences that the message was created from. A newline is inserted after every sentence.

func (*Message) Type

func (m *Message) Type() uint8

Type de-armors only the first byte of the payload. This is kinda too high level for this package, but avoids de-armoring the whole payload for message types that won't be decoded further.

type MessageAssembler

type MessageAssembler struct {
	MaxMessageTimespan  time.Duration
	MaxSentencesBetween uint64

	SourceName string
	// contains filtered or unexported fields
}

MessageAssembler takes in sentences out of order and returns a Message if the sentence completes one. Sentences can come out of order, as can messages with different SMID. Single-sentence messages pass through without affecting multi-sentence messages.

func NewMessageAssembler

func NewMessageAssembler(maxSentencesBetween uint, maxMessageTimespan time.Duration, sourceName string) MessageAssembler

NewMessageAssembler creates a new MessageAssembler. There's nothing happening behind the scenes, so a value is returned, but the struct is quite big so it shouldn't be moved around too much.

  • maxSentencesBetwee: The maximum number of sentences that might be received between

two of the same message. Scales with traffic and the number of sentences in a message.

  • maxMessageTimespan: The maximum duration between when the first and last sentence

of a message was received. Doesn't scale with traffic or the number of sentences in a message, but becomes relevant if the connection goes down or traffic slows to a crawl.

func (*MessageAssembler) Accept

func (ma *MessageAssembler) Accept(s Sentence) (*Message, error)

Accept takes in a sentence, returns a Message if it completes one, an error if it's invalid or aborts an incomplete one, or neither. Sentences that have failed the checksum are checked against incomplete messages, and if it matches the message is aborted.

type Sentence

type Sentence struct {
	Identifier [5]byte // "AIVDM" and the like
	Parts      uint8   // starts at 1
	PartIndex  uint8   // starts at 0
	SMID       uint8   // Sequential message ID, 10 when missing (10 makes indexing based on it easy)
	HasSMID    bool    // Is false if SMID field is empty
	Channel    byte    // '*' if empty

	Checksum ChecksumResult

	Received time.Time
	Text     string // everything plus "\r\n"
	// contains filtered or unexported fields
}

Sentence contains the values parsed from a NMEA 0183 sentence assumed to encapsulate an AIS message, and the sentence itself. Saves all possibly interesting information; some of them are never actually used for anything. There are many fields, but most of them are small: Text takes up nearly half the size.

func ParseSentence

func ParseSentence(b []byte, received time.Time) (Sentence, error)

ParseSentence extracts the fields out of an assumed NMEA0183 AIS-containing sentence. It does the minimum possible validation for the sentence to be useful: All fields (except Received) might contain invalid values, call .Validate() to check them. The checksum is evaluated if present, but not even a checksum mismatch is an error; the result is stored in .Checksum. For speed, ParseSentence assumes the correct width of fixed-width fields.

func (Sentence) Payload

func (s Sentence) Payload() (string, uint8)

Payload returns a view of the ASCII-armored payload plus how many bits of the last character should be ignored.

func (Sentence) Validate

func (s Sentence) Validate(parserErr error) error

Validate performs many checks that ParseSentence doesn't.

Jump to

Keyboard shortcuts

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