Calculators example¶
This example illustrates how you can create a package that holds two implementations of a class defined in STL.
Interface¶
This package provides the definition of a calculator.
package calculators;
// A simple calculator that can add and divide numbers.
class Calculator
{
// The model of the calculator
var model : string [static];
// The last result, or what is currently presented at the screen.
var current : f32;
// Returns "a + b" and sets the last result to it.
//
// @param a left-hand operator.
// @param b right-hand operator.
fn add(a: f32, b: f32) -> f32;
// Returns "a + R" where R is was the last result.
//
// @param a left-hand operator.
fn addWithCurrent(a: f32) -> f32;
// Returns "a / b" and sets the last result to it.
//
// @param a left-hand operator.
// @param b right-hand operator (if 0, the divisionByZero event gets emitted).
fn divide(a: f32, b: f32) -> f32;
// Returns "a / R" where R is was the last result.
// If R is 0, the divisionByZero event gets emitted.
//
// @param a left-hand operator.
fn divideByCurrent(a: f32) -> f32;
// Emitted when there's an attempt to divide by zero.
event divisionByZero();
}
Implementation¶
It also provides two implementations for the Calculator class.
// === casio_calculator.cpp ============================================================================================
// Sen Infrastructure
// Released under the Apache License v2.0 (SPDX-License-Identifier Apache-2.0).
// See the LICENSE.txt file for more information.
// © Airbus SAS, Airbus Helicopters, and Airbus Defence and Space SAU/GmbH/SAS.
// =====================================================================================================================
// generated code
#include "stl/calculator.stl.h"
// sen
#include "sen/core/base/compiler_macros.h"
#include "sen/core/base/numbers.h"
#include "sen/core/meta/class_type.h"
namespace calculators
{
/// Our implementation of a calculator.
/// We inherit from the CalculatorBase class (generated by Sen).
class CasioCalculator: public CalculatorBase
{
public:
SEN_NOCOPY_NOMOVE(CasioCalculator)
public:
using CalculatorBase::CalculatorBase;
~CasioCalculator() override = default;
protected:
/// This is the implementation of the "add" method.
/// We need to provide an implementation to be able to instantiate this class.
float32_t addImpl(float32_t a, float32_t b) override
{
const auto result = a + b;
setNextCurrent(result); // Save the result in our "current" property.
return result;
}
/// Implementation of addWithCurrent.
float32_t addWithCurrentImpl(float32_t a) override
{
// Just call add with what we have in our "current" property.
return addImpl(a, getCurrent());
}
/// Implementation of divide.
float32_t divideImpl(float32_t a, float32_t b) override
{
float32_t result = 0.0f;
if (b == 0.0f)
{
divisionByZero(); // If we divide by zero, emit the event.
}
else
{
result = a / b;
}
// Save the result in our "current" property.
setNextCurrent(result);
return result;
}
/// Implementation of divideWithCurrent.
float32_t divideByCurrentImpl(float32_t a) override { return divideImpl(a, getCurrent()); }
};
// With this macro we let Sen know that this package provides our class.
// You need to define this only once in a cpp file.
SEN_EXPORT_CLASS(CasioCalculator)
} // namespace calculators
// === faulty_calculator.cpp ===========================================================================================
// Sen Infrastructure
// Released under the Apache License v2.0 (SPDX-License-Identifier Apache-2.0).
// See the LICENSE.txt file for more information.
// © Airbus SAS, Airbus Helicopters, and Airbus Defence and Space SAU/GmbH/SAS.
// =====================================================================================================================
// generated code
#include "stl/calculator.stl.h"
// sen
#include "sen/core/base/compiler_macros.h"
#include "sen/core/base/numbers.h"
#include "sen/core/meta/class_type.h"
// std
#include <cstdint>
namespace calculators
{
/// A calculator implementation that sometimes provides wrong results.
class FaultyCalculator: public CalculatorBase
{
public:
SEN_NOCOPY_NOMOVE(FaultyCalculator)
public:
using CalculatorBase::CalculatorBase;
~FaultyCalculator() override = default;
protected:
/// Implementation of the add method.
/// Might return a wrong answer.
float32_t addImpl(float32_t a, float32_t b) override
{
callCount_++;
const auto result = a + b + (shouldFail() ? 1.0f : 0.0f);
setNextCurrent(result);
return result;
}
/// Implementation of the addWithCurrent method.
/// Might return a wrong answer.
float32_t addWithCurrentImpl(float32_t a) override
{
// Same as add() but use the value of our "current" property.
return addImpl(a, getCurrent());
}
/// Implementation of the divide method.
/// Might return a wrong answer.
float32_t divideImpl(float32_t a, float32_t b) override
{
callCount_++;
float32_t result = 0.0f;
if (b == 0.0f)
{
divisionByZero();
}
else
{
result = (a / b) + (shouldFail() ? 1.0f : 0.0f);
}
setNextCurrent(result);
return result;
}
/// Implementation of the divideWithCurrent method.
/// Might return a wrong answer.
float32_t divideByCurrentImpl(float32_t a) override { return divideImpl(a, getCurrent()); }
private:
[[nodiscard]] bool shouldFail() const noexcept
{
// Fail every other call.
return callCount_ % 2 == 0;
}
private:
uint32_t callCount_ = 0U;
};
SEN_EXPORT_CLASS(FaultyCalculator)
} // namespace calculators
How to run it¶
Let's define what we want to run in our Sen kernel.
# $schema: ../base/schema.json
include:
# bring the shell so that we can interact with our objects
- ../base/shell.yaml
build:
# Let's build a component
- name: myComponent
freqHz: 30
# Import our package so that we can instantiate our objects
imports: [calculators]
group: 3
objects:
# We know that this package contains a CasioCalculator class. We instantiate it here.
- class: calculators.CasioCalculator
name: goodCalc
bus: my.tutorial
model: superCalc # Defining the model is mandatory for instantiating this object.
- class: calculators.FaultyCalculator
name: badCalc
bus: my.tutorial
model: bsCalc
To run it, let's call sen run:
This will open a shell and tell Sen to instantiate the two implementations in the my.tutorial bus.
You can interact with the objects by doing commands such as:
info my.tutorial.goodCalc
my.tutorial.goodCalc.add 2, 2
my.tutorial.goodCalc.print
my.tutorial.goodCalc.addWithCurrent 2
my.tutorial.goodCalc.getCurrent
my.tutorial.goodCalc.divideByCurrent 12
my.tutorial.goodCalc.divide 4, 2
my.tutorial.goodCalc.addWithCurrent -2
my.tutorial.goodCalc.divideByCurrent 4
my.tutorial.bsCalc.add 2, 2
my.tutorial.bsCalc.add 2, 2
Running it over the network¶
We can run it over the network using the eth component. This is the same as the first example, but you will need to start two processes.
First run:
Then, in another terminal or command prompt, run:
In this new Sen instance, open the bus where we should find our objects:
You should be able to work with the objects as if you were on the same process.
Using the explorer¶
You can also run it using the explorer to see and interact with the objects in a more graphical way.