gcode_nom/binary/thumbnail_block/
mod.rs1use core::fmt::Display;
2use std::fmt::Write;
3
4use super::{
5 block_header::{block_header_parser, BlockHeader},
6 BlockError,
7};
8
9use nom::{
10 bytes::streaming::take,
11 combinator::verify,
12 error::Error,
13 number::streaming::{le_u16, le_u32},
14 sequence::preceded,
15 IResult, Parser,
16};
17
18mod param;
19use param::param_parser;
20use param::Param;
21
22use crate::binary::{CompressionType, Markdown};
23
24#[derive(Clone, Debug, PartialEq, Eq)]
25pub struct ThumbnailBlock<'a> {
26 header: BlockHeader,
27 pub param: Param,
28 pub data: &'a [u8],
29 checksum: Option<u32>,
30}
31impl Display for ThumbnailBlock<'_> {
32 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
33 writeln!(
34 f,
35 "-------------------------- ThumbnailBlock --------------------------"
36 )?;
37 writeln!(f)?;
38 writeln!(f, "Params")?;
39 writeln!(f, "{}", self.param)?;
40 writeln!(f, "DataBlock omitted")?;
41 writeln!(f)?;
42 write!(f, "-------------------------- ThumbnailBlock ")?;
43 match self.checksum {
44 Some(checksum) => writeln!(f, "Checksum Ox{checksum:X} ---------")?,
45 None => writeln!(f, "No checksum")?,
46 }
47 Ok(())
48 }
49}
50
51impl Markdown for Vec<ThumbnailBlock<'_>> {
52 fn markdown<W>(&self, f: &mut W) -> core::fmt::Result
54 where
55 W: Write,
56 {
57 writeln!(f)?;
58 writeln!(f, "## ThumbnailBlocks")?;
59 for (i, thumbnail) in self.iter().enumerate() {
60 writeln!(f)?;
63 writeln!(f, "### ThumbnailBlock {i}")?;
64 writeln!(f)?;
65 thumbnail.headless_markdown(f)?;
66 }
67 Ok(())
68 }
69}
70
71impl ThumbnailBlock<'_> {
72 pub(super) fn headless_markdown<W>(&self, f: &mut W) -> core::fmt::Result
74 where
75 W: Write,
76 {
77 writeln!(f, "### Params")?;
78 writeln!(f)?;
79 writeln!(f, "{}", self.param)?;
80 writeln!(f, "DataBlock omitted")?;
81 writeln!(f)?;
82 match self.checksum {
83 Some(checksum) => writeln!(f, "Checksum Ox{checksum:X}")?,
84 None => writeln!(f, "No checksum")?,
85 }
86 Ok(())
87 }
88}
89
90static THUMBNAIL_BLOCK_ID: u16 = 5u16;
91pub fn thumbnail_parser(input: &[u8]) -> IResult<&[u8], ThumbnailBlock<'_>, BlockError> {
92 let (after_block_header, header) = preceded(
93 verify(le_u16, |block_type| {
94 log::debug!(
95 "Looking for THUMBNAIL_BLOCK_ID {THUMBNAIL_BLOCK_ID} found {block_type} cond {}",
96 *block_type == THUMBNAIL_BLOCK_ID
97 );
98 *block_type == THUMBNAIL_BLOCK_ID
99 }),
100 block_header_parser,
101 )
102 .parse(input)
103 .map_err(|e| e.map(|_e| BlockError::Thumbnail))?;
104
105 log::info!("Found thumbnail block id");
106
107 let (after_param, param) =
108 param_parser(after_block_header).map_err(|e| e.map(|_e| BlockError::Thumbnail))?;
109
110 let (after_data, data) = match header.compressed_size {
112 Some(size) => take(size)(after_param)?,
113 None => take(header.uncompressed_size)(after_param)?,
114 };
115
116 let (after_checksum, checksum) =
117 le_u32(after_data).map_err(|e| e.map(|_e: Error<_>| BlockError::Thumbnail))?;
118
119 Ok((
120 after_checksum,
121 ThumbnailBlock {
122 header,
123 param,
124 data,
125 checksum: Some(checksum),
126 },
127 ))
128}
129
130pub fn thumbnail_parser_with_checksum(
131 input: &[u8],
132) -> IResult<&[u8], ThumbnailBlock<'_>, BlockError> {
133 let (remain, thumbnail) = thumbnail_parser(input)?;
134
135 if let Some(checksum) = thumbnail.checksum {
136 let param_size = 6;
137 let payload_size = match thumbnail.header.compression_type {
138 CompressionType::None => thumbnail.header.uncompressed_size as usize,
139 _ => thumbnail.header.compressed_size.unwrap() as usize,
140 };
141 let block_size = thumbnail.header.size_in_bytes() + param_size + payload_size;
142 let crc_input = &input[..block_size];
143 let computed_checksum = crc32fast::hash(crc_input);
144
145 log::debug!(
146 "thumbnail checksum 0x{checksum:04x} computed checksum 0x{computed_checksum:04x} "
147 );
148 if checksum == computed_checksum {
149 log::debug!("checksum match");
150 } else {
151 log::error!("fail checksum");
152 return Err(nom::Err::Error(BlockError::Thumbnail));
153 }
154 }
155
156 Ok((remain, thumbnail))
157}