1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
//! MT(1) Raw Data Serial Out Packet Format
use crate::ParseError;
/// MT Serial Out Packet Format.
#[derive(Clone, Debug, PartialEq)]
pub struct MtStructured {
/// Header, should be `MT1`.
pub header: String,
/// UUU - Three character MT-RX configurable ID – by default this is `001`.
pub id: String,
/// NNN - Three decimal digit cycling packet sequence number from `000` to `511`. This sequence number
// increments after each new test or distress message is received. After `511` the sequence cycles to `000`
// and begins again.
pub sequence_number: usize,
/// T - Single character message type 'T' or 'A' (test or distress alert)
pub message_type: char,
/// F - Single character format flag `S` or `L` (short or long) – this relates to the 406 beacon transmission specification.
pub format_flag: char,
/// 15 character hex code used to define beacon owner and beacon capabilities as per the 406 beacon specification.
pub beacon: [u8; 15],
/// SS - Two character signal strength indication – `00` if not used.
pub signal_strength: [char; 2],
/// 11 - Two decimal character latitude degrees.
pub lat_degrees: u8,
/// 22 - Two decimal character latitude minutes.
pub lat_minutes: u8,
/// 33 - Two decimal character latitude seconds.
pub lat_seconds: u8,
/// N - is `N` or `S`.
pub n: char,
/// 444 - Three decimal character longitude degrees.
pub long_degrees: u16,
/// 22 - Two decimal character longitude minutes.
pub long_minutes: u8,
/// 55 - Two decimal character longitude seconds.
pub long_seconds: u8,
/// W - is `W` or `E`.
pub w: char,
/// YYYY - Four character checksum (calculated from M – the first character).
/// If all location characters are '-' then there is no location information available.
pub checksum: u16,
}
impl MtStructured {
/// Returns whether `message` is a valid MT(1) message.
///
/// ## Examples
/// ```
/// use wte_mt_rx_parser::mt_structured::MtStructured;
/// println!("is it MT1? {}", MtStructured::is_mt("MT1001000AL400C592753572B323433212S1723756E4706"));
/// ```
pub fn is_mt(message: &str) -> bool {
return message.starts_with("MT1");
}
/// Tries to parse a "MT Serial Out Packet Format" `message`.
///
/// ## Notes
/// - Checksum is not calculated here.
///
/// ## Examples
/// ```
/// use wte_mt_rx_parser::mt_structured::MtStructured;
/// let parsed = MtStructured::parse("MT1001000AL400C592753572B323433212S1723756E4706").unwrap();
/// // ...
/// ```
///
/// ## Message format
/// Data provided should be in the following format:
/// - `MT1UUUNNNTFHHHHHHHHHHHHHHHSS112233N4445566WYYYY`
pub fn parse(message: &str) -> Result<MtStructured, ParseError> {
// 012 345 678 9 0 123456789012345 67 89 01 23 4 567 89 01 2 3456
// MT1 UUU NNN T F HHHHHHHHHHHHHHH SS 11 22 33 N 444 55 66 W YYYY
const MT1_LEN: usize = 47;
if message.len() != MT1_LEN {
return Err(ParseError::SizeNotMatch {
expected: MT1_LEN,
found: message.len(),
});
}
let header = message[0..3].to_string();
let id = message[3..6].to_string();
let sequence_number = message[6..9].parse::<usize>()?;
let message_type = message.as_bytes()[9] as char;
let format_flag = message.as_bytes()[10] as char;
let beacon: [u8; 15] = message[11..26].as_bytes().try_into().unwrap();
let signal_strength = [
message.as_bytes()[26] as char,
message.as_bytes()[27] as char,
];
let lat_degrees = message[28..30].parse::<u8>()?;
let lat_minutes = message[30..32].parse::<u8>()?;
let lat_seconds = message[32..34].parse::<u8>()?;
let n = message.as_bytes()[34] as char;
let long_degrees = message[35..38].parse::<u16>()?;
let long_minutes = message[38..40].parse::<u8>()?;
let long_seconds = message[40..42].parse::<u8>()?;
let w = message.as_bytes()[42] as char;
let checksum = u16::from_str_radix(&message[43..47], 16)?;
// TODO: calculate checksum here?
let result = MtStructured {
header,
id,
sequence_number,
message_type,
format_flag,
beacon,
signal_strength,
lat_degrees,
lat_minutes,
lat_seconds,
n,
long_degrees,
long_minutes,
long_seconds,
w,
checksum,
};
Ok(result)
}
}