///|
fn checksum_status_name(status : ChecksumStatus) -> String {
match status {
PresentValid => "present_valid"
PresentInvalid => "present_invalid"
MissingChecksum => "missing"
NotChecked => "not_checked"
}
}
///|
fn severity_name(severity : Severity) -> String {
match severity {
Info => "info"
Warning => "warning"
Error => "error"
}
}
///|
fn finding_kind_name(kind : TrackFindingKind) -> String {
match kind {
NoFixFinding => "no_fix"
LowSatellitesFinding => "low_satellites"
LowFixQualityFinding => "low_fix_quality"
NonMonotonicTimeFinding => "non_monotonic_time"
LongGapFinding => "long_gap"
CoordinateJumpFinding => "coordinate_jump"
ExcessiveSpeedFinding => "excessive_speed"
SpeedMismatchFinding => "speed_mismatch"
}
}
///|
fn int_array_text(values : Array[Int]) -> String {
let mut result = ""
for index = 0; index < values.length(); index = index + 1 {
if index > 0 {
result = result + ","
}
result = result + values[index].to_string()
}
result
}
///|
fn int_array_json(values : Array[Int]) -> Json {
let items : Array[Json] = []
for value in values {
items.push(Json::number(value.to_double()))
}
Json::array(items)
}
///|
fn string_count_json(
entries : Array[StringCountEntry],
key_name : String,
) -> Json {
let items : Array[Json] = []
for entry in entries {
let object : Map[String, Json] = {
"count": Json::number(entry.count_value.to_double()),
}
object.set(key_name, Json::string(entry.key_value))
items.push(Json::object(object))
}
Json::array(items)
}
///|
pub fn render_batch_text(batch : NmeaBatch) -> String {
let summary = batch.summary_value
let mut text = "NMEA batch summary\n" +
"total: " +
summary.total_value.to_string() +
"\n" +
"successes: " +
summary.successes_value.to_string() +
"\n" +
"failures: " +
summary.failures_value.to_string() +
"\n" +
"formatters:\n"
for entry in summary.formatter_entries_value {
text = text +
"- " +
entry.key_value +
": " +
entry.count_value.to_string() +
"\n"
}
text = text + "talkers:\n"
for entry in summary.talker_entries_value {
text = text +
"- " +
entry.key_value +
": " +
entry.count_value.to_string() +
"\n"
}
text = text + "errors:\n"
for entry in summary.error_entries_value {
text = text +
"- " +
entry.key_value +
": " +
entry.count_value.to_string() +
"\n"
}
text
}
///|
pub fn render_batch_json(batch : NmeaBatch) -> String {
let summary = batch.summary_value
let checksums : Array[Json] = []
for entry in summary.checksum_entries_value {
checksums.push(
Json::object({
"status": Json::string(checksum_status_name(entry.status_value)),
"count": Json::number(entry.count_value.to_double()),
}),
)
}
Json::object({
"type": Json::string("nmea_batch"),
"total": Json::number(summary.total_value.to_double()),
"successes": Json::number(summary.successes_value.to_double()),
"failures": Json::number(summary.failures_value.to_double()),
"formatters": string_count_json(
summary.formatter_entries_value,
"formatter",
),
"talkers": string_count_json(summary.talker_entries_value, "talker"),
"checksums": Json::array(checksums),
"errors": string_count_json(summary.error_entries_value, "code"),
}).stringify()
}
///|
pub fn render_gsv_text(assembly : GsvAssembly) -> String {
let signal_id = match assembly.signal_id_value {
Some(value) => value
None => ""
}
"GSV assembly\n" +
"talker: " +
assembly.talker_value +
"\n" +
"signal_id: " +
signal_id +
"\n" +
"total_satellites: " +
assembly.total_satellites_value.to_string() +
"\n" +
"observations: " +
assembly.observations_value.length().to_string() +
"\n" +
"source_records: " +
int_array_text(assembly.source_record_indexes_value) +
"\n"
}
///|
fn optional_int_json(value : Int?) -> Json {
match value {
Some(integer) => Json::number(integer.to_double())
None => Json::null()
}
}
///|
pub fn render_gsv_json(assembly : GsvAssembly) -> String {
let observations : Array[Json] = []
for observation in assembly.observations_value {
observations.push(
Json::object({
"satellite_id": Json::string(observation.satellite_id_value),
"elevation_degrees": optional_int_json(
observation.elevation_degrees_value,
),
"azimuth_degrees": optional_int_json(observation.azimuth_degrees_value),
"snr": optional_int_json(observation.snr_value),
}),
)
}
Json::object({
"type": Json::string("gsv_assembly"),
"talker": Json::string(assembly.talker_value),
"signal_id": match assembly.signal_id_value {
Some(value) => Json::string(value)
None => Json::null()
},
"total_messages": Json::number(assembly.total_messages_value.to_double()),
"total_satellites": Json::number(
assembly.total_satellites_value.to_double(),
),
"observations": Json::array(observations),
"source_records": int_array_json(assembly.source_record_indexes_value),
}).stringify()
}
///|
fn optional_double_text(value : Double?) -> String {
match value {
Some(number) => number.to_string()
None => ""
}
}
///|
fn optional_double_json(value : Double?) -> Json {
match value {
Some(number) => Json::number(number)
None => Json::null()
}
}
///|
fn optional_decimal_json(value : ExactDecimal?) -> Json {
match value {
Some(decimal) => Json::string(decimal.to_string())
None => Json::null()
}
}
///|
fn date_text(value : UtcDate?) -> String {
match value {
Some(date) =>
date.year_value.to_string() +
"-" +
pad2(date.month_value) +
"-" +
pad2(date.day_value)
None => ""
}
}
///|
pub fn render_fused_fix_text(fix : FusedFix) -> String {
"Fused fix\n" +
"date: " +
date_text(fix.date_value) +
"\n" +
"time: " +
utc_time_wire(fix.time_value) +
"\n" +
"latitude: " +
optional_double_text(fix.latitude_value) +
"\n" +
"longitude: " +
optional_double_text(fix.longitude_value) +
"\n" +
"usable: " +
fix.usable_value.to_string() +
"\n" +
"diagnostics: " +
fix.diagnostics_value.length().to_string() +
"\n" +
"source_records: " +
int_array_text(fix.source_record_indexes_value) +
"\n"
}
///|
pub fn render_fused_fix_json(fix : FusedFix) -> String {
let provenance : Array[Json] = []
for item in fix.provenance_value {
provenance.push(
Json::object({
"field": Json::string(item.field_value),
"source": Json::string(
match item.source_value {
GgaSource => "GGA"
RmcSource => "RMC"
VtgSource => "VTG"
},
),
"record_index": Json::number(item.record_index_value.to_double()),
}),
)
}
Json::object({
"type": Json::string("fused_fix"),
"date": if fix.date_value is Some(_) {
Json::string(date_text(fix.date_value))
} else {
Json::null()
},
"time": Json::string(utc_time_wire(fix.time_value)),
"latitude": optional_double_json(fix.latitude_value),
"longitude": optional_double_json(fix.longitude_value),
"altitude": optional_decimal_json(fix.altitude_value),
"speed_knots": optional_decimal_json(fix.speed_knots_value),
"course": optional_decimal_json(fix.course_value),
"usable": Json::boolean(fix.usable_value),
"provenance": Json::array(provenance),
"source_records": int_array_json(fix.source_record_indexes_value),
}).stringify()
}
///|
pub fn render_track_quality_text(report : TrackQualityReport) -> String {
let mut text = "Track quality report\nfindings: " +
report.findings_value.length().to_string() +
"\n"
for finding in report.findings_value {
text = text +
"- " +
finding_kind_name(finding.kind_value) +
" [" +
severity_name(finding.severity_value) +
"]: " +
finding.diagnostic_value.message() +
"\n"
}
text
}
///|
pub fn render_track_quality_json(report : TrackQualityReport) -> String {
let findings : Array[Json] = []
for finding in report.findings_value {
findings.push(
Json::object({
"kind": Json::string(finding_kind_name(finding.kind_value)),
"severity": Json::string(severity_name(finding.severity_value)),
"point_index": optional_int_json(finding.point_index_value),
"segment_index": optional_int_json(finding.segment_index_value),
"code": Json::string(finding.diagnostic_value.code()),
"message": Json::string(finding.diagnostic_value.message()),
}),
)
}
Json::object({
"type": Json::string("track_quality"),
"finding_count": Json::number(report.findings_value.length().to_double()),
"findings": Json::array(findings),
}).stringify()
}