APX IDL v1.3¶
This is the specification for the APX Interface Definition Language (IDL) v1.3.
New features in APX IDL v1.3¶
New type code primitives:
Boolean (
b)Byte/ByteArray (
B)Char (
a, redefined as Latin-1 encoded character)Char8 (
A, UTF-8 encoded character)Char16 (
u, UTF-16 encoded character, defined for v1.4)Char32 (
U, UTF-32 encoded character, defined for v1.4)Int64 (
q)UInt64 (
Q)
New complex type support:
Dynamically sized arrays (APX uses the term dynamic array for short)
Type reference by name (
T["TypeName"])Arrays of type references (
T[0][8],T["TypeName"][8])Records inside records (Structs within structs)
Arrays of records (Array of structs)
Dynamically sized arrays of records
Records containing inner type references
New type attributes:
RationalScaling (
RS) (Lower limit, Upper limit, Offset, Numerator, Denominator, Unit)Extended ValueTable (
VT) support (Offsets, Value ranges, and Multiple ValueTables)
New port attributes:
Parameter port attribute (
P) (Identifies calibration/configuration parameters)Queue size attribute (
Q[n]) (For queued signals)Empty array initializers (
={}) (Used together with dynamic arrays)
Other:
ValueTable support is now mandatory
Type code range checks are now mandatory
Compatibility with APX IDL v1.2¶
APX IDL v1.3 builds on top of v1.2 and mostly adds new features. However, there are two key differences to be aware of when migrating from APX IDL v1.2 to v1.3:
1. 64-bit Integer Type Codes¶
In APX IDL v1.2, 64-bit signed and unsigned integers used the type codes u and U, respectively. In APX IDL v1.3, these have been changed to:
q: int64 (Signed 64-bit integer)Q: uint64 (Unsigned 64-bit integer)
The type codes u and U have been reassigned to char16 (UTF-16) and char32 (UTF-32), which are reserved for APX IDL v1.4.
2. String and Character Encodings¶
APX IDL v1.2 was ambiguous regarding string encoding, offering only a single type code a for character arrays. APX IDL v1.3 introduces explicit character encodings:
a: char character (Latin-1 encoding)A: char8 character (UTF-8 encoding)u: char16 character (UTF-16 encoding, reserved for v1.4)U: char32 character (UTF-32 encoding, reserved for v1.4)
If you have existing APX IDL v1.2 files that contain UTF-8 encoded characters as part of a port initializer or string data, replace the lowercase a type code with uppercase A.
Definition files¶
APX IDL is written to definition files that use the .apx file extension.
Preferably these files should be generated by a toolchain, but they can also be written by hand.
Each file shall be used to describe one APX node. Placing multiple node declarations in the same file is not permitted.
Line endings¶
The preferred line ending (EOL) sequence is the UNIX line ending (\n). APX parsers may optionally support Windows line endings (\r\n).
For maximum portability, users of APX should convert their definition files to UNIX line endings before use.
Structure of an APX Definition File¶
Example:
APX/1.3
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. Inspired by HTTP headers, it consists of the prefix APX/ followed by the IDL version number.
Example:
APX/1.3
Statements and specifiers¶
Following the APX header line come one or more APX statement lines. The first letter of each line selects the statement type:
Statement Specifier |
Statement Type |
|---|---|
N |
|
T |
|
R |
|
P |
There can be at most one statement per line; there is no statement separator in APX IDL other than the end-of-line (EOL) character.
The colon separation character¶
The colon : character is used to separate a statement into a left and a right part. What appears to the left of the colon is the actual definition (type or port), while what appears to the right is the attribute list.
On a line containing a type definition (
T), the attributes are called Type attributes.On a line that declares a port (
R,P), the attributes are called Port attributes.
Attributes are optional. When declaring a type or port without attributes, the colon separator is omitted.
A line must not end with a colon : without an attribute definition following it.
Node Declarations¶
A node declaration begins a new APX node. All subsequent lines belong to that node.
Each node has a name (string literal enclosed in quotes) that must be unique within the APX client connection.
There can only be a single node declaration per definition file, and the node name must match the file name without the .apx extension.
A Node declaration does not have an attribute section.
Example:
N"MyNode"
Type Declarations¶
A type declaration statement creates a new named type that can be referenced later by port declarations or by other type declarations.
‘T’ Name Data-Signature
Example:
# Type "VehicleSpeed_T" with type uint16
T"VehicleSpeed_T"S
You can also include an optional type attribute section separated by a : character:
‘T’ Name Data-Signature : Type-Attribute
Example:
# Type "OffOn_T" with type uint8, range 0..3 and ValueTable
T"OffOn_T"C(0,3):VT("OffOn_Off", "OffOn_On", "OffOn_Error", "OffOn_NotAvailable")
Data Signatures¶
Primitive Type Codes¶
APX uses single-letter primitive type codes. In general, lowercase letters represent signed types and uppercase letters represent unsigned types.
Type Code |
Platform Type |
Bits |
Lower Limit |
Upper Limit |
Encoding |
Notes |
|---|---|---|---|---|---|---|
c |
int8 |
8 |
-128 |
127 |
||
s |
int16 |
16 |
-32768 |
32767 |
Little Endian |
|
l |
int32 |
32 |
-2147483648 |
2147483647 |
Little Endian |
|
q |
int64 |
64 |
-(2^63) |
(2^63)-1 |
Little Endian |
New in v1.3 (replaces v1.2 |
C |
uint8 |
8 |
0 |
255 |
||
S |
uint16 |
16 |
0 |
65535 |
Little Endian |
|
L |
uint32 |
32 |
0 |
4294967295 |
Little Endian |
|
Q |
uint64 |
64 |
0 |
(2^64)-1 |
Little Endian |
New in v1.3 (replaces v1.2 |
a |
char |
8 |
0 |
255 |
Latin-1 |
Redefined in v1.3 |
A |
char8 |
8 |
0 |
255 |
UTF-8 |
New in v1.3 |
u |
char16 |
16 |
0 |
65535 |
UTF-16 |
Reserved for v1.4 |
U |
char32 |
32 |
0 |
(2^32)-1 |
UTF-32 |
Reserved for v1.4 |
b |
boolean |
8 |
0 |
1 |
New in v1.3 |
|
B |
byte |
8 |
0 |
255 |
New in v1.3 |
|
T |
type reference |
- |
- |
- |
Index or name reference |
Array Types¶
Any primitive type code or type reference can be followed by [n], where n is the number of array elements.
Examples:
C[3] # type: uint8, array-length: 3, memory-size: 3 bytes
S[4] # type: uint16, array-length: 4, memory-size: 8 bytes
Dynamically sized arrays¶
Any primitive, record, or type reference can be followed by [n*], where n is the maximum number of array elements.
The initial length of a dynamically sized array is zero (unless an explicit empty initializer ={} is used).
The APX server will only connect ports together where the receiver buffer is equal to or larger than the sender buffer.
Examples:
P"MyBuffer"B[400*] # type: Byte, Array-length: 400, is-dynamic: True
R"MyBuffer"B[420*] # type: Byte, Array-length: 420, is-dynamic: True (Matches OK in APX server)
R"MyBuffer"B[300*] # type: Byte, Array-length: 300, is-dynamic: True (Matches NOK in APX server)
Record Types¶
Record types (structs) are declared in APX by wrapping the record elements in curly braces {}.
Each record element consists of two parts:
Element name: String literal enclosed in quotes (e.g.
"UserId")Element signature: Data Signature
Record elements are placed consecutively without whitespace or separators (such as commas). The order of elements is preserved during serialization and deserialization.
Examples:
# Record with 2 elements: "UserId" (uint32) and "UserName" (string of 64 Latin-1 characters)
{"UserId"L"UserName"a[64]}
# Record with 3 uint8 elements
{"Red"C"Green"C"Blue"C}
# Nested records (records inside records)
{"Notification"{"ID"C(0,127)"Status"C(0,3)}}
# Record containing type references
{"Header"T["Header_T"]"Payload"B[256]}
# Array of records
{"Id"S"Value"C}[10]
# Dynamically sized array of records
{"Id"S"Status"b}[50*]
Type Limits¶
Primitive integer and byte type codes can declare an optional lower and upper limit using the (Lower, Upper) syntax immediately following the type code:
Lower: Lower value limit (decimal integer or hex)
Upper: Upper value limit (decimal integer or hex)
If no limit is specified, the range implicitly defaults to the underlying primitive type’s full range. When combined with an array declaration, the limit is placed before the array brackets.
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
q(-1000,1000)# type: int64, lower-limit: -1000, upper-limit: 1000
C # type: uint8, lower-limit: 0 (implicit), upper-limit: 255 (implicit)
S # type: uint16, lower-limit: 0 (implicit), upper-limit: 65535 (implicit)
C(0,3)[10] # type: uint8 array, length: 10, limits: 0..3 for each element
Type References¶
Data signatures can reference a type definition using the capital letter T followed by either the numeric type index or the type name enclosed in brackets []:
By Index:
T[index](e.g.T[0])By Name:
T["TypeName"](e.g.T["VehicleSpeed_T"])
Type references can also be declared as fixed-size arrays (T[0][8] / T["Type"][8]) or dynamic arrays (T[0][8*] / T["Type"][8*]), and can be nested within record definitions.
Examples:
T"VehicleSpeed_T"S # Type index 0
T"EngineSpeed_T"S # Type index 1
P"VehicleSpeed"T[0]:=65535 # Reference by index
P"EngineSpeed"T["EngineSpeed_T"]:=0 # Reference by name
R"SpeedHistory"T[0][10] # Array of 10 type references
Strings¶
In APX IDL, strings are represented as character arrays using the a (Latin-1) or A (UTF-8) type codes. The array length specifies the maximum size of the string in bytes:
a[10] # Latin-1 string, max length 10 bytes
A[64] # UTF-8 string, max length 64 bytes
APX allows transmitting strings shorter than or equal to the declared maximum length. In that case, APX automatically sets the remaining bytes to null (\0).
Type Attributes¶
APX IDL v1.3 supports two categories of type attributes:
ValueTable (
VT)RationalScaling (
RS)
Multiple type attributes can be combined on a single type declaration by separating them with commas.
Value Table¶
A ValueTable maps numeric values or ranges to enumeration names. It uses the VT(...) syntax:
Standard 0-Indexed Table: Comma-separated string literals starting at index 0.
VT("OffOn_Off", "OffOn_On", "OffOn_Error", "OffOn_NotAvailable")Custom Starting Offset: The first argument specifies the lower limit integer:
VT(4, "State_Active", "State_Pending", "State_Complete") # Values 4, 5, 6 VT(-3, "Err3", "Err2", "Err1", "NoError") # Values -3, -2, -1, 0
Value Range Mapping: Two integer arguments define a range mapped to a string literal:
VT(251, 254, "Error") # Values 251 through 254 all map to "Error"
Multiple ValueTables:
VT(251, 254, "Error"), VT(255, "NotAvailable")
Rational Scaling¶
The RationalScaling attribute specifies physical unit scaling for integer-based data types. It uses the RS(...) syntax with 6 arguments:
RS(LowerLimit, UpperLimit, Offset, Numerator, Denominator, "Unit")
The mathematical formula relating raw value to physical value is:
Arguments:
LowerLimit: Lower integer raw value limit
UpperLimit: Upper integer raw value limit
Offset: Floating-point or integer offset
Numerator: Integer multiplier
Denominator: Non-zero integer divisor
Unit: String literal specifying the engineering unit
Examples:
# Vehicle speed with 1/64 km/h resolution
T"VehicleSpeed_T"S:RS(0, 65280, 0, 1, 64, "km/h")
# Combined Rational Scaling and ValueTables
T"VehicleSpeed_T"S:RS(0, 0xFDFF, 0, 1, 64, "km/h"), VT(0xFE00, 0xFEFF, "Error"), VT(0xFF00, 0xFFFF, "NotAvailable")
Port Declarations¶
There are two types of ports in APX:
Require-ports (
R): Input ports receiving data into the node.Provide-ports (
P): Output ports transmitting data from the node.
Require-port Declaration¶
A Require-port declaration starts with capital letter R followed by its name and data signature:
‘R’ Name Data-Signature
# Require-port "VehicleSpeed" with data type uint16
R"VehicleSpeed"S
# Require-port "EngineSpeed" with type reference by index
R"EngineSpeed"T[1]
# Require-port with type reference by name
R"EngineSpeed"T["EngineSpeed_T"]
Optional port attributes are appended after a colon : separator:
‘R’ Name Data-Signature : Port-Attributes
# Require-port with init-value
R"VehicleSpeed"S:=65535
Provide-port Declaration¶
A Provide-port declaration starts with capital letter P followed by its name and data signature:
‘P’ Name Data-Signature
# Provide-port "VehicleSpeed" with data type uint16
P"VehicleSpeed"S
# Provide-port with init-value
P"VehicleSpeed"S:=65535
Port Attributes¶
Port attributes appear after the colon : separator in a port declaration. Multiple attributes are separated by commas; their order does not matter.
Init-Value (=)¶
The init-value attribute defines the initial state of the port data. If omitted, the port data defaults to zero (or empty).
APX IDL v1.3 supports the following forms of initializers:
Decimal and Hexadecimal Initializers¶
=7 # Decimal init-value
=255 # Decimal init-value
=0xff # Hexadecimal init-value
=0xffff # Hexadecimal init-value
String Initializers¶
="" # Empty string initializer
="Hello" # String initializer
Array and Record Initializers¶
Enclosed in curly braces {} with comma-separated elements:
={255, 255, 255} # Record initializer with 3 fields
={ {0xFFFF, 0}, {0xFFFF, 0} } # Array of 2 records
Empty Initializers for Dynamic Arrays¶
For dynamically sized arrays ([n*]), dynamic array initializers must be empty:
={} # Empty array initializer for dynamic arrays
Parameter Attribute (P)¶
The P port attribute designates the port as a calibration or configuration parameter rather than regular runtime signal data.
P"WheelCircumference"S:=1850, P
Queue Length Attribute (Q[n])¶
The Q[n] attribute configures a port as a queued port with a maximum queue capacity of n elements:
R"EventLog"S:=0, Q[10]
Combined Port Attributes¶
Port attributes can be freely combined using comma separators:
P"ConfigParam"S:=100, P
R"EventQueue"T["Event_T"]:={}, Q[16]
Full Language Specification¶
Document
ApxHeader '\n' Statements
ApxHeader
'APX/1.3'
Statements
Statement '\n'
Statement '\n' Statements
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 Limits
PrimitiveType ArrayLength
PrimitiveType Limits ArrayLength
TypeReference
TypeReference ArrayLength
RecordType
RecordType ArrayLength
PrimitiveType
'c'
's'
'l'
'q'
'C'
'S'
'L'
'Q'
'a'
'A'
'u'
'U'
'b'
'B'
Limits
'(' Integer ',' Integer ')'
ArrayLength
'[' Digits ']'
'[' Digits '*' ']'
TypeReference
'T[' Digits ']'
'T[' Name ']'
RecordType
'{' RecordElements '}'
RecordElements
RecordElement
RecordElement RecordElements
RecordElement
Name TypeSignature
TypeAttributes
TypeAttribute
TypeAttribute ',' TypeAttributes
TypeAttribute
ValueTable
RationalScaling
ValueTable
'VT(' ValueTableArgs ')'
ValueTableArgs
Names
Integer ',' Names
Integer ',' Integer ',' Names
RationalScaling
'RS(' Integer ',' Integer ',' Number ',' Integer ',' Integer ',' StringLiteral ')'
PortAttributes
PortAttribute
PortAttribute ',' PortAttributes
PortAttribute
'=' Initializer
'P'
'Q[' Digits ']'
Initializer
Integer
StringLiteral
'{' '}'
'{' InitializerList '}'
InitializerList
Initializer
Initializer ',' InitializerList
Number
Integer
Float
Float
Integer '.' Digits
Integer
'0'
OneNine DigitsOptional
'-' '0'
'-' OneNine DigitsOptional
'0x' HexDigits
DigitsOptional
/* empty */
Digits
Digits
Digit
Digit Digits
Digit
'0' . '9'
OneNine
'1' . '9'
HexDigits
HexDigit
HexDigit HexDigits
HexDigit
'0' . '9'
'a' . 'f'
'A' . 'F'
StringLiteral
'"' CharactersOptional '"'
CharactersOptional
/* empty */
Characters
Characters
Character
Character Characters
Character
'0020' . '007F' - '"'