Skip to content

Operations

Operations in UML2 are usually part of classes, as such the code generation works as follows. For methods, a parameter is inserted which should point to an instance of the generated C structure. The default name of this parameter is me (in C++, the object orientation support of the language is used, so this reference is called this). For method calls in activity or state machine diagrams, this parameter is automatically assigned to me. For details how the name of an operation is generated, see the Naming chapter. For static operations (functions), there is no such automatic parameter introduction. Find out more about Static Operations! For singletons, the situation is similar. Find out more about Singletons!

Naming

Naming of Operations is a very important topic for C-Code generation, especially if you use the generated code from hand-written code.

Keep the following simple rules in mind, and you won't have any problems with operation naming:

  • If a method is defined by an interface (either directly, or because it's part of the realization of an interface), the method name will not be altered.
  • If the class has the Stereotype - executable entry point and the classifier behavior points to the method, the method name will not be altered.
  • Otherwise, the method name will be prepended by the class name and an underscore, e.g. ClassName_MethodName.

If you need a method to have the same name in C as in UML, you can just create an interface and "realize" it via a realization Dependency. It's good practice that if you depend on a name, it should be defined in an interface.

ClassName Prefix

You can use the model setting Suppress operation prefix to generate operations without the ClassName prefix.

Parameters

Parameters can also be augmented with properties allowed by UML, Stereotypes and/or Tagged Values, but one of the most common issue regarding Parameters is on how to set pointers, constants and types and all their combinations, with all their different meanings.

Stackoverflow: Difference between const int, int const and const int pointer,...

We think the currently best/fastest/easiest solution to this issue is to use the a Primitive Element to set its name to any one of the needed combination and use this Primitive Element as the type for the Parameter.

Call Chain

For operation calls, the code generator tries to resolve the value of the parameters in the order of the call chain.

What is a call chain?

It's a succession of calls where one behavior just calls another which calls another and so on. The first behavior of a call chain is the caller, and the last behavior is the behavior for which code will be generated (the intermediate behaviors are not visible in the generated code), the callee.

Parameters must have the same name in every part of the call chain; the value can be defined by specifying the Default Value for that parameter, or by using parameter nodes in activities. If a parameters value is defined more than once in the call chain, the first definition is used and subsequent ones are ignored.

To define parameters for transition effects, where the effect is a behavior, the effect must either be written literally as code or an intermediate behavior without parameters must be introduced where you can define the parameter values.

Parameter Containment

When modeling operations for classes the containment of a parameter can be set by setting the Direction to inout.

Direction

This can also be achieved by adding a ReferenceType tagged value with the prefered reference type to the parameter. The ReferencType tagged value can also be used to overwrite/change the reference type generated by the inout Direction.

Direction

Static Operations

Static operations get a special treatment in Embedded Engineer. While the generated code will be very similar to that of methods, keep the following differences in mind:

  • Static operations have no access to an instance of the class they're defined in. There might not even be an instance if they are part of a static class.
  • When you define static operations in singleton classes, you also don't have access to the instance.

Initialization Code

You can define an initialization method by giving an operation in your class the stereotype constructor. If you do so, the method will be generated as usual, but it will also contain code to initialize the state machines and the default values of the class attributes.

Function Preambles

To fully define a function, it is sometimes neccessary to add code in front of the function implementation. For example, if you want to define an interrupt handler, you might need to add a #pragma directive or other macro invocation in front of the function. If you want to add such a preamble, add the FunctionPreamble tagged value to your operation. The text you add there will be written directly in front of the generated function implementation. You can also do this with the help of the Toolbox.

Direction

This will result in the following code (given that the return type is void, there are no parameters, and the operation is static):

#pragma vector=TIMER0_A0_VECTOR
__interrupt void HandleTimerInterrupt(void)
{
}

Warning

What you define in the FunctionPreamble is written directly before the operation to enable the common use cases. Please take care when using this functionality and check that your FunctionPreamble is defined correctly.

Behavior

You can add behavior to an operation in two different ways:

  • By adding verbatim code to an operation, which is inserted in the generated method body. This will result in a function which contains the code you type in the field Initial Code (check your Model Setting User Code storage field). No code will be added after your code, but the code generator might insert code neccessary to support the singleton pattern in front of the user supplied code.

Behavior Code

  • By referencing an activity which will be called when the operation is called. This will result in a function which calls the supplied activity. If the activity has a return type, and this type corresponds to the return type of the operation, a return statement will be added and therefore the return value will be propagated to the caller.

Behavior Element

  • Adding a behavior in the Method property of the operation.

Method

  • When clicking on the "edit" button you can either select or create a new behavior.

Method

  • Supported behavior types:
    • OpaqueBehavior
    • FunctionBehavior
    • Activities

Warning

If multiple behaviors are defined only the first will be selected by the Code generation.

Function pointer

To generate a function pointer, multiple elements need to be generated and linked

  1. Generate a type definition for the function pointer
    1. Create an operation
    2. Add parameters
    3. Add the stereotype typedef
  2. Generate a function pointer Type
    1. Create a DataType element
    2. Add the fncPointer Stereotype
    3. Set the Signature Tagged Value to reference the typedef Operation from step 1.
  3. Now you can use the new DataType to define a function pointer for e.g.: an Attribute or a Parameter

Warning

We updated the way to define a function pointer with features other than only Attributes.

The "old way" using the FunctionPointer Stereotype is deprecated and will result in a code generation warning.

Function Pointer

Generated code

/* Operation 'FncPointerDefinition' of class 'Class1' */
typedef void (*FncPointerDefinition)(int, byte, char);

typedef struct Class1Struct
{
    FncPointerDefinition FncPointerAttr;
} Class1;