1pub const SERVICE: &str = "03b80e5a-ede8-4b33-a751-6ce34ec4c700";
14pub const CHARACTERISTIC: &str = "7772e5db-3868-4112-a1a9-f2669d106bf3";
15
16pub const MIN_PACKET: usize = 20;
18
19fn header(ts: u16) -> u8 {
20 0x80 | ((ts >> 7) & 0x3F) as u8
21}
22
23fn stamp(ts: u16) -> u8 {
24 0x80 | (ts & 0x7F) as u8
25}
26
27pub fn encode(msgs: &[Vec<u8>], ts_ms: u16, max: usize) -> Vec<Vec<u8>> {
30 let max = max.max(5);
31 let (h, t) = (header(ts_ms), stamp(ts_ms));
32 let mut out = vec![];
33 let mut cur = vec![h];
34 let flush = |cur: &mut Vec<u8>, out: &mut Vec<Vec<u8>>| {
35 if cur.len() > 1 {
36 out.push(std::mem::replace(cur, vec![h]));
37 }
38 };
39 for m in msgs {
40 if m.is_empty() {
41 continue;
42 }
43 if m[0] == 0xF0 {
44 if cur.len() + 3 > max {
46 flush(&mut cur, &mut out);
47 }
48 cur.extend([t, 0xF0]);
49 let end = m.last() == Some(&0xF7);
50 let data = &m[1..m.len() - end as usize];
51 for &b in data {
52 if cur.len() + 1 > max {
53 out.push(std::mem::replace(&mut cur, vec![h]));
54 }
55 cur.push(b);
56 }
57 if end {
58 if cur.len() + 2 > max {
59 out.push(std::mem::replace(&mut cur, vec![h]));
60 }
61 cur.extend([t, 0xF7]);
62 }
63 } else {
64 if cur.len() + 1 + m.len() > max {
65 flush(&mut cur, &mut out);
66 }
67 cur.push(t);
68 cur.extend_from_slice(m);
69 }
70 }
71 flush(&mut cur, &mut out);
72 out
73}
74
75fn data_len(status: u8) -> usize {
77 match status {
78 0xF1 | 0xF3 => 1,
79 0xF2 => 2,
80 0xF0..=0xFF => 0,
81 s if s & 0xF0 == 0xC0 || s & 0xF0 == 0xD0 => 1,
82 _ => 2,
83 }
84}
85
86#[derive(Default)]
89pub struct Decoder {
90 sysex: Option<Vec<u8>>,
91 running: Option<u8>,
92 msg: Vec<u8>,
93}
94
95impl Decoder {
96 pub fn push(&mut self, packet: &[u8]) -> Vec<Vec<u8>> {
97 let mut out = vec![];
98 if packet.first().is_none_or(|h| h & 0x80 == 0) {
99 return out;
100 }
101 let mut i = 1;
102 while i < packet.len() {
103 let b = packet[i];
104 if b & 0x80 == 0 {
105 self.data(b, &mut out);
106 i += 1;
107 continue;
108 }
109 i += 1;
111 let Some(&s) = packet.get(i) else { break };
112 if s & 0x80 == 0 {
113 continue;
114 }
115 i += 1;
116 match s {
117 0xF7 => {
118 if let Some(mut x) = self.sysex.take() {
119 x.push(0xF7);
120 out.push(x);
121 }
122 }
123 0xF0 => {
124 self.sysex = Some(vec![0xF0]);
125 self.running = None;
126 }
127 0xF8..=0xFF => out.push(vec![s]),
128 _ => {
129 self.sysex = None;
130 self.running = (s < 0xF0).then_some(s);
131 self.msg = vec![s];
132 if data_len(s) == 0 {
133 out.push(std::mem::take(&mut self.msg));
134 }
135 }
136 }
137 }
138 out
139 }
140
141 fn data(&mut self, b: u8, out: &mut Vec<Vec<u8>>) {
142 if let Some(x) = &mut self.sysex {
143 x.push(b);
144 return;
145 }
146 if self.msg.is_empty() {
147 match self.running {
148 Some(r) => self.msg.push(r),
149 None => return,
150 }
151 }
152 self.msg.push(b);
153 if self.msg.len() == 1 + data_len(self.msg[0]) {
154 out.push(std::mem::take(&mut self.msg));
155 }
156 }
157}
158
159#[cfg(test)]
160mod tests {
161 use super::*;
162
163 fn decode_all(packets: &[Vec<u8>]) -> Vec<Vec<u8>> {
164 let mut d = Decoder::default();
165 packets.iter().flat_map(|p| d.push(p)).collect()
166 }
167
168 #[test]
169 fn pedal_replies() {
170 let p = [
172 0x99, 0xE4, 0xF0, 0x00, 0x21, 0x7A, 0x10, 0x56, 0x31, 0x2E, 0x31, 0x2E, 0x31, 0x00, 0x4A, 0x4D, 0x45, 0xE4,
173 0xF7,
174 ];
175 assert_eq!(
176 decode_all(&[p.to_vec(), vec![0xA0, 0x81, 0xB0, 0x3B, 0x02]]),
177 vec![
178 vec![0xF0, 0x00, 0x21, 0x7A, 0x10, 0x56, 0x31, 0x2E, 0x31, 0x2E, 0x31, 0x00, 0x4A, 0x4D, 0x45, 0xF7],
179 vec![0xB0, 0x3B, 0x02],
180 ]
181 );
182 }
183
184 #[test]
185 fn host_request_matches_probe() {
186 let ts = (0x19 << 7) | 0x50;
188 assert_eq!(
189 encode(&[vec![0xF0, 0x00, 0x21, 0x7A, 0x00, 0xF7]], ts, 182),
190 vec![vec![0x99, 0xD0, 0xF0, 0x00, 0x21, 0x7A, 0x00, 0xD0, 0xF7]]
191 );
192 }
193
194 #[test]
195 fn running_status() {
196 let p = vec![0x80, 0x81, 0xB0, 0x12, 0x40, 0x82, 0x13, 0x41, 0x14, 0x42];
198 assert_eq!(decode_all(&[p]), vec![vec![0xB0, 0x12, 0x40], vec![0xB0, 0x13, 0x41], vec![0xB0, 0x14, 0x42]]);
199 }
200
201 #[test]
202 fn realtime_inside_sysex() {
203 let p = vec![0x80, 0x81, 0xF0, 0x01, 0x02, 0x82, 0xF8, 0x03, 0x83, 0xF7];
204 assert_eq!(decode_all(&[p]), vec![vec![0xF8], vec![0xF0, 0x01, 0x02, 0x03, 0xF7]]);
205 }
206
207 #[test]
208 fn round_trip_split() {
209 let big: Vec<u8> = [0xF0].into_iter().chain((0..300).map(|i| (i % 128) as u8)).chain([0xF7]).collect();
210 let msgs = vec![vec![0xB1, 0x05, 0x03], big, vec![0xC1, 0x04], vec![0xF0, 0x7E, 0xF7]];
211 for max in [5, 6, 7, 20, 179] {
212 let packets = encode(&msgs, 0x1ABC, max);
213 assert!(packets.iter().all(|p| p.len() <= max && p.len() > 1), "max {max}");
214 assert_eq!(decode_all(&packets), msgs, "max {max}");
215 }
216 assert_eq!(encode(&msgs[..1], 0, 20).len(), 1);
217 assert_eq!(
219 encode(&[vec![0xB1, 1, 2], vec![0xB1, 3, 4]], 0, 20),
220 vec![vec![0x80, 0x80, 0xB1, 1, 2, 0x80, 0xB1, 3, 4]]
221 );
222 }
223}