miniHIL Getting Started VSCode Tutorial 
In this tutorial, you’ll develop a basic program that emulates the behavior of a "working light". A working light is a light that you would expect to see on a machine, that when lit up, indicates that the machine is operating in a certain state or "working". A common use-case for this is activating the working light after pressing a button, which is the basis of what you will be implementing in the program. You’ll be guided through this process step-by-step, with explanations of why each step is necessary, so that you gain a deeper understanding of how projects are constructed and how you can create your own!
Learning Objectives
-
To understand the basic skills required to use and navigate around the IDE. Skills covered:
-
Creating a new project
-
Using Code Snippets
-
Building and Flashing examples on the miniHIL board
-
-
To understand the basic concepts of ROOM and how to implement them in a project. Concepts covered:
-
Actors
-
Ports
-
Protocols
-
Bindings
-
State Machines
-
Services and SAP’s
-
Setup the project
The following are required for this tutorial:
-
miniHIL Extensions installed in VSCode
-
miniHIL Tools
-
Example Project
These can be downloaded from the Protos Download Site. The Quick Start for VSCode shows you how to install these components.
This tutorial assumes that C:\miniHIL is the root miniHIL folder where miniHIL Tools and the Example Project reside.
Once everything is installed, open the extracted Example Project folder in VSCode (C:\miniHIL\MiniHilProject_Examples)
Navigating the miniHIL project
Let’s first familiarize ourselves with the project structure.
Open up the ROOM model of the miniHIL platform by going to the Project Explorer view and navigating to MiniHILProject → model-user → MiniHilProject.room. Double click on MiniHilProject.room to open it. You should be greeted with something like this:
This is the main file that will contain the content of your application. While the code content in this Textual View file may appear unclear to you now, it’ll be explained later in the tutorial. A better way to understand what’s happening here, is to open up the Structural View of "Application".
There are two ways you can enter this view:
-
Select the line containing
ActorClass Application {and pressCtrl+Shift+Alt+S. -
Above
ActorClass Application {, click theOpen Structure Diagrambutton.
This is the Structural view, which provides a graphical representation of the project. The blocks inside the large rectangle are Actors, which are essentially the fundamental building blocks of miniHIL (you’ll learn about Actors and how to create them in the following steps).
During development it’s sometimes better to use this view for certain tasks such as navigating around the code and visualizing the application’s structure. For now just keep in mind that both the Textual view and the Structural view represent the same thing, so changes that are made in the Textual view will show up in the Structural view.
Go back to the textual view by clicking the MiniHilProject.room tab at the top of the editor. Sometimes you’ll want to find the declaration of a class/variable that’s declared in another library.
To find a class/variable’s declaration, either Ctrl + Click the class/variable or right click the class/variable and select Go to Definition.
Step 1 - An Introduction to Actors
This step introduces the concept of Actors, a fundamental building block in ROOM, and how they are used in miniHIL. In essence, an Actor is a representation of an object as a logical machine with defined behavior. Its structure, behavior and protocols are all defined within an element called an ActorClass.
Each step of the WorkingLight has been written as separate Actors and each of their ActorClasses can be found in MiniHilProject/tutorials/WorkingLight.room. Open this file and have a quick look at each step and how they’ve been implemented as ActorClasses.
Declaring an Actor
Now return to MiniHilProject.room. Under the main body of ActorClass Application, there should be a commented line ActorRef workingLight_Step1: Tutorial_WorkingLight_Step1. Uncomment this line and then change to the Structural View (Ctrl + Alt + Shift + S or Open Structure Diagram button). You should be able to see a new block appear representing this new ActorClass declaration!
Let’s go over what just happened. An Actor Reference (ActorRef) to the actor class Tutorial_WorkingLight_Step1 was declared and was given the name exampleActor1. It can now interact with other Actors in our project.
Now let’s take a look at the internal workings of the WorkingLight_Step1 actor. Open the WorkingLight.room by using the Project Explorer tab on the left side of the window or alternatively go to the line containing Tutorial_WorkingLight_Step1 that you just uncommented and open its declaration.
Now navigate to the line containing ActorClass Tutorial_Workinglight_Step1 and look at the ActorClass. You’ll see the 3 main components that make up an ActorClass:
Ports, Protocols and Bindings
As mentioned briefly earlier, ports are the interaction points whereby the actor can interact with elements outside of itself. They operate by following an interface description called a Protocol, which is formally defined set of incoming and outgoing messages. Each port has exactly one protocol associated with it, but many ports can share the same protocol.
Ports are also classified into two types: Standard and Conjugated. This is to address the directional nature of protocols, which is necessary for example when two actors communicate and the incoming messages for one actor are the outgoing messages for the other, and vice versa. To summarize:
This tutorial won’t cover the how to write your own protocols, however for a quick idea of how protocols are constructed take a look at the protocol declaration found at SimModelLib/model/minihil/api/onoff.room.
The ports used in this Step use this exact protocol called POnOff, which as the name suggests, provides a simple On/Off behavior. The POnOff protocol provides incoming Messages on() and off() and outgoing Message done().
The two ports, light and button, use this POnOff protocol and are defined in the Interface as well as the Structure of the workingLight_Step1 Actor. In the Interface section the Port button is a standard port, which means it can handle the incoming Messages on() and off() as incoming Messages. In the interface section the Port light is defined as a conjugated port, which means it can handle the Messages on() and off() as outgoing Messages.
These ports can also be seen visually using the structural view, as small, labelled squares contained in the actor. You can drag these around on the actor to make binding positioning easier.
Creating State Machines
Every actor in ROOM can have their behavior defined by a finite state machine. If a behavior is defined, it can be viewed in a graphical view by either:
-
pressing
Ctrl+Shift+Alt+Bwith the cursor focused on an ActorClass -
or with the
Open Behavior Diagrambutton directly above the ActorClass in the code
Open the behavior diagram for workingLight_Step1. First Ctrl + Click on Tutorial_WorkingLight_Step1 to navigate to the ActorClass’s definition and then use one of the two above mentioned methods to open the diagram. You should now see a diagram like this:
The state machine needs to be defined in the code. We can inspect its behavior and navigate around the code using the graphical view. Use Shift + Click on the state WorkingLightOn in the behavior diagram to jump to the state’s definition in the code. Here we can see definitions for what occurs when the state is entered and exited. Upon entering the state, we turn the light on and upon exiting, we turn it off.
Jumping to the definition of the state WorkingLightOff (Shift + Click) will show us that the state is only defined without entry or exit code. This is because the messages to turn the light on and off are all handled by the state WorkingLightOn and this state is only used as a sort of idle state.
The behavior diagram also includes three transitions, init, on:button and off:button. Using Shift + Click on these transition labels will take us to their definitions where we can see the transition names, which states they transition to and from, what triggers the transition and what code gets executed during the transition. Let’s look at on:button as an example. Here we can see the transitions actual name is tr0 and it transitions from WorkingLightOff to WorkingLightOn. The trigger block tells us that this transition is triggered when an on message arrives at the button port. This trigger is also what is used in the behavior diagram as a label. Finally there is an action block where C code can be written to be executed during the transition. In this case it is empty because the behavior is all handled by the state WorkingLightOn.
|
Adding new states and transitions can be done easily by using VSCode code snippets. Try typing |
Finally we have to connect this actor to the Hardware Abstraction Actor (hwmmi), so that the buttons and LEDs on the miniHIL board can be used. In MiniHILProject.room, we need to add a binding between workingLight_Step1.light and any LED, in this case we’ll use hwmmi.ledBlue. This is accomplished by adding the the following line to Structure section of the Actor Application:
Binding workingLight_Step1.light and hwmmi.ledBlue
We then also need to do the same for workingLight_Step1.button and hwmmi.s1 (or any switch of your choice):
Binding workingLight_Step1.button and hwmmi.s1
|
If you are receiving port multiplicity errors, you have to delete or comment out an existing binding from another example. Look for any Bindings containing |
The complete behavior of step 1:
Behavior {
StateMachine {
State WorkingLightOff
State WorkingLightOn {
entry '''
// the entry code is called when the state is entered through a transition
light.on(); // turning the working light on
// tip: turning something on in the entry code and turning it off in the exit code
// makes sure that it is always active in this state and inactive outside'''
exit '''
// the exit code is called when the state is left through a transition
light.off(); // turning the working light off'''
}
Transition init0: initial -> WorkingLightOff
Transition tr0: WorkingLightOff -> WorkingLightOn {
triggers {
<on: button>
}
action '''
// this transition is triggered by the message >on< from the port >button<
'''
}
Transition tr1: WorkingLightOn -> WorkingLightOff {
triggers {
<off: button>
}
action '''
// this transition is triggered by the message >off< from the port >button<
'''
}
}
}
Example code of Actor Application after step 1:
ActorClass Application {
Structure {
//
// Standard elements
//
ActorRef hwmmi : AHWMMI
//
// WorkingLight Step 1
//
ActorRef workingLight_Step1: Tutorial_WorkingLight_Step1
Binding workingLight_Step1.light and hwmmi.ledBlue
Binding workingLight_Step1.button and hwmmi.s1
}
}
Build and Flash onto the miniHIL board
Now that the code has been written, it is ready to be built and flashed onto the miniHIL board. You can see in the "Quick Start" part of the User Guide how to set up your hardware.
In the bottom left corner of VSCode, underneath the file explorer, there is a section labeled MINIHIL PROJECTS that allows you to build and flash projects to the miniHIL board. See the VSCode IDE guide for more details.
Click the flash button to build and run your project on the miniHIL board. Alternatively build and flash the project by executing the terminal commands .\gradlew.bat build and .\gradlew.bat flash in the folder C:/miniHIL/MiniHilProject_Examples. You should now see the board LEDs initialize. Verify that the working light functionality is implemented correctly by pressing the S1 switch. You should see the LED toggle with your button presses.
Step 2 - Adding a timeout
In Step 1 the simplest possible Working Light was modelled in miniHIL. This step will add a little bit more functionality to the base working light.
The behavior implemented in this step is a simple timeout, where pressing the button will cause the light to turn on for 1 second, before shutting off. This step is implemented as another ActorClass, therefore, a new ActorRef needs to be declared for this new class.
Below the ActorRef of step 1 in miniHILProject.room, the ActorRef’s for steps 2 and 3 should be commented out. Uncomment the line with Tutorial_WorkingLight_Step2 by removing the // at the beginning of the line.
You can see the changes made in Step2 by opening its declaration. The Interface is identical with the first step, however there are a few differences in the Structure and Behavior.
In Structure, a new element is declared here which is called a Service Access Point (SAP). This introduces you to the concept of services, which for the purposes of this tutorial step are functions that don’t require an explicit binding to access the Actors state. Since the modelling system used in miniHIL is inherently hierarchial (i.e. actors on the same level can interact with each other, but require a port-port connection to interact with actors that are on a different level). What services use instead are Service Access Points (SAPs) and Service Provision Points (SPPs), where SAPs provide access for an Actor to access the SPP of a service, which is where the service is "provided".
Services are typically functions that are required by multiple actors. Using services for them reduces the number of bindings present in the Structural view of the application, as the actors that require it won’t need them, thus de-cluttering the view. The service being provided here is the PTimer service, which is used to achieve the 1 second timeout in the program.
The Behavior also has an added state called ButtonReleased_Waiting.
Connect the light binding of Step2 to ledBlue and the button binding to s2. Now rearrange the bindings of Step 1 in the structural view to accommodate for the new ActorClass. Change the light binding of Step1 to ledRed, so that the LEDs align with the buttons. You may have to delete or comment out an existing binding from another example.
Binding workingLight_Step1.light and hwmmi.ledRed Binding workingLight_Step1.button and hwmmi.s1
Binding workingLight_Step2.light and hwmmi.ledBlue Binding workingLight_Step2.button and hwmmi.s2
Now flash the code once again onto the miniHIL board. Verify that the implemented behavior is correct by pressing Switch 2 on the board and seeing if the LED remains on for 1 second after releasing the switch.
In this tutorial, the behavior of the switch was verified manually (i.e. you looked at the light to see if it stayed on or not). A primary benefit of the miniHIL board is its capability for running automated tests, so that all combinatorial paths of execution can be evaluated quickly. This tutorial doesn’t cover writing automated tests, but is covered in the more advanced tutorials.
Step 3 - Implementing debounce functionality
In this step the Working Light is developed further by adding in a debouncing function and is implemented in another independent ActorClass. Button debouncing is a commonly used technique in embedded platforms, to ensure that the extra signal "bounces" from a single button push aren’t registered as multiple button toggles. While there exist many algorithms used to address this issue, the debouncing function used in this step will simply use a timeout and check if the button is released longer than the timeout before turning the light off. Essentially, a small extension to the timeout function introduced in step 2.
Once again, the Step 3 ActorRef needs to be declared in miniHILProject.room in order for it to be used. Uncomment the line with Tutorial_WorkingLight_Step3 found below the Step2 declaration from the previous step. Then go to the structural view and bind the light and the button of the new Actor to the remaining LED on the hw actor (ledGreen).
Binding workingLight_Step3.light and hwmmi.ledGreen Binding workingLight_Step3.button and hwmmi.s3
The only difference in this step is a small change in the Actor’s behavior. Open up the Actors behavior view and take a look at the loop created between states ButtonReleased_Waiting and WorkingLightOn using the transitions tr3 and tr1. Now Shift + Click on tr3(on:button) and look at its Action Code.
Transition tr3: ButtonReleased_Waiting -> WorkingLightOn {
triggers {
<on: button>
}
action '''
// debouncing: if the button is pressed again the timeout is killed
// and we go back to working light on
workingTimeout.kill(); '''
}
While the state machine is in the ButtonReleased_Waiting state, the transition tr3 triggers when the button goes to the on state. As you can see in the Action Code, the transition stops the timeout and returns to the WorkingLightOn state, thus completing the debouncing loop. This means that the light will be robust to spurious button bounces and instead only turn off when the timeout is successfully reached without intermediate button bounces. Compare this to step 2, where pressing and holding the button, quickly releasing it and holding it again will result in the light still turning off despite the button still being held down.
Flash the code once more onto the miniHIL board and play around with the 3 Working Light setups with switches 1,2 and 3.
Tutorial Summary
You should now be able to:
-
Setup your own project from the the template project
-
Write your own ActorClass and use them in an application
-
Create and change bindings to connect actors together
-
Build and Flash to the miniHIL board
And that’s what you’ll need to get started with miniHIL! Try out some of the more advanced tutorials to learn about the other features of miniHIL.