Split command into sub structs
This commit is contained in:
parent
c184fc603e
commit
631e88aa46
10 changed files with 270 additions and 79 deletions
|
@ -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"] }
|
||||
|
|
|
@ -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
41
src/command/body.rs
Normal 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
71
src/command/header.rs
Normal 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
36
src/command/mod.rs
Normal 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
69
src/command/request.rs
Normal 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
46
src/command/response.rs
Normal 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 }
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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>> {
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
use std::num::ParseIntError;
|
||||
|
||||
#[macro_use]
|
||||
extern crate num_derive;
|
||||
|
||||
mod cloud;
|
||||
mod cloud_security;
|
||||
mod command;
|
||||
|
|
Loading…
Reference in a new issue