Difference between revisions of "DCE Binary Communication Protocol"

From LinuxMCE
Jump to: navigation, search
(How to serialize a message)
(Enums)
 
(39 intermediate revisions by 5 users not shown)
Line 1: Line 1:
 +
{| align="right"
 +
  | __TOC__
 +
  |}
 +
[[Category:Development]]
 +
[[Category:Programmer's Guide]]
 
== Introduction ==
 
== Introduction ==
  
 
A device can create a command connection and one or more event connections to the router.
 
A device can create a command connection and one or more event connections to the router.
  
The command connection is used as an incoming connection and device will use it to receive message from the router (commands).
+
* The command connection is used as an incoming connection and device will use it to receive message from the router (commands).
 
+
* An event connection is used by the device as an outgoing connection to notify the router about events or the deliver commands to other devices.
An event connection is used by the device as an outgoing connection to notify the router about events or the deliver commands to other devices.
+
  
 
The DCERouter process is listening on 3450 port.
 
The DCERouter process is listening on 3450 port.
Line 15: Line 19:
 
>> Device sends:  
 
>> Device sends:  
  
'''''HELLO <my_device_id> '\n''''''
+
'''''EVENT <my_device_id> '\n''''''
  
  
<< To router can response with :  
+
<< To router will respond with :  
  
'''''NOT IN THIS INSTALLATION IP=<device_ip_address> '\n''''''
+
'''''OK <my_device_id> IP=<device_ip_address> '\n''''''
  
or
 
  
'''''OK 43 IP=<device_ip_address> '\n''''''
+
>> To send a message, the device will send :
 +
 
 +
'''''MESSAGE <size_of_binary_message> '\n''''''
 +
 
 +
and then
 +
 
 +
'''''<serialized_binary_message>'''''
 +
 
 +
== How to create a command connection ==
  
 +
Here is how the handshake is made for a command connection:
  
 
>> Device sends:  
 
>> Device sends:  
  
'''''EVENT 43 '\n''''''
+
'''''COMMAND <my_device_id> '\n''''''
  
  
<< To router will response with :  
+
<< To router will respond with :  
  
'''''OK 43 IP=<device_ip_address> '\n''''''
+
'''''OK <my_device_id> IP=<device_ip_address> '\n''''''
  
  
>> To send a message, the device will send :
+
>> The device will wait for messages from dcerouter; the router will send :
  
 
'''''MESSAGE <size_of_binary_message> '\n''''''
 
'''''MESSAGE <size_of_binary_message> '\n''''''
Line 45: Line 57:
 
'''''<serialized_binary_message>'''''
 
'''''<serialized_binary_message>'''''
  
== How to create a command connection ==
+
== How to serialize data ==  
  
Here is how the handshake is made for an event connection:
+
DCE uses SerializeClass to serialize/deserialize data.
  
>> Device sends:  
+
The sources can be found here : src/SerializeClass/Serialize.h/cpp.
  
'''''HELLO <my_device_id> '\n''''''
+
The deserialize the data, the deserializing module must know the way the data was serialized like this:
  
 +
- 4 bytes, unsigned long
  
<< To router can response with :
+
- 1 byte, unsigned char
  
'''''NOT IN THIS INSTALLATION IP=<device_ip_address> '\n''''''
 
  
or
+
Primitives:
  
'''''OK 43 IP=<device_ip_address> '\n''''''
+
- 8 bytes, unsigned int64
  
 +
- 8 bytes, int64
  
>> Device sends:
+
- 4 bytes, unsigned long
  
'''''COMMAND 43 '\n''''''
+
- 4 bytes, unsigned short
  
 +
- 1 byte, unsigned char
  
<< To router will response with :
+
- 1 byte, char
  
'''''OK 43 IP=<device_ip_address> '\n''''''
+
- 1 byte, long
  
 +
- 4 bytes, float
  
>> The device will wait for messages from dcerouter; the router will send :
+
- 8 bytes, double
  
'''''MESSAGE <size_of_binary_message> '\n''''''
+
- 2 bytes, short
  
and then
 
  
'''''<serialized_binary_message>'''''
+
Complex types:
  
== How to serialize a message ==
 
  
 +
1. string
 +
 +
- STR_LENGTH bytes, the array with chars
 +
 +
- 1 byte, '/0' (value 0x00)
 +
 +
 +
2. block of data
 +
 +
- BLOCK_LENGTH bytes, the array with bytes
 +
 +
 +
3. vector of strings
 +
 +
- VECT_LENGTH bytes, the number of strings from vector
 +
 +
- string 0
 +
 +
- string 1
 +
 +
...
 +
 +
- string VECT_LENGTH - 1
 +
 +
 +
 +
Other complex types serialized (see SerializeClass.cpp for details) :
 +
 +
- map<int,string>
 +
 +
- map<u_int64_t,string>
 +
 +
- map<int,int>
 +
 +
- map<string,string>
 +
 +
- vector<int>
 +
 +
- vector< pair<int,int> >
 +
 +
- map<string, pair<int,int> >
 +
 +
 +
SerializeClass also allowed you to serialize/deserialize custom objects. Examples:
 +
 +
- PlutoColor
 +
 +
- PlutoPoint
 +
 +
- PlutoSize
 +
 +
- PlutoRectangle
 +
 +
- PlutoDataBlock
 +
 +
== How to serialize a message ==
 
The class used by DCE is Message class from src/DCE/Message.h/cpp unit.
 
The class used by DCE is Message class from src/DCE/Message.h/cpp unit.
  
== How to serialize data ==  
+
This is how the raw data looks like into a binary message:
 +
* long, value must be 1234 (magic number)
 +
* long, <device_from_id>
 +
* long, <device_to_id>
 +
* long, <device_group_to_id>
 +
* long, <message_id>
 +
* long, <message_priority>
 +
* long, <message_type>
 +
* long, <device_category_to>
 +
* long, <device_template_to>
 +
* unsigned char, <include_children>
 +
* long, <message_broadcast_level>
 +
* long, <message_retry>
 +
* unsigned char, <relative_to_sender>
 +
* long, <expected_response>
 +
* string, <device_list_to>
 +
* unsigned long, <number_of_string_parameters>
 +
** foreach <string_parameter>
 +
*** long, <string_parameter_id>
 +
*** string, <string_parameter_value>
 +
** end_foreach
 +
* unsigned long, <number_of_data_parameters>
 +
** foreach <data_parameter>
 +
*** long, <data_parameter_id>
 +
*** unsigned long, <data_parameter_length>
 +
*** array of bytes, <data_parameter_value>
 +
** end_foreach
 +
* unsigned long, <number_of_extra_messages>
 +
** foreach <extra_message>
 +
*** unsigned long, <serialized_extra_message_length>
 +
*** array of bytes, <serialized_extra_message_value>
 +
** end_foreach
 +
* unsigned long, must be 6789
 +
 
 +
===Enums===
 +
* enum eBroadcastLevel { BL_None=0, BL_DirectSiblings=1, BL_SameComputer=2, BL_SameRoom=3, BL_SameHouse=4, BL_AllHouses=5 };
 +
* enum eRetry { MR_None=0, MR_Retry=1, MR_Persist=2 };
 +
* enum eExpectedResponse { ER_None=0, ER_ReplyMessage, ER_ReplyString, ER_DeliveryConfirmation };
 +
* message types:   
 +
** enum { MESSAGETYPE_COMMAND=1, MESSAGETYPE_EVENT=2, MESSAGETYPE_DATAPARM_CHANGE=3, MESSAGETYPE_REPLY=4, MESSAGETYPE_DATAPARM_REQUEST=5, MESSAGETYPE_LOG=6, MESSAGETYPE_SYSCOMMAND=7, MESSAGETYPE_REGISTER_INTERCEPTOR=8, MESSAGETYPE_MESSAGE_INTERCEPTED=9, MESSAGETYPE_EXEC_COMMAND_GROUP=10, MESSAGETYPE_START_PING=11, MESSAGETYPE_STOP_PING=12, MESSAGETYPE_PURGE_INTERCEPTORS=13, MESSAGETYPE_PENDING_TASKS=14 };
 +
* message priority
 +
** enum { PRIORITY_LOW=0, PRIORITY_NORMAL=1, PRIORITY_HIGH=2, PRIORITY_URGENT=3 };
 +
 
 +
===Important note===
 +
* when sending to device template, set <device_template_to> to desired device template and also <device_to_id> to -2000 (DEVICEID_MASTERDEVICE)
 +
* when sending to device category, set <device_category_to> to desired device category and also <device_to_id> to -2001 (DEVICEID_CATEGORY)
 +
* when sending to a list with devices, set <device_list_to> to comma delimited list with devices and also <device_to_id> to -2002 (DEVICEID_LIST).
 +
 
 +
=== Example ===
 +
Here is the pseudocode to send the "on" command to a light switch.
 +
 
 +
We'll assume that the your device has #id 250 and the light switch has device #id 100
 +
 
 +
MyDevice.Connect(router_ip, 3450 /*port*/)
 +
MyDevice.SendData("EVENT 250\n")
 +
MyDevice.ReceiveData()  //until you'll get a '\n' ; you should receive: "OK 250 IP=<device_ip_address> '\n';
 +
//next: creating a message
 +
//let's say MyData is an array of bytes
 +
SerializeLong(MyData, 1234) //magic number
 +
SerializeLong(MyData, 250) //my id
 +
SerializeLong(MyData, 100) //the light switch
 +
SerializeLong(MyData, 0) //not used now
 +
SerializeLong(MyData, 192) //message id of command 'on'
 +
SerializeLong(MyData, 1) //normal priority
 +
SerializeLong(MyData, 1) //message type : command
 +
SerializeLong(MyData, 0) //not used now
 +
SerializeLong(MyData, 0) //not used now
 +
SerializeUnsignedChar(MyData, 0) //not including children
 +
SerializeLong(MyData, 0) //broadcast level : none
 +
SerializeLong(MyData, 0) //don't retry
 +
SerializeUnsignedChar(MyData, 0) //relative to sender false
 +
SerializeLong(MyData, 3) //delivery confirmation
 +
SerializeString(MyData, "") //device list to empty
 +
SerializeUnsignedLong(MyData, 2) //2 parameters
 +
SerializeLong(MyData, 98) //parameter type #98
 +
SerializeString(MyData, "") //empty value
 +
SerializeLong(MyData, 97) //parameter type #97
 +
SerializeString(MyData, "") //empty value
 +
SerializeUnsignedLong(MyData, 0) //no binary parameters
 +
SerializeUnsignedLong(MyData, 0) //no extra messages
 +
SerializeUnsignedLong(6789) //magic number
 +
//
 +
MyDevice.SendData("MESSAGE " + MyData.length() + '\n')
 +
MyDevice.SendData(MyData)
 +
MyDevice.ReceiveData()  //until you'll get a '\n' ; you should receive: "OK" an error message
 +
MyDevice.CloseConnection();
 +
 
 
== How to serialize data-grids ==
 
== How to serialize data-grids ==
 +
 +
(in work)
 +
 +
 +
Complex objects:
 +
 +
1) DataGridCellSerializableData
 +
 +
- unsigned long, <sizeof(DataGridCellSerializableData)>
 +
 +
- unsigned long, <graphic_length>
 +
 +
- unsigned long, <message_length>
 +
 +
- unsigned long, <text_length>
 +
 +
- unsigned long, <value_length>
 +
 +
- unsigned long, <image_path_length>
 +
 +
- unsigned long, <number_of_attributes_length>
 +
 +
- unsigned long, <attributes_length>
 +
 +
- int, <alternate_color>
 +
 +
- unsigned long, <graphic_format>
 +
 +
- unsigned char, <selectable>
 +
 +
- int, <style_detail>
 +
 +
- int, <col_span>
 +
 +
- int, <row_span>
 +
 +
- unsigned char, <dont_fire_grid_event>
 +
 +
 +
Enums:
 +
 +
- enum eGraphicFormat { GR_UNKNOWN=0, GR_JPG=1, GR_GIF=2, GR_TIF=3, GR_PNG=4, GR_MNG=5, GR_BMP=6, GR_OCG=7, GR_PFG=8 };
 +
 +
 +
 +
 +
2) DataGridCell
 +
 +
- DataGridCellSerializableData, <datagrid_cell_serializable_data>
 +
 +
- array of chars, <text> 
 +
 +
- array of chars, <value>
 +
 +
- array of bytes, <graphic_data>
 +
 +
- array of bytes, <message_data>
 +
 +
- array of chars, <image_path>
 +
 +
* foreach <cell_attribute>
 +
 +
*  - array of chars ended with '\0' , <cell_attribute_name>
 +
 +
*  - array of chars ended with '\0', <cell_attribute_value>
 +
 +
* end_foreach
 +
 +
 +
 +
3) DataGridTableSerializableData
 +
 +
- int, <total_number_of_columns>
 +
 +
- int, <total_number_of_rows>
 +
 +
- unsigned char, <keep_row_header>
 +
 +
- unsigned char, <keep_column_header>
 +
 +
- int, <column_count>
 +
 +
- int, <row_count>
 +
 +
- int, <starting_column>
 +
 +
- int, <starting_row>
 +
 +
- int, <cell_count>
 +
 +
 +
 +
4) DataGridTableCellIndex
 +
 +
- unsigned int, <column_row_type>
 +
 +
- unsigned int, <size>
 +
 +
 +
 +
5) DataGridTable
 +
 +
- unsigned long, <sizeof(DataGridTableSerializableData)>
 +
 +
- array of DataGridTableCellIndex, <col * row * sizeof(DataGridTableCellIndex)>
 +
 +
- array of DataGridCell, <col * row * serialized DataGridCell>
 +
 +
/*********************************************************************************/
 +
 +
Additional step: lzo compression/decompression
 +
 +
Note: can be disabled if compiled with DISABLE_LZO_DATAGRID
 +
 +
/*********************************************************************************/

Latest revision as of 21:19, 17 May 2010

Introduction

A device can create a command connection and one or more event connections to the router.

  • The command connection is used as an incoming connection and device will use it to receive message from the router (commands).
  • An event connection is used by the device as an outgoing connection to notify the router about events or the deliver commands to other devices.

The DCERouter process is listening on 3450 port.

How to create an event connection

Here is how the handshake is made for an event connection:

>> Device sends:

EVENT <my_device_id> '\n'


<< To router will respond with :

OK <my_device_id> IP=<device_ip_address> '\n'


>> To send a message, the device will send :

MESSAGE <size_of_binary_message> '\n'

and then

<serialized_binary_message>

How to create a command connection

Here is how the handshake is made for a command connection:

>> Device sends:

COMMAND <my_device_id> '\n'


<< To router will respond with :

OK <my_device_id> IP=<device_ip_address> '\n'


>> The device will wait for messages from dcerouter; the router will send :

MESSAGE <size_of_binary_message> '\n'

and then

<serialized_binary_message>

How to serialize data

DCE uses SerializeClass to serialize/deserialize data.

The sources can be found here : src/SerializeClass/Serialize.h/cpp.

The deserialize the data, the deserializing module must know the way the data was serialized like this:

- 4 bytes, unsigned long

- 1 byte, unsigned char


Primitives:

- 8 bytes, unsigned int64

- 8 bytes, int64

- 4 bytes, unsigned long

- 4 bytes, unsigned short

- 1 byte, unsigned char

- 1 byte, char

- 1 byte, long

- 4 bytes, float

- 8 bytes, double

- 2 bytes, short


Complex types:


1. string

- STR_LENGTH bytes, the array with chars

- 1 byte, '/0' (value 0x00)


2. block of data

- BLOCK_LENGTH bytes, the array with bytes


3. vector of strings

- VECT_LENGTH bytes, the number of strings from vector

- string 0

- string 1

...

- string VECT_LENGTH - 1


Other complex types serialized (see SerializeClass.cpp for details) :

- map<int,string>

- map<u_int64_t,string>

- map<int,int>

- map<string,string>

- vector<int>

- vector< pair<int,int> >

- map<string, pair<int,int> >


SerializeClass also allowed you to serialize/deserialize custom objects. Examples:

- PlutoColor

- PlutoPoint

- PlutoSize

- PlutoRectangle

- PlutoDataBlock

How to serialize a message

The class used by DCE is Message class from src/DCE/Message.h/cpp unit.

This is how the raw data looks like into a binary message:

  • long, value must be 1234 (magic number)
  • long, <device_from_id>
  • long, <device_to_id>
  • long, <device_group_to_id>
  • long, <message_id>
  • long, <message_priority>
  • long, <message_type>
  • long, <device_category_to>
  • long, <device_template_to>
  • unsigned char, <include_children>
  • long, <message_broadcast_level>
  • long, <message_retry>
  • unsigned char, <relative_to_sender>
  • long, <expected_response>
  • string, <device_list_to>
  • unsigned long, <number_of_string_parameters>
    • foreach <string_parameter>
      • long, <string_parameter_id>
      • string, <string_parameter_value>
    • end_foreach
  • unsigned long, <number_of_data_parameters>
    • foreach <data_parameter>
      • long, <data_parameter_id>
      • unsigned long, <data_parameter_length>
      • array of bytes, <data_parameter_value>
    • end_foreach
  • unsigned long, <number_of_extra_messages>
    • foreach <extra_message>
      • unsigned long, <serialized_extra_message_length>
      • array of bytes, <serialized_extra_message_value>
    • end_foreach
  • unsigned long, must be 6789

Enums

  • enum eBroadcastLevel { BL_None=0, BL_DirectSiblings=1, BL_SameComputer=2, BL_SameRoom=3, BL_SameHouse=4, BL_AllHouses=5 };
  • enum eRetry { MR_None=0, MR_Retry=1, MR_Persist=2 };
  • enum eExpectedResponse { ER_None=0, ER_ReplyMessage, ER_ReplyString, ER_DeliveryConfirmation };
  • message types:
    • enum { MESSAGETYPE_COMMAND=1, MESSAGETYPE_EVENT=2, MESSAGETYPE_DATAPARM_CHANGE=3, MESSAGETYPE_REPLY=4, MESSAGETYPE_DATAPARM_REQUEST=5, MESSAGETYPE_LOG=6, MESSAGETYPE_SYSCOMMAND=7, MESSAGETYPE_REGISTER_INTERCEPTOR=8, MESSAGETYPE_MESSAGE_INTERCEPTED=9, MESSAGETYPE_EXEC_COMMAND_GROUP=10, MESSAGETYPE_START_PING=11, MESSAGETYPE_STOP_PING=12, MESSAGETYPE_PURGE_INTERCEPTORS=13, MESSAGETYPE_PENDING_TASKS=14 };
  • message priority
    • enum { PRIORITY_LOW=0, PRIORITY_NORMAL=1, PRIORITY_HIGH=2, PRIORITY_URGENT=3 };

Important note

  • when sending to device template, set <device_template_to> to desired device template and also <device_to_id> to -2000 (DEVICEID_MASTERDEVICE)
  • when sending to device category, set <device_category_to> to desired device category and also <device_to_id> to -2001 (DEVICEID_CATEGORY)
  • when sending to a list with devices, set <device_list_to> to comma delimited list with devices and also <device_to_id> to -2002 (DEVICEID_LIST).

Example

Here is the pseudocode to send the "on" command to a light switch.

We'll assume that the your device has #id 250 and the light switch has device #id 100

MyDevice.Connect(router_ip, 3450 /*port*/) 
MyDevice.SendData("EVENT 250\n")
MyDevice.ReceiveData()  //until you'll get a '\n' ; you should receive: "OK 250 IP=<device_ip_address> '\n';
//next: creating a message
//let's say MyData is an array of bytes
SerializeLong(MyData, 1234) //magic number
SerializeLong(MyData, 250) //my id
SerializeLong(MyData, 100) //the light switch
SerializeLong(MyData, 0) //not used now 
SerializeLong(MyData, 192) //message id of command 'on'
SerializeLong(MyData, 1) //normal priority 
SerializeLong(MyData, 1) //message type : command
SerializeLong(MyData, 0) //not used now 
SerializeLong(MyData, 0) //not used now
SerializeUnsignedChar(MyData, 0) //not including children
SerializeLong(MyData, 0) //broadcast level : none 
SerializeLong(MyData, 0) //don't retry
SerializeUnsignedChar(MyData, 0) //relative to sender false
SerializeLong(MyData, 3) //delivery confirmation
SerializeString(MyData, "") //device list to empty
SerializeUnsignedLong(MyData, 2) //2 parameters
SerializeLong(MyData, 98) //parameter type #98
SerializeString(MyData, "") //empty value
SerializeLong(MyData, 97) //parameter type #97
SerializeString(MyData, "") //empty value
SerializeUnsignedLong(MyData, 0) //no binary parameters
SerializeUnsignedLong(MyData, 0) //no extra messages
SerializeUnsignedLong(6789) //magic number
//
MyDevice.SendData("MESSAGE " + MyData.length() + '\n')
MyDevice.SendData(MyData)
MyDevice.ReceiveData()  //until you'll get a '\n' ; you should receive: "OK" an error message
MyDevice.CloseConnection();

How to serialize data-grids

(in work)


Complex objects:

1) DataGridCellSerializableData

- unsigned long, <sizeof(DataGridCellSerializableData)>

- unsigned long, <graphic_length>

- unsigned long, <message_length>

- unsigned long, <text_length>

- unsigned long, <value_length>

- unsigned long, <image_path_length>

- unsigned long, <number_of_attributes_length>

- unsigned long, <attributes_length>

- int, <alternate_color>

- unsigned long, <graphic_format>

- unsigned char, <selectable>

- int, <style_detail>

- int, <col_span>

- int, <row_span>

- unsigned char, <dont_fire_grid_event>


Enums:

- enum eGraphicFormat { GR_UNKNOWN=0, GR_JPG=1, GR_GIF=2, GR_TIF=3, GR_PNG=4, GR_MNG=5, GR_BMP=6, GR_OCG=7, GR_PFG=8 };



2) DataGridCell

- DataGridCellSerializableData, <datagrid_cell_serializable_data>

- array of chars, <text>

- array of chars, <value>

- array of bytes, <graphic_data>

- array of bytes, <message_data>

- array of chars, <image_path>

  • foreach <cell_attribute>
  • - array of chars ended with '\0' , <cell_attribute_name>
  • - array of chars ended with '\0', <cell_attribute_value>
  • end_foreach


3) DataGridTableSerializableData

- int, <total_number_of_columns>

- int, <total_number_of_rows>

- unsigned char, <keep_row_header>

- unsigned char, <keep_column_header>

- int, <column_count>

- int, <row_count>

- int, <starting_column>

- int, <starting_row>

- int, <cell_count>


4) DataGridTableCellIndex

- unsigned int, <column_row_type>

- unsigned int, <size>


5) DataGridTable

- unsigned long, <sizeof(DataGridTableSerializableData)>

- array of DataGridTableCellIndex, <col * row * sizeof(DataGridTableCellIndex)>

- array of DataGridCell, <col * row * serialized DataGridCell>

/*********************************************************************************/

Additional step: lzo compression/decompression

Note: can be disabled if compiled with DISABLE_LZO_DATAGRID

/*********************************************************************************/