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