1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#![deny(missing_debug_implementations)]

use std::io::{self, Read};
use std::fmt;

use dlms_cosem::{Error as DlmsError, Dlms, ObisMap};
use mbusparse::{Error as MbusError, Telegram};

#[derive(Debug)]
pub enum Error {
  Io(io::Error),
  DecryptionFailed,
}

impl fmt::Display for Error {
  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    match self {
      Self::Io(err) => err.fmt(f),
      Self::DecryptionFailed => write!(f, "decryption failed"),
    }
  }
}

impl std::error::Error for Error {}

#[derive(Debug)]
pub struct SmartMeter<R> {
  reader: R,
  dlms: Dlms,
  buffer: Vec<u8>,
}

impl<R> SmartMeter<R> {
  pub fn new(reader: R, dlms: Dlms) -> Self {
    SmartMeter { reader, dlms, buffer: Vec::new() }
  }
}

impl<R: Read> Iterator for SmartMeter<R> {
  type Item = Result<ObisMap, Error>;

  /// Get the next reading.
  fn next(&mut self) -> Option<Self::Item> {
    let mut bytes_needed = 0;
    let mut telegrams_needed = 1;

    'outer: loop {
      match (&mut self.reader).take(bytes_needed as u64).read_to_end(&mut self.buffer) {
        Ok(_) => (),
        Err(err) => return Some(Err(Error::Io(err))),
      }

      let mut telegrams = Vec::new();

      let mut buffer = self.buffer.as_slice();
      let mut telegram_1_len = 0;
      let mut telegrams_len = 0;

      for i in 0..telegrams_needed {
        match Telegram::parse(buffer) {
          Ok((next_buffer, telegram)) => {
            let telegram_len = buffer.len() - next_buffer.len();
            if i == 0 {
              telegram_1_len = telegram_len;
            }
            telegrams_len += telegram_len;
            buffer = next_buffer;
            telegrams.push(telegram);
          },
          Err(MbusError::Incomplete(n)) => {
            bytes_needed = n.map(|b| b.get()).unwrap_or(1);
            continue 'outer
          },
          Err(MbusError::InvalidStartCharacter) => {
            self.buffer.remove(0);
            bytes_needed = 0;
            continue 'outer
          }
          Err(MbusError::InvalidFormat | MbusError::ChecksumMismatch) => {
            // Input is invalid but not incomplete,
            // so try advancing the buffer.
            self.buffer.remove(0);
            bytes_needed = 0;
            continue 'outer
          },
        }
      }
      bytes_needed = 0;

      match self.dlms.decrypt(&telegrams) {
        Ok((_, obis_map)) => {
          self.buffer.drain(0..telegrams_len);
          return Some(Ok(obis_map))
        },
        Err(DlmsError::Incomplete(n)) => {
          telegrams_needed += n.map(|t| t.get()).unwrap_or(1);
        },
        Err(DlmsError::InvalidFormat | DlmsError::ChecksumMismatch) => {
          // Other error, continue with next telegram.
          self.buffer.drain(0..telegram_1_len);
          telegrams_needed = 1;
          continue
        },
        Err(DlmsError::DecryptionFailed) => {
          return Some(Err(Error::DecryptionFailed))
        },
      }
    }
  }
}