irp/
encode.rs

1use super::{Expression, GeneralSpec, Irp, Message, Pronto, RepeatMarker, Unit, Vartable};
2use bitvec::prelude::*;
3use log::warn;
4use num::{ToPrimitive, Zero};
5use num_rational::Rational64;
6use std::{collections::HashMap, rc::Rc};
7
8impl Irp {
9    /// Render it to raw IR with the given variables, separated into intro, repeat, ending
10    pub fn encode<'a>(&'a self, mut vars: Vartable<'a>) -> Result<[Vec<u32>; 3], String> {
11        self.check_parameters(&mut vars)?;
12
13        let mut encoder = Encoder::new(&self.general_spec, vars);
14
15        let mut res = [Vec::new(), Vec::new(), Vec::new()];
16
17        for (i, variant) in self.variants.iter().enumerate() {
18            if let Some(variant) = variant {
19                encoder.encode(variant, None)?;
20
21                if encoder.has_trailing_pulse() {
22                    return Err("stream must end with a gap".into());
23                }
24
25                res[i] = encoder.done()
26            }
27        }
28
29        Ok(res)
30    }
31
32    /// Render it to raw IR with the given variables
33    pub fn encode_raw<'a>(&'a self, vars: Vartable<'a>, repeats: u64) -> Result<Message, String> {
34        let [down, repeat, up] = self.encode(vars)?;
35
36        let mut raw = down;
37
38        for _ in 0..repeats {
39            raw.extend_from_slice(&repeat);
40        }
41
42        raw.extend(up);
43
44        Ok(Message {
45            carrier: Some(self.general_spec.carrier.to_integer()),
46            duty_cycle: self.general_spec.duty_cycle,
47            raw,
48        })
49    }
50
51    /// Render it to pronto hex with the given variables.
52    /// This always produces pronto hex long codes, never the short variant.
53    pub fn encode_pronto<'a>(&'a self, vars: Vartable<'a>) -> Result<Pronto, String> {
54        let [down, repeat, up] = self.encode(vars)?;
55
56        let intro = down.iter().map(|v| *v as f64).collect();
57
58        let repeat = repeat.iter().map(|v| *v as f64).collect();
59
60        if !up.is_empty() {
61            warn!("ending sequence cannot be represented in pronto, dropped");
62        }
63
64        if !self.general_spec.carrier.is_zero() {
65            Ok(Pronto::LearnedModulated {
66                frequency: self.general_spec.carrier.to_f64().unwrap(),
67                intro,
68                repeat,
69            })
70        } else {
71            Ok(Pronto::LearnedUnmodulated {
72                // This is the carrier transmogrifier uses for unmodulated signals
73                frequency: 414514.0,
74                intro,
75                repeat,
76            })
77        }
78    }
79
80    fn check_parameters<'a>(&'a self, vars: &mut Vartable<'a>) -> Result<(), String> {
81        for p in &self.parameters {
82            let val = if let Ok(val) = vars.get(&p.name) {
83                val
84            } else if let Some(e) = &p.default {
85                let v = e.eval(vars)?;
86
87                vars.set(p.name.to_owned(), v);
88
89                v
90            } else {
91                return Err(format!("missing value for {}", p.name));
92            };
93
94            if val < p.min {
95                return Err(format!(
96                    "{} is less than minimum value {} for parameter {}",
97                    val, p.min, p.name
98                ));
99            }
100
101            if val > p.max {
102                return Err(format!(
103                    "{} is more than maximum value {} for parameter {}",
104                    val, p.max, p.name
105                ));
106            }
107        }
108
109        // if parameters are defined, only allow parameters to be set
110        if !self.parameters.is_empty() {
111            for name in vars.vars.keys() {
112                if !self.parameters.iter().any(|p| &p.name == name) {
113                    return Err(format!("no parameter called {name}"));
114                }
115            }
116        }
117
118        for e in &self.definitions {
119            if let Expression::Assignment(name, expr) = e {
120                vars.set_definition(name.clone(), expr.as_ref());
121            } else {
122                unreachable!();
123            }
124        }
125
126        Ok(())
127    }
128}
129
130impl<'a> Vartable<'a> {
131    pub fn new() -> Self {
132        Vartable {
133            vars: HashMap::new(),
134        }
135    }
136
137    /// IRP definitions are evaluated each time when they are referenced
138    fn set_definition(&mut self, id: String, expr: &'a Expression) {
139        self.vars.insert(id, (0, Some(expr)));
140    }
141
142    pub fn set(&mut self, id: String, value: i64) {
143        self.vars.insert(id, (value, None));
144    }
145
146    pub fn is_defined(&self, id: &str) -> bool {
147        self.vars.contains_key(id)
148    }
149
150    pub fn get(&self, id: &str) -> Result<i64, String> {
151        match self.vars.get(id) {
152            Some((val, None)) => Ok(*val),
153            Some((_, Some(expr))) => expr.eval(self),
154            None => Err(format!("variable `{id}ยด not defined")),
155        }
156    }
157}
158
159/// Encoder. This can be used to add flash, gap, extents and deals with nested bitspec scopes.
160struct Encoder<'a, 'b> {
161    /// Reference to general spec for lsb/msb etc
162    general_spec: &'a GeneralSpec,
163    /// Raw output. Even entries are flash, odd are gaps
164    raw: Vec<u32>,
165    /// Are we currently in a leading gap
166    leading_gap: bool,
167    /// Length of IR generated, including leading gap
168    total_length: i64,
169    /// Extents start from this point
170    extent_marker: i64,
171    /// The variables
172    vars: Vartable<'a>,
173    /// bitspec scopes
174    bitspec_scope: Vec<BitspecScope<'b>>,
175}
176
177/// A single bitscope
178struct BitspecScope<'a> {
179    /// The bitspec itself
180    bit_spec: &'a [Rc<Expression>],
181    /// The bitstream. This will be populated bit by bit, and then flushed.
182    bitstream: BitVec<usize, LocalBits>,
183}
184
185impl<'a, 'b> Encoder<'a, 'b> {
186    /// Create a new encoder. One is needed per IRP encode.
187    fn new(general_spec: &'a GeneralSpec, vars: Vartable<'a>) -> Self {
188        Encoder {
189            general_spec,
190            vars,
191            raw: Vec::new(),
192            leading_gap: true,
193            total_length: 0,
194            extent_marker: 0,
195            bitspec_scope: Vec::new(),
196        }
197    }
198
199    /// Add a flash of length microseconds
200    fn add_flash(&mut self, length: i64) -> Result<(), String> {
201        if length <= 0 {
202            warn!("length should be non-zero");
203            return Ok(());
204        }
205
206        if let Some(v) = self.total_length.checked_add(length) {
207            self.total_length = v;
208        } else {
209            return Err("length overflow".into());
210        }
211
212        if (self.raw.len() % 2) == 1 {
213            let raw = self.raw.last_mut().unwrap();
214
215            if let Some(v) = raw.checked_add(length as u32) {
216                *raw = v;
217            } else {
218                return Err("length overflow".into());
219            }
220        } else {
221            self.raw.push(length as u32);
222        }
223        self.leading_gap = false;
224        Ok(())
225    }
226
227    /// Add a gap of length microseconds
228    fn add_gap(&mut self, length: i64) -> Result<(), String> {
229        if length <= 0 {
230            warn!("length should be non-zero");
231            return Ok(());
232        }
233
234        // Leading gaps must be added to the totals
235        if let Some(v) = self.total_length.checked_add(length) {
236            self.total_length = v;
237        } else {
238            return Err("length overflow".into());
239        }
240
241        let len = self.raw.len();
242
243        if self.leading_gap {
244            // ignore leading gaps
245        } else if (len % 2) == 0 {
246            let raw = self.raw.last_mut().unwrap();
247
248            if let Some(v) = raw.checked_add(length as u32) {
249                *raw = v;
250            } else {
251                return Err("length overflow".into());
252            }
253        } else {
254            self.raw.push(length as u32);
255        }
256        Ok(())
257    }
258
259    /// Add an extent.
260    fn add_extent(&mut self, extent: i64) -> Result<(), String> {
261        // remove length of stream generated so far
262        let trimmed_extent = extent - (self.total_length - self.extent_marker);
263
264        if trimmed_extent > 0 {
265            self.add_gap(trimmed_extent)?;
266        } else {
267            // IrpTransmogrifier will error here with: Argument of extent smaller than actual duration
268            // We do this to remain compatible with lircd transmit
269            return Err("extent shorter than duration".into());
270        }
271
272        // Reset extent marker
273        self.extent_marker = self.total_length;
274
275        Ok(())
276    }
277
278    /// Add some bits after evaluating a bitfield.
279    fn add_bits(&mut self, bits: i64, length: i64, level: Option<usize>) -> Result<(), String> {
280        match level {
281            Some(level) => {
282                let mut bv = BitVec::<usize, LocalBits>::from_element(bits as usize);
283
284                bv.truncate(length as usize);
285
286                bv.reverse();
287
288                let level = &mut self.bitspec_scope[level];
289
290                if self.general_spec.lsb {
291                    bv.append(&mut level.bitstream);
292                    level.bitstream = bv;
293                } else {
294                    level.bitstream.append(&mut bv);
295                }
296
297                Ok(())
298            }
299            None => Err(String::from("bits not permitted")),
300        }
301    }
302
303    /// Flush the bitstream for a bitspec scope, which should recurse all the way down the scopes
304    fn flush_level(&mut self, level: Option<usize>) -> Result<(), String> {
305        let level = match level {
306            Some(level) => level,
307            None => {
308                return Ok(());
309            }
310        };
311
312        let lower_level = if level > 0 { Some(level - 1) } else { None };
313
314        if !self.bitspec_scope[level].bitstream.is_empty() {
315            let mut bits = BitVec::new();
316
317            // Swap in a new empty bitvec, we will consume the enter stream and then we
318            // don't need a mutable reference.
319            std::mem::swap(&mut bits, &mut self.bitspec_scope[level].bitstream);
320
321            let max_bit = self.bitspec_scope[level].bit_spec.len();
322
323            let bits_step = match max_bit {
324                1..=2 => 1,
325                3..=4 => 2,
326                5..=8 => 3,
327                9..=16 => 4,
328                _ => unreachable!(),
329            };
330
331            let bits_len = bits.len();
332
333            if (bits_len % bits_step) != 0 {
334                return Err(format!(
335                    "Cannot encode {bits_len} bits with bitspec of {max_bit}"
336                ));
337            }
338
339            if !self.general_spec.lsb {
340                for bit in bits.chunks(bits_step) {
341                    let bit = bit_to_usize(bit);
342
343                    if bit >= max_bit {
344                        return Err(format!("Cannot encode {bit} with current bit_spec"));
345                    }
346
347                    self.encode(
348                        self.bitspec_scope[level].bit_spec[bit].as_ref(),
349                        lower_level,
350                    )?;
351                }
352            } else {
353                for bit in bits.chunks(bits_step).rev() {
354                    let bit = bit_to_usize(bit);
355
356                    if bit >= max_bit {
357                        return Err(format!("Cannot encode {bit} with current bit_spec"));
358                    }
359
360                    self.encode(
361                        self.bitspec_scope[level].bit_spec[bit].as_ref(),
362                        lower_level,
363                    )?;
364                }
365            }
366        }
367
368        self.flush_level(lower_level)?;
369
370        Ok(())
371    }
372
373    fn encode(&mut self, expr: &'b Expression, level: Option<usize>) -> Result<(), String> {
374        match expr {
375            Expression::FlashConstant(p, u) => {
376                self.flush_level(level)?;
377                self.add_flash(u.eval_rational(p, self.general_spec)?)?;
378            }
379            Expression::FlashIdentifier(id, u) => {
380                self.flush_level(level)?;
381                let v = u.eval(self.vars.get(id)?, self.general_spec)?;
382                if v > 0 {
383                    self.add_flash(v)?;
384                } else {
385                    self.add_gap(v.wrapping_neg())?;
386                }
387            }
388            Expression::ExtentConstant(p, u) => {
389                self.flush_level(level)?;
390                self.add_extent(u.eval_rational(p, self.general_spec)?)?;
391            }
392            Expression::ExtentIdentifier(id, u) => {
393                self.flush_level(level)?;
394                self.add_extent(u.eval(self.vars.get(id)?, self.general_spec)?)?;
395            }
396            Expression::GapConstant(p, u) => {
397                self.flush_level(level)?;
398                self.add_gap(u.eval_rational(p, self.general_spec)?)?;
399            }
400            Expression::GapIdentifier(id, u) => {
401                self.flush_level(level)?;
402                let v = u.eval(self.vars.get(id)?, self.general_spec)?;
403                if v > 0 {
404                    self.add_gap(v)?;
405                } else {
406                    self.add_flash(v.wrapping_neg())?;
407                }
408            }
409            Expression::Assignment(id, expr) => {
410                self.flush_level(level)?;
411
412                let v = expr.eval(&self.vars)?;
413
414                self.vars.set(id.into(), v);
415            }
416            Expression::Stream(stream) => {
417                let repeats = match stream.repeat {
418                    None => 1,
419                    Some(RepeatMarker::Count(num)) => num,
420                    _ => unreachable!(),
421                };
422
423                let level = if !stream.bit_spec.is_empty() {
424                    self.bitspec_scope.push(BitspecScope {
425                        bit_spec: &stream.bit_spec,
426                        bitstream: BitVec::new(),
427                    });
428
429                    match level {
430                        None => Some(0),
431                        Some(level) => Some(level + 1),
432                    }
433                } else {
434                    level
435                };
436
437                for _ in 0..repeats {
438                    for expr in &stream.stream {
439                        if let Expression::List(list) = expr.as_ref() {
440                            if list.is_empty() {
441                                break;
442                            }
443                        }
444                        self.encode(expr, level)?;
445                    }
446                }
447
448                self.flush_level(level)?;
449
450                if !stream.bit_spec.is_empty() {
451                    self.bitspec_scope.pop();
452                }
453            }
454            Expression::BitField { .. } => {
455                let (bits, length) = expr.bitfield(&self.vars)?;
456
457                self.add_bits(bits, length, level)?;
458            }
459            Expression::List(list) => {
460                for expr in list {
461                    self.encode(expr, level)?;
462                }
463            }
464            _ => unreachable!(),
465        }
466
467        Ok(())
468    }
469
470    fn has_trailing_pulse(&self) -> bool {
471        (self.raw.len() % 2) != 0
472    }
473
474    fn done(&mut self) -> Vec<u32> {
475        self.total_length = 0;
476        self.extent_marker = 0;
477        self.leading_gap = true;
478
479        let mut res = Vec::new();
480
481        std::mem::swap(&mut res, &mut self.raw);
482
483        res
484    }
485}
486
487impl Unit {
488    pub(crate) fn eval(&self, v: i64, spec: &GeneralSpec) -> Result<i64, String> {
489        match self {
490            Unit::Units if spec.unit.is_zero() => Err("cannot use units when unit set to 0".into()),
491            Unit::Units => Ok((spec.unit * v).to_integer()),
492            Unit::Microseconds => Ok(v),
493            Unit::Milliseconds => Ok(v * 1000),
494            Unit::Pulses if spec.carrier.is_zero() => {
495                Err("pulses cannot be used with zero carrier".into())
496            }
497            Unit::Pulses => Ok((Rational64::from(v) * 1_000_000 / spec.carrier).to_integer()),
498        }
499    }
500
501    pub(crate) fn eval_rational(&self, v: &Rational64, spec: &GeneralSpec) -> Result<i64, String> {
502        match self {
503            Unit::Units if spec.unit.is_zero() => Err("cannot use units when unit set to 0".into()),
504            Unit::Units => Ok((spec.unit * v).to_integer()),
505            Unit::Microseconds => Ok(v.to_integer()),
506            Unit::Milliseconds => Ok((v * 1000).to_integer()),
507            Unit::Pulses if spec.carrier.is_zero() => {
508                Err("pulses cannot be used with zero carrier".into())
509            }
510            Unit::Pulses => Ok((v * 1_000_000 / spec.carrier).to_integer()),
511        }
512    }
513}
514
515// See https://github.com/bitvecto-rs/bitvec/issues/119
516fn bit_to_usize(bit: &BitSlice) -> usize {
517    let mut v = 0;
518
519    for i in 0..bit.len() {
520        if bit[i] {
521            v |= 1 << (bit.len() - 1 - i);
522        }
523    }
524
525    v
526}