tello/
drone_state.rs

1use super::PackageData;
2use byteorder::{LittleEndian, ReadBytesExt};
3use std::io::{BufRead, Cursor, Seek, SeekFrom};
4
5/// Represents the last received meta data from the drone
6///
7#[derive(Debug, Clone, Default)]
8pub struct DroneMeta {
9    flight: Option<FlightData>,
10    wifi: Option<WifiInfo>,
11    light: Option<LightInfo>,
12}
13
14impl DroneMeta {
15    /// returns an option of the FlightData.
16    ///
17    /// this will always represent the last state event if the network connection is dropped
18    pub fn get_flight_data(&self) -> Option<FlightData> {
19        self.flight.clone()
20    }
21    /// returns an option of the WifiInfo.
22    /// stang 90% is max in the AP mode
23    ///
24    /// this will always represent the last state event if the network connection is dropped
25    pub fn get_wifi_info(&self) -> Option<WifiInfo> {
26        self.wifi.clone()
27    }
28    /// returns an option of the LightInfo.
29    ///
30    /// this will always represent the last state event if the network connection is dropped
31    pub fn get_light_info(&self) -> Option<LightInfo> {
32        self.light.clone()
33    }
34    /// applies the package to the current data.
35    /// It ignore non Meta package data and just overwrite the current metadata
36    pub fn update(&mut self, package: &PackageData) {
37        match package {
38            PackageData::FlightData(fd) => self.flight = Some(fd.clone()),
39            PackageData::WifiInfo(wifi) => self.wifi = Some(wifi.clone()),
40            PackageData::LightInfo(li) => self.light = Some(li.clone()),
41            _ => (),
42        };
43    }
44}
45
46fn int16(val0: u8, val1: u8) -> i16 {
47    if val1 != 0 {
48        (((val0 as i32) | ((val1 as i32) << 8)) - 0x10000) as i16
49    } else {
50        (val0 as i16) | ((val1 as i16) << 8)
51    }
52}
53
54#[derive(Clone)]
55pub struct FlightData {
56    pub height: i16,
57    pub north_speed: i16,
58    pub east_speed: i16,
59    pub ground_speed: i16,
60    pub fly_time: i16,
61    pub imu_state: bool,
62    pub pressure_state: bool,
63    pub down_visual_state: bool,
64    pub power_state: bool,
65    pub battery_state: bool,
66    pub gravity_state: bool,
67    pub wind_state: bool,
68    pub imu_calibration_state: u8,
69    pub battery_percentage: u8,
70    pub drone_battery_left: i16,
71    pub drone_fly_time_left: i16,
72
73    pub em_sky: bool,
74    pub em_ground: bool,
75    pub em_open: bool,
76    pub drone_hover: bool,
77    pub outage_recording: bool,
78    pub battery_low: bool,
79    pub battery_lower: bool,
80    pub factory_mode: bool,
81
82    pub fly_mode: u8,
83    pub throw_fly_timer: u8,
84    pub camera_state: u8,
85    pub electrical_machinery_state: u8,
86    pub front_in: bool,
87    pub front_out: bool,
88    pub front_lsc: bool,
89    pub temperature_height: bool,
90}
91
92impl std::fmt::Debug for FlightData {
93    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94        write!(
95            f,
96            "FlightData {{ alt: {}, north_sp: {}, east_sp: {}, ground_sp: {}, fly_time: {}, imu_cal: {}, battery: {}, battery_left: {}, fly_time_left: {}, fly_mode: {}, throw_fly_timer: {}, camera: {}, em: {}}}",
97            self.height, self.north_speed, self.east_speed, self.ground_speed, self.fly_time, self.imu_calibration_state, self.battery_percentage,
98            self.drone_battery_left, self.drone_fly_time_left, self.fly_mode, self.throw_fly_timer, self.camera_state, self.electrical_machinery_state
99        )
100    }
101}
102
103impl From<Vec<u8>> for FlightData {
104    fn from(data: Vec<u8>) -> FlightData {
105        FlightData {
106            height: int16(data[0], data[1]),
107            north_speed: int16(data[2], data[3]),
108            east_speed: int16(data[4], data[5]),
109            ground_speed: int16(data[6], data[7]),
110            fly_time: int16(data[8], data[9]),
111
112            imu_state: ((data[10]) & 0x1) != 0,
113            pressure_state: ((data[10] >> 1) & 0x1) != 0,
114            down_visual_state: ((data[10] >> 2) & 0x1) != 0,
115            power_state: ((data[10] >> 3) & 0x1) != 0,
116            battery_state: ((data[10] >> 4) & 0x1) != 0,
117            gravity_state: ((data[10] >> 5) & 0x1) != 0,
118            wind_state: ((data[10] >> 7) & 0x1) != 0,
119
120            imu_calibration_state: data[11],
121            battery_percentage: data[12],
122            drone_battery_left: int16(data[13], data[14]),
123            drone_fly_time_left: int16(data[15], data[16]),
124
125            em_sky: ((data[17]) & 0x1) != 0,
126            em_ground: ((data[17] >> 1) & 0x1) != 0,
127            em_open: ((data[17] >> 2) & 0x1) != 0,
128            drone_hover: ((data[17] >> 3) & 0x1) != 0,
129            outage_recording: ((data[17] >> 4) & 0x1) != 0,
130            battery_low: ((data[17] >> 5) & 0x1) != 0,
131            battery_lower: ((data[17] >> 6) & 0x1) != 0,
132            factory_mode: ((data[17] >> 7) & 0x1) != 0,
133
134            fly_mode: data[18],
135            throw_fly_timer: data[19],
136            camera_state: data[20],
137            electrical_machinery_state: data[21],
138
139            front_in: ((data[22]) & 0x1) != 0,
140            front_out: ((data[22] >> 1) & 0x1) != 0,
141            front_lsc: ((data[22] >> 2) & 0x1) != 0,
142
143            temperature_height: ((data[23]) & 0x1) != 0,
144        }
145    }
146}
147
148/// current strength of the wifi signal and distortion.
149/// When the drone is in the AP mode, the max strength value is 90
150#[derive(Debug, Clone)]
151pub struct WifiInfo {
152    strength: u8,
153    disturb: u8,
154}
155impl From<Vec<u8>> for WifiInfo {
156    /// parse the incoming network package
157    fn from(data: Vec<u8>) -> WifiInfo {
158        WifiInfo {
159            strength: data[0],
160            disturb: data[1],
161        }
162    }
163}
164
165/// some features like a flip or bouncing is only available when the battery is charged and there is enough light
166/// check the FlightData for the battery state
167#[derive(Debug, Clone)]
168pub struct LightInfo {
169    good: bool,
170}
171impl From<Vec<u8>> for LightInfo {
172    /// parse the incoming network package
173    fn from(data: Vec<u8>) -> LightInfo {
174        LightInfo { good: data[0] == 0 }
175    }
176}
177
178/// not complete parse log message. This message is send frequently from the drone
179#[derive(Debug, Clone)]
180pub struct LogMessage {
181    pub id: u16,
182    pub message: String,
183}
184impl From<Vec<u8>> for LogMessage {
185    /// parse the incoming network package
186    fn from(data: Vec<u8>) -> LogMessage {
187        let mut cur = Cursor::new(data);
188        let id: u16 = cur.read_u16::<LittleEndian>().unwrap();
189        cur.seek(SeekFrom::Start(19)).unwrap();
190        let mut msg: Vec<u8> = Vec::new();
191        cur.read_until(0, &mut msg).unwrap();
192        LogMessage {
193            id,
194            message: String::from_utf8(msg)
195                .unwrap()
196                .trim_matches('\u{0}')
197                .to_string(),
198        }
199    }
200}