Drop-in simulator for C/C++-programmable microcontrollers and hardware models
HAR is a modular set of libraries that aid in simulating hardware models that incorporate microcontrollers.
It features a platform independent simulation runtime,
an easy to use drag-and-drop editor for creating models, an optional interactive UI
and APIs to expand it's capabilities.
You can also pack complete simulations into static libraries for use in assignments.
This project is the continuation of a project in a course on software system design.
The original assignment reads as follows:
In a course on electrical engineering students are assigned to implement a controller for a given hardware system
consisting of a C-programmable MCU with attached sensors and actuators.
To enable them to work on the assignment at home, a software solution is to be implemented.
The solution should mimic the programming interface of the microcontroller the students use
as well as it's build and deployment process.
Further, the solution should be easily adaptable to changes in the assignment (different MCU, hardware model, etc.)
while remaining closed enough to be applicable for graded assignments.
This repository is divided as follows:
-
HAR
C++ library that realizes the simulation process itself -
HARgui
A GUI for HAR simulations. Written for gtkmm -
HARduino
Adds support to run Arduino C programs on HAR simulations (uses HARgui)
The bulk of this repository's code compiles to libraries, so to run them, you have to provide some code yourself. What this code has to contain needs to match one of these approaches:
-
Arduino-like:
This approach works only for the HARduino library.
The main goal of this approach is mimicking the build process of Arduino sketches.Your code has to contain at least a
setup
and aloop
function, just as in an Arduino sketch.
For example:void setup() { ... } void loop() { ... }
Your code may not contain an entry function (resp.
main
), so that the library can supply its own entry function. This entry function provides the runtime to run Arduino programs as HAR simulations. -
Standard C/C++-like:
If you need more control over the simulation and its participants, use this approach.
It works with all libraries in this repository (including HARduino).Your code has to define a
main
function. This prevents the library from supplying an entry function for the executable. From there, you can access the library's symbols by including thehar*.hpp
headers.#include <har.hpp> #include <har/gui.hpp> #include <har/duino.hpp> int main(int argc, char * argv[]) { har::simulation sim{ }; har::gui gui{ }; har::duino duino{ }; sim.attach(gui); sim.attach(duino); ... sim.commence(); ... }
For a complete example on how to write such entry function and runtime, see
arduino.cpp
andduino.hpp
.
The build targets are organized with CMake.
Building all targets requires:
- A C++17 supporting compiler
- CMake 3.13 or higher
Building and running the included GUI and targets that depend on the included GUI additionally require:
- pkg-config 0.29
- gtkmm 3.0
- glibmm 2.4
- libsigc++ 2.0
- an implementation for
dlfcn.h
(on Windows)
Building the HARduino library additionally requires (for compiling resources):
- xxd
The test targets additionally require:
The documentation targets require:
You can build the targets via command line
cmake --build .
make [...]
The CMakeLists.txt holds the following targets:
Target | Description |
---|---|
har |
The HAR library |
har_test |
Catch2 unit tests for the HAR library |
hargui |
The gtkmm GUI |
harduino |
The HARduino library |
harduino_test |
Catch2 unit tests for the HARduino library |
doc |
Doxygen documentation for this repository |
Additionally, the following example targets:
Target | Description |
---|---|
example_blink |
The blink example for Arduino |
example_gol |
Conway's Game of Life as a HAR simulation |
HAR simulations employs a modified cellular automaton.
Cellular automata have a world of uniform cells.
These cells cyclically alter their own state based on the state of their neighboring cells.
In HAR simulations, these cells are of parts and pins of the simulated model.
The part associated to a cell determines its behaviour and possible states.
Cells can also be connected to each other. These connections count as additional neighbors.
Furthermore, HAR supports movable cells that can be moved across the world.
In an object-oriented sense, think of the parts as classes and the cells as their instances.
If the HARduino library doesn't satisfy your needs, you can easily write extensions to a HAR simulation yourself.
Parts are what a HAR simulation simulates. They come in three variations:
-
Component parts are what the microcontroller is attached to:
Buttons, lamps, motors, etc. -
Board parts are the pins and SMD parts the microcontroller board comes with.
They can be connected to component parts. -
Cargo parts have no fixed position and can be moved by other parts.
They can also be changed by the fixed parts under them.
All parts have a property model which defines the information an instance of a part can hold.
This information can be the current state of the part (e.g. whether a button is pressed),
information relevant to adjacent parts (e.g. the speed of a conveyor belt section)
or information relevant to connected parts (e.g. the output voltage of an analog pin).
The property model consists of a list of tuples containing a unique ID for the property, it's name, it's datatype and in some cases type-specific information on allowed values.
using namespace har;
...
part pin{ PART[1234], //Unique ID
"eg:pin", //Unique name
BOARD_PART, //Is placed on the MCU board
"Example pin" }; //Friendly name
...
pin.add_entry(of::PIN_MODE, //ID
"__PIN_MODE", //Unique name
"Pin mode", //Friendly name
value(uint_t(0u)), //Datatype and default value
ui_access::CHANGEABLE, //Property can be edited in UI
serialize::SERIALIZE, //Property is serialized
{ //List of valid values and their meaning
{ 0u, "Tri-state" },
{ 1u, "Output" },
{ 2u, "Input" }
});
...
Additionally, parts have behaviour. That includes cyclic behaviour (e.g. a timer increments a counter in certain intervals) and interactive behaviour (e.g. a button closes/opens a circuit when pressed).
Here's an example for cyclical behaviour of an analog input pin:
using namespace har;
...
part analog_pin{ PART[4711], //Unique ID
"eg:analog_pin", //Unique name
BOARD_PART | //Is placed on the MCU board
INPUT | //May require an input
OUTPUT | //Provides an output
COLORED, //Is colored
"Analog pin" }; //Friendly name
...
analog_pin.delegates.cycle = [=](cell & cl) { //Each cycle
double sum = 0.;
for (auto &[use, ncl] : cl.connected()) { //For each cell connected to this cell
sum += double(ncl[POWERING_PIN]); //Sum up Vout of the connected pin
}
cl[POWERED_PIN] = voltage / cl.connected().size(); //Set this cells Vin to mean of sum
};
...
The interactive behaviour gets triggered when the user clicks on a cell of this part in the GUI.
Consider this excerpt from a rudimentary push button:
using namespace har;
...
part push_button{ PART[ 815], //Unique ID
"eg:push_button", //Unique name
COMPONENT_PART | //Is not placed on the MCU board
INPUT | //May require an input
OUTPUT | //Provides an output
SENSOR | //Is a sensor
COLORED, //Is colored
"Push button" }; //Friendly name
...
push_button.delegates.press = [=](cell & cl, const ccoords_t & at) { //When the button is pressed
cl[FIRING] = true; //Set the button (as a sensor) to firing.
cl[POWERING_PIN] = cl[POWERED_PIN]; //Set Vout to Vin
};
push_button.delegates.release = [=](cell & cl, const ccoords_t & at) { //When the button is released
cl[FIRING] = false; //Set the button (as a sensor) to not firing.
cl[POWERING_PIN] = 0.; //Set Vout to 0
};
...
For further examples on how to write parts, see the part definitions in the HARduino library.
Participants, as the name suggests, participate in a simulation. They are the primary way to interact with the simulation, every access to the simulation's resources is routed through these. This repository already contains some participants:
har::program
: A generic interface to interact with the simulationhar::gui
: A GUI that displays the simulation and allows for user interactionhar::duino
: An Arduino-like interface for C programs
For information on how to implement your own participants,
see the Doxygen documentation for har::participant
.
This software is still in development. The API and implementation are subject to possible change.
Suggestions of any kind are welcome.
Andy Egal | DosennooB | PatVax |
The source code in this repository is released under the BSD 2-Clause license.
See the LICENSE file for the full license text.
For software used in this repository, see the copyright NOTICE.