]> code.octet-stream.net Git - m17rt/blob - m17core/src/reflector/convert.rs
Fix clippy lints
[m17rt] / m17core / src / reflector / convert.rs
1 //! Utilities for converting streams between UDP and RF representations
2
3 use crate::protocol::{LsfFrame, StreamFrame};
4
5 use super::packet::Voice;
6
7 /// Accepts `Voice` packets from a reflector and turns them into LSF and Stream frames.
8 ///
9 /// This is the format required for the voice data to cross the KISS protocol boundary.
10 #[derive(Debug, Default)]
11 pub struct VoiceToRf {
12 /// Link Setup most recently acquired
13 lsf: Option<LsfFrame>,
14 /// Which LICH part we are going to emit next, 0-5
15 lich_cnt: usize,
16 }
17
18 impl VoiceToRf {
19 pub fn new() -> Self {
20 Self {
21 lsf: None,
22 lich_cnt: 0,
23 }
24 }
25
26 /// For a Voice packet received from a reflector, return the frames that would be transmitted
27 /// on RF, including by reconstructing the LICH parts of the stream frame.
28 ///
29 /// If this is the start of a new or different stream transmission, this returns the Link Setup
30 /// Frame which comes first, then the first associated Stream frame.
31 ///
32 /// If this is a continuation of a transmission matching the previous LSF, then it returns only
33 /// the Stream frame.
34 pub fn next(&mut self, voice: &Voice) -> (Option<LsfFrame>, StreamFrame) {
35 let this_lsf = voice.link_setup_frame();
36 let emit_lsf = if Some(&this_lsf) != self.lsf.as_ref() {
37 self.lsf = Some(this_lsf.clone());
38 self.lich_cnt = 0;
39 true
40 } else {
41 false
42 };
43 let lsf = self.lsf.as_ref().unwrap();
44 let stream = StreamFrame {
45 lich_idx: self.lich_cnt as u8,
46 lich_part: (&lsf.0[self.lich_cnt * 5..(self.lich_cnt + 1) * 5])
47 .try_into()
48 .unwrap(),
49 frame_number: voice.frame_number(),
50 end_of_stream: voice.is_end_of_stream(),
51 stream_data: voice.payload().try_into().unwrap(),
52 };
53 let lsf = if emit_lsf { self.lsf.clone() } else { None };
54 if voice.is_end_of_stream() {
55 self.lsf = None;
56 }
57 (lsf, stream)
58 }
59 }
60
61 /// Accepts LSF and stream RF payloads and merges them into `Voice` packets for reflector use.
62 ///
63 /// For a series of transmissions this object should be re-used so that Stream ID is correctly
64 /// changed after each new LSF.
65 pub struct RfToVoice {
66 lsf: LsfFrame,
67 stream_id: u16,
68 }
69
70 impl RfToVoice {
71 pub fn new(lsf: LsfFrame) -> Self {
72 Self { lsf, stream_id: 0 }
73 }
74
75 pub fn process_lsf(&mut self, lsf: LsfFrame) {
76 self.lsf = lsf;
77 self.stream_id = self.stream_id.wrapping_add(1);
78 }
79
80 pub fn process_stream(&self, stream: &StreamFrame) -> Voice {
81 let mut v = Voice::new();
82 v.set_stream_id(self.stream_id);
83 v.set_frame_number(stream.frame_number);
84 v.set_end_of_stream(stream.end_of_stream);
85 v.set_payload(&stream.stream_data);
86 v.set_link_setup_frame(&self.lsf);
87 v
88 }
89 }
90
91 #[cfg(test)]
92 mod tests {
93 use crate::{
94 address::{Address, Callsign},
95 protocol::{LsfFrame, StreamFrame},
96 };
97
98 use super::{RfToVoice, VoiceToRf};
99
100 #[test]
101 fn convert_roundtrip() {
102 let lsf = LsfFrame::new_voice(
103 &Address::Callsign(Callsign(*b"VK7XT ")),
104 &Address::Broadcast,
105 );
106 let stream = StreamFrame {
107 lich_idx: 0,
108 lich_part: lsf.0[0..5].try_into().unwrap(),
109 frame_number: 0,
110 end_of_stream: false,
111 stream_data: [1u8; 16],
112 };
113 let rf_to_voice = RfToVoice::new(lsf.clone());
114 let voice = rf_to_voice.process_stream(&stream);
115
116 let mut voice_to_rf = VoiceToRf::new();
117 let (lsf2, stream2) = voice_to_rf.next(&voice);
118 assert_eq!(lsf2, Some(lsf));
119 assert_eq!(stream2, stream);
120 }
121 }