Skip to content

My counter

Prerequisites: none. This is the first package, built step by step in the Getting Started guide.

This package demonstrates the minimal structure of a Sen package: a single STL file that declares one class, and one C++ implementation class. It is intentionally small so you can focus on the mechanics of writing and wiring a Sen package rather than on business logic.

The Counter class has:

  • a value property that increments automatically,
  • a step property, set once at construction, that says how much it increments by,
  • a hello method that prints a greeting, and
  • a valueIsDivisibleByTen event fired whenever value becomes divisible by 10.

Interface

counter.stl
package my_counter;
class Counter
{
  // The current value of the counter.
  var value : i32;

  // How much should the counter increase each cycle.
  var step : i32 [static];

  // Returns a greeting message.
  fn hello() -> string [const];

  // Emitted each time the current value is divisible by 10.
  event valueIsDivisibleByTen(newValue: i32);
}

Implementation

counter.h
// === counter.h =======================================================================================================
//                                               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.
// =====================================================================================================================
#pragma once

#include "stl/my_counter/counter.stl.h"  // (1)!

// sen
#include "sen/kernel/component_api.h"

namespace my_counter
{

class CounterImpl: public CounterBase  // (2)!
{
public:
  SEN_NOCOPY_NOMOVE(CounterImpl)  // (3)!

  using CounterBase::CounterBase;
  ~CounterImpl() override = default;

public:
  void update(sen::kernel::RunApi& runApi) override;  // (4)!

protected:
  std::string helloImpl() const override;  // (5)!
};

}  // namespace my_counter
  1. The generated header. Sen writes CounterBase from counter.stl, carrying the properties, the event and the method you declared there.
  2. Your implementation inherits from the generated base, which handles serialisation, subscriptions and dispatch.
  3. Deletes the copy and move constructors.
  4. Called once per cycle, during the update stage. This is where the next state is computed.
  5. The base class declares helloImpl pure virtual, so it has to be implemented here.
counter.cpp
// === counter.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.
// =====================================================================================================================
#include "counter.h"

// sen
#include "sen/core/meta/class_type.h"
#include "sen/kernel/component_api.h"

// std
#include <string>

namespace my_counter
{

void CounterImpl::update(sen::kernel::RunApi& /*runApi*/)
{
  setNextValue(getValue() + getStep());  // (1)!

  if (getNextValue() % 10 == 0)
  {
    valueIsDivisibleByTen(getNextValue());  // (2)!
  }
}

std::string CounterImpl::helloImpl() const
{
  return "Hello from Sen! My current value is: " + std::to_string(getValue());
}

// (3)!
SEN_EXPORT_CLASS(CounterImpl)

}  // namespace my_counter
  1. getValue() and getStep() read the current buffer, the snapshot frozen before the cycle began. setNextValue() writes the next one, which everyone sees once Sen commits.
  2. Fires the valueIsDivisibleByTen event. Events are buffered like property changes and delivered after the commit.
  3. Registers CounterImpl so the kernel can instantiate it. Leave it out and the build still succeeds, but the kernel stops at startup saying it cannot find the type.

CMakeLists.txt explained

add_sen_package(
  TARGET my_counter                      # Name of the CMake and runtime target
  MAINTAINER "..."                       # Who owns this package
  VERSION "0.0.1"                        # Semantic version embedded in metadata
  DESCRIPTION "Hello Sen tutorial"       # Free text
  SOURCES src/counter.h src/counter.cpp  # C++ files implementing the package logic
  STL_FILES stl/my_counter/counter.stl   # STL interface file; Sen generates C++ from this
)

add_sen_package creates a shared library that Sen loads at runtime. STL_FILES triggers code generation: the Sen compiler reads the STL file and produces the CounterBase C++ class. SOURCES lists the hand-written C++ files compiled alongside the generated code.

How to run it

config.yaml
load:
  - name: term
    group: 2
    open: [local.counters]

build:
  - name: counterComponent
    freqHz: 2
    group: 3
    imports: [my_counter]
    objects:
      - class: my_counter.CounterImpl
        name: myCounter
        step: 5
        bus: local.counters

Run the package with:

sen run packages/my_counter/config.yaml

This opens a Sen shell with the myCounter object published on the local.counters bus. You can interact with it using:

local.counters.myCounter.print
local.counters.myCounter.hello

print shows the current property values. hello calls the method and prints a greeting to the terminal running the Sen process.