Embedded system developers are stuck between the rock and the hard place, faced as they are with increasingly complex systems, more lines of code, more powerful processors, and the need to generate code that accurately reflects the real-time and deterministic requirements of applications such as automotive and industrial control.
On the one hand, developers need to use high-level Model Driven Development (MDD) tools, such as UML, to accurately capture the behavior and characteristics of the design environment inside, say, an automobile, in which multiple processors may be linked together to enable all elements in that environment to communicate and, when necessary, work together. On the other hand, developers must also work at the code level, usually within an integrated development environment (IDE) to generate, debug, analyze, and test the code for each element in the system.
However, very often the twain do not meet. And when they do, the linkage between the two has been problematic. The separate stand-alone MDD environments and IDEs within which they've worked have forced embedded system developers to work in either one or the other with no substantive interaction between the two “worlds.”
In cases where the developer wants to work with models, if the models don't generate code that includes behavior, he faces the difficult task of writing the code in an IDE and then maintaining both the models and the code since the MDD environment and IDE are completely out of synch with each other. The link between model and code inevitably would be broken; the model information would lose its value as the code changed because most likely the developer would not update the model to reflect the code changes.
Early MDD solutions that did generate code produced black-box code, which is unreadable and offers very little code-level control. Getting the black-box code to look right and operate as intended was nearly a “black art,” and if the user could change the code, the model and the code would be out of synch, leading to a major maintenance issue. This lack of control and synchronization of the model and code reduced the value of modeling throughout the development lifecycle.
By incorporating bidirectional linkage between an Eclipse IDE-based code-centric workflow and an MDD model-centric workflow, engineers can work within the familiar code-level IDE and within the same framework use modeling. In addition to easing the learning curve for embedded system developers now reluctant to incorporate model-driven tools into their work flow, the linkage also provides a number of powerful capabilities, including:
• Reverse engineering of existing code into a graphical model;
• Round tripping of changes made to the code at the IDE level being developed back into the model;
• Automatic generation of new code from the model;
• Synchronizing of changes to either the code or the model through the Dynamic Model Code Associativity (DMCA); and
• Ensured code respect; that is, when code is reverse engineered or round-tripped and then regenerated, the user has the option in a bidirectional environment of maintaining the original file structure and naming of the files while also not changing the internal flow, structure, and naming of the code itself.
This combination of capabilities made possible by the bidirectional linkage is particularly effective when challenges arise in meeting the project requirements for the code. By working in the Eclipse IDE to write or modify the code and having the changes automatically appear in the MDD environment, users can ensure that algorithms meet special characteristics including timing, safety, and security. This also is a benefit in situations where the size of the code is of concern or direct interaction with the hardware is required. Additionally, a scenario where the existing code must be included in the project, such as a wish to reuse legacy code or a need to integrate third-party code, the combined Eclipse IDE and MDD environment is a powerful tool.
Graphically modeling the project allows engineers and developers to abstract away from the code, to clearly see how all the elements of the project operate together. With the ability to simulate the model and the code on the host computer during the development process, rooting out problems is done quickly at the beginning of the process, when the costs and time needed to fix these issues is at a minimum.
Additionally, this enables development and testing to begin on the host before the target hardware is available. By automatically generating the code for a majority of the new capabilities and reverse engineering any existing code into the model, engineers can shorten the development time through automation. Perhaps the most valuable feature is the self-documenting workflow. The ability to generate designs of the code being developed makes design intent much clearer to all.
Code visualization and bidirectionality
Conventional wisdom says that jumping into a software development project already underway is not the time to change workflow approaches. This wisdom holds true for most design environments, but the ability to function bidirectionally either in a code- or model-centric approach with a transparency to either process challenges this thinking.
When developers are able to use code-visualization tools to graphically show the structure and architecture of their code using reverse engineering and still continue to work in their existing environment, suddenly adopting a model-centric workflow midstream is not nearly the disruptive force it used to be. In an MDD environment using tight synchronization between the code and the model, the developer can continue developing code or move to the model level, reusing legacy code with better understanding of its functionality through visualization.
Applications that may have been developed over many years may be rather large, sometimes reaching millions of lines of code. The optimal approach to effectively reverse engineer a large code base is to reverse engineer smaller portions of the code in an iterative fashion. A large application is generally structured in a modular fashion; reverse engineering should be approached at one module at a time.
For example, Figure 1 shows how code for a mobile handset could be represented visually in a UML class diagram.
The diagram shows the dependencies between the files and from this the structure of the application can be visualized. The code to reverse engineer is mapped into corresponding constructs defined in UML. In this example, a profile tailoring UML for the C developer is used to map the code to files, functions and data, which are much more intuitive for the C developer.
With the ability to visualize external code into an ongoing project, today's powerful MDD environments are the time- and labor-saving techniques that developers need to meet tight schedules. Developers can reuse code from other projects, and integrate code developed by third-party providers. In addition, code generated in other tools is no longer a problem, because the MDD environment is tool agnostic and accepts code from other tools. Now this code can be viewed externally, providing an easy reference from the model. In addition, code visualization enables developers to graphically visualize their intellectual property (IP).
This bidirectional process enables developers to seamlessly exchange between model and handwritten code; moreover, the legacy code can be automatically reverse engineered to become part of the model. The net effect is that visualizing the code clarifies the structure and architecture of the application, accelerating the team's ability to deliver applications on time and clearly communicate designs amongst each other.
Should implementation across a widespread project prove too much, another approach that can be taken is to adopt MDD for a new portion of the design. In this case the code being developed (or that may already exist for the rest of the application) can be reverse engineered into the model as an external reference.
This provides the developer the ability to visualize how the new functionality being created in the model is interacting with the other parts of the applica- tion, and the modeler can easily reference this code from within the model.
Figure 2 shows how the new functionality being created in the model for a Bluetooth Reader and Bluetooth Writer can be shown working with the other code being developed for the application.
The modeler can see the content of the external code from within the modeling environment and can easily leverage the functionality provided by the MDD environment.
This same concept can also apply to third-party libraries, too. In addition, common interfaces to libraries, such as studio library, can be added as external references in the modeling environment enabling the developer to see where third-party libraries are used within the application.
Documentation, a necessary but typically painful and slow task, is usually not in step with the latest code design, which can lead to many problems. These problems arise when a developer reuses the existing code, expecting a certain behavior based on out-of-date documentation. This may be as simple as compiler errors that are uncovered early in the development cycle, but in the worst case subtle incorrect behavior may be implemented that may not be uncovered until late in the development cycle resulting in product delays.
A bidirectional IDE/MDD framework offers developers the benefit of automatic documentation, keeping the design and the code in synch with DMCA. Reducing the learning curve and increasing effectiveness by working at either the code or model level makes a bidirectional workflow possible by enabling the developer to change one view and have all the other views change automatically. Since this happens automatically, the developer need not change the way he wishes to work: the workflow environment works the way he does, at either the model or the code level. As the work environment automatically documents the design, the code and the documentation are always up to date, enabling embedded and real-time development projects to move in any direction the team needs to go.
For example, Figure 3 shows a snippet of code for a temperature sensor and a representation of the code in an MDD environment.
We may want to perform some refactoring in the code, renaming the data variable to clarify the purpose of the variable like temp for temperature and change the name of the operation to reflect reading the temperature variable.
Once we're done with the edits from within the Eclipse editor and save the code, the modeling environment automatically detects the change and automatically updates the model to reflect the changes in the code. Figure 4 shows that the variable is now visible in the model and the operation name changed.
The code and the documentation in the model remain in synch. It's important to note that making changes such as these get reflected in all references to the effected element within the model, in other words, all diagrams that show the attribute are updated to reflect the change. In a similar fashion, performing an edit of the model is also reflected in code. Keeping both the model and code in synch ensures that your documentation represented in the model accurately reflects the actual implementation.
Working in a totally integrated environment
By integrating design (MDD), development (IDE), and deployment (RTOS and middleware) into one seamless, bidirectional workflow environment, both systems and software engineers have a common framework that includes all phases of development in one tightly integrated tool chain.
Rather than using a traditional “waterfall” approach where separate processes are used for different aspects of development–for example, separating requirements analysis through design from the implementation through deployment process–now a tight, iterative model-based approach can be used to rapidly construct and respond to requirements changes throughout the development process.
The MDD tools within this bidirectional environment can then generate production quality C, C++, Java, and Ada source code automatically from the UML models, which can be fed into the IDE's C/C++, Java, and Ada compilers, and the object code then transferred to the target.
The developer can then take programs running on the target, set breakpoints on the graphics in the modeling environment, and have the program stop at the same point in the IDE's source-level debugger. Working from the other direction, a developer can load and debug the code in the IDE environment and set break points as well.
The modeling environment will highlight the graphical diagrams that correspond with the breakpoints, allowing a seamless, bidirectional workflow in a clearly understood environment that's most natural to the user's development process. The resulting debugged application is then downloaded and deployed on the target through the IDE.
Now the models, from which the code was generated, are linked to the executable enabling run-time analysis and debug. Lastly, any changes made in the model or code is automatically synchronized, ensuring that the design and the code are always in step with each other.
Paul Urban is senior marketing manager at Telelogic, an IBM company. He has over 20 years experience in the embedded and real-time systems industry in a wide range of roles from developer, technical lead, consultant, trainer, and customer support. Currently, he works with customers to develop software and systems Model Driven Development tools and methods. Paul has a BS in computer and systems engineering from Rensselaer Polytechnic Institute. He may be reached at email@example.com.