Modelling for full code generation within the automotive industry
Since the introduction of Assembler, higher abstraction levels of programming languages have led to better productivity in software development. The improvements in raising abstraction – and therefore productivity – by newer programming languages, however, are relatively modest. Currently, a programming language’s contribution to productivity seems focused on providing libraries and frameworks, while over the past 20years the mechanism for raising abstraction has shifted from programming to modelling languages.
Most mainstream modelling languages, such as UML, focus on visualising the code and therefore fail to provide a significant improvement in overall productivity when compared to coding in C, C++ or Java. Furthermore, the modelling tools that support these languages are constructed in such a way that the code generated from these models consistently requires manual completion. This further reduces the already modest productivity benefits afforded by this approach.
Here, we provide an alternative approach to modelling and code generation, called Domain-Specific Modelling (DSM), which allows for full code generation from higher abstraction models. A key element of its success is the focus of the models on the application domain, rather than abstractions of software construction mechanisms.
Since it is possible to include the rules of the problem domain into the language as constraints, the opportunity to specify illegal or unwanted design models can be eliminated. In nearly every case where companies apply this approach on top of a platform or framework, they can automatically generate complete final products from the high-level specification models. This is possible because both the modelling language and the code generator are designed to fit only one problem domain and its implementation space. Since the experienced developers in a company specify the languages and code generators (Fig.1) the resulting code is better than most application developers write by hand.
To demonstrate the strength of DSM, we present a brief example of an automotive software development project: a controller unit for windscreen wipers. We focus on the language definition and generator creation and thus to the expert developer’s role. The microcontroller is an AVR128 8-Bit RISC processor with 128KB data flash and 4KBSRAM. The software running on this controller consists of the PURE operating system, a generic hardware abstraction layer, and several C++ classes that are to be generated. Beyond the microcontroller, this system comprises a combination switch, an ignition key, one wiper motor for each wiper, an optional rotary switch and several optional sensors (rain sensor, door open sensor, bonnet (hood) open sensor, outside temperature sensor, speed sensor). The system shall support one or two front wiper arms, and one optional rear wiper arm. The front wipers are to be installed at three possible positions (left, centre, right).
By using a domain-specific language and an accompanying framework, it becomes possible to rapidly and reliably implement these features without having to code each manually. Next we introduce domain-specific modelling (DSM) by describing how the modelling language and generator are defined for our wiper control system.
Complete code generation from models is not possible if the modelling language does not specify the problem domain adequately. Therefore, we start by defining the modelling language for the particular domain. This means identifying the domain concepts and rules relevant for specifying windscreen wiper control and its various features. The domain concepts for the language can be found from the basic system architecture and from the different services it may provide. These services are comparable to use cases from classical object-orientated analysis. For example, the service ‘Ignition off’ could lead to the response ‘Finish wiping’, an optional feature standing for the function that the moving wiper returns to its start position if the ignition is turned off. In detail, the event list comprises preconditions, requirements, in/out states, and constraints for the listed events.
Generally, these major domain concepts are mapped to modelling language objects, while others are captured as object properties, connections, sub-models or links to models in other languages. For example, the domain concept wiper is presented in the language as a modelling object. Additional attributes can be added to the modelling concepts to satisfy the specification and code generation needs. In our sample case, for example, the sensor can be selected to be a speed or a temperature sensor.
In addition to pure modelling concepts we can also detect related rules. These rules constrain the use of the language and enforce the correctness of models. For instance, in a wiper control system speed adaptation can be connected only via a bus to the main system. The type of bus (LIN, MOST, CAN) can be chosen from the list of possible bus types while connecting the speed adaptation to the main system. A further rule can specify that a speed sensor may have only one connection to a bus.
Another example from our sample case is the restriction that there has to be one or two wiper arms at the windscreen. In the case of a single wiper arm scenario, the rules require that it must be installed in the centre position. While in the dual wiper configuration, the arms could be installed in either the left and centre positions, or in the left and right positions. In the modelling language a wiper has position information that can be selected by creating the respective element (Fig.2). The language is formalised by defining its metamodel. The form of the metamodel is dependent on the DSM tool used, but at a minimum it should allow the user to define the concepts of the language, their properties, legal connections between elements of the language, model hierarchy structures and correctness rules. In all but the smallest cases, support for reuse and various model integration approaches is also essential. In this case we have used MetaCase’s MetaEdit+ tool which allows language specification and automatically provides advanced modelling tool support based on the defined metamodel.
Having defined the abstract syntax of the language we finalised it by providing a visual representation for it, usually in the form of a diagram, but occasionally as a matrix, a table, or in plain text. A good modelling language uses a notation that closely reflects the actual problem domain so that the models become easier to read, understand, check and maintain. Using UML-style rectangles for all the different concepts is analogous to trying to understand a foreign language where the only letter is A, with 20 slight variations of inflection. For our sample language we have taken the notation from the real product appearance, such as a wiper, or formed the intuitively known symbols for different sensors (like rain or speed).
Fig.2 illustrates a design using the constructed modelling language: the architecture with modules, their content and different communication buses used. With the expert created modelling language in place, other developers design the specific features by adding elements to the model. The modelling language guides in making correct designs and checks that the required information is given making full code generation possible. For example, while adding the connection to specific wipers their position information is needed and verified (one left, one right and a rear wiper). The language can also be defined to minimise the modelling work required. If a single wiper configuration is being designed, the model would automatically know that the wiper is expected to be in the central position.
The modelling language definition was not as straightforward as described here. First we constructed part of the modelling language and then immediately tested it by modelling sample applications. If the result was not satisfying (eg, allowed for the creation of illegal designs), we made the necessary corrections to the metamodel. Here tools can dramatically help us. MetaEdit+ made this language testing part agile: we were able to quickly test and learn what the language looks like in practice, and how easily it was to create and reuse models. This minimises the risk of making a poor language, or a good language created for the wrong task. Tool support for language creation also greatly assists in finding good mappings for code generation.
A code generator specifies how information is extracted from the models and transformed into code. This process depends on the modelling language as the models created form the input to the generator. A domain framework and other available libraries can make this task easier by raising the level of abstraction on the code side. In the simplest cases, each modelling symbol produces certain fixed code, including the values entered into the symbol as arguments. The generator can also generate different code depending on the values in the symbol, the relationships it has with other symbols, or other information in the model.
In our windscreen wiper example we began the implementation work by programming a specific prototype. From a certain level of complexity such a prototype is needed to implement a generator because it yields the necessary fragments of source code, enriched by task-related knowledge and experience. Based on this prototype, we divided the source code modules into generic and non-generic modules. While the latter were to be generated, the generic modules formed the hardware abstraction layer. In fact, this layer raised the level of abstraction of the other source code modules.
To implement the generator for the remaining modules we used the generator development tool HyperSenses. It provides an interactive, model-based approach to define code generators. Here, HyperSenses was coupled with MetaEdit+ by importing the appropriate metamodel and model data. For the generator’s development, the metamodel was imported into HyperSenses, as it provides a definition of the variable elements for code generation. Based on this automatically derived metamodel, so-called code patterns were defined: a fragment of prototypical source code is tagged with ‘slots’ and ‘blocks’. In the source code, slots mark variation points that are to be filled with concrete values at generation time, eg a class name. Blocks define larger pieces of code that are to be generated as a whole or not at all. This decision depends on the status ‘filled’ of contained slots as well as on specified conditions. Additionally, blocks may be nested, providing for expressing even complex dependencies between several pieces of code (Fig. 3). Slots and block conditions are defined via expressions that refer to items from the metamodel. This way the former specific source code fragments become parameterised and neutralised fragments of target code: code patterns.
Code patterns may be connected to hierarchies, according to the structure of the metamodel. In detail, one code pattern comprises one or more implementations, eg for different target languages. One hierarchy of code pattern implementations is named ‘rendering’, because it renders the model data with target code. There is one rendering defined for each code module to be generated. Together with the metamodel, they form the domain-specific generator – without the necessity to manually write the code generator. Even if a domain-specific generator has to be implemented only once for a selected domain, we have to take this matter into account: In the end it depends on the number of variants to be generated if these efforts are worthwhile.
Decreasing these efforts results in enhancing the usage area of our DSM approach.
To produce the target code for the specified concrete model the code generator is applied. On a technical level, this is performed by importing the model from MetaEdit+ into HyperSenses, followed by applying the appropriate renderings. Please note that the model already is the configuration for the code generator. No additional work is required; a single button press generates the working target code.
Concluding remarks
Domain-specific modelling only makes sense in combination with domain-specific code generation. Domain-specific models are technically included in the development cycle, becoming first-class development artifacts. In addition to the productivity gains achieved through automation, the generated code is also expected to be of a better quality than handwritten code: there are fewer bugs, and, moreover, they are easier to detect. Depending on the number of generated product variants, the efforts invested in the development of the domain-specific language and the domain-specific code generator become worthwhile. This break-even point is reached even earlier, if a comprehensive tool support for these tasks is available. n
Cord Giese is with Delta Software Technology GmbH, Schmallenburg, Germany. www.d-s-t-g.com; Dr Juha-Pekka Tolvanen is CEO of MetaCase, Jyvaskyla, Finland. www.metacase.com