Pulsar IDL Guide
Introduction
Nebula pulsar platform uses Franca IDL for defining service interfaces. Franca IDL is language-neutral and independent of concrete bindings. Here is a simple example with an interface which supports just one method:
Interface CalculatorAPI {
method add {
in {
Float a
Float b
}
out {
Float sum
}
}
}
APIs defined with Franca IDL may consist of attributes, methods and broadcasts. You may rely on built-in, primitive types (e.g., Int16 or String) or define your own types using arrays, structures, enumerations, type aliases and others.
IDL Reference
The core of IDL is the support for interface definitions, consisting of attributes, methods and broadcasts. Those definitions will be based on a type system, which provides a variety of primitive and user-defined types as well as constant definitions. Types and constants can be defined either on a global scope using type collections, or as part of an interface definition. Finally, IDL supports Java-doc like tagged comments called structured comments and language features like packages.
Data Types
IDL supports a predefined set of primitive data types and a variety of user-defined types. User-defined types may be arrays, type aliases, structures, unions, enumerations or maps. User-defined types can refer to primitive types or other, previously defined types.
Primitive Types
The primitive types supported by IDL are listed in Table 1.1. There are several very specific signed and unsigned integer types with varying ranges. This allows us to be very specific about the size of these types on any target platform.
Type | Description |
---|---|
UInt8 | unsigned 8-bit integer (range 0..255) |
Int8 | signed 8-bit integer (range -128..127) |
UInt16 | unsigned 16-bit integer (range 0..65535) |
Int16 | signed 16-bit integer (range -32768..32767) |
UInt32 | unsigned 32-bit integer (range 0..4294967295) |
Int32 | signed 32-bit integer (range -2147483648..2147483647) |
UInt64 | unsigned 64-bit integer |
Int64 | signed 64-bit integer |
Boolean | boolean value, which can take one of two values: false or true. |
Float | floating point number (4 bytes, range +/- 3.4e +/- 38, ˜7 digits) |
Double | double precision floating point number (8 bytes, range +/- 1.7e +/- 308,˜15 digits) |
String | character string, see caveat below |
Arrays
Explicitly named, one-dimensional arrays can be defined by array ExampleArray of UInt8 size 10
The array’s element type can be any primitive or user-defined type, including another array.
array ExampleArrayRow of UInt8 size 10
Enumerations
An enumeration (also called enumerated type) is a data type consisting of a set of named values called enumerators. In Franca IDL, an enumeration is defined by.
enumeration ExampleEnumeration1 {
VALUE 1
VALUE 2
VALUE 3
// ...
}
The enumerators are identifiers which can be used as unique constants. Values for the enumerators can be defined optionally. Each value is defined using an expression (§5.3) of type integer:
enumeration ExampleEnumeration2 {
VALUE 1 = 100
VALUE 2 = 100+1
VALUE 3 = 30∗30
// ...
}
As the enumerator value can be any expression of type integer, it is also possible to specify it with a hexadecimal literal:
enumeration ExampleEnumeration2b {
VALUE 1 = 0xBADA
VALUE 2 = 0X89ab
// ...
}
Structures
A struct (also called record, tuple, or compound data) is a value that contains other values, typically in fixed number and sequence and typically indexed by names. The elements of structs are usually called fields or members (source: Wikipedia). User-defined structures can be defined by specifying the structure’s members, with a type and name for each member:
struct ExampleStruct {
UInt8 member1
String member2
ExampleArray member3
UInt16 member4
}
Element types might be predefined types or user-defined types. This allows e.g. nested structures or arrays of structures. Element types may also be arrays, e.g., member4 is an unnamed array of type UInt16.
Note that the struct type definition also defines the order of the elements. Thus, the following two struct definitions are different:
struct ExampleStruct1 {
UInt8 member1
String member2
}
struct ExampleStruct1 {
String member2
UInt8 member1
}
Unions
A union is a value that may have any of several representations or formats; or a data structure that consists of a variable which may hold such a value (source: Wikipedia). Unions can be defined by specifying its possible value types, together with a name for each representation. As a union will have only one representation at a time, the order of the union’s elements is not important. Example of a union definition:
union ExampleUnion {
UInt32 element1
Float element2
}
Element types might be predefined types or user-defined types. This allows e.g. nested unions, or unions of structures. No two elements of an union may have the same type.
Type definitions
Type definitions can be used to create new type names which are simple aliases for existing primitive or user-defined types. Example: typedef ExampleAlias is UInt32
Type Collections
A type collection is a (maybe empty) set of user-defined types and constant definitions. Each type collection in IDL has some metadata: a single identifier name for the collection and an optional version number (with major/minor scheme). The name of the type collection will be scoped relative to the fully qualified name of the package defined at the beginning of the IDL file. The following example shows the basic type collection definition:
typeCollection ExampleTypeCollection {
version { major 3 minor 1 }
// put user−defined types and constant definitions here
}
All user-defined types inside a type collection have global visibility. I.e., they can be used for defining interfaces as well as user-defined types in another type collection.
Interface Definitions
Each interface in IDL consists of some metadata (e.g., interface name and version number), the actual interface definition (consisting of attributes, methods and broadcasts) and user-defined data types. An interface definition might use the user-defined types of another interface definition. Thus, the visibility of user-defined types as part of an interface definition is not restricted.
Basic interface definition
The basic interface definition using IDL includes an interface name and a version number. (major/minor scheme). The name of an interface must be a single identifier. The following example gives a blueprint for the structure of an interface definition:
interface ExampleInterface {
version { major 5 minor 0 }
// put type definitions and constant definitions here
// put attributes, methods and broadcasts here
// put optional contract here
}
The name of the interface will be scoped relative to the fully qualified name of the package defined at the beginning of the IDL file.
The specification of a major/minor version number is optional but is strongly recommended. Changes in the major number indicate changes which are not backward compatible. Example use cases for incompatible changes:
- remove attributes, method or broadcast.
- remove element from struct or union.
- rename an attribute.
- rename a method or broadcast, or one of its arguments.
- rename a user-defined datatype.
Attributes
An attribute is a property on the provider side, which is defined as part of the interface with its type and name:
interface ExampleInterface {
version { major 5 minor 0 }
attribute {
UInt32 someAttribute
}
attribute {
arrayType arrayAttribute
}
}
Attributes might have primitive types or user-defined types. They also can be defined arrays.
The interface provider holds the data for its attributes and can change their values. The clients of an interface might actively read its attributes’ values. The clients also might register for updates of this attribute and will get change notifications afterwards. The detailed behavior of an attribute can be specified by a combination of flags.
Methods
A method in IDL interface is called by one of the clients using the interface; the response will be sent by the server. Therefore, a method definition will contain a set of in-arguments and a set of out-arguments, each with own type and name. Example:
interface Calculator {
method divide {
in {
UInt32 dividend
UInt32 divisor
} out{
UInt32 quotient
UInt32 remainder
}
}
}
Arguments might have primitive types or user-defined types. Arguments may be also specified as arrays.
Methods which do not return any values can be defined by specifying a fireAndForget flag for the method, which indicates that the server will not respond at all. Example:
interface Watchdog {
method stillAlive fireAndForget {
in {
UInt16 health
}
}
}
This can be used to implement lightweight communication patterns.
Broadcast
A broadcast in a Franca interface is called by the server and will be received by the clients using the interface. A broadcast definition will contain a single out-argument, with own type and name. Example:
interface ExampleInterface {
broadcast buttonClicked {
out {
Boolean isLongPress
}
}
}
Arguments might have primitive types or user-defined types.
Comments
IDL supports two kinds of comments: unstructured and structured comments.
Unstructured comments
Unstructured comments are usually one-line and multi-line comments as well-known from C, C++ or Java. Examples:
// this is a one−line unstructured comment
typedef TypeOne is UInt8
/∗ this is a multi−line unstructured comment, it could be used also for one−liners :−) */
typedef TypeTwo is Int16
Structured comments
Structured comments consist of tagged meta-information as known for example from
JavaDoc. Each tag starts with an @-sign. As of now the tags are not restricted and are meant for providing meta information to specific tools.
<** @description : Currently active player. All other players will reject any requests.
@author : Nebula **>
attribute tPlayer activePlayer
Fully qualified names, packages, and multiple files
Fully qualified names
A fully qualified name (or short: FQN) is a sequence of identifiers (at least one) separated by dots.
Package declarations
Each IDL file starts with a package-declaration (like Java). This puts all type collections and interfaces defined in that file into the package. The absolute reference for this top-level element is computed by concatenating the package’s FQN and the element’s FQN. Example:
package examples.demo
interface ExampleInterface {
// this interface can be globally accessed by the FQN
// examples.demo.ExampleInterface
}
Imports
IDL supports the elements to be defined in separate files and later included in other files by importing them. An example for importing is given below.
package examples.demo
// file import
import from ”basic types.fidl”
interface ExampleInterface {
// ...
}
Deployment
The deployment details in IDL models are related to the implementation of the interfaces on a target platform and the actual deployment of these interfaces on the platform. The meaning of these parameters is binding dependent and different bindings may define specific parameters. The code generator uses this information while generating interface accessor code.
Each element in the model, like interfaces, methods, events or attributes can have their own deployment details and are specified inside the deployment as shown in example:
package examples.demo
interface ExampleInterface {
// ...
attribute fooAttribute {
// elements
}
method fooMethod {
// elements
}
broadcast fooEvent {
// elements
}
}
deployment for examples.demo.ExampleInterface {
SomeIpServiceID = 1000
instance {
SomeIpInstanceID = 100
}
attribute fooAttribute {
// deplyment details
}
method fooMethod {
// deplyment details
}
broadcast fooEvent {
// deplyment details
}
}
Deployment for SOMEIP binding.
This section describes the deployment details specific to SOMEIP. As mentioned before for SOMEIP binding each element like interface should have its own deployment details provided. The deployment details for different elements are explained below.
Interface
For interface the deployment contains SOMEIP instance details grouped using instance tag. Examples are given below.
package examples.demo
deployment for examples.demo.ExampleInterface {
// ...
instance {
// instance details
}
}
The following table describes the elements that can be included in each of the instance deployment elements.
Parameter | Description |
---|---|
SomeIpInstanceID | Instance Id of the service |
SomeIpUnicastAddress | IP address of the system where the service will be deployed (Optional) |
SomeIpReliableUnicastPort | TCP port to use (Optional) |
SomeIpUnReliableUnicastPort | UDP port to use (Optional) |
Attributes
The attributes deployment describes the runtime behavior of the attributes such as readonly, write only etc. The following table describes the deployment elements supported by attributes for SOMEIP binding.
Parameter | Description |
---|---|
SomeIpGetterId | Method Id for getter method. If not defined attribute is write only (Optional) |
SomeIpSetterId | Method Id for setter method. If no defined attribute is read only (Optional) |
SomeIpNotifierId | EventId for notification (Optional) |
SomeIpNotifierEventGroups | Event group for notification (Optional) |
SomeIpAttributeReliable | True/false. If true implementation will use TCP for transport otherwise use UDP |
Methods
The following table summarizes the elements supported for method deployment for SOMEIP.
Parameter | Description |
---|---|
SomeIpMethodId | Some IP method Id |
SomeIpReliable | True/false. If true implementation will use TCP for transport otherwise use UDP |
Broadcast
The following table summarizes the elements supported for event deployment for SOMEIP.
Parameter | Description |
---|---|
SomeIpEventId | Some IP method Id |
SomeIpEventReliable | True/false. If true implementation will use TCP for transport otherwise use UDP |