Midea/src/packet_builder.rs

96 lines
2.4 KiB
Rust

use std::str::from_utf8;
use chrono::Local;
use crate::{command::RequestSerializer, security::Security};
pub struct PacketBuilder<S: RequestSerializer> {
command: S,
packet: [u8; 40],
}
impl<S: RequestSerializer> PacketBuilder<S> {
pub fn builder(device_id: u64, command: S) -> Self {
#[rustfmt::skip]
let mut packet = [
// 2 bytes - StaicHeader
0x5a, 0x5a,
// 2 bytes - mMessageType
0x01, 0x11,
// 2 bytes - PacketLenght
0x00, 0x00,
// 2 bytes
0x20, 0x00,
// 4 bytes - MessageId
0x00, 0x00, 0x00, 0x00,
// 8 bytes - Date&Time
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 6 bytes - mDeviceID
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 12 bytes
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
];
packet[12..20].copy_from_slice(&Self::packet_time());
packet[20..28].copy_from_slice(&device_id.to_le_bytes()[0..8]);
Self { command, packet }
}
fn packet_time() -> [u8; 8] {
let mut t = Local::now()
.format("%Y%m%d%H%M%S%f")
.to_string()
.as_bytes()
.to_vec();
t.truncate(16);
let mut b = [0; 8];
for (index, chars) in t.chunks(2).enumerate() {
b[7 - index] = from_utf8(chars).unwrap().parse().unwrap();
}
b
}
pub fn finalize(self, msg_type: u8) -> Vec<u8> {
let mut packet = self.packet.to_vec();
if msg_type != 1 {
packet[3] = 0x10;
packet[6] = 0x7b;
} else {
packet.extend(Security::aes_encrypt(&self.command.serialize()));
}
// packet length
packet[4..6].copy_from_slice(&(self.packet.len() as u16 + 16).to_le_bytes());
// append a basic checksum data (16 bytes) to the packet
packet.extend(Security::encode32_data(&self.packet));
packet
}
}
#[cfg(test)]
mod test {
use std::str::from_utf8;
#[test]
fn packet_time() {
let t = b"2023092913400641";
let b_ref = b")\x06(\r\x1d\t\x17\x14";
let mut b = [0; 8];
for (index, chars) in t.chunks(2).enumerate() {
b[7 - index] = from_utf8(chars).unwrap().parse().unwrap();
}
assert_eq!(&b, b_ref);
}
}