Annex A: | Language Translations |
---|---|
A.1 | C Language Mapping |
A.1.1 | Naming Conventions |
A.1.2 | Header Files |
A.1.3 | Interface Type Mappings |
A.1.4 | Inheritance and Base Types |
A.1.5 | Interface Operations |
A.2 | C++ Language Mapping |
A.2.1 | Naming Conventions |
A.2.2 | Header Files |
A.2.3 | Constructor and Destructor |
A.2.4 | Interface Classes |
A.3 | Python Mapping |
A.3.1 | Naming Conventions |
A.3.2 | Application Classes |
A.3.3 | Constructor and Destructor |
A.3.4 | Interface Operations |
A.4 | Perl Mapping |
A.5 | Ruby Mapping |
A.6 | Java Mapping |
A.7 | Lua Mapping |
Annex A: Language Translations
This appendix describes some specific mappings to programming languages for STI interfaces. This section is intended to clarify certain aspects of the IDL mappings to ensure that different implementations will remain consistent with regard to these interface definitions.
Many of the interface definitions in this specification are provided as OMG Interface Definition Language (IDL) fragments. OMG also specifies a specific method for mapping these interfaces to source code in various common programming languages, and the STI implementation of these interfaces will adhere to these mappings where relevant.
Earlier versions of the OMG IDL specification were specifically designed for defining the interfaces within a CORBA environment. IDL has since been revised as a general-purpose interface definition language and has been released independently from CORBA since version 3.5. While a compliant implementation of STI may utilize a CORBA-like layer to exchange data between modules, there is no requirement for nor assumption of a CORBA environment within STI. As such, the function prototypes or interface definitions based on the IDL fragments in this specification will not directly include any CORBA references.
All IDL fragments in this document shall be interpreted as belonging to an IDL module called “STI”, with interface and identifier names mapped accordingly. To ensure naming consistency across differing OE implementations, a specific header file/module/namespace needs to be implemented such that the same function names are present and available on all STI implementations. Each programming language environment has differences in the paradigms used for this purpose.
The general STI architecture can also be implemented in programming languages using the translations prescribed by the IDL specification. Additional directives on how the IDL translations apply to the STI applications and infrastructure is available in this section. This section is intended to clarify certain aspects of the interface translation for commonly used programming languages, but other language translations beyond what is specified here are also possible. The appendix may be extended in a future revision of this specification to contain additional language mappings.
Nearly all modern high-level programming languages support some notion of “packages” or “modules” to separate functionality into logical entities. Whenever possible, all STI functionality should be encapsulated in a single package or module called “STI”. Note that some languages, such as Java, dictate additional package naming recommendations. Any such language-specific package name recommendations should also be adhered to. In C and C++, the interfaces are available through multiple header files.
All object-oriented languages such as C++, Java, and Python generally support the same fundamental concepts of inheritance and interfaces. For these languages, the interface translation is fairly straightforward, and the application will use the language’s native inheritance mechanisms. For other languages such as C, which are not natively object-oriented, the approach differs slightly, but many of the same concepts can still be employed even if not directly supported by the language. Therefore, a different set of requirements will apply to applications implemented in C versus other object-oriented languages.
All STI applications and devices should encapsulate their state in an object or structure of some type, referred to as the “base object”. Even for “singleton” objects of which there can only be one, STI requires that there is still a base object associated with the instance, even if this object does not contain any extra information.
Figure 9 also shows several different optional interfaces that an application or device may implement, depending on its specific design needs. In object-oriented languages, the set of interfaces is indicated in the object definition, using the language’s inheritance mechanisms. In these languages, a “connection” between the implementation and interface is automatically made through the language’s type system. In non-object-oriented languages, such as C, a separate mechanism is necessary to explicitly create the connection between a given implementation to the interface it implements. For STI, a naming convention is employed to facilitate this connection.
In object-oriented languages, the conversion to an Instance object is achieved by simply inheriting from the proper base class. In non-object-oriented languages, the application developer will implement this conversion, and it is not specified how the conversion takes place. For a singleton object, this can be a simple global. In C, this could be performed using a pointer conversion of some sort. Alternatively, this could be implemented using a lookup table or dictionary.
A.1 C Language Mapping
The C programming language is standardized as ISO/IEC 9899, with a specific revision to the standard identified by a year number suffix (e.g. ISO/IEC 9899:1999). The STI architecture should be implementable in any current or future version of the C programming language.
A.1.1 Naming Conventions
Unlike other languages, the C language does not include the concept of a “namespace” or “module” to avoid identifier name collisions between global-scope symbols in separate libraries or code units. As such, it is common practice to add a prefix to all global identifier names supplied by a library or module as a means of differentiation.
All infrastructure-provided functions, constants, and types defined in this specification shall be denoted with an “STI_” prefix when mapped to identifiers in the C programming language. For example, the “Instance” type is named “STI_Instance”, the “OK” result value constant is named “STI_OK”, the “Write” method is named “STI_Write”, and so forth.
All application-provided implementation written in the C language shall be denoted with a prefix defined by the application. For instance, if an application were named “Example”, the application-provided application control methods may be called “Example_APP_Instantiate”, “Example_APP_Start”, and so forth.
A.1.2 Header Files
The following header files shall be provided by the infrastructure, such that applications can use the #include preprocessor directive to incorporate the respective resources:,
Table 90: C Language Header Files
Include File | Provides |
---|---|
STI.h | C language STI data types and abstract object definitions. This file provides declarations of all data types described in section 12.4. |
STI_APIs.h | C language function prototype declarations for all infrastructure-provided API calls. This file provides declarations of all calls described in section 12.7. |
STI_ApplicationControl.h | C language function prototype declarations associated with ApplicationControl interface, as described in sections 12.5.1 – 12.5.11. |
STI_DeviceControl.h | C language function prototype declarations associated with DeviceControl interface, as described in section 12.6. |
STI_Source.h | C language function prototype declarations associated with the Source interface, as described in section 12.5.12. |
STI_Sink.h | C language function prototype declarations associated with the Sink interface, as described in section 12.5.13. |
STI_RandomAccess.h | C language function prototype declarations associated with the RandomAccess interface, as described in sections 12.5.14 – 12.5.15. |
After utilizing the language-specific import statement, all components of the STI API can be referenced using the paradigm of the respective language’s package/module facility.
A.1.3 Interface Type Mappings
Table 5, Infrastructure-provided Data Types, in section 12.4 indicates the general semantics of each STI-defined type. These general semantics, in turn, determine the proper method to pass a value or object of that type through an IDL-defined interface or function definition.
The table below indicates the basic type mappings for the C language. This table also indicates whether an operand should be passed as value or as a pointer/reference, and how the pointer type should be qualified, if applicable. For operations which utilize an abstract base type containing application-defined data of arbitrary size (e.g. Message and PropertyValue types), the size of this data will also be specified. In these cases, a single object in the IDL fragment will translate to two arguments in the C function prototype. This also applies to strings, as the C language implements strings as a pointer to the char type, rather than as a distinct value type in itself.
Table 91: C Language Data Type Mapping
Semantics | Usage | Pass As | C Data Type(s) | Applicable to |
---|---|---|---|---|
Integer, Enumeration, or aggregate value | in, return | Value | STI_<type> | Access, CalendarKind, FileSize, HandleID, Nanoseconds, Offset, QueueMaxMessages, Result, Seconds, TestID, TimeRate, TimeWarp |
out, inout | Pointer to Value | STI_<type> * | ||
string | in, return | Pointer | const char * | Object Names |
out, inout | Pointer and Size | char *, size_t | ||
Abstract Object | in | Pointer and Size | const STI_<type> *, size_t | Message, PropertyValue |
out | Pointer and Size | STI_<type> *, size_t | ||
Base Type | any | Pointer | STI_Instance * | Context Objects |
A.1.4 Inheritance and Base Types
Although C is not an object-oriented language by nature, the same basic concepts can still be manually implemented by the programmer through use of specific patterns and by utilizing type casting where necessary. The main requirement is that structure definitions be defined appropriately such that a pointer to a base structure can be reliably converted to a derived structure and vice versa.
The first element of a C structure is guaranteed to be at the same memory address as the structure itself, as specified in ISO/IEC 9899 section 6.7.2.1, as follows:
A pointer to a structure object, suitably converted, points to its initial member, and vice versa. There may be unnamed padding within a structure object, but not at its beginning.
Given this requirement, the concept of single inheritance may be implemented simply by ensuring that the “base type” of a given structure is declared as its first element. For STI, the base type of all context objects is the Instance type. The specific content of the Instance type is implementation-defined, but the infrastructure will provide this type such that it is suitable for use as a base type, as in this example:
typedef struct { STI_Instance Base; int LocalValue; } Example_Object;
Using this definition, a pointer to the base object (STI_Instance*) may be safely typecast by the application to the derived object (Example_Object*) and vice-versa. Note that while this approach generally works for simple cases, more complex applications may necessitate a different approach. The STI infrastructure only stipulates that interaction with the infrastructure takes place using an Instance object; more complex applications may in turn use this object to index into a larger state table or database.
A.1.5 Interface Operations
All methods defined in the STI application or device control interfaces in section 12.5 – 12.6, Application and Device Control Interface shall have a context object as the first parameter in the calling sequence.
All operations defined in the STI application or device control interfaces in section 12.5 – 12.6, Application and Device Control Interface, require a context object, which is the in-memory data structure comprising the device or application state. This is an application defined structure that may contain any arbitrary state information needed by the application. In object-oriented languages this object is often referred to as the “self” or “this” object and is usually implicitly supplied through the respective language internal mechanisms.
Since the C programming language does not provide these object-oriented features, the context object shall be explicitly included as the first argument in the function prototype, followed by the remainder of the operands specified in the interface definition.
STI requires that all such context objects in the system are derivatives of the infrastructure-defined Instance type. Therefore, in the C programming language, all interaction between the infrastructure and the application will use a pointer to the “STI_Instance” type to identify the target of the operation. For example, the C prototype for the APP_Instance() and APP_Start() operations in the “Example” application would be:
STI_Instance* Example_APP_Instance(STI_HandleID id, const char *name); STI_Result Example_APP_Start(STI_Instance *inst);
A.2 C++ Language Mapping
The C++ programming language is standardized as ISO/IEC 14882, with a specific revision to the standard identified by a year number suffix (e.g. ISO/IEC 14882:2003). The STI architecture should be implementable in any current or future version of the C++ programming language.
Mapping of the STI interfaces to C++ should follow the guidelines set forth in the OMG IDL C++ language mapping. However, in STI there is no assumption or dependence on CORBA types or interfaces. This section is intended to clarify how the C++ language mapping applies to STI.
A.2.1 Naming Conventions
All STI infrastructure-provided functions, constants, and types shall be defined within a C++ namespace called “STI”. For example, the “Instance” type is named “STI::Instance”, the “OK” result value constant is named “STI::OK”, the “Write” method is named “STI::Write”, and so forth.
A.2.2 Header Files
The following header files shall be provided by the infrastructure, such that applications can use the #include preprocessor directive to incorporate the respective resources:
Table 92: C++ Language Header Files
Include File | Provides |
---|---|
STI.hh | Fundamental STI data types and abstract object definitions. This file provides declarations of all data types described in section 12.4. |
STI_APIs.hh | Function prototype declarations for all infrastructure-provided API calls. This file provides declarations of all calls described in section 12.7. |
STI_ApplicationControl.hh | ApplicationControl interface class definition, as described in section 12.5.1 – 12.5.11. |
STI_DeviceControl.hh | DeviceControl interface class definition, as described in section 12.6. |
STI_Source.hh | Source interface class definition, as described in section 12.5.12. |
STI_Sink.hh | Sink interface class definition, as described in section 12.5.13. |
STI_RandomAccess.hh | RandomAccess interface class definition, as described in section 12.5.14 – 12.5.15. |
After utilizing the language-specific import statement, all components of the STI API can be referenced using the paradigm of the respective language’s package/module facility.
A.2.3 Constructor and Destructor
STI defines the APP_Instance() and APP_Destroy() methods as a means to construct and destruct instances, rather than relying on language-specific paradigms to invoke a class constructor or destructor. These should be implemented as static methods in the C++ application class. This aligns with a “factory” design pattern that allows additional application control over the construction process. When the infrastructure invokes the factory function, the application should invoke the class constructor appropriately, and return the newly constructed object.
A.2.4 Interface Classes
All other application and device control interfaces defined in section 12.5 – 12.6, Application and Device Control Interface, shall each be mapped to a C++ abstract interface base class provided by the infrastructure.
The class shall declare each of the operations as a pure virtual function, which in turn requires that any derivative class provide an implementation as a prerequisite to being instantiated.
For example, the following class definition would represent the ControllableComponent interface:
namespace STI { class ControllableComponent { public: virtual Result APP_Start() = 0; virtual Result APP_Stop() = 0; }; }
All application-provided methods shall be class member functions of an application-defined class inheriting from some or all of these abstract interface classes.
Table 5, Infrastructure-provided Data Types, in section 12.4 indicates the general semantics of each STI-defined type. These general semantics, in turn, determine the proper method to pass a value or object of that type through an IDL-defined interface or function definition.
Table 93: C++ Language Data Type Mapping
Semantics | Usage | Pass As | C++ Data Type(s) | Applicable to |
---|---|---|---|---|
Integer, Enumeration, or aggregate value | in, return | Value | STI::<type> | Access, CalendarKind, FileSize, HandleID, Nanoseconds, Offset, QueueMaxMessages, Result, Seconds, TestID, TimeRate, TimeWarp |
out, inout | Pointer to Value | STI::<type> * | ||
string (see note) | in, return | Pointer | const char * | Object Names |
out, inout | Pointer and Size | char *, size_t | ||
Abstract Object | in | Pointer and Size | const STI::<type> *, size_t | Message, PropertyValue |
out | Pointer and Size | STI::<type> *, size_t | ||
Base Type | any | Pointer | STI::Instance * | Context Objects |
The “string” types in C++ shall utilize C-style string representations (pointer to char) rather than the std::string type. This is because the C++ string type typically relies on dynamic memory allocation, and usage of this type may also introduce additional compile-time and run-time dependencies on the C++ standard library. Using C-style strings also facilitates an infrastructure implementation supporting both C and C++.
A.3 Python Mapping
Python is an object-oriented programming language developed by the Python Software Foundation. The language has seen significant adoption by the scientific and research communities and is often used for prototyping software algorithms.
Python is an interpreted language and utilizes a dynamic type system with automatic memory management. As such, it may not be suitable for flight software environments where strict deterministic behavior is required. However, during the SDR development stages, the ability to integrate existing Python applications into an SDR may be highly useful and beneficial. This can be accomplished by mapping the STI interfaces to a Python language environment.
A.3.1 Naming Conventions
All STI infrastructure-provided functions, constants, and types shall be provided through a Python module called “STI”.
All infrastructure-provided types and methods shall be available through this module. For example, the “Instance” type is identified as “STI.Instance”, the “OK” result value constant is named “STI.OK”, the “Write” method is named “STI.Write”, and so forth.
A.3.2 Application Classes
Applications utilizing the STI infrastructure shall use the standard Python module import mechanisms to access the STI infrastructure.
All application base classes utilized with STI shall inherit from the “Instance” class provided through this module.
For example, an application would typically have an “import” statement at the beginning of the source file, followed by an application class definition.
import STI class ExampleWaveform(STI.Instance): …
After utilizing the language-specific import statement, all components of the STI API can be referenced using the paradigm of the respective language’s package/module facility. For instance, in languages such as Python, Ruby and Lua, the module contents are designated by the module name and a period (.) separator, for example the term “STI.Initialize” would refer to the Initialize function within the STI module.
A.3.3 Constructor and Destructor
The Python application module shall also provide an implementation of the APP_Instance and APP_Destroy methods, implementing a “factory” design pattern that can be invoked by the infrastructure. These are be implemented as static methods in the application class.
A.3.4 Interface Operations
Unlike C++, the methods in a Python class are dynamic and do not need to be explicitly declared at compile time. Therefore, applications do not need to inherit from an interface class as in C++. Instead, implementation of any application-provided interface method defined in section 12.5 or 12.6, Application and Device Control Interface, is simply a matter of defining a matching method within the application class.
For example, the following class definition would implement the ControllableComponent interface:
class ExampleWaveform(STI.Instance): def APP_Start(self): # Implementation-defined action… return STI.OK def APP_Stop(self): # Implementation-defined action… return STI.OK
All application-provided methods shall be class member functions of an application-defined class inheriting from some or all of these abstract interface classes.
Being a fully object-oriented language with automatic memory management, Python represents all values in software code as a logical object of some type. Unlike C and C++, the actual memory storage and representation of these objects is hidden from the developer, and there is no direct equivalent of a “pointer” type. However, Python does provide some data types that can directly deal with memory reservation and access, and these can be used to exchange data directly with C/C++ software. Since all Python objects are fundamentally self-describing, with a type and size known to the interpreter, the STI interfaces do not need to explicitly indicate size information when passing abstract buffer objects through the interface.
Python classifies certain object types as “immutable”, which include strings, integers, and other fundamental value types. Once instantiated, these values can never be modified; instead, a new, distinct value object will be created, and the previous object can be destroyed. On the other hand, aggregate types such as classes, dictionaries, and lists are “mutable”, meaning that the content can be modified after instantiation. Some fundamental objects have both mutable and immutable variants (e.g. byte/bytearray, frozenset/set, etc.). When translating from IDL, immutable types can only be used to implement “in” or “return” parameter values from an operation definition. Parameters designated as “out” or “inout” will only use mutable types.
Table 5, Infrastructure-provided Data Types, in section 12.4 indicates the general semantics of each STI-defined type. These general semantics, in turn, define the expected mutability of a value of the given type, and therefore its applicability to IDL-defined operations.
Table 94: Python Language Data Type Mapping
Semantics | Mutability | Python Data Type | Applicable to |
---|---|---|---|
Integer | immutable | STI.<type> | FileSize, HandleID, Nanoseconds, Offset, QueueMaxMessages, Result, Seconds, TestID, TimeRate, TimeWarp |
Enumeration | immutable | Integer, see below | Access, CalendarKind |
string | immutable | str | Object Names |
Aggregate Value | mutable | STI.TimeWarp | TimeWarp |
Abstract Object | mutable | Any object type implementing the Python “buffer protocol”, such as bytearray. | Message, PropertyValue |
Base Type | mutable | STI.Instance | Context Objects |
Note that Python does not implement enumerated data types as C/C++ do
Access enumerated values shall be implemented as integer constant named values of type Access, with each value being one more than the preceding one.
CalendarKind enumerated values shall be implemented as integer constant named values of type CalendarKind with each value being one more than the preceding one.
A.4 Perl Mapping
Only certain features have been determined to be required when software is implemented in Perl.
The STI module/package namespace for Perl shall be OMG::STI.
An example of its use is:
use OMG::STI
After utilizing the language-specific import statement, all components of the STI API can be referenced using the paradigm of the respective language’s package/module facility. For instance, in Perl, the module contents are designated by the module name and a double-colon (:) separator, for example the term “OMG::STI::Initialize()” would refer to the Initialize function within the OMG::STI package.
Perl has built-in strings but not enumerations. Enumerations are implemented as a set of constant Integer values. It is possible to implement an enumeration pragma function for this purpose. Perl does not have built-in Integer types. On those platforms without floating point hardware, using a Perl pragma to tell the compiler to use integer operations instead of floating point within the block can make a big difference in performance.
A.5 Ruby Mapping
Only certain features have been determined to be required when software is implemented in Ruby.
The STI module namespace for Ruby shall be STI.
An example of its use is:
require 'STI'
After utilizing the language-specific import statement, all components of the STI API can be referenced using the paradigm of the respective language’s package/module facility. For instance, in Ruby, the module contents are designated by the module name and a period (.) separator, for example the term “STI.Initialize()” would refer to the Initialize function within the STI module.
Ruby has built-in strings but not enumerations. Enumerations are implemented as a set of constant Integer values. These values are not considered to be Enumerable.
A.6 Java Mapping
Only certain features have been determined to be required when software is implemented in Java.
The STI module namespace for Java shall be org.omg.STI package.
An example of its use is:
import org.omg.STI.*
After utilizing the language-specific import statement, all components of the STI API can be referenced using the paradigm of the respective language’s package/module facility. For instance, in Java, the module contents are designated by the package name and a period (.) separator, for example the term “org.omg.STI.Initialize()” would refer to the Initialize function within the STI module.
Java has built-in strings and enumerations.
A.7 Lua Mapping
Only certain features have been determined to be required when software is implemented in Lua.
The STI module namespace for Lua shall be STI.
An example of its use is:
STI = require(“STI”)
After utilizing the language-specific import statement, all components of the STI API can be referenced using the paradigm of the respective language’s package/module facility. For instance, in Lua, the module contents are designated by the module name and a period (.) separator, for example the term “STI.Initialize()” would refer to the Initialize function within the STI module.
Lua has built-in strings but not enumerations. Enumerations are implemented as a set of constant Integer values.