jvs_packets/
jvs_modified.rs

1//! A packet structures for slightly modified JAMMA Video Standart protocol,
2//! that mostly used for NFS readers.
3//!
4//! # Request Packet (master -> slave)
5//!  00     | 01  | 02     | 03    | 04    | 05       | 06       | ...          | N + 1                                                                                                                                                  |
6//! :------:|:---:|:------:|:-----:|:-----:|:--------:|:--------:|:------------:|:-----:
7//!  [SYNC] | `N` | `DEST` | `SEQ` | `CMD` | `DATA_0` | `DATA_1` | `DATA_(N-4)` | `SUM`
8//!  
9//! # Response Packet (slave -> master)
10//!  00     | 01  | 02     | 03    | 04       | 05    | 06       | 07       | 08       | ...          | N + 1                                                                                                                                                             |
11//! :------:|:---:|:------:|:-----:|:--------:|:-----:|:--------:|:--------:|:--------:|:------------:|:-----:
12//!  [SYNC] | `N` | `DEST` | `SEQ` | `STATUS` | `CMD` | [REPORT] | `DATA_0` | `DATA_1` | `DATA_(N-4)` | `SUM`
13//!
14//! [SYNC]: crate::SYNC_BYTE
15//! [REPORT]: crate::Report
16
17use crate::{impl_required_packet_blocks, Packet, ReportField};
18
19pub trait ModifiedPacket: Packet {
20    const CMD_INDEX: usize;
21    const SEQUENCE_INDEX: usize;
22
23    /// Returns a CMD byte at [`ModifiedPacket::CMD_INDEX`]
24    ///
25    /// The CMD byte is used for telling a JVS to execute a specific command
26    fn cmd(&self) -> u8 {
27        self.as_ref()[Self::CMD_INDEX]
28    }
29
30    /// Sets a CMD byte at [`ModifiedPacket::CMD_INDEX`]
31    fn set_cmd(&mut self, cmd: u8) -> &mut Self {
32        self.as_mut()[Self::CMD_INDEX] = cmd;
33        self
34    }
35
36    fn sequence(&self) -> u8 {
37        self.as_ref()[Self::SEQUENCE_INDEX]
38    }
39
40    fn set_sequence(&mut self, sequence: u8) -> &mut Self {
41        self.as_mut()[Self::SEQUENCE_INDEX] = sequence;
42        self
43    }
44}
45
46#[derive(Debug, Clone)]
47pub struct RequestPacket<const N: usize = 256> {
48    inner: [u8; N],
49}
50
51impl<const N: usize> Packet for RequestPacket<N> {
52    const SIZE_INDEX: usize = 1;
53    const DATA_BEGIN_INDEX: usize = 5;
54    const DESTINATION_INDEX: usize = 2;
55}
56
57impl<const N: usize> ModifiedPacket for RequestPacket<N> {
58    const CMD_INDEX: usize = 4;
59    const SEQUENCE_INDEX: usize = 3;
60}
61
62impl_required_packet_blocks!(RequestPacket);
63
64#[derive(Debug, Clone)]
65pub struct ResponsePacket<const N: usize = 256> {
66    inner: [u8; N],
67}
68
69impl<const N: usize> Packet for ResponsePacket<N> {
70    const SIZE_INDEX: usize = 1;
71    const DATA_BEGIN_INDEX: usize = 7;
72    const DESTINATION_INDEX: usize = 2;
73}
74
75impl<const N: usize> ModifiedPacket for ResponsePacket<N> {
76    const CMD_INDEX: usize = 5;
77    const SEQUENCE_INDEX: usize = 3;
78}
79
80impl<const N: usize> ReportField for ResponsePacket<N> {
81    const REPORT_INDEX: usize = 6;
82}
83
84impl<const N: usize> ResponsePacket<N> {
85    const STATUS_INDEX: usize = 4;
86
87    pub fn status(&self) -> u8 {
88        self.as_ref()[Self::STATUS_INDEX]
89    }
90
91    pub fn set_status(&mut self, status: u8) -> &mut Self {
92        self.as_mut()[Self::STATUS_INDEX] = status;
93        self
94    }
95}
96
97impl_required_packet_blocks!(ResponsePacket);
98
99#[cfg(test)]
100mod tests {
101    use super::*;
102    use crate::WritePacket;
103
104    const REQUEST_DATA: [u8; 8] = [0xE0, 0x06, 0xFF, 0x01, 0x02, 0x01, 0x02, 0x0B];
105    const RESPONSE_DATA: [u8; 10] = [0xE0, 0x08, 0xFF, 0x01, 0x03, 0x02, 0x04, 0x01, 0x02, 0x14];
106
107    // Request Packet tests
108    #[test]
109    fn test_request_packet_from_slice() {
110        let packet = RequestPacket::<256>::from_slice(&REQUEST_DATA);
111        assert_eq!(REQUEST_DATA, packet.as_slice());
112    }
113
114    #[test]
115    fn test_request_packet_access_methods() {
116        let packet = RequestPacket::<256>::from_slice(&REQUEST_DATA);
117
118        assert_eq!(packet.sync(), REQUEST_DATA[0]);
119        assert_eq!(packet.size(), REQUEST_DATA[1]);
120        assert_eq!(packet.dest(), REQUEST_DATA[2]);
121        assert_eq!(packet.sequence(), REQUEST_DATA[3]);
122        assert_eq!(packet.cmd(), REQUEST_DATA[4]);
123        assert_eq!(packet.data(), &[REQUEST_DATA[5], REQUEST_DATA[6]]);
124        assert_eq!(packet.checksum(), REQUEST_DATA[7]);
125    }
126
127    #[test]
128    fn test_request_packet_setter_methods() {
129        let mut packet = RequestPacket::<256>::new();
130        packet
131            .set_sync()
132            .set_dest(REQUEST_DATA[2])
133            .set_sequence(REQUEST_DATA[3])
134            .set_cmd(REQUEST_DATA[4])
135            .set_data(&[REQUEST_DATA[5], REQUEST_DATA[6]])
136            .set_checksum(REQUEST_DATA[7])
137            .set_size(REQUEST_DATA[1]);
138
139        assert_eq!(packet.as_slice(), REQUEST_DATA);
140        packet.calculate_checksum();
141        assert_eq!(packet.checksum(), REQUEST_DATA[7]);
142        packet.set_data(&[0x01]);
143        assert_eq!(packet.size(), REQUEST_DATA[1] - 1);
144    }
145
146    #[test]
147    fn test_request_packet_read() {
148        use crate::ReadPacket;
149        let mut cursor = std::io::Cursor::new(REQUEST_DATA);
150        let mut packet = RequestPacket::<256>::new();
151        cursor.read_packet(&mut packet).unwrap();
152
153        assert_eq!(cursor.into_inner(), packet.as_slice())
154    }
155
156    #[test]
157    fn test_request_packet_write() {
158        let mut writer = std::io::Cursor::new(vec![]);
159        let packet = RequestPacket::<256>::from_slice(&REQUEST_DATA);
160        writer.write_packet(&packet).unwrap();
161
162        assert_eq!(writer.into_inner(), packet.as_slice())
163    }
164
165    // Response Packet tests
166    #[test]
167    fn test_response_packet_from_slice() {
168        let packet = ResponsePacket::<256>::from_slice(&REQUEST_DATA);
169        assert_eq!(REQUEST_DATA, packet.as_slice());
170    }
171
172    // #[test]
173    // #[should_panic]
174    // fn test_response_packet_from_slice_panic() {
175    //     let data = [0, 1, 2];
176    //     ResponsePacket::<256>::from_slice(&data);
177    // }
178
179    #[test]
180    fn test_response_packet_access_methods() {
181        let packet = ResponsePacket::<256>::from_slice(&RESPONSE_DATA);
182
183        assert_eq!(packet.sync(), RESPONSE_DATA[0]);
184        assert_eq!(packet.size(), RESPONSE_DATA[1]);
185        assert_eq!(packet.dest(), RESPONSE_DATA[2]);
186        assert_eq!(packet.sequence(), RESPONSE_DATA[3]);
187        assert_eq!(packet.status(), RESPONSE_DATA[4]);
188        assert_eq!(packet.cmd(), RESPONSE_DATA[5]);
189        assert_eq!(packet.report_raw(), RESPONSE_DATA[6]);
190        assert_eq!(packet.data(), &[RESPONSE_DATA[7], RESPONSE_DATA[8]]);
191        assert_eq!(packet.checksum(), RESPONSE_DATA[9]);
192    }
193
194    #[test]
195    fn test_response_packet_setter_methods() {
196        let mut packet = ResponsePacket::<256>::new();
197        packet
198            .set_sync()
199            .set_dest(RESPONSE_DATA[2])
200            .set_sequence(RESPONSE_DATA[3])
201            .set_status(RESPONSE_DATA[4])
202            .set_cmd(RESPONSE_DATA[5])
203            .set_report(RESPONSE_DATA[6])
204            .set_data(&[RESPONSE_DATA[7], RESPONSE_DATA[8]])
205            .set_checksum(RESPONSE_DATA[9])
206            .set_size(RESPONSE_DATA[1]);
207
208        assert_eq!(packet.as_slice(), RESPONSE_DATA);
209        packet.calculate_checksum();
210        assert_eq!(packet.checksum(), RESPONSE_DATA[9]);
211        packet.set_data(&[0x01]);
212        assert_eq!(packet.size(), RESPONSE_DATA[1] - 1);
213    }
214
215    #[test]
216    fn test_response_packet_read() {
217        use crate::ReadPacket;
218        let mut reader = std::io::Cursor::new(RESPONSE_DATA);
219        let mut packet = ResponsePacket::<256>::new();
220        reader.read_packet(&mut packet).unwrap();
221
222        assert_eq!(reader.into_inner(), packet.as_slice())
223    }
224
225    #[test]
226    fn test_response_packet_write() {
227        let mut writer = std::io::Cursor::new(vec![]);
228        let packet = ResponsePacket::<256>::from_slice(&RESPONSE_DATA);
229        writer.write_packet(&packet).unwrap();
230
231        assert_eq!(writer.into_inner(), packet.as_slice())
232    }
233}