From d7897145533bb9a9200d46f700c59fbc4c19bc0c Mon Sep 17 00:00:00 2001 From: fusiled Date: Sun, 21 Jun 2026 23:20:46 -0500 Subject: [PATCH] Add example 2 --- .../1_FirstModule_and_SimoSim/README.md | 2 +- .../system_config.yaml | 14 ++++ .../2_Ports_and_SimoSim/README.md | 71 +++++++++++++++++++ .../2_Ports_and_SimoSim/system_config.yaml | 49 +++++++++++++ docs/guided_examples/build_all_examples.sh | 5 ++ include/Simo/module/Module.h | 5 ++ src/SimoSim/SimoSim.cc | 4 +- tests/module/ModuleTest.cc | 10 +++ 8 files changed, 158 insertions(+), 2 deletions(-) create mode 100644 docs/guided_examples/2_Ports_and_SimoSim/README.md create mode 100644 docs/guided_examples/2_Ports_and_SimoSim/system_config.yaml diff --git a/docs/guided_examples/1_FirstModule_and_SimoSim/README.md b/docs/guided_examples/1_FirstModule_and_SimoSim/README.md index b1efe59..3ce95ea 100644 --- a/docs/guided_examples/1_FirstModule_and_SimoSim/README.md +++ b/docs/guided_examples/1_FirstModule_and_SimoSim/README.md @@ -1,7 +1,7 @@ # FirstModule SimoSim ## Introduction -The documents highlights some location in the source of [FirstModule.cc](./FirstModule.cc) +The document highlights some location in the source of [FirstModule.cc](./FirstModule.cc) to better understand how to write your own `Module` class and how to use it in `SimoSim`, a general purpose executable to run simulations. diff --git a/docs/guided_examples/1_FirstModule_and_SimoSim/system_config.yaml b/docs/guided_examples/1_FirstModule_and_SimoSim/system_config.yaml index 5a0e806..3ec21bf 100644 --- a/docs/guided_examples/1_FirstModule_and_SimoSim/system_config.yaml +++ b/docs/guided_examples/1_FirstModule_and_SimoSim/system_config.yaml @@ -1,3 +1,17 @@ +# Copyright 2026 Matteo Fusi and Contributors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + # List all modules in the modules section modules: # This is the module of the tutorial diff --git a/docs/guided_examples/2_Ports_and_SimoSim/README.md b/docs/guided_examples/2_Ports_and_SimoSim/README.md new file mode 100644 index 0000000..b86b95b --- /dev/null +++ b/docs/guided_examples/2_Ports_and_SimoSim/README.md @@ -0,0 +1,71 @@ +# Ports and SimoSimo + +# Introduction + +This document explains basic principle of ports of `Simo` and how to use them +in `SimoSim`. + + +# Connecting Modules with ports + +Ports allow to create connections between modules. The class `Simo::Port` is a +templated class and it is the base class. Any protocol can be built on top of it. +To create a new port class, it is required to implement is the `bool connect(Port* other)` +method in the subclass. This method is called when two ports are connected together +and this is what `SimoSim` uses to connect the ports. + +Some templated implementations are already provided in the library to ease integration: +- `Simo::InPort`: Allows to receive a payload of type `T`. It connects to a `Simo::OutPort` +- `Simo::OutPort`: Allows to send a payload of type `T`. It connects to a `Simo::InPort` +- `Simo::BidirectionalPortTyped`: Allows to send a payload of type `OutPayload` and receive a payload of type `InPayload`. +It connects to another `Simo::BidirectionalPortTyped` (notice that +`OutPayload` and `InPayload` are swapped). +- `Simo::BidirectionalPort`: It is an alias for `Simo::BidirectionalPortTyped`. +It is a good general-purpose port in case bidirectional communication is needed of +the same payload type. + +Look at `Simo/port/Port.h` for the implementation of these classes. Here below a +recap of the methods that `Simo::BidirectionalPort` provides: +```text ++------------------------------------+ +| [Port A] | +| - send_out / clear_out works on X | +| - receive_in / clear_in works X | ++------------------------------------+ + | ^ + | X goes | Y goes + | from A | from B + | to B | to A + v | ++------------------------------------+ +| [Port B] | +| - receive_in / clear_in works X | +| - send_out / clear_out works on Y | ++------------------------------------+ +``` + +No specific protocol is enforced and both sides of the port can remove the payload +anytime. This is a design choice to allow more flexibility. + +# Connecting ports in SimoSim + +The configuration file of `SimoSim` allows to connect using the `connections` section. +Look at [system_config.yaml](./system_config.yaml) for an example: + +```yaml +connections: + - ping_module/port: pong_module/port +``` + +Here `ping_module` and `pong_module` both expose a port named `port`, and these +two are connected together. Look at `tests/collection/PingPongCollection.cc` for +the implementation of these modules and how the ports are defined. Inside a module, +a port can be created with the `Simo::Module::create_port<{Port-Class}>({port_name})` +method. + +To run this example, you need the `PingPongCollection`. This is built by default +when Simo is built. To run the example, use the following command: + +```bash +SimoSim --config /system_config.yaml --search-path +``` \ No newline at end of file diff --git a/docs/guided_examples/2_Ports_and_SimoSim/system_config.yaml b/docs/guided_examples/2_Ports_and_SimoSim/system_config.yaml new file mode 100644 index 0000000..103c85b --- /dev/null +++ b/docs/guided_examples/2_Ports_and_SimoSim/system_config.yaml @@ -0,0 +1,49 @@ +# Copyright 2026 Matteo Fusi and Contributors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Simple example to demonstrate ports +modules: + - name: ping_module + type: ping + parameters: + - name: period + value: + time: 10 + unit: PS + - name: pong_module + type: pong + parameters: + - name: period + value: + time: 10 + unit: PS + - name: log_level + value: INFO + - name: collector + type: collector + parameters: + - name: start_time + value: + time: 0 + unit: NS + - name: end_time + value: + time: 100 + unit: NS +connections: + - ping_module/port: pong_module/port +simulation: + time: + time: 100 + unit: NS diff --git a/docs/guided_examples/build_all_examples.sh b/docs/guided_examples/build_all_examples.sh index 00dd906..f06f5e7 100755 --- a/docs/guided_examples/build_all_examples.sh +++ b/docs/guided_examples/build_all_examples.sh @@ -20,6 +20,11 @@ BUILD_TYPE="Debug" while IFS= read -r -d '' dir do + if [[ ! -f "$dir/CMakeLists.txt" ]]; then + echo "Skipping $dir: no CMakeLists.txt" + continue + fi + pushd "$dir" > /dev/null || exit echo "Building example in $dir" cmake -B ./build "-DCMAKE_BUILD_TYPE=$BUILD_TYPE" diff --git a/include/Simo/module/Module.h b/include/Simo/module/Module.h index 8560252..edad6fe 100644 --- a/include/Simo/module/Module.h +++ b/include/Simo/module/Module.h @@ -99,6 +99,11 @@ class SIMO_PUBLIC Module { [[nodiscard]] std::string_view name() const; + [[nodiscard]] constexpr std::string name_of_child( + const std::string_view child) const { + return name_ + "/" + std::string(child); + } + [[nodiscard]] Context& sim_ctx() const; virtual ~Module() {} diff --git a/src/SimoSim/SimoSim.cc b/src/SimoSim/SimoSim.cc index 50cbd00..3302cd5 100644 --- a/src/SimoSim/SimoSim.cc +++ b/src/SimoSim/SimoSim.cc @@ -128,7 +128,7 @@ int main(const int argc, char* argv[]) { if (verbosity >= 3) { std::cout << "Detected modules:\n"; for (const auto& type : factory_map | std::views::keys) { - std::cerr << type << "\n"; + std::cout << type << "\n"; } } @@ -233,7 +233,9 @@ int main(const int argc, char* argv[]) { } } + std::cout << "Starting simulation of " << cfg.simulation.time << "\n"; ctx.run_at(cfg.simulation.time); + std::cout << "Simulation completed\n"; Simo::Log::Logger::flush_all_sinks(); return SUCCESS; diff --git a/tests/module/ModuleTest.cc b/tests/module/ModuleTest.cc index 26ad084..1706b09 100644 --- a/tests/module/ModuleTest.cc +++ b/tests/module/ModuleTest.cc @@ -105,3 +105,13 @@ BOOST_AUTO_TEST_CASE(StdoutLogSetupEnablesLogger) { BOOST_CHECK(status.success()); BOOST_CHECK_EQUAL(logger.enabled(), true); } + +BOOST_AUTO_TEST_CASE(NameOfChild) { + Simo::Context ctx; + Simo::Parameters p; + Simo::Module m; + p.name("root"); + const auto status = m.initialize(ctx, p); + auto child_name = m.name_of_child("child"); + BOOST_CHECK_EQUAL(child_name, "root/child"); +}