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

  1. APX Header

  2. Node Declaration

  3. Type Declaration(s) (Optional)

  4. Port Declaration(s)

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:

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 u)

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 U)

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:

  1. Element name: String literal enclosed in quotes (e.g. "UserId")

  2. 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:

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:

  1. Standard 0-Indexed Table: Comma-separated string literals starting at index 0.

    VT("OffOn_Off", "OffOn_On", "OffOn_Error", "OffOn_NotAvailable")
    
  2. 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
    
  3. 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"
    
  4. 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:

\[\text{PhysicalValue} = \left(\text{RawValue} \times \frac{\text{Numerator}}{\text{Denominator}}\right) + \text{Offset}\]

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' - '"'