ibus_rs/
lib.rs

1// Copyright 2024 Alexey 'alexxy' Shvetsov
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9pub struct IbusParser {
10    buffer: [u8; 32],
11    index: usize,
12    state: IbusState,
13}
14
15enum IbusState {
16    Sync,
17    Data,
18}
19
20impl IbusParser {
21    pub fn new() -> Self {
22        Self {
23            buffer: [0; 32],
24            index: 0,
25            state: IbusState::Sync,
26        }
27    }
28
29    pub fn parse_byte(&mut self, byte: u8) -> Option<IbusMessage> {
30        match self.state {
31            IbusState::Sync => {
32                if byte == 0x20 {
33                    self.buffer[0] = byte;
34                    self.index = 1;
35                    self.state = IbusState::Data;
36                }
37            }
38            IbusState::Data => {
39                self.buffer[self.index] = byte;
40                self.index += 1;
41
42                if self.index == 32 {
43                    let mut checksum: u16 = 0xffff;
44                    for byte in &self.buffer[0..30] {
45                        checksum -= *byte as u16;
46                    }
47
48                    if checksum == ((self.buffer[31] as u16) << 8) | (self.buffer[30] as u16) {
49                        let message = IbusMessage::from_buffer(&self.buffer);
50                        self.state = IbusState::Sync;
51                        return Some(message);
52                    } else {
53                        self.state = IbusState::Sync;
54                    }
55                }
56            }
57        }
58
59        None
60    }
61}
62
63#[derive(Debug)]
64pub struct IbusMessage {
65    pub channels: [u16; 14],
66}
67
68impl IbusMessage {
69    pub fn from_buffer(buffer: &[u8]) -> Self {
70        let mut channels = [0; 14];
71        for ch in 0..14 {
72            channels[ch] =
73                ((buffer[2 * (ch + 1) + 1] as u16) << 8) | buffer[2 * (ch + 1) + 0] as u16;
74        }
75        Self { channels }
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use super::*;
82
83    #[test]
84    fn parse_message() {
85        let stream: [u8; 32] = [
86            0x20, 0x40, 0xDB, 0x5, 0xDC, 0x5, 0x54, 0x5, 0xDC, 0x5, 0xE8, 0x3, 0xD0, 0x7, 0xD2,
87            0x5, 0xE8, 0x3, 0xDC, 0x5, 0xDC, 0x5, 0xDC, 0x5, 0xDC, 0x5, 0xDC, 0x5, 0xDC, 0x5, 0xDA,
88            0xF3,
89        ];
90        let ref_msg: [u16; 14] = [
91            1499, 1500, 1364, 1500, 1000, 2000, 1490, 1000, 1500, 1500, 1500, 1500, 1500, 1500,
92        ];
93
94        let mut ibus = IbusParser::new();
95        for byte in stream {
96            if let Some(message) = ibus.parse_byte(byte) {
97                let channels = message.channels;
98                for i in 0..14 {
99                    assert_eq!(channels[i], ref_msg[i]);
100                }
101            }
102        }
103    }
104}