unbounded_gpsd/types.rs
1//! Types employed in the GPSD API.
2//!
3//! For further information (or where documentation may be sparse), refer to the
4//! GPSD API documentation [here](http://www.catb.org/gpsd/gpsd_json.html).
5use chrono::*;
6
7fn serde_true() -> bool { true }
8fn serde_false() -> bool { false }
9
10#[derive(Serialize, Deserialize, Debug)]
11#[serde(untagged)]
12/// A time-position-velocity (TPV) report.
13///
14/// The API here splits the TPV object that GPSD sends into various variants, in
15/// a bid to classify common responses so that you don't have to do this
16/// yourself. See the variant documentation for details.
17///
18/// Basically, the aim here is to reduce the amount of Option unwrapping
19/// you have to do, as gpsd specifies that all these fields are optional.
20///
21/// The field documentation is exactly the same across variants; it may be omitted
22/// for brevity.
23pub enum TpvResponse {
24 /// 3D GPS fix, with speed and climb data.
25 Fix3D {
26 /// Name of originating device.
27 device: Option<String>,
28 /// Timestamp.
29 time: DateTime<Utc>,
30 /// Fix type: 0 = unknown, 1 = no fix, 2 = 2D fix, 3 = 3D fix.
31 mode: u8,
32 /// Estimated timestamp error (seconds, 95% confidence).
33 #[serde(rename = "ept")]
34 time_err: f64,
35 /// Latitude in degrees: +/- signifies North/South. Present when mode is 2 or 3.
36 lat: f64,
37 /// Latitude error estimate in meters, 95% confidence. Present if mode
38 /// is 2 or 3 and DOPs can be calculated from the satellite view.
39 #[serde(rename = "epy")]
40 lat_err: Option<f64>,
41 /// Longitude in degrees: +/- signifies East/West. Present when mode is 2 or 3.
42 lon: f64,
43 /// Longitude error estimate in meters, 95% confidence. Present if mode
44 /// is 2 or 3 and DOPs can be calculated from the satellite view.
45 #[serde(rename = "epx")]
46 lon_err: Option<f64>,
47 /// Altitude in meters. Present if mode is 3.
48 alt: f64,
49 /// Estimated vertical error in meters, 95% confidence. Present if mode
50 /// is 3 and DOPs can be calculated from the satellite view.
51 #[serde(rename = "epv")]
52 alt_err: Option<f64>,
53 /// Course over ground, degrees from true north.
54 track: Option<f64>,
55 /// Direction error estimate in degrees, 95% confidence.
56 #[serde(rename = "epd")]
57 track_err: Option<f64>,
58 /// Speed over ground, meters per second.
59 speed: f64,
60 /// Speed error estinmate in meters/sec, 95% confidence.
61 #[serde(rename = "eps")]
62 speed_err: Option<f64>,
63 /// Climb (positive) or sink (negative) rate, meters per second.
64 climb: f64,
65 /// Climb/sink error estimate in meters/sec, 95% confidence.
66 #[serde(rename = "epc")]
67 climb_err: Option<f64>
68 },
69 /// 2D GPS fix, with speed data.
70 Fix2D {
71 /// Name of originating device.
72 device: Option<String>,
73 /// Timestamp.
74 time: DateTime<Utc>,
75 /// Fix type: 0 = unknown, 1 = no fix, 2 = 2D fix, 3 = 3D fix.
76 mode: u8,
77 /// Estimated timestamp error (seconds, 95% confidence).
78 #[serde(rename = "ept")]
79 time_err: f64,
80 /// Latitude in degrees: +/- signifies North/South. Present when mode is 2 or 3.
81 lat: f64,
82 #[serde(rename = "epy")]
83 lat_err: Option<f64>,
84 /// Longitude in degrees: +/- signifies East/West. Present when mode is 2 or 3.
85 lon: f64,
86 #[serde(rename = "epx")]
87 lon_err: Option<f64>,
88 /// Course over ground, degrees from true north.
89 track: Option<f64>,
90 #[serde(rename = "epd")]
91 track_err: Option<f64>,
92 /// Speed over ground, meters per second.
93 speed: f64,
94 #[serde(rename = "eps")]
95 speed_err: Option<f64>,
96 },
97 /// Fix with lat/lon, and an unknown smattering of fields.
98 /// You'll get this variant if a fix is obtained (lat/lon available), but GPSD
99 /// otherwise sent data that doesn't exactly fit into any of the categories above.
100 ///
101 /// If you are getting this variant, we'd greatly appreciate it if you filed an issue,
102 /// so we can see what sort of strange data your GPSD is sending!
103 LatLonOnly {
104 /// Name of originating device.
105 device: Option<String>,
106 /// Timestamp.
107 time: DateTime<Utc>,
108 /// Fix type: 0 = unknown, 1 = no fix, 2 = 2D fix, 3 = 3D fix.
109 mode: u8,
110 /// Estimated timestamp error (seconds, 95% confidence).
111 #[serde(rename = "ept")]
112 time_err: f64,
113 /// Latitude in degrees: +/- signifies North/South. Present when mode is 2 or 3.
114 lat: f64,
115 #[serde(rename = "epy")]
116 lat_err: Option<f64>,
117 /// Longitude in degrees: +/- signifies East/West. Present when mode is 2 or 3.
118 lon: f64,
119 #[serde(rename = "epx")]
120 lon_err: Option<f64>,
121 /// Altitude in meters. Present if mode is 3.
122 alt: Option<f64>,
123 #[serde(rename = "epv")]
124 alt_err: Option<f64>,
125 /// Course over ground, degrees from true north.
126 track: Option<f64>,
127 #[serde(rename = "epd")]
128 track_err: Option<f64>,
129 /// Speed over ground, meters per second.
130 speed: Option<f64>,
131 #[serde(rename = "eps")]
132 speed_err: Option<f64>,
133 /// Climb (positive) or sink (negative) rate, meters per second.
134 climb: Option<f64>,
135 #[serde(rename = "epc")]
136 climb_err: Option<f64>,
137 },
138 /// No fix.
139 NoFix {
140 /// Name of originating device.
141 device: Option<String>,
142 /// Timestamp.
143 time: DateTime<Utc>,
144 /// Fix type: 0 = unknown, 1 = no fix, 2 = 2D fix, 3 = 3D fix.
145 mode: u8
146 },
147 /// Possibly no useful data whatsoever.
148 Nothing {
149 /// Name of originating device.
150 device: Option<String>,
151 /// Timestamp.
152 time: Option<DateTime<Utc>>,
153 /// Fix type: 0 = unknown, 1 = no fix, 2 = 2D fix, 3 = 3D fix.
154 mode: Option<u8>
155 },
156 /// Something else! You'll get this variant if GPSD sent data that doesn't
157 /// exactly fit into any of the categories above.
158 ///
159 /// If you are getting this variant, we'd greatly appreciate it if you filed an issue,
160 /// so we can see what sort of strange data your GPSD is sending!
161 Dustbin {
162 device: Option<String>,
163 time: Option<DateTime<Utc>>,
164 mode: Option<u8>,
165 #[serde(rename = "ept")]
166 time_err: Option<f64>,
167 lat: Option<f64>,
168 #[serde(rename = "epy")]
169 lat_err: Option<f64>,
170 lon: Option<f64>,
171 #[serde(rename = "epx")]
172 lon_err: Option<f64>,
173 alt: Option<f64>,
174 #[serde(rename = "epv")]
175 alt_err: Option<f64>,
176 track: Option<f64>,
177 #[serde(rename = "epd")]
178 track_err: Option<f64>,
179 speed: Option<f64>,
180 #[serde(rename = "eps")]
181 speed_err: Option<f64>,
182 climb: Option<f64>,
183 #[serde(rename = "epc")]
184 climb_err: Option<f64>,
185 },
186}
187impl Default for TpvResponse {
188 fn default() -> TpvResponse {
189 TpvResponse::Nothing { device: None, time: None, mode: None }
190 }
191}
192/// A single satellite.
193#[derive(Serialize, Deserialize, Debug)]
194pub struct SatelliteObject {
195 #[serde(rename = "PRN")]
196 /// PRN ID of the satellite. 1-63 are GNSS satellites, 64-96 are GLONASS
197 /// satellites, 100-164 are SBAS satellites
198 pub prn: u16,
199 #[serde(rename = "az")]
200 /// Azimuth, degrees from true north.
201 pub azimuth: f32,
202 #[serde(rename = "el")]
203 /// Elevation in degrees.
204 pub elevation: f32,
205 #[serde(rename = "ss")]
206 /// Signal strength in dB.
207 pub signal_strength: f32,
208 /// Used in current solution? (SBAS/WAAS/EGNOS satellites may be flagged
209 /// used if the solution has corrections from them, but not all drivers make
210 /// this information available.)
211 pub used: bool
212}
213#[derive(Serialize, Deserialize, Debug)]
214/// A sky view report (SKY) of GPS satellite positions.
215///
216/// If there is no GPS device available, or no skyview has been reported yet,
217/// all fields will be blank.
218///
219/// # Dilutions of precision
220///
221/// Fields ending `dop` denote dilutions of precision. These are dimensionless
222/// factors that should be multiplied by a base UERE to get an error estimate.
223///
224/// Many devices compute dilution of precision factors but do not include them
225/// in their reports. Many that do report DOPs report only HDOP, two-dimensional
226/// circular error. gpsd always passes through whatever the device actually
227/// reports, then attempts to fill in other DOPs by calculating the appropriate
228/// determinants in a covariance matrix based on the satellite view. DOPs may be
229/// missing if some of these determinants are singular. It can even happen that
230/// the device reports an error estimate in meters when the corresponding DOP is
231/// unavailable; some devices use more sophisticated error modeling than the
232/// covariance calculation.
233pub struct SkyResponse {
234 /// Name of originating device.
235 pub device: Option<String>,
236 /// Timestamp.
237 pub time: Option<DateTime<Utc>>,
238 /// Longitudinal d.o.p.
239 pub xdop: Option<f32>,
240 /// Latitutinal d.o.p.
241 pub ydop: Option<f32>,
242 /// Altitude d.o.p.
243 pub vdop: Option<f32>,
244 /// Time d.o.p.
245 pub tdop: Option<f32>,
246 /// Horizontal d.o.p.
247 pub hdop: Option<f32>,
248 /// Spherical d.o.p.
249 pub pdop: Option<f32>,
250 /// Hyperspherical d.o.p.
251 pub gdop: Option<f32>,
252 /// Satellites in skyview.
253 pub satellites: Vec<SatelliteObject>
254}
255#[derive(Serialize, Deserialize, Debug)]
256#[serde(untagged)]
257/// Information about a device known to gpsd.
258///
259/// The API splits the DEVICE object into three variants:
260/// - `ActiveSeenPackets`: the device is active, and we've seen packets from it.
261/// - `Active`: the device is active, but we haven't seen any packets.
262/// - `Inactive`: the device is inactive.
263///
264/// Basically, the aim here is to reduce the amount of Option unwrapping
265/// you have to do, as gpsd specifies that all these fields are optional.
266pub enum DeviceObject {
267 ActiveSeenPackets {
268 /// Name the device for which the control bits are being reported, or
269 /// for which they are to be applied. This attribute may be omitted only
270 /// when there is exactly one subscribed channel
271 path: Option<String>,
272 /// Time the device was activated as an ISO8601 timestamp. If the device
273 /// is inactive this attribute is absent.
274 activated: DateTime<Utc>,
275 /// Bit vector of property flags. Currently defined flags are: describe
276 /// packet types seen so far (GPS, RTCM2, RTCM3, AIS). Won't be reported
277 /// if empty, e.g. before gpsd has seen identifiable packets from the
278 /// device.
279 ///
280 /// # Flags
281 ///
282 /// - 0x01: GPS data seen
283 /// - 0x02: RTCM2 data seen
284 /// - 0x04: RTCM3 data seen
285 /// - 0x08: AIS data seen
286 ///
287 /// Yes, I know manual bitflags suck. I'll fix it one day if you bug me.
288 flags: u8,
289 /// GPSD's name for the device driver type. Won't be reported before
290 /// gpsd has seen identifiable packets from the device.
291 driver: String,
292 /// Whatever version information the device returned.
293 subtype: Option<String>,
294 /// Device speed in bits per second.
295 bps: Option<u32>,
296 /// N, O or E for no parity, odd, or even.
297 parity: Option<String>,
298 /// Stop bits (1 or 2).
299 stopbits: Option<String>,
300 /// 0 means NMEA mode and 1 means alternate mode (binary if it has one,
301 /// for SiRF and Evermore chipsets in particular). Attempting to set
302 /// this mode on a non-GPS device will yield an error.
303 native: Option<u8>,
304 /// Device cycle time in seconds.
305 cycle: Option<f32>,
306 /// Device minimum cycle time in seconds. Reported from ?DEVICE when
307 /// (and only when) the rate is switchable. It is read-only and not
308 /// settable.
309 minicycle: Option<f32>
310 },
311 Active {
312 path: Option<String>,
313 activated: DateTime<Utc>,
314 subtype: Option<String>,
315 bps: Option<u32>,
316 parity: Option<String>,
317 stopbits: Option<String>,
318 native: Option<u8>,
319 cycle: Option<f32>,
320 minicycle: Option<f32>
321 },
322 Inactive {
323 path: Option<String>
324 }
325}
326#[derive(Serialize, Deserialize, Debug)]
327/// Information about watcher mode parameters.
328pub struct WatchObject {
329 #[serde(default = "serde_true")]
330 /// Enable (true) or disable (false) watcher mode. Default is true.
331 pub enable: bool,
332 #[serde(default = "serde_false")]
333 /// Enable (true) or disable (false) dumping of JSON reports. Default is
334 /// false.
335 pub json: bool,
336 #[serde(default = "serde_false")]
337 /// Enable (true) or disable (false) dumping of binary packets as
338 /// pseudo-NMEA. Default is false.
339 pub nmea: bool,
340 /// Controls 'raw' mode. When this attribute is set to 1 for a channel, gpsd
341 /// reports the unprocessed NMEA or AIVDM data stream from whatever device
342 /// is attached. Binary GPS packets are hex-dumped. RTCM2 and RTCM3 packets
343 /// are not dumped in raw mode. When this attribute is set to 2 for a
344 /// channel that processes binary data, gpsd reports the received data
345 /// verbatim without hex-dumping.
346 pub raw: Option<u32>,
347 #[serde(default = "serde_false")]
348 /// If true, apply scaling divisors to output before dumping; default is
349 /// false.
350 pub scaled: bool,
351 #[serde(default = "serde_false")]
352 /// If true, aggregate AIS type24 sentence parts. If false, report each part
353 /// as a separate JSON object, leaving the client to match MMSIs and
354 /// aggregate. Default is false. Applies only to AIS reports.
355 pub split24: bool,
356 #[serde(default = "serde_false")]
357 /// If true, emit the TOFF JSON message on each cycle and a PPS JSON message
358 /// when the device issues 1PPS. Default is false.
359 pub pps: bool,
360 /// If present, enable watching only of the specified device rather than all
361 /// devices. Useful with raw and NMEA modes in which device responses aren't
362 /// tagged. Has no effect when used with enable:false.
363 pub device: Option<String>,
364 /// URL of the remote daemon reporting the watch set. If empty, this is a
365 /// WATCH response from the local daemon.
366 pub remote: Option<String>
367}
368impl Default for WatchObject {
369 fn default() -> Self {
370 Self {
371 enable: true,
372 json: false,
373 nmea: false,
374 raw: None,
375 scaled: false,
376 split24: false,
377 pps: false,
378 device: None,
379 remote: None
380 }
381 }
382}
383#[derive(Serialize, Deserialize, Debug)]
384#[serde(tag = "class")]
385/// A response from GPSD.
386///
387/// For single-struct variants, the documentation on the struct usually has
388/// more information.
389pub enum Response {
390 #[serde(rename = "TPV")]
391 Tpv(TpvResponse),
392 #[serde(rename = "SKY")]
393 Sky(SkyResponse),
394 #[serde(rename = "POLL")]
395 /// Data from the last-seen fixes on all active GPS devices.
396 Poll {
397 time: DateTime<Utc>,
398 /// Count of active devices.
399 active: u32,
400 tpv: Vec<TpvResponse>,
401 sky: Vec<SkyResponse>
402 },
403 #[serde(rename = "DEVICE")]
404 Device(DeviceObject),
405 #[serde(rename = "DEVICES")]
406 Devices {
407 devices: Vec<DeviceObject>,
408 remote: Option<String>
409 },
410 #[serde(rename = "WATCH")]
411 Watch(WatchObject),
412 #[serde(rename = "VERSION")]
413 Version {
414 release: String,
415 rev: String,
416 proto_major: u32,
417 proto_minor: u32,
418 remote: Option<String>
419 },
420 #[serde(rename = "ERROR")]
421 Error {
422 message: String
423 },
424 Raw(String)
425}