Split command into sub structs

This commit is contained in:
hodasemi 2023-09-27 15:42:32 +02:00
parent c184fc603e
commit 631e88aa46
10 changed files with 270 additions and 79 deletions

View file

@ -16,6 +16,8 @@ reqwest = "0.11.20"
tokio = { version = "1.32.0", features=["macros", "rt-multi-thread"] }
futures = "0.3.28"
serial_test = "2.0.0"
num-traits = "0.2.0"
num-derive = "0.4.0"
#crypto
cbc = { version = "0.1.2", features = ["alloc"] }

View file

@ -1,65 +0,0 @@
use serde::{Deserialize, Serialize};
#[repr(u8)]
#[derive(Debug, Clone, Serialize, Deserialize)]
enum MessageType {
Query,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Command {
device_protocol_version: u8,
device_type: u8,
message_type: MessageType,
body_type: u8,
}
impl Command {
pub fn sub_type(device_type: u32) -> Self {
// Self {}
todo!()
}
pub fn query(device_type: u8, device_protocol_version: u8) -> Self {
Self {
device_protocol_version,
device_type,
message_type: MessageType::Query,
body_type: 0x00,
}
}
}
impl Command {
const HEADER_LENGTH: u8 = 10;
pub fn header(&self) -> Vec<u8> {
let length = Self::HEADER_LENGTH + self.body().len() as u8;
vec![
// flag
0xAA,
// length
length,
// device type
self.device_type,
// frame checksum
0x00, // self._device_type ^ length,
// unused
0x00,
0x00,
// frame ID
0x00,
// frame protocol version
0x00,
// device protocol version
self.device_protocol_version,
// frame type
self.message_type as u8,
]
}
pub fn body(&self) -> Vec<u8> {
todo!()
}
}

41
src/command/body.rs Normal file
View file

@ -0,0 +1,41 @@
use std::ops::Index;
use super::header::Header;
#[derive(Debug, Clone)]
pub struct Body(Vec<u8>);
impl Body {
pub fn body_type(&self) -> u8 {
self.0[0]
}
pub fn raw(&self) -> &[u8] {
&self.0
}
pub fn len(&self) -> usize {
self.0.len()
}
}
impl From<&[u8]> for Body {
fn from(value: &[u8]) -> Self {
Self(
value[(Header::HEADER_LENGTH as usize)..value.len() - 1]
.iter()
.cloned()
.collect::<Vec<u8>>()
.try_into()
.unwrap(),
)
}
}
impl Index<usize> for Body {
type Output = u8;
fn index(&self, index: usize) -> &Self::Output {
&self.0[index]
}
}

71
src/command/header.rs Normal file
View file

@ -0,0 +1,71 @@
use num_traits::FromPrimitive;
use serde::{Deserialize, Serialize};
use super::MessageType;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Header([u8; Self::HEADER_LENGTH as usize]);
impl Header {
pub(crate) const HEADER_LENGTH: u8 = 10;
pub fn new(
body_length: u8,
device_type: u8,
device_protocol_version: u8,
message_type: MessageType,
) -> Self {
let length = Self::HEADER_LENGTH + body_length;
Self([
// flag
0xAA,
// length
length,
// device type
device_type,
// frame checksum
0x00, // self._device_type ^ length,
// unused
0x00,
0x00,
// frame ID
0x00,
// frame protocol version
0x00,
// device protocol version
device_protocol_version,
// frame type
message_type as u8,
])
}
pub fn device_protocol_version(&self) -> u8 {
self.0[8]
}
pub fn message_type(&self) -> MessageType {
MessageType::from_u8(self.0[9]).unwrap()
}
pub fn device_type(&self) -> u8 {
self.0[2]
}
pub(crate) fn raw(&self) -> &[u8; Self::HEADER_LENGTH as usize] {
&self.0
}
}
impl From<&[u8]> for Header {
fn from(value: &[u8]) -> Self {
Self(
value[0..Self::HEADER_LENGTH as usize]
.iter()
.cloned()
.collect::<Vec<u8>>()
.try_into()
.unwrap(),
)
}
}

36
src/command/mod.rs Normal file
View file

@ -0,0 +1,36 @@
mod body;
mod header;
mod request;
mod response;
use serde::{Deserialize, Serialize};
use self::{body::Body, header::Header};
#[repr(u8)]
#[derive(Debug, Clone, Serialize, Deserialize, FromPrimitive)]
pub enum MessageType {
None = 0x00,
Set = 0x02,
Query = 0x03,
Notify1 = 0x04,
Notify2 = 0x05,
Exception = 0x06,
QuerySN = 0x07,
Exception2 = 0x0A,
QuerySubtype = 0xA0,
}
impl Default for MessageType {
fn default() -> Self {
Self::None
}
}
#[derive(Debug, Clone)]
pub struct Command {
pub(crate) header: Header,
pub(crate) body: Body,
}
impl Command {}

69
src/command/request.rs Normal file
View file

@ -0,0 +1,69 @@
use super::{body::Body, header::Header, Command, MessageType};
pub struct CommandRequest {
command: Command,
}
impl CommandRequest {
fn checksum(data: &[u8]) -> u8 {
((!data.iter().map(|&b| b as u16).sum::<u16>() + 1) & 0xFF) as u8
}
pub fn new(
device_protocol_version: u8,
device_type: u8,
message_type: MessageType,
body: Body,
) -> Self {
Self {
command: Command {
header: Header::new(
body.len() as u8,
device_type,
device_protocol_version,
message_type,
),
body,
},
}
}
pub fn serialize(&self, body: &[u8]) -> Vec<u8> {
let mut stream = Vec::new();
stream.extend_from_slice(self.command.header.raw());
stream.extend_from_slice(self.command.body.raw());
stream.push(Self::checksum(&stream[1..]));
stream
}
}
pub struct CommandQuerySubtype {
command: CommandRequest,
}
impl CommandQuerySubtype {
pub fn new(device_type: u8) -> Self {
Self {
command: CommandRequest::new(
0,
device_type,
MessageType::QuerySubtype,
Body::from([0x00; 18].as_slice()),
),
}
}
}
pub struct CommandQueryCustom {
command: CommandRequest,
}
impl CommandQueryCustom {
pub fn new(device_type: u8, message_type: MessageType, body: Body) -> Self {
Self {
command: CommandRequest::new(0, device_type, message_type, body),
}
}
}

46
src/command/response.rs Normal file
View file

@ -0,0 +1,46 @@
use super::{body::Body, header::Header, Command, MessageType};
pub struct CommandResponse {
command: Command,
}
impl CommandResponse {
pub fn new(msg: &[u8]) -> Self {
Self {
command: Command {
header: Header::from(msg),
body: Body::from(msg),
},
}
}
}
pub struct CommandSubtypeResponse {
command: CommandResponse,
pub sub_type: u16,
}
impl CommandSubtypeResponse {
pub fn new(msg: &[u8]) -> Self {
let command = CommandResponse::new(msg);
let sub_type = match command.command.header.message_type() {
MessageType::QuerySubtype => {
let body = &command.command.body;
let t = if body.len() > 2 { body[2] as u16 } else { 0 }
+ if body.len() > 3 {
(body[3] as u16) << 8
} else {
0
};
t
}
_ => 0,
};
Self { command, sub_type }
}
}

View file

@ -10,7 +10,7 @@ use anyhow::{bail, Context, Error, Result};
use serde_json::to_string;
use crate::{
command::Command,
command::{Command, MessageType},
devices::{e1::E1, DeviceBackend},
hex,
packet_builder::PacketBuilder,
@ -18,18 +18,6 @@ use crate::{
DeviceInfo,
};
#[repr(u8)]
enum MessageType {
Set = 0x02,
Query = 0x03,
Notify1 = 0x04,
Notify2 = 0x05,
Exception = 0x06,
QuerySN = 0x07,
Exception2 = 0x0A,
QuerySubtype = 0xA0,
}
enum ParseMessage {
Success,
Padding,

View file

@ -192,7 +192,7 @@ impl E1 {
impl DeviceBackend for E1 {
fn build_query(&self, device_protocol_version: u32) -> Result<Vec<Command>> {
Ok(vec![Command::query(device_protocol_version)])
Ok(vec![CommandQuery::new(device_protocol_version)])
}
fn process_message(&self, msg: &[u8]) -> Result<Vec<u8>> {

View file

@ -1,5 +1,8 @@
use std::num::ParseIntError;
#[macro_use]
extern crate num_derive;
mod cloud;
mod cloud_security;
mod command;