1use crate::stream::ubx_frame;
8use crate::ubx::{CFG_VALSET, CLS_CFG};
9
10pub const TMODE_MODE: u32 = 0x2003_0001;
12pub const TMODE_POS_TYPE: u32 = 0x2003_0002;
14pub const TMODE_LAT: u32 = 0x4003_0009;
16pub const TMODE_LON: u32 = 0x4003_000A;
18pub const TMODE_HEIGHT: u32 = 0x4003_000B;
20pub const TMODE_LAT_HP: u32 = 0x2003_000C;
22pub const TMODE_LON_HP: u32 = 0x2003_000D;
24pub const TMODE_HEIGHT_HP: u32 = 0x2003_000E;
26pub const TMODE_SVIN_MIN_DUR: u32 = 0x4003_0010;
28pub const TMODE_SVIN_ACC_LIMIT: u32 = 0x4003_0011;
30
31pub const LAYER_RAM: u8 = 0x01;
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
37pub enum RxPort {
38 #[default]
40 Uart1,
41 Usb,
43}
44
45impl RxPort {
46 pub fn parse(s: &str) -> Option<Self> {
48 match s {
49 "uart1" => Some(Self::Uart1),
50 "usb" => Some(Self::Usb),
51 _ => None,
52 }
53 }
54}
55
56const RTCM_MSGOUT: [(u16, u32, u32); 6] = [
59 (1005, 0x2091_02BE, 0x2091_02C0),
60 (1074, 0x2091_035F, 0x2091_0361),
61 (1084, 0x2091_0364, 0x2091_0366),
62 (1094, 0x2091_0369, 0x2091_036B),
63 (1124, 0x2091_036E, 0x2091_0370),
64 (1230, 0x2091_0304, 0x2091_0306),
65];
66pub const NAV_PVT_MSGOUT: (u32, u32) = (0x2091_0007, 0x2091_0009);
68pub const NAV_DOP_MSGOUT: (u32, u32) = (0x2091_0039, 0x2091_003B);
70pub const NAV_SVIN_MSGOUT: (u32, u32) = (0x2091_0089, 0x2091_008B);
72pub const NAV_RELPOSNED_MSGOUT: (u32, u32) = (0x2091_008E, 0x2091_0090);
74pub const TIM_TP_MSGOUT: (u32, u32) = (0x2091_017E, 0x2091_0180);
76
77fn port_key(keys: (u32, u32), port: RxPort) -> u32 {
78 match port {
79 RxPort::Uart1 => keys.0,
80 RxPort::Usb => keys.1,
81 }
82}
83
84#[derive(Debug, Clone, Copy, PartialEq, Eq)]
86pub struct Item(pub u32, pub i64);
87
88fn value_len(key: u32) -> usize {
89 match (key >> 28) & 0x07 {
90 1 | 2 => 1,
91 3 => 2,
92 4 => 4,
93 _ => 8,
94 }
95}
96
97pub fn valset(layers: u8, items: &[Item]) -> Vec<u8> {
99 let mut p = vec![0x00, layers, 0x00, 0x00];
100 for &Item(key, value) in items {
101 p.extend_from_slice(&key.to_le_bytes());
102 p.extend_from_slice(&value.to_le_bytes()[..value_len(key)]);
103 }
104 ubx_frame(CLS_CFG, CFG_VALSET, &p)
105}
106
107fn rtcm_items(port: RxPort, rate: i64) -> impl Iterator<Item = Item> {
109 RTCM_MSGOUT
110 .into_iter()
111 .map(move |(_, uart, usb)| Item(port_key((uart, usb), port), rate))
112}
113
114fn msgout_items(port: RxPort) -> Vec<Item> {
116 let mut v: Vec<Item> = rtcm_items(port, 1).collect();
117 v.push(Item(port_key(NAV_SVIN_MSGOUT, port), 1));
118 v
119}
120
121pub fn nav_outputs(port: RxPort, base: bool, heading: bool) -> Vec<u8> {
126 let mut keys = vec![NAV_PVT_MSGOUT, NAV_DOP_MSGOUT];
127 if base {
128 keys.extend([TIM_TP_MSGOUT, NAV_SVIN_MSGOUT]);
129 }
130 if heading {
131 keys.push(NAV_RELPOSNED_MSGOUT);
132 }
133 let items: Vec<Item> = keys
134 .into_iter()
135 .map(|k| Item(port_key(k, port), 1))
136 .collect();
137 valset(LAYER_RAM, &items)
138}
139
140pub fn survey_in(port: RxPort, min_dur_s: u32, accuracy_m: f64) -> Vec<u8> {
142 let acc = (accuracy_m * 10_000.0).round().clamp(1.0, u32::MAX as f64) as i64;
143 let mut items = vec![
144 Item(TMODE_MODE, 1),
145 Item(TMODE_SVIN_MIN_DUR, min_dur_s as i64),
146 Item(TMODE_SVIN_ACC_LIMIT, acc),
147 ];
148 items.extend(msgout_items(port));
149 valset(LAYER_RAM, &items)
150}
151
152fn split_hp(value: f64, unit_per: f64) -> (i64, i64) {
155 let scaled = value * unit_per;
156 let main = scaled.trunc();
157 let hp = ((scaled - main) * 100.0).round().clamp(-99.0, 99.0);
158 (main as i64, hp as i64)
159}
160
161pub fn fixed(port: RxPort, lat_deg: f64, lon_deg: f64, h_ellipsoid_m: f64) -> Vec<u8> {
163 let (lat, lat_hp) = split_hp(lat_deg, 1e7);
164 let (lon, lon_hp) = split_hp(lon_deg, 1e7);
165 let (h, h_hp) = split_hp(h_ellipsoid_m, 100.0);
166 let mut items = vec![
167 Item(TMODE_MODE, 2),
168 Item(TMODE_POS_TYPE, 1),
169 Item(TMODE_LAT, lat),
170 Item(TMODE_LON, lon),
171 Item(TMODE_HEIGHT, h),
172 Item(TMODE_LAT_HP, lat_hp),
173 Item(TMODE_LON_HP, lon_hp),
174 Item(TMODE_HEIGHT_HP, h_hp),
175 ];
176 items.extend(msgout_items(port));
177 valset(LAYER_RAM, &items)
178}
179
180pub fn off(port: RxPort) -> Vec<u8> {
182 let mut items = vec![Item(TMODE_MODE, 0)];
183 items.extend(rtcm_items(port, 0));
184 valset(LAYER_RAM, &items)
185}
186
187pub fn poll_mon_ver() -> Vec<u8> {
189 ubx_frame(crate::ubx::CLS_MON, crate::ubx::MON_VER, &[])
190}
191
192#[cfg(test)]
193mod tests;