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
! define_message
{
8 pub struct $
t([u8; $sz
]);
10 pub fn from_bytes(b
: &[u8]) -> Option
<Self> {
14 let mut s
= Self([0; $sz
]);
15 s
.0[..].copy_from_slice(b
);
16 if !s
.verify_integrity() {
25 macro_rules
! impl_stream_id
{
26 ($t
:ty
, $from
:tt
) => {
28 pub fn stream_id(&self) -> u16 {
29 u16::from_be_bytes([self.0[$from
], self.0[$from
+ 1]])
35 macro_rules
! impl_link_setup
{
36 ($t
:ty
, $from
:tt
) => {
38 pub fn link_setup_frame(&self) -> LsfFrame
{
39 let mut frame
= LsfFrame([0; 30]);
40 frame
.0[0..28].copy_from_slice(&self.0[$from
..($from
+ 28)]);
41 frame
.recalculate_crc();
48 macro_rules
! impl_link_setup_frame
{
49 ($t
:ty
, $from
:tt
) => {
51 pub fn link_setup_frame(&self) -> LsfFrame
{
52 let mut frame
= LsfFrame([0; 30]);
53 frame
.0[..].copy_from_slice(&self.0[$from
..($from
+ 30)]);
60 macro_rules
! impl_frame_number
{
61 ($t
:ty
, $from
:tt
) => {
63 pub fn frame_number(&self) -> u16 {
64 let frame_num
= u16::from_be_bytes([self.0[$from
], self.0[$from
+ 1]]);
68 pub fn is_end_of_stream(&self) -> bool
{
69 let frame_num
= u16::from_be_bytes([self.0[$from
], self.0[$from
+ 1]]);
70 (frame_num
& 0x8000) > 0
76 macro_rules
! impl_payload
{
77 ($t
:ty
, $from
:tt
, $to
:tt
) => {
79 pub fn payload(&self) -> &[u8] {
86 macro_rules
! impl_modules
{
87 ($t
:ty
, $from
:tt
, $to
:tt
) => {
89 pub fn modules(&self) -> ModulesIterator
{
90 ModulesIterator
::new(&self.0[$from
..$to
])
96 macro_rules
! impl_module
{
99 pub fn module(&self) -> char {
106 macro_rules
! impl_address
{
107 ($t
:ty
, $from
:tt
) => {
109 pub fn address(&self) -> crate::address
::Address
{
110 crate::address
::decode_address(self.0[$from
..($from
+ 6)].try_into().unwrap
())
116 macro_rules
! impl_trailing_crc_verify
{
119 pub fn verify_integrity(&self) -> bool
{
120 crate::crc
::m17_crc(&self.0) == 0
126 macro_rules
! impl_internal_crc
{
127 ($t
:ty
, $from
:tt
, $to
:tt
) => {
129 pub fn verify_integrity(&self) -> bool
{
130 crate::crc
::m17_crc(&self.0[$from
..$to
]) == 0
136 macro_rules
! no_crc
{
139 pub fn verify_integrity(&self) -> bool
{
146 macro_rules
! impl_is_relayed
{
149 pub fn is_relayed(&self) -> bool
{
150 self.0[self.0.len() - 1] != 0
156 pub struct ModulesIterator
<'a
> {
161 impl<'a
> ModulesIterator
<'a
> {
162 fn new(modules
: &'a
[u8]) -> Self {
163 Self { modules
, idx
: 0 }
167 impl Iterator
for ModulesIterator
<'_
> {
170 fn next(&mut self) -> Option
<Self::Item
> {
171 if self.idx
< self.modules
.len() {
172 if self.modules
[self.idx
] == 0 {
176 return Some(self.modules
[self.idx
- 1] as char);
182 pub const MAGIC_VOICE
: &[u8] = b
"M17 ";
183 pub const MAGIC_VOICE_HEADER
: &[u8] = b
"M17H";
184 pub const MAGIC_VOICE_DATA
: &[u8] = b
"M17D";
185 pub const MAGIC_PACKET
: &[u8] = b
"M17P";
186 pub const MAGIC_ACKNOWLEDGE
: &[u8] = b
"ACKN";
187 pub const MAGIC_CONNECT
: &[u8] = b
"CONN";
188 pub const MAGIC_DISCONNECT
: &[u8] = b
"DISC";
189 pub const MAGIC_LISTEN
: &[u8] = b
"LSTN";
190 pub const MAGIC_NACK
: &[u8] = b
"NACK";
191 pub const MAGIC_PING
: &[u8] = b
"PING";
192 pub const MAGIC_PONG
: &[u8] = b
"PONG";
194 /// Messages sent from a station/client to a reflector
195 #[allow(clippy::large_enum_variant)]
196 pub enum ClientMessage
{
197 VoiceFull(VoiceFull
),
198 VoiceHeader(VoiceHeader
),
199 VoiceData(VoiceData
),
204 Disconnect(Disconnect
),
208 pub fn parse(bytes
: &[u8]) -> Option
<Self> {
213 MAGIC_VOICE
=> Some(Self::VoiceFull(VoiceFull
::from_bytes(&bytes
)?
)),
214 MAGIC_VOICE_HEADER
=> Some(Self::VoiceHeader(VoiceHeader
::from_bytes(&bytes
)?
)),
215 MAGIC_VOICE_DATA
=> Some(Self::VoiceData(VoiceData
::from_bytes(&bytes
)?
)),
216 MAGIC_PACKET
=> Some(Self::Packet(Packet
::from_bytes(&bytes
)?
)),
217 MAGIC_PONG
=> Some(Self::Pong(Pong
::from_bytes(&bytes
)?
)),
218 MAGIC_CONNECT
=> Some(Self::Connect(Connect
::from_bytes(&bytes
)?
)),
219 MAGIC_LISTEN
=> Some(Self::Listen(Listen
::from_bytes(&bytes
)?
)),
220 MAGIC_DISCONNECT
=> Some(Self::Disconnect(Disconnect
::from_bytes(&bytes
)?
)),
226 /// Messages sent from a reflector to a station/client
227 #[allow(clippy::large_enum_variant)]
228 pub enum ServerMessage
{
229 VoiceFull(VoiceFull
),
230 VoiceHeader(VoiceHeader
),
231 VoiceData(VoiceData
),
234 DisconnectAcknowledge(DisconnectAcknowledge
),
235 ForceDisconnect(ForceDisconnect
),
236 ConnectAcknowledge(ConnectAcknowledge
),
237 ConnectNack(ConnectNack
),
241 pub fn parse(bytes
: &[u8]) -> Option
<Self> {
246 MAGIC_VOICE
=> Some(Self::VoiceFull(VoiceFull
::from_bytes(&bytes
)?
)),
247 MAGIC_VOICE_HEADER
=> Some(Self::VoiceHeader(VoiceHeader
::from_bytes(&bytes
)?
)),
248 MAGIC_VOICE_DATA
=> Some(Self::VoiceData(VoiceData
::from_bytes(&bytes
)?
)),
249 MAGIC_PACKET
=> Some(Self::Packet(Packet
::from_bytes(&bytes
)?
)),
250 MAGIC_PING
=> Some(Self::Ping(Ping
::from_bytes(&bytes
)?
)),
251 MAGIC_DISCONNECT
if bytes
.len() == 4 => Some(Self::DisconnectAcknowledge(
252 DisconnectAcknowledge
::from_bytes(&bytes
)?
,
254 MAGIC_DISCONNECT
=> Some(Self::ForceDisconnect(ForceDisconnect
::from_bytes(&bytes
)?
)),
255 MAGIC_ACKNOWLEDGE
=> Some(Self::ConnectAcknowledge(ConnectAcknowledge
::from_bytes(
258 MAGIC_NACK
=> Some(Self::ConnectNack(ConnectNack
::from_bytes(&bytes
)?
)),
264 /// Messages sent and received between reflectors
265 #[allow(clippy::large_enum_variant)]
266 pub enum InterlinkMessage
{
267 VoiceInterlink(VoiceInterlink
),
268 VoiceHeaderInterlink(VoiceHeaderInterlink
),
269 VoiceDataInterlink(VoiceDataInterlink
),
270 PacketInterlink(PacketInterlink
),
272 ConnectInterlink(ConnectInterlink
),
273 ConnectInterlinkAcknowledge(ConnectInterlinkAcknowledge
),
274 ConnectNack(ConnectNack
),
275 DisconnectInterlink(DisconnectInterlink
),
278 impl InterlinkMessage
{
279 pub fn parse(bytes
: &[u8]) -> Option
<Self> {
284 MAGIC_VOICE
=> Some(Self::VoiceInterlink(VoiceInterlink
::from_bytes(&bytes
)?
)),
285 MAGIC_VOICE_HEADER
=> Some(Self::VoiceHeaderInterlink(
286 VoiceHeaderInterlink
::from_bytes(&bytes
)?
,
288 MAGIC_VOICE_DATA
=> Some(Self::VoiceDataInterlink(VoiceDataInterlink
::from_bytes(
291 MAGIC_PACKET
=> Some(Self::PacketInterlink(PacketInterlink
::from_bytes(&bytes
)?
)),
292 MAGIC_PING
=> Some(Self::Ping(Ping
::from_bytes(&bytes
)?
)),
293 MAGIC_CONNECT
=> Some(Self::ConnectInterlink(ConnectInterlink
::from_bytes(
296 MAGIC_ACKNOWLEDGE
=> Some(Self::ConnectInterlinkAcknowledge(
297 ConnectInterlinkAcknowledge
::from_bytes(&bytes
)?
,
299 MAGIC_NACK
=> Some(Self::ConnectNack(ConnectNack
::from_bytes(&bytes
)?
)),
300 MAGIC_DISCONNECT
=> Some(Self::DisconnectInterlink(DisconnectInterlink
::from_bytes(
308 define_message
!(VoiceFull
, 54);
309 impl_stream_id
!(VoiceFull
, 4);
310 impl_link_setup
!(VoiceFull
, 6);
311 impl_frame_number
!(VoiceFull
, 34);
312 impl_payload
!(VoiceFull
, 36, 52);
313 impl_trailing_crc_verify
!(VoiceFull
);
315 define_message
!(VoiceHeader
, 36);
316 impl_stream_id
!(VoiceHeader
, 4);
317 impl_link_setup
!(VoiceHeader
, 6);
318 impl_trailing_crc_verify
!(VoiceHeader
);
320 define_message
!(VoiceData
, 26);
321 impl_stream_id
!(VoiceData
, 4);
322 impl_frame_number
!(VoiceData
, 6);
323 impl_payload
!(VoiceData
, 8, 24);
324 impl_trailing_crc_verify
!(VoiceData
);
326 define_message
!(Packet
, 859);
327 impl_link_setup_frame
!(Packet
, 4);
330 pub fn payload(&self) -> &[u8] {
334 pub fn verify_integrity(&self) -> bool
{
335 self.link_setup_frame().check_crc() == 0
336 && self.payload().len() >= 4
337 && crate::crc
::m17_crc(self.payload()) == 0
341 define_message
!(Pong
, 10);
342 impl_address
!(Pong
, 4);
345 define_message
!(Connect
, 11);
346 impl_address
!(Connect
, 4);
347 impl_module
!(Connect
, 10);
350 define_message
!(Listen
, 11);
351 impl_address
!(Listen
, 4);
352 impl_module
!(Listen
, 10);
355 define_message
!(Disconnect
, 10);
356 impl_address
!(Disconnect
, 4);
359 define_message
!(Ping
, 10);
360 impl_address
!(Ping
, 4);
363 define_message
!(DisconnectAcknowledge
, 4);
364 no_crc
!(DisconnectAcknowledge
);
366 define_message
!(ForceDisconnect
, 10);
367 impl_address
!(ForceDisconnect
, 4);
368 no_crc
!(ForceDisconnect
);
370 define_message
!(ConnectAcknowledge
, 4);
371 no_crc
!(ConnectAcknowledge
);
373 define_message
!(ConnectNack
, 4);
374 no_crc
!(ConnectNack
);
376 define_message
!(VoiceInterlink
, 55);
377 impl_stream_id
!(VoiceInterlink
, 4);
378 impl_link_setup
!(VoiceInterlink
, 6);
379 impl_frame_number
!(VoiceInterlink
, 34);
380 impl_payload
!(VoiceInterlink
, 36, 52);
381 impl_internal_crc
!(VoiceInterlink
, 0, 54);
382 impl_is_relayed
!(VoiceInterlink
);
384 define_message
!(VoiceHeaderInterlink
, 37);
385 impl_stream_id
!(VoiceHeaderInterlink
, 4);
386 impl_link_setup
!(VoiceHeaderInterlink
, 6);
387 impl_internal_crc
!(VoiceHeaderInterlink
, 0, 36);
388 impl_is_relayed
!(VoiceHeaderInterlink
);
390 define_message
!(VoiceDataInterlink
, 27);
391 impl_stream_id
!(VoiceDataInterlink
, 4);
392 impl_frame_number
!(VoiceDataInterlink
, 6);
393 impl_payload
!(VoiceDataInterlink
, 8, 24);
394 impl_internal_crc
!(VoiceDataInterlink
, 0, 24);
395 impl_is_relayed
!(VoiceDataInterlink
);
397 define_message
!(PacketInterlink
, 860);
398 impl_link_setup_frame
!(PacketInterlink
, 4);
399 impl_is_relayed
!(PacketInterlink
);
401 impl PacketInterlink
{
402 pub fn payload(&self) -> &[u8] {
403 &self.0[34..(self.0.len() - 1)]
406 pub fn verify_integrity(&self) -> bool
{
407 self.link_setup_frame().check_crc() == 0
408 && self.payload().len() >= 4
409 && crate::crc
::m17_crc(self.payload()) == 0
413 define_message
!(ConnectInterlink
, 37);
414 impl_address
!(ConnectInterlink
, 4);
415 impl_modules
!(ConnectInterlink
, 10, 37);
416 no_crc
!(ConnectInterlink
);
418 define_message
!(ConnectInterlinkAcknowledge
, 37);
419 impl_address
!(ConnectInterlinkAcknowledge
, 4);
420 impl_modules
!(ConnectInterlinkAcknowledge
, 10, 37);
421 no_crc
!(ConnectInterlinkAcknowledge
);
423 define_message
!(DisconnectInterlink
, 10);
424 impl_address
!(DisconnectInterlink
, 4);
425 no_crc
!(DisconnectInterlink
);