diff --git a/src/whisker/gps.rs b/src/whisker/gps.rs index d44f9ad4a8a376ab6e506a2ab5e680f0eaca5d2e..e0ee62fbc13928d92d452f9850290ee6ca0d5e4e 100644 --- a/src/whisker/gps.rs +++ b/src/whisker/gps.rs @@ -33,8 +33,14 @@ impl Gps { let longitude = longitude.clamp(-179.999, 179.999); let longitude = (longitude * ((1u32 << 31) as f64) / 180.0) as i32; - let heading = heading.clamp(0.0, 359.999); - let heading = (heading * 128.0 / 360.0) as u8; + let heading = if heading >= 0.0 { + heading % 360.0 + } else { + // slightly hacky no-std floor + let factor = (-heading / 360.0) as u32 as f64; + 360.0 * (1.0 + factor) + heading + }; + let heading = round(heading * 128.0 / 180.0) as u8; Self { latitude, @@ -55,7 +61,7 @@ impl Gps { } pub fn heading(&self) -> f64 { - self.heading as f64 / 128.0 * 360.0 + self.heading as f64 / 128.0 * 180.0 } pub fn encode<'a>(&self, buf: &'a mut [u8]) -> Option<&'a [u8]> { @@ -93,3 +99,40 @@ impl Gps { }) } } + +// no-std and it's not worth bringing in a library for this +fn round(v: f64) -> u32 { + let floor = v as u32; + let delta = v - floor as f64; + if delta <= 0.5 { + floor + } else { + floor + 1 + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn heading_is_correct() { + let gps = Gps::new(0.0, 0.0, f16::from_f32(0.0), 0, 359.0, f16::from_f32(0.0)); + assert_eq!(gps.heading, 255); + + let gps = Gps::new(0.0, 0.0, f16::from_f32(0.0), 0, 0.0, f16::from_f32(0.0)); + assert_eq!(gps.heading, 0); + + let gps = Gps::new(0.0, 0.0, f16::from_f32(0.0), 0, -20.0, f16::from_f32(0.0)); + assert_eq!(gps.heading, 242); + + let gps = Gps::new(0.0, 0.0, f16::from_f32(0.0), 0, 719.0, f16::from_f32(0.0)); + assert_eq!(gps.heading, 255); + + let gps = Gps::new(0.0, 0.0, f16::from_f32(0.0), 0, 180.0, f16::from_f32(0.0)); + assert_eq!(gps.heading, 128); + + let gps = Gps::new(0.0, 0.0, f16::from_f32(0.0), 0, 540.0, f16::from_f32(0.0)); + assert_eq!(gps.heading, 128); + } +} diff --git a/src/whisker/mod.rs b/src/whisker/mod.rs index d08f9c380e98afba638a6c91e69cf70a3451fe46..6a63f96a4b2d37ff8a097597a64eff9820acd489 100644 --- a/src/whisker/mod.rs +++ b/src/whisker/mod.rs @@ -248,7 +248,7 @@ mod tests { assert_eq!(89.99899999704212, gps.latitude()); assert_eq!(-179.9989999551326, gps.longitude()); - assert_eq!(120.9375, gps.heading()); + assert_eq!(123.75, gps.heading()); } #[test] @@ -258,11 +258,58 @@ mod tests { 23.45, f16::from_f32(45.02), 24, - 360.0, + 359.0, f16::from_f32(12.3), ); - assert_eq!(357.1875, gps.heading()); + assert_eq!(358.59375, gps.heading()); + + let gps = Gps::new( + 4.0, + 23.45, + f16::from_f32(45.02), + 24, + 957.47, + f16::from_f32(12.3), + ); + + assert_eq!(957.65625 - 360.0 * 2.0, gps.heading()); + } + + #[test] + fn gps_min_heading() { + let gps = Gps::new( + 4.0, + 23.45, + f16::from_f32(45.02), + 24, + 0.0, + f16::from_f32(12.3), + ); + + assert_eq!(0.0, gps.heading()); + + let gps = Gps::new( + 4.0, + 23.45, + f16::from_f32(45.02), + 24, + -22.0, + f16::from_f32(12.3), + ); + + assert_eq!(337.5, gps.heading()); + + let gps = Gps::new( + 4.0, + 23.45, + f16::from_f32(45.02), + 24, + -1206.0, + f16::from_f32(12.3), + ); + + assert_eq!(233.4375, gps.heading()); } #[test]