feat: rewrite spec and proto
This commit is contained in:
parent
11e58c3d1d
commit
7999ac6103
6 changed files with 298 additions and 144 deletions
|
@ -1,10 +1,69 @@
|
|||
> **Version:** `1`
|
||||
> **Authored by:** `Raine <raine@ixvd.net>`
|
||||
> **Status**: `planning`
|
||||
>
|
||||
# Table of contents
|
||||
- [Table of contents](#table-of-contents)
|
||||
- [Prelude](#prelude)
|
||||
- [Interpretation of types](#interpretation-of-types)
|
||||
- [Booleans](#booleans)
|
||||
- [Reserved fields](#reserved-fields)
|
||||
- [Structure](#structure)
|
||||
- [Data types](#data-types)
|
||||
- [Dynamic data (`dynamic_data`)](#dynamic-data-dynamic_data)
|
||||
- [Commands](#commands)
|
||||
- [`0x0*` - Node management](#0x0---node-management)
|
||||
- [`0x00` - Ping](#0x00---ping)
|
||||
- [Command data](#command-data)
|
||||
- [`0x01` - Register node](#0x01---register-node)
|
||||
- [Command data](#command-data-1)
|
||||
- [`0x02` - Remove node](#0x02---remove-node)
|
||||
- [Command data](#command-data-2)
|
||||
- [`0x0A` - Acknowledge packets](#0x0a---acknowledge-packets)
|
||||
- [`0x0E` - Error](#0x0e---error)
|
||||
- [Command data](#command-data-3)
|
||||
- [Error codes](#error-codes)
|
||||
- [`0x1*` - Properties control](#0x1---properties-control)
|
||||
- [`0x10` - Register property](#0x10---register-property)
|
||||
- [Command data](#command-data-4)
|
||||
- [`0x11` - Remove property](#0x11---remove-property)
|
||||
- [Command data](#command-data-5)
|
||||
- [`0x12` - Get property](#0x12---get-property)
|
||||
- [Command data](#command-data-6)
|
||||
- [`0x13` - Set property](#0x13---set-property)
|
||||
- [Command data](#command-data-7)
|
||||
- [`0x14` - Reset property](#0x14---reset-property)
|
||||
- [Command data](#command-data-8)
|
||||
- [`0x1A` - Subscribe to property](#0x1a---subscribe-to-property)
|
||||
- [`0x1B` - Unsubscribe to property](#0x1b---unsubscribe-to-property)
|
||||
- [`0x1F` - All properties](#0x1f---all-properties)
|
||||
- [Command data](#command-data-9)
|
||||
- [`0xF*` - Raw data transmission](#0xf---raw-data-transmission)
|
||||
- [`0xF0` - Setup transfer](#0xf0---setup-transfer)
|
||||
- [Command data](#command-data-10)
|
||||
- [`0xF1` - Data](#0xf1---data)
|
||||
- [Command data](#command-data-11)
|
||||
|
||||
|
||||
# Prelude
|
||||
|
||||
Version 1 has zero security on itself.
|
||||
This document only describes what the protocol looks like.
|
||||
The specification can be found at `./specification.md`.
|
||||
|
||||
## Interpretation of types
|
||||
|
||||
### Booleans
|
||||
|
||||
If in the description of a property it's marked as a boolean the exact logic that should be executed is:
|
||||
`value != 0`
|
||||
|
||||
## Reserved fields
|
||||
|
||||
The "reserved" column (if present) will state what should be filled in by each side.
|
||||
|
||||
- "no": this should be filled in by both sides. (default)
|
||||
- "request": this should only be filled in the request.
|
||||
- "response": this should only be filled in the response.
|
||||
|
||||
|
||||
# Structure
|
||||
|
||||
|
@ -22,30 +81,6 @@ Packets are sent in big endian.
|
|||
| `0x14` | `<0x11-0x12:data_length>` | `data` | This is the data of the command | `0x0000` |
|
||||
| `0x14 + <0x11-0x12:data_length>` | 4 bytes | `checksum` | This is the CRC32 checksum of the packet without the checksum. | `0x00000000` |
|
||||
|
||||
# Packets in practice
|
||||
|
||||
## Statuses
|
||||
|
||||
When an error occurs the response should be a `0x0E` (error command).
|
||||
This can contain error data.
|
||||
|
||||
To mark a success, you should just send back the expected response.
|
||||
|
||||
## Reserved fields
|
||||
|
||||
The "reserved" column (if present) will state what should be filled in by each side.
|
||||
|
||||
- "no": this should be filled in by both sides. (default)
|
||||
- "request": this should only be filled in the request.
|
||||
- "response": this should only be filled in the response.
|
||||
|
||||
# Error checking
|
||||
|
||||
If the CRC32 doesn't match up the receiver will send a `0x0E` (error) packet to the probable source.
|
||||
The error code `0x01`/`net_broken_packet` should be used. The metadata may contain some textual info on what went
|
||||
wrong.
|
||||
The master will not track the broken packet's `packet_id`, so the slave can send it again.
|
||||
|
||||
# Data types
|
||||
|
||||
Domo has a data framework reliant on data types.
|
||||
|
@ -64,23 +99,16 @@ These define what kind of data the property holds.
|
|||
| `0x2*` | | | **Color** |
|
||||
| `0x20` | 3 bytes | RGB | An RGB value. |
|
||||
|
||||
<!--
|
||||
REQ prop/get "firmware"
|
||||
RES prop/get <DataType::Identifier(0xABFF21FA)> // this is the setup packet id
|
||||
RES raw/setup size=10B
|
||||
RES raw/data [0x0000 (0x2710)] ....
|
||||
-->
|
||||
|
||||
## Dynamic data (`dynamic_data`)
|
||||
|
||||
Dynamic data is a data snippet with a `prop_data_type` byte and the data next to it.
|
||||
|
||||
> **Note**: this section uses relative offset
|
||||
|
||||
| offset | size | name | description | example |
|
||||
| ------ | ----------------------------- | ---------------- | ----------------------- | ------- |
|
||||
| `0x00` | 1 byte | `prop_data_type` | Describes the data type | `0x00` |
|
||||
| `0x01` | depending on `prop_data_type` | `data` | The data | |
|
||||
| offset | size | name | description | example |
|
||||
| ------ | --------------------------- | ---------------- | ----------------------- | ------- |
|
||||
| `0x00` | 1 byte | `prop_data_type` | Describes the data type | `0x00` |
|
||||
| `0x01` | depends on `prop_data_type` | `data` | The data | |
|
||||
|
||||
# Commands
|
||||
|
||||
|
@ -121,23 +149,13 @@ Remove node from network
|
|||
|
||||
there is no extra data required.
|
||||
|
||||
### `0x03` - Register property
|
||||
### `0x0A` - Acknowledge packets
|
||||
|
||||
#### Command data
|
||||
Acknowledge received packets.
|
||||
|
||||
| offset | size | name | description | reserved | example |
|
||||
| ------ | -------- | --------------- | ------------------------------------------------------------------ | -------- | ------- |
|
||||
| `0x14` | 32 bytes | `property_name` | The name of the property as a UTF-8 string. | no | "Power" |
|
||||
| `0x34` | 1 byte | `data_type` | The type of data; see "Data types". | no | `0x01` |
|
||||
| `0x35` | 1 byte | `read_only` | Whether the property is readonly. <br/>(`0x00` = no, `0x01` = yes) | no | `0x00` |
|
||||
|
||||
### `0x04` - Remove property
|
||||
|
||||
#### Command data
|
||||
|
||||
| offset | size | name | description | reserved | example |
|
||||
| ------ | -------- | --------------- | ------------------------------------------- | -------- | ------- |
|
||||
| `0x14` | 32 bytes | `property_name` | The name of the property as a UTF-8 string. | no | "Power" |
|
||||
| offset | size | name | description | reserved | example |
|
||||
| ------ | ------------- | ----------- | ---------------------------------- | ----------- | ------- |
|
||||
| `0x14` | 4 bytes * `n` | `packet_id` | list of packet_id's to acknowledge | origin node | |
|
||||
|
||||
### `0x0E` - Error
|
||||
|
||||
|
@ -145,10 +163,10 @@ Send a packet to state an error occurred.
|
|||
|
||||
#### Command data
|
||||
|
||||
| offset | size | name | description | example |
|
||||
| ------ | ----------------------------- | ------------ | ------------------------------- | ------- |
|
||||
| `0x14` | 1 byte | `error_code` | error code; check 'Error codes' | `0x00` |
|
||||
| `0x15` | `<0x14-0x15:metadata_length>` | `metadata` | metadata | |
|
||||
| offset | size | name | description | example |
|
||||
| ------ | ------------- | ------------ | ------------------------------- | ------- |
|
||||
| `0x14` | 1 byte | `error_code` | error code; check 'Error codes' | `0x00` |
|
||||
| `0x15` | `data_length` | `metadata` | metadata | |
|
||||
|
||||
#### Error codes
|
||||
|
||||
|
@ -167,20 +185,40 @@ Send a packet to state an error occurred.
|
|||
| `0x20` | `node_invalid_property` | the property specified is invalid | no |
|
||||
| `0x21` | `node_failed_request` | the request could not be completed. | consult metadata |
|
||||
|
||||
|
||||
## `0x1*` - Properties control
|
||||
|
||||
### `0x10` - Get property
|
||||
### `0x10` - Register property
|
||||
|
||||
#### Command data
|
||||
|
||||
| offset | size | name | description | reserved | example |
|
||||
| ------ | -------- | --------------- | ---------------------------------------------- | -------- | ------- |
|
||||
| `0x14` | 32 bytes | `property_name` | The name of the property as a UTF-8 string. | no | "Power" |
|
||||
| `0x34` | 1 byte | `data_type` | The type of data; see "Data types". | no | `0x01` |
|
||||
| `0x35` | 1 byte | `read_only` | Whether the property is readonly. (boolean) | no | `0x00` |
|
||||
| `0x36` | 1 byte | `descriptive` | Whether the property is descriptive. (boolean) | no | `0x00` |
|
||||
|
||||
### `0x11` - Remove property
|
||||
|
||||
#### Command data
|
||||
|
||||
| offset | size | name | description | reserved | example |
|
||||
| ------ | -------- | --------------- | ------------------------------------------- | -------- | ------- |
|
||||
| `0x14` | 32 bytes | `property_name` | The name of the property as a UTF-8 string. | no | "Power" |
|
||||
|
||||
### `0x12` - Get property
|
||||
|
||||
Get a properties value
|
||||
|
||||
#### Command data
|
||||
|
||||
| offset | size | name | description | reserved | example |
|
||||
| ------ | -------- | --------------- | ------------------------------------------- | -------- | -------- |
|
||||
| `0x14` | 32 bytes | `property_name` | The name of the property as a UTF-8 string. | no | "Power" |
|
||||
| `0x34` | dynamic | `dynamic_data` | Dynamic data snippet | response | `0x0100` |
|
||||
| offset | size | name | description | reserved | example |
|
||||
| ------ | -------- | --------------- | ------------------------------------------- | ---------------- | -------- |
|
||||
| `0x14` | 32 bytes | `property_name` | The name of the property as a UTF-8 string. | no | "Power" |
|
||||
| `0x34` | dynamic | `dynamic_data` | Dynamic data snippet | destination node | `0x0100` |
|
||||
|
||||
### `0x11` - Set property
|
||||
### `0x13` - Set property
|
||||
|
||||
#### Command data
|
||||
|
||||
|
@ -189,7 +227,7 @@ Get a properties value
|
|||
| `0x14` | 32 bytes | `property_name` | The name of the property as a UTF-8 string. | no | "Power" |
|
||||
| `0x34` | dynamic | `dynamic_data` | Dynamic data snippet | no | `0x0100` |
|
||||
|
||||
### `0x12` - Reset property
|
||||
### `0x14` - Reset property
|
||||
|
||||
#### Command data
|
||||
|
||||
|
@ -204,13 +242,26 @@ Get a properties value
|
|||
| `0x14` | 4 bytes | `device_id` | Who's property? | no | `0x00000000` |
|
||||
| `0x18` | 32 bytes | `property_name` | The name of the property as a UTF-8 string. | no | "Power" |
|
||||
|
||||
### `0x1A` - Unsubscribe to property
|
||||
### `0x1B` - Unsubscribe to property
|
||||
|
||||
| offset | size | name | description | reserved | example |
|
||||
| ------ | -------- | --------------- | ------------------------------------------- | -------- | ------------ |
|
||||
| `0x14` | 4 bytes | `device_id` | Who's property? | no | `0x00000000` |
|
||||
| `0x18` | 32 bytes | `property_name` | The name of the property as a UTF-8 string. | no | "Power" |
|
||||
|
||||
### `0x1F` - All properties
|
||||
|
||||
Return all properties.
|
||||
|
||||
#### Command data
|
||||
|
||||
| offset | size | name | description | reserved | example |
|
||||
| ------ | ------ | ------ | ------------------------- | -------- | ------- |
|
||||
| `0x14` | 1 byte | `type` | | no | `0x00` |
|
||||
| | | | `0x00` - all | | |
|
||||
| | | | `0x01` - descriptive only | | |
|
||||
| | | | `0x02` - m only | | |
|
||||
|
||||
## `0xF*` - Raw data transmission
|
||||
|
||||
This is useful for things like OTA updates.
|
||||
|
@ -221,10 +272,10 @@ Since this procedure is quite expensive (network wise), the sides must shake han
|
|||
|
||||
#### Command data
|
||||
|
||||
| offset | size | name | description | reserved | example |
|
||||
| ------ | --------- | ------ | -------------------- | -------- | ------- |
|
||||
| `0x14` | 8 bytes | `size` | u64 size of the data | request | `0x00` |
|
||||
| `0x1c` | 128 bytes | `mime` | media type of data | request | `0x00` |
|
||||
| offset | size | name | description | reserved | example |
|
||||
| ------ | --------- | ------ | -------------------- | ----------- | ------- |
|
||||
| `0x14` | 8 bytes | `size` | u64 size of the data | origin node | `0x00` |
|
||||
| `0x1c` | 128 bytes | `mime` | media type of data | origin node | `0x00` |
|
||||
|
||||
### `0xF1` - Data
|
||||
|
||||
|
@ -235,7 +286,7 @@ This may be sent without the initial transfer setup for custom implementations.
|
|||
|
||||
The `sequence_number` is added for redundancy, all data sent will always reply to it's previous data segment.
|
||||
|
||||
| offset | size | name | description | example |
|
||||
| ------ | -------- | ----------------- | ------------------------------- | ------------ |
|
||||
| `0x14` | 4 bytes | `sequence_number` | the sequence number of the data | `0x00000000` |
|
||||
| `0x18` | `<size>` | `data` | the data | |
|
||||
| offset | size | name | description | example |
|
||||
| ------ | ------------- | ----------------- | ------------------------------- | ------------ |
|
||||
| `0x14` | 4 bytes | `sequence_number` | the sequence number of the data | `0x00000000` |
|
||||
| `0x18` | `data_length` | `data` | the data | |
|
46
doc/specification.md
Normal file
46
doc/specification.md
Normal file
|
@ -0,0 +1,46 @@
|
|||
# Protocol Design
|
||||
|
||||
In this document I will define how this document is designed and how it should be implemented.
|
||||
|
||||
# Prelude
|
||||
|
||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL",
|
||||
"NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and
|
||||
"OPTIONAL" in this document are to be interpreted as described in
|
||||
RFC 2119.
|
||||
|
||||
"node" or "nodes" are referring to a device that implements the Domo protocol.
|
||||
|
||||
## Transactions
|
||||
|
||||
All interactions between 2 nodes is called a transaction; a request and response.
|
||||
The initial packet sent in the transaction is called the "origin packet".
|
||||
A initial packet MUST NOT have a `reply_to`.
|
||||
A transaction consists of 2 nodes;
|
||||
- "Origin node"; the node who sent the origin packet.
|
||||
- "Destination node"; the node who is marked as the destination by the origin packet.
|
||||
|
||||
# Behaviour
|
||||
|
||||
This chapter describes the behaviour of a node.
|
||||
|
||||
## Statuses
|
||||
|
||||
When an error occurs on the destination node in result of a request, the response to the origin node MUST be a `0x0E` (error command).
|
||||
This MAY contain error data.
|
||||
To mark a success, you MUST send back the request packet altered with the data specified in the protocol.
|
||||
|
||||
## Reserved addresses
|
||||
|
||||
### Broadcast (`0xFFFFFFFF`)
|
||||
|
||||
Nodes MUST listen to this address.
|
||||
Owner nodes MUST forward this address to their owners if applicable.
|
||||
|
||||
# Packet inspection
|
||||
|
||||
## Error checking
|
||||
|
||||
If the CRC32 doesn't match up the destination node MUST send a `0x0E` (error) packet to the origin node.
|
||||
The error code `0x01`/`net_broken_packet` MUST be used. The metadata MAY contain some textual info on what went wrong.
|
||||
The master MUST not track the broken packet's `packet_id`, so the slave can send it again.
|
|
@ -12,13 +12,8 @@ pub enum NodeManagementCommand {
|
|||
Ping,
|
||||
RegisterNode { device_id: Identifier },
|
||||
RemoveNode,
|
||||
RegisterProperty {
|
||||
property_name: String,
|
||||
data_type: u8,
|
||||
read_only: bool,
|
||||
},
|
||||
RemoveProperty {
|
||||
property_name: String,
|
||||
AcknowledgePackets {
|
||||
packet_ids: Vec<Identifier>
|
||||
},
|
||||
Error {
|
||||
error_code: u8,
|
||||
|
@ -32,9 +27,8 @@ impl NodeManagementCommand {
|
|||
NodeManagementCommand::Ping => 0x00,
|
||||
NodeManagementCommand::RegisterNode { .. } => 0x01,
|
||||
NodeManagementCommand::RemoveNode => 0x02,
|
||||
NodeManagementCommand::RegisterProperty { .. } => 0x03,
|
||||
NodeManagementCommand::RemoveProperty { .. } => 0x04,
|
||||
NodeManagementCommand::Error { .. } => 0x0E
|
||||
NodeManagementCommand::AcknowledgePackets { .. } => 0x0A,
|
||||
NodeManagementCommand::Error { .. } => 0x0E,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -68,26 +62,15 @@ impl TryFrom<RawPacket> for NodeManagementCommand {
|
|||
},
|
||||
// remove node
|
||||
0x02 => Ok(NodeManagementCommand::RemoveNode),
|
||||
// register property
|
||||
0x03 => if raw_packet.data_length == 34 {
|
||||
Ok(NodeManagementCommand::RegisterProperty {
|
||||
property_name: String::from_utf8(raw_packet.data[..32].to_vec())
|
||||
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "String is not UTF-8"))?,
|
||||
data_type: raw_packet.data[33],
|
||||
read_only: raw_packet.data[34] != 0,
|
||||
})
|
||||
0x0A => if raw_packet.data_length >= 4 && (raw_packet.data_length % 4 == 0) {
|
||||
Ok(NodeManagementCommand::AcknowledgePackets {
|
||||
packet_ids: raw_packet.data.chunks(4)
|
||||
.map(|c| Identifier::from(c))
|
||||
.collect()
|
||||
})
|
||||
} else {
|
||||
build_invalid_input_err("expected 34 bytes")
|
||||
},
|
||||
// remove property
|
||||
0x04 => if raw_packet.data_length == 32 {
|
||||
Ok(NodeManagementCommand::RemoveProperty {
|
||||
property_name: String::from_utf8(raw_packet.data.to_vec())
|
||||
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "String is not UTF-8"))?
|
||||
})
|
||||
} else {
|
||||
build_invalid_input_err("expected 32 bytes")
|
||||
},
|
||||
build_invalid_input_err("expected at least 4 bytes and data_length%4=0")
|
||||
}
|
||||
// error
|
||||
0x0E => if raw_packet.data_length >= 1 {
|
||||
Ok(NodeManagementCommand::Error {
|
||||
|
|
|
@ -6,18 +6,21 @@ impl Into<Vec<u8>> for NodeManagementCommand {
|
|||
match self {
|
||||
NodeManagementCommand::Ping => vec![],
|
||||
NodeManagementCommand::RegisterNode { device_id } => {
|
||||
vec![device_id.bytes[0], device_id.bytes[1], device_id.bytes[2], device_id.bytes[3]]
|
||||
},
|
||||
vec![
|
||||
device_id.bytes[0],
|
||||
device_id.bytes[1],
|
||||
device_id.bytes[2],
|
||||
device_id.bytes[3],
|
||||
]
|
||||
}
|
||||
NodeManagementCommand::RemoveNode => vec![],
|
||||
NodeManagementCommand::RegisterProperty { property_name, data_type, read_only } => {
|
||||
let mut vec = vec![];
|
||||
vec.extend(property_name.into_bytes());
|
||||
vec.push(data_type);
|
||||
vec.push(read_only as u8);
|
||||
vec
|
||||
},
|
||||
NodeManagementCommand::RemoveProperty { property_name } => property_name.into_bytes(),
|
||||
NodeManagementCommand::Error { error_code, metadata } => {
|
||||
NodeManagementCommand::AcknowledgePackets { packet_ids } =>
|
||||
packet_ids.iter().map(|i| i.bytes).flatten().collect(),
|
||||
|
||||
NodeManagementCommand::Error {
|
||||
error_code,
|
||||
metadata,
|
||||
} => {
|
||||
let mut vec = vec![];
|
||||
vec.push(error_code);
|
||||
vec.extend(metadata);
|
||||
|
|
|
@ -1,15 +1,24 @@
|
|||
use std::io;
|
||||
use crate::data_types::DataType;
|
||||
use crate::identifier::Identifier;
|
||||
use crate::packet::packet_data::PacketData;
|
||||
use crate::packet::raw_packet::RawPacket;
|
||||
use crate::packet::{Packet, ToPacket};
|
||||
use crate::packet::packet_data::PacketData;
|
||||
use crate::prelude::as_u32_be;
|
||||
use std::io;
|
||||
|
||||
pub mod vec;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum PropertyControlCommand {
|
||||
Register {
|
||||
property_name: String,
|
||||
data_type: u8,
|
||||
read_only: bool,
|
||||
// TODO: descriptive
|
||||
},
|
||||
Remove {
|
||||
property_name: String,
|
||||
},
|
||||
Get {
|
||||
property_name: String,
|
||||
data: DataType,
|
||||
|
@ -34,21 +43,32 @@ pub enum PropertyControlCommand {
|
|||
impl PropertyControlCommand {
|
||||
pub fn command(&self) -> u8 {
|
||||
match self {
|
||||
PropertyControlCommand::Get { .. } => 0x10,
|
||||
PropertyControlCommand::Set { .. } => 0x11,
|
||||
PropertyControlCommand::Reset { .. } => 0x12,
|
||||
PropertyControlCommand::Register { .. } => 0x10,
|
||||
PropertyControlCommand::Remove { .. } => 0x11,
|
||||
PropertyControlCommand::Get { .. } => 0x12,
|
||||
PropertyControlCommand::Set { .. } => 0x13,
|
||||
PropertyControlCommand::Reset { .. } => 0x14,
|
||||
PropertyControlCommand::Subscribe { .. } => 0x1A,
|
||||
PropertyControlCommand::Unsubscribe { .. } => 0x1B
|
||||
PropertyControlCommand::Unsubscribe { .. } => 0x1B,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToPacket for PropertyControlCommand {
|
||||
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 {
|
||||
Packet {
|
||||
src, dest, packet_id, reply_to,
|
||||
src,
|
||||
dest,
|
||||
packet_id,
|
||||
reply_to,
|
||||
command: self.command(),
|
||||
data: PacketData::PropertyControl(self.clone())
|
||||
data: PacketData::PropertyControl(self.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -56,26 +76,56 @@ impl ToPacket for PropertyControlCommand {
|
|||
impl TryFrom<RawPacket> for PropertyControlCommand {
|
||||
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 build_invalid_input_err = |r: &str| Err(io::Error::new(io::ErrorKind::InvalidInput, r));
|
||||
match raw_packet.command {
|
||||
// get property
|
||||
0x10 => if raw_packet.data_length == 33 {
|
||||
Ok(PropertyControlCommand::Get {
|
||||
property_name: String::from_utf8(raw_packet.data[..0x34].to_vec())
|
||||
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "String is not UTF-8"))?,
|
||||
data: DataType::try_from(raw_packet.data[0x34..].to_vec())?,
|
||||
})
|
||||
} else {
|
||||
build_invalid_input_err("expected 33 bytes")
|
||||
},
|
||||
// set property
|
||||
// remove node
|
||||
0x10 => {
|
||||
if raw_packet.data_length == 34 {
|
||||
Ok(PropertyControlCommand::Register {
|
||||
property_name: String::from_utf8(raw_packet.data[..32].to_vec()).map_err(
|
||||
|_| io::Error::new(io::ErrorKind::InvalidInput, "String is not UTF-8"),
|
||||
)?,
|
||||
data_type: raw_packet.data[33],
|
||||
read_only: raw_packet.data[34] != 0,
|
||||
})
|
||||
} else {
|
||||
build_invalid_input_err("expected 34 bytes")
|
||||
}
|
||||
}
|
||||
// remove property
|
||||
0x11 => {
|
||||
if raw_packet.data_length == 32 {
|
||||
Ok(PropertyControlCommand::Remove {
|
||||
property_name: String::from_utf8(raw_packet.data.to_vec()).map_err(
|
||||
|_| io::Error::new(io::ErrorKind::InvalidInput, "String is not UTF-8"),
|
||||
)?,
|
||||
})
|
||||
} else {
|
||||
build_invalid_input_err("expected 32 bytes")
|
||||
}
|
||||
}
|
||||
// get property
|
||||
0x12 => {
|
||||
if raw_packet.data_length == 33 {
|
||||
Ok(PropertyControlCommand::Get {
|
||||
property_name: String::from_utf8(raw_packet.data[..0x34].to_vec())
|
||||
.map_err(|_| {
|
||||
io::Error::new(io::ErrorKind::InvalidInput, "String is not UTF-8")
|
||||
})?,
|
||||
data: DataType::try_from(raw_packet.data[0x34..].to_vec())?,
|
||||
})
|
||||
} else {
|
||||
build_invalid_input_err("expected 33 bytes")
|
||||
}
|
||||
}
|
||||
// set property
|
||||
0x13 => {
|
||||
if raw_packet.data_length == 33 {
|
||||
Ok(PropertyControlCommand::Set {
|
||||
property_name: String::from_utf8(raw_packet.data[..0x34].to_vec())
|
||||
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "String is not UTF-8"))?,
|
||||
.map_err(|_| {
|
||||
io::Error::new(io::ErrorKind::InvalidInput, "String is not UTF-8")
|
||||
})?,
|
||||
data: DataType::try_from(raw_packet.data[0x34..].to_vec())?,
|
||||
})
|
||||
} else {
|
||||
|
@ -83,11 +133,13 @@ impl TryFrom<RawPacket> for PropertyControlCommand {
|
|||
}
|
||||
}
|
||||
// reset property
|
||||
0x12 => {
|
||||
0x14 => {
|
||||
if raw_packet.data_length == 33 {
|
||||
Ok(PropertyControlCommand::Reset {
|
||||
property_name: String::from_utf8(raw_packet.data[..0x34].to_vec())
|
||||
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "String is not UTF-8"))?,
|
||||
.map_err(|_| {
|
||||
io::Error::new(io::ErrorKind::InvalidInput, "String is not UTF-8")
|
||||
})?,
|
||||
})
|
||||
} else {
|
||||
build_invalid_input_err("expected 33 bytes")
|
||||
|
@ -97,9 +149,13 @@ impl TryFrom<RawPacket> for PropertyControlCommand {
|
|||
0x1A => {
|
||||
if raw_packet.data_length == 36 {
|
||||
Ok(PropertyControlCommand::Subscribe {
|
||||
device_id: Identifier::from(as_u32_be(raw_packet.data[0x14..0x18].as_ref())),
|
||||
device_id: Identifier::from(as_u32_be(
|
||||
raw_packet.data[0x14..0x18].as_ref(),
|
||||
)),
|
||||
property_name: String::from_utf8(raw_packet.data[0x18..0x4C].to_vec())
|
||||
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "String is not UTF-8"))?,
|
||||
.map_err(|_| {
|
||||
io::Error::new(io::ErrorKind::InvalidInput, "String is not UTF-8")
|
||||
})?,
|
||||
})
|
||||
} else {
|
||||
build_invalid_input_err("expected 36 bytes")
|
||||
|
@ -109,15 +165,22 @@ impl TryFrom<RawPacket> for PropertyControlCommand {
|
|||
0x1B => {
|
||||
if raw_packet.data_length == 36 {
|
||||
Ok(PropertyControlCommand::Unsubscribe {
|
||||
device_id: Identifier::from(as_u32_be(raw_packet.data[0x14..0x18].as_ref())),
|
||||
device_id: Identifier::from(as_u32_be(
|
||||
raw_packet.data[0x14..0x18].as_ref(),
|
||||
)),
|
||||
property_name: String::from_utf8(raw_packet.data[0x18..0x4C].to_vec())
|
||||
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "String is not UTF-8"))?,
|
||||
.map_err(|_| {
|
||||
io::Error::new(io::ErrorKind::InvalidInput, "String is not UTF-8")
|
||||
})?,
|
||||
})
|
||||
} else {
|
||||
build_invalid_input_err("expected 36 bytes")
|
||||
}
|
||||
}
|
||||
_ => Err(io::Error::new(io::ErrorKind::InvalidInput, "command group is unsupported"))
|
||||
_ => Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"command group is unsupported",
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,14 @@ use crate::commands::property_control::PropertyControlCommand;
|
|||
impl Into<Vec<u8>> for PropertyControlCommand {
|
||||
fn into(self) -> Vec<u8> {
|
||||
match self {
|
||||
PropertyControlCommand::Register { property_name, data_type, read_only } => {
|
||||
let mut vec = vec![];
|
||||
vec.extend(property_name.into_bytes());
|
||||
vec.push(data_type);
|
||||
vec.push(read_only as u8);
|
||||
vec
|
||||
},
|
||||
PropertyControlCommand::Remove { property_name } => property_name.into_bytes(),
|
||||
PropertyControlCommand::Get { property_name, data } => {
|
||||
let mut v = vec![];
|
||||
v.extend(property_name.into_bytes());
|
||||
|
|
Loading…
Reference in a new issue