1use std::io::{Cursor, Error, ErrorKind};
7
8use bytes::{Buf, BytesMut};
9
10use crate::nineteen::header::decode_header;
11use crate::packet::ensure_packet_size;
12use crate::packet::telemetry::{Button, Gear, Surface, Telemetry, TelemetryPacket};
13use crate::types::CornerProperty;
14
15pub const PACKET_SIZE: usize = 1347;
17
18pub fn decode_telemetry(cursor: &mut Cursor<&mut BytesMut>) -> Result<TelemetryPacket, Error> {
23 ensure_packet_size(PACKET_SIZE, cursor)?;
24
25 let header = decode_header(cursor)?;
26 let mut telemetry = Vec::with_capacity(20);
27
28 for _ in 0..20 {
29 telemetry.push(Telemetry::new(
30 cursor.get_u16_le(),
31 cursor.get_f32_le(),
32 cursor.get_f32_le(),
33 cursor.get_f32_le(),
34 cursor.get_u8(),
35 decode_gear(cursor)?,
36 cursor.get_u16_le(),
37 cursor.get_u8() > 0,
38 cursor.get_u8(),
39 decode_brake_temperature(cursor),
40 decode_tyre_surface_temperature(cursor),
41 decode_tyre_inner_temperature(cursor),
42 cursor.get_u16_le(),
43 decode_tyre_pressure(cursor),
44 decode_surface_type(cursor)?,
45 ));
46 }
47
48 let button_status = match Button::from_bits(cursor.get_u32_le()) {
49 Some(button) => button,
50 None => Button::NONE,
51 };
52
53 Ok(TelemetryPacket::new(header, telemetry, button_status))
54}
55
56fn decode_gear(cursor: &mut Cursor<&mut BytesMut>) -> Result<Gear, Error> {
57 let value = cursor.get_i8();
58
59 match value {
60 -1 => Ok(Gear::Reverse),
61 0 => Ok(Gear::Neutral),
62 1 => Ok(Gear::First),
63 2 => Ok(Gear::Second),
64 3 => Ok(Gear::Third),
65 4 => Ok(Gear::Fourth),
66 5 => Ok(Gear::Fifth),
67 6 => Ok(Gear::Sixth),
68 7 => Ok(Gear::Seventh),
69 8 => Ok(Gear::Eighth),
70 _ => Err(Error::new(ErrorKind::InvalidData, "Failed to decode gear.")),
71 }
72}
73
74fn decode_brake_temperature(cursor: &mut Cursor<&mut BytesMut>) -> CornerProperty<u16> {
75 CornerProperty::new(
76 cursor.get_u16_le(),
77 cursor.get_u16_le(),
78 cursor.get_u16_le(),
79 cursor.get_u16_le(),
80 )
81}
82
83fn decode_tyre_surface_temperature(cursor: &mut Cursor<&mut BytesMut>) -> CornerProperty<u16> {
84 CornerProperty::new(
85 cursor.get_u16_le(),
86 cursor.get_u16_le(),
87 cursor.get_u16_le(),
88 cursor.get_u16_le(),
89 )
90}
91
92fn decode_tyre_inner_temperature(cursor: &mut Cursor<&mut BytesMut>) -> CornerProperty<u16> {
93 CornerProperty::new(
94 cursor.get_u16_le(),
95 cursor.get_u16_le(),
96 cursor.get_u16_le(),
97 cursor.get_u16_le(),
98 )
99}
100
101fn decode_tyre_pressure(cursor: &mut Cursor<&mut BytesMut>) -> CornerProperty<f32> {
102 CornerProperty::new(
103 cursor.get_f32_le(),
104 cursor.get_f32_le(),
105 cursor.get_f32_le(),
106 cursor.get_f32_le(),
107 )
108}
109
110fn decode_surface_type(
111 cursor: &mut Cursor<&mut BytesMut>,
112) -> Result<CornerProperty<Surface>, Error> {
113 Ok(CornerProperty::new(
114 decode_surface(cursor)?,
115 decode_surface(cursor)?,
116 decode_surface(cursor)?,
117 decode_surface(cursor)?,
118 ))
119}
120
121fn decode_surface(cursor: &mut Cursor<&mut BytesMut>) -> Result<Surface, Error> {
122 let value = cursor.get_u8();
123
124 match value {
125 0 => Ok(Surface::Tarmac),
126 1 => Ok(Surface::RumbleStrip),
127 2 => Ok(Surface::Concrete),
128 3 => Ok(Surface::Rock),
129 4 => Ok(Surface::Gravel),
130 5 => Ok(Surface::Mud),
131 6 => Ok(Surface::Sand),
132 7 => Ok(Surface::Grass),
133 8 => Ok(Surface::Water),
134 9 => Ok(Surface::Cobblestone),
135 10 => Ok(Surface::Metal),
136 11 => Ok(Surface::Ridged),
137 _ => Err(Error::new(
138 ErrorKind::InvalidData,
139 "Failed to decode surface.",
140 )),
141 }
142}
143
144#[cfg(test)]
145mod tests {
146 use std::io::Cursor;
147
148 use assert_approx_eq::assert_approx_eq;
149 use bytes::{BufMut, BytesMut};
150
151 use crate::nineteen::telemetry::{decode_telemetry, PACKET_SIZE};
152 use crate::packet::telemetry::{Button, Gear, Surface};
153
154 fn put_packet_header(mut bytes: BytesMut) -> BytesMut {
155 bytes.put_u16_le(2019);
156 bytes.put_u8(1);
157 bytes.put_u8(2);
158 bytes.put_u8(3);
159 bytes.put_u8(0);
160 bytes.put_u64_le(u64::max_value());
161 bytes.put_f32_le(1.0);
162 bytes.put_u32_le(u32::max_value());
163 bytes.put_u8(0);
164
165 bytes
166 }
167
168 #[test]
169 fn decode_telemetry_with_error() {
170 let mut bytes = BytesMut::with_capacity(0);
171 let mut cursor = Cursor::new(&mut bytes);
172
173 let packet = decode_telemetry(&mut cursor);
174 assert!(packet.is_err());
175 }
176
177 #[test]
178 fn decode_telemetry_with_success() {
179 let mut bytes = BytesMut::with_capacity(PACKET_SIZE);
180 bytes = put_packet_header(bytes);
181
182 for _ in 0..20 {
183 bytes.put_u16_le(1);
184 bytes.put_f32_le(2.0);
185 bytes.put_f32_le(3.0);
186 bytes.put_f32_le(4.0);
187 bytes.put_u8(5);
188 bytes.put_u8(6);
189 bytes.put_u16_le(7);
190 bytes.put_u8(1);
191 bytes.put_u8(9);
192 bytes.put_u16_le(10);
193 bytes.put_u16_le(11);
194 bytes.put_u16_le(12);
195 bytes.put_u16_le(13);
196 bytes.put_u16_le(14);
197 bytes.put_u16_le(15);
198 bytes.put_u16_le(16);
199 bytes.put_u16_le(17);
200 bytes.put_u16_le(18);
201 bytes.put_u16_le(19);
202 bytes.put_u16_le(20);
203 bytes.put_u16_le(21);
204 bytes.put_u16_le(22);
205 bytes.put_f32_le(23.0);
206 bytes.put_f32_le(24.0);
207 bytes.put_f32_le(25.0);
208 bytes.put_f32_le(26.0);
209 bytes.put_u8(5);
210 bytes.put_u8(6);
211 bytes.put_u8(7);
212 bytes.put_u8(8);
213 }
214
215 bytes.put_u32_le(0x0001);
216
217 let mut cursor = Cursor::new(&mut bytes);
218
219 let packet = decode_telemetry(&mut cursor).unwrap();
220 let telemetry = packet.telemetry()[0];
221
222 assert_eq!(1, telemetry.speed());
223 assert_approx_eq!(2.0, telemetry.throttle());
224 assert_approx_eq!(3.0, telemetry.steering());
225 assert_approx_eq!(4.0, telemetry.brake());
226 assert_eq!(5, telemetry.clutch());
227 assert_eq!(Gear::Sixth, telemetry.gear());
228 assert_eq!(7, telemetry.engine_rpm());
229 assert!(telemetry.drs());
230 assert_eq!(9, telemetry.rev_lights());
231 assert_eq!(10, telemetry.brake_temperature().front_left());
232 assert_eq!(14, telemetry.tyre_surface_temperature().front_left());
233 assert_eq!(18, telemetry.tyre_inner_temperature().front_left());
234 assert_eq!(22, telemetry.engine_temperature());
235 assert_approx_eq!(23.0, telemetry.tyre_pressure().front_left());
236 assert_eq!(Surface::Mud, telemetry.surface_type().front_left());
237 assert_eq!(Button::CROSS_OR_A, packet.button_status());
238 }
239}