This document provides an overview of the range of options available in PathMATE to integrate non-modeled C and C++ code, types and components with your PI-MDD modeled systems, and also to provide usage key details on these features.
2. Table Of Contents
1. Introduction .......................................................................................... 1
2. Basics.................................................................................................... 1
PI-MDD Models are Separate from Code – On Purpose.................................. 1
PI-MDD Models are Generally Preferred To Handwritten Code ........................ 2
But Not Always… ..................................................................................... 2
3. Realized Code Outside Modeled Domains .............................................. 2
Realized Scalar Types .............................................................................. 2
Advanced Realized Types ......................................................................... 3
4. Realized Domains.................................................................................. 4
Handwritten <domain>_services_REALIZED.cpp ......................................... 5
Derived Services - InlineCode ................................................................... 5
5. Hybrid Domains..................................................................................... 5
Limitations of Standard Realized Domains................................................... 6
Hybrid or Green Domains ......................................................................... 6
The Dangers of #INLINING....................................................................... 6
When to go Hybrid .................................................................................. 7
ii
3. Blending Realized Code with PI-MDD Models
1. Introduction
This document provides an overview of the range of options available in PathMATE to
integrate non-modeled C and C++ code, types and components with your PI-MDD
modeled systems, and also to provide usage key details on these features.
Integrating modeled systems with external non-modeled elements is a universal and
natural element in building PathMATE systems in real-world settings. Legacy code,
components from third party developers and other external sources, and code
generated from non-PathMATE technologies are all part of the real-world landscape
for any complex system, and a universal reality of the vast majority of projects that
we build PI-MDD systems in.
It is assumed the reader is familiar with PI-MDD modeling including generating code
and the use of model element markings, and with implementation-level
programming.
2. Basics
PI-MDD Models are Separate from Code – On Purpose
Platform-Independent Model Driven Development (PI-MDD) is a methodology where
executable UML models are constructed with an explicit focus on the problem space
subject matter, as opposed to the implementation details of how code runs on a
specific target platform. To facilitate this focus a UML-level Action Language is used
for detailed behavioral specification for model actions. PI-MDD models - including
Actions – generate code that runs on a UML virtual machine layer. High-
performance and embedded system use sophisticated self optimization code
generation and tightly configured virtual machines targeted to specific deployment
platforms. This separation of the problem-space models from the details of how to
run reliably and efficiently on a specific platform yields some critical strategic-level
benefits:
Much shorter time to market and higher productivity
The focus on the problem space results in a system with much higher
concept-to-code fidelity, producing a simply better product
The models in particular and the system overall are far simpler, making them
easier to create, debug, deploy and maintain
The discipline of separation results in far stronger modularity, and greater
reuse
1
4. Blending Realized Code with PI-MDD Models
The ability to move quickly to new deployment platforms, including dramatic
variations in multi-task and multi-processor topologies.
PI-MDD Models are Generally Preferred To Handwritten
Code
In short, PI-MDD models are good because they give us Faster, Cheaper and Better
systems. So we should model all of our systems in order to get more of this
goodness – right? Well … not always.
But Not Always…
PI-MDD Models are not always the best way to address all software needs on a
complex system. Sometimes there are large bodies of legacy code that are
sufficiently functional and provide a large base to start from. Sometimes code is
generated from specialty environments. Sometimes other parts of our team produce
code by hand and don’t use models. Sometimes a specific part of our system is
awkward to implement in PI-MDD UML and better addressed by the implementation
code level of abstraction. Often, there simply isn’t enough time to model all the
parts of the system that we’d like to.
What that all adds up to is the need to be able to integrate realized (non-modeled)
code with the modeled parts of our system. The purpose of the techniques and
mechanisms outlines in the document are to provide the flexibility needed to
integrate implementation-code elements with modeled system.
3. Realized Code Outside Modeled Domains
Realized Scalar Types
Likely the first contact modelers have with realized code elements comes in the form
of a user-defined data type visible in the model, but with an actual implementation
specified at the code level. First let’s consider a simple alias type for a scalar value.
Assume the existence of a SensorInterface domain that publishes a user-defined
type si_temperature_t “A temperature value in degrees centigrade, ranging from -
100C to 350C”. At the model level we specify the base type for this is Integer.
Specifically this means that then things in the model work with and manipulate data
atoms if this type it will be treated like an Integer. By default a typedef statement
will be generated for this:
typedef int si_temperature_t;
2
5. Blending Realized Code with PI-MDD Models
Let’s assume we don’t want si_temperature_t to be an int, instead let’s use a
legacy type definition standard in Our Company: ourco_uint16. To accomplish this
we apply the ExternalType marking:
UserNonEnumerate,MySys.SensorInterface.si_temperature_t,ExternalType,ourco_uint16
Now PathMATE generates this for us:
typedef ourco_uint16 si_temperature_t;
But where is OURCO_UINT_16 defined? Let’s say it’s defined in ourco_base_types.h.
If there are lots of other things we want to use in there, we can manually add an
include for this file to our system-wide includes file, c/system/sys_incl.h, or
cpp/system/sys_incl.hpp.
Alternatively if we have an include file that we only want to include where this
specific type is used – say uint16.h – then we can use the IncludeFile marking to
specify this:
UserNonEnumerate,MySys.SensorInterface.si_temperature_t,IncludeFile,uint16.h
This causes PathMATE to generate an include of this file at the top of each generated
module that contains a data atom of the si_temperature_t type. In any of
SensorInterface’s client domains we can declare data atoms like attributes,
parameters or variables to be of type si_temperature_t and they will be of the
appropriate type – ourco_unit16 – at the implementation code level with the correct
include where it is needed.
Advanced Realized Types
Assume another realized type, but this one is structure defined in sens_ramp.h:
/* Legacy type used by sensor library to scale raw sensor input
values. */
struct Sensor_ValueRamp
{
ourco_uint8 sensorId; /* Sensor channel this ramp is
calibrated for */
ourco_real32 rampSlope; /* Slope of adjustment line */
ourco_real32 rampBottom; /* Lowest valid value */
ourco_real32 rampTop; /* Highest valid value */
};
The SensorInterface domain publishes a user-defined type si_sensor_value_ramp_t
at the model level with a base type of Handle. This means PathMATE treats this
essentially like a void*. This type we also mark with ExternalType and IncludeFile:
3
6. Blending Realized Code with PI-MDD Models
UserNonEnumerate,MySys.SensorInterface.si_sensor_value_ramp_t,ExternalType,Sensor_ValueRamp*
UserNonEnumerate,MySys.SensorInterface.si_sensor_value_ramp_t IncludeFile,sens_ramp.h
Typically Realized Complex Types are used to provide modeled client domains with a
handle to a resource that they will use via services of the providing realized domain.
For example SensorInterface publishes the following services:
si_sensor_value_ramp_t GetChannelDataConditioner(<some selector
inputs>);
An old school traditional C programmer may wonder how a modeled client domain
gets at the Sensor_ValueRamp members? Their first inclination may be to have the
“client” function grab a Sensor_ValueRamp and then intimately condition its own
values by directly using the rampSlope, rampTop and rampBottom. Other client
functions using sensor input may similarly perform raw value conditioning. Clever
programmers may clone these bits. But all this cloning is bad – very bad for many
reasons. And through this intimacy the client functions become tightly coupled to
the SensorInterface domain. Also bad.
With PI-MDD the discipline of domain separations saves us from these potentially
mortal dangers. By allowing the SensorInterface domain retain exclusive
responsibility for the details of sensor raw value conditioning including the knowledge
of the makeup of the si_sensor_value_ramp_t, we can keep the Sensor_ValueRamp
from being exposed to the client domains. They do not need to know the details of
the ramp structure, or how to apply it to get a conditioned value. This valuable and
useful nugget is captured in this SensorInterface service:
si_temperature_t GetConditionedValue (si_raw_value_t raw_value,
si_sensor_value_ramp_t ramp_handle);
The modeled client simply passes the ramp_handle into GetConditionedValue. The
realized SensorInterface domain accesses the members of Sensor_ValueRamp. In
this manner the clients of SensorInterface are not tightly coupled via the shared
knowledge of the details of Sensor_ValueRamp. Cloning is avoided, and integration
fire drills consuming Saturdays are minimized.
4. Realized Domains
As implied in the previous sections, SensorInterface is a realized domain. That
means that the types () and services () it publishes are visible to the model, the
remainder of the domain exists only in the realm of implementation code. The
implementation of the domain services are handwritten code, which may call into
legacy libraries, external or COTS functions – anywhere, really.
4
7. Blending Realized Code with PI-MDD Models
Handwritten <domain>_services_REALIZED.cpp
The most straightforward genesis and organization of a realized domain follows these
steps:
Define all types used in domain service parameters or return values in the
model
Define all domain services and parameters in the model
Generate code
Copy the generated <domain>_services.cpp (or .c) file to a realized code
folder for the domain, and rename it to <domain>_services_REALIZED.cpp
(or .c)
Hand-edit the copied <domain>_services_REALIZED.cpp (or .c) file to add
domain services implementations. For services with complex implementation
it is recommended that a thin wrapper approach be applied, where the service
implementation calls external modules to complete the service behavior.
Derived Services - InlineCode
Where the handwritten <domain>_services_REALIZED.cpp approach generates
actual function/method calls that resolve to functions/methods, the Derived Service
approach uses something more like a C macro. Code transformation maps support
the specification of domain service implementations via directly emitting the desired
code in place of the invocation. The expansion of a derived service is specified in a
marking for the service – InlineCode. The value specified for the InlineCode marking
is the actual code to be substituted for the service invocation.
To make service parameters conveniently available, they via numeric reference: $n$,
where n is the number of the ordinal parameter (1-based). For example, presume a
domain service GG:ComputeDistance(x, y) is marked:
DomainService,MySys.GG.ComputeDistance,InlineCode,sqrt($1$**2 + $2$**2)
The PAL dist = GG:ComputeDistance(x_coord, y_coord); would generate:
dist = sqrt(x_coord**2 + y_coord**2);
5. Hybrid Domains
5
8. Blending Realized Code with PI-MDD Models
Limitations of Standard Realized Domains
Considered generally, a realized domain with handwritten services is actually a
hybrid domain, where types, services and parameters are modeled and the rest is
handwritten. This pattern is valuable, especially for organizations new to PI-MDD
because it provides clear boundaries for the modeler/coder.
However realizing a domain means the power and convenience of modeling cannot
be applied. The flexibility and longevity of Platform Independence are more elusive
to achieve. The addition of a realized domain to resolve limitations in PAL or PI-MDD
may also distort the architectural perspective, adding a domain where there was no
separate subject matter.
Hybrid or Green Domains
A Hybrid Domain is a modeled domain with one or more #INLINE sections in its
actions. The #INLINE preprocessing directive for PAL (and it’s partner
#END_INLINE) is used to escape to the implementation code level. Consider the PAL
segment:
Handle my_reg;
#INLINE
my_reg = &BASE_LOAD_REGISTER;
#END_INLINE
HardwareMonitoring:Load(my_reg);
This would generate (in C++):
void* my_reg;
my_reg = &BASE_LOAD_REGISTER;
HardwareMonitoring::Load(my_reg);
The Dangers of #INLINING
Escaping to implementation code seems like a convenient way to cast off all the
limitations of UML and PAL. This can be compelling, especially for beginners to PI-
MDD that may not know PAL very well but may be very familiar with C. However the
constraints imposed by PI-MDD help avoid common coding pitfalls and provide a
foundation for automation to help with challenging hurdles. Using #INLINE discards
these key benefits provided by PI-MDD disciplines and automation:
Assures platform-independent system, with flexible deployment to test
topologies and multiple target architectures
Provides flexibility in applying implementation optimizations – even after the
model is complete and tested
6
9. Blending Realized Code with PI-MDD Models
Automated verification of the integrity between model elements and where
they are used in actions
Guaranteed conformance to domain boundaries
Prevents unwanted code patterns
Project experience has shown that indiscriminant use of the #INLINE
feature substantially impacts system quality, flexibility, maintainability and
run-time performance.
When to go Hybrid
As a general rule all newly constructed domains should be modeled. When a
modeled domain contains actions where a portion of the action requires
implementation code then the limited use of #INLINE should be considered.
When creating a hybrid action, the core requirements for creating any modeled
actions still apply:
Clear, concise, and appropriate for the action context
Platform independent
Understandable, maintainable
Rules for Going Green:
Ultimately the action needs to deliver high quality, including within the inline portion.
The following guidelines can help Hybrid domains retain the value of the PI-MDD
approach:
Limit the extent of the inline section. Do as much in PAL as possible.
Use bitwise PAL operators (same as C) to avoid inline – but ensure these are
platform independent
In all code be endian independent
Strive for platform independent code in the inlined implementation code
section.
If your action requires platform-specific, endian-specific, or other non-portable
constructs, do not use #INLINE. Instead use a Standard Realized Domain to fully
isolate this code in a separate module.
7