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