1use super::CN_BLOCK_SIZE;
2use crate::{
3 Result,
4 blocks::{
5 common::{
6 BlockHeader, BlockParse, DataType, debug_assert_aligned, read_f64, read_u8, read_u16,
7 read_u32, read_u64, validate_block_id, validate_block_length, validate_buffer_size,
8 },
9 conversion::ConversionBlock,
10 text_block::TextBlock,
11 },
12 types::DecodedValue,
13};
14use alloc::string::String;
15use alloc::vec::Vec;
16
17#[derive(Debug, Clone)]
18pub struct ChannelBlock {
19 pub header: BlockHeader,
20 pub next_ch_addr: u64,
21 pub component_addr: u64,
22 pub name_addr: u64,
23 pub source_addr: u64,
24 pub conversion_addr: u64,
25 pub data_addr: u64,
26 pub unit_addr: u64,
27 pub comment_addr: u64,
28 pub channel_type: u8,
29 pub sync_type: u8,
30 pub data_type: DataType,
31 pub bit_offset: u8,
32 pub byte_offset: u32,
33 pub bit_count: u32,
34 pub flags: u32,
35 pub pos_invalidation_bit: u32,
36 pub precision: u8,
37 pub reserved1: u8,
38 pub attachment_count: u16,
39 pub min_raw_value: f64,
40 pub max_raw_value: f64,
41 pub lower_limit: f64,
42 pub upper_limit: f64,
43 pub lower_ext_limit: f64,
44 pub upper_ext_limit: f64,
45 pub name: Option<String>,
46 pub conversion: Option<ConversionBlock>,
47}
48
49impl BlockParse<'_> for ChannelBlock {
50 const ID: &'static str = "##CN";
51
52 fn from_bytes(bytes: &[u8]) -> Result<Self> {
53 let header = Self::parse_header(bytes)?;
54 validate_buffer_size(bytes, CN_BLOCK_SIZE)?;
55
56 Ok(Self {
57 header,
58 next_ch_addr: read_u64(bytes, 24),
60 component_addr: read_u64(bytes, 32),
61 name_addr: read_u64(bytes, 40),
62 source_addr: read_u64(bytes, 48),
63 conversion_addr: read_u64(bytes, 56),
64 data_addr: read_u64(bytes, 64),
65 unit_addr: read_u64(bytes, 72),
66 comment_addr: read_u64(bytes, 80),
67 channel_type: read_u8(bytes, 88),
69 sync_type: read_u8(bytes, 89),
70 data_type: DataType::from_u8(read_u8(bytes, 90)),
71 bit_offset: read_u8(bytes, 91),
72 byte_offset: read_u32(bytes, 92),
73 bit_count: read_u32(bytes, 96),
74 flags: read_u32(bytes, 100),
75 pos_invalidation_bit: read_u32(bytes, 104),
76 precision: read_u8(bytes, 108),
77 reserved1: read_u8(bytes, 109),
78 attachment_count: read_u16(bytes, 110),
79 min_raw_value: read_f64(bytes, 112),
81 max_raw_value: read_f64(bytes, 120),
82 lower_limit: read_f64(bytes, 128),
83 upper_limit: read_f64(bytes, 136),
84 lower_ext_limit: read_f64(bytes, 144),
85 upper_ext_limit: read_f64(bytes, 152),
86 name: None,
88 conversion: None,
89 })
90 }
91}
92
93impl ChannelBlock {
94 pub fn to_bytes(&self) -> Result<Vec<u8>> {
96 validate_block_id(&self.header, "##CN")?;
97 validate_block_length(&self.header, CN_BLOCK_SIZE as u64)?;
98
99 let mut buffer = Vec::with_capacity(CN_BLOCK_SIZE);
100
101 buffer.extend_from_slice(&self.header.to_bytes()?);
103
104 buffer.extend_from_slice(&self.next_ch_addr.to_le_bytes());
106 buffer.extend_from_slice(&self.component_addr.to_le_bytes());
107 buffer.extend_from_slice(&self.name_addr.to_le_bytes());
108 buffer.extend_from_slice(&self.source_addr.to_le_bytes());
109 buffer.extend_from_slice(&self.conversion_addr.to_le_bytes());
110 buffer.extend_from_slice(&self.data_addr.to_le_bytes());
111 buffer.extend_from_slice(&self.unit_addr.to_le_bytes());
112 buffer.extend_from_slice(&self.comment_addr.to_le_bytes());
113
114 buffer.push(self.channel_type);
116 buffer.push(self.sync_type);
117 buffer.push(self.data_type.to_u8());
118 buffer.push(self.bit_offset);
119 buffer.extend_from_slice(&self.byte_offset.to_le_bytes());
120 buffer.extend_from_slice(&self.bit_count.to_le_bytes());
121 buffer.extend_from_slice(&self.flags.to_le_bytes());
122 buffer.extend_from_slice(&self.pos_invalidation_bit.to_le_bytes());
123 buffer.push(self.precision);
124 buffer.push(self.reserved1);
125 buffer.extend_from_slice(&self.attachment_count.to_le_bytes());
126
127 buffer.extend_from_slice(&self.min_raw_value.to_le_bytes());
129 buffer.extend_from_slice(&self.max_raw_value.to_le_bytes());
130 buffer.extend_from_slice(&self.lower_limit.to_le_bytes());
131 buffer.extend_from_slice(&self.upper_limit.to_le_bytes());
132 buffer.extend_from_slice(&self.lower_ext_limit.to_le_bytes());
133 buffer.extend_from_slice(&self.upper_ext_limit.to_le_bytes());
134
135 debug_assert_aligned(buffer.len());
136 Ok(buffer)
137 }
138
139 pub fn resolve_name(&mut self, file_data: &[u8]) -> Result<()> {
141 if self.name.is_none() && self.name_addr != 0 {
142 let offset = self.name_addr as usize;
143 if offset + 24 <= file_data.len() {
144 let text_block = TextBlock::from_bytes(&file_data[offset..])?;
145 self.name = Some(text_block.text);
146 }
147 }
148 Ok(())
149 }
150
151 pub fn resolve_conversion(&mut self, bytes: &[u8]) -> Result<()> {
153 if self.conversion.is_none() && self.conversion_addr != 0 {
154 let offset = self.conversion_addr as usize;
155 validate_buffer_size(bytes, offset + 24)?;
156
157 let mut conv_block = ConversionBlock::from_bytes(&bytes[offset..])?;
158 let _ = conv_block.resolve_formula(bytes);
159 self.conversion = Some(conv_block);
160 }
161 Ok(())
162 }
163
164 pub fn apply_conversion_value(
166 &self,
167 raw: DecodedValue,
168 file_data: &[u8],
169 ) -> Result<DecodedValue> {
170 if let Some(conv) = &self.conversion {
171 conv.apply_decoded(raw, file_data)
172 } else {
173 Ok(raw)
174 }
175 }
176}
177
178impl Default for ChannelBlock {
179 fn default() -> Self {
180 Self {
181 header: BlockHeader {
182 id: String::from("##CN"),
183 reserved: 0,
184 length: CN_BLOCK_SIZE as u64,
185 link_count: 8,
186 },
187 next_ch_addr: 0,
188 component_addr: 0,
189 name_addr: 0,
190 source_addr: 0,
191 conversion_addr: 0,
192 data_addr: 0,
193 unit_addr: 0,
194 comment_addr: 0,
195 channel_type: 0,
196 sync_type: 0,
197 data_type: DataType::UnsignedIntegerLE,
198 bit_offset: 0,
199 byte_offset: 0,
200 bit_count: 0,
201 flags: 0,
202 pos_invalidation_bit: 0,
203 precision: 0,
204 reserved1: 0,
205 attachment_count: 0,
206 min_raw_value: 0.0,
207 max_raw_value: 0.0,
208 lower_limit: 0.0,
209 upper_limit: 0.0,
210 lower_ext_limit: 0.0,
211 upper_ext_limit: 0.0,
212 name: None,
213 conversion: None,
214 }
215 }
216}