1 // Based on https://github.com/n7tae/mrefd/blob/master/Packet-Description.md
2 // and the main M17 specification
4 use crate::protocol
::LsfFrame
;
6 macro_rules
! impl_stream_id
{
9 pub fn stream_id(&self) -> u16 {
10 u16::from_be_bytes([self.0[$from
], self.0[$from
+ 1]])
16 macro_rules
! impl_link_setup
{
17 ($t
:ty
, $from
:tt
) => {
19 pub fn link_setup_frame(&self) -> LsfFrame
{
20 let mut frame
= LsfFrame([0; 30]);
21 frame
.0[0..28].copy_from_slice(&self.0[$from
..($from
+ 28)]);
22 frame
.recalculate_crc();
29 macro_rules
! impl_link_setup_frame
{
30 ($t
:ty
, $from
:tt
) => {
32 pub fn link_setup_frame(&self) -> LsfFrame
{
33 let mut frame
= LsfFrame([0; 30]);
34 frame
.0[..].copy_from_slice(&self.0[$from
..($from
+ 30)]);
41 macro_rules
! impl_frame_number
{
42 ($t
:ty
, $from
:tt
) => {
44 pub fn frame_number(&self) -> u16 {
45 let frame_num
= u16::from_be_bytes([self.0[$from
], self.0[$from
+ 1]]);
49 pub fn is_end_of_stream(&self) -> bool
{
50 let frame_num
= u16::from_be_bytes([self.0[$from
], self.0[$from
+ 1]]);
51 (frame_num
& 0x8000) > 0
57 macro_rules
! impl_payload
{
58 ($t
:ty
, $from
:tt
, $to
:tt
) => {
60 pub fn payload(&self) -> &[u8] {
67 macro_rules
! impl_modules
{
68 ($t
:ty
, $from
:tt
, $to
:tt
) => {
70 pub fn modules(&self) -> ModulesIterator
{
71 ModulesIterator
::new(&self.0[$from
..$to
])
77 macro_rules
! impl_module
{
80 pub fn module(&self) -> char {
87 macro_rules
! impl_address
{
88 ($t
:ty
, $from
:tt
) => {
90 pub fn address(&self) -> crate::address
::Address
{
91 crate::address
::decode_address(self.0[$from
..($from
+ 6)].try_into().unwrap
())
97 macro_rules
! impl_trailing_crc_verify
{
100 pub fn verify_integrity(&self) -> bool
{
101 crate::crc
::m17_crc(&self.0) == 0
107 macro_rules
! impl_internal_crc
{
108 ($t
:ty
, $from
:tt
, $to
:tt
) => {
110 pub fn verify_integrity(&self) -> bool
{
111 crate::crc
::m17_crc(&self.0[$from
..$to
]) == 0
117 macro_rules
! impl_is_relayed
{
120 pub fn is_relayed(&self) -> bool
{
121 self.0[self.0.len() - 1] != 0
127 pub struct ModulesIterator
<'a
> {
132 impl<'a
> ModulesIterator
<'a
> {
133 fn new(modules
: &'a
[u8]) -> Self {
134 Self { modules
, idx
: 0 }
138 impl Iterator
for ModulesIterator
<'_
> {
141 fn next(&mut self) -> Option
<Self::Item
> {
142 if self.modules
[self.idx
] == 0 {
145 if self.idx
< self.modules
.len() {
147 return Some(self.modules
[self.idx
- 1] as char);
153 pub const MAGIC_VOICE
: &[u8] = b
"M17 ";
154 pub const MAGIC_VOICE_HEADER
: &[u8] = b
"M17H";
155 pub const MAGIC_VOICE_DATA
: &[u8] = b
"M17D";
156 pub const MAGIC_PACKET
: &[u8] = b
"M17P";
157 pub const MAGIC_ACKNOWLEDGE
: &[u8] = b
"ACKN";
158 pub const MAGIC_CONNECT
: &[u8] = b
"CONN";
159 pub const MAGIC_DISCONNECT
: &[u8] = b
"DISC";
160 pub const MAGIC_LISTEN
: &[u8] = b
"LSTN";
161 pub const MAGIC_NACK
: &[u8] = b
"NACK";
162 pub const MAGIC_PING
: &[u8] = b
"PING";
163 pub const MAGIC_PONG
: &[u8] = b
"PONG";
165 /// Messages sent from a station/client to a reflector
166 #[allow(clippy::large_enum_variant)]
167 pub enum ClientMessage
{
168 VoiceFull(VoiceFull
),
169 VoiceHeader(VoiceHeader
),
170 VoiceData(VoiceData
),
175 Disconnect(Disconnect
),
178 /// Messages sent from a reflector to a station/client
179 #[allow(clippy::large_enum_variant)]
180 pub enum ServerMessage
{
181 VoiceFull(VoiceFull
),
182 VoiceHeader(VoiceHeader
),
183 VoiceData(VoiceData
),
186 DisconnectAcknowledge(DisconnectAcknowledge
),
187 ForceDisconnect(ForceDisconnect
),
188 ConnectAcknowledge(ConnectAcknowledge
),
189 ConnectNack(ConnectNack
),
192 /// Messages sent and received between reflectors
193 #[allow(clippy::large_enum_variant)]
194 pub enum InterlinkMessage
{
195 VoiceInterlink(VoiceInterlink
),
196 VoiceHeaderInterlink(VoiceHeaderInterlink
),
197 VoiceDataInterlink(VoiceDataInterlink
),
198 PacketInterlink(PacketInterlink
),
200 ConnectInterlink(ConnectInterlink
),
201 ConnectInterlinkAcknowledge(ConnectInterlinkAcknowledge
),
202 ConnectNack(ConnectNack
),
203 DisconnectInterlink(DisconnectInterlink
),
206 pub struct VoiceFull(pub [u8; 54]);
207 impl_stream_id
!(VoiceFull
, 4);
208 impl_link_setup
!(VoiceFull
, 6);
209 impl_frame_number
!(VoiceFull
, 34);
210 impl_payload
!(VoiceFull
, 36, 52);
211 impl_trailing_crc_verify
!(VoiceFull
);
213 pub struct VoiceHeader(pub [u8; 36]);
214 impl_stream_id
!(VoiceHeader
, 4);
215 impl_link_setup
!(VoiceHeader
, 6);
216 impl_trailing_crc_verify
!(VoiceHeader
);
218 pub struct VoiceData(pub [u8; 26]);
219 impl_stream_id
!(VoiceData
, 4);
220 impl_frame_number
!(VoiceData
, 6);
221 impl_payload
!(VoiceData
, 8, 24);
222 impl_trailing_crc_verify
!(VoiceData
);
224 pub struct Packet(pub [u8; 859]);
225 impl_link_setup_frame
!(Packet
, 4);
228 pub fn payload(&self) -> &[u8] {
232 pub fn verify_integrity(&self) -> bool
{
233 self.link_setup_frame().check_crc() == 0
234 && self.payload().len() >= 4
235 && crate::crc
::m17_crc(self.payload()) == 0
239 pub struct Pong(pub [u8; 10]);
240 impl_address
!(Pong
, 4);
242 pub struct Connect(pub [u8; 11]);
243 impl_address
!(Connect
, 4);
244 impl_module
!(Connect
, 10);
246 pub struct Listen(pub [u8; 11]);
247 impl_address
!(Listen
, 4);
248 impl_module
!(Listen
, 10);
250 pub struct Disconnect(pub [u8; 10]);
251 impl_address
!(Disconnect
, 4);
253 pub struct Ping(pub [u8; 10]);
254 impl_address
!(Ping
, 4);
256 pub struct DisconnectAcknowledge(pub [u8; 4]);
258 pub struct ForceDisconnect(pub [u8; 10]);
259 impl_address
!(ForceDisconnect
, 4);
261 pub struct ConnectAcknowledge(pub [u8; 4]);
263 pub struct ConnectNack(pub [u8; 4]);
265 pub struct VoiceInterlink(pub [u8; 55]);
266 impl_stream_id
!(VoiceInterlink
, 4);
267 impl_link_setup
!(VoiceInterlink
, 6);
268 impl_frame_number
!(VoiceInterlink
, 34);
269 impl_payload
!(VoiceInterlink
, 36, 52);
270 impl_internal_crc
!(VoiceInterlink
, 0, 54);
271 impl_is_relayed
!(VoiceInterlink
);
273 pub struct VoiceHeaderInterlink(pub [u8; 37]);
274 impl_stream_id
!(VoiceHeaderInterlink
, 4);
275 impl_link_setup
!(VoiceHeaderInterlink
, 6);
276 impl_internal_crc
!(VoiceHeaderInterlink
, 0, 36);
277 impl_is_relayed
!(VoiceHeaderInterlink
);
279 pub struct VoiceDataInterlink(pub [u8; 27]);
280 impl_stream_id
!(VoiceDataInterlink
, 4);
281 impl_frame_number
!(VoiceDataInterlink
, 6);
282 impl_payload
!(VoiceDataInterlink
, 8, 24);
283 impl_internal_crc
!(VoiceDataInterlink
, 0, 24);
284 impl_is_relayed
!(VoiceDataInterlink
);
286 pub struct PacketInterlink(pub [u8; 860]);
287 impl_link_setup_frame
!(PacketInterlink
, 4);
288 impl_is_relayed
!(PacketInterlink
);
290 impl PacketInterlink
{
291 pub fn payload(&self) -> &[u8] {
292 &self.0[34..(self.0.len() - 1)]
295 pub fn verify_integrity(&self) -> bool
{
296 self.link_setup_frame().check_crc() == 0
297 && self.payload().len() >= 4
298 && crate::crc
::m17_crc(self.payload()) == 0
302 pub struct ConnectInterlink(pub [u8; 37]);
303 impl_address
!(ConnectInterlink
, 4);
304 impl_modules
!(ConnectInterlink
, 10, 37);
306 pub struct ConnectInterlinkAcknowledge(pub [u8; 37]);
307 impl_address
!(ConnectInterlinkAcknowledge
, 4);
308 impl_modules
!(ConnectInterlinkAcknowledge
, 10, 37);
310 pub struct DisconnectInterlink(pub [u8; 10]);
311 impl_address
!(DisconnectInterlink
, 4);