Skip to content

Commit 4248afe

Browse files
author
Daniel Montgomery
committedDec 9, 2020
Updated docs/communication.md
1 parent 24b1dec commit 4248afe

File tree

1 file changed

+101
-46
lines changed

1 file changed

+101
-46
lines changed
 

‎docs/communication.md

+101-46
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# Communication
2-
libproc includes a low-ish overhead communication protocol that attempts to reduce the time and busywork required of developers. The communication protocol is based on [XDR (External Data Representation Standard)](https://tools.ietf.org/html/rfc4506). There are minimal changes to the over-the-wire protocol and more changes to the XDR schema syntax, each of which is described in the following sections.
2+
libproc includes a low-ish overhead communication protocol that attempts to reduce the time and busywork required of developers. The communication protocol is based on [XDR (External Data Representation Standard)](https://tools.ietf.org/html/rfc4506). There are minimal changes to the over-the-wire protocol and more changes to the XDR schema syntax, each of which is described in the following sections.
33

44
# Schema
5-
The objective of the schema is to streamline the developer's time when defining additional command formats. The schema is a modified version of the XDR schema. Most of the additions focus on adding support for consolid command and data documentation, but there are also additions to help the format scale to a more distributed architecture, such as namespaces and include directives. There is a custom, python-based parser in the xdrgen folder of libproc.
5+
The objective of the schema is to streamline the developer's time when defining additional command formats. The schema is a modified version of the XDR schema. Most of the additions focus on adding support for consolid command and data documentation, but there are also additions to help the format scale to a more distributed architecture, such as namespaces and include directives. There is a custom, python-based parser in the xdrgen folder of libproc.
66

77
## Schema Narrative
88

@@ -11,22 +11,22 @@ The schema must start with a namespace declaration:
1111
```
1212
namespace ID;
1313
```
14-
The root namespace is assumed to be `IPC`. All other namespaces fall under IPC. Sub-namespaces can exist via imports. Namespaces in imported files are added under the namespace of their parent file.
14+
The root namespace is assumed to be `IPC`. All other namespaces fall under IPC. Sub-namespaces can exist via imports. Namespaces in imported files are added under the namespace of their parent file.
1515

1616
### Imports
17-
The import directive can be used at any time at the top-level of the schema file. Importing another schema file is an easy way to delegate parts of the schema to sub-modules within the same process. All imported items are incorporated into the root schema in a sub-namespace. The format of the import statement is:
17+
The import directive can be used at any time at the top-level of the schema file. Importing another schema file is an easy way to delegate parts of the schema to sub-modules within the same process. All imported items are incorporated into the root schema in a sub-namespace. The format of the import statement is:
1818
```
1919
import "relative path to .x file";
2020
```
2121
### Constants
22-
Constants are a good way ensure all command, structure, and error numbers come from a consistent number space. They get converted into the appropriate constant type of the target language. The syntax for constants is:
22+
Constants are a good way ensure all command, structure, and error numbers come from a consistent number space. They get converted into the appropriate constant type of the target language. The syntax for constants is:
2323
```
2424
const BASE = VALUE;
2525
```
2626
The VALUE can be expressed in either decimal or hexadecimal.
2727

2828
### Enumerations
29-
Enumerations are used for multiple purposes. First, you must use enumerated types as the basis for type numbers, command numbers, and error numbers. You should also use them when storing enumerated types in a structure. The syntax for enumerations is:
29+
Enumerations are used for multiple purposes. First, you must use enumerated types as the basis for type numbers, command numbers, and error numbers. You should also use them when storing enumerated types in a structure. The syntax for enumerations is:
3030
```
3131
enum NAME {
3232
ITEM1 = VALUE1;
@@ -36,33 +36,52 @@ enum NAME {
3636
A value can either be a constant, numeric literal, or a constant plus a numeric literal.
3737

3838
### Errors
39-
Error values get assigned a textual description. This assists in documentation and auto-generating code that produces more human readable error messages. The syntax for errors is:
39+
Error values get assigned a textual description. This assists in documentation and auto-generating code that produces more human readable error messages. The syntax for errors is:
4040
```
4141
error ENUM_NAME::ENUM_ITEM = "error message";
4242
```
43-
Note that all error numbers must be defined as an enumerated type. You must specify both the name of the enumerated type and the name of the item when specifying the error number.
43+
Note that all error numbers must be defined as an enumerated type. You must specify both the name of the enumerated type and the name of the item when specifying the error number.
4444

4545
### Commands
46-
Commands specify the actual commands sent over the network to control the target process. There are two general types of commands. First, you can specify commands that can be handled by a callback function in the process. This can also return data via a response. The second type of command is one that only returns data without side effects. This type of command is so prevalent that there is special handling code in libproc to streamline it and make it more flexible. The syntax for commands is:
46+
Commands specify the actual commands sent over the network to control the target process. There are two general types of commands: Generic commands and handled commands. Generic commands are commands that are only used to aggregate and return data. Handled commands are commands that and handled explicitly by a callback function.
47+
48+
#### Generic commands
49+
50+
A generic command has the following form.
51+
4752
```
4853
command "command-name" {
4954
summary "command description";
5055
param ENUM_NAME::ENUM_ITEM;
5156
types = ENUM_NAME::ENUM_ITEM, ENUM_NAME::ENUM_ITEM, ...;
52-
} = ENUM_NAME::ENUM_ITEM;
57+
};
5358
```
54-
As with other numbers, all command numbers must be defined as an enumerated type. Enumerated type names must include both the enumeration name and the item name, separated by double colons. The summary field is required but the other fields are only needed some of the time.
59+
All commands must be defined as an enumerated type. Enumerated type names must include both the enumeration name and the item name, separated by double colons. The `summary` and `types` field are required, but the `param` field is optional. Descriptions of the command's values are listed below.
5560

56-
`summary`: A textual description of what the command does. This description flows down to command-line help messages and other documentation.
61+
`summary`: A textual description of what the command does. This description flows down to command-line help messages and other documentation.
5762

58-
`params`: If present it specifies the structure number of the parameters to the command. The structure must be defined in a structure statement (see the next section). Commands that do not require parameters may omit this option and will automatically be given a void param.
63+
`params`: If present it specifies the structure number of the parameters to the command. The structure must be defined in a structure statement (see the next section). Commands that do not require parameters may omit this option and will automatically be given a void parameter.
5964

60-
`types`: A comma separated list of structure numbers to request for this command. This triggers the special handling code that automatically responds with the correct structures. When using they types option you do not specify a command number. The list of types gets set to the remote process using a built-in command.
65+
`types`: A comma separated list of structures used in this command.
6166

62-
`...} = ENUM_NAME::ENUM_ITEM`: This option specifies the number of this command. It is mutually exclusive with the `types` field.
67+
#### Handled commands
68+
Handled command have a similar syntax.
69+
```
70+
command "command-name" {
71+
summary "command description";
72+
param ENUM_NAME::ENUM_ITEM;
73+
} = ENUM_NAME::ENUM_ITEM;
74+
```
75+
As with generic commands, the summary field is required but the `param` field is optional.
76+
77+
`summary`: A textual description of what the command does. This description flows down to command-line help messages and other documentation.
78+
79+
`param`: If present it specifies the structure number of the parameters to the command. The structure must be defined in a structure statement (see the next section). Commands that do not require parameters may omit this option and will automatically be given a void param.
80+
81+
`...} = ENUM_NAME::ENUM_ITEM`: Specifies this commands number.
6382

6483
### Structures
65-
Structures define the data that gets sent over the network. They result in an equivalent language-level structure and code that automatically encodes it and decodes it for transmission. They also include field-level documentation and identifiers that are included in generated documentation and command line utilities. The syntax for structure definitions is:
84+
Structures define the data that gets sent over the network. They result in an equivalent language-level structure and code that automatically encodes it and decodes it for transmission. They also include field-level documentation and identifiers that are included in generated documentation and command line utilities. The syntax for structure definitions is:
6685
```
6786
struct Name {
6887
fieldtype fieldname {
@@ -78,30 +97,30 @@ struct Name {
7897
...
7998
} = ENUM_NAME::ENUM_ITEM;
8099
```
81-
Structure names must be unique within the namespace. They must have one or more field definitions. The field documentation appears in the `{}` block following the fieldname and before the semi-colon. It is optional but strongly encouraged. In some cases, just as a length field for an array, require no documentation.
100+
Structure names must be unique within the namespace. They must have one or more field definitions. The field documentation appears in the `{}` block following the fieldname and before the semi-colon. It is optional but strongly encouraged. In some cases, just as a length field for an array, require no documentation.
82101

83-
`fieldtype`: The type of the structure field. Available types are: `int`, `unsigned int`, `hyper`, `unsigned hyper`, `float`, `string`, `opaque`, and any enumeration or structure name.
102+
`fieldtype`: The type of the structure field. Available types are: `int`, `unsigned int`, `hyper`, `unsigned hyper`, `float`, `string`, `opaque`, and any enumeration or structure name.
84103

85-
When specifying an array you must separately declare a field to hold the array length and it must be before the array in the structure. Use the `[]` syntax to specify a field as an array and denote the field that serves as the length.
104+
When specifying an array you must separately declare a field to hold the array length and it must be before the array in the structure. Use the `[]` syntax to specify a field as an array and denote the field that serves as the length.
86105

87-
`...} = ENUM_NAME::ENUM_ITEM`: This option specifies the number of this structure.
106+
`...} = ENUM_NAME::ENUM_ITEM`: This option specifies the number of this structure. `ENUM_NAME` is case-insensitive.
88107

89108
#### Field Documentation Options
90-
The following options are available for fields. These options can be specified in any order:
109+
The following options are available for fields. These options can be specified in any order:
91110

92-
`name`: Provides a textual, human-readable name for this field. This is used in documentation and when printing the field to stdout in human-readable form.
111+
`name`: Provides a textual, human-readable name for this field. This is used in documentation and when printing the field to stdout in human-readable form.
93112

94-
`type`: A globally unique identifier for this field. It isn't a quoted string and needs to follow standard language identifier rules. The key needs to be globally unique among all fields in the entire combined schema. The key is used when producing key=value pair output and comma separated output. It is also used to identify the field when automatically parsing from the command line. If this field is omitted the field will not be available for printing or scanning from a command line.
113+
`type`: A globally unique identifier for this field. It isn't a quoted string and needs to follow standard language identifier rules. The key needs to be globally unique among all fields in the entire combined schema. The key is used when producing key=value pair output and comma separated output. It is also used to identify the field when automatically parsing from the command line. If this field is omitted the field will not be available for printing or scanning from a command line.
95114

96-
`description`: A longer description of this field. It is used for documentation and command line help.
115+
`description`: A longer description of this field. It is used for documentation and command line help.
97116

98117
`unit`: The unit label for the engineering units of the field.
99118

100-
`divisor`: `offset`: Used to specify a linear conversion from raw units to engineering units. The raw value is converted as follows: `(value/divisor) + offset`. The values in the structure are always transmitted as raw values. If no values are provided 0 is assumed. A 0 divisor results in no conversion, not a math error.
119+
`divisor`: `offset`: Used to specify a linear conversion from raw units to engineering units. The raw value is converted as follows: `(value/divisor) + offset`. The values in the structure are always transmitted as raw values. If no values are provided 0 is assumed. A 0 divisor results in no conversion, not a math error.
101120

102121
### Number spaces
103-
All enumeration, structure, and command numbers need to be globally unique in order for the system to work correctly. All the numeric values are 4 bytes long. Numbers are allocated in 1-byte chunks to help minimize coordination overhead. The high-order byte of all command numbers must be zero. The number allocations are
104-
documented in the [libproc number allocation table](https://github.com/PolySat/libproc/blob/xdr-updates/docs/number_allocations.md). This table must be updated prior to use any numbers.
122+
All enumeration, structure, and command numbers need to be globally unique in order for the system to work correctly. All the numeric values are 4 bytes long. Numbers are allocated in 1-byte chunks to help minimize coordination overhead. The high-order byte of all command numbers must be zero. The number allocations are
123+
documented in the [libproc number allocation table](https://github.com/PolySat/libproc/blob/xdr-updates/docs/number_allocations.md). This table must be updated prior to use any numbers.
105124

106125
## Example
107126
The following example shows a small schema, including structures, commands, and errors.
@@ -114,7 +133,6 @@ const ERR_BASE = 0x02FFFF00;
114133
115134
enum Cmds {
116135
SET_SPEED = CMD_BASE + 0
117-
118136
};
119137
120138
enum Types {
@@ -123,10 +141,9 @@ enum Types {
123141
};
124142
125143
enum Responses {
126-
BAD_SPEED = TYPE_BASE + 0
144+
BAD_SPEED = ERR_BASE + 0
127145
};
128146
129-
130147
error Responses::BAD_SPEED = "User specified an unsupported speed";
131148
132149
struct Speed {
@@ -148,33 +165,33 @@ struct Speed {
148165
description "The rotational speed of the z-axis wheel";
149166
unit "RPM";
150167
};
151-
};
168+
} = types::SPEED_SETTINGS;
152169
153170
struct Debug {
154171
unsigned int state {
155172
name "State";
156173
key wheel_state;
157-
description "The state of the wheel driver. Provides a bit-field of internal information.";
174+
description "The state of the wheel driver. Provides a bit-field of internal information.";
158175
};
159-
};
176+
} = Types::DEBUG;
160177
161178
command "example-set-wheel-speed" {
162-
summary "Sets the speed of the reaction wheels";
163-
param types::Speed;
164-
} = cmds::SET_SPEED;
179+
summary "Handled command setting the speed of the reaction wheels";
180+
param Types::SPEED_SETTINGS;
181+
} = Cmds::SET_SPEED;
165182
166183
command "example-debug" {
167-
summary "Provides debugging data about the wheel sub-system";
168-
types = types::DEBUG;
184+
summary "Generic command providing debugging data about the wheel sub-system";
185+
types = Types::DEBUG;
169186
};
170187
171188
```
172189

173190
## Built-in Functionality
174-
libproc includes some built-in functionality to support universal features across all programs. The include providing generic structures for commands, responses, common error messages, and process heartbeats. All the constants, structures, and related functions can be found in libproc's "cmd_schema.h" header file.
191+
libproc includes some built-in functionality to support universal features across all programs. The library provides general structures for commands, responses, common error messages, and process heartbeats. All the constants, structures, and related functions can be found in libproc's "cmd_schema.h" header file.
175192

176193
### Heartbeat Structure
177-
Heartbeats can be requested via the `IPC::types::HEARTBEAT` structure and `IPC::cmds::DATA_REQ` command. It contains basic command, response, and heartbeat counters.
194+
Heartbeats can be requested via the `IPC::Types::HEARTBEAT` structure and `IPC::Cmds::DATA_REQ` command. It contains basic command, response, and heartbeat counters.
178195

179196
### Errors
180197
libproc provides 4 error messages, including one that denotes success:
@@ -194,19 +211,57 @@ The built-in structures include the following:
194211

195212
### Commands
196213
The built-in commands include the following:
197-
`IPC::cmds::DATA_REQ`: The command to request data structures by number.
198-
`IPC::types::HEARTBEAT`: The command to request a heartbeat from the process.
199-
214+
`IPC::Cmds::DATA_REQ`: The command to request data structures by number.
215+
`IPC::Types::HEARTBEAT`: The command to request a heartbeat from the process.
200216

201217
# Parser
202-
The parser and code generator is written in Python. It can be found in xdrgen/xdrgen within the libproc project. To use the parser run the following:
218+
The parser and code generator is written in Python. It can be found in xdrgen/xdrgen within the libproc project. To use the parser run the following:
203219
```
204-
xdrgen/xdrgen --target libproc --output <prefix> cmd_schema.x
220+
xdrgen/xdrgen --target libproc --output <prefix> cmd_schema.xp
205221
```
206-
where <prefix> is the base name of the output file you want. This will generate both a <prefix>.c and <prefix>.h file.
222+
where <prefix> is the base name of the output file you want. This will generate both a <prefix>.c and <prefix>.h file.
207223

208224
# C API
209225

226+
## Generic commands
227+
Generic commands are handled internally within libproc. The response structures are created via populators. The following code is a populator from the example schema above.
228+
229+
```c
230+
static void debug_populator(void *arg, XDR_tx_struct cb, void *cb_args) {
231+
struct IPC_EXAMPLE_Debug resp;
232+
233+
resp.state = /* Set the debug state here! */
234+
235+
cb(&resp, cb_args, IPC_RESULTCODE_SUCCESS);
236+
}
237+
```
238+
239+
Populators must be registered with libproc.
240+
241+
```c
242+
XDR_register_populator(&debug_populator, NULL, IPC_EXAMPLE_TYPES_DEBUG);
243+
```
244+
245+
## Handled commands
246+
247+
```c
248+
static void speed_cmd_handler(struct ProcessData *proc, struct IPC_Command *cmd,
249+
struct sockaddr_in *fromAddr, void *arg, int fd);
250+
251+
struct XDR_CommandHandlers handlers[] = {
252+
{IPC_EXAMPLE_CMDS_SPEED, &speed_cmd_handler, NULL}
253+
};
254+
255+
int main(int argc, char *argv[]) {
256+
// ...
257+
258+
ProcessData *proc = PROC_init_xdr("example", WD_XDR, handlers);
259+
260+
// ...
261+
}
262+
263+
```
264+
210265
# Over-the-wire Protocol
211266
212267
# Marshaling / Unmarshaling API

0 commit comments

Comments
 (0)
Please sign in to comment.