libits_client/reception/exchange/
mobile.rs

1// Software Name: its-client
2// SPDX-FileCopyrightText: Copyright (c) 2016-2022 Orange
3// SPDX-License-Identifier: MIT License
4//
5// This software is distributed under the MIT license, see LICENSE.txt file for more details.
6//
7// Author: Frédéric GARDES <frederic.gardes@orange.com> et al.
8// Software description: This Intelligent Transportation Systems (ITS) [MQTT](https://mqtt.org/) client based on the [JSon](https://www.json.org) [ETSI](https://www.etsi.org/committee/its) specification transcription provides a ready to connect project for the mobility (connected and autonomous vehicles, road side units, vulnerable road users,...).
9extern crate integer_sqrt;
10
11use crate::reception::exchange::ReferencePosition;
12
13use self::integer_sqrt::IntegerSquareRoot;
14
15pub trait Mobile {
16    fn mobile_id(&self) -> u32;
17
18    fn position(&self) -> &ReferencePosition;
19
20    fn speed(&self) -> Option<u16>;
21
22    fn heading(&self) -> Option<u16>;
23
24    fn stopped(&self) -> bool {
25        if let Some(speed) = self.speed() {
26            return speed <= 36;
27        }
28        false
29    }
30
31    fn heading_in_degrees(&self) -> Option<f64> {
32        if let Some(heading) = self.heading() {
33            return Some(heading_in_degrees(heading));
34        }
35        None
36    }
37
38    fn speed_in_meter_per_second(&self) -> Option<f64> {
39        if let Some(speed) = self.speed() {
40            return Some(speed_in_meter_per_second(speed));
41        }
42        None
43    }
44
45    fn speed_in_kilometer_per_hour(&self) -> Option<f64> {
46        if let Some(speed) = self.speed() {
47            return Some(speed_in_kilometer_per_hour(speed));
48        }
49        None
50    }
51}
52
53pub(crate) fn heading_in_degrees(heading: u16) -> f64 {
54    heading as f64 / 10.0
55}
56
57pub(crate) fn speed_in_meter_per_second(speed: u16) -> f64 {
58    speed as f64 / 100.0
59}
60
61pub(crate) fn speed_in_kilometer_per_hour(speed: u16) -> f64 {
62    speed_in_meter_per_second(speed) * 3.6
63}
64
65pub(crate) fn speed_from_yaw_angle(x_speed: i16, y_speed: i16) -> u16 {
66    ((x_speed.abs() as u32).pow(2) + (y_speed.abs() as u32).pow(2)).integer_sqrt() as u16
67}
68
69#[cfg(test)]
70mod tests {
71    use crate::reception::exchange::mobile::{speed_from_yaw_angle, Mobile};
72    use crate::reception::exchange::reference_position::ReferencePosition;
73
74    #[test]
75    fn it_can_compute_speed() {
76        assert_eq!(speed_from_yaw_angle(1400, 500), 1486);
77        assert_eq!(speed_from_yaw_angle(-1400, 500), 1486);
78        assert_eq!(speed_from_yaw_angle(1400, -500), 1486);
79        assert_eq!(speed_from_yaw_angle(-1400, -500), 1486);
80    }
81
82    struct StoppedMobileStub {}
83
84    impl Mobile for StoppedMobileStub {
85        fn mobile_id(&self) -> u32 {
86            todo!()
87        }
88
89        fn position(&self) -> &ReferencePosition {
90            todo!()
91        }
92
93        fn speed(&self) -> Option<u16> {
94            Some(35)
95        }
96
97        fn heading(&self) -> Option<u16> {
98            Some(1800) // south
99        }
100    }
101
102    struct MovingMobileStub {}
103
104    impl Mobile for MovingMobileStub {
105        fn mobile_id(&self) -> u32 {
106            todo!()
107        }
108
109        fn position(&self) -> &ReferencePosition {
110            todo!()
111        }
112
113        fn speed(&self) -> Option<u16> {
114            Some(37)
115        }
116
117        fn heading(&self) -> Option<u16> {
118            Some(900) // east
119        }
120    }
121
122    #[test]
123    fn it_can_check_if_stopped() {
124        assert!(StoppedMobileStub {}.stopped());
125    }
126
127    #[test]
128    fn it_can_check_if_moving() {
129        assert_eq!(MovingMobileStub {}.stopped(), false);
130    }
131
132    #[test]
133    fn it_can_provide_heading_in_degrees() {
134        // south
135        assert_eq!(StoppedMobileStub {}.heading_in_degrees(), Some(180.0));
136        // north
137        assert_eq!(MovingMobileStub {}.heading_in_degrees(), Some(90.0));
138    }
139
140    #[test]
141    fn it_can_provide_speed_in_meter_per_second() {
142        // south
143        assert_eq!(StoppedMobileStub {}.speed_in_meter_per_second(), Some(0.35));
144        // north
145        assert_eq!(MovingMobileStub {}.speed_in_meter_per_second(), Some(0.37));
146    }
147
148    #[test]
149    fn it_can_provide_speed_in_kilometer_per_hour() {
150        // south
151        assert_eq!(
152            StoppedMobileStub {}.speed_in_kilometer_per_hour(),
153            Some(1.26)
154        );
155        // north
156        assert_eq!(
157            MovingMobileStub {}.speed_in_kilometer_per_hour(),
158            Some(1.332)
159        );
160    }
161}