Skip to content

nmeasim::core::log

namespace nmeasim::core::log · Library API

Recorded sentence logs, part of the Qt-free nmeasim::core library: the format the simulator writes when recording and the third-party variants it reads back for replay.

A log is a text file with one sentence per line. The recorder (nmeasim::io::LogTransport) writes kHeaderLine, # key: value header lines made by format_header_line, and one ISO-8601-UTC-time sentence line per sentence made by format_log_line. parse_log and load_log read that format and also plain NMEA logs, Unix-time prefixes and IEC 61162-450 TAG block times, mixed freely, for simulation::ReplaySource. The format is described in docs/reference/log-format.md and chosen in ADR 0012.

Types

Type Description
LogEntry One sentence of a log, with the time at which a replay sends it.
Log A parsed log: its sentences in file order with their offsets, and the header metadata.
LogParseOptions Options for parse_log and load_log.

Summary

Enumerations

Name Description
TimingSource How the entry offsets of a log were derived, in parse_log's order of preference.

Functions

Name Description
to_string() Returns the lower-case display name of a timing source, such as sentence times.
parse_log() Parses the text of a log into its sentences and their replay offsets.
load_log() Reads a log file from disk and parses it with parse_log.
format_log_line() Formats one log line as the recorder writes it, without line terminator.
format_header_line() Formats a # key: value header line, without line terminator.

Variables

Name Description
kHeaderLine First line written by the recorder; the trailing number is the format version.

Enumerations

TimingSource

enum class TimingSource

How the entry offsets of a log were derived, in parse_log's order of preference.

Enumerator Value Description
Timestamps At least one line carried an absolute time (prefix or TAG block); offsets come from those times. Display name timestamps.
SentenceTimes No line carried an absolute time, but at least one sentence carried a UTC time field; offsets come from those fields. Display name sentence times.
FixedInterval The log had no time information; entries are spaced by LogParseOptions::fixed_interval. Display name fixed interval.

Declared in src/core/include/nmeasim/core/log/log_file.hpp:56

Functions

to_string()

const char* to_string(TimingSource source) noexcept

Returns the lower-case display name of a timing source, such as sentence times.

Parameters

Name Type Description
source TimingSource The timing source to name.

Returns const char*: A static string, valid for the lifetime of the program: timestamps, sentence times or fixed interval, and unknown for a value outside the enumeration.

Declared in src/core/include/nmeasim/core/log/log_file.hpp:74 · defined in src/core/src/log/log_file.cpp:174

parse_log()

std::optional<Log> parse_log(
    std::string_view text,
    const LogParseOptions& options,
    std::string* error)

Parses the text of a log into its sentences and their replay offsets.

The text is split into lines at line feeds and each line is trimmed, so <CR><LF> and <LF> endings both work. Each line is then handled on its own:

  • a blank line is ignored;
  • a line starting with # is a comment. # key: value, with a non-empty key without spaces, becomes a Log::header entry, and kHeaderLine sets format; other comments are ignored. Comments are not counted as skipped;
  • a line starting with \\endiskip has an IEC 61162-450 TAG block up to the next \\endiskip; its first c: parameter, a positive Unix time in seconds (with optional fraction) or in milliseconds, gives the line's time. A *hh checksum at the end of the block must match, as for a sentence, and a block without one is accepted. A line whose block is not closed or has a checksum that does not match is skipped and counted in Log::skipped_lines;
  • the sentence starts at the first $ or ! and must pass nmea0183::parse_sentence: a checksum, when present, must match, and a sentence without one is accepted. A line without $ or !, or with a rejected sentence, is skipped and counted in Log::skipped_lines;
  • when the TAG block gave no time, the text before the sentence is read as a time: an ISO 8601 time (T or space separator, optional fraction and offset, UTC when there is none) or a Unix time in seconds or milliseconds (a number above 1e11 is taken as milliseconds), optionally followed by ,, ;, :, tabs or spaces, either as the whole prefix or as its last whitespace-separated word. Any other prefix, such as [10:00:00], is ignored and the line has no time.

The offsets are then derived in this order of preference, recorded in Log::timing:

  1. TimingSource::Timestamps, when any line has an absolute time. The first time in the file is the origin; each timed entry is at its time minus the origin, and an untimed entry shares the previous entry's offset (zero before the first timed line). An offset is never lower than the previous one, so a clock stepping back holds the replay instead of reversing it.
  2. TimingSource::SentenceTimes, when any sentence carries a valid UTC time of day (RMC, GGA, GLL, ZDA, GNS, GST, GBS, GRS; see nmea0183::sentence_time). Each such sentence advances the offset by its time minus the latest sentence time seen so far; a step back of more than 12 hours is taken as crossing midnight and gets 24 hours added. Any other step back leaves the offset unchanged and does not lower the latest time, so the replay holds until the times have caught up and no time is counted twice. Dates are ignored. Sentences without a time share the offset of the previous entry.
  3. TimingSource::FixedInterval otherwise: entry i is at i times options.fixed_interval.

Parameters

Name Type Description
text std::string_view The complete log text.
options const LogParseOptions& Parsing options; only the fixed interval, which must not be negative.
error std::string* Receives the reason when the log is rejected; left unchanged on success. May be null. It is The fixed interval must not be negative for a negative options.fixed_interval, The log is empty when no line was counted as skipped (the text holds only blank and comment lines, or nothing), and No valid NMEA sentence found in the log when lines were skipped.

Returns std::optional<Log>: The log, with at least one entry, or std::nullopt when no sentence could be read or the options are invalid. Malformed lines never reject the log on their own.

See also

  • IEC 61162-450, TAG block parameter "c" and checksum.
  • docs/reference/log-format.md

Declared in src/core/include/nmeasim/core/log/log_file.hpp:163 · defined in src/core/src/log/log_file.cpp:191

load_log()

std::optional<Log> load_log(
    const std::string& path,
    const LogParseOptions& options,
    std::string* error)

Reads a log file from disk and parses it with parse_log.

The whole file is read into memory first (ADR 0012 puts multi-gigabyte logs out of scope).

Parameters

Name Type Description
path const std::string& Path of the file, in the encoding std::ifstream expects.
options const LogParseOptions& Parsing options passed on to parse_log.
error std::string* Receives the reason on failure; left unchanged on success. May be null. It is Cannot read PATH when the file cannot be opened, and PATH: REASON with the reason from parse_log when no sentence could be read.

Returns std::optional<Log>: The log, or std::nullopt on failure.

Declared in src/core/include/nmeasim/core/log/log_file.hpp:177 · defined in src/core/src/log/log_file.cpp:320

format_log_line()

std::string format_log_line(
    std::chrono::system_clock::time_point recorded_at,
    std::string_view sentence)

Formats one log line as the recorder writes it, without line terminator.

Parameters

Name Type Description
recorded_at std::chrono::system_clock::time_point The UTC wall-clock time at which the sentence was written; it is written with millisecond resolution as YYYY-MM-DDThh:mm:ss.mmmZ.
sentence std::string_view The sentence as sent, without line terminator; copied unchanged.

Returns std::string: The time, one space and the sentence, a line that parse_log reads back with recorded_at as its time.

Declared in src/core/include/nmeasim/core/log/log_file.hpp:187 · defined in src/core/src/log/log_file.cpp:340

format_header_line()

std::string format_header_line(std::string_view key, std::string_view value)

Formats a # key: value header line, without line terminator.

Parameters

Name Type Description
key std::string_view The metadata key, such as profile.
value std::string_view The metadata value.

Returns std::string: #, the key, : and the value. parse_log reads the pair back into Log::header when key is non-empty and contains no space or :; it trims whitespace from both ends of value.

Declared in src/core/include/nmeasim/core/log/log_file.hpp:197 · defined in src/core/src/log/log_file.cpp:348

Variables

kHeaderLine

std::string_view kHeaderLine{"# NMEA Simulator X log 1"}

First line written by the recorder; the trailing number is the format version.

parse_log stores the text after NMEA Simulator X log as the format header entry.

Declared in src/core/include/nmeasim/core/log/log_file.hpp:39