Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F10550609
DeluxeSensor.hpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Size
17 KB
Referenced Files
None
Subscribers
None
DeluxeSensor.hpp
View Options
//===-- rosa/deluxe/DeluxeSensor.hpp ----------------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/deluxe/DeluxeSensor.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017-2019
///
/// \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"
/// 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, \
T Value) noexcept { \
saveMasterInput(MasterId, 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
class
DeluxeSensor
:
public
Agent
{
public
:
/// The type of values produced by \p this object.
///
/// That is the type of values \p this object sends to its *master*.
///
/// \see \c rosa::deluxe::DeluxeSensor::master
const
TypeNumber
OutputType
;
/// The type of values \p this object processes from its *master*.
///
/// \see \c rosa::deluxe::DeluxeSensor::master
const
TypeNumber
MasterInputType
;
private
:
/// 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 type 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 MT type of master-input processed by \p MF
///
/// \param MF function that processes master-input
///
/// \note A master-input type of \c rosa::unit_t indicates that \p this object
/// does not receive master-input, \p MF is never called if \p MT is \c
/// rosa::unit_t.
///
/// \return trigger handler function based on \p MF
///
/// \pre \p MT matches \c rosa::deluxe::DeluxeSensor::MasterInputType: \code
/// MasterInputType == TypeNumberOf<MT>::Value
/// \endcode
template
<
typename
MT
>
H
triggerHandlerFromProcessingFunction
(
std
::
function
<
void
(
std
::
pair
<
MT
,
bool
>
)
>
&&
MF
)
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
///
/// \return trigger handler function based on \p F
///
/// \pre \p T matches \c rosa::deluxe::DeluxeSensor::OutputType: \code
/// OutputType == TypeNumberOf<T>::Value
/// \endcode
template
<
typename
T
>
H
triggerHandlerFromDataSource
(
std
::
function
<
T
(
void
)
>
&&
F
)
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 T and \p MT is
/// not a built-in type.
///
/// \note If \p MT is \c rosa::unit_t, 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 built-in types:\code
/// TypeListSubsetOf<TypeList<MT, T>, BuiltinTypes>::Value
/// \endcode
/// Dynamically, the instance is created as of kind
/// \c rosa::deluxe::atoms::SensorKind:
/// \code
/// Kind == rosa::deluxe::atoms::SensorKind
/// \endcode
template
<
typename
MT
,
typename
T
,
typename
=
std
::
enable_if_t
<
TypeListSubsetOf
<
TypeList
<
MT
,
T
>
,
BuiltinTypes
>::
Value
>>
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
;
/// 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 T type of data provided by \p SF
///
/// \param SF function to generate value with
///
/// \pre \p T matches \c rosa::deluxe::DeluxeSensor::OutputType: \code
/// OutputType == TypeNumberOf<T>::Value
/// \endcode
template
<
typename
T
>
void
registerSimulationDataSource
(
std
::
function
<
T
(
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.
///
/// \tparam T type of the value to send
///
/// \param Value value to send
///
/// \pre \p T matches \c rosa::deluxe::DeluxeSensor::OutputType: \code
/// OutputType == TypeNumberOf<T>::Value
/// \endcode
template
<
typename
T
>
void
sendToMaster
(
const
T
&
Value
)
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.
void
handleTrigger
(
atoms
::
Trigger
)
noexcept
;
/// Stores a new input value from the *master*.
///
/// The function stores \p Value in \c
/// rosa::deluxe::DeluxeSensor::MasterInputValue and also sets the
/// corresponding flag \c rosa::deluxe::DeluxeSensor::MasterInputChanged.
///
/// \note Utilized by member functions of group \c
/// DeluxeSensorMasterInputHandlers.
///
/// \tparam T type of input to store
///
/// \param Id unique identifier of the *master*
/// \param Value the input value to store
///
/// \pre The *master* with \p Id is registered and the input from the *master*
/// is expected to be of type \p T: \code
/// Master && masterId() == Id && MasterInputType == TypeNumberOf<T>::Value
/// \endcode
template
<
typename
T
>
void
saveMasterInput
(
id_t
Id
,
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, except for \c rosa::unit_t, 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; but do no
/// include \c rosa::unit_t.
///
///@{
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
(
bool
)
DSMASTERHANDLERDEF
(
double
)
DSMASTERHANDLERDEF
(
float
)
/// @}
};
template
<
typename
MT
>
DeluxeSensor
::
H
DeluxeSensor
::
triggerHandlerFromProcessingFunction
(
std
::
function
<
void
(
std
::
pair
<
MT
,
bool
>
)
>
&&
MF
)
noexcept
{
ASSERT
(
MasterInputType
==
TypeNumberOf
<
MT
>::
Value
);
return
[
this
,
MF
](
void
)
noexcept
{
// Do not do anything for master-input type \c rosa::unit_t.
if
(
MasterInputType
!=
TypeNumberOf
<
unit_t
>::
Value
)
{
LOG_TRACE_STREAM
<<
"DeluxeSensor "
<<
Name
<<
" handles master-input."
<<
std
::
endl
;
const
auto
MasterInputArg
=
std
::
make_pair
(
*
static_cast
<
const
MT
*>
(
MasterInputValue
->
pointerTo
(
0
)),
MasterInputChanged
);
MasterInputChanged
=
false
;
MF
(
MasterInputArg
);
}
};
}
template
<
typename
T
>
DeluxeSensor
::
H
DeluxeSensor
::
triggerHandlerFromDataSource
(
std
::
function
<
T
(
void
)
>
&&
F
)
noexcept
{
ASSERT
(
OutputType
==
TypeNumberOf
<
T
>::
Value
);
return
[
this
,
F
](
void
)
noexcept
{
LOG_TRACE_STREAM
<<
"DeluxeSensor "
<<
Name
<<
" obtains next value."
<<
std
::
endl
;
sendToMaster
(
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
(
bool
),
DSMASTERHANDLERREF
(
double
),
DSMASTERHANDLERREF
(
float
)),
OutputType
(
TypeNumberOf
<
T
>::
Value
),
MasterInputType
(
TypeNumberOf
<
MT
>::
Value
),
MasterInputChanged
(
false
),
MasterInputValue
(
new
TokenizedStorage
<
MT
>
()),
MFP
(
triggerHandlerFromProcessingFunction
(
std
::
move
(
MF
))),
FP
(
triggerHandlerFromDataSource
(
std
::
move
(
F
))),
SFP
(
nullptr
)
{
ASSERT
(
Kind
==
atoms
::
SensorKind
);
LOG_TRACE
(
"DeluxeSensor is created."
);
}
template
<
typename
T
>
void
DeluxeSensor
::
registerSimulationDataSource
(
std
::
function
<
T
(
void
)
>
&&
SF
)
noexcept
{
ASSERT
(
OutputType
==
TypeNumberOf
<
T
>::
Value
);
SFP
=
triggerHandlerFromDataSource
(
std
::
move
(
SF
));
}
template
<
typename
T
>
void
DeluxeSensor
::
sendToMaster
(
const
T
&
Value
)
noexcept
{
ASSERT
(
OutputType
==
TypeNumberOf
<
T
>::
Value
);
// There is a handle and the referred *master* is in a valid state.
if
(
Master
&&
*
Master
)
{
Master
->
sendMessage
(
Message
::
create
(
atoms
::
Slave
::
Value
,
Id
,
Value
));
}
}
template
<
typename
T
>
void
DeluxeSensor
::
saveMasterInput
(
id_t
Id
,
T
Value
)
noexcept
{
ASSERT
(
Master
&&
masterId
()
==
Id
&&
MasterInputType
==
TypeNumberOf
<
T
>::
Value
);
*
static_cast
<
T
*>
(
MasterInputValue
->
pointerTo
(
0
))
=
Value
;
MasterInputChanged
=
true
;
}
}
// End namespace deluxe
}
// End namespace rosa
#undef DSMASTERHANDLEREF
#undef DSMASTERHANDLEDEF
#undef DSMASTERHANDLEDEFN
#undef DSMASTERHANDLENAME
#endif
// ROSA_DELUXE_DELUXESENSOR_HPP
File Metadata
Details
Attached
Mime Type
text/x-c++
Expires
Sun, May 31, 12:05 AM (1 d, 3 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
329439
Default Alt Text
DeluxeSensor.hpp (17 KB)
Attached To
Mode
R20 SoC_Rosa_repo
Attached
Detach File
Event Timeline
Log In to Comment