We’re here to help you

Menu

Dezyne Hello World: Turning an LED On and Off

Language keywords: behaviour component import in interface on provides void

In this section we build a near-minimal Dezyne model in which one component presents one interface.

The simplest possible valid Dezyne model consists of one component that presents no interface to its outside environment.

Step 1. Create a new Dezyne model by entering or copy-pasting the below two lines of model code into a new file in the Dezyne editor (in Eclipse: File / New / Dezyne Model File)

component LED {
}

You can copy and paste any code sample in this tutorial directly into the Dezyne editor. Most Dezyne language keywords are displayed like this in the Dezyne editor and in the tutorial code samples; a few special keywords including “enum” are colored blue. You can position curly-brackets exactly as in C/C++/Java: at the end of the line, on the next line, and so forth.

Step 2. Verify this model (in Eclipse: the double-arrow green toolbar icon (image).

Dezyne will respond that no component in the model has behaviour, therefore there’s nothing yet to verify.

Step 3. Add a minimum behaviour block as below. In each code sample, added or changed lines of code from the previous sample will be highlighted like this.

component LED {
  behaviour {
  }
}

In Eclipse a small red symbol appears, indicating invalid syntax and/or semantics; moving the cursor over the symbol brings up the below information.

image

A well-formed, verifiable Dezyne component presents (provides) at least one defined interface to its environment, and at least one of its presented/provided interfaces has to define one or more trigger events accessible from outside as callable functions.

Step 4. Remove the behaviour {} block from the component for now. We will add it back later.

Step 5. Enter or copy-paste the new code in the below model into the Dezyne editor. This code defines a simple interface through which a caller can turn on and turn off an LED through synchronous void function calls to the providing component. The component provides (implements) this interface. Note that commenting in Dezyne works exactly as in C/C++/C#/Java.

interface ILED {
  in void turnOn();
  in void turnOff();

  behaviour {
    on turnOn: {}
    on turnOff: {}
  }
}
component LED {
   provides ILED iLed; // removed the component's behaviour block for now
}

Step 6. Verify your copy of the above model code (image) and study the following paragraphs.

The LED component is now well-formed: it has instanced a defined interface, ILED, and we have verified that it and its interface have no bugs or other problems.

An instanced interface is known as a “port” in Dezyne; each port must have a unique name (here “iLed”) within the providing component. The term “port” is not a keyword in the Dezyne modeling language.

You may have noticed that keywords and user-defined names in Dezyne are case-sensitive. You will need to select your own conventions for naming things; in this tutorial we prefix each interface name with a capital “I” and each instance of an interface with a lower-case “i”. Dezyne requires that user-defined names contain only letters, digits and the underscore character ‘_’, and that the leading character in a name is not a digit.

In the above, by not defining any behaviour inside the component, we are asserting that the outside world needs to know only that the component supports void functions named “turnOn” and “turnOff”, and that the component will quietly and correctly do its work whenever triggered by an input event, i.e. whenever one of the functions is called. This behaviourless feature turns out to be important in practice: you can use it for placeholder model components for which you will write all C/C++ source code manually, and for which you will not use automatically-generated C/C++ source coming out of the Dezyne model. For example, you might write hardware or communications abstraction components manually. In Dezyne, a component with no defined behaviour is sometimes called “hand-written”.

To “verify” in Dezyne means to trace every possible execution sequence through a component model, and to stop and report the first occurrence of a problem – either a mismatch between a providing component’s actual functional behaviour versus its contracted functional behaviour, or a non-deterministic behaviour such as an overlapping guard or unmanaged race condition, or an unhandled event, or some other issue. If no problem is found, then the model has been verified. In the Eclipse editor, if a verification problem was found, then it is reported as the entire sequence of trace steps that led to it.

Note that, by definition, a verified interface’s externally visible functional behaviour exactly matches a verified providing component’s externally visible functional behaviour for that interface. Verification proceeds through exhaustive stimulus-response of a component’s provided functions, using the applicable interface definition to decide if the providing component’s responses are complete and correct. A providing component, however, can also optionally contain additional non-visible internal behaviour that extends and refines its responses to events. And a given interface can have any number of providing components in a Dezyne project. We will revisit these matters later.

Step 7. Create a new file named “ILED.dzn”, move the ILED interface code into it, and delete the ILED interface code from the model. Add a new import line to your original file as follows:

import ILED.dzn;

component LED {
  provides ILED iLed;   // removed the component's behaviour block for now
}

You can import any number of files in any order into a Dezyne file. All imports must precede other non-comment/non-whitespace contents in the file.

Step 8. Enter or copy-paste the component behaviour as shown in the code sample below. Observe the parentheses () in the component’s added code, which differ from the parallel declarations in the interface definition. Remember that if a component defines behaviour for a called function, that behaviour must exactly match the interface’s defined behaviour as seen through function calls and only in that sense. In practice, you would replicate the exact interface behaviour in the component only if you plan to refine and extend the component’s own internal management in response to events. Notice also that the component’s function names are qualified with the port name, i.e. the interface instance’s name.

import ILED.dzn;
component LED {
  provides ILED iLed;   /* "provides" means implements ILED functions */

  behaviour {
    on iLed.turnOn(): {}    // qualify funcs w/interface *instance* (port) name
    on iLed.turnOff(): {}
  }
}

Step 9. Verify the model. Then, simulate interface ILED and component LED via the Eclipse toolbar icon image, which initiates traces with events. Be sure the Eclipse Sequence View is on (menu Window / Show View / Sequence View) as well as the Trace View and Watch View.

Step 10. Experiment with the Sequence Diagram view: select Next Events (“eligible events”) one by one to build up a trace, then click on transitions in the diagram and see how the corresponding code is automatically highlighted. In the below Eclipse screen shot, the turnOff call was clicked in the diagram, highlighting its source to the left:

image

The above screen shot shows the Dezyne console output. Every verification and simulation step executes through the console command-line interface to access the Dezyne server. Enter “dzn -h” at the command prompt at the bottom for a summary of the commands.

image

Look also at the Verify Results tab contents, shown below, to see the categories of model verification. You can search the Dezyne help for details about these.

Notice the differences between verifying versus simulating. Simulation enables interactive exploration and explanation of the detailed interface protocol – a powerful way of communicating to other people about how an interface and its implementing component(s) function.

Step 11. You can generate this component’s C or C++ source code via Eclipse’s toolbar icon image and view it. Future tutorial sections will discuss generated source code and how to integrate with it.

The generated source as seen in the sandbox comprises 100 to 200 lines of compilable code not counting whitespace, comments, or lines consisting of only a curly-bracket. Most of the source for this small example is generic to any Dezyne-generated code. In practice, you would rarely change automatically generated code; instead, you would modify only code that supports it or interacts with it. In this way you guarantee not introducing subtle bugs into your system, and you greatly simplify matters when refactoring or adding new features later.

That’s all! We’ve created and verified our first system model. Well, not quite, only our first verifiable and verified component model and its source code. Next we’ll build our first system.

Before moving on, consider the following. In the model so far, we could have used just one function that toggles the light on and off. Why didn’t we? In this case, because we want users/callers of the LED controller to know what the light’s state is – on or off – after sending a control command to the light. If the only control was a toggle, then even in a single-threaded system a caller would have to manage initialization and perhaps poll to know the light’s current state for sure. In a multi-threaded system the light could receive a toggle from anyone any time, and polling would likely be essential. In later sections we’ll return to these and other related matters.

The Efficiency of Code-Like Dezyne Models for States and Communications Logic.

In Dezyne, you define components and their interfaces through a familiar and compact C/Java-like language, then automatically verify the completeness and syntactical correctness of your logic, and then exercise sequence diagrams to check that the coded behaviour is what you intended. Contrast this with going in the opposite direction: you’d whiteboard a sequence diagram or draw it in a graphics editor, converge on the behaviour you seek, write the code, compile and link it, and then try to test the code to ensure it’s working properly. With Dezyne, you direct the machine to test your logic and generate interactive visualizations of the behaviour. The Dezyne approach, once mastered, is dramatically more efficient, and that efficiency translates to dramatic savings across entire projects – and with no subtle logical bugs, such as race conditions or deadlocks or livelocks, in states-and-communications logic

If you have questions that weren’t answered by this Guide,
let our support team help you out.

Enjoy this article? Don't forget to share.