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"] }
|
tokio = { version = "1.32.0", features=["macros", "rt-multi-thread"] }
|
||||||
futures = "0.3.28"
|
futures = "0.3.28"
|
||||||
serial_test = "2.0.0"
|
serial_test = "2.0.0"
|
||||||
|
num-traits = "0.2.0"
|
||||||
|
num-derive = "0.4.0"
|
||||||
|
|
||||||
#crypto
|
#crypto
|
||||||
cbc = { version = "0.1.2", features = ["alloc"] }
|
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 serde_json::to_string;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
command::Command,
|
command::{Command, MessageType},
|
||||||
devices::{e1::E1, DeviceBackend},
|
devices::{e1::E1, DeviceBackend},
|
||||||
hex,
|
hex,
|
||||||
packet_builder::PacketBuilder,
|
packet_builder::PacketBuilder,
|
||||||
|
@ -18,18 +18,6 @@ use crate::{
|
||||||
DeviceInfo,
|
DeviceInfo,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[repr(u8)]
|
|
||||||
enum MessageType {
|
|
||||||
Set = 0x02,
|
|
||||||
Query = 0x03,
|
|
||||||
Notify1 = 0x04,
|
|
||||||
Notify2 = 0x05,
|
|
||||||
Exception = 0x06,
|
|
||||||
QuerySN = 0x07,
|
|
||||||
Exception2 = 0x0A,
|
|
||||||
QuerySubtype = 0xA0,
|
|
||||||
}
|
|
||||||
|
|
||||||
enum ParseMessage {
|
enum ParseMessage {
|
||||||
Success,
|
Success,
|
||||||
Padding,
|
Padding,
|
||||||
|
|
|
@ -192,7 +192,7 @@ impl E1 {
|
||||||
|
|
||||||
impl DeviceBackend for E1 {
|
impl DeviceBackend for E1 {
|
||||||
fn build_query(&self, device_protocol_version: u32) -> Result<Vec<Command>> {
|
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>> {
|
fn process_message(&self, msg: &[u8]) -> Result<Vec<u8>> {
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
use std::num::ParseIntError;
|
use std::num::ParseIntError;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate num_derive;
|
||||||
|
|
||||||
mod cloud;
|
mod cloud;
|
||||||
mod cloud_security;
|
mod cloud_security;
|
||||||
mod command;
|
mod command;
|
||||||
|
|
Loading…
Reference in a new issue