]> code.octet-stream.net Git - m17rt/blob - m17core/src/reflector/convert.rs
fd52df87377908b2b3101f230c607c4c56346dbe
[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 #[derive(Debug, Clone)]
66 pub struct RfToVoice {
67 lsf: LsfFrame,
68 stream_id: u16,
69 }
70
71 impl RfToVoice {
72 pub fn new(lsf: LsfFrame) -> Self {
73 Self { lsf, stream_id: 0 }
74 }
75
76 pub fn process_lsf(&mut self, lsf: LsfFrame) {
77 self.lsf = lsf;
78 self.stream_id = self.stream_id.wrapping_add(1);
79 }
80
81 pub fn process_stream(&self, stream: &StreamFrame) -> Voice {
82 let mut v = Voice::new();
83 v.set_stream_id(self.stream_id);
84 v.set_frame_number(stream.frame_number);
85 v.set_end_of_stream(stream.end_of_stream);
86 v.set_payload(&stream.stream_data);
87 v.set_link_setup_frame(&self.lsf);
88 v
89 }
90 }
91
92 #[cfg(test)]
93 mod tests {
94 use crate::{
95 address::{Address, Callsign},
96 protocol::{LsfFrame, StreamFrame},
97 };
98
99 use super::{RfToVoice, VoiceToRf};
100
101 #[test]
102 fn convert_roundtrip() {
103 let lsf = LsfFrame::new_voice(
104 &Address::Callsign(Callsign(*b"VK7XT ")),
105 &Address::Broadcast,
106 );
107 let stream = StreamFrame {
108 lich_idx: 0,
109 lich_part: lsf.0[0..5].try_into().unwrap(),
110 frame_number: 0,
111 end_of_stream: false,
112 stream_data: [1u8; 16],
113 };
114 let rf_to_voice = RfToVoice::new(lsf.clone());
115 let voice = rf_to_voice.process_stream(&stream);
116
117 let mut voice_to_rf = VoiceToRf::new();
118 let (lsf2, stream2) = voice_to_rf.next(&voice);
119 assert_eq!(lsf2, Some(lsf));
120 assert_eq!(stream2, stream);
121 }
122 }