2016-06-15 23:48:41 +02:00
# ifndef DEVICEHANDLERBASE_H_
# define DEVICEHANDLERBASE_H_
# include <framework/action/ActionHelper.h>
# include <framework/action/HasActionsIF.h>
# include <framework/datapool/DataSet.h>
# include <framework/datapool/PoolVariableIF.h>
# include <framework/devicehandlers/DeviceCommunicationIF.h>
# include <framework/devicehandlers/DeviceHandlerIF.h>
# include <framework/health/HealthHelper.h>
# include <framework/modes/HasModesIF.h>
# include <framework/objectmanager/SystemObject.h>
# include <framework/objectmanager/SystemObjectIF.h>
# include <framework/parameters/ParameterHelper.h>
# include <framework/power/PowerSwitchIF.h>
# include <framework/returnvalues/HasReturnvaluesIF.h>
2018-07-12 16:29:32 +02:00
# include <framework/tasks/ExecutableObjectIF.h>
# include <framework/devicehandlers/DeviceHandlerFailureIsolation.h>
# include <framework/datapool/HkSwitchHelper.h>
# include <framework/serialize/SerialFixedArrayListAdapter.h>
2016-06-15 23:48:41 +02:00
# include <map>
2018-07-12 16:29:32 +02:00
# include <framework/ipc/MessageQueueIF.h>
# include <framework/tasks/PeriodicTaskIF.h>
namespace Factory {
void setStaticFrameworkObjectIds ( ) ;
}
2016-06-15 23:48:41 +02:00
class StorageManagerIF ;
/**
2019-08-28 14:50:24 +02:00
* \ defgroup devices Devices
* Contains all devices and the DeviceHandlerBase class .
*/
2019-10-27 13:38:08 +01:00
2019-08-28 14:50:24 +02:00
/**
2019-12-03 19:30:37 +01:00
* @ brief This is the abstract base class for device handlers .
* @ details
2019-08-28 14:50:24 +02:00
* Documentation : Dissertation Baetz p .138 , 139 , p .141 - 149
2016-06-15 23:48:41 +02:00
*
2019-10-27 13:38:08 +01:00
* It features handling of @ link DeviceHandlerIF : : Mode_t Modes @ endlink , communication with
* physical devices , using the @ link DeviceCommunicationIF , and communication with commanding objects .
*
2019-12-03 19:30:37 +01:00
* NOTE : RMAP is a standard which is used for FLP .
2019-10-27 13:38:08 +01:00
* RMAP communication is not mandatory for projects implementing the FSFW .
* However , the communication principles are similar to RMAP as there are two write and two send calls involved .
*
2016-06-15 23:48:41 +02:00
* It inherits SystemObject and thus can be created by the ObjectManagerIF .
*
2018-07-12 16:29:32 +02:00
* This class uses the opcode of ExecutableObjectIF to perform a step - wise execution .
2019-10-27 13:38:08 +01:00
* For each step an RMAP action is selected and executed . If data has been received ( GET_READ ) , the data will be interpreted .
* The action for each step can be defined by the child class but as most device handlers share a 4 - call
* ( sendRead - getRead - sendWrite - getWrite ) structure , a default implementation is provided .
2016-06-15 23:48:41 +02:00
*
* Device handler instances should extend this class and implement the abstract functions .
2019-08-28 14:50:24 +02:00
* Components and drivers can send so called cookies which are used for communication
2019-10-27 13:38:08 +01:00
* and contain information about the communcation ( e . g . slave address for I2C or RMAP structs ) .
2019-08-28 14:50:24 +02:00
*
2019-12-03 19:30:37 +01:00
* @ ingroup devices
2016-06-15 23:48:41 +02:00
*/
class DeviceHandlerBase : public DeviceHandlerIF ,
public HasReturnvaluesIF ,
2018-07-12 16:29:32 +02:00
public ExecutableObjectIF ,
2016-06-15 23:48:41 +02:00
public SystemObject ,
public HasModesIF ,
public HasHealthIF ,
public HasActionsIF ,
public ReceivesParameterMessagesIF {
2018-07-12 16:29:32 +02:00
friend void ( Factory : : setStaticFrameworkObjectIds ) ( ) ;
2016-06-15 23:48:41 +02:00
public :
/**
* The constructor passes the objectId to the SystemObject ( ) .
*
* @ param setObjectId the ObjectId to pass to the SystemObject ( ) Constructor
* @ param maxDeviceReplyLen the length the RMAP getRead call will be sent with
* @ param setDeviceSwitch the switch the device is connected to , for devices using two switches , overwrite getSwitches ( )
*/
2019-11-09 13:17:54 +01:00
DeviceHandlerBase ( uint32_t logicalAddress , object_id_t setObjectId ,
2016-06-15 23:48:41 +02:00
uint32_t maxDeviceReplyLen , uint8_t setDeviceSwitch ,
2019-11-05 19:30:02 +01:00
object_id_t deviceCommunication , uint32_t thermalStatePoolId =
PoolVariableIF : : NO_PARAMETER ,
2018-07-12 16:29:32 +02:00
uint32_t thermalRequestPoolId = PoolVariableIF : : NO_PARAMETER ,
FailureIsolationBase * fdirInstance = NULL , uint32_t cmdQueueSize = 20 ) ;
2016-06-15 23:48:41 +02:00
virtual MessageQueueId_t getCommandQueue ( void ) const ;
2019-08-28 14:50:24 +02:00
/**
2019-12-03 19:30:37 +01:00
* @ brief This function is the device handler base core component and is called periodically .
* @ details
* General sequence , showing where abstract virtual functions are called :
* If the State is SEND_WRITE :
* 1. Set the cookie state to COOKIE_UNUSED and read the command queue
* 2. Handles Device State Modes by calling doStateMachine ( ) .
* This function calls callChildStatemachine ( ) which calls the abstract functions
* doStartUp ( ) and doShutDown ( )
* 3. Check switch states by calling checkSwitchStates ( )
* 4. Decrements counter for timeout of replies by calling decrementDeviceReplyMap ( )
* 5. Performs FDIR check for failures
* 6. Calls hkSwitcher . performOperation ( )
* 7. If the device mode is MODE_OFF , return RETURN_OK . Otherwise , perform the Action property
* and performs depending on value specified
* by input value counter . The child class tells base class what to do by setting this value .
* - SEND_WRITE : Send data or commands to device by calling doSendWrite ( ) which calls
* sendMessage function of # communicationInterface
* and calls buildInternalCommand if the cookie state is COOKIE_UNUSED
* - GET_WRITE : Get ackknowledgement for sending by calling doGetWrite ( ) which calls
* getSendSuccess of # communicationInterface .
* Calls abstract functions scanForReply ( ) and interpretDeviceReply ( ) .
* - SEND_READ : Request reading data from device by calling doSendRead ( ) which calls
* requestReceiveMessage of # communcationInterface
* - GET_READ : Access requested reading data by calling doGetRead ( ) which calls
* readReceivedMessage of # communicationInterface
* @ param counter Specifies which Action to perform
* @ return RETURN_OK for successful execution
*/
2018-07-12 16:29:32 +02:00
virtual ReturnValue_t performOperation ( uint8_t counter ) ;
2016-06-15 23:48:41 +02:00
virtual ReturnValue_t initialize ( ) ;
/**
*
* @ param parentQueueId
*/
virtual void setParentQueue ( MessageQueueId_t parentQueueId ) ;
/**
* Destructor .
*/
virtual ~ DeviceHandlerBase ( ) ;
ReturnValue_t executeAction ( ActionId_t actionId ,
MessageQueueId_t commandedBy , const uint8_t * data , uint32_t size ) ;
Mode_t getTransitionSourceMode ( ) const ;
Submode_t getTransitionSourceSubMode ( ) const ;
virtual void getMode ( Mode_t * mode , Submode_t * submode ) ;
HealthState getHealth ( ) ;
ReturnValue_t setHealth ( HealthState health ) ;
virtual ReturnValue_t getParameter ( uint8_t domainId , uint16_t parameterId ,
2018-07-12 16:29:32 +02:00
ParameterWrapper * parameterWrapper ,
const ParameterWrapper * newValues , uint16_t startAtIndex ) ;
2018-07-13 18:28:26 +02:00
/**
* Implementation of ExecutableObjectIF function
*
* Used to setup the reference of the task , that executes this component
* @ param task_ Pointer to the taskIF of this task
*/
virtual void setTaskIF ( PeriodicTaskIF * task_ ) ;
2016-06-15 23:48:41 +02:00
protected :
/**
* The Returnvalues id of this class , required by HasReturnvaluesIF
*/
2018-07-12 16:29:32 +02:00
static const uint8_t INTERFACE_ID = CLASS_ID : : DEVICE_HANDLER_BASE ;
2016-06-15 23:48:41 +02:00
static const ReturnValue_t INVALID_CHANNEL = MAKE_RETURN_CODE ( 4 ) ;
2019-10-27 03:21:38 +01:00
static const ReturnValue_t APERIODIC_REPLY = MAKE_RETURN_CODE ( 5 ) ; //!< This is used to specify for replies from a device which are not replies to requests
2019-11-29 19:56:05 +01:00
static const ReturnValue_t IGNORE_REPLY_DATA = MAKE_RETURN_CODE ( 6 ) ; //!< Ignore parts of the received packet
static const ReturnValue_t IGNORE_FULL_PACKET = MAKE_RETURN_CODE ( 7 ) ; //!< Ignore full received packet
2016-06-15 23:48:41 +02:00
// static const ReturnValue_t ONE_SWITCH = MAKE_RETURN_CODE(8);
// static const ReturnValue_t TWO_SWITCHES = MAKE_RETURN_CODE(9);
static const ReturnValue_t NO_SWITCH = MAKE_RETURN_CODE ( 10 ) ;
static const ReturnValue_t COMMAND_MAP_ERROR = MAKE_RETURN_CODE ( 11 ) ;
static const ReturnValue_t NOTHING_TO_SEND = MAKE_RETURN_CODE ( 12 ) ;
//Mode handling error Codes
static const ReturnValue_t CHILD_TIMEOUT = MAKE_RETURN_CODE ( 0xE1 ) ;
static const ReturnValue_t SWITCH_FAILED = MAKE_RETURN_CODE ( 0xE2 ) ;
static const DeviceCommandId_t RAW_COMMAND_ID = - 1 ;
static const DeviceCommandId_t NO_COMMAND_ID = - 2 ;
static const MessageQueueId_t NO_COMMANDER = 0 ;
2019-10-22 00:06:11 +02:00
2016-06-15 23:48:41 +02:00
/**
* Pointer to the raw packet that will be sent .
*/
uint8_t * rawPacket ;
/**
* Size of the # rawPacket .
*/
uint32_t rawPacketLen ;
/**
* The mode the device handler is currently in .
*
* This should never be changed directly but only with setMode ( )
*/
Mode_t mode ;
/**
* The submode the device handler is currently in .
*
* This should never be changed directly but only with setMode ( )
*/
Submode_t submode ;
/**
2018-07-12 16:29:32 +02:00
* This is the counter value from performOperation ( ) .
2016-06-15 23:48:41 +02:00
*/
uint8_t pstStep ;
/**
* This will be used in the RMAP getRead command as expected length , is set by the constructor , can be modiefied at will .
*/
const uint32_t maxDeviceReplyLen ;
/**
* wiretapping flag :
*
* indicates either that all raw messages to and from the device should be sent to # theOneWhoWantsToReadRawTraffic
* or that all device TM should be downlinked to # theOneWhoWantsToReadRawTraffic
*/
enum WiretappingMode {
OFF = 0 , RAW = 1 , TM = 2
} wiretappingMode ;
/**
2018-07-12 16:29:32 +02:00
* A message queue that accepts raw replies
2016-06-15 23:48:41 +02:00
*
2018-07-12 16:29:32 +02:00
* Statically initialized in initialize ( ) to a configurable object . Used when there is no method
* of finding a recipient , ie raw mode and reporting erreonous replies
2016-06-15 23:48:41 +02:00
*/
2018-07-12 16:29:32 +02:00
MessageQueueId_t defaultRawReceiver ;
2016-06-15 23:48:41 +02:00
store_address_t storedRawData ;
/**
* the message queue which wants to read all raw traffic
*
* if # isWiretappingActive all raw communication from and to the device will be sent to this queue
*/
2018-07-12 16:29:32 +02:00
MessageQueueId_t requestedRawTraffic ;
2016-06-15 23:48:41 +02:00
/**
* the object used to set power switches
*/
PowerSwitchIF * powerSwitcher ;
/**
* Pointer to the IPCStore .
*
* This caches the pointer received from the objectManager in the constructor .
*/
StorageManagerIF * IPCStore ;
/**
* cached for init
*/
object_id_t deviceCommunicationId ;
/**
* Communication object used for device communication
*/
DeviceCommunicationIF * communicationInterface ;
/**
* Cookie used for communication
*/
Cookie * cookie ;
/**
* The MessageQueue used to receive device handler commands and to send replies .
*/
2018-07-12 16:29:32 +02:00
MessageQueueIF * commandQueue ;
2016-06-15 23:48:41 +02:00
/**
* this is the datapool variable with the thermal state of the device
*
* can be set to PoolVariableIF : : NO_PARAMETER to deactivate thermal checking
*/
uint32_t deviceThermalStatePoolId ;
/**
* this is the datapool variable with the thermal request of the device
*
* can be set to PoolVariableIF : : NO_PARAMETER to deactivate thermal checking
*/
uint32_t deviceThermalRequestPoolId ;
/**
* Taking care of the health
*/
HealthHelper healthHelper ;
ModeHelper modeHelper ;
ParameterHelper parameterHelper ;
/**
* Optional Error code
* Can be set in doStartUp ( ) , doShutDown ( ) and doTransition ( ) to signal cause for Transition failure .
*/
ReturnValue_t childTransitionFailure ;
uint32_t ignoreMissedRepliesCount ; //!< Counts if communication channel lost a reply, so some missed replys can be ignored.
2018-07-12 16:29:32 +02:00
FailureIsolationBase * fdirInstance ; //!< Pointer to the used FDIR instance. If not provided by child, default class is instantiated.
HkSwitchHelper hkSwitcher ;
2016-06-15 23:48:41 +02:00
bool defaultFDIRUsed ; //!< To correctly delete the default instance.
bool switchOffWasReported ; //!< Indicates if SWITCH_WENT_OFF was already thrown.
2018-07-13 18:28:26 +02:00
PeriodicTaskIF * executingTask ; //!< Pointer to the task which executes this component, is invalid before setTaskIF was called.
2018-07-12 16:29:32 +02:00
static object_id_t powerSwitcherId ; //!< Object which switches power on and off.
static object_id_t rawDataReceiverId ; //!< Object which receives RAW data by default.
static object_id_t defaultFDIRParentId ; //!< Object which may be the root cause of an identified fault.
2016-06-15 23:48:41 +02:00
/**
* Helper function to report a missed reply
*
* Can be overwritten by children to act on missed replies or to fake reporting Id .
*
* @ param id of the missed reply
*/
virtual void missedReply ( DeviceCommandId_t id ) ;
/**
* Send a reply to a received device handler command .
*
* This also resets # DeviceHandlerCommand to 0.
*
* @ param reply the reply type
* @ param parameter parameter for the reply
*/
void replyReturnvalueToCommand ( ReturnValue_t status ,
uint32_t parameter = 0 ) ;
/**
*
* @ param parameter2 additional parameter
*/
void replyToCommand ( ReturnValue_t status , uint32_t parameter = 0 ) ;
/**
* Set the device handler mode
*
* Sets # timeoutStart with every call .
*
* Sets # transitionTargetMode if necessary so transitional states can be entered from everywhere without breaking the state machine
* ( which relies on a correct # transitionTargetMode ) .
*
* The submode is left unchanged .
*
*
* @ param newMode
*/
void setMode ( Mode_t newMode ) ;
/**
* @ overload
* @ param submode
*/
void setMode ( Mode_t newMode , Submode_t submode ) ;
/**
* This is used to let the child class handle the transition from mode @ c _MODE_START_UP to @ c MODE_ON
*
* It is only called when the device handler is in mode @ c _MODE_START_UP . That means , the device switch ( es ) are already set to on .
* Device handler commands are read and can be handled by the child class . If the child class handles a command , it should also send
* an reply accordingly .
* If an Command is not handled ( ie # DeviceHandlerCommand is not @ c CMD_NONE , the base class handles rejecting the command and sends a reply .
* The replies for mode transitions are handled by the base class .
*
* If the device is started and ready for operation , the mode should be set to MODE_ON . It is possible to set the mode to _MODE_TO_ON to
* use the to on transition if available .
* If the power - up fails , the mode should be set to _MODE_POWER_DOWN which will lead to the device being powered off .
* If the device does not change the mode , the mode will be changed to _MODE_POWER_DOWN , after the timeout ( from getTransitionDelay ( ) ) has passed .
*
* # transitionFailure can be set to a failure code indicating the reason for a failed transition
*/
virtual void doStartUp ( ) = 0 ;
/**
* This is used to let the child class handle the transition from mode @ c _MODE_SHUT_DOWN to @ c _MODE_POWER_DOWN
*
* It is only called when the device handler is in mode @ c _MODE_SHUT_DOWN .
* Device handler commands are read and can be handled by the child class . If the child class handles a command , it should also send
* an reply accordingly .
* If an Command is not handled ( ie # DeviceHandlerCommand is not @ c CMD_NONE , the base class handles rejecting the command and sends a reply .
* The replies for mode transitions are handled by the base class .
*
* If the device ready to be switched off , the mode should be set to _MODE_POWER_DOWN .
* If the device should not be switched off , the mode can be changed to _MODE_TO_ON ( or MODE_ON if no transition is needed ) .
* If the device does not change the mode , the mode will be changed to _MODE_POWER_DOWN , when the timeout ( from getTransitionDelay ( ) ) has passed .
*
* # transitionFailure can be set to a failure code indicating the reason for a failed transition
*/
virtual void doShutDown ( ) = 0 ;
/**
* Do the transition to the main modes ( MODE_ON , MODE_NORMAL and MODE_RAW ) .
*
* If the transition is complete , the mode should be set to the target mode , which can be deduced from the current mode which is
* [ _MODE_TO_ON , _MODE_TO_NORMAL , _MODE_TO_RAW ]
*
* The intended target submode is already set . The origin submode can be read in subModeFrom .
*
* If the transition can not be completed , the child class can try to reach an working mode by setting the mode either directly
* or setting the mode to an transitional mode ( TO_ON , TO_NORMAL , TO_RAW ) if the device needs to be reconfigured .
*
* If nothing works , the child class can wait for the timeout and the base class will reset the mode to the mode where the transition
* originated from ( the child should report the reason for the failed transition ) .
*
* The intended way to send commands is to set a flag ( enum ) indicating which command is to be sent here
* and then to check in buildTransitionCommand ( ) for the flag . This flag can also be used by doStartUp ( ) and
* doShutDown ( ) to get a nice and clean implementation of buildTransitionCommand ( ) without switching through modes .
*
* When the the condition for the completion of the transition is met , the mode can be set , for example in the parseReply ( ) function .
*
* The default implementation goes into the target mode ;
*
* # transitionFailure can be set to a failure code indicating the reason for a failed transition
*
* @ param modeFrom the mode the transition originated from : [ MODE_ON , MODE_NORMAL , MODE_RAW and _MODE_POWER_DOWN ( if the mode changed from _MODE_START_UP to _MODE_TO_ON ) ]
* @ param subModeFrom the subMode of modeFrom
*/
virtual void doTransition ( Mode_t modeFrom , Submode_t subModeFrom ) ;
/**
* Get the time needed to transit from modeFrom to modeTo .
*
* Used for the following transitions :
* modeFrom - > modeTo :
* MODE_ON - > [ MODE_ON , MODE_NORMAL , MODE_RAW , _MODE_POWER_DOWN ]
* MODE_NORMAL - > [ MODE_ON , MODE_NORMAL , MODE_RAW , _MODE_POWER_DOWN ]
* MODE_RAW - > [ MODE_ON , MODE_NORMAL , MODE_RAW , _MODE_POWER_DOWN ]
* _MODE_START_UP - > MODE_ON ( do not include time to set the switches , the base class got you covered )
*
* The default implementation returns 0 ;
*
* @ param modeFrom
* @ param modeTo
* @ return time in ms
*/
virtual uint32_t getTransitionDelayMs ( Mode_t modeFrom , Mode_t modeTo ) ;
/**
* Is the combination of mode and submode valid ?
*
* @ param mode
* @ param submode
* @ return
* - @ c RETURN_OK if valid
* - @ c RETURN_FAILED if invalid
*/
virtual ReturnValue_t isModeCombinationValid ( Mode_t mode ,
Submode_t submode ) ;
/**
* Get the Rmap action for the current step .
*
* The step number can be read from # pstStep .
*
* @ return The Rmap action to execute in this step
*/
virtual RmapAction_t getRmapAction ( ) ;
/**
* Build the device command to send for normal mode .
*
* This is only called in @ c MODE_NORMAL . If multiple submodes for @ c MODE_NORMAL are supported ,
* different commands can built returned depending on the submode .
*
* # rawPacket and # rawPacketLen must be set by this method to the packet to be sent .
*
* @ param [ out ] id the device command id that has been built
* @ return
* - @ c RETURN_OK when a command is to be sent
* - not @ c RETURN_OK when no command is to be sent
*/
virtual ReturnValue_t buildNormalDeviceCommand ( DeviceCommandId_t * id ) = 0 ;
/**
* Build the device command to send for a transitional mode .
*
* This is only called in @ c _MODE_TO_NORMAL , @ c _MODE_TO_ON , @ c _MODE_TO_RAW ,
* @ c _MODE_START_UP and @ c _MODE_TO_POWER_DOWN . So it is used by doStartUp ( ) and doShutDown ( ) as well as doTransition ( )
*
* A good idea is to implement a flag indicating a command has to be built and a variable containing the command number to be built
* and filling them in doStartUp ( ) , doShutDown ( ) and doTransition ( ) so no modes have to be checked here .
*
* # rawPacket and # rawPacketLen must be set by this method to the packet to be sent .
*
* @ param [ out ] id the device command id built
* @ return
* - @ c RETURN_OK when a command is to be sent
* - not @ c RETURN_OK when no command is to be sent
*/
virtual ReturnValue_t buildTransitionDeviceCommand (
DeviceCommandId_t * id ) = 0 ;
/**
* Build the device command to send for raw mode .
*
* This is only called in @ c MODE_RAW . It is for the rare case that in raw mode packets
* are to be sent by the handler itself . It is NOT needed for the raw commanding service .
* Its only current use is in the STR handler which gets its raw packets from a different
* source .
* Also it can be used for transitional commands , to get the device ready for @ c MODE_RAW
*
* As it is almost never used , there is a default implementation returning @ c NOTHING_TO_SEND .
*
* # rawPacket and # rawPacketLen must be set by this method to the packet to be sent .
*
* @ param [ out ] id the device command id built
* @ return
* - @ c RETURN_OK when a command is to be sent
* - not @ c NOTHING_TO_SEND when no command is to be sent
*/
virtual ReturnValue_t buildChildRawCommand ( ) ;
/**
* Build a device command packet from data supplied by a direct command .
*
* # rawPacket and # rawPacketLen should be set by this method to the packet to be sent .
*
* @ param deviceCommand the command to build , already checked against deviceCommandMap
* @ param commandData pointer to the data from the direct command
* @ param commandDataLen length of commandData
* @ return
* - @ c RETURN_OK when # rawPacket is valid
* - @ c RETURN_FAILED when # rawPacket is invalid and no data should be sent
*/
virtual ReturnValue_t buildCommandFromCommand (
DeviceCommandId_t deviceCommand , const uint8_t * commandData ,
size_t commandDataLen ) = 0 ;
/**
* fill the # deviceCommandMap
*
* called by the initialize ( ) of the base class
*
* This is used to let the base class know which replies are expected .
* There are different scenarios regarding this :
* - " Normal " commands . These are commands , that trigger a direct reply from the device . In this case , the id of the command should be added to the command map
* with a commandData_t where maxDelayCycles is set to the maximum expected number of PST cycles the reply will take . Then , scanForReply returns the id of the command and the base class can handle time - out and missing replies .
* - Periodic , unrequested replies . These are replies that , once enabled , are sent by the device on its own in a defined interval . In this case , the id of the reply or a placeholder id should be added to the deviceCommandMap
* with a commandData_t where maxDelayCycles is set to the maximum expected number of PST cycles between two replies ( also a tolerance should be added , as an FDIR message will be generated if it is missed ) .
* As soon as the replies are enabled , DeviceCommandInfo . periodic must be set to 1 , DeviceCommandInfo . delayCycles to DeviceCommandInfo . MaxDelayCycles . From then on , the base class handles the reception .
* Then , scanForReply returns the id of the reply or the placeholder id and the base class will take care of checking that all replies are received and the interval is correct .
* When the replies are disabled , DeviceCommandInfo . periodic must be set to 0 , DeviceCommandInfo . delayCycles to 0 ;
* - Aperiodic , unrequested replies . These are replies that are sent by the device without any preceding command and not in a defined interval . These are not entered in the deviceCommandMap but handled by returning @ c APERIODIC_REPLY in scanForReply ( ) .
*
*/
virtual void fillCommandAndReplyMap ( ) = 0 ;
2019-11-09 13:07:26 +01:00
/**
* @ brief Can be implemented by child handler to
* perform debugging
* @ details Example : Calling this in performOperation
2019-11-09 18:15:45 +01:00
* to track values like mode .
* @ param positionTracker Provide the child handler a way to know where the debugInterface was called
* @ param objectId Provide the child handler object Id to specify actions for spefic devices
* @ param parameter Supply a parameter of interest
2019-11-09 13:07:26 +01:00
* Please delete all debugInterface calls in DHB after debugging is finished !
*/
2019-11-09 18:15:45 +01:00
virtual void debugInterface ( uint8_t positionTracker = 0 , object_id_t objectId = 0 , uint32_t parameter = 0 ) ;
2019-11-09 13:07:26 +01:00
2016-06-15 23:48:41 +02:00
/**
* This is a helper method to facilitate inserting entries in the command map .
* @ param deviceCommand Identifier of the command to add .
* @ param maxDelayCycles The maximum number of delay cycles the command waits until it times out .
* @ param periodic Indicates if the command is periodic ( i . e . it is sent by the device repeatedly without request ) or not .
* Default is aperiodic ( 0 )
* @ return RETURN_OK when the command was successfully inserted , COMMAND_MAP_ERROR else .
*/
ReturnValue_t insertInCommandAndReplyMap ( DeviceCommandId_t deviceCommand ,
2019-11-05 19:25:00 +01:00
uint16_t maxDelayCycles , uint8_t periodic = 0 ,
2016-06-15 23:48:41 +02:00
bool hasDifferentReplyId = false , DeviceCommandId_t replyId = 0 ) ;
/**
* This is a helper method to insert replies in the reply map .
* @ param deviceCommand Identifier of the reply to add .
* @ param maxDelayCycles The maximum number of delay cycles the reply waits until it times out .
* @ param periodic Indicates if the command is periodic ( i . e . it is sent by the device repeatedly without request ) or not .
* Default is aperiodic ( 0 )
* @ return RETURN_OK when the command was successfully inserted , COMMAND_MAP_ERROR else .
*/
ReturnValue_t insertInReplyMap ( DeviceCommandId_t deviceCommand ,
uint16_t maxDelayCycles , uint8_t periodic = 0 ) ;
/**
* A simple command to add a command to the commandList .
* @ param deviceCommand The command to add
* @ return RETURN_OK if the command was successfully inserted , RETURN_FAILED else .
*/
2019-11-05 19:25:00 +01:00
ReturnValue_t insertInCommandMap ( DeviceCommandId_t deviceCommand ) ;
2016-06-15 23:48:41 +02:00
/**
* This is a helper method to facilitate updating entries in the reply map .
* @ param deviceCommand Identifier of the reply to update .
* @ param delayCycles The current number of delay cycles to wait . As stated in # fillCommandAndCookieMap , to disable periodic commands , this is set to zero .
* @ param maxDelayCycles The maximum number of delay cycles the reply waits until it times out . By passing 0 the entry remains untouched .
* @ param periodic Indicates if the command is periodic ( i . e . it is sent by the device repeatedly without request ) or not .
* Default is aperiodic ( 0 ) . Warning : The setting always overrides the value that was entered in the map .
* @ return RETURN_OK when the reply was successfully updated , COMMAND_MAP_ERROR else .
*/
ReturnValue_t updateReplyMapEntry ( DeviceCommandId_t deviceReply ,
uint16_t delayCycles , uint16_t maxDelayCycles ,
uint8_t periodic = 0 ) ;
/**
* Returns the delay cycle count of a reply .
* A count ! = 0 indicates that the command is already executed .
* @ param deviceCommand The command to look for
* @ return The current delay count . If the command does not exist ( should never happen ) it returns 0.
*/
uint8_t getReplyDelayCycles ( DeviceCommandId_t deviceCommand ) ;
2019-11-29 19:56:05 +01:00
2016-06-15 23:48:41 +02:00
/**
* Scans a buffer for a valid reply .
*
* This is used by the base class to check the data received from the RMAP stack for valid packets .
* It only checks if a valid packet starts at @ c start .
* It also only checks the structural validy of the packet , eg checksums lengths and protocol data . No
* information check is done , eg range checks etc .
*
* Errors should be reported directly , the base class does NOT report any errors based on the return
* value of this function .
*
2019-11-29 19:56:05 +01:00
* @ param start start of remaining buffer to be scanned
* @ param len length of remaining buffer to be scanned
* @ param [ out ] foundId the id of the data found in the buffer .
* @ param [ out ] foundLen length of the data found . Is to be set in function , buffer is scanned at previous position + foundLen .
2016-06-15 23:48:41 +02:00
* @ return
* - @ c RETURN_OK a valid packet was found at @ c start , @ c foundLen is valid
2019-10-27 03:21:38 +01:00
* - @ c RETURN_FAILED no reply could be found starting at @ c start , implies @ c foundLen is not valid , base class will call scanForReply ( ) again with + + start
* - @ c DeviceHandlerIF : : INVALID_DATA a packet was found but it is invalid , eg checksum error , implies @ c foundLen is valid , can be used to skip some bytes
* - @ c DeviceHandlerIF : : LENGTH_MISSMATCH @ c len is invalid
2019-11-29 19:56:05 +01:00
* - @ c DeviceHandlerIF : : IGNORE_REPLY_DATA Ignore this specific part of the packet
* - @ c DeviceHandlerIF : : IGNORE_FULL_PACKET Ignore the packet
2016-06-15 23:48:41 +02:00
* - @ c APERIODIC_REPLY if a valid reply is received that has not been requested by a command , but should be handled anyway ( @ see also fillCommandAndCookieMap ( ) )
*/
virtual ReturnValue_t scanForReply ( const uint8_t * start , uint32_t len ,
DeviceCommandId_t * foundId , uint32_t * foundLen ) = 0 ;
/**
* Interpret a reply from the device .
*
* This is called after scanForReply ( ) found a valid packet , it can be assumed that the length and structure is valid .
* This routine extracts the data from the packet into a DataSet and then calls handleDeviceTM ( ) , which either sends
2019-11-05 19:25:00 +01:00
* a TM packet or stores the data in the DataPool depending on whether the it was an external command .
2016-06-15 23:48:41 +02:00
* No packet length is given , as it should be defined implicitly by the id .
*
* @ param id the id found by scanForReply ( )
* @ param packet
* @ return
* - @ c RETURN_OK when the reply was interpreted .
* - @ c RETURN_FAILED when the reply could not be interpreted , eg . logical errors or range violations occurred
*/
virtual ReturnValue_t interpretDeviceReply ( DeviceCommandId_t id ,
2019-11-05 19:25:00 +01:00
const uint8_t * packet ) = 0 ;
2016-06-15 23:48:41 +02:00
/**
* Construct a command reply containing a raw reply .
*
* It gets space in the # IPCStore , copies data there , then sends a raw reply
* containing the store address .
*
* This method is virtual , as the STR has a different channel to send raw replies
* and overwrites it accordingly .
*
* @ param data data to send
* @ param len length of @ c data
* @ param sendTo the messageQueueId of the one to send to
* @ param isCommand marks the raw data as a command , the message then will be of type raw_command
*/
virtual void replyRawData ( const uint8_t * data , size_t len ,
MessageQueueId_t sendTo , bool isCommand = false ) ;
2018-07-12 16:29:32 +02:00
/**
* Calls replyRawData ( ) with # defaultRawReceiver , but checks if wiretapping is active and if so ,
* does not send the Data as the wiretapping will have sent it already
*/
void replyRawReplyIfnotWiretapped ( const uint8_t * data , size_t len ) ;
2016-06-15 23:48:41 +02:00
/**
* Return the switches connected to the device .
*
* The default implementation returns one switch set in the ctor .
*
*
* @ param [ out ] switches pointer to an array of switches
* @ param [ out ] numberOfSwitches length of returned array
* @ return
* - @ c RETURN_OK if the parameters were set
* - @ c RETURN_FAILED if no switches exist
*/
virtual ReturnValue_t getSwitches ( const uint8_t * * switches ,
uint8_t * numberOfSwitches ) ;
/**
* notify child about mode change
*/
virtual void modeChanged ( void ) ;
struct DeviceCommandInfo {
bool isExecuting ; //!< Indicates if the command is already executing.
2019-11-04 01:55:40 +01:00
uint8_t expectedReplies ; //!< Dynamic value to indicate how many replies are expected. Inititated with 0.
uint8_t expectedRepliesWhenEnablingReplyMap ; //!< Constant value which specifies expected replies when enabling reply map. Inititated in insertInCommandAndReplyMap()
2016-06-15 23:48:41 +02:00
MessageQueueId_t sendReplyTo ; //!< if this is != NO_COMMANDER, DHB was commanded externally and shall report everything to commander.
} ;
typedef std : : map < DeviceCommandId_t , DeviceCommandInfo > DeviceCommandMap ;
/**
* Enable the reply checking for a command
*
* Is only called , if the command was sent ( ie the getWriteReply was successful ) .
* Must ensure that all replies are activated and correctly linked to the command that initiated it .
* The default implementation looks for a reply with the same id as the command id in the replyMap or
* uses the alternativeReplyId if flagged so .
* When found , copies maxDelayCycles to delayCycles in the reply information and sets the command to
* expect one reply .
*
* Can be overwritten by the child , if a command activates multiple replies or replyId differs from
* commandId .
* Notes for child implementations :
* - If the command was not found in the reply map , NO_REPLY_EXPECTED MUST be returned .
* - A failure code may be returned if something went fundamentally wrong .
*
* @ param deviceCommand
* @ return - RETURN_OK if a reply was activated .
* - NO_REPLY_EXPECTED if there was no reply found . This is not an error case as many commands
* do not expect a reply .
*/
virtual ReturnValue_t enableReplyInReplyMap ( DeviceCommandMap : : iterator cmd ,
2019-11-05 19:25:00 +01:00
uint8_t expectedReplies = 1 , bool useAlternateId = false ,
2016-06-15 23:48:41 +02:00
DeviceCommandId_t alternateReplyID = 0 ) ;
/**
* get the state of the PCDU switches in the datapool
*
* @ return
* - @ c PowerSwitchIF : : SWITCH_ON if all switches specified by # switches are on
* - @ c PowerSwitchIF : : SWITCH_OFF one of the switches specified by # switches are off
* - @ c PowerSwitchIF : : RETURN_FAILED if an error occured
*/
ReturnValue_t getStateOfSwitches ( void ) ;
/**
* set all datapool variables that are update periodically in normal mode invalid
*
* Child classes should provide an implementation which sets all those variables invalid
* which are set periodically during any normal mode .
*/
virtual void setNormalDatapoolEntriesInvalid ( ) = 0 ;
2018-07-12 16:29:32 +02:00
/**
* build a list of sids and pass it to the # hkSwitcher
*/
virtual void changeHK ( Mode_t mode , Submode_t submode , bool enable ) ;
2016-06-15 23:48:41 +02:00
/**
* Children can overwrite this function to suppress checking of the command Queue
*
* This can be used when the child does not want to receive a command in a certain
* situation . Care must be taken that checking is not permanentely disabled as this
* would render the handler unusable .
*
* @ return whether checking the queue should NOT be done
*/
virtual bool dontCheckQueue ( ) ;
2019-11-09 13:29:12 +01:00
/**
* Used to retrieve logical address
* @ return
*/
virtual uint32_t getLogicalAddress ( ) ;
2016-06-15 23:48:41 +02:00
Mode_t getBaseMode ( Mode_t transitionMode ) ;
bool isAwaitingReply ( ) ;
void handleDeviceTM ( SerializeIF * dataSet , DeviceCommandId_t commandId ,
2018-07-12 16:29:32 +02:00
bool neverInDataPool = false , bool forceDirectTm = false ) ;
2016-06-15 23:48:41 +02:00
virtual ReturnValue_t checkModeCommand ( Mode_t mode , Submode_t submode ,
uint32_t * msToReachTheMode ) ;
virtual void startTransition ( Mode_t mode , Submode_t submode ) ;
virtual void setToExternalControl ( ) ;
virtual void announceMode ( bool recursive ) ;
virtual ReturnValue_t letChildHandleMessage ( CommandMessage * message ) ;
/**
* Overwrites SystemObject : : triggerEvent in order to inform FDIR " Helper " faster about executed events .
* This is a bit sneaky , but improves responsiveness of the device FDIR .
* @ param event The event to be thrown
* @ param parameter1 Optional parameter 1
* @ param parameter2 Optional parameter 2
*/
void triggerEvent ( Event event , uint32_t parameter1 = 0 ,
uint32_t parameter2 = 0 ) ;
/**
* Same as triggerEvent , but for forwarding if object is used as proxy .
*/
virtual void forwardEvent ( Event event , uint32_t parameter1 = 0 ,
uint32_t parameter2 = 0 ) const ;
/**
* Checks state of switches in conjunction with mode and triggers an event if they don ' t fit .
*/
virtual void checkSwitchState ( ) ;
/**
* Reserved for the rare case where a device needs to perform additional operation cyclically in OFF mode .
*/
virtual void doOffActivity ( ) ;
/**
* Reserved for the rare case where a device needs to perform additional operation cyclically in ON mode .
*/
virtual void doOnActivity ( ) ;
/**
* Checks if current mode is transitional mode .
* @ return true if mode is transitional , false else .
*/
bool isTransitionalMode ( ) ;
/**
* Checks if current handler state allows reception of external device commands .
* Default implementation allows commands only in plain MODE_ON and MODE_NORMAL .
* @ return RETURN_OK if commands are accepted , anything else otherwise .
*/
virtual ReturnValue_t acceptExternalDeviceCommands ( ) ;
bool commandIsExecuting ( DeviceCommandId_t commandId ) ;
/**
* Information about expected replies
*
* This is used to keep track of pending replies
*/
struct DeviceReplyInfo {
uint16_t maxDelayCycles ; //!< The maximum number of cycles the handler should wait for a reply to this command.
uint16_t delayCycles ; //!< The currently remaining cycles the handler should wait for a reply, 0 means there is no reply expected
uint8_t periodic ; //!< if this is !=0, the delayCycles will not be reset to 0 but to maxDelayCycles
DeviceCommandMap : : iterator command ; //!< The command that expects this reply.
} ;
2018-07-12 16:29:32 +02:00
2016-06-15 23:48:41 +02:00
/**
* Definition for the important reply Map .
*/
typedef std : : map < DeviceCommandId_t , DeviceReplyInfo > DeviceReplyMap ;
/**
* This map is used to check and track correct reception of all replies .
*
* It has multiple use :
* - it stores the information on pending replies . If a command is sent , the DeviceCommandInfo . count is incremented .
* - it is used to time - out missing replies . If a command is sent , the DeviceCommandInfo . DelayCycles is set to MaxDelayCycles .
* - it is queried to check if a reply from the device can be interpreted . scanForReply ( ) returns the id of the command a reply was found for .
* The reply is ignored in the following cases :
* - No entry for the returned id was found
* - The deviceReplyInfo . delayCycles is = = 0
*/
DeviceReplyMap deviceReplyMap ;
2018-07-12 16:29:32 +02:00
/**
* Information about commands
*/
DeviceCommandMap deviceCommandMap ;
ActionHelper actionHelper ;
2019-10-22 00:06:11 +02:00
2018-07-12 16:29:32 +02:00
private :
2019-11-09 13:29:12 +01:00
2016-06-15 23:48:41 +02:00
/**
* State a cookie is in .
*
* Used to keep track of the state of the RMAP communication .
*/
enum CookieState_t {
COOKIE_UNUSED , //!< The Cookie is unused
COOKIE_WRITE_READY , //!< There's data available to send.
COOKIE_READ_SENT , //!< A sendRead command was sent with this cookie
COOKIE_WRITE_SENT //!< A sendWrite command was sent with this cookie
} ;
/**
* Information about a cookie .
*
* This is stored in a map for each cookie , to not only track the state , but also information
* about the sent command . Tracking this information is needed as
* the state of a commandId ( waiting for reply ) is done when a RMAP write reply is received .
*/
struct CookieInfo {
CookieState_t state ;
DeviceCommandMap : : iterator pendingCommand ;
} ;
/**
* Info about the # cookie
*
* Used to track the state of the communication
*/
CookieInfo cookieInfo ;
2019-11-09 13:29:12 +01:00
/**
* cached from ctor for initialize ( )
*/
const uint32_t logicalAddress ;
2016-06-15 23:48:41 +02:00
/**
* Used for timing out mode transitions .
*
* Set when setMode ( ) is called .
*/
uint32_t timeoutStart ;
/**
* Delay for the current mode transition , used for time out
*/
uint32_t childTransitionDelay ;
/**
* The mode the current transition originated from
*
* This is private so the child can not change it and fuck up the timeouts
*
* IMPORTANT : This is not valid during _MODE_SHUT_DOWN and _MODE_START_UP ! ! ( it is _MODE_POWER_DOWN during this modes )
*
* is element of [ MODE_ON , MODE_NORMAL , MODE_RAW ]
*/
Mode_t transitionSourceMode ;
/**
* the submode of the source mode during a transition
*/
Submode_t transitionSourceSubMode ;
/**
* the switch of the device
*
* for devices using two switches override getSwitches ( )
*/
const uint8_t deviceSwitch ;
/**
* read the command queue
*/
void readCommandQueue ( void ) ;
/**
* Handle the device handler mode .
*
* - checks whether commands are valid for the current mode , rejects them accordingly
* - checks whether commanded mode transitions are required and calls handleCommandedModeTransition ( )
* - does the necessary action for the current mode or calls doChildStateMachine in modes @ c MODE_TO_ON and @ c MODE_TO_OFF
* - actions that happen in transitions ( eg setting a timeout ) are handled in setMode ( )
*/
void doStateMachine ( void ) ;
void buildRawDeviceCommand ( CommandMessage * message ) ;
void buildInternalCommand ( void ) ;
// /**
// * Send a reply with the current mode and submode.
// */
// void announceMode(void);
/**
* Decrement the counter for the timout of replies .
*
* This is called at the beginning of each cycle . It checks whether a reply has timed out ( that means a reply was expected
* but not received ) .
2019-10-27 03:21:38 +01:00
* In case the reply is periodic , the counter is simply set back to a specified value .
2016-06-15 23:48:41 +02:00
*/
void decrementDeviceReplyMap ( void ) ;
/**
* Convenience function to handle a reply .
*
* Called after scanForReply ( ) has found a packet . Checks if the found id is in the # deviceCommandMap , if so ,
* calls interpretDeviceReply ( DeviceCommandId_t id , const uint8_t * packet ) for further action .
*
* It also resets the timeout counter for the command id .
*
* @ param data the found packet
* @ param id the found id
2018-07-12 16:29:32 +02:00
* @ foundLen the length of the packet
2016-06-15 23:48:41 +02:00
*/
2018-07-12 16:29:32 +02:00
void handleReply ( const uint8_t * data , DeviceCommandId_t id , uint32_t foundLen ) ;
2016-06-15 23:48:41 +02:00
void replyToReply ( DeviceReplyMap : : iterator iter , ReturnValue_t status ) ;
/**
* Build and send a command to the device .
*
* This routine checks whether a raw or direct command has been received , checks the content of the received command and
* calls buildCommandFromCommand ( ) for direct commands or sets # rawpacket to the received raw packet .
* If no external command is received or the received command is invalid and the current mode is @ c MODE_NORMAL or a transitional mode ,
* it asks the child class to build a command ( via getNormalDeviceCommand ( ) or getTransitionalDeviceCommand ( ) and buildCommand ( ) ) and
* sends the command via RMAP .
*/
void doSendWrite ( void ) ;
/**
* Check if the RMAP sendWrite action was successful .
*
* Depending on the result , the following is done
* - if the device command was external commanded , a reply is sent indicating the result
* - if the action was successful , the reply timout counter is initialized
*/
void doGetWrite ( void ) ;
/**
* Send a RMAP getRead command .
*
* The size of the getRead command is # maxDeviceReplyLen .
* This is always executed , independently from the current mode .
*/
void doSendRead ( void ) ;
/**
* Check the getRead reply and the contained data .
*
* If data was received scanForReply ( ) and , if successful , handleReply ( ) are called .
* If the current mode is @ c MODE_RAW , the received packet is sent to the commanding object
* via commandQueue .
*/
void doGetRead ( void ) ;
/**
* Retrive data from the # IPCStore .
*
* @ param storageAddress
* @ param [ out ] data
* @ param [ out ] len
* @ return
* - @ c RETURN_OK @ c data is valid
* - @ c RETURN_FAILED IPCStore is NULL
* - the return value from the IPCStore if it was not @ c RETURN_OK
*/
ReturnValue_t getStorageData ( store_address_t storageAddress , uint8_t * * data ,
uint32_t * len ) ;
/**
* set all switches returned by getSwitches ( )
*
* @ param onOff on = = @ c SWITCH_ON ; off ! = @ c SWITCH_ON
*/
void commandSwitch ( ReturnValue_t onOff ) ;
/**
* @ param modeTo either @ c MODE_ON , MODE_NORMAL or MODE_RAW NOTHING ELSE ! ! !
*/
void setTransition ( Mode_t modeTo , Submode_t submodeTo ) ;
/**
* calls the right child function for the transitional submodes
*/
void callChildStatemachine ( ) ;
/**
* Switches the channel of the cookie used for the communication
*
*
* @ param newChannel the object Id of the channel to switch to
* @ return
* - @ c RETURN_OK when cookie was changed
* - @ c RETURN_FAILED when cookies could not be changed , eg because the newChannel is not enabled
* - @ c returnvalues of RMAPChannelIF : : isActive ( )
*/
ReturnValue_t switchCookieChannel ( object_id_t newChannelId ) ;
ReturnValue_t handleDeviceHandlerMessage ( CommandMessage * message ) ;
2019-10-27 03:21:38 +01:00
2016-06-15 23:48:41 +02:00
} ;
# endif /* DEVICEHANDLERBASE_H_ */