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`
|
> **Version:** `1`
|
||||||
> **Authored by:** `Raine <raine@ixvd.net>`
|
> **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
|
# 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
|
# 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>` | `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` |
|
| `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
|
# Data types
|
||||||
|
|
||||||
Domo has a data framework reliant on data types.
|
Domo has a data framework reliant on data types.
|
||||||
|
@ -64,13 +99,6 @@ These define what kind of data the property holds.
|
||||||
| `0x2*` | | | **Color** |
|
| `0x2*` | | | **Color** |
|
||||||
| `0x20` | 3 bytes | RGB | An RGB value. |
|
| `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 (`dynamic_data`)
|
||||||
|
|
||||||
Dynamic data is a data snippet with a `prop_data_type` byte and the data next to it.
|
Dynamic data is a data snippet with a `prop_data_type` byte and the data next to it.
|
||||||
|
@ -78,9 +106,9 @@ Dynamic data is a data snippet with a `prop_data_type` byte and the data next to
|
||||||
> **Note**: this section uses relative offset
|
> **Note**: this section uses relative offset
|
||||||
|
|
||||||
| offset | size | name | description | example |
|
| offset | size | name | description | example |
|
||||||
| ------ | ----------------------------- | ---------------- | ----------------------- | ------- |
|
| ------ | --------------------------- | ---------------- | ----------------------- | ------- |
|
||||||
| `0x00` | 1 byte | `prop_data_type` | Describes the data type | `0x00` |
|
| `0x00` | 1 byte | `prop_data_type` | Describes the data type | `0x00` |
|
||||||
| `0x01` | depending on `prop_data_type` | `data` | The data | |
|
| `0x01` | depends on `prop_data_type` | `data` | The data | |
|
||||||
|
|
||||||
# Commands
|
# Commands
|
||||||
|
|
||||||
|
@ -121,23 +149,13 @@ Remove node from network
|
||||||
|
|
||||||
there is no extra data required.
|
there is no extra data required.
|
||||||
|
|
||||||
### `0x03` - Register property
|
### `0x0A` - Acknowledge packets
|
||||||
|
|
||||||
#### Command data
|
Acknowledge received packets.
|
||||||
|
|
||||||
| offset | size | name | description | reserved | example |
|
| offset | size | name | description | reserved | example |
|
||||||
| ------ | -------- | --------------- | ------------------------------------------------------------------ | -------- | ------- |
|
| ------ | ------------- | ----------- | ---------------------------------- | ----------- | ------- |
|
||||||
| `0x14` | 32 bytes | `property_name` | The name of the property as a UTF-8 string. | no | "Power" |
|
| `0x14` | 4 bytes * `n` | `packet_id` | list of packet_id's to acknowledge | origin node | |
|
||||||
| `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" |
|
|
||||||
|
|
||||||
### `0x0E` - Error
|
### `0x0E` - Error
|
||||||
|
|
||||||
|
@ -146,9 +164,9 @@ Send a packet to state an error occurred.
|
||||||
#### Command data
|
#### Command data
|
||||||
|
|
||||||
| offset | size | name | description | example |
|
| offset | size | name | description | example |
|
||||||
| ------ | ----------------------------- | ------------ | ------------------------------- | ------- |
|
| ------ | ------------- | ------------ | ------------------------------- | ------- |
|
||||||
| `0x14` | 1 byte | `error_code` | error code; check 'Error codes' | `0x00` |
|
| `0x14` | 1 byte | `error_code` | error code; check 'Error codes' | `0x00` |
|
||||||
| `0x15` | `<0x14-0x15:metadata_length>` | `metadata` | metadata | |
|
| `0x15` | `data_length` | `metadata` | metadata | |
|
||||||
|
|
||||||
#### Error codes
|
#### Error codes
|
||||||
|
|
||||||
|
@ -167,20 +185,40 @@ Send a packet to state an error occurred.
|
||||||
| `0x20` | `node_invalid_property` | the property specified is invalid | no |
|
| `0x20` | `node_invalid_property` | the property specified is invalid | no |
|
||||||
| `0x21` | `node_failed_request` | the request could not be completed. | consult metadata |
|
| `0x21` | `node_failed_request` | the request could not be completed. | consult metadata |
|
||||||
|
|
||||||
|
|
||||||
## `0x1*` - Properties control
|
## `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
|
Get a properties value
|
||||||
|
|
||||||
#### Command data
|
#### Command data
|
||||||
|
|
||||||
| offset | size | name | description | reserved | example |
|
| offset | size | name | description | reserved | example |
|
||||||
| ------ | -------- | --------------- | ------------------------------------------- | -------- | -------- |
|
| ------ | -------- | --------------- | ------------------------------------------- | ---------------- | -------- |
|
||||||
| `0x14` | 32 bytes | `property_name` | The name of the property as a UTF-8 string. | no | "Power" |
|
| `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` |
|
| `0x34` | dynamic | `dynamic_data` | Dynamic data snippet | destination node | `0x0100` |
|
||||||
|
|
||||||
### `0x11` - Set property
|
### `0x13` - Set property
|
||||||
|
|
||||||
#### Command data
|
#### 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" |
|
| `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` |
|
| `0x34` | dynamic | `dynamic_data` | Dynamic data snippet | no | `0x0100` |
|
||||||
|
|
||||||
### `0x12` - Reset property
|
### `0x14` - Reset property
|
||||||
|
|
||||||
#### Command data
|
#### Command data
|
||||||
|
|
||||||
|
@ -204,13 +242,26 @@ Get a properties value
|
||||||
| `0x14` | 4 bytes | `device_id` | Who's property? | no | `0x00000000` |
|
| `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" |
|
| `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 |
|
| offset | size | name | description | reserved | example |
|
||||||
| ------ | -------- | --------------- | ------------------------------------------- | -------- | ------------ |
|
| ------ | -------- | --------------- | ------------------------------------------- | -------- | ------------ |
|
||||||
| `0x14` | 4 bytes | `device_id` | Who's property? | no | `0x00000000` |
|
| `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" |
|
| `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
|
## `0xF*` - Raw data transmission
|
||||||
|
|
||||||
This is useful for things like OTA updates.
|
This is useful for things like OTA updates.
|
||||||
|
@ -222,9 +273,9 @@ Since this procedure is quite expensive (network wise), the sides must shake han
|
||||||
#### Command data
|
#### Command data
|
||||||
|
|
||||||
| offset | size | name | description | reserved | example |
|
| offset | size | name | description | reserved | example |
|
||||||
| ------ | --------- | ------ | -------------------- | -------- | ------- |
|
| ------ | --------- | ------ | -------------------- | ----------- | ------- |
|
||||||
| `0x14` | 8 bytes | `size` | u64 size of the data | request | `0x00` |
|
| `0x14` | 8 bytes | `size` | u64 size of the data | origin node | `0x00` |
|
||||||
| `0x1c` | 128 bytes | `mime` | media type of data | request | `0x00` |
|
| `0x1c` | 128 bytes | `mime` | media type of data | origin node | `0x00` |
|
||||||
|
|
||||||
### `0xF1` - Data
|
### `0xF1` - Data
|
||||||
|
|
||||||
|
@ -236,6 +287,6 @@ 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.
|
The `sequence_number` is added for redundancy, all data sent will always reply to it's previous data segment.
|
||||||
|
|
||||||
| offset | size | name | description | example |
|
| offset | size | name | description | example |
|
||||||
| ------ | -------- | ----------------- | ------------------------------- | ------------ |
|
| ------ | ------------- | ----------------- | ------------------------------- | ------------ |
|
||||||
| `0x14` | 4 bytes | `sequence_number` | the sequence number of the data | `0x00000000` |
|
| `0x14` | 4 bytes | `sequence_number` | the sequence number of the data | `0x00000000` |
|
||||||
| `0x18` | `<size>` | `data` | the data | |
|
| `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,
|
Ping,
|
||||||
RegisterNode { device_id: Identifier },
|
RegisterNode { device_id: Identifier },
|
||||||
RemoveNode,
|
RemoveNode,
|
||||||
RegisterProperty {
|
AcknowledgePackets {
|
||||||
property_name: String,
|
packet_ids: Vec<Identifier>
|
||||||
data_type: u8,
|
|
||||||
read_only: bool,
|
|
||||||
},
|
|
||||||
RemoveProperty {
|
|
||||||
property_name: String,
|
|
||||||
},
|
},
|
||||||
Error {
|
Error {
|
||||||
error_code: u8,
|
error_code: u8,
|
||||||
|
@ -32,9 +27,8 @@ impl NodeManagementCommand {
|
||||||
NodeManagementCommand::Ping => 0x00,
|
NodeManagementCommand::Ping => 0x00,
|
||||||
NodeManagementCommand::RegisterNode { .. } => 0x01,
|
NodeManagementCommand::RegisterNode { .. } => 0x01,
|
||||||
NodeManagementCommand::RemoveNode => 0x02,
|
NodeManagementCommand::RemoveNode => 0x02,
|
||||||
NodeManagementCommand::RegisterProperty { .. } => 0x03,
|
NodeManagementCommand::AcknowledgePackets { .. } => 0x0A,
|
||||||
NodeManagementCommand::RemoveProperty { .. } => 0x04,
|
NodeManagementCommand::Error { .. } => 0x0E,
|
||||||
NodeManagementCommand::Error { .. } => 0x0E
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,26 +62,15 @@ impl TryFrom<RawPacket> for NodeManagementCommand {
|
||||||
},
|
},
|
||||||
// remove node
|
// remove node
|
||||||
0x02 => Ok(NodeManagementCommand::RemoveNode),
|
0x02 => Ok(NodeManagementCommand::RemoveNode),
|
||||||
// register property
|
0x0A => if raw_packet.data_length >= 4 && (raw_packet.data_length % 4 == 0) {
|
||||||
0x03 => if raw_packet.data_length == 34 {
|
Ok(NodeManagementCommand::AcknowledgePackets {
|
||||||
Ok(NodeManagementCommand::RegisterProperty {
|
packet_ids: raw_packet.data.chunks(4)
|
||||||
property_name: String::from_utf8(raw_packet.data[..32].to_vec())
|
.map(|c| Identifier::from(c))
|
||||||
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "String is not UTF-8"))?,
|
.collect()
|
||||||
data_type: raw_packet.data[33],
|
|
||||||
read_only: raw_packet.data[34] != 0,
|
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
build_invalid_input_err("expected 34 bytes")
|
build_invalid_input_err("expected at least 4 bytes and data_length%4=0")
|
||||||
},
|
}
|
||||||
// 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")
|
|
||||||
},
|
|
||||||
// error
|
// error
|
||||||
0x0E => if raw_packet.data_length >= 1 {
|
0x0E => if raw_packet.data_length >= 1 {
|
||||||
Ok(NodeManagementCommand::Error {
|
Ok(NodeManagementCommand::Error {
|
||||||
|
|
|
@ -6,18 +6,21 @@ impl Into<Vec<u8>> for NodeManagementCommand {
|
||||||
match self {
|
match self {
|
||||||
NodeManagementCommand::Ping => vec![],
|
NodeManagementCommand::Ping => vec![],
|
||||||
NodeManagementCommand::RegisterNode { device_id } => {
|
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::RemoveNode => vec![],
|
||||||
NodeManagementCommand::RegisterProperty { property_name, data_type, read_only } => {
|
NodeManagementCommand::AcknowledgePackets { packet_ids } =>
|
||||||
let mut vec = vec![];
|
packet_ids.iter().map(|i| i.bytes).flatten().collect(),
|
||||||
vec.extend(property_name.into_bytes());
|
|
||||||
vec.push(data_type);
|
NodeManagementCommand::Error {
|
||||||
vec.push(read_only as u8);
|
error_code,
|
||||||
vec
|
metadata,
|
||||||
},
|
} => {
|
||||||
NodeManagementCommand::RemoveProperty { property_name } => property_name.into_bytes(),
|
|
||||||
NodeManagementCommand::Error { error_code, metadata } => {
|
|
||||||
let mut vec = vec![];
|
let mut vec = vec![];
|
||||||
vec.push(error_code);
|
vec.push(error_code);
|
||||||
vec.extend(metadata);
|
vec.extend(metadata);
|
||||||
|
|
|
@ -1,15 +1,24 @@
|
||||||
use std::io;
|
|
||||||
use crate::data_types::DataType;
|
use crate::data_types::DataType;
|
||||||
use crate::identifier::Identifier;
|
use crate::identifier::Identifier;
|
||||||
|
use crate::packet::packet_data::PacketData;
|
||||||
use crate::packet::raw_packet::RawPacket;
|
use crate::packet::raw_packet::RawPacket;
|
||||||
use crate::packet::{Packet, ToPacket};
|
use crate::packet::{Packet, ToPacket};
|
||||||
use crate::packet::packet_data::PacketData;
|
|
||||||
use crate::prelude::as_u32_be;
|
use crate::prelude::as_u32_be;
|
||||||
|
use std::io;
|
||||||
|
|
||||||
pub mod vec;
|
pub mod vec;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum PropertyControlCommand {
|
pub enum PropertyControlCommand {
|
||||||
|
Register {
|
||||||
|
property_name: String,
|
||||||
|
data_type: u8,
|
||||||
|
read_only: bool,
|
||||||
|
// TODO: descriptive
|
||||||
|
},
|
||||||
|
Remove {
|
||||||
|
property_name: String,
|
||||||
|
},
|
||||||
Get {
|
Get {
|
||||||
property_name: String,
|
property_name: String,
|
||||||
data: DataType,
|
data: DataType,
|
||||||
|
@ -34,21 +43,32 @@ pub enum PropertyControlCommand {
|
||||||
impl PropertyControlCommand {
|
impl PropertyControlCommand {
|
||||||
pub fn command(&self) -> u8 {
|
pub fn command(&self) -> u8 {
|
||||||
match self {
|
match self {
|
||||||
PropertyControlCommand::Get { .. } => 0x10,
|
PropertyControlCommand::Register { .. } => 0x10,
|
||||||
PropertyControlCommand::Set { .. } => 0x11,
|
PropertyControlCommand::Remove { .. } => 0x11,
|
||||||
PropertyControlCommand::Reset { .. } => 0x12,
|
PropertyControlCommand::Get { .. } => 0x12,
|
||||||
|
PropertyControlCommand::Set { .. } => 0x13,
|
||||||
|
PropertyControlCommand::Reset { .. } => 0x14,
|
||||||
PropertyControlCommand::Subscribe { .. } => 0x1A,
|
PropertyControlCommand::Subscribe { .. } => 0x1A,
|
||||||
PropertyControlCommand::Unsubscribe { .. } => 0x1B
|
PropertyControlCommand::Unsubscribe { .. } => 0x1B,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToPacket for PropertyControlCommand {
|
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 {
|
Packet {
|
||||||
src, dest, packet_id, reply_to,
|
src,
|
||||||
|
dest,
|
||||||
|
packet_id,
|
||||||
|
reply_to,
|
||||||
command: self.command(),
|
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 {
|
impl TryFrom<RawPacket> for PropertyControlCommand {
|
||||||
type Error = io::Error;
|
type Error = io::Error;
|
||||||
fn try_from(raw_packet: RawPacket) -> io::Result<Self> {
|
fn try_from(raw_packet: RawPacket) -> io::Result<Self> {
|
||||||
let build_invalid_input_err = |r: &str| {
|
let build_invalid_input_err = |r: &str| Err(io::Error::new(io::ErrorKind::InvalidInput, r));
|
||||||
Err(io::Error::new(io::ErrorKind::InvalidInput, r))
|
|
||||||
};
|
|
||||||
match raw_packet.command {
|
match raw_packet.command {
|
||||||
|
// 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
|
// get property
|
||||||
0x10 => if raw_packet.data_length == 33 {
|
0x12 => {
|
||||||
|
if raw_packet.data_length == 33 {
|
||||||
Ok(PropertyControlCommand::Get {
|
Ok(PropertyControlCommand::Get {
|
||||||
property_name: String::from_utf8(raw_packet.data[..0x34].to_vec())
|
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())?,
|
data: DataType::try_from(raw_packet.data[0x34..].to_vec())?,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
build_invalid_input_err("expected 33 bytes")
|
build_invalid_input_err("expected 33 bytes")
|
||||||
},
|
}
|
||||||
|
}
|
||||||
// set property
|
// set property
|
||||||
0x11 => {
|
0x13 => {
|
||||||
if raw_packet.data_length == 33 {
|
if raw_packet.data_length == 33 {
|
||||||
Ok(PropertyControlCommand::Set {
|
Ok(PropertyControlCommand::Set {
|
||||||
property_name: String::from_utf8(raw_packet.data[..0x34].to_vec())
|
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())?,
|
data: DataType::try_from(raw_packet.data[0x34..].to_vec())?,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
@ -83,11 +133,13 @@ impl TryFrom<RawPacket> for PropertyControlCommand {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// reset property
|
// reset property
|
||||||
0x12 => {
|
0x14 => {
|
||||||
if raw_packet.data_length == 33 {
|
if raw_packet.data_length == 33 {
|
||||||
Ok(PropertyControlCommand::Reset {
|
Ok(PropertyControlCommand::Reset {
|
||||||
property_name: String::from_utf8(raw_packet.data[..0x34].to_vec())
|
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 {
|
} else {
|
||||||
build_invalid_input_err("expected 33 bytes")
|
build_invalid_input_err("expected 33 bytes")
|
||||||
|
@ -97,9 +149,13 @@ impl TryFrom<RawPacket> for PropertyControlCommand {
|
||||||
0x1A => {
|
0x1A => {
|
||||||
if raw_packet.data_length == 36 {
|
if raw_packet.data_length == 36 {
|
||||||
Ok(PropertyControlCommand::Subscribe {
|
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())
|
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 {
|
} else {
|
||||||
build_invalid_input_err("expected 36 bytes")
|
build_invalid_input_err("expected 36 bytes")
|
||||||
|
@ -109,15 +165,22 @@ impl TryFrom<RawPacket> for PropertyControlCommand {
|
||||||
0x1B => {
|
0x1B => {
|
||||||
if raw_packet.data_length == 36 {
|
if raw_packet.data_length == 36 {
|
||||||
Ok(PropertyControlCommand::Unsubscribe {
|
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())
|
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 {
|
} else {
|
||||||
build_invalid_input_err("expected 36 bytes")
|
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 {
|
impl Into<Vec<u8>> for PropertyControlCommand {
|
||||||
fn into(self) -> Vec<u8> {
|
fn into(self) -> Vec<u8> {
|
||||||
match self {
|
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 } => {
|
PropertyControlCommand::Get { property_name, data } => {
|
||||||
let mut v = vec![];
|
let mut v = vec![];
|
||||||
v.extend(property_name.into_bytes());
|
v.extend(property_name.into_bytes());
|
||||||
|
|
Loading…
Reference in a new issue