binarygcode/components/
serialiser.rs1use alloc::{boxed::Box, vec::Vec};
2use embedded_heatshrink::{
3 HSEFinishRes, HSEPollRes, HSESinkRes, HeatshrinkEncoder,
4};
5use miniz_oxide::deflate::compress_to_vec_zlib;
6
7use crate::components::common::{
8 crc32, BinaryGcodeError, BlockKind, Checksum, CompressionAlgorithm,
9 Encoding, MAGIC,
10};
11
12pub fn serialise_file_header(
13 version: u32,
14 checksum: Checksum,
15) -> Box<[u8]> {
16 let mut header = Vec::with_capacity(10);
17 header.extend(MAGIC.to_le_bytes());
18 header.extend(version.to_le_bytes());
19 header.extend(checksum.to_le_bytes());
20 header.into_boxed_slice()
21}
22
23pub fn serialise_block(
25 kind: BlockKind,
26 compression: CompressionAlgorithm,
27 encoding: Encoding,
28 checksum: Checksum,
29 additional_parameters: &[u8],
30 data: &[u8],
31) -> Result<Box<[u8]>, BinaryGcodeError> {
32 let mut block: Vec<u8> = Vec::new();
34 block.extend(kind.to_le_bytes());
35 block.extend(compression.to_le_bytes());
36 let uncompressed_len = data.len() as u32;
37 block.extend(uncompressed_len.to_le_bytes());
38
39 let mut parameters: Vec<u8> = Vec::with_capacity(0);
41 parameters.extend(encoding.to_le_bytes());
42 parameters.extend(additional_parameters);
43 match compression {
48 CompressionAlgorithm::None => {
49 block.extend(parameters);
50 block.extend(data);
51 }
52 CompressionAlgorithm::Deflate => {
53 let compressed = compress_to_vec_zlib(data, 10);
54 let compressed_len = compressed.len() as u32;
55 block.extend(compressed_len.to_le_bytes());
56 block.extend(parameters);
57 block.extend(compressed);
58 }
59 CompressionAlgorithm::Heatshrink11_4 => {
60 let compressed = shrink(11, 4, data)?;
61 let compressed_len = compressed.len() as u32;
62 block.extend(compressed_len.to_le_bytes());
63 block.extend(parameters);
64 block.extend(compressed);
65 }
66 CompressionAlgorithm::Heatshrink12_4 => {
67 let compressed = shrink(12, 4, data)?;
68 let compressed_len = compressed.len() as u32;
69 block.extend(compressed_len.to_le_bytes());
70 block.extend(parameters);
71 block.extend(compressed);
72 }
73 }
74
75 if checksum == Checksum::Crc32 {
77 let crc = crc32(&block);
78 block.extend(crc.to_le_bytes());
79 }
80
81 Ok(block.into_boxed_slice())
82}
83
84fn shrink(
89 window: u8,
90 lookahead: u8,
91 input: &[u8],
92) -> Result<Box<[u8]>, BinaryGcodeError> {
93 let mut encoder = HeatshrinkEncoder::new(window, lookahead).unwrap();
94 let mut sunk: usize = 0;
95 let mut polled: usize = 0;
96
97 let mut output = vec![0u8; input.len()];
99
100 while sunk < input.len() {
102 match encoder.sink(&input[sunk..]) {
104 HSESinkRes::Ok(sz) => {
105 sunk += sz;
106 }
107 _ => return Err(BinaryGcodeError::SerialiseError("heatshrink_01")),
108 }
109 loop {
111 match encoder.poll(&mut output[polled..]) {
112 HSEPollRes::Empty(sz) => {
115 polled += sz;
116 if sz == 0 {
117 break;
118 }
119 }
120 _ => {
121 return Err(BinaryGcodeError::SerialiseError(
122 "heatshrink_02",
123 ))
124 }
125 }
126 }
127 }
128
129 loop {
131 match encoder.finish() {
132 HSEFinishRes::Done => break,
133 HSEFinishRes::More => match encoder.poll(&mut output[polled..]) {
134 HSEPollRes::Empty(sz) => polled += sz,
137 _ => {
138 return Err(BinaryGcodeError::SerialiseError(
139 "heatshrink_03",
140 ))
141 }
142 },
143 _ => return Err(BinaryGcodeError::SerialiseError("heatshrink_04")),
144 }
145 }
146
147 output.resize(polled, 0u8);
149 Ok(output.into_boxed_slice())
150}
151
152#[cfg(test)]
153mod test {
154 use super::*;
155 use crate::{
156 Checksum, {DeserialisedResult, Deserialiser},
157 };
158
159 #[test]
160 pub fn serde_gcode_none() {
161 let header = serialise_file_header(1, Checksum::Crc32);
162 let gcode = "M73 P0 R30";
163 let block = serialise_block(
164 BlockKind::GCode,
165 CompressionAlgorithm::None,
166 Encoding::Ascii,
167 Checksum::Crc32,
168 &[],
169 gcode.as_bytes(),
170 )
171 .unwrap();
172 let mut deserialiser = Deserialiser::default();
173 deserialiser.digest(&header);
174 deserialiser.digest(&block);
175 loop {
176 let r = deserialiser.deserialise().unwrap();
177 match r {
178 DeserialisedResult::FileHeader(_) => {}
179 DeserialisedResult::Block(_) => {}
180 DeserialisedResult::MoreBytesRequired(_) => {
181 break;
182 }
183 }
184 }
185 }
186
187 #[test]
188 pub fn serde_gcode_deflate() {
189 let header = serialise_file_header(1, Checksum::Crc32);
190 let gcode = "M73 P0 R30";
191 let block = serialise_block(
192 BlockKind::GCode,
193 CompressionAlgorithm::Deflate,
194 Encoding::Ascii,
195 Checksum::Crc32,
196 &[],
197 gcode.as_bytes(),
198 )
199 .unwrap();
200 let mut deserialiser = Deserialiser::default();
201 deserialiser.digest(&header);
202 deserialiser.digest(&block);
203 loop {
204 let r = deserialiser.deserialise().unwrap();
205 match r {
206 DeserialisedResult::FileHeader(_) => {}
207 DeserialisedResult::Block(_) => {}
208 DeserialisedResult::MoreBytesRequired(_) => {
209 break;
210 }
211 }
212 }
213 }
214
215 #[test]
216 pub fn serde_gcode_deflate_no_crc() {
217 let header = serialise_file_header(1, Checksum::None);
218 let gcode = "M73 P0 R30";
219 let block = serialise_block(
220 BlockKind::GCode,
221 CompressionAlgorithm::Deflate,
222 Encoding::Ascii,
223 Checksum::None,
224 &[],
225 gcode.as_bytes(),
226 )
227 .unwrap();
228 let mut deserialiser = Deserialiser::default();
229 deserialiser.digest(&header);
230 deserialiser.digest(&block);
231 loop {
232 let r = deserialiser.deserialise().unwrap();
233 match r {
234 DeserialisedResult::FileHeader(_) => {}
235 DeserialisedResult::Block(_) => {}
236 DeserialisedResult::MoreBytesRequired(_) => {
237 break;
238 }
239 }
240 }
241 }
242}