fix: implement new proto spec
This commit is contained in:
parent
53f1b36505
commit
5811d29032
9 changed files with 161 additions and 46 deletions
|
@ -1,8 +1,15 @@
|
||||||
use crate::packet::packet_data::PacketData;
|
use crate::packet::packet_data::PacketData;
|
||||||
|
|
||||||
|
/// NM = Node Management
|
||||||
|
/// This is the abstraction for managing nodes.
|
||||||
pub mod node_management;
|
pub mod node_management;
|
||||||
|
/// PC = Property Control
|
||||||
|
/// This is the abstraction for controling properties on a node.
|
||||||
pub mod property_control;
|
pub mod property_control;
|
||||||
|
/// RDT = Raw Data Transmission
|
||||||
|
/// This is the abstraction for sending raw data over domo.
|
||||||
|
pub mod raw_data_transmission;
|
||||||
|
|
||||||
impl_into_enum_variant!(PacketData::NodeManagement, node_management::NodeManagementCommand);
|
impl_into_enum_variant!(PacketData::NodeManagement, node_management::NodeManagementCommand);
|
||||||
impl_into_enum_variant!(PacketData::PropertyControl, property_control::PropertyControlCommand);
|
impl_into_enum_variant!(PacketData::PropertyControl, property_control::PropertyControlCommand);
|
||||||
impl_into_enum_variant!(PacketData::Raw, Vec<u8>);
|
impl_into_enum_variant!(PacketData::Unknown, Vec<u8>);
|
||||||
|
|
78
domo_proto/src/commands/raw_data_transmission/mod.rs
Normal file
78
domo_proto/src/commands/raw_data_transmission/mod.rs
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
identifier::Identifier,
|
||||||
|
packet::{packet_data::PacketData, raw_packet::RawPacket, Packet, ToPacket},
|
||||||
|
prelude::as_u32_be,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub mod vec;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum RawDataTransmission {
|
||||||
|
SetupTransmission {
|
||||||
|
/// The total size of the data being sent.
|
||||||
|
size: u64,
|
||||||
|
/// This string is the mime type of the data being sent.
|
||||||
|
/// By default this should be `application/octet-stream`.
|
||||||
|
/// The maximum length of this string is 128 bytes since the mime rfc states the recommended max is 127 bytes.
|
||||||
|
mime_type: String,
|
||||||
|
},
|
||||||
|
Data {
|
||||||
|
/// The number of the segment in the sequence of segments being sent.
|
||||||
|
sequence_number: u32,
|
||||||
|
/// Segment size in bytes
|
||||||
|
size: u32,
|
||||||
|
/// A segment of the data being sent
|
||||||
|
data: Vec<u8>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToPacket for RawDataTransmission {
|
||||||
|
fn to_packet(
|
||||||
|
self,
|
||||||
|
src: Identifier,
|
||||||
|
dest: Identifier,
|
||||||
|
packet_id: Identifier,
|
||||||
|
reply_to: Identifier,
|
||||||
|
) -> Packet {
|
||||||
|
Packet {
|
||||||
|
src,
|
||||||
|
dest,
|
||||||
|
packet_id,
|
||||||
|
reply_to,
|
||||||
|
command: 0x20,
|
||||||
|
data: PacketData::RawDataTransmission(self.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<RawPacket> for RawDataTransmission {
|
||||||
|
type Error = io::Error;
|
||||||
|
fn try_from(raw_packet: RawPacket) -> io::Result<Self> {
|
||||||
|
let build_invalid_input_err = |r: &str| Err(io::Error::new(io::ErrorKind::InvalidInput, r));
|
||||||
|
|
||||||
|
let mut data = raw_packet.data;
|
||||||
|
match raw_packet.command {
|
||||||
|
0x20 => {
|
||||||
|
let size = u64::from_be_bytes([
|
||||||
|
data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
|
||||||
|
]);
|
||||||
|
let mime_type = String::from_utf8(data[8..].to_vec()).map_err(|_| {
|
||||||
|
io::Error::new(io::ErrorKind::InvalidInput, "Invalid mime type string")
|
||||||
|
})?;
|
||||||
|
Ok(RawDataTransmission::SetupTransmission { size, mime_type })
|
||||||
|
}
|
||||||
|
0x21 => {
|
||||||
|
let sequence_number = as_u32_be(&mut data);
|
||||||
|
let size = as_u32_be(&mut data);
|
||||||
|
Ok(RawDataTransmission::Data {
|
||||||
|
sequence_number,
|
||||||
|
size,
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => build_invalid_input_err("Invalid command"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
domo_proto/src/commands/raw_data_transmission/vec.rs
Normal file
21
domo_proto/src/commands/raw_data_transmission/vec.rs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
use super::RawDataTransmission;
|
||||||
|
|
||||||
|
impl Into<Vec<u8>> for RawDataTransmission {
|
||||||
|
fn into(self) -> Vec<u8> {
|
||||||
|
match self {
|
||||||
|
RawDataTransmission::SetupTransmission { size, mime_type } => {
|
||||||
|
let mut v = vec![];
|
||||||
|
v.extend(size.to_be_bytes().to_vec());
|
||||||
|
v.extend(mime_type.into_bytes());
|
||||||
|
v
|
||||||
|
},
|
||||||
|
RawDataTransmission::Data { sequence_number, size, data } => {
|
||||||
|
let mut v = vec![];
|
||||||
|
v.extend(sequence_number.to_be_bytes().to_vec());
|
||||||
|
v.extend(size.to_be_bytes().to_vec());
|
||||||
|
v.extend(data);
|
||||||
|
v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,39 +11,30 @@ pub enum DataType {
|
||||||
Array(Vec<DataType>),
|
Array(Vec<DataType>),
|
||||||
|
|
||||||
// Basic types
|
// Basic types
|
||||||
/// Basic Type: Switch (`0x10`]
|
/// Basic Type: Boolean (`0x10`]
|
||||||
Switch(bool),
|
Boolean(bool),
|
||||||
/// Basic Type: Slider (`0x11`)
|
/// Basic Type: Slider (`0x11`)
|
||||||
Slider(u8),
|
Number(u64),
|
||||||
/// Basic Type: Text (`0x12`)
|
/// Basic Type: Text (`0x12`)
|
||||||
Text(String),
|
Text(String),
|
||||||
|
/// Basic Type: Identifier (`0x13`)
|
||||||
|
Identifier(Identifier),
|
||||||
|
|
||||||
// Cosmetic
|
// Color
|
||||||
/// Cosmetic Type: RGB (`0x20`)
|
/// Color Type: RGB (`0x20`)
|
||||||
RGB(u8, u8, u8),
|
RGB(u8, u8, u8),
|
||||||
|
|
||||||
// Time & Space
|
|
||||||
/// Time & Space Type: Seconds (`0x90`)
|
|
||||||
Seconds(u64),
|
|
||||||
|
|
||||||
// Domo Types
|
|
||||||
/// Domo type: Node Ref (`0xF0`)
|
|
||||||
NodeRef(Identifier),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DataType {
|
impl DataType {
|
||||||
pub fn get_data_size(data_type: u8) -> usize {
|
pub fn get_data_size(data_type: u8) -> usize {
|
||||||
match data_type {
|
match data_type {
|
||||||
0x00 => 0,
|
0x00 => 0,
|
||||||
0x01 => {
|
0x01 => 2,
|
||||||
2
|
|
||||||
},
|
|
||||||
0x10 => 1,
|
0x10 => 1,
|
||||||
0x11 => 1,
|
0x11 => 8,
|
||||||
0x12 => 256,
|
0x12 => 256,
|
||||||
|
0x13 => 4,
|
||||||
0x20 => 3,
|
0x20 => 3,
|
||||||
0x90 => 8,
|
|
||||||
0xF0 => 4,
|
|
||||||
_ => 0,
|
_ => 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::io;
|
use std::io;
|
||||||
use crate::data_types::{DataType, get_data_types};
|
use crate::data_types::{DataType, get_data_types};
|
||||||
use crate::identifier::Identifier;
|
use crate::identifier::{Identifier, self};
|
||||||
use crate::prelude::as_u64_be;
|
use crate::prelude::as_u64_be;
|
||||||
|
|
||||||
impl Into<Vec<u8>> for DataType {
|
impl Into<Vec<u8>> for DataType {
|
||||||
|
@ -14,24 +14,23 @@ impl Into<Vec<u8>> for DataType {
|
||||||
}
|
}
|
||||||
res
|
res
|
||||||
},
|
},
|
||||||
DataType::Switch(b) => vec![0x10, b as u8],
|
DataType::Boolean(b) => vec![0x10, b as u8],
|
||||||
DataType::Slider(v) => vec![0x11, v],
|
DataType::Number(v) => {
|
||||||
|
let mut bytes = vec![0x11];
|
||||||
|
bytes.extend(v.to_be_bytes());
|
||||||
|
bytes
|
||||||
|
},
|
||||||
DataType::Text(s) => {
|
DataType::Text(s) => {
|
||||||
let mut bytes = vec![0x12];
|
let mut bytes = vec![0x12];
|
||||||
bytes.extend(s.into_bytes());
|
bytes.extend(s.into_bytes());
|
||||||
bytes
|
bytes
|
||||||
},
|
},
|
||||||
|
DataType::Identifier(identifier) => {
|
||||||
|
let mut bytes = vec![0x13];
|
||||||
|
bytes.extend(identifier.bytes);
|
||||||
|
bytes
|
||||||
|
},
|
||||||
DataType::RGB(r, g, b) => vec![0x20, r, g, b],
|
DataType::RGB(r, g, b) => vec![0x20, r, g, b],
|
||||||
DataType::Seconds(s) => {
|
|
||||||
let mut bytes = vec![0x90];
|
|
||||||
bytes.extend_from_slice(s.to_be_bytes().as_ref());
|
|
||||||
bytes
|
|
||||||
},
|
|
||||||
DataType::NodeRef(id) => {
|
|
||||||
let mut bytes = vec![0xF0];
|
|
||||||
bytes.extend_from_slice(id.bytes.as_ref());
|
|
||||||
bytes
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,8 +60,11 @@ impl TryFrom<Vec<u8>> for DataType {
|
||||||
if value.len() - 1 < size as usize { return Err(io::Error::new(io::ErrorKind::InvalidData, "Array specified data length != array data length")) }
|
if value.len() - 1 < size as usize { return Err(io::Error::new(io::ErrorKind::InvalidData, "Array specified data length != array data length")) }
|
||||||
Ok(DataType::Array(get_data_types(value[3..(size as usize)].to_vec())))
|
Ok(DataType::Array(get_data_types(value[3..(size as usize)].to_vec())))
|
||||||
},
|
},
|
||||||
0x10 => impl_data_type!(value, 1, DataType::Switch(value[1] != 0)),
|
0x10 => impl_data_type!(value, 1, DataType::Boolean(value[1] != 0)),
|
||||||
0x11 => impl_data_type!(value, 1, DataType::Slider(value[1])),
|
0x11 => impl_data_type!(value, 8, DataType::Number(u64::from_be_bytes([
|
||||||
|
value[1], value[2], value[3], value[4],
|
||||||
|
value[5], value[6], value[7], value[8]
|
||||||
|
]))),
|
||||||
0x12 => impl_data_type!(
|
0x12 => impl_data_type!(
|
||||||
value,
|
value,
|
||||||
256,
|
256,
|
||||||
|
@ -72,9 +74,8 @@ impl TryFrom<Vec<u8>> for DataType {
|
||||||
DataType::Nothing
|
DataType::Nothing
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
0x13 => impl_data_type!(value, 4, DataType::Identifier(Identifier::from(&value[1..5]))),
|
||||||
0x20 => impl_data_type!(value, 3, DataType::RGB(value[1], value[2], value[3])),
|
0x20 => impl_data_type!(value, 3, DataType::RGB(value[1], value[2], value[3])),
|
||||||
0x90 => impl_data_type!(value, 8, DataType::Seconds(as_u64_be(&value[1..9]))),
|
|
||||||
0xF0 => impl_data_type!(value, 4, DataType::NodeRef(Identifier::from(&value[1..5]))),
|
|
||||||
_ => Err(io::Error::new(io::ErrorKind::InvalidData, "Could not match data type header to a data type.")),
|
_ => Err(io::Error::new(io::ErrorKind::InvalidData, "Could not match data type header to a data type.")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//! Welcome to the Domo protocol rust implementation.
|
//! Welcome to the Domo protocol rust implementation.
|
||||||
//!
|
//!
|
||||||
//! This implementation is up-to-date with DomoProto v1.
|
//! This implementation is up-to-date with Domo protocol v1.
|
||||||
//!
|
//!
|
||||||
//! Most code that should/is actually used (usually) has documentation with it.
|
//! Most code that should/is actually used (usually) has documentation with it.
|
||||||
|
|
||||||
|
@ -27,7 +27,6 @@ mod tests {
|
||||||
use crate::packet;
|
use crate::packet;
|
||||||
use crate::data_types::{DataType, get_data_types};
|
use crate::data_types::{DataType, get_data_types};
|
||||||
use crate::identifier::Identifier;
|
use crate::identifier::Identifier;
|
||||||
use crate::packet::Packet;
|
|
||||||
use crate::packet::packet_data::PacketData;
|
use crate::packet::packet_data::PacketData;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -37,12 +36,12 @@ mod tests {
|
||||||
get_data_types(vec![0x00, 0x10, 0x00]),
|
get_data_types(vec![0x00, 0x10, 0x00]),
|
||||||
vec![
|
vec![
|
||||||
DataType::Nothing,
|
DataType::Nothing,
|
||||||
DataType::Switch(false),
|
DataType::Boolean(false),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// test DataType -> Vec<u8>
|
// test DataType -> Vec<u8>
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Into::<Vec<u8>>::into(DataType::Switch(true)),
|
Into::<Vec<u8>>::into(DataType::Boolean(true)),
|
||||||
vec![0x10, 0x01]
|
vec![0x10, 0x01]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ pub const FULL_PACKET_SIZE: usize = 65559;
|
||||||
pub const BASE_PACKET_SIZE: usize = 65555;
|
pub const BASE_PACKET_SIZE: usize = 65555;
|
||||||
|
|
||||||
/// The abstraction for all DomoProto packets.
|
/// The abstraction for all DomoProto packets.
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Packet {
|
pub struct Packet {
|
||||||
pub dest: Identifier,
|
pub dest: Identifier,
|
||||||
pub src: Identifier,
|
pub src: Identifier,
|
||||||
|
@ -31,6 +31,20 @@ pub trait ToPacket {
|
||||||
fn to_packet(self, src: Identifier, dest: Identifier, packet_id: Identifier, reply_to: Identifier) -> Packet;
|
fn to_packet(self, src: Identifier, dest: Identifier, packet_id: Identifier, reply_to: Identifier) -> Packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Default packet is a ping from 0x0 to 0xFFFFFFFF
|
||||||
|
impl Default for Packet {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
dest: Identifier::from(0xFFFFFFFF),
|
||||||
|
src: Identifier::from(0),
|
||||||
|
command: 0x00,
|
||||||
|
packet_id: Identifier::random(),
|
||||||
|
reply_to: Identifier::default(),
|
||||||
|
data: PacketData::Unknown(vec![])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Secretly calls RawPacket::try_from().into()
|
/// Secretly calls RawPacket::try_from().into()
|
||||||
impl TryFrom<Vec<u8>> for Packet {
|
impl TryFrom<Vec<u8>> for Packet {
|
||||||
type Error = io::Error;
|
type Error = io::Error;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use std::io;
|
use std::io;
|
||||||
use crate::commands::property_control::PropertyControlCommand;
|
use crate::commands::property_control::PropertyControlCommand;
|
||||||
use crate::commands::node_management::NodeManagementCommand;
|
use crate::commands::node_management::NodeManagementCommand;
|
||||||
|
use crate::commands::raw_data_transmission::RawDataTransmission;
|
||||||
use crate::packet::raw_packet::RawPacket;
|
use crate::packet::raw_packet::RawPacket;
|
||||||
|
|
||||||
/// Abstraction used for interpreting the data in a packet.
|
/// Abstraction used for interpreting the data in a packet.
|
||||||
|
@ -8,13 +9,14 @@ use crate::packet::raw_packet::RawPacket;
|
||||||
pub enum PacketData {
|
pub enum PacketData {
|
||||||
NodeManagement(NodeManagementCommand),
|
NodeManagement(NodeManagementCommand),
|
||||||
PropertyControl(PropertyControlCommand),
|
PropertyControl(PropertyControlCommand),
|
||||||
Raw(Vec<u8>)
|
RawDataTransmission(RawDataTransmission),
|
||||||
|
Unknown(Vec<u8>)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an empty `PacketData::Raw`
|
/// Returns an empty `PacketData::Raw`
|
||||||
impl Default for PacketData {
|
impl Default for PacketData {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
PacketData::Raw(vec![])
|
PacketData::Unknown(vec![])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +25,8 @@ impl PacketData {
|
||||||
match self {
|
match self {
|
||||||
PacketData::NodeManagement(v) => v.into(),
|
PacketData::NodeManagement(v) => v.into(),
|
||||||
PacketData::PropertyControl(v) => v.into(),
|
PacketData::PropertyControl(v) => v.into(),
|
||||||
PacketData::Raw(v) => v
|
PacketData::RawDataTransmission(v) => v.into(),
|
||||||
|
PacketData::Unknown(v) => v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,6 +39,7 @@ impl TryFrom<RawPacket> for PacketData {
|
||||||
} {
|
} {
|
||||||
0x0 => Ok(PacketData::NodeManagement(NodeManagementCommand::try_from(raw_packet)?)),
|
0x0 => Ok(PacketData::NodeManagement(NodeManagementCommand::try_from(raw_packet)?)),
|
||||||
0x1 => Ok(PacketData::PropertyControl(PropertyControlCommand::try_from(raw_packet)?)),
|
0x1 => Ok(PacketData::PropertyControl(PropertyControlCommand::try_from(raw_packet)?)),
|
||||||
|
0xF => Ok(PacketData::RawDataTransmission(RawDataTransmission::try_from(raw_packet)?)),
|
||||||
_ => Err(io::Error::new(io::ErrorKind::InvalidInput, "command group is unsupported"))
|
_ => Err(io::Error::new(io::ErrorKind::InvalidInput, "command group is unsupported"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ impl Into<Packet> for RawPacket {
|
||||||
println!("{}", e);
|
println!("{}", e);
|
||||||
e
|
e
|
||||||
})
|
})
|
||||||
.unwrap_or(PacketData::Raw(self.data)),
|
.unwrap_or(PacketData::Unknown(self.data)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue