APX IDL v1.2
This is the specification for the APX Interface Definition Language (IDL) v1.2.
Table of contents
- Definition files
- APX Header
- Statements and specifiers
- Node Declarations
- Type Declarations
- Data Signatures
- Type Attributes
- Port Declarations
- Port Attributes
- Full Language Specification
Definition files
APX IDL is used when writing definition files that use the .apx
file extension. Preferably these files should be generated by a toolchain but they can on occasion be written by hand.
Each file shall be used to describe one APX node. It’s not allowed (in this version of IDL) to place multiple node declarations in the same file.
Line endings
The only acceptable line ending (or EOL) is the UNIX line ending (\n
). If you are a Windows developer you must remember to convert your APX definition file to UNIX line ending before use with any of the implementations.
Structure of an APX Definition File
Example:
APX/1.2
N"Example"
T"VehicleSpeed_T"S
T"EngineSpeed_T"S
P"VehicleSpeed"T[0]:=65535
P"EngineSpeed"T[1]:=65535
APX Header
The first line of the definition file must contain an APX header. This is inspired by the HTTP header and contains the letters APX/
followed by the IDL version.
Example:
APX/1.2
Statements and specifiers
Following the APX header line are one or more APX statement lines. The first letter of each line sets what kind of statement it is.
Statement Specifier | Statement Type |
---|---|
N | Node Declaration |
T | Type Declaration |
R | Require-Port Declaration |
P | Provide-Port Declaration |
There can be at most one statement per line as there is no statement separator in APX IDL.
Node Declarations
A node declaration begins a new APX node. All lines following it belongs to that node. Each node has a name (string literal), it must be unique within the same APX client. There can only be a single node declaration for each definition file.
A Node declaration does not have an attribute section, only a name.
Example:
N"MyNode"
Type Declarations
A type declaration statement creates a new type that can be referenced later by one or more port declarations.
‘T’ Name Data-Signature
Example:
# Type "VehicleSpeed_T" with type uint16
T"VehicleSpeed_T"S
You can also add an optional type attribute section separated by a :
character.
‘T’ Name Data-Signature ’:’ Type-Attribute
Example:
# Type "OffOn_T" with type uint8 and range 0..3
T"VehicleSpeed_T"C(0,3):VT("OffOn_Off", "OffOn_On", "OffOn_Error", "OffOn_NotAvailable")
Data Signatures
Primitive Type Codes
APX uses single letter type codes. In general (but not always) a lower-case letter means signed while an upper-case letter means unsigned.
Type Code | Platform Type | Bits | Lower Limit | Upper Limit |
---|---|---|---|---|
c | int8 | 8 | -128 | 127 |
s | int16 | 16 | -32768 | 32767 |
l | int32 | 32 | -2147483648 | 2147483647 |
u | int64 | 64 | -(2^63) | (2^63)-1 |
C | uint8 | 8 | 0 | 255 |
S | uint16 | 16 | 0 | 65535 |
L | uint32 | 32 | 0 | 4294967295 |
U | uint64 | 64 | 0 | (2^64)-1 |
a | unsigned char | 8 | 0 | 255 |
Array Types
Any primitive type code can be followed by [n]
where n is the number of array elements.
Examples:
C[3] # type: uint8, array-length: 3, memory-size: 3
S[4] # type: uint16, array-length: 4, memory-size: 8 bytes
Strings
Declaring an array using the a
type code turns the type into a string. The array length in that case declares how many bytes the string can contain (at the most).
APX allows writing of strings whose length are shorter to or equal to the maximum number of array elements (bytes). In that case, APX automatically sets the remaining bytes in the string to zero or null. This is not the case for other array types. reading and writing these ports must contain data that matches the number of array elements in the declaration.
Examples:
a[10] # type string, array-length: 10, memory-size: 10 bytes
a[40] # type string, array-length: 40, memory-size: 40 bytes
Data Limits
All primitive type codes can have an optional lower/upper limit. This is done by adding (Lower, Upper)
right after the type code.
- Lower: Lower data limit (decimal integer)
- Upper: Upper data limit (decimal integer)
If no data limit is defined it will implicitly derive the data limit from the underlying primitve type.
When a data limit is combined with an array declaration the limit declaration is always placed before the array declaration
Examples:
C(0,1) #type:uint8, lower-limit: 0, upper-limit: 1
C(0,3) #type:uint8, lower-limit: 0, upper-limit: 3
S(0,10000) #type:uint16, lower-limit: 0, upper-limit: 10000
C #type: uint8, lower-limit: 0 (implicit), upper-limit: 255 (implicit)
S #type: uint8, lower-limit: 0 (implicit), upper-limit: 65535 (implicit)
C(0,3)[10] #type: uint8, array-length: 10, lower-limit (for each elem): 0 upper-limit (for each elem): 3
Record Types
Record types (sometimes known as struct types) can be declared in APX by wrapping the data signature in braces {}
.
After the opening brace {
Any number of record elements can be added until the closing brace }
is seen.
Each record elements consist of type parts in the following order.
- Element name: String Literal
- Element signature: Data Signature
Record elements are entered one after the other (name, data signature, name data signature, etc.). No whitespace or separators (such as commas are allowed). The order of record elements data is preserved during serialization/deserialization.
Examples:
# Record with 2 elements. "UserId" has type uint32 while "UserName" is a string of max 64 bytes.
{"UserId"L"UserName"a[64]}
#Record with 3 elements named "Red", "Green" and "Blue". Each element is of type uint8.
{"Red"C"Green"C"Blue"C}
For this version of the IDL, any APX implementation do not need to support records to be defined within records (nested structures). APX IDL 1.3 however has that conformance requirement.
Type References
Data signatures can reference a type definition by using capital letter T
followed by the index of the data type enclosed in brackets []
.
Example:
T"VehicleSpeed_T"S # This type has index 0
T"EngineSpeed_T"S # This type has index 1
P"VehicleSpeed"T[0]:=65535 # References VehicleSpeed_T
P"EngineSpeed"T[1]:=65535 # Reference EngineSpeed_T
This version of the IDL does not support type reference by name (see APX IDL v1.3).
Type Attributes
In this version of the IDL there is only a single type attribute, the value table.
Value Table
A value table maps enumeration names onto a data type. You declare it using the VT()
syntax where you place a list string literals inside the parenthesis. Each string literal shall be separated by a comma.
Example:
VT("OffOn_Off", "OffOn_On", "OffOn_Error", "OffOn_NotAvailable")
This version of the IDL does not have any fancy options such as manually selecting what string literal is assigned to what value etc.
Port Declarations
There are two types of ports in APX, Require-ports and Provide-ports. The only difference between them is wether the data is coming into or going out from the APX node.
Require-port Declaration
A Require port declaration starts with capital letter R
followed by its name and data signature.
‘R’ Name Data-Signature
Example:
# Require-port "VehicleSpeed" with data type uint16
R"VehicleSpeed"S
# Require-Port "EngineSpeed" with type reference 1
R"EngineSpeed"T[1]
The port definition can also have an optional port attribute section separated by the :
character.
‘R’ Name Data-Signature ’:’ Port-Attributes
Example:
# Require-port "VehicleSpeed" with data type uint16 and init-value 65535
R"VehicleSpeed"S:=65535
# Require-Port "EngineSpeed" with type reference 1 and init-value 65535
R"EngineSpeed"T[1]:=65535
Provide-port Declaration
A Provide-port declaration starts with capital letter P
followed by its name and data signature.
‘P’ Name Data-Signature
Example:
# Provide-Port "VehicleSpeed" with data type uint16
P"VehicleSpeed"S
# Provide-Port "EngineSpeed" with type reference 1
P"EngineSpeed"T[1]
The port definition can also have an optional port attribute section separated by the :
character.
‘P’ Name Data-Signature ’:’ Port-Attributes
Example:
# Provide-port "VehicleSpeed" with data type uint16 and init-value 65535
P"VehicleSpeed"S:=65535
# Provide-Port "EngineSpeed" with type reference 1 and init-value 65535
P"EngineSpeed"T[1]:=65535
Port Attributes
Port attributes is a list of characters that is placed after the :
in a port declaration. Some port attributes are a single character while other can be more than one character.
- Each attribute must be separated by a comma.
- The order of the attributes does not matter, they all get applied to your port declaration.
Init-Value
The init-value attribute sets the initial value of the port data. If no init value exists, the port data will be initialized to zero. This attribute can be 2 or more characters depending on the complexity of the port data signature.
The first character of this attribute must be the equal-sign =
, this identfies the character(s) to come after it to be part of the init-value (until either next comma or end-of-line is encountered).
APX accepts four different forms of initializers:
- decimal
- hexadecimal
- string
- record
Decimal and Hexadecimal Initializers
The most common form of initializer is a decimal integer. APX also accepts hexadecimal initializers when prefixed with 0x
.
Examples:
=7 #Decimal init-value
=255 #Decimal init-value
=0xff #Hexadecimal init-value
=0xffff #Hexadecimal init-value
String Initializer
When the data signature is of string type (arrray of typecode a) a string initializer is expected. Not all implementations of APX IDL v1.2 supports unicode characters as part of the initializer so it is best not to use them until all implementations supports APX IDL v1.3.
Example:
="" #Empty string initializer.
Record Initializer
Record initializer works similarly to C struct initializers. The initializer must be a non-empty, brace-enclosed, comma-separated list of initializers for each member in the data signature.
Example:
={255, 255, 255} #Record initializer for data signature containing 3 members.
Full Language Specification
Document
ApxHeader '\n' Statements
ApxHeader
'APX/1.2'
Statements
Statement '\n'
Statement '\n' Statement
Statement
NodeDeclaration
TypeDeclaration
RequirePortDeclaration
ProvidePortDeclaration
NodeDeclaration
'N' Name
TypeDeclaration
'T' Name TypeSignature
'T' Name TypeSignature ':' TypeAttributes
RequirePortDeclaration
'R' Name TypeSignature
'R' Name TypeSignature ':' PortAttributes
ProvidePortDeclaration
'P' Name TypeSignature
'P' Name TypeSignature ':' PortAttributes
Name
'"' NameChars '"'
Names
Name
Name ',' Names
NameChars
NameChar
NameChar NameChars
NameChar
'a' . 'z'
'A' . 'Z'
'0' . '9'
'_'
'-'
TypeSignature
PrimitiveType
PrimitiveType '[' OneNine Digits ']'
'T[' Digits ']'
'{' RecordElements '}'
PrimitiveType
c
s
l
u
C
S
L
U
RecordElements
Name TypeSignature
Name TypeSignature ',' RecordElements
TypeAttributes
TypeAttribute
TypeAttribute ',' TypeAttributes
TypeAttribute
VT(Names)
PortAttributes
PortAttribute
PortAttributes ',' PortAttributes
PortAttribute
'=' Integer
'=' StringLiteral
Integer
Digit
OneNine Digits
'-' Digit
'-' OneNine Digits
'0x' HexDigits
Digits
Digit
Digit Digits
Digit
'0'
OneNine
OneNine
'1' . '9'
HexDigits
HexDigit
HexDigit HexDigits
HexDigit
Digit
'a' . 'f'
'A' . 'F'
StringLiteral
'"' '"'
'"' Characters '"'
Characters
character
character characters
character
'0020' . '007F' - '"'