f1_api/nineteen/
event.rs

1//! Decoder for event packets sent by F1 2019
2//!
3//! F1 2019 extended the event packet with seven new events compared to its predecessor, four of
4//! which can carry a payload.
5
6use std::io::{Cursor, Error, ErrorKind};
7use std::time::Duration;
8
9use bytes::{Buf, BytesMut};
10
11use crate::nineteen::header::decode_header;
12use crate::packet::ensure_packet_size;
13use crate::packet::event::{
14    Event, EventPacket, FastestLap, RaceWinner, Retirement, TeammateInPits,
15};
16
17/// Size of the event packet in bytes
18///
19/// The event packet can have a maximum size of 32 bytes, but since not all events carry a payload,
20/// it might very well be smaller.
21pub const PACKET_SIZE: usize = 32;
22
23/// Decode an event packet sent by F1 2019
24///
25/// F1 2019 extended the event packet with seven new events compared to its predecessor, four of
26/// which can carry a payload. A four character event code is provided after the packet header to
27/// identify the event. Based on this code the right decoding function is called, and a variant of
28/// the `EventPacket` is returned.
29pub fn decode_event(cursor: &mut Cursor<&mut BytesMut>) -> Result<EventPacket, Error> {
30    ensure_packet_size(PACKET_SIZE, cursor)?;
31
32    let header = decode_header(cursor)?;
33    let event_code = decode_event_code(cursor);
34
35    let payload = match event_code.as_str() {
36        "SSTA" => Event::SessionStarted,
37        "SEND" => Event::SessionEnded,
38        "FTLP" => decode_fastest_lap(cursor),
39        "RTMT" => decode_retirement(cursor),
40        "DRSE" => Event::DrsEnabled,
41        "DRSD" => Event::DrsDisabled,
42        "TMPT" => decode_teammate_pits(cursor),
43        "CHQF" => Event::ChequeredFlag,
44        "RCWN" => decode_race_winner(cursor),
45        event_code => {
46            return Err(Error::new(
47                ErrorKind::InvalidData,
48                format!("Unexpected event code {}", event_code),
49            ))
50        }
51    };
52
53    Ok(EventPacket::new(header, payload))
54}
55
56/// Decode the event code at the beginning of the event packet
57///
58/// The event packet contains a string that identifies the type of the event. Based on the event
59/// code different logic can be used to decode the remainder of the packet.
60fn decode_event_code(cursor: &mut Cursor<&mut BytesMut>) -> String {
61    [
62        cursor.get_u8() as char,
63        cursor.get_u8() as char,
64        cursor.get_u8() as char,
65        cursor.get_u8() as char,
66    ]
67    .iter()
68    .collect()
69}
70
71/// Decode the "Fastest Lap" event.
72fn decode_fastest_lap(cursor: &mut Cursor<&mut BytesMut>) -> Event {
73    Event::FastestLap(FastestLap::new(
74        cursor.get_u8(),
75        Duration::from_secs_f32(cursor.get_f32_le()),
76    ))
77}
78
79/// Decode the "Retirement" event.
80fn decode_retirement(cursor: &mut Cursor<&mut BytesMut>) -> Event {
81    Event::Retirement(Retirement::new(cursor.get_u8()))
82}
83
84/// Decode the "Teammate in Pits" event.
85fn decode_teammate_pits(cursor: &mut Cursor<&mut BytesMut>) -> Event {
86    Event::TeammatesInPits(TeammateInPits::new(cursor.get_u8()))
87}
88
89/// Decode the "Race Winner" event.
90fn decode_race_winner(cursor: &mut Cursor<&mut BytesMut>) -> Event {
91    Event::RaceWinner(RaceWinner::new(cursor.get_u8()))
92}
93
94#[cfg(test)]
95mod tests {
96    use std::io::Cursor;
97
98    use bytes::{BufMut, BytesMut};
99
100    use crate::nineteen::event::{decode_event, PACKET_SIZE};
101    use crate::packet::event::Event;
102
103    fn put_packet_header(mut bytes: BytesMut) -> BytesMut {
104        bytes.put_u16_le(2019);
105        bytes.put_u8(1);
106        bytes.put_u8(2);
107        bytes.put_u8(3);
108        bytes.put_u8(0);
109        bytes.put_u64_le(u64::max_value());
110        bytes.put_f32_le(1.0);
111        bytes.put_u32_le(u32::max_value());
112        bytes.put_u8(0);
113
114        bytes
115    }
116
117    #[test]
118    fn decode_event_with_error() {
119        let mut bytes = BytesMut::with_capacity(0);
120        let mut cursor = Cursor::new(&mut bytes);
121
122        let packet = decode_event(&mut cursor);
123        assert!(packet.is_err());
124    }
125
126    #[test]
127    fn decode_ftlp_event() {
128        let bytes = BytesMut::with_capacity(PACKET_SIZE);
129        let mut bytes = put_packet_header(bytes);
130
131        bytes.put_u8(b'F');
132        bytes.put_u8(b'T');
133        bytes.put_u8(b'L');
134        bytes.put_u8(b'P');
135        bytes.put_u8(1);
136        bytes.put_f32_le(2.0);
137
138        let mut cursor = Cursor::new(&mut bytes);
139
140        let packet = decode_event(&mut cursor).unwrap();
141        match packet.event() {
142            Event::FastestLap(fastest_lap) => assert_eq!(2, fastest_lap.time().as_secs()),
143            _ => panic!("Expected a fastest lap event"),
144        }
145    }
146
147    #[test]
148    fn decode_ssta_event() {
149        let bytes = BytesMut::with_capacity(PACKET_SIZE);
150        let mut bytes = put_packet_header(bytes);
151
152        bytes.put_u8(b'S');
153        bytes.put_u8(b'S');
154        bytes.put_u8(b'T');
155        bytes.put_u8(b'A');
156        let padding = vec![0u8; 5];
157        bytes.put(padding.as_slice());
158
159        let mut cursor = Cursor::new(&mut bytes);
160
161        let packet = decode_event(&mut cursor).unwrap();
162        assert_eq!(Event::SessionStarted, *packet.event())
163    }
164}