Page MenuHomePhorge

No OneTemporary

Size
43 KB
Referenced Files
None
Subscribers
None
diff --git a/docs/Design.rst b/docs/Design.rst
new file mode 100644
index 0000000..4f07a0f
--- /dev/null
+++ b/docs/Design.rst
@@ -0,0 +1,119 @@
+===============
+Design Overview
+===============
+
+Last updated: 2019-11-27
+
+TODO:
+
+- Add cross references to relevant parts of the documentation and external links (e.g., relevant papers or source of info)
+
+.. contents::
+ :local:
+
+
+Principles
+==========
+
+The main priorities for the design of the software implementation are
+
+#. providing a high-level, easy-to-use but safe interface for application developers;
+#. allowing the same application code to be used for *simulation* and *deployment*;
+#. realizing small-footprint software that can be deployed in resource-constrained embedded devices.
+
+The RoSA software framework, is implemented in C++.
+The language allows defining high-level but lightweight interfaces with flexibility in the realization.
+The framework heavily utilizes templates, template metaprogramming, and constant expressions to let the compiler generate optimized code.
+We also encode dynamically-relevant static information into a custom format so that RoSA supports message passing with flexibility and minimal resource need --- without the dynamic overhead of C++ RTTI.
+
+Performing message passing and data manipulation is decoupled from the agent interface.
+The implementation of the runtime system is easily switched behind the declarative definition of agent-based applications.
+Running an application in different modes (e.g., simulation and deployment) is a matter of static configuration.
+
+Simulation is the execution of the application on a computer with sensor and actuator agents associated to input and output streams, respectively.
+Those sensor and actuator agents may interface actual sensors and actuators with custom C++ code when deployed in an embedded device.
+
+Case studies have been dony in simulation; support for deployment requires further development effort to complete the corresponding runtime implementation.
+
+The framework is being coded in standard C++.
+The only exceptions are some OS-specific code snippets within debugging and simulation facilities.
+The software can readily be deployed to all devices that are supported by a modern C++ compiler.
+
+Software Modules
+================
+
+The software implementation consists of four main modules:
+
+`Support`
+ provides general debugging, logging, typing, and I/O facilities, which are used in other modules and application code.
+
+`Agent`
+ is a library of self-aware functionalities for defining agents in application code.
+
+`Core`
+ defines a minimal agent system with message passing capabilities and runtime system implementations.
+
+`Deluxe`
+ provides an interface that matches the RoSA Architecture and utilizes RoSA Core.
+
+
+The RoSA Deluxe interface wraps the general agent interface of RoSA Core.
+RoSA Deluxe agents are defined by functions that take their input messages as parameters and provide their output messages as return values.
+The implementation takes care of handling messages --- minimizing boilerplate in application code --- and may perform static and dynamic checks to ensure operating conditions.
+
+Agents and Agent Systems
+------------------------
+
+RoSA Core defines the means for agents to receive and send messages.
+Messages are statically-typed tuples of basic types.
+An agent is defined as a list of message handler functions.
+An incoming message is handled by the first handler that can take the message as actual parameter.
+The handler may generate output messages via RoSA API calls.
+
+RoSA Deluxe agents build on RoSA Core agents and provide a higher abstraction level by hiding message passing.
+
+Each agent is owned by a *system*.
+Systems can instantiate agents and provide the actual implementation for execution: channels --- for message passing --- and control --- for triggering data manipulation.
+
+RoSA Core allows message passing between arbitrary agents within a system.
+The RoSA Deluxe interface enforces a hierarchical structure with master-slave relations.
+
+
+A RoSA application is an agent system.
+The Deluxe module allows implementing a system as a set of agent definitions and declarative description of their connections.
+
+Execution Model
+---------------
+
+How an application (i.e., agent system) is executed depends on the system implementation.
+The implementation of the system --- channel and control facilities --- is decoupled from the definition of an application --- agents and their connections within a system.
+RoSA Core allows swapping the system implementation for any application as a configuration option or by changing one line of application code.
+
+The current system implementation is based on Models of Computations (MoCs).
+We use the untimed MoC and are prepared for the discrete-timed MoC when time aspects have to be represented.
+The concepts of the agent-based approach are easily mapped to the formal MoCs.
+
+=================== ===========
+Agent-based concept MoC concept
+=================== ===========
+Agent Process
+Channel Signal
+Message Event
+=================== ===========
+
+A RoSA agent system --- mapping to a process network --- can be analysed in the formal model.
+
+
+Building and Running Applications
+---------------------------------
+
+RoSA has a CMake build project, which allows using the framework in different development environments.
+The build project defines compile-time options to disable or tune features statically (e.g., logging, debugging, and tracing facilities).
+Disabling unnecessary features improves the efficiency of compiled framework code in particular uses.
+A RoSA application and framework modules are linked into one executable, which allows exploiting link-time optimization possibilities (optimizing framework code for application need, removing unused framework code, etc.).
+
+
+The RoSA runtime system is a thin layer between the self-aware application and the underlying system; still it fulfills important responsibilities.
+The runtime system initializes the application by instantiating an agent system, performs message passing, and triggers data manipulation in agents.
+I/O and monitoring features are also provided by RoSA.
+The application code is not bloated with system-level bookkeeping and developers can focus on details of self-awareness.
diff --git a/docs/index.rst b/docs/index.rst
index e42d88a..cf61d5a 100755
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -1,83 +1,86 @@
==================
The RoSA Framework
==================
.. contents::
:local:
Overview
========
The RoSA (Research on Self-Awareness) Framework is intended to be used as a tool
for experimenting and evaluating new ways of implementing self-aware
applications.
This documentation was generated for RoSA version |release| on |today|.
Documentation
=============
.. toctree::
:hidden:
- Changelog
+ Design
Use
Build
Dev
Issues
Release
Plan
CommandGuide/index
+:doc:`Design`
+ General overview of design principles and decisions.
+
:doc:`Use`
Describes how to create your own software based on RoSA.
:doc:`Build`
Describes how to build RoSA.
:doc:`Dev`
Provides basic information for developers on how to contribute to RoSA.
:doc:`Issues`
Known issues and things to do with the current implementation of RoSA.
:doc:`Release`
Describes for maintainers how to make a new release of RoSA.
:doc:`Plan`
Discusses future work and possible ways to develop RoSA.
:doc:`CommandGuide/index`
Documentation for RoSA applications and tools.
Changes
=======
Refer to :doc:`Changelog`.
.. _API_Documentation:
API Documentation
=================
For details of the provided interface, refer to our `API documentation`_.
.. _API documentation: ../doxygen/html/index.html
License
=======
RoSA is distributed under the terms and conditions of the
`Boost Software License 1.0 <http://www.boost.org/LICENSE_1_0.txt>`_:
.. literalinclude:: ../LICENSE
:language: none
.. note::
3rd party externals in the directory `modules` are not part of the RoSA source base and are licensed separately.
Indices and Tables
==================
* :ref:`genindex`
* :ref:`search`
diff --git a/include/rosa/config/config.h b/include/rosa/config/config.h
index 6090667..7359ccd 100644
--- a/include/rosa/config/config.h
+++ b/include/rosa/config/config.h
@@ -1,86 +1,86 @@
//===-- rosa/config/config.h ------------------------------------*- C++ -*-===//
//
// The RoSA Framework
//
// Distributed under the terms and conditions of the Boost Software License 1.0.
// See accompanying file LICENSE.
//
// If you did not receive a copy of the license file, see
// http://www.boost.org/LICENSE_1_0.txt.
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/config/config.h
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
-/// \date 2017-2019
+/// \date 2017-2020
///
/// \brief Configuration information on the build of the library.
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_CONFIG_CONFIG_H
#define ROSA_CONFIG_CONFIG_H
#include "rosa/config/rosa_config.h"
#include <iostream>
// This OS-specific block defines one of the following:
// - ROSA_LINUX
// - ROSA_WINDOWS
// It also defines ROSA_POSIX for POSIX-compatible systems.
#if defined(__linux__)
#define ROSA_LINUX
#elif defined(WIN32) || defined(_WIN32)
#define ROSA_WINDOWS
#else
#error Platform and/or compiler not supported
#endif
#if defined(ROSA_LINUX)
#define ROSA_POSIX
#endif
// Defining filenames in a project-relative way based on absolute paths.
#include "rosa/config/project_path.hpp"
/// The project-relative path of the current source file.
-#define __FILENAME__ (__FILE__ + project_relative_path_index(__FILE__))
+#define __FILENAME__ (project_relative_path(__FILE__))
// Convenience macros.
/// No-op.
#define ROSA_VOID_STMT static_cast<void>(0)
/// Ignors an expression.
///
/// \param x expression
#define ROSA_IGNORE_UNUSED_EXPR(x) static_cast<void>(x)
/// Ignors a statement (not an expression).
///
/// \param s statement
#define ROSA_IGNORE_UNUSED_STMT(s) \
while (false) { \
s; \
} \
/// Prints an error message and aborts execution.
///
/// \param error the error message to print
#define ROSA_CRITICAL(error) \
do { \
std::cerr << "[FATAL] " << __func__ << "@" << __FILENAME__ << ":" \
<< __LINE__ << ": critical error: '" << (error) << "'" \
<< std::endl; \
::abort(); \
} while (false)
/// Raises a runtime error in the program.
///
/// \param msg message describing the error
///
/// \throws std::runtime_error
#define ROSA_RAISE_ERROR(msg) throw std::runtime_error(msg)
#endif // ROSA_CONFIG_CONFIG_H
diff --git a/include/rosa/config/project_path.hpp b/include/rosa/config/project_path.hpp
index a719fae..046ddfc 100644
--- a/include/rosa/config/project_path.hpp
+++ b/include/rosa/config/project_path.hpp
@@ -1,72 +1,87 @@
//===-- rosa/config/project_path.hpp ----------------------------*- C++ -*-===//
//
// The RoSA Framework
//
// Distributed under the terms and conditions of the Boost Software License 1.0.
// See accompanying file LICENSE.
//
// If you did not receive a copy of the license file, see
// http://www.boost.org/LICENSE_1_0.txt.
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/config/project_path.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
-/// \date 2017
+/// \date 2017-2020
///
/// \brief Facility for compile-time manipulation of paths.
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_CONFIG_PROJECT_PATH_HPP
#define ROSA_CONFIG_PROJECT_PATH_HPP
#include "rosa/config/rosa_config.h"
+#include "rosa/support/diagnostics.h"
#include <cstdlib>
namespace rosa {
/// Nested namespace with implementation of the provided features,
/// consider it private.
namespace {
/// Tells the index of the project-relative part of an absolute path.
///
/// \param path absolute path to check
/// \param project the absolute path of the project
/// \param index number of leading characters already checked and found
/// matching
///
/// \return index of the part relative to \c project in \p path; \c 0 if \p path
/// is not under \p project
constexpr size_t
project_relative_path_index_impl(const char *const path,
const char *const project = ROSA_SRC_DIR,
const size_t index = 0) {
return project[index] == '\0'
? index // Found it.
: (path[index] == '\0' || project[index] != path[index])
? 0 // Path is not under project.
: project_relative_path_index_impl(
path, project,
index + 1); // Continue searching...
}
} // End namespace
/// Tells the index of the project-relative part of an absolute path.
///
/// \param path absolute path to check
///
/// \return index of the project-relative part of \p path; \c 0 if \p path is
-/// not under the RoSA siource directory.
+/// not under the RoSA source directory.
constexpr size_t project_relative_path_index(const char *const path) {
return project_relative_path_index_impl(path);
}
+/// Gives the project-relative part of an absolute path.
+///
+/// \param path absolute path to check
+///
+/// \return the project-relative part of \p path; \c path if it is not under the
+/// RoSA source directory.
+constexpr const char *project_relative_path(const char *const path) {
+// NOTE: Some compilers warn about adding int to string.
+ROSA_DISABLE_WARNING_PUSH;
+ROSA_DISABLE_WARNING_ADDING_INT_TO_STRING;
+ return path + project_relative_path_index(path);
+ROSA_DISABLE_WARNING_POP;
+}
+
} // End namespace rosa
#endif // ROSA_CONFIG_PROJECT_PATH_HPP
diff --git a/include/rosa/deluxe/DeluxeSensor.hpp b/include/rosa/deluxe/DeluxeSensor.hpp
index 151024c..c4846a6 100644
--- a/include/rosa/deluxe/DeluxeSensor.hpp
+++ b/include/rosa/deluxe/DeluxeSensor.hpp
@@ -1,678 +1,676 @@
//===-- rosa/deluxe/DeluxeSensor.hpp ----------------------------*- C++ -*-===//
//
// The RoSA Framework
//
// Distributed under the terms and conditions of the Boost Software License 1.0.
// See accompanying file LICENSE.
//
// If you did not receive a copy of the license file, see
// http://www.boost.org/LICENSE_1_0.txt.
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/deluxe/DeluxeSensor.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
-/// \date 2017-2019
+/// \date 2017-2020
///
/// \brief Specialization of \c rosa::Agent for *sensor* role of the the *deluxe
/// interface*.
///
/// \see \c rosa::deluxe::DeluxeContext
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_DELUXE_DELUXESENSOR_HPP
#define ROSA_DELUXE_DELUXESENSOR_HPP
#include "rosa/core/Agent.hpp"
#include "rosa/deluxe/DeluxeAtoms.hpp"
#include "rosa/deluxe/DeluxeExecutionPolicy.h"
#include "rosa/deluxe/DeluxeTuple.hpp"
+#include "rosa/support/diagnostics.h"
+
/// Local helper macros to deal with built-in types.
///
///@{
/// Creates function name for member functions in \c rosa::deluxe::DeluxeSensor.
///
/// \param N name suffix to use
#define DSMASTERHANDLERNAME(N) handleMaster_##N
/// Defines member functions for handling messages from *master* in
/// \c rosa::deluxe::DeluxeSensor.
///
/// \see \c DeluxeSensorMasterInputHandlers
///
/// \note No pre- and post-conditions are validated directly by these functions,
/// they rather rely on \c rosa::deluxe::DeluxeSensor::saveMasterInput to do
/// that.
///
/// \param T the type of input to handle
/// \param N name suffix for the function identifier
#define DSMASTERHANDLERDEFN(T, N) \
void DSMASTERHANDLERNAME(N)(atoms::Master, id_t MasterId, token_size_t Pos, \
T Value) noexcept { \
saveMasterInput(MasterId, Pos, Value); \
}
/// Convenience macro for \c DSMASTERHANDLERDEFN with identical arguments.
///
/// \see \c DSMASTERHANDLERDEFN
///
/// This macro can be used instead of \c DSMASTERHANDLERDEFN if the actual value
/// of \p T can be used as a part of a valid identifier.
///
/// \param T the type of input to handle
#define DSMASTERHANDLERDEF(T) DSMASTERHANDLERDEFN(T, T)
/// Results in a \c THISMEMBER reference to a member function defined by
/// \c DSMASTERHANDLERDEFN.
///
/// Used in the constructor of \c rosa::deluxe::DeluxeSensor to initialize super
/// class \c rosa::Agent with member function defined by \c DSMASTERHANDLERDEFN.
///
/// \see \c DSMASTERHANDLERDEFN, \c THISMEMBER
///
/// \param N name suffix for the function identifier
#define DSMASTERHANDLERREF(N) THISMEMBER(DSMASTERHANDLERNAME(N))
///@}
namespace rosa {
namespace deluxe {
/// Specialization of \c rosa::Agent for *sensor* role of the *deluxe
/// interface*.
///
/// \see \c rosa::deluxe::DeluxeContext
///
/// \invariant There is a compatible *execution policy* set; the actual value in
/// \c rosa::deluxe::DeluxeSensor::MasterInputNextPos is valid with respect to
/// the corresponding types.
///
/// \see Definition of \c rosa::deluxe::DeluxeSensor::inv on the class invariant
///
/// \note All member functions validate the class invariant as part of their
/// precondition. Moreover, non-const functions validate the invariant before
/// return as their postcondition.
class DeluxeSensor : public Agent {
/// Checks whether \p this object holds the class invariant.
///
/// \see Invariant of the class \c rosa::deluxe::DeluxeSensor
///
/// \return if \p this object holds the class invariant
bool inv(void) const noexcept;
/// The \c rosa::deluxe::DeluxeExecutionPolicy that controls the execution of
/// \c this object.
std::unique_ptr<DeluxeExecutionPolicy> ExecutionPolicy;
public:
/// The type of values produced by \p this object.
///
/// That is the types of values \p this object sends to its *master* in a
/// \c rosa::deluxe::DeluxeTuple.
///
/// \see \c rosa::deluxe::DeluxeSensor::master
const Token OutputType;
/// The type of values \p this object processes from its *master*.
///
/// That is the types of values \p this object receives from its *master* in a
/// \c rosa::deluxe::DeluxeTuple.
///
/// \see \c rosa::deluxe::DeluxeSensor::master
const Token MasterInputType;
private:
/// Indicates which element of the master-input is expected from the *master*.
///
/// The *master* is supposed to send one \c rosa::deluxe::DeluxeTuple value
/// element by element in their order of definition. This member field tells
/// the element at which position should be received next.
///
/// \p this object is supposed to be triggered only when a complete
/// master-input has been received, that is the field should hold the value
/// `0`.
///
/// \see \c rosa::deluxe::DeluxeSensor::handleTrigger
/// \c rosa::deluxe::DeluxeSensor::saveMasterInput
token_size_t MasterInputNextPos;
/// Indicates whether the input value from the *master* has been changed since
/// the last trigger received from the system.
///
/// The flag is reset to \c false upon handling a trigger and then set to \c
/// true by \c rosa::deluxe::DeluxeSensor::saveMasterInput when storig a new
/// input value in \c rosa::deluxe::DeluxeSensor::MasterInputValue.
bool MasterInputChanged;
/// Stores the actual input value from *master*.
///
/// \note The type of the stored value matches the types indicated by \c
/// rosa::deluxe::DeluxeSensor::MasterInputType.
const std::unique_ptr<AbstractTokenizedStorage> MasterInputValue;
/// Alias for function objects used as trigger handler for
/// \c rosa::deluxe::DeluxeSensor.
///
/// \note The function used for \c H is to be \c noexcept.
///
/// \see \c DeluxeSensorTriggerHandlers
using H = std::function<void(void)>;
/// \defgroup DeluxeSensorTriggerHandlers Trigger handlers of
/// rosa::deluxe::DeluxeSensor
///
/// \brief Trigger handler functions of \c rosa::deluxe::DeluxeSensor
///
/// The actual data source functions and master-input processing function are
/// captured in lambda expressions that are in turn wrapped in \c
/// std::function objects. The lambda expression calls a processing function,
/// either to handle master-input or obtain the next sensory value from data
/// source. The next sensory value is sent it to *master* by calling \c
/// rosa::deluxe::DeluxeSensor::sendToMaster. Also, the flag \c
/// rosa::deluxe::DeluxeSensor::MasterInputChanged is reset when the current
/// value is passed to the master-input processing function. The function \c
/// rosa::deluxe::DeluxeSensor::handleTrigger needs only to call the proper
/// function object.
/// Processes master-input.
///
/// \ingroup DeluxeSensorTriggerHandlers
///
/// The function is called upon the sensor is trigged by the system.
const H MFP;
/// Produces the next sensory value during normal execution.
///
/// \ingroup DeluxeSensorTriggerHandlers
///
/// The function is used during normal execution. During simulation, the
/// simulation environment sets \c rosa::deluxe::DeluxeSensor::SFP, which is
/// used instead of \c rosa::deluxe::DeluxeSensor::FP.
const H FP;
/// Produces the next sensory value during simulation.
///
/// \ingroup DeluxeSensorTriggerHandlers
///
/// The function is empty by default. The simulation environment sets it to be
/// used during simulation.
H SFP;
/// The *master* to send values to.
///
/// \note *Masters* are set dynamically, hence it is possible that a
/// \c rosa::deluxe::DeluxeSensor instance does not have any *master* at a
/// given moment.
Optional<AgentHandle> Master;
/// Tells the unique identifier of the *master* of \p this object, if any
/// registered.
///
/// \return the unique identifier of the *master*
///
/// \pre A *master* is registered for \p this object: \code
/// Master
/// \endcode
id_t masterId(void) const noexcept;
/// Wraps a master-input processing function into a trigger handler.
///
/// \see \c rosa::deluxe::DeluxeSensor::MFP and \c DeluxeSensorTriggerHandlers
///
/// \tparam Ts types of elements of master-input processed by \p MF
/// \tparam S0 indices for accessing master-input values
///
/// \param MF function that processes master-input
///
/// \note The second argument provides indices statically as template
/// arguments \p S0..., so its actual value is ignored.
///
/// \note A master-input type of \c rosa::deluxe::EmptyDeluxeTuple indicates
/// that \p this object does not receive master-input, \p MF is never called
/// if \p Ts is empty.
///
/// \return trigger handler function based on \p MF
///
/// \pre Statically, the indices match the elements: \code
/// sizeof...(Ts) == sizeof...(S0)
/// \endcode Dynamically, \p Ts... match \c
/// rosa::deluxe::DeluxeSensor::MasterInputType: \code
/// MasterInputType == DeluxeTuple<Ts...>::TT
/// \endcode
template <typename... Ts, size_t... S0>
H triggerHandlerFromProcessingFunction(
std::function<void(std::pair<DeluxeTuple<Ts...>, bool>)> &&MF,
Seq<S0...>) noexcept;
/// Wraps a data source function into a trigger handler.
///
/// \see \c rosa::deluxe::DeluxeSensor::FP, \c
/// rosa::deluxe::DeluxeSensor::SFP, and \c DeluxeSensorTriggerHandlers
///
/// \tparam T type of data provided by \p F
///
/// \param F function to generate value with
/// \param inSimulation if F is a data source for Simulation
///
/// \return trigger handler function based on \p F
///
/// \pre Statically, the type agument \p T is an instance of \c
/// rosa::deluxe::DeluxeTuple: \code
/// IsDeluxeTuple<T>::Value
/// \endcode Dynamically, \p T matches \c
/// rosa::deluxe::DeluxeSensor::OutputType: \code
/// OutputType == T::TT
/// \endcode
template <typename T>
H triggerHandlerFromDataSource(std::function<T(void)> &&F,
bool inSimulation) noexcept;
public:
/// Creates a new instance.
///
/// The constructor instantiates the base-class with functions to handle
/// messages as defined for the *deluxe interface*.
///
/// \todo Enforce \p F and \p MF do not potentially throw exception.
///
/// \tparam MT type of master-input handled by \p MF
/// \tparam T type of data to operate on
///
/// \note Instantiation fails if any of the type arguments \p MT and \p T is
/// not an instance of \c rosa::deluxe::DeluxeTuple or \p T is \c
/// rosa::deluxe::EmptyDeluxeTuple.
///
/// \note If \p MT is \c rosa::deluxe::EmptyDeluxeTuple, the constructed
/// object does not receive master-input.
///
/// \param Kind kind of the new \c rosa::Unit instance
/// \param Id unique identifier of the new \c rosa::Unit instance
/// \param Name name of the new \c rosa::Unit instance
/// \param S \c rosa::MessagingSystem owning the new instance
/// \param MF function to process master-input values with
/// \param F function to generate the next value with during normal operation
///
/// \pre Statically, \p MT and \p T are instances of \c
/// rosa::deluxe::DeluxeTuple and \p T contains at least one element:\code
/// TypeListAllDeluxeTuple<TypeList<MT, T>>::Value && T::Length > 0
/// \endcode
/// Dynamically, the instance is created as of kind
/// \c rosa::deluxe::atoms::SensorKind:
/// \code
/// Kind == rosa::deluxe::atoms::SensorKind
/// \endcode
///
/// \see \c rosa::deluxe::DeluxeTuple
template <
typename MT, typename T,
typename = std::enable_if_t<
TypeListAllDeluxeTuple<TypeList<MT, T>>::Value && (T::Length > 0)>>
DeluxeSensor(const AtomValue Kind, const id_t Id, const std::string &Name,
MessagingSystem &S,
std::function<void(std::pair<MT, bool>)> &&MF,
std::function<T(void)> &&F) noexcept;
/// Destroys \p this object.
~DeluxeSensor(void) noexcept;
/// Returns the current execution policy of \p this object.
///
/// \see \c rosa::deluxe::DeluxeExecutionPolicy
///
/// \note The returned reference is valid only as long as \c
/// rosa::deluxe::DeluxeSensor::setExecutionPolicy() is not called and \p this
/// object is not destroyed.
///
/// \return \c rosa::deluxe::DeluxeSensor::ExecutionPolicy
const DeluxeExecutionPolicy &executionPolicy(void) const noexcept;
/// Sets the current execution policy of \p this object to \p EP.
///
/// \see \c rosa::deluxe::DeluxeExecutionPolicy
///
/// \note \p EP is set only if it can handle \p this object.
///
/// \param EP the new execution policy for \p this object
///
/// \return if \p EP was successfully set for \p this object.
bool setExecutionPolicy(std::unique_ptr<DeluxeExecutionPolicy> &&EP) noexcept;
/// The *master* of \p this object, if any.
///
/// \see \c rosa::deluxe::DeluxeSensor::registerMaster
///
/// \return the *master* registered for \p this object
Optional<AgentHandle> master(void) const noexcept;
/// Registers a *master* for \p this object.
///
/// The new *master* is registered by overwriting the reference to any
/// already registered *master*. One can clear the registered reference by
/// passing an *empty* \c rosa::Optional object as actual argument.
///
/// \note The role of the referred *master* is validated by checking its
/// *kind*.
///
/// \note Any call to \c rosa::deluxe::DeluxeSensor::registerMaster should be
/// paired with a corresponding call of \c
/// rosa::deluxe::DeluxeAgent::registerSlave, which validates that
/// input/output types of master and slave matches.
///
/// \param _Master the *master* to register
///
/// \pre \p Master is empty or of kind \c rosa::deluxe::atoms::AgentKind:
/// \code
/// !_Master || unwrapAgent(*_Master).Kind == rosa::deluxe::atoms::AgentKind
/// \endcode
void registerMaster(const Optional<AgentHandle> _Master) noexcept;
/// Clears the simulation trigger handler of \p this object.
///
/// The function assigns \c rosa::deluxe::DeluxeSensor::SFP with \c nullptr.
void clearSimulationDataSource(void) noexcept;
/// Tells whether a simulation trigger handler is set for \p this object.
///
/// The function returns whether \c rosa::deluxe::DeluxeSensor::SFP is not
/// \c nullptr.
///
/// \return if a simulation trigger handler is set for \p this object.
bool simulationDataSourceIsSet(void) const noexcept;
/// Registers a simulation data source for \p this object.
///
/// A new simulation trigger handler wrapping \p SF is stored in
/// \c rosa::deluxe::DeluxeSensor::SFP by overwriting any already registered
/// simulation data source.
///
/// \todo Enforce SF does not potentially throw exception.
///
/// \tparam Ts types of elements of values provided by \p SF
///
/// \param SF function to generate value with
///
/// \pre \p Ts... match \c rosa::deluxe::DeluxeSensor::OutputType: \code
/// OutputType == TypeToken<Ts...>::Value
/// \endcode
template <typename... Ts>
void registerSimulationDataSource(
std::function<DeluxeTuple<Ts...>(void)> &&SF) noexcept;
private:
/// Sends a value to the *master* of \p this object.
///
/// \p Value is getting sent to \c rosa::deluxe::DeluxeSensor::Master if it
/// contains a valid handle for a \c rosa::deluxe::DeluxeAgent. The function
/// does nothing otherwise.
///
/// The elements from \p Value are sent one by one in separate messages to the
/// *master*.
///
/// \tparam Ts types of the elements in \p Value
/// \tparam S0 indices for accessing elements of \p Value
///
/// \param Value value to send
///
/// \note The second argument provides indices statically as template
/// arguments \p S0..., so its actual value is ignored.
///
/// \pre Statically, the indices match the elements: \code
/// sizeof...(Ts) == sizeof...(S0)
/// \endcode Dynamically, \p Ts match \c
/// rosa::deluxe::DeluxeSensor::OutputType: \code
/// OutputType == TypeToken<Ts...>::Value
/// \endcode
template <typename... Ts, size_t... S0>
void sendToMaster(const DeluxeTuple<Ts...> &Value, Seq<S0...>) noexcept;
/// Handles master-input and generates the next sensory value upon trigger
/// from the system.
///
/// Executes \c rosa::deluxe::DeluxeSensor::MFP for processing master-input
/// and data generating function \c rosa::deluxe::DeluxeSensor::FP or \c
/// rosa::deluxe::DeluxeSensor::SFP if set.
///
/// \note The only argument is a \c rosa::AtomConstant, hence its actual
/// value is ignored.
///
/// \pre Master-input is supposed to be completely received upon triggering:
/// \code
/// MasterInputNextPos == 0
/// \endcode
void handleTrigger(atoms::Trigger) noexcept;
/// Stores a new input value from the *master*.
///
/// The function stores \p Value at position \p Pos in \c
/// rosa::deluxe::DeluxeSensor::MasterInputValue and also sets the
/// flag \c rosa::deluxe::DeluxeSensor::MasterInputChanged. The function also
/// takes care of checking and updating \c
/// rosa::deluxe::DeluxeSensor::MasterInputNextPos: increments its value and
/// resets it to `0` when the last element is received.
///
/// \note Utilized by member functions of group \c
/// DeluxeSensorMasterInputHandlers.
///
/// \tparam T type of input to store
///
/// \param Id unique identifier of the *master*
/// \param Pos position of the value in the \c rosa::deluxe::DeluxeTuple
/// \param Value the input value to store
///
/// \pre The *master* with \p Id is registered, \p Pos is the expected
/// position of master-input, and the input from the *master* at position \p
/// Pos is expected to be of type \p T: \code
/// Master && masterId() == Id && Pos == MasterInputNextPos &&
/// typeAtPositionOfToken(MasterInputType, Pos) == TypeNumberOf<T>::Value
/// \endcode
template <typename T>
void saveMasterInput(id_t Id, token_size_t Pos, T Value) noexcept;
/// \defgroup DeluxeSensorMasterInputHandlers Master-input handlers of
/// rosa::deluxe::DeluxeSensor
///
/// Definition of member functions handling messages from the *master* with
/// different types of input
///
/// A *slave* generally needs to be prepared to deal with values of any
/// built-in type to handle messages from its *master*. Each type requires a
/// separate message handler, which are implemented by these functions. The
/// functions instantiate \c rosa::deluxe::DeluxeSensor::saveMasterInput with
/// the proper template argument and pass the content of the message on for
/// processing.
///
/// \note The member functions in this group are defined by \c
/// DSMASTERHANDLERDEF.
///
/// \note Keep these definitions in sync with \c rosa::BuiltinTypes.
///
///@{
DSMASTERHANDLERDEF(AtomValue)
DSMASTERHANDLERDEF(int16_t)
DSMASTERHANDLERDEF(int32_t)
DSMASTERHANDLERDEF(int64_t)
DSMASTERHANDLERDEF(int8_t)
DSMASTERHANDLERDEFN(long double, long_double)
DSMASTERHANDLERDEFN(std::string, std__string)
DSMASTERHANDLERDEF(uint16_t)
DSMASTERHANDLERDEF(uint32_t)
DSMASTERHANDLERDEF(uint64_t)
DSMASTERHANDLERDEF(uint8_t)
DSMASTERHANDLERDEF(unit_t)
DSMASTERHANDLERDEF(bool)
DSMASTERHANDLERDEF(double)
DSMASTERHANDLERDEF(float)
/// @}
};
template <typename... Ts, size_t... S0>
DeluxeSensor::H DeluxeSensor::triggerHandlerFromProcessingFunction(
std::function<void(std::pair<DeluxeTuple<Ts...>, bool>)> &&MF,
Seq<S0...>) noexcept {
using MT = DeluxeTuple<Ts...>;
STATIC_ASSERT(sizeof...(Ts) == sizeof...(S0), "inconsistent arguments");
ASSERT(MasterInputType == MT::TT);
// NOTE: Clang 6 warns about unused lambda captures; we suppress that
// warning (those variables need to be captured).
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunused-lambda-capture"
-#endif // defined __clang__
+ROSA_DISABLE_WARNING_PUSH;
+ROSA_DISABLE_WARNING_UNUSED_LAMBDA_CAPTURE;
return [ this, MF ](void) noexcept {
// Do not do anything for master-input type \c
// rosa::deluxe::EmptyDeluxeTuple.
if
constexpr(!std::is_same<MT, EmptyDeluxeTuple>::value) {
LOG_TRACE_STREAM << "DeluxeSensor " << FullName
<< " handles master-input." << std::endl;
// The assert must hold if \p this object was successfully constructed.
STATIC_ASSERT(
(true && ... &&
(static_cast<size_t>(static_cast<token_size_t>(S0)) == S0)),
"Unexpected error");
const auto MasterInputArg = std::make_pair(
// Get all elements of the tuple in a fold expression.
DeluxeTuple<Ts...>(*static_cast<const Ts *>(
MasterInputValue->pointerTo(static_cast<token_size_t>(S0)))...),
MasterInputChanged);
MasterInputChanged = false;
MF(MasterInputArg);
}
};
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif // defined __clang__
+ROSA_DISABLE_WARNING_POP;
}
template <typename T>
DeluxeSensor::H
DeluxeSensor::triggerHandlerFromDataSource(std::function<T(void)> &&F,
bool inSimulation) noexcept {
STATIC_ASSERT(IsDeluxeTuple<T>::Value, "not tuple type argument");
ASSERT(OutputType == T::TT);
return [ this, F, inSimulation ](void) noexcept {
// Get value and send it to master only if \p ExecutionPolicy allows it.
if (ExecutionPolicy->shouldProcess({})) {
LOG_TRACE_STREAM << "DeluxeSensor " << Name << " obtains next value."
<< std::endl;
sendToMaster(F(), seq_t<T::Length>());
} else {
LOG_TRACE_STREAM << "DeluxeSensor " << Name << " skips next value."
<< std::endl;
if (inSimulation) {
// But read input value in Simulation anyway as input values are
// provided for the highest execution frequency for simulation
(void)F();
}
}
};
}
template <typename MT, typename T, typename>
DeluxeSensor::DeluxeSensor(const AtomValue Kind, const id_t Id,
const std::string &Name, MessagingSystem &S,
std::function<void(std::pair<MT, bool>)> &&MF,
std::function<T(void)> &&F) noexcept
: Agent(Kind, Id, Name, S, THISMEMBER(handleTrigger),
DSMASTERHANDLERREF(AtomValue), DSMASTERHANDLERREF(int16_t),
DSMASTERHANDLERREF(int32_t), DSMASTERHANDLERREF(int64_t),
DSMASTERHANDLERREF(int8_t), DSMASTERHANDLERREF(long_double),
DSMASTERHANDLERREF(std__string), DSMASTERHANDLERREF(uint16_t),
DSMASTERHANDLERREF(uint32_t), DSMASTERHANDLERREF(uint64_t),
DSMASTERHANDLERREF(uint8_t), DSMASTERHANDLERREF(unit_t),
DSMASTERHANDLERREF(bool), DSMASTERHANDLERREF(double),
DSMASTERHANDLERREF(float)),
ExecutionPolicy(DeluxeExecutionPolicy::decimation(1)), OutputType(T::TT),
MasterInputType(MT::TT), MasterInputNextPos(0), MasterInputChanged(false),
MasterInputValue(new typename TokenizedStorageForTypeList<
typename UnwrapDeluxeTuple<MT>::Type>::Type()),
MFP(triggerHandlerFromProcessingFunction(std::move(MF),
seq_t<MT::Length>())),
FP(triggerHandlerFromDataSource(std::move(F), false)), SFP(nullptr) {
ASSERT(Kind == atoms::SensorKind);
LOG_TRACE_STREAM << "DeluxeSensor " << FullName << " is created."
<< std::endl;
ASSERT(inv());
}
template <typename... Ts>
void DeluxeSensor::registerSimulationDataSource(
std::function<DeluxeTuple<Ts...>(void)> &&SF) noexcept {
ASSERT(OutputType == TypeToken<Ts...>::Value);
SFP = triggerHandlerFromDataSource(std::move(SF), true);
ASSERT(inv());
}
template <typename... Ts, size_t... S0>
void DeluxeSensor::sendToMaster(const DeluxeTuple<Ts...> &Value,
Seq<S0...>) noexcept {
STATIC_ASSERT(sizeof...(Ts) == sizeof...(S0), "inconsistent arguments");
ASSERT(OutputType == TypeToken<Ts...>::Value);
// The assert must hold if \p this object was successfully constructed.
STATIC_ASSERT((true && ... &&
(static_cast<size_t>(static_cast<token_size_t>(S0)) == S0)),
"Unexpected error");
// Create a static constant array for these indices to be available as lvalue
// references when creating messages below. \c S0... when used directly in a
// fold expression is a temporary value, which would result in \c
// rosa::Message instances being created with rvalue references. Further, all
// other values would to copied into a temporary variable for making them
/// available as rvalue references (they are constant lvalue references here).
static constexpr std::array<token_size_t, sizeof...(S0)> Indices{{S0...}};
LOG_TRACE_STREAM << "DeluxeSensor " << FullName << "(" << Id
<< ") sends to master("
<< static_cast<bool>(Master && *Master) << "): " << Value
<< std::endl;
// There is a handle and the referred *master* is in a valid state.
if (Master && *Master) {
// Handle each element of the tuple in a fold expression.
(Master->sendMessage(Message::create(atoms::Slave::Value, Id, Indices[S0],
std::get<S0>(Value))),
...);
}
ASSERT(inv());
}
template <typename T>
void DeluxeSensor::saveMasterInput(id_t Id, token_size_t Pos,
T Value) noexcept {
ASSERT(Master && masterId() == Id && Pos == MasterInputNextPos &&
typeAtPositionOfToken(MasterInputType, Pos) == TypeNumberOf<T>::Value);
LOG_TRACE_STREAM << "DeluxeSensor " << FullName << "(" << Id
<< ") saves value from master: (" << static_cast<size_t>(Pos)
<< ") " << Value << std::endl;
// Save value.
*static_cast<T *>(MasterInputValue->pointerTo(Pos)) = Value;
// Update position of next value.
if (++MasterInputNextPos == lengthOfToken(MasterInputType)) {
MasterInputNextPos = 0;
}
// Set flag.
MasterInputChanged = true;
}
} // End namespace deluxe
} // End namespace rosa
#undef DSMASTERHANDLEREF
#undef DSMASTERHANDLEDEF
#undef DSMASTERHANDLEDEFN
#undef DSMASTERHANDLENAME
#endif // ROSA_DELUXE_DELUXESENSOR_HPP
diff --git a/include/rosa/support/diagnostics.h b/include/rosa/support/diagnostics.h
new file mode 100644
index 0000000..99b3fe4
--- /dev/null
+++ b/include/rosa/support/diagnostics.h
@@ -0,0 +1,55 @@
+//===-- rosa/support/diagnostics.h ------------------------------*- C++ -*-===//
+//
+// The RoSA Framework
+//
+// Distributed under the terms and conditions of the Boost Software License 1.0.
+// See accompanying file LICENSE.
+//
+// If you did not receive a copy of the license file, see
+// http://www.boost.org/LICENSE_1_0.txt.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file rosa/support/diagnostics.h
+///
+/// \author David Juhasz (david.juhasz@tuwien.ac.at)
+///
+/// \date 2020
+///
+/// \brief Facility for diagnostics.
+///
+//===----------------------------------------------------------------------===//
+
+#if defined(_MSC_VER)
+
+#define ROSA_DISABLE_WARNING_PUSH __pragma(warning(push))
+#define ROSA_DISABLE_WARNING_POP __pragma(warning(pop))
+
+#define ROSA_DISABLE_WARNING(warningNumber) \
+ __pragma(warning(disable : warningNumber))
+
+#define ROSA_DISABLE_WARNING_UNUSED_LAMBDA_CAPTURE
+#define ROSA_DISABLE_WARNING_ADDING_INT_TO_STRING
+
+#elif defined(__GNUC__) || defined(__clang__)
+
+#define _ROSA_DIAG_DO_PRAGMA(X) _Pragma(#X)
+
+#define ROSA_DISABLE_WARNING_PUSH _ROSA_DIAG_DO_PRAGMA(GCC diagnostic push)
+#define ROSA_DISABLE_WARNING_POP _ROSA_DIAG_DO_PRAGMA(GCC diagnostic pop)
+#define ROSA_DISABLE_WARNING(warningName) \
+ _ROSA_DIAG_DO_PRAGMA(GCC diagnostic ignored warningName)
+
+#define ROSA_DISABLE_WARNING_UNUSED_LAMBDA_CAPTURE \
+ ROSA_DISABLE_WARNING("-Wunused-lambda-capture")
+#define ROSA_DISABLE_WARNING_ADDING_INT_TO_STRING \
+ ROSA_DISABLE_WARNING("-Wstring-plus-int")
+
+#else
+
+#define ROSA_DISABLE_WARNING_PUSH
+#define ROSA_DISABLE_WARNING_POP
+#define ROSA_DISABLE_WARNING_UNUSED_LAMBDA_CAPTURE
+#define ROSA_DISABLE_WARNING_ADDING_INT_TO_STRING
+
+#endif

File Metadata

Mime Type
text/x-diff
Expires
Sun, Apr 27, 7:52 AM (1 d, 2 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
134486
Default Alt Text
(43 KB)

Event Timeline