1 // Based on https://github.com/n7tae/mrefd/blob/master/Packet-Description.md
2 // and the main M17 specification
4 use crate::address
::Address
;
5 use crate::protocol
::LsfFrame
;
7 macro_rules
! define_message
{
8 ($t
:tt
, $sz
:tt
, $min_sz
:tt
, $magic
:tt
) => {
9 pub struct $
t(pub [u8; $sz
], pub usize);
12 pub fn new() -> Self {
13 let mut bytes
= [0u8; $sz
];
14 bytes
[0..4].copy_from_slice($magic
);
18 #[allow(clippy::double_comparisons)] // occurs in some macro invocations
19 #[allow(clippy::manual_range_contains)] // way more readable, good grief
20 pub fn from_bytes(b
: &[u8]) -> Option
<Self> {
22 if len
> $sz
|| len
< $min_sz
{
25 let mut s
= Self([0; $sz
], len
);
26 s
.0[0..len
].copy_from_slice(b
);
27 if !s
.verify_integrity() {
33 pub fn as_bytes(&self) -> &[u8] {
39 fn default() -> Self {
46 macro_rules
! impl_stream_id
{
47 ($t
:ty
, $from
:tt
) => {
49 pub fn stream_id(&self) -> u16 {
50 u16::from_be_bytes([self.0[$from
], self.0[$from
+ 1]])
53 pub fn set_stream_id(&mut self, id
: u16) {
54 let bytes
= id
.to_be_bytes();
55 self.0[$from
] = bytes
[0];
56 self.0[$from
+ 1] = bytes
[1];
57 self.recalculate_crc();
63 macro_rules
! impl_link_setup
{
64 ($t
:ty
, $from
:tt
) => {
66 pub fn link_setup_frame(&self) -> LsfFrame
{
67 let mut frame
= LsfFrame([0; 30]);
68 frame
.0[0..28].copy_from_slice(&self.0[$from
..($from
+ 28)]);
69 frame
.recalculate_crc();
73 pub fn set_link_setup_frame(&mut self, lsf
: &LsfFrame
) {
74 self.0[$from
..($from
+ 28)].copy_from_slice(&lsf
.0[0..28]);
75 self.recalculate_crc();
81 macro_rules
! impl_link_setup_frame
{
82 ($t
:ty
, $from
:tt
) => {
84 pub fn link_setup_frame(&self) -> LsfFrame
{
85 let mut frame
= LsfFrame([0; 30]);
86 frame
.0[..].copy_from_slice(&self.0[$from
..($from
+ 30)]);
90 pub fn set_link_setup_frame(&mut self, lsf
: &LsfFrame
) {
91 debug_assert_eq
!(lsf
.check_crc(), 0);
92 self.0[$from
..($from
+ 30)].copy_from_slice(&lsf
.0);
93 self.recalculate_crc();
99 macro_rules
! impl_frame_number
{
100 ($t
:ty
, $from
:tt
) => {
102 pub fn frame_number(&self) -> u16 {
103 let frame_num
= u16::from_be_bytes([self.0[$from
], self.0[$from
+ 1]]);
107 pub fn is_end_of_stream(&self) -> bool
{
108 let frame_num
= u16::from_be_bytes([self.0[$from
], self.0[$from
+ 1]]);
109 (frame_num
& 0x8000) > 0
112 pub fn set_frame_number(&mut self, number
: u16) {
113 let existing_eos
= u16::from_be_bytes([self.0[$from
], self.0[$from
+ 1]]) & 0x8000;
114 let new
= (existing_eos
| (number
& 0x7fff)).to_be_bytes();
115 self.0[$from
] = new
[0];
116 self.0[$from
+ 1] = new
[1];
117 self.recalculate_crc();
120 pub fn set_end_of_stream(&mut self, eos
: bool
) {
121 let existing_fn
= u16::from_be_bytes([self.0[$from
], self.0[$from
+ 1]]) & 0x7fff;
122 let new
= (existing_fn
| (if eos
{ 0x8000 } else { 0 })).to_be_bytes();
123 self.0[$from
] = new
[0];
124 self.0[$from
+ 1] = new
[1];
125 self.recalculate_crc();
131 macro_rules
! impl_payload
{
132 ($t
:ty
, $from
:tt
, $to
:tt
) => {
134 pub fn payload(&self) -> &[u8] {
138 pub fn set_payload(&mut self, bytes
: &[u8]) {
139 self.0[$from
..$to
].copy_from_slice(bytes
);
140 self.recalculate_crc();
146 macro_rules
! impl_modules
{
147 ($t
:ty
, $from
:tt
, $to
:tt
) => {
149 pub fn modules(&self) -> ModulesIterator
{
150 ModulesIterator
::new(&self.0[$from
..$to
])
153 pub fn set_modules(&mut self, list
: &str) {
154 debug_assert
!(list
.len() < 27);
156 for m
in list
.chars() {
157 self.0[idx
] = m
as u8;
161 self.recalculate_crc();
167 macro_rules
! impl_module
{
170 pub fn module(&self) -> char {
174 pub fn set_module(&mut self, m
: char) {
175 self.0[$at
] = m
as u8;
176 self.recalculate_crc();
182 macro_rules
! impl_address
{
183 ($t
:ty
, $from
:tt
) => {
185 pub fn address(&self) -> Address
{
186 crate::address
::decode_address(self.0[$from
..($from
+ 6)].try_into().unwrap
())
189 pub fn set_address(&mut self, address
: Address
) {
190 let encoded
= crate::address
::encode_address(&address
);
191 self.0[$from
..($from
+ 6)].copy_from_slice(&encoded
);
192 self.recalculate_crc();
198 macro_rules
! impl_trailing_crc_verify
{
201 pub fn verify_integrity(&self) -> bool
{
202 crate::crc
::m17_crc(&self.0) == 0
205 pub fn recalculate_crc(&mut self) {
206 let len
= self.0.len();
207 let start_crc
= crate::crc
::m17_crc(&self.0[0..(len
- 2)]).to_be_bytes();
208 self.0[len
- 2] = start_crc
[0];
209 self.0[len
- 1] = start_crc
[1];
210 debug_assert
!(self.verify_integrity());
216 macro_rules
! impl_internal_crc
{
217 ($t
:ty
, $from
:tt
, $to
:tt
) => {
219 pub fn verify_integrity(&self) -> bool
{
220 crate::crc
::m17_crc(&self.0[$from
..$to
]) == 0
223 pub fn recalculate_crc(&mut self) {
224 // assume the last two bytes of the range are the CRC
225 let start_crc
= crate::crc
::m17_crc(&self.0[$from
..($to
- 2)]).to_be_bytes();
226 self.0[$to
- 2] = start_crc
[0];
227 self.0[$to
- 1] = start_crc
[1];
228 debug_assert
!(self.verify_integrity());
234 macro_rules
! no_crc
{
237 pub fn verify_integrity(&self) -> bool
{
240 pub fn recalculate_crc(&mut self) {}
245 macro_rules
! impl_is_relayed
{
248 pub fn is_relayed(&self) -> bool
{
249 self.0[self.0.len() - 1] != 0
252 pub fn set_relayed(&mut self, relayed
: bool
) {
253 self.0[self.0.len() - 1] = if relayed
{ 1 } else { 0 };
254 self.recalculate_crc();
260 pub struct ModulesIterator
<'a
> {
265 impl<'a
> ModulesIterator
<'a
> {
266 fn new(modules
: &'a
[u8]) -> Self {
267 Self { modules
, idx
: 0 }
271 impl Iterator
for ModulesIterator
<'_
> {
274 fn next(&mut self) -> Option
<Self::Item
> {
275 if self.idx
< self.modules
.len() {
276 if self.modules
[self.idx
] == 0 {
280 return Some(self.modules
[self.idx
- 1] as char);
286 pub const MAGIC_VOICE
: &[u8] = b
"M17 ";
287 pub const MAGIC_VOICE_HEADER
: &[u8] = b
"M17H";
288 pub const MAGIC_VOICE_DATA
: &[u8] = b
"M17D";
289 pub const MAGIC_PACKET
: &[u8] = b
"M17P";
290 pub const MAGIC_ACKNOWLEDGE
: &[u8] = b
"ACKN";
291 pub const MAGIC_CONNECT
: &[u8] = b
"CONN";
292 pub const MAGIC_DISCONNECT
: &[u8] = b
"DISC";
293 pub const MAGIC_LISTEN
: &[u8] = b
"LSTN";
294 pub const MAGIC_NACK
: &[u8] = b
"NACK";
295 pub const MAGIC_PING
: &[u8] = b
"PING";
296 pub const MAGIC_PONG
: &[u8] = b
"PONG";
298 /// Messages sent from a station/client to a reflector
299 #[allow(clippy::large_enum_variant)]
300 pub enum ClientMessage
{
302 VoiceHeader(VoiceHeader
),
303 VoiceData(VoiceData
),
308 Disconnect(Disconnect
),
312 pub fn parse(bytes
: &[u8]) -> Option
<Self> {
317 MAGIC_VOICE
=> Some(Self::Voice(Voice
::from_bytes(bytes
)?
)),
318 MAGIC_VOICE_HEADER
=> Some(Self::VoiceHeader(VoiceHeader
::from_bytes(bytes
)?
)),
319 MAGIC_VOICE_DATA
=> Some(Self::VoiceData(VoiceData
::from_bytes(bytes
)?
)),
320 MAGIC_PACKET
=> Some(Self::Packet(Packet
::from_bytes(bytes
)?
)),
321 MAGIC_PONG
=> Some(Self::Pong(Pong
::from_bytes(bytes
)?
)),
322 MAGIC_CONNECT
=> Some(Self::Connect(Connect
::from_bytes(bytes
)?
)),
323 MAGIC_LISTEN
=> Some(Self::Listen(Listen
::from_bytes(bytes
)?
)),
324 MAGIC_DISCONNECT
=> Some(Self::Disconnect(Disconnect
::from_bytes(bytes
)?
)),
330 /// Messages sent from a reflector to a station/client
331 #[allow(clippy::large_enum_variant)]
332 pub enum ServerMessage
{
334 VoiceHeader(VoiceHeader
),
335 VoiceData(VoiceData
),
338 DisconnectAcknowledge(DisconnectAcknowledge
),
339 ForceDisconnect(ForceDisconnect
),
340 ConnectAcknowledge(ConnectAcknowledge
),
341 ConnectNack(ConnectNack
),
345 pub fn parse(bytes
: &[u8]) -> Option
<Self> {
350 MAGIC_VOICE
=> Some(Self::Voice(Voice
::from_bytes(bytes
)?
)),
351 MAGIC_VOICE_HEADER
=> Some(Self::VoiceHeader(VoiceHeader
::from_bytes(bytes
)?
)),
352 MAGIC_VOICE_DATA
=> Some(Self::VoiceData(VoiceData
::from_bytes(bytes
)?
)),
353 MAGIC_PACKET
=> Some(Self::Packet(Packet
::from_bytes(bytes
)?
)),
354 MAGIC_PING
=> Some(Self::Ping(Ping
::from_bytes(bytes
)?
)),
355 MAGIC_DISCONNECT
if bytes
.len() == 4 => Some(Self::DisconnectAcknowledge(
356 DisconnectAcknowledge
::from_bytes(bytes
)?
,
358 MAGIC_DISCONNECT
=> Some(Self::ForceDisconnect(ForceDisconnect
::from_bytes(bytes
)?
)),
359 MAGIC_ACKNOWLEDGE
=> Some(Self::ConnectAcknowledge(ConnectAcknowledge
::from_bytes(
362 MAGIC_NACK
=> Some(Self::ConnectNack(ConnectNack
::from_bytes(bytes
)?
)),
368 /// Messages sent and received between reflectors
369 #[allow(clippy::large_enum_variant)]
370 pub enum InterlinkMessage
{
371 VoiceInterlink(VoiceInterlink
),
372 VoiceHeaderInterlink(VoiceHeaderInterlink
),
373 VoiceDataInterlink(VoiceDataInterlink
),
374 PacketInterlink(PacketInterlink
),
376 ConnectInterlink(ConnectInterlink
),
377 ConnectInterlinkAcknowledge(ConnectInterlinkAcknowledge
),
378 ConnectNack(ConnectNack
),
379 DisconnectInterlink(DisconnectInterlink
),
382 impl InterlinkMessage
{
383 pub fn parse(bytes
: &[u8]) -> Option
<Self> {
388 MAGIC_VOICE
=> Some(Self::VoiceInterlink(VoiceInterlink
::from_bytes(bytes
)?
)),
389 MAGIC_VOICE_HEADER
=> Some(Self::VoiceHeaderInterlink(
390 VoiceHeaderInterlink
::from_bytes(bytes
)?
,
392 MAGIC_VOICE_DATA
=> Some(Self::VoiceDataInterlink(VoiceDataInterlink
::from_bytes(
395 MAGIC_PACKET
=> Some(Self::PacketInterlink(PacketInterlink
::from_bytes(bytes
)?
)),
396 MAGIC_PING
=> Some(Self::Ping(Ping
::from_bytes(bytes
)?
)),
397 MAGIC_CONNECT
=> Some(Self::ConnectInterlink(ConnectInterlink
::from_bytes(bytes
)?
)),
398 MAGIC_ACKNOWLEDGE
=> Some(Self::ConnectInterlinkAcknowledge(
399 ConnectInterlinkAcknowledge
::from_bytes(bytes
)?
,
401 MAGIC_NACK
=> Some(Self::ConnectNack(ConnectNack
::from_bytes(bytes
)?
)),
402 MAGIC_DISCONNECT
=> Some(Self::DisconnectInterlink(DisconnectInterlink
::from_bytes(
410 define_message
!(Voice
, 54, 54, MAGIC_VOICE
);
411 impl_stream_id
!(Voice
, 4);
412 impl_link_setup
!(Voice
, 6);
413 impl_frame_number
!(Voice
, 34);
414 impl_payload
!(Voice
, 36, 52);
415 impl_trailing_crc_verify
!(Voice
);
417 define_message
!(VoiceHeader
, 36, 36, MAGIC_VOICE_HEADER
);
418 impl_stream_id
!(VoiceHeader
, 4);
419 impl_link_setup
!(VoiceHeader
, 6);
420 impl_trailing_crc_verify
!(VoiceHeader
);
422 define_message
!(VoiceData
, 26, 26, MAGIC_VOICE_DATA
);
423 impl_stream_id
!(VoiceData
, 4);
424 impl_frame_number
!(VoiceData
, 6);
425 impl_payload
!(VoiceData
, 8, 24);
426 impl_trailing_crc_verify
!(VoiceData
);
428 define_message
!(Packet
, 859, 38, MAGIC_PACKET
);
429 impl_link_setup_frame
!(Packet
, 4);
432 pub fn payload(&self) -> &[u8] {
436 pub fn set_payload(&mut self, bytes
: &[u8]) {
437 let end
= 34 + bytes
.len();
438 self.0[34..end
].copy_from_slice(bytes
);
442 pub fn verify_integrity(&self) -> bool
{
443 self.link_setup_frame().check_crc() == 0
444 && self.payload().len() >= 4
445 && crate::crc
::m17_crc(self.payload()) == 0
448 pub fn recalculate_crc(&mut self) {
449 // LSF and payload should be confirmed valid before construction
453 define_message
!(Pong
, 10, 10, MAGIC_PONG
);
454 impl_address
!(Pong
, 4);
457 define_message
!(Connect
, 11, 11, MAGIC_CONNECT
);
458 impl_address
!(Connect
, 4);
459 impl_module
!(Connect
, 10);
462 define_message
!(Listen
, 11, 11, MAGIC_LISTEN
);
463 impl_address
!(Listen
, 4);
464 impl_module
!(Listen
, 10);
467 define_message
!(Disconnect
, 10, 10, MAGIC_DISCONNECT
);
468 impl_address
!(Disconnect
, 4);
471 define_message
!(Ping
, 10, 10, MAGIC_PING
);
472 impl_address
!(Ping
, 4);
475 define_message
!(DisconnectAcknowledge
, 4, 4, MAGIC_DISCONNECT
);
476 no_crc
!(DisconnectAcknowledge
);
478 define_message
!(ForceDisconnect
, 10, 10, MAGIC_DISCONNECT
);
479 impl_address
!(ForceDisconnect
, 4);
480 no_crc
!(ForceDisconnect
);
482 define_message
!(ConnectAcknowledge
, 4, 4, MAGIC_ACKNOWLEDGE
);
483 no_crc
!(ConnectAcknowledge
);
485 define_message
!(ConnectNack
, 4, 4, MAGIC_NACK
);
486 no_crc
!(ConnectNack
);
488 define_message
!(VoiceInterlink
, 55, 55, MAGIC_VOICE
);
489 impl_stream_id
!(VoiceInterlink
, 4);
490 impl_link_setup
!(VoiceInterlink
, 6);
491 impl_frame_number
!(VoiceInterlink
, 34);
492 impl_payload
!(VoiceInterlink
, 36, 52);
493 impl_internal_crc
!(VoiceInterlink
, 0, 54);
494 impl_is_relayed
!(VoiceInterlink
);
496 define_message
!(VoiceHeaderInterlink
, 37, 37, MAGIC_VOICE_HEADER
);
497 impl_stream_id
!(VoiceHeaderInterlink
, 4);
498 impl_link_setup
!(VoiceHeaderInterlink
, 6);
499 impl_internal_crc
!(VoiceHeaderInterlink
, 0, 36);
500 impl_is_relayed
!(VoiceHeaderInterlink
);
502 define_message
!(VoiceDataInterlink
, 27, 27, MAGIC_VOICE_DATA
);
503 impl_stream_id
!(VoiceDataInterlink
, 4);
504 impl_frame_number
!(VoiceDataInterlink
, 6);
505 impl_payload
!(VoiceDataInterlink
, 8, 24);
506 impl_internal_crc
!(VoiceDataInterlink
, 0, 24);
507 impl_is_relayed
!(VoiceDataInterlink
);
509 define_message
!(PacketInterlink
, 860, 39, MAGIC_PACKET
);
510 impl_link_setup_frame
!(PacketInterlink
, 4);
511 impl_is_relayed
!(PacketInterlink
);
513 impl PacketInterlink
{
514 pub fn payload(&self) -> &[u8] {
515 &self.0[34..(self.1 - 1)]
518 pub fn set_payload(&mut self, bytes
: &[u8]) {
519 let is_relayed
= self.is
_relayed
();
520 let end
= 34 + bytes
.len();
521 self.0[34..end
].copy_from_slice(bytes
);
523 self.set_relayed(is_relayed
);
526 pub fn verify_integrity(&self) -> bool
{
527 self.link_setup_frame().check_crc() == 0
528 && self.payload().len() >= 4
529 && crate::crc
::m17_crc(self.payload()) == 0
532 pub fn recalculate_crc(&mut self) {
533 // LSF and payload should be confirmed valid before construction
537 define_message
!(ConnectInterlink
, 37, 37, MAGIC_CONNECT
);
538 impl_address
!(ConnectInterlink
, 4);
539 impl_modules
!(ConnectInterlink
, 10, 37);
540 no_crc
!(ConnectInterlink
);
542 define_message
!(ConnectInterlinkAcknowledge
, 37, 37, MAGIC_ACKNOWLEDGE
);
543 impl_address
!(ConnectInterlinkAcknowledge
, 4);
544 impl_modules
!(ConnectInterlinkAcknowledge
, 10, 37);
545 no_crc
!(ConnectInterlinkAcknowledge
);
547 define_message
!(DisconnectInterlink
, 10, 10, MAGIC_DISCONNECT
);
548 impl_address
!(DisconnectInterlink
, 4);
549 no_crc
!(DisconnectInterlink
);