Node
ModuleId 0
Purpose
The node module is the central part of the FruityMesh Algorithm. It is a mandatory module. It is responsible for clustering and other mesh related tasks and functionalities that are part of FruityMesh.
Functionality
The node keeps track of all MeshConnections and monitors connects and disconnects. It works in conjunction with the MeshConnection and ConnectionManager classes for this. The node is also responsible for broadcasting mesh discovery (JOIN_ME) packets. It will also activate scanning if necessary and monitor the incoming discovery packets of other nodes. It will create new MeshConnections to other nodes if necessary. A state machine is used to toggle between different discovery states.
The node only permits one mesh handshake at a certain time. During the handshake, both mesh nodes will exchange information about their clusters and will decide which cluster is the biggest one. The packets used are specified under Clustering Messages. During the handshake, a backup of the current cluster state is made and used throughout the handshake. After the handshake, cluster changes that happened in the meantime are sent to these connections. Updates on the cluster size or structure are also sent to all MeshAccessConnections.
There are a number of undocumented commands. These are mostly for debugging and there is no guarantee that they will be available in future builds. |
Reboot Message
On reboot, the firmware sends a JSON to the connected device, giving more information about the reboot. The JSON has the following structure:
{
"type":"reboot",
"reason":3, //Integer, see below
"code1":17, //Additional information, depending on the reason given. The valid codes are purposefully undocumented, as they are highly subject to change and are mainly intended to help firmware developers.
"stack":128, //Stack address of the reboot, if available.
"version":80021 //Version of the firmware.
}
The reason can have the following values:
Code | Name | Description |
---|---|---|
0 |
UNKNOWN |
The reboot reason is unknown. A typical case where this can happen is when the node lost power and thus was unable to save any valid reason. Note though, that the reason really is unknown and as such could have any other reason as well. |
1 |
HARDFAULT |
A hardfault occurred on the device. |
2 |
APP_FAULT |
Some runtime check of the firmware failed, which rebooted the device. |
3 |
SD_FAULT |
The Softdevice crashed. |
4 |
PIN_RESET |
The Power Reset Button was pressed. |
5 |
WATCHDOG |
The Watchdogs were not fed. |
6 |
FROM_OFF_STATE |
The node previously was turned off and is now turned on. |
7 |
LOCAL_RESET |
The "reset" command was used, without any additional parameters. |
8 |
REMOTE_RESET |
The "action NodeId node reset" command was sent to the node. |
9 |
ENROLLMENT |
The reboot happened because of an enrollment. |
10 |
PREFERRED_CONNECTIONS |
The preferred connections were set. |
200-255 |
USER_DEFINED |
Some user defined reboot reasons. |
Terminal Commands
Setting the Discovery State
action [nodeId] node discovery [on / off]
It might be necessary to switch the node’s state machine into a different discovery state. This can be done through the mesh and can be used by a MeshGateway to turn off discovery once all enrolled nodes are connected. This allows the node to use a very low power consumption if scanning does not have to be active for other tasks.
Once the node loses a connection to one of its partners, it will automatically switch discovery on again.
Examples
//E.g. switch discovery off for all nodes
action 0 node discovery off
The response acknowledges the receipt of the command.
{"type":"set_discovery_result","nodeId":123,"module":0}
Setting prefered connections
action [nodeId] node set_preferred_connections [ignored / penalty] {up to eight preferred nodeIDs}
Sets the given nodeIDs as preferred connection partners while meshing. Other partners will be either completely ignored or their cluster score gets a heavy penalty. Executing this command without any nodeID disables this feature. After saving the preferred connections, the node reboots after a delay of 10 seconds. The "ignored / penalty" parameter determines the behaviour regarding the unpreferred connection partners, meaning any nodeID that is NOT in the thereafter following list. NOTE: For a connection to happen, both connection partners have to set each other as a preferred connection partner. This means that if you want to set the preferred connections of a mesh, you should best start at the leafs of the mesh.
WARNING!!! Using this command with the "ignored" parameter must be used with caution as using invalid or unreachable nodeIDs results in a state where the mesh can not be created. If this happened to you, you have two options: 1. flash the beacon. This erases the set preferred connections. 2. Connect to the beacon via a mesh access connection and execute the command again with correct parameters.
Examples
//E.g. Sets the preferred connections of 123 to 17, 32 and 12. Other connections partners are ignored for meshing.
action 123 node set_preferred_connections ignored 17 32 12
The response acknowledges the receipt of the command.
{"type":"set_preferred_connections_result","nodeId":123,"module":0}
Sensor values
// Generate a sensor event and send through mesh
// (Only used for debugging)
component_sense [nodeId] [moduleId] [actionType] [component] [registerAddress] [dataHex] {requestHandle=0}
//E.g. broadcast sensor event for module 123 from component 7 and registerAddress 77
component_sense 0 123 0 7 77 AA:BB
Following low-level data structure transports sensor measurement values across the mesh.
enum SensorMessageActionType {
UNSPECIFIED = 0, // E.g. Generated by sensor itself
ERROR_RSP = 1, // Error during READ/WRITE/...
READ_RSP = 2, // Response following a READ
WRITE_RSP = 3 // Response following a WRITE_ACK
}
Bytes | Type | Name | Description |
---|---|---|---|
5 |
connPacketHeader |
header |
|
1 |
u8 |
moduleId |
The module that generated this value |
1 |
u8 |
requestHandle |
Optional request handle, otherwise 0 |
1 |
u8 |
actionType |
One of the above actionTypes |
2 |
u16 |
component |
Some number identifying the source of the measurements such as a lamp head (vendor specific) |
2 |
u16 |
registerAddress |
An address used to differentiate data transported such as a hardware register number or a message profile id (vendor specific) |
1-.. |
u8[] |
payload |
Actual binary data that represents a sensor reading or multiple. |
The packet header consumes 12 bytes, which allows for 8 bytes of payload in a single packet and should be enough for most sensor values. For bigger payloads, it will be split.
The output on a sink will be:
{
"nodeId": 5, // sender
"type": "component_sense", // discriminator
"module": 123, // moduleId
"requestHandle": 0,
"actionType" : 0,
"component" : 7,
"register" : 77,
"payload": "abcdeQ==" // base64 encoded
}
Actor message
// Instruct device to write data into a register address
component_act [nodeId] [moduleId] [actionType] [component] [registerAddress] [dataHex] {requestHandle=0}
The following message is used for transporting write or read requests through the mesh.
enum ActorMessageActionType {
RESERVED = 0, // Unused
WRITE = 1, // Write without acknowledgement
READ = 2, // Read a value
WRITE_ACK = 3 // Write with acknowledgement
}
Bytes | Type | Name | Description |
---|---|---|---|
5 |
connPacketHeader |
header |
|
1 |
u8 |
moduleId |
The module that should act on the message |
1 |
u8 |
requestHandle |
Optional request handle, otherwise 0 |
1 |
u8 |
actionType |
One of the above actionTypes |
2 |
u16 |
component |
Some number identifying the destination for the action (vendor specific) |
2 |
u16 |
registerAddress |
An address, e.g. hardware register number or a message profile id where the data should be written (vendor specific) |
1-.. |
u8[] |
payload |
For READ, this must be a singly byte that represents the number of bytes to read. For WRITE and WRITE_ACK, the payload is the bytes that should be written. |
No json representation is necessary for the moment as the meshgateway will not react on act messages.
Getting basic information (Local Command)
status
It is very conveniant to get easily readable information about a node. The status command displays the currently active connections and their state. It also display device information and the clustering state.
The following will be printed on the local terminal after the command was entered:
Node BBBBB (nodeId: 1) vers: 80000, NodeKey: 01:00:....:00:00 Mesh clusterSize:10, clusterId:4201185286 Enrolled 1: networkId:10, deviceType:0, NetKey 04:00:....:00:00, UserBaseKey 00:00:....:00:00 Addr:00:00:00:01:00:00, ConnLossCounter:3, AckField:0, State: 1 CONNECTIONS 2 (freeIn:0, freeOut:2, pendingPackets:0 IN (0) FM 7, state:4, cluster:fa690006(8), sink:-1, Queue:0-0(0), Buf:1/7, mb:0, hnd:16 OUT(1) FM 10, state:4, cluster:fa690006(1), sink:-1, Queue:0-0(0), Buf:1/7, mb:1, hnd:17
Setting the Terminal Mode (Local Command)
When working with UART (Terminal and Uart must be enabled), FruityMesh supports a convenient blocking terminal mode with echo back functionality. For communication with another device such as a MeshGateway, an interrupt based input method and json output is used. To toggle between these two modes, there are two commands.
startterm
Using startterm will use a blocking mode where all functionality is halted and user input is received in a busy loop until a line feed '\r' is received. The command will then be processed and other functionality will be resumed. The input will be echoed back on the terminal and backspace is supported as well for most terminal programs. If the command cannot be recognized, a warning will be echoed.
stopterm
The stopterm command will switch the node into an interrupt based input mode where terminal input does not affect the functionality until a line feed '\r' is received. All output messages will be in json format.
Rebooting (Local Command)
reset
If you just want to reset the node via the terminal, enter this command and it will do a software reboot.
Time Synchronization
If you want to synchronize a time over the mesh, you must first set the time to your local node using the settime command. It is internally stored as an unsigned 32 bit integer.
settime [u32 unixTimestampSec] [i16 offsetMinutes]
Afterwards, you can query the time of the local node using:
gettime
The output should give you the current time and date of the node in a human readable form. Be aware that this is only an approximate calculation. It is just for debugging if the time was set correctly. Internally, the nodes only work with unix timestamps.
Querying Active Modules
get_modules [nodeId]
Often, it is necessary to get a list of modules that are available on a node. The returned list includes all modules that are available (compiled into the firmware): their moduleId, their version and whether they are currently active.
{
"nodeId": 1,
"type": "module_list",
"modules": [
{
"id": 1,
"version": 2,
"active": 1
},
{
"id": 2,
"version": 1,
"active": 0
},
// ...
]
Sending raw data
General overview

Sending raw data can be used to send any arbitrary data, for example (but not limited to) zip files. The data which should be sent is split into various chunks which are then sent through the mesh. The data which should be sent is called the "payload".
Every raw data transaction (except raw_data_light, which will be explained later) starts with a raw_data_start message. This message includes the amount of chunks in the transaction and the protocol of the payload. Once the receiver receives this message, he answers with a raw_data_start_received message, which indicates to the sender that the receiver is ready for the transaction of the chunks.
When the sender receives this message, he starts sending all the raw_data_chunks. Besides part of the payload, every raw_data_chunk includes a chunkID which is a uniquely (regarding the current transaction) ascending number, starting at 1 for the raw_data_chunks. The chunkID 0 is reserved for the raw_data_start which always implicitly has the chunkID 0. Using this chunkID, and the information of the amount of chunks form the raw_data_start message, the receiver is able to determine whether or not a received chunk is the last chunk in the transaction. Once he receives the last chunk he reports back to the sender using a single raw_data_report. This message includes up to three missing chunkIDs. If all chunks were received, the list of missing chunks is empty, which tells the sender that the transaction was successful. If however, the list of missing chunks is not empty, the sender must send the chunks with the corresponding chunkIDs again. The last chunkID of the previous raw_data_report message acts as a last chunk, regarding the sending of additional raw_data_reports. This sending of raw_data_chunks and raw_data_reports is repeated until raw_data_report has an empty list of missing chunkIDs.
All devices involved in the communication (meaning both sender and receiver as well as the mesh) are able to cancel the communication by sending a raw_data_error message to the sender as well as the receiver. If the sender or the receiver is the device that hung up the transmission, it is allowed to not send the error to itself. The raw_data_error message includes an error code, indicating the reason for the cancellation. It is possible to receive a raw_data_error message without an open transmission. This can happen for example, if the sender cancels the transmission using a raw_data_error, but this error is dropped during the transmission. The receiver then might send another raw_data_error indicating a timeout while the sender already canceled the communication. Such messages without an open transmission may be discarded.
Dropped messages
As any other message in the mesh, every message in the raw send protocol could be dropped. This section describes how an implementation must behave in such scenarios. It also tells the obligations of the sender and the receiver.
Dropped message | Reaction |
---|---|
raw_data_start or raw_data_start_received |
The sender must send the raw_data_start again after a timeout of 10 seconds or stop the transmission. The receiver thus has to be able to handle several successive raw_data_start messages with the same content (in case the raw_data_start_received message is dropped) as well as closing a dropped connection after a timeout of 15 seconds (in case the sender does not send another raw_data_start). |
raw_data_chunk |
Missing chunks are reported in raw_data_report once the last chunk is received. These missing chunks must be resent. |
Last raw_data_chunk or raw_data_report |
Using the ChunkID, both sender and receiver are able to identify the last data chunk. If this message or the raw_data_report is dropped, the sender must send the last chunk again. This however means that the receiver is only allowed to save the last chunk id once the first chunk after a raw_data_report is received, not immediately after the raw_data_report is sent. |
raw_data_error |
If a raw_data_error message is dropped, the sender or receiver has already canceled the transmission, leading to the sending of another raw_data_error upon receiving an invalid out-of-transmission message or a raw_data_error indicating a timeout. In the rare cases where the origin of the raw_data_error is the mesh itself, it could happen that both raw_data_errors are dropped. In such cases the connection is still up but probably will create another raw_data_error once the ill-formed chunk is sent again. |
Start of a transmission
raw_data_start [receiverId] [destinationModuleId] [numChunks] [protocolId] {requestHandle = 0}
This command starts a raw data transmission. The payload shall be sent using raw_data_chunk messages.
Parameter | Type | Description |
---|---|---|
receiverId |
u16 |
The NodeID that this message should be sent to |
destinationModuleId |
u8 |
The ModuleId is used for giving context to this message. If the transmission should only be printed on the receiver and otherwise be ignored by the firmware, it must be set to 0. |
numChunks |
u24 |
Number of Chunks for the total message. Must not be 0. |
protocolId |
u8 |
One of the protocolIds mentioned in the table below |
requestHandle |
u8 |
A handle that can be used to distinguish between different raw data transmissions (Default: 0) |
Protocol ID | Name | Description |
---|---|---|
0 |
Invalid |
Invalid Protocol ID |
1 |
HTTP |
A raw HTTP request or response |
2 |
GZIPPED_JSON |
A JSON that was gzipped |
3 - 199 |
Reserved |
Not yet used |
200 - 255 |
User defined |
May be different in each implementation |
If received by a JSON capable device, the raw_data_start will be printed out like this:
{
"nodeId":5,
"type":"raw_data_start",
"module":4,
"numChunks":3,
"protocol":1,
"fmKeyId":2,
"requestHandle":0
}
Accepting a transmission
raw_data_start_received [receiverId] [destinationModuleId] {requestHandle = 0}
Once a raw_data_start is received, the receiver shall send the sender a raw_data_start_received message.
Parameter | Type | Description |
---|---|---|
receiverId |
u16 |
The NodeID that this message should be sent to |
destinationModuleId |
u8 |
The ModuleId is used for giving context to this message. If the transmission should only be printed on the receiver and otherwise be ignored by the firmware, it must be set to 0. |
requestHandle |
u8 |
A handle that can be used to distinguish between different raw data transmissions (Default: 0) |
If received by a JSON capable device, the raw_data_start will be printed out like this:
{
"nodeId":5,
"type":"raw_data_start_received",
"module":4,
"requestHandle":0
}
Subsequent chunk messages
raw_data_chunk [receiverId] [destinationModuleId] [chunkId] [payloadHex] {requestHandle = 0}
Once a raw transmission was started, the appropriate number of chunks should follow in the correct order. Once the last chunk is received by the receiver it is possible to reassemble and parse the whole message. The moduleId is present in all chunks so that they can be assigned to the correct stream and to avoid clashes between different modules. A module can send intermittent data streams if is uses different request handles.
Parameter | Type | Description |
---|---|---|
receiverId |
u16 |
The NodeID that this message should be sent to |
destinationModuleId |
u8 |
The ModuleId is used for giving context to this message. If the transmission should only be printed on the receiver and otherwise be ignored by the firmware, it must be set to 0. |
chunkId |
u24 |
ID of this data chunk starting from 0. |
payloadHex |
HexString or Base64String |
The binary data to send. E.g. AA:BB:CC. The maximum length is 60 bytes for HexStrings, 120 bytes for Base64Strings. |
requestHandle |
u8 |
A handle that can be used to distinguish between different raw data transmissions (Default: 0) |
If received by a JSON capable device, the raw_data_start will be printed out like this:
{
"nodeId":5,
"type":"raw_data_chunk",
"module":4,
"chunkId":1,
"payload":"abcdeQ==",
"requestHandle":0
}
Sending a report
raw_data_report [receiverId] [destinationModuleId] [MissingChunkIds] {requestHandle = 0}
Once the last chunk is received, the receiver sends this message to the sender, indicating either a successful transmission (empty missing chunk IDs) or informs the sender about missing chunk IDs.
Parameter | Type | Description |
---|---|---|
receiverId |
u16 |
The NodeID that this message should be sent to |
destinationModuleId |
u8 |
The ModuleId is used for giving context to this message. If the transmission should only be printed on the receiver and otherwise be ignored by the firmware, it must be set to 0. |
MissingChunkIds |
Comma separated Integers or the literal string "-" (without "") |
Up to three chunkIDs of missing chunks. Must not contain spaces! E.g. 2,17,312 |
requestHandle |
u8 |
A handle that can be used to distinguish between different raw data transmissions (Default: 0) |
If received by a JSON capable device, the raw_data_start will be printed out like this:
{
"nodeId":5,
"type":"raw_data_report",
"module":4,
"missing":[2,17,312],
"requestHandle":0
}
Or in cases where the transmission was successful:
{
"nodeId":5,
"type":"raw_data_report",
"module":4,
"missing":[],
"requestHandle":0
}
Sending an error
raw_data_error [receiverId] [destinationModuleId] [errorCode] [destination] {requestHandle = 0}
This command indicates that some error occurred and the transmission must be closed. Will be sent to the receiver as well as the sender.
Error Code | Name | Meaning |
---|---|---|
1 |
Unexpected end of transmission |
Three timeouts happened without receiving a message from the transmission partner. |
2 |
Not in a transmission |
A raw_data_chunk or raw_data_report was received without an open transmission. |
3 |
Malformed Message |
A message was received which was malformed and did not fit any other error code. |
4 |
Unsupported Protocol |
The receiver is unable to interpret the given protocol. |
5 |
Malformed GZIP |
The receiver got all chunks but could could not unpack the gzip. |
6 |
Malformed Type |
Thrown in case of a gzip communication. The unpacking worked, but the provided type inside the gzip json was unknown. |
7 |
Invalid Chunk ID |
The given chunk ID was out of range. |
0, 4 - 199 |
Reserved |
Not yet used |
200 - 255 |
User defined |
May be different in each implementation. |
Destination Code | Name | Meaning |
---|---|---|
1 |
Sender |
The error is sent to the sender. |
2 |
Receiver |
The error is sent to the receiver. |
3 |
Both |
The error is sent both to the sender and the receiver. |
If received by a JSON capable device, the raw_data_error will be printed out like this:
{
"nodeId":5,
"type":"raw_data_error",
"module":4,
"error":1,
"destination":1
"requestHandle":0
}
Sending a single light message of arbitrary data
raw_data_light [receiverId] [destinationModuleId] [protocolId] [payload] {requestHandle = 0}
Sends a single, responseless chunk of arbitrary data to the receiver. There is no guarantee that the message is transmitted. The sender thus should make sure to have some resending logic.
Parameter | Type | Description |
---|---|---|
receiverId |
u16 |
The NodeID that this message should be sent to |
destinationModuleId |
u8 |
The ModuleId is used for giving context to this message. If the transmission should only be printed on the receiver and otherwise be ignored by the firmware, it must be set to 0. |
protocolId |
u8 |
One of the protocolIds mentioned in the table of raw_data_start |
payloadHex |
HexString or Base64String |
The binary data to send. E.g. AA:BB:CC. The maximum length is 60 bytes for HexStrings, 120 bytes for Base64Strings. |
requestHandle |
u8 |
A handle that can be used to distinguish between different raw data transmissions (Default: 0) |
If received by a JSON capable device, the raw_data_start will be printed out like this:
{
"nodeId":5,
"type":"raw_data_light",
"module":4,
"protocol":2,
"payload":"abcdeQ==",
"requestHandle":0
}
Messages
Clustering Messages
ClusterWelcome (Local Handshake between two nodes)
The ClusterWelcome Packet is sent be the node that thinks it has the bigger cluster. If not, the other node will also send a ClusterWelcome packet after which both nodes know who is bigger.
Bytes | Type | Name | Description |
---|---|---|---|
5 |
header |
messageType: MESSAGE_TYPE_CLUSTER_WELCOME(20) |
|
4 |
ClusterId |
clusterId |
The id of the cluster |
4 |
ClusterSize |
clusterSize |
Size of the cluster |
4 |
u16 |
meshWriteHandle |
Write handle for the mesh rx characteristic for data transmission. (Allows us to skip service discovery) |
4 |
ClusterSize |
hopsToSink |
The number of hops to sink if there is one, otherwise -1. |
1 |
u8 |
preferredConnectionInterval |
Preferred interval for the meshConnection |
2 |
NetworkId |
networkId |
The id of the other clusters network |
ClusterAck1 (Local Handshake between two nodes)
Acknowledge packet sent by the smaller cluster to acknowledge that it is now taking part in the mesh.
Bytes | Type | Name | Description |
---|---|---|---|
5 |
header |
messageType: MESSAGE_TYPE_CLUSTER_ACK_1(21) |
|
4 |
ClusterSize |
hopsToSink |
Hops to the shortest sink |
1 |
u8 |
preferredConnectionInterval |
Preferred interval for the meshConnection |
ClusterAck2 (Local Handshake between two nodes)
Acknowledge packet sent by the bigger cluster after receiving ack1 from the smaller cluster
Bytes | Type | Name | Description |
---|---|---|---|
5 |
header |
messageType: MESSAGE_TYPE_CLUSTER_ACK_2(22) |
|
4 |
ClusterId |
clusterId |
The id of the cluster |
4 |
ClusterSize |
clusterSize |
Size of the cluster |
4 |
ClusterSize |
hopsToSink |
The number of hops to sink if there is one, otherwise -1. |
ClusterInfoUpdate
This packet informs a node about a change in the cluster size or structure. It can be sent throughout the mesh but is modified on each node before resending. It will only give the change in clusterSize and not the absolute value, the node must keep count itself. It will however give the absolute size if it is sent over a MeshAccessConnection.
Bytes | Type | Name | Description |
---|---|---|---|
5 |
header |
messageType: MESSAGE_TYPE_CLUSTER_INFO_UPDATE(23) |
|
4 |
u32 |
reserved |
deprecated |
4 |
ClusterSize |
clusterSize |
Change in clusterSize or absolute size |
4 |
ClusterSize |
hopsToSink |
The number of hops to sink if there is one, otherwise -1. |
1 bit |
u8 : 1 |
connectionMasterBitHandover |
Hands over the masterBit to the bigger cluster. If sent over the MeshAccessConnection, this is 1 if the node has the masterBit. |
1 bit |
u8 : 1 |
counter |
Next expected sequence number for clusterUpdate |
6 bit |
u8 : 6 |
reserved |
- |
Raw Data Messages
raw_data_start
Bytes | Type | Name | Description |
---|---|---|---|
8 |
Conn Packet Module |
Message Type = 54, Action Type = 0. |
|
3 |
u24 |
Number of Chunks |
The total amount of raw_data_chunk messages for this transmission. |
1 |
u8 |
Protocol ID |
See above for a list of valid protocol IDs. |
4 |
u32 |
fmKeyId |
raw_data_start_received
Bytes | Type | Name | Description |
---|---|---|---|
8 |
Conn Packet Module |
Message Type = 54, Action Type = 1. |
raw_data_error
Bytes | Type | Name | Description |
---|---|---|---|
8 |
Conn Packet Module |
Message Type = 54, Action Type = 4. |
|
1 |
u8 |
Error Code |
See above for a list of possible error codes. |
1 |
u8 |
Destination Code |
See above for a list of possible Destination Codes. |
raw_data_chunk
Bytes | Type | Name | Description |
---|---|---|---|
8 |
Conn Packet Module |
Message Type = 54, Action Type = 2. |
|
3 |
u24 |
Chunk ID |
The ID of this chunk. The first chunk has ID 1. |
1 |
u8 |
reserved |
A reserved value that must be set to 0. |
1-60 |
u8[1-60] |
payload |
The payload. |
raw_data_report
Bytes | Type | Name | Description |
---|---|---|---|
8 |
Conn Packet Module |
Message Type = 54, Action Type = 3. |
|
12 |
u32[3] |
missings |
The IDs of the missing chunks. |
raw_data_chunk
Bytes | Type | Name | Description |
---|---|---|---|
5 |
Conn Packet Header |
Message Type = 55 |
|
1 |
u8 |
module ID |
The module ID which should receive this message. Must be 0 in most cases. |
1 |
u8 |
request Handle |
The request Handle under which the receiver may (or may not) answer. |
1 |
u8 |
Protocol ID |
See above for a list of all protocol IDs. |
1-60 |
u8[1-60] |
payload |
The payload. |