use std::time::{SystemTime, UNIX_EPOCH};
use crate::engine::format_iso_ms;
pub const TUI_SRC: u8 = 0;
pub fn format_plain(prio: u8, pgn: u32, src: u8, dst: u8, data: &[u8]) -> String {
let ts = current_timestamp();
let mut out = String::with_capacity(ts.len() + 16 + 4 + data.len() * 3);
out.push_str(&ts);
out.push(',');
out.push_str(&prio.to_string());
out.push(',');
out.push_str(&pgn.to_string());
out.push(',');
out.push_str(&src.to_string());
out.push(',');
out.push_str(&dst.to_string());
out.push(',');
out.push_str(&data.len().to_string());
for b in data {
out.push(',');
out.push_str(&format!("{b:02x}"));
}
out
}
pub fn iso_request(dst: u8, requested_pgn: u32) -> String {
let payload = [
(requested_pgn & 0xff) as u8,
((requested_pgn >> 8) & 0xff) as u8,
((requested_pgn >> 16) & 0xff) as u8,
];
format_plain(6, 59904, TUI_SRC, dst, &payload)
}
pub fn nmea0183_filter_set(source: u8, sentence: &str, muted: bool) -> String {
let s = sentence.as_bytes();
let data = [
1u8, source,
*s.first().unwrap_or(&b' '),
*s.get(1).unwrap_or(&b' '),
*s.get(2).unwrap_or(&b' '),
u8::from(muted),
0xff,
0xff,
];
format_plain(7, 262657, TUI_SRC, 255, &data)
}
pub fn nmea0183_filter_request() -> String {
let data = [
crate::n2kd::nmea_filter::FILTER_FN_REQUEST,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
];
format_plain(7, 262657, TUI_SRC, 255, &data)
}
pub fn override_set(
src: u8,
pgn: u32,
interval_ms: u32,
mfr: Option<u16>,
industry: Option<u8>,
) -> String {
format_plain(
7,
crate::n2kd::overrides::PGN_PGN_OVERRIDE,
TUI_SRC,
255,
&override_payload(
crate::n2kd::overrides::OV_FN_SET,
src,
pgn,
interval_ms,
mfr,
industry,
),
)
}
pub fn override_delete(src: u8, pgn: u32) -> String {
format_plain(
7,
crate::n2kd::overrides::PGN_PGN_OVERRIDE,
TUI_SRC,
255,
&override_payload(
crate::n2kd::overrides::OV_FN_DELETE,
src,
pgn,
0,
None,
None,
),
)
}
pub fn override_request() -> String {
let mut data = vec![crate::n2kd::overrides::OV_FN_REQUEST];
data.resize(12, 0xff);
format_plain(
7,
crate::n2kd::overrides::PGN_PGN_OVERRIDE,
TUI_SRC,
255,
&data,
)
}
fn override_payload(
function: u8,
src: u8,
pgn: u32,
interval_ms: u32,
mfr: Option<u16>,
industry: Option<u8>,
) -> Vec<u8> {
let mut data = Vec::with_capacity(12);
data.push(function);
data.push(src);
data.extend_from_slice(&pgn.to_le_bytes()[..3]);
data.extend_from_slice(&interval_ms.to_le_bytes());
data.extend_from_slice(&mfr.unwrap_or(0xffff).to_le_bytes());
data.push(industry.unwrap_or(0xff));
data
}
fn current_timestamp() -> String {
let ms = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|d| d.as_millis() as u64)
.unwrap_or(0);
format_iso_ms(ms)
}
#[cfg(test)]
mod tests {
use super::*;
fn no_ts(line: &str) -> &str {
line.split_once(',').map(|(_, rest)| rest).unwrap_or(line)
}
#[test]
fn nmea0183_filter_set_whole_source() {
let line = nmea0183_filter_set(33, "ALL", true);
assert_eq!(no_ts(&line), "7,262657,0,255,8,01,21,41,4c,4c,01,ff,ff");
}
#[test]
fn nmea0183_filter_set_one_sentence_unmute() {
let line = nmea0183_filter_set(35, "VLW", false);
assert_eq!(no_ts(&line), "7,262657,0,255,8,01,23,56,4c,57,00,ff,ff");
}
#[test]
fn nmea0183_filter_request_is_a_request_frame() {
let line = nmea0183_filter_request();
assert_eq!(no_ts(&line), "7,262657,0,255,8,02,ff,ff,ff,ff,ff,ff,ff");
let frame = crate::engine::format::parse_plain(&line).unwrap();
assert!(crate::n2kd::nmea_filter::is_request_frame(&frame));
assert!(!crate::n2kd::nmea_filter::is_set_frame(&frame));
}
#[test]
fn iso_request_payload_is_le_pgn() {
let line = iso_request(35, 126464);
assert!(line.ends_with(",6,59904,0,35,3,00,ee,01"));
}
#[test]
fn override_set_payload_layout() {
let line = override_set(52, 130578, 1000, None, None);
assert_eq!(
no_ts(&line),
"7,262658,0,255,12,01,34,12,fe,01,e8,03,00,00,ff,ff,ff"
);
}
#[test]
fn override_delete_payload_layout() {
let line = override_delete(52, 130578);
assert_eq!(
no_ts(&line),
"7,262658,0,255,12,03,34,12,fe,01,00,00,00,00,ff,ff,ff"
);
}
#[test]
fn override_request_is_a_request_frame() {
let line = override_request();
let frame = crate::engine::format::parse_plain(&line).unwrap();
assert!(crate::n2kd::overrides::is_request_frame(&frame));
assert!(!crate::n2kd::overrides::is_set_frame(&frame));
}
}