1use crate::codec::bytes::{assemble_u64, byte_at, copy_bytes, mask_for, sign_extend};
8use crate::codec::rat::Rat;
9use crate::desc::{
10 DateTimeEncoding, PointDesc, ScaleMode, StorageType, StringPadding, StringTermination,
11 ValueKind,
12};
13use crate::error::DecodeError;
14use crate::value::Value;
15
16#[derive(Clone, Copy, Debug, Default)]
20pub struct Ctx<'a> {
21 pub refs: &'a [(&'a str, i64)],
22}
23
24impl<'a> Ctx<'a> {
25 pub const EMPTY: Ctx<'static> = Ctx { refs: &[] };
26
27 pub fn get(&self, id: &str) -> Option<i64> {
28 self.refs.iter().find(|(k, _)| *k == id).map(|(_, v)| *v)
29 }
30}
31
32pub fn decode(p: &PointDesc<'_>, regs: &[u16], ctx: &Ctx<'_>) -> Result<Value, DecodeError> {
37 if regs.len() < p.words() {
38 return Err(DecodeError::ShortRead);
39 }
40 let regs = ®s[..p.words()];
41
42 if let ValueKind::Composed {
44 base,
45 mantissa_offset,
46 mantissa_words,
47 exponent_offset,
48 exponent_words,
49 } = p.value
50 {
51 if base == 0 {
52 return Err(DecodeError::ComposedBaseZero);
53 }
54 let mant = sub_int(
55 regs,
56 mantissa_offset,
57 mantissa_words,
58 p.byte_big,
59 p.word_big,
60 );
61 let exp = sub_int(
62 regs,
63 exponent_offset,
64 exponent_words,
65 p.byte_big,
66 p.word_big,
67 );
68 let mut r = Rat::int(mant);
69 let b = Rat::int(base);
70 if exp >= 0 {
71 for _ in 0..exp.min(64) {
72 r = r.mul(b);
73 }
74 } else {
75 for _ in 0..(-exp).min(64) {
76 r = r.div(b);
77 }
78 }
79 return Ok(Value::F64(r.to_f64()));
80 }
81
82 if p.storage == StorageType::F32 {
84 let raw = assemble_u64(regs, p.byte_big, p.word_big) as u32;
85 return Ok(Value::F64(apply_float_scale(f32::from_bits(raw) as f64, p)));
86 }
87 if p.storage == StorageType::F64 {
88 let raw = assemble_u64(regs, p.byte_big, p.word_big);
89 return Ok(Value::F64(apply_float_scale(f64::from_bits(raw), p)));
90 }
91
92 let bits = p.storage.bits(regs.len());
94 let raw = assemble_u64(regs, p.byte_big, p.word_big) & mask_for(bits);
95
96 for na in p.na {
98 if (na.raw as u64) & mask_for(bits) == raw {
99 return Ok(Value::Unavailable);
100 }
101 }
102
103 match p.value {
105 ValueKind::Flags(_) => return Ok(Value::Flags(raw)),
106 ValueKind::Fields(_) => return Ok(Value::Fields(raw)),
107 _ => {}
108 }
109
110 if p.storage == StorageType::Bcd {
111 return Ok(Value::I64(bcd_to_int(regs, p.byte_big, p.word_big)));
112 }
113
114 let signed = p.storage.signed();
115 let raw_int: i64 = if signed {
116 sign_extend(raw, bits)
117 } else {
118 raw as i64
119 };
120
121 match p.value {
122 ValueKind::Bool => Ok(Value::Bool(raw != 0)),
123 ValueKind::DateTime(enc) => Ok(Value::DateTime(match enc {
124 DateTimeEncoding::EpochSeconds | DateTimeEncoding::EpochMillis => raw as i64,
125 })),
126 ValueKind::Decimal => Ok(Value::F64(apply_scale(raw_int, signed, raw, p, ctx)?)),
127 ValueKind::Uint => Ok(Value::U64(raw)),
128 ValueKind::Int => Ok(Value::I64(raw_int)),
129 _ => Ok(if signed {
132 Value::I64(raw_int)
133 } else {
134 Value::U64(raw)
135 }),
136 }
137}
138
139pub fn decode_raw(p: &PointDesc<'_>, regs: &[u16]) -> Result<(u64, u32), DecodeError> {
142 if regs.len() < p.words() {
143 return Err(DecodeError::ShortRead);
144 }
145 let regs = ®s[..p.words()];
146 let bits = p.storage.bits(regs.len());
147 Ok((
148 assemble_u64(regs, p.byte_big, p.word_big) & mask_for(bits),
149 bits,
150 ))
151}
152
153pub fn decode_str<'b>(
155 p: &PointDesc<'_>,
156 regs: &[u16],
157 out: &'b mut [u8],
158) -> Result<&'b str, DecodeError> {
159 if regs.len() < p.words() {
160 return Err(DecodeError::ShortRead);
161 }
162 let regs = ®s[..p.words()];
163 let n = copy_bytes(regs, p.byte_big, p.word_big, out).ok_or(DecodeError::BufferTooSmall)?;
164 let (padding, termination) = match p.value {
165 ValueKind::Str {
166 padding,
167 termination,
168 } => (padding, termination),
169 _ => (StringPadding::None, StringTermination::FixedLength),
170 };
171 let mut end = n;
172 if termination == StringTermination::NullTerminated {
173 if let Some(i) = out[..n].iter().position(|&b| b == 0) {
174 end = i;
175 }
176 }
177 let pad = match padding {
178 StringPadding::Null => Some(0u8),
179 StringPadding::Space => Some(b' '),
180 StringPadding::None => None,
181 };
182 if let Some(c) = pad {
183 while end > 0 && out[end - 1] == c {
184 end -= 1;
185 }
186 }
187 core::str::from_utf8(&out[..end]).map_err(|_| DecodeError::InvalidUtf8)
188}
189
190pub fn decode_bytes<'b>(
192 p: &PointDesc<'_>,
193 regs: &[u16],
194 out: &'b mut [u8],
195) -> Result<&'b [u8], DecodeError> {
196 if regs.len() < p.words() {
197 return Err(DecodeError::ShortRead);
198 }
199 let regs = ®s[..p.words()];
200 let n = copy_bytes(regs, p.byte_big, p.word_big, out).ok_or(DecodeError::BufferTooSmall)?;
201 Ok(&out[..n])
202}
203
204fn apply_scale(
206 raw_int: i64,
207 signed: bool,
208 raw_u: u64,
209 p: &PointDesc<'_>,
210 ctx: &Ctx<'_>,
211) -> Result<f64, DecodeError> {
212 let mut r = if signed {
213 Rat::int(raw_int)
214 } else {
215 Rat::from_u64(raw_u)
216 };
217
218 if let Some(sel) = &p.selector {
221 if let Some(key) = ctx.get(sel.point_id) {
222 if let Some(c) = sel.cases.iter().find(|c| c.key == key) {
223 if let Some(s) = c.scale {
224 if s.den != 0 {
225 r = r.mul(Rat::new(s.num as i128, s.den as i128));
226 }
227 }
228 if let Some(o) = c.offset {
229 if o.den != 0 {
230 r = r.add(Rat::new(o.num as i128, o.den as i128));
231 }
232 }
233 return Ok(r.to_f64());
234 }
235 }
236 }
237
238 if let Some(sr) = &p.scale_ref {
239 let sf = ctx.get(sr.point_id).ok_or(DecodeError::UnresolvedRef)?;
240 match sr.mode {
241 ScaleMode::Pow10 => r = r.mul(Rat::pow10(sf)),
242 ScaleMode::Multiply => {
243 let den = if sr.denominator == 0 {
244 1
245 } else {
246 sr.denominator
247 };
248 r = r.mul(Rat::new(sf as i128, den as i128));
249 }
250 }
251 } else if let Some(s) = p.scale {
252 if s.den == 0 {
253 return Err(DecodeError::ZeroScaleDenominator);
254 }
255 r = r.mul(Rat::new(s.num as i128, s.den as i128));
256 }
257
258 if let Some(o) = p.offset_add {
259 if o.den != 0 {
260 r = r.add(Rat::new(o.num as i128, o.den as i128));
261 }
262 }
263 Ok(r.to_f64())
264}
265
266fn apply_float_scale(mut f: f64, p: &PointDesc<'_>) -> f64 {
267 if let Some(s) = p.scale {
268 if s.den != 0 {
269 f = f * s.num as f64 / s.den as f64;
270 }
271 }
272 if let Some(o) = p.offset_add {
273 if o.den != 0 {
274 f += o.num as f64 / o.den as f64;
275 }
276 }
277 f
278}
279
280fn sub_int(regs: &[u16], offset: u16, words: u8, byte_big: bool, word_big: bool) -> i64 {
282 let idx = offset as usize;
283 let n = if words == 0 { 1 } else { words as usize };
284 if idx + n > regs.len() {
285 return 0;
286 }
287 let slice = ®s[idx..idx + n];
288 let raw = assemble_u64(slice, byte_big, word_big);
289 sign_extend(raw & mask_for((n * 16) as u32), (n * 16) as u32)
290}
291
292fn bcd_to_int(regs: &[u16], byte_big: bool, word_big: bool) -> i64 {
293 let mut v: i64 = 0;
294 for i in 0..regs.len() * 2 {
295 let b = byte_at(regs, i, byte_big, word_big);
296 v = v * 100 + ((b >> 4) as i64) * 10 + (b & 0x0f) as i64;
297 }
298 v
299}