2016-06-15 23:48:41 +02:00
#include <framework/datapool/DataSet.h>
#include <framework/datapool/PoolVariable.h>
#include <framework/datapool/PoolVector.h>
2018-07-12 16:29:32 +02:00
#include <framework/devicehandlers/AcceptsDeviceResponsesIF.h>
2016-06-15 23:48:41 +02:00
#include <framework/devicehandlers/DeviceHandlerBase.h>
#include <framework/devicehandlers/DeviceTmReportingWrapper.h>
2020-04-19 13:24:10 +02:00
#include <framework/globalfunctions/CRC.h>
2016-06-15 23:48:41 +02:00
#include <framework/objectmanager/ObjectManager.h>
#include <framework/storagemanager/StorageManagerIF.h>
#include <framework/subsystem/SubsystemBase.h>
2018-07-12 16:29:32 +02:00
#include <framework/thermal/ThermalComponentIF.h>
#include <framework/ipc/QueueFactory.h>
2019-08-28 14:50:24 +02:00
#include <framework/serviceinterface/ServiceInterfaceStream.h>
2018-07-12 16:29:32 +02:00
object_id_t DeviceHandlerBase :: powerSwitcherId = 0 ;
object_id_t DeviceHandlerBase :: rawDataReceiverId = 0 ;
object_id_t DeviceHandlerBase :: defaultFDIRParentId = 0 ;
2016-06-15 23:48:41 +02:00
2020-04-19 13:24:10 +02:00
DeviceHandlerBase :: DeviceHandlerBase ( uint32_t ioBoardAddress ,
object_id_t setObjectId , uint32_t maxDeviceReplyLen ,
uint8_t setDeviceSwitch , object_id_t deviceCommunication ,
2020-03-23 19:16:01 +01:00
uint32_t thermalStatePoolId , uint32_t thermalRequestPoolId ,
2020-04-19 13:24:10 +02:00
FailureIsolationBase * fdirInstance , uint32_t cmdQueueSize ) :
2020-04-19 13:29:50 +02:00
SystemObject ( setObjectId ), rawPacket ( 0 ), rawPacketLen ( 0 ), mode ( MODE_OFF ),
submode ( SUBMODE_NONE ), pstStep ( 0 ), maxDeviceReplyLen ( maxDeviceReplyLen ),
wiretappingMode ( OFF ), defaultRawReceiver ( 0 ), storedRawData ( StorageManagerIF :: INVALID_ADDRESS ),
requestedRawTraffic ( 0 ), powerSwitcher ( NULL ), IPCStore ( NULL ),
deviceCommunicationId ( deviceCommunication ), communicationInterface ( NULL ),
cookie ( NULL ), commandQueue ( NULL ), deviceThermalStatePoolId ( thermalStatePoolId ),
deviceThermalRequestPoolId ( thermalRequestPoolId ), healthHelper ( this , setObjectId ),
modeHelper ( this ), parameterHelper ( this ), childTransitionFailure ( RETURN_OK ),
ignoreMissedRepliesCount ( 0 ), fdirInstance ( fdirInstance ), hkSwitcher ( this ),
defaultFDIRUsed ( fdirInstance == NULL ), switchOffWasReported ( false ),
executingTask ( NULL ), actionHelper ( this , NULL ), cookieInfo (), ioBoardAddress ( ioBoardAddress ),
timeoutStart ( 0 ), childTransitionDelay ( 5000 ), transitionSourceMode ( _MODE_POWER_DOWN ),
transitionSourceSubMode ( SUBMODE_NONE ), deviceSwitch ( setDeviceSwitch ) {
2020-04-19 13:24:10 +02:00
commandQueue = QueueFactory :: instance () -> createMessageQueue ( cmdQueueSize ,
CommandMessage :: MAX_MESSAGE_SIZE );
2016-06-15 23:48:41 +02:00
cookieInfo . state = COOKIE_UNUSED ;
insertInCommandMap ( RAW_COMMAND_ID );
2020-04-19 13:24:10 +02:00
if ( this -> fdirInstance == NULL ) {
this -> fdirInstance = new DeviceHandlerFailureIsolation ( setObjectId ,
defaultFDIRParentId );
2016-06-15 23:48:41 +02:00
}
}
DeviceHandlerBase ::~ DeviceHandlerBase () {
2020-04-19 13:24:10 +02:00
communicationInterface -> close ( cookie );
2016-06-15 23:48:41 +02:00
if ( defaultFDIRUsed ) {
delete fdirInstance ;
}
2018-07-12 16:29:32 +02:00
QueueFactory :: instance () -> deleteMessageQueue ( commandQueue );
2016-06-15 23:48:41 +02:00
}
2018-07-12 16:29:32 +02:00
ReturnValue_t DeviceHandlerBase :: performOperation ( uint8_t counter ) {
2016-06-15 23:48:41 +02:00
this -> pstStep = counter ;
2020-04-19 13:24:10 +02:00
2016-06-15 23:48:41 +02:00
if ( counter == 0 ) {
cookieInfo . state = COOKIE_UNUSED ;
readCommandQueue ();
doStateMachine ();
checkSwitchState ();
decrementDeviceReplyMap ();
fdirInstance -> checkForFailures ();
2018-07-12 16:29:32 +02:00
hkSwitcher . performOperation ();
2016-06-15 23:48:41 +02:00
}
if ( mode == MODE_OFF ) {
2018-07-12 16:29:32 +02:00
return RETURN_OK ;
2016-06-15 23:48:41 +02:00
}
2020-04-19 13:24:10 +02:00
switch ( getRmapAction ()) {
2016-06-15 23:48:41 +02:00
case SEND_WRITE :
if (( cookieInfo . state == COOKIE_UNUSED )) {
buildInternalCommand ();
}
doSendWrite ();
break ;
case GET_WRITE :
doGetWrite ();
break ;
case SEND_READ :
doSendRead ();
break ;
case GET_READ :
doGetRead ();
cookieInfo . state = COOKIE_UNUSED ;
break ;
default :
break ;
}
2020-02-03 22:34:15 +01:00
return RETURN_OK ;
}
2016-06-15 23:48:41 +02:00
void DeviceHandlerBase :: decrementDeviceReplyMap () {
for ( std :: map < DeviceCommandId_t , DeviceReplyInfo >:: iterator iter =
deviceReplyMap . begin (); iter != deviceReplyMap . end (); iter ++ ) {
if ( iter -> second . delayCycles != 0 ) {
iter -> second . delayCycles -- ;
if ( iter -> second . delayCycles == 0 ) {
if ( iter -> second . periodic != 0 ) {
iter -> second . delayCycles = iter -> second . maxDelayCycles ;
}
replyToReply ( iter , TIMEOUT );
missedReply ( iter -> first );
}
}
}
}
void DeviceHandlerBase :: readCommandQueue () {
if ( dontCheckQueue ()) {
return ;
}
CommandMessage message ;
2018-07-12 16:29:32 +02:00
ReturnValue_t result = commandQueue -> receiveMessage ( & message );
2016-06-15 23:48:41 +02:00
if ( result != RETURN_OK ) {
return ;
}
result = healthHelper . handleHealthCommand ( & message );
if ( result == RETURN_OK ) {
return ;
}
result = modeHelper . handleModeCommand ( & message );
if ( result == RETURN_OK ) {
return ;
}
result = actionHelper . handleActionMessage ( & message );
if ( result == RETURN_OK ) {
return ;
}
result = parameterHelper . handleParameterMessage ( & message );
if ( result == RETURN_OK ) {
return ;
}
result = handleDeviceHandlerMessage ( & message );
if ( result == RETURN_OK ) {
return ;
}
result = letChildHandleMessage ( & message );
if ( result == RETURN_OK ) {
return ;
}
replyReturnvalueToCommand ( CommandMessage :: UNKNOW_COMMAND );
}
void DeviceHandlerBase :: doStateMachine () {
switch ( mode ) {
case _MODE_START_UP :
case _MODE_SHUT_DOWN :
case _MODE_TO_NORMAL :
case _MODE_TO_ON :
case _MODE_TO_RAW : {
Mode_t currentMode = mode ;
callChildStatemachine ();
//Only do timeout if child did not change anything
if ( mode != currentMode ) {
break ;
}
uint32_t currentUptime ;
2018-07-12 16:29:32 +02:00
Clock :: getUptime ( & currentUptime );
2016-06-15 23:48:41 +02:00
if ( currentUptime - timeoutStart >= childTransitionDelay ) {
triggerEvent ( MODE_TRANSITION_FAILED , childTransitionFailure , 0 );
setMode ( transitionSourceMode , transitionSourceSubMode );
break ;
}
}
break ;
case _MODE_POWER_DOWN :
commandSwitch ( PowerSwitchIF :: SWITCH_OFF );
setMode ( _MODE_WAIT_OFF );
break ;
case _MODE_POWER_ON :
commandSwitch ( PowerSwitchIF :: SWITCH_ON );
setMode ( _MODE_WAIT_ON );
break ;
case _MODE_WAIT_ON : {
uint32_t currentUptime ;
2018-07-12 16:29:32 +02:00
Clock :: getUptime ( & currentUptime );
2016-06-15 23:48:41 +02:00
if ( currentUptime - timeoutStart >= powerSwitcher -> getSwitchDelayMs ()) {
triggerEvent ( MODE_TRANSITION_FAILED , PowerSwitchIF :: SWITCH_TIMEOUT ,
0 );
setMode ( _MODE_POWER_DOWN );
callChildStatemachine ();
break ;
}
ReturnValue_t switchState = getStateOfSwitches ();
if (( switchState == PowerSwitchIF :: SWITCH_ON )
|| ( switchState == NO_SWITCH )) {
//NOTE: TransitionSourceMode and -SubMode are set by handleCommandedModeTransition
childTransitionFailure = CHILD_TIMEOUT ;
setMode ( _MODE_START_UP );
callChildStatemachine ();
}
}
break ;
case _MODE_WAIT_OFF : {
uint32_t currentUptime ;
2018-07-12 16:29:32 +02:00
Clock :: getUptime ( & currentUptime );
2016-06-15 23:48:41 +02:00
if ( currentUptime - timeoutStart >= powerSwitcher -> getSwitchDelayMs ()) {
triggerEvent ( MODE_TRANSITION_FAILED , PowerSwitchIF :: SWITCH_TIMEOUT ,
0 );
setMode ( MODE_ERROR_ON );
break ;
}
ReturnValue_t switchState = getStateOfSwitches ();
if (( switchState == PowerSwitchIF :: SWITCH_OFF )
|| ( switchState == NO_SWITCH )) {
setMode ( _MODE_SWITCH_IS_OFF );
}
}
break ;
case MODE_OFF :
doOffActivity ();
break ;
case MODE_ON :
doOnActivity ();
break ;
case MODE_RAW :
case MODE_NORMAL :
case MODE_ERROR_ON :
break ;
case _MODE_SWITCH_IS_OFF :
setMode ( MODE_OFF , SUBMODE_NONE );
break ;
default :
triggerEvent ( OBJECT_IN_INVALID_MODE , mode , submode );
setMode ( _MODE_POWER_DOWN , 0 );
break ;
}
}
ReturnValue_t DeviceHandlerBase :: isModeCombinationValid ( Mode_t mode ,
Submode_t submode ) {
switch ( mode ) {
case MODE_OFF :
case MODE_ON :
case MODE_NORMAL :
case MODE_RAW :
if ( submode == SUBMODE_NONE ) {
return RETURN_OK ;
} else {
return INVALID_SUBMODE ;
}
default :
return HasModesIF :: INVALID_MODE ;
}
}
2020-04-19 13:24:10 +02:00
ReturnValue_t DeviceHandlerBase :: insertInCommandAndReplyMap (
DeviceCommandId_t deviceCommand , uint16_t maxDelayCycles ,
uint8_t periodic , bool hasDifferentReplyId , DeviceCommandId_t replyId ) {
//No need to check, as we may try to insert multiple times.
2016-06-15 23:48:41 +02:00
insertInCommandMap ( deviceCommand );
if ( hasDifferentReplyId ) {
2020-04-19 13:24:10 +02:00
return insertInReplyMap ( replyId , maxDelayCycles , periodic );
2016-06-15 23:48:41 +02:00
} else {
2020-04-19 13:24:10 +02:00
return insertInReplyMap ( deviceCommand , maxDelayCycles , periodic );
2016-06-15 23:48:41 +02:00
}
}
ReturnValue_t DeviceHandlerBase :: insertInReplyMap ( DeviceCommandId_t replyId ,
2020-04-19 13:24:10 +02:00
uint16_t maxDelayCycles , uint8_t periodic ) {
2016-06-15 23:48:41 +02:00
DeviceReplyInfo info ;
info . maxDelayCycles = maxDelayCycles ;
info . periodic = periodic ;
info . delayCycles = 0 ;
info . command = deviceCommandMap . end ();
2020-04-19 13:24:10 +02:00
std :: pair < std :: map < DeviceCommandId_t , DeviceReplyInfo >:: iterator , bool > returnValue ;
returnValue = deviceReplyMap . insert (
std :: pair < DeviceCommandId_t , DeviceReplyInfo > ( replyId , info ));
if ( returnValue . second ) {
2016-06-15 23:48:41 +02:00
return RETURN_OK ;
} else {
return RETURN_FAILED ;
}
}
2020-04-19 13:24:10 +02:00
ReturnValue_t DeviceHandlerBase :: insertInCommandMap (
DeviceCommandId_t deviceCommand ) {
2016-06-15 23:48:41 +02:00
DeviceCommandInfo info ;
info . expectedReplies = 0 ;
info . isExecuting = false ;
info . sendReplyTo = NO_COMMANDER ;
2020-04-19 13:24:10 +02:00
std :: pair < std :: map < DeviceCommandId_t , DeviceCommandInfo >:: iterator , bool > returnValue ;
returnValue = deviceCommandMap . insert (
std :: pair < DeviceCommandId_t , DeviceCommandInfo > ( deviceCommand ,
info ));
if ( returnValue . second ) {
2016-06-15 23:48:41 +02:00
return RETURN_OK ;
} else {
return RETURN_FAILED ;
}
}
2020-04-19 13:24:10 +02:00
ReturnValue_t DeviceHandlerBase :: updateReplyMapEntry (
DeviceCommandId_t deviceReply , uint16_t delayCycles ,
uint16_t maxDelayCycles , uint8_t periodic ) {
2016-06-15 23:48:41 +02:00
std :: map < DeviceCommandId_t , DeviceReplyInfo >:: iterator iter =
deviceReplyMap . find ( deviceReply );
if ( iter == deviceReplyMap . end ()) {
triggerEvent ( INVALID_DEVICE_COMMAND , deviceReply );
return RETURN_FAILED ;
} else {
DeviceReplyInfo * info = & ( iter -> second );
if ( maxDelayCycles != 0 ) {
info -> maxDelayCycles = maxDelayCycles ;
}
info -> delayCycles = delayCycles ;
info -> periodic = periodic ;
return RETURN_OK ;
}
}
void DeviceHandlerBase :: callChildStatemachine () {
if ( mode == _MODE_START_UP ) {
doStartUp ();
} else if ( mode == _MODE_SHUT_DOWN ) {
doShutDown ();
} else if ( mode & TRANSITION_MODE_CHILD_ACTION_MASK ) {
doTransition ( transitionSourceMode , transitionSourceSubMode );
}
}
void DeviceHandlerBase :: setTransition ( Mode_t modeTo , Submode_t submodeTo ) {
triggerEvent ( CHANGING_MODE , modeTo , submodeTo );
childTransitionDelay = getTransitionDelayMs ( mode , modeTo );
transitionSourceMode = mode ;
transitionSourceSubMode = submode ;
childTransitionFailure = CHILD_TIMEOUT ;
//transitionTargetMode is set by setMode
setMode (( modeTo | TRANSITION_MODE_CHILD_ACTION_MASK ), submodeTo );
}
void DeviceHandlerBase :: setMode ( Mode_t newMode , uint8_t newSubmode ) {
2018-07-12 16:29:32 +02:00
changeHK ( mode , submode , false );
2016-06-15 23:48:41 +02:00
submode = newSubmode ;
mode = newMode ;
modeChanged ();
setNormalDatapoolEntriesInvalid ();
if ( ! isTransitionalMode ()) {
modeHelper . modeChanged ( newMode , newSubmode );
announceMode ( false );
}
2018-07-12 16:29:32 +02:00
Clock :: getUptime ( & timeoutStart );
2016-06-15 23:48:41 +02:00
if ( mode == MODE_OFF ) {
DataSet mySet ;
PoolVariable < int8_t > thermalRequest ( deviceThermalRequestPoolId , & mySet ,
PoolVariableIF :: VAR_READ_WRITE );
mySet . read ();
if ( thermalRequest != ThermalComponentIF :: STATE_REQUEST_IGNORE ) {
thermalRequest = ThermalComponentIF :: STATE_REQUEST_NON_OPERATIONAL ;
}
mySet . commit ( PoolVariableIF :: VALID );
}
2018-07-12 16:29:32 +02:00
changeHK ( mode , submode , true );
2016-06-15 23:48:41 +02:00
}
void DeviceHandlerBase :: setMode ( Mode_t newMode ) {
setMode ( newMode , submode );
}
void DeviceHandlerBase :: replyReturnvalueToCommand ( ReturnValue_t status ,
uint32_t parameter ) {
2019-08-28 14:50:24 +02:00
//This is actually the reply protocol for raw and misc DH commands.
2016-06-15 23:48:41 +02:00
if ( status == RETURN_OK ) {
CommandMessage reply ( CommandMessage :: REPLY_COMMAND_OK , 0 , parameter );
2018-07-12 16:29:32 +02:00
commandQueue -> reply ( & reply );
2016-06-15 23:48:41 +02:00
} else {
CommandMessage reply ( CommandMessage :: REPLY_REJECTED , status , parameter );
2018-07-12 16:29:32 +02:00
commandQueue -> reply ( & reply );
2016-06-15 23:48:41 +02:00
}
}
void DeviceHandlerBase :: replyToCommand ( ReturnValue_t status ,
uint32_t parameter ) {
//Check if we reply to a raw command.
if ( cookieInfo . pendingCommand -> first == RAW_COMMAND_ID ) {
if ( status == NO_REPLY_EXPECTED ) {
status = RETURN_OK ;
}
replyReturnvalueToCommand ( status , parameter );
//Always delete data from a raw command.
IPCStore -> deleteData ( storedRawData );
return ;
}
//Check if we were externally commanded.
if ( cookieInfo . pendingCommand -> second . sendReplyTo != NO_COMMANDER ) {
MessageQueueId_t queueId = cookieInfo . pendingCommand -> second . sendReplyTo ;
if ( status == NO_REPLY_EXPECTED ) {
actionHelper . finish ( queueId , cookieInfo . pendingCommand -> first ,
RETURN_OK );
} else {
actionHelper . step ( 1 , queueId , cookieInfo . pendingCommand -> first ,
status );
}
}
}
void DeviceHandlerBase :: replyToReply ( DeviceReplyMap :: iterator iter ,
ReturnValue_t status ) {
//No need to check if iter exists, as this is checked by callers. If someone else uses the method, add check.
if ( iter -> second . command == deviceCommandMap . end ()) {
//Is most likely periodic reply. Silent return.
return ;
}
//Check if more replies are expected. If so, do nothing.
2020-04-19 13:24:10 +02:00
DeviceCommandInfo * info = & ( iter -> second . command -> second );
2016-06-15 23:48:41 +02:00
if ( -- info -> expectedReplies == 0 ) {
//Check if it was transition or internal command. Don't send any replies in that case.
if ( info -> sendReplyTo != NO_COMMANDER ) {
actionHelper . finish ( info -> sendReplyTo , iter -> first , status );
}
info -> isExecuting = false ;
}
}
void DeviceHandlerBase :: doSendWrite () {
if ( cookieInfo . state == COOKIE_WRITE_READY ) {
2020-04-19 13:24:10 +02:00
ReturnValue_t result = communicationInterface -> sendMessage ( cookie ,
2016-06-15 23:48:41 +02:00
rawPacket , rawPacketLen );
if ( result == RETURN_OK ) {
cookieInfo . state = COOKIE_WRITE_SENT ;
} else {
//always generate a failure event, so that FDIR knows what's up
triggerEvent ( DEVICE_SENDING_COMMAND_FAILED , result ,
cookieInfo . pendingCommand -> first );
replyToCommand ( result );
cookieInfo . state = COOKIE_UNUSED ;
cookieInfo . pendingCommand -> second . isExecuting = false ;
}
}
}
void DeviceHandlerBase :: doGetWrite () {
if ( cookieInfo . state != COOKIE_WRITE_SENT ) {
return ;
}
cookieInfo . state = COOKIE_UNUSED ;
2020-04-19 13:24:10 +02:00
ReturnValue_t result = communicationInterface -> getSendSuccess ( cookie );
2016-06-15 23:48:41 +02:00
if ( result == RETURN_OK ) {
if ( wiretappingMode == RAW ) {
2018-07-12 16:29:32 +02:00
replyRawData ( rawPacket , rawPacketLen , requestedRawTraffic , true );
2016-06-15 23:48:41 +02:00
}
2020-04-19 13:24:10 +02:00
//We need to distinguish here, because a raw command never expects a reply. (Could be done in eRIRM, but then child implementations need to be careful.
2016-06-15 23:48:41 +02:00
result = enableReplyInReplyMap ( cookieInfo . pendingCommand );
} else {
//always generate a failure event, so that FDIR knows what's up
triggerEvent ( DEVICE_SENDING_COMMAND_FAILED , result ,
cookieInfo . pendingCommand -> first );
}
if ( result != RETURN_OK ) {
cookieInfo . pendingCommand -> second . isExecuting = false ;
}
replyToCommand ( result );
}
void DeviceHandlerBase :: doSendRead () {
2020-04-19 13:24:10 +02:00
ReturnValue_t result ;
2020-03-27 14:44:54 +01:00
2020-04-19 13:24:10 +02:00
result = communicationInterface -> requestReceiveMessage ( cookie );
2016-06-15 23:48:41 +02:00
if ( result == RETURN_OK ) {
cookieInfo . state = COOKIE_READ_SENT ;
2020-04-19 13:24:10 +02:00
} else {
2016-06-15 23:48:41 +02:00
triggerEvent ( DEVICE_REQUESTING_REPLY_FAILED , result );
//We can't inform anyone, because we don't know which command was sent last.
//So, we need to wait for a timeout.
//but I think we can allow to ignore one missedReply.
ignoreMissedRepliesCount ++ ;
cookieInfo . state = COOKIE_UNUSED ;
}
}
void DeviceHandlerBase :: doGetRead () {
2020-04-19 13:24:10 +02:00
uint32_t receivedDataLen ;
2016-06-15 23:48:41 +02:00
uint8_t * receivedData ;
DeviceCommandId_t foundId = 0xFFFFFFFF ;
2020-04-19 13:24:10 +02:00
uint32_t foundLen = 0 ;
2016-06-15 23:48:41 +02:00
ReturnValue_t result ;
if ( cookieInfo . state != COOKIE_READ_SENT ) {
cookieInfo . state = COOKIE_UNUSED ;
return ;
}
cookieInfo . state = COOKIE_UNUSED ;
2020-04-19 13:24:10 +02:00
result = communicationInterface -> readReceivedMessage ( cookie , & receivedData ,
2016-06-15 23:48:41 +02:00
& receivedDataLen );
if ( result != RETURN_OK ) {
triggerEvent ( DEVICE_REQUESTING_REPLY_FAILED , result );
//I think we can allow to ignore one missedReply.
ignoreMissedRepliesCount ++ ;
return ;
}
2020-04-19 13:24:10 +02:00
if ( receivedDataLen == 0 )
2016-06-15 23:48:41 +02:00
return ;
if ( wiretappingMode == RAW ) {
2018-07-12 16:29:32 +02:00
replyRawData ( receivedData , receivedDataLen , requestedRawTraffic );
2016-06-15 23:48:41 +02:00
}
if ( mode == MODE_RAW ) {
2018-07-12 16:29:32 +02:00
replyRawReplyIfnotWiretapped ( receivedData , receivedDataLen );
2016-06-15 23:48:41 +02:00
} else {
//The loop may not execute more often than the number of received bytes (worst case).
//This approach avoids infinite loops due to buggy scanForReply routines (seen in bug 1077).
uint32_t remainingLength = receivedDataLen ;
for ( uint32_t count = 0 ; count < receivedDataLen ; count ++ ) {
result = scanForReply ( receivedData , remainingLength , & foundId ,
& foundLen );
switch ( result ) {
case RETURN_OK :
2018-07-12 16:29:32 +02:00
handleReply ( receivedData , foundId , foundLen );
2016-06-15 23:48:41 +02:00
break ;
case APERIODIC_REPLY : {
result = interpretDeviceReply ( foundId , receivedData );
if ( result != RETURN_OK ) {
2018-07-12 16:29:32 +02:00
replyRawReplyIfnotWiretapped ( receivedData , foundLen );
2016-06-15 23:48:41 +02:00
triggerEvent ( DEVICE_INTERPRETING_REPLY_FAILED , result ,
foundId );
}
}
break ;
case IGNORE_REPLY_DATA :
break ;
2020-04-19 13:41:43 +02:00
case IGNORE_FULL_PACKET :
return ;
2016-06-15 23:48:41 +02:00
default :
//We need to wait for timeout.. don't know what command failed and who sent it.
2018-07-12 16:29:32 +02:00
replyRawReplyIfnotWiretapped ( receivedData , foundLen );
2016-06-15 23:48:41 +02:00
triggerEvent ( DEVICE_READING_REPLY_FAILED , result , foundLen );
break ;
}
receivedData += foundLen ;
if ( remainingLength > foundLen ) {
remainingLength -= foundLen ;
} else {
return ;
}
}
}
}
ReturnValue_t DeviceHandlerBase :: getStorageData ( store_address_t storageAddress ,
2020-04-19 13:24:10 +02:00
uint8_t * * data , uint32_t * len ) {
uint32_t lenTmp ;
2016-06-15 23:48:41 +02:00
if ( IPCStore == NULL ) {
* data = NULL ;
* len = 0 ;
return RETURN_FAILED ;
}
ReturnValue_t result = IPCStore -> modifyData ( storageAddress , data , & lenTmp );
if ( result == RETURN_OK ) {
* len = lenTmp ;
return RETURN_OK ;
} else {
triggerEvent ( StorageManagerIF :: GET_DATA_FAILED , result ,
storageAddress . raw );
* data = NULL ;
* len = 0 ;
return result ;
}
}
2020-04-19 13:24:10 +02:00
ReturnValue_t DeviceHandlerBase :: initialize () {
ReturnValue_t result = SystemObject :: initialize ();
if ( result != RETURN_OK ) {
return result ;
}
communicationInterface = objectManager -> get < DeviceCommunicationIF > (
deviceCommunicationId );
if ( communicationInterface == NULL ) {
return RETURN_FAILED ;
}
result = communicationInterface -> open ( & cookie , ioBoardAddress ,
maxDeviceReplyLen );
if ( result != RETURN_OK ) {
return result ;
}
IPCStore = objectManager -> get < StorageManagerIF > ( objects :: IPC_STORE );
if ( IPCStore == NULL ) {
return RETURN_FAILED ;
}
AcceptsDeviceResponsesIF * rawReceiver = objectManager -> get <
AcceptsDeviceResponsesIF > ( rawDataReceiverId );
if ( rawReceiver == NULL ) {
return RETURN_FAILED ;
}
defaultRawReceiver = rawReceiver -> getDeviceQueue ();
powerSwitcher = objectManager -> get < PowerSwitchIF > ( powerSwitcherId );
if ( powerSwitcher == NULL ) {
return RETURN_FAILED ;
}
result = healthHelper . initialize ();
if ( result != RETURN_OK ) {
return result ;
}
result = modeHelper . initialize ();
if ( result != RETURN_OK ) {
return result ;
}
result = actionHelper . initialize ( commandQueue );
if ( result != RETURN_OK ) {
return result ;
}
result = fdirInstance -> initialize ();
if ( result != HasReturnvaluesIF :: RETURN_OK ) {
return result ;
}
result = parameterHelper . initialize ();
if ( result != HasReturnvaluesIF :: RETURN_OK ) {
return result ;
}
result = hkSwitcher . initialize ();
if ( result != HasReturnvaluesIF :: RETURN_OK ) {
return result ;
}
fillCommandAndReplyMap ();
//Set temperature target state to NON_OP.
DataSet mySet ;
PoolVariable < int8_t > thermalRequest ( deviceThermalRequestPoolId , & mySet ,
PoolVariableIF :: VAR_WRITE );
mySet . read ();
thermalRequest = ThermalComponentIF :: STATE_REQUEST_NON_OPERATIONAL ;
mySet . commit ( PoolVariableIF :: VALID );
return RETURN_OK ;
}
2016-06-15 23:48:41 +02:00
void DeviceHandlerBase :: replyRawData ( const uint8_t * data , size_t len ,
MessageQueueId_t sendTo , bool isCommand ) {
if ( IPCStore == NULL || len == 0 ) {
return ;
}
store_address_t address ;
ReturnValue_t result = IPCStore -> addData ( & address , data , len );
if ( result != RETURN_OK ) {
triggerEvent ( StorageManagerIF :: STORE_DATA_FAILED , result );
return ;
}
CommandMessage message ;
2020-04-19 13:24:10 +02:00
2019-08-28 14:50:24 +02:00
DeviceHandlerMessage :: setDeviceHandlerRawReplyMessage ( & message ,
2016-06-15 23:48:41 +02:00
getObjectId (), address , isCommand );
// this->DeviceHandlerCommand = CommandMessage::CMD_NONE;
2018-07-12 16:29:32 +02:00
result = commandQueue -> sendMessage ( sendTo , & message );
2016-06-15 23:48:41 +02:00
if ( result != RETURN_OK ) {
IPCStore -> deleteData ( address );
2018-07-12 16:29:32 +02:00
//Silently discard data, this indicates heavy TM traffic which should not be increased by additional events.
2016-06-15 23:48:41 +02:00
}
}
//Default child implementations
2020-04-19 13:24:10 +02:00
DeviceHandlerBase :: RmapAction_t DeviceHandlerBase :: getRmapAction () {
2016-06-15 23:48:41 +02:00
switch ( pstStep ) {
case 0 :
return SEND_WRITE ;
break ;
case 1 :
return GET_WRITE ;
break ;
case 2 :
return SEND_READ ;
break ;
case 3 :
return GET_READ ;
break ;
default :
break ;
}
return NOTHING ;
}
MessageQueueId_t DeviceHandlerBase :: getCommandQueue () const {
2018-07-12 16:29:32 +02:00
return commandQueue -> getId ();
2016-06-15 23:48:41 +02:00
}
void DeviceHandlerBase :: handleReply ( const uint8_t * receivedData ,
2018-07-12 16:29:32 +02:00
DeviceCommandId_t foundId , uint32_t foundLen ) {
2016-06-15 23:48:41 +02:00
ReturnValue_t result ;
DeviceReplyMap :: iterator iter = deviceReplyMap . find ( foundId );
if ( iter == deviceReplyMap . end ()) {
2018-07-12 16:29:32 +02:00
replyRawReplyIfnotWiretapped ( receivedData , foundLen );
2016-06-15 23:48:41 +02:00
triggerEvent ( DEVICE_UNKNOWN_REPLY , foundId );
return ;
}
DeviceReplyInfo * info = & ( iter -> second );
if ( info -> delayCycles != 0 ) {
if ( info -> periodic != 0 ) {
info -> delayCycles = info -> maxDelayCycles ;
} else {
info -> delayCycles = 0 ;
}
result = interpretDeviceReply ( foundId , receivedData );
if ( result != RETURN_OK ) {
//Report failed interpretation to FDIR.
2018-07-12 16:29:32 +02:00
replyRawReplyIfnotWiretapped ( receivedData , foundLen );
2016-06-15 23:48:41 +02:00
triggerEvent ( DEVICE_INTERPRETING_REPLY_FAILED , result , foundId );
}
replyToReply ( iter , result );
} else {
//Other completion failure messages are created by timeout.
2018-07-12 16:29:32 +02:00
//Powering down the device might take some time during which periodic replies may still come in.
2016-06-15 23:48:41 +02:00
if ( mode != _MODE_WAIT_OFF ) {
triggerEvent ( DEVICE_UNREQUESTED_REPLY , foundId );
}
}
}
2020-04-19 13:24:10 +02:00
ReturnValue_t DeviceHandlerBase :: switchCookieChannel ( object_id_t newChannelId ) {
DeviceCommunicationIF * newCommunication = objectManager -> get <
DeviceCommunicationIF > ( newChannelId );
if ( newCommunication != NULL ) {
ReturnValue_t result = newCommunication -> reOpen ( cookie , ioBoardAddress ,
maxDeviceReplyLen );
if ( result != RETURN_OK ) {
return result ;
}
return RETURN_OK ;
}
return RETURN_FAILED ;
}
2016-06-15 23:48:41 +02:00
void DeviceHandlerBase :: buildRawDeviceCommand ( CommandMessage * commandMessage ) {
storedRawData = DeviceHandlerMessage :: getStoreAddress ( commandMessage );
ReturnValue_t result = getStorageData ( storedRawData , & rawPacket ,
& rawPacketLen );
if ( result != RETURN_OK ) {
replyReturnvalueToCommand ( result , RAW_COMMAND_ID );
storedRawData . raw = StorageManagerIF :: INVALID_ADDRESS ;
} else {
2020-04-19 13:24:10 +02:00
cookieInfo . pendingCommand = deviceCommandMap . find (
( DeviceCommandId_t ) RAW_COMMAND_ID );
2016-06-15 23:48:41 +02:00
cookieInfo . pendingCommand -> second . isExecuting = true ;
cookieInfo . state = COOKIE_WRITE_READY ;
}
}
void DeviceHandlerBase :: commandSwitch ( ReturnValue_t onOff ) {
const uint8_t * switches ;
uint8_t numberOfSwitches = 0 ;
ReturnValue_t result = getSwitches ( & switches , & numberOfSwitches );
if ( result == RETURN_OK ) {
while ( numberOfSwitches > 0 ) {
powerSwitcher -> sendSwitchCommand ( switches [ numberOfSwitches - 1 ],
onOff );
numberOfSwitches -- ;
}
}
}
ReturnValue_t DeviceHandlerBase :: getSwitches ( const uint8_t ** switches ,
uint8_t * numberOfSwitches ) {
* switches = & deviceSwitch ;
* numberOfSwitches = 1 ;
return RETURN_OK ;
}
void DeviceHandlerBase :: modeChanged ( void ) {
}
ReturnValue_t DeviceHandlerBase :: enableReplyInReplyMap (
DeviceCommandMap :: iterator command , uint8_t expectedReplies ,
bool useAlternativeId , DeviceCommandId_t alternativeReply ) {
DeviceReplyMap :: iterator iter ;
if ( useAlternativeId ) {
iter = deviceReplyMap . find ( alternativeReply );
} else {
iter = deviceReplyMap . find ( command -> first );
}
if ( iter != deviceReplyMap . end ()) {
2020-04-19 13:24:10 +02:00
DeviceReplyInfo * info = & ( iter -> second );
2020-03-27 14:44:54 +01:00
info -> delayCycles = info -> maxDelayCycles ;
info -> command = command ;
2016-06-15 23:48:41 +02:00
command -> second . expectedReplies = expectedReplies ;
return RETURN_OK ;
} else {
return NO_REPLY_EXPECTED ;
}
}
void DeviceHandlerBase :: doTransition ( Mode_t modeFrom , Submode_t subModeFrom ) {
setMode ( getBaseMode ( mode ));
}
uint32_t DeviceHandlerBase :: getTransitionDelayMs ( Mode_t modeFrom ,
Mode_t modeTo ) {
return 0 ;
}
ReturnValue_t DeviceHandlerBase :: getStateOfSwitches ( void ) {
uint8_t numberOfSwitches = 0 ;
const uint8_t * switches ;
ReturnValue_t result = getSwitches ( & switches , & numberOfSwitches );
if (( result == RETURN_OK ) && ( numberOfSwitches != 0 )) {
while ( numberOfSwitches > 0 ) {
2020-04-19 13:24:10 +02:00
if ( powerSwitcher -> getSwitchState ( switches [ numberOfSwitches - 1 ])
== PowerSwitchIF :: SWITCH_OFF ) {
2016-06-15 23:48:41 +02:00
return PowerSwitchIF :: SWITCH_OFF ;
}
numberOfSwitches -- ;
}
return PowerSwitchIF :: SWITCH_ON ;
}
return NO_SWITCH ;
}
Mode_t DeviceHandlerBase :: getBaseMode ( Mode_t transitionMode ) {
//only child action special modes are handled, as a child should never see any base action modes
if ( transitionMode == _MODE_START_UP ) {
return _MODE_TO_ON ;
}
if ( transitionMode == _MODE_SHUT_DOWN ) {
return _MODE_POWER_DOWN ;
}
return transitionMode
& ~ ( TRANSITION_MODE_BASE_ACTION_MASK
| TRANSITION_MODE_CHILD_ACTION_MASK );
}
//SHOULDDO: Allow transition from OFF to NORMAL to reduce complexity in assemblies. And, by the way, throw away DHB and write a new one:
// - Include power and thermal completely, but more modular :-)
// - Don't use modes for state transitions, reduce FSM (Finte State Machine) complexity.
// - Modularization?
ReturnValue_t DeviceHandlerBase :: checkModeCommand ( Mode_t commandedMode ,
Submode_t commandedSubmode , uint32_t * msToReachTheMode ) {
if ( isTransitionalMode ()) {
return IN_TRANSITION ;
}
if (( mode == MODE_ERROR_ON ) && ( commandedMode != MODE_OFF )) {
return TRANS_NOT_ALLOWED ;
}
if (( commandedMode == MODE_NORMAL ) && ( mode == MODE_OFF )) {
return TRANS_NOT_ALLOWED ;
}
if (( commandedMode == MODE_ON ) && ( mode == MODE_OFF )
&& ( deviceThermalStatePoolId != PoolVariableIF :: NO_PARAMETER )) {
DataSet mySet ;
PoolVariable < int8_t > thermalState ( deviceThermalStatePoolId , & mySet ,
PoolVariableIF :: VAR_READ );
PoolVariable < int8_t > thermalRequest ( deviceThermalRequestPoolId , & mySet ,
PoolVariableIF :: VAR_READ );
mySet . read ();
if ( thermalRequest != ThermalComponentIF :: STATE_REQUEST_IGNORE ) {
if ( ! ThermalComponentIF :: isOperational ( thermalState )) {
2018-07-12 16:29:32 +02:00
triggerEvent ( ThermalComponentIF :: TEMP_NOT_IN_OP_RANGE ,
thermalState );
2016-06-15 23:48:41 +02:00
return NON_OP_TEMPERATURE ;
}
}
}
return isModeCombinationValid ( commandedMode , commandedSubmode );
}
void DeviceHandlerBase :: startTransition ( Mode_t commandedMode ,
Submode_t commandedSubmode ) {
switch ( commandedMode ) {
case MODE_ON :
if ( mode == MODE_OFF ) {
transitionSourceMode = _MODE_POWER_DOWN ;
transitionSourceSubMode = SUBMODE_NONE ;
setMode ( _MODE_POWER_ON , commandedSubmode );
//already set the delay for the child transition so we don't need to call it twice
childTransitionDelay = getTransitionDelayMs ( _MODE_START_UP ,
MODE_ON );
triggerEvent ( CHANGING_MODE , commandedMode , commandedSubmode );
DataSet mySet ;
PoolVariable < int8_t > thermalRequest ( deviceThermalRequestPoolId ,
& mySet , PoolVariableIF :: VAR_READ_WRITE );
mySet . read ();
if ( thermalRequest != ThermalComponentIF :: STATE_REQUEST_IGNORE ) {
thermalRequest = ThermalComponentIF :: STATE_REQUEST_OPERATIONAL ;
mySet . commit ( PoolVariableIF :: VALID );
}
} else {
setTransition ( MODE_ON , commandedSubmode );
}
break ;
case MODE_OFF :
if ( mode == MODE_OFF ) {
triggerEvent ( CHANGING_MODE , commandedMode , commandedSubmode );
setMode ( _MODE_POWER_DOWN , commandedSubmode );
} else {
//already set the delay for the child transition so we don't need to call it twice
childTransitionDelay = getTransitionDelayMs ( mode , _MODE_POWER_DOWN );
transitionSourceMode = _MODE_POWER_DOWN ;
transitionSourceSubMode = commandedSubmode ;
childTransitionFailure = CHILD_TIMEOUT ;
setMode ( _MODE_SHUT_DOWN , commandedSubmode );
triggerEvent ( CHANGING_MODE , commandedMode , commandedSubmode );
}
break ;
case MODE_RAW :
if ( mode != MODE_OFF ) {
setTransition ( MODE_RAW , commandedSubmode );
} else {
setMode ( MODE_RAW , commandedSubmode );
}
break ;
case MODE_NORMAL :
if ( mode != MODE_OFF ) {
setTransition ( MODE_NORMAL , commandedSubmode );
} else {
replyReturnvalueToCommand ( HasModesIF :: TRANS_NOT_ALLOWED );
}
break ;
}
}
void DeviceHandlerBase :: getMode ( Mode_t * mode , Submode_t * submode ) {
* mode = this -> mode ;
* submode = this -> submode ;
}
void DeviceHandlerBase :: setToExternalControl () {
healthHelper . setHealth ( EXTERNAL_CONTROL );
}
void DeviceHandlerBase :: announceMode ( bool recursive ) {
triggerEvent ( MODE_INFO , mode , submode );
}
bool DeviceHandlerBase :: dontCheckQueue () {
return false ;
}
void DeviceHandlerBase :: missedReply ( DeviceCommandId_t id ) {
if ( ignoreMissedRepliesCount > 0 ) {
ignoreMissedRepliesCount -- ;
} else {
triggerEvent ( DEVICE_MISSED_REPLY , id );
}
}
HasHealthIF :: HealthState DeviceHandlerBase :: getHealth () {
return healthHelper . getHealth ();
}
ReturnValue_t DeviceHandlerBase :: setHealth ( HealthState health ) {
healthHelper . setHealth ( health );
return HasReturnvaluesIF :: RETURN_OK ;
}
void DeviceHandlerBase :: checkSwitchState () {
if (( mode == MODE_ON || mode == MODE_NORMAL )) {
//We only check in ON and NORMAL, ignore RAW and ERROR_ON.
ReturnValue_t result = getStateOfSwitches ();
if ( result == PowerSwitchIF :: SWITCH_OFF && ! switchOffWasReported ) {
triggerEvent ( PowerSwitchIF :: SWITCH_WENT_OFF );
switchOffWasReported = true ;
}
} else {
switchOffWasReported = false ;
}
}
void DeviceHandlerBase :: doOnActivity () {
}
ReturnValue_t DeviceHandlerBase :: acceptExternalDeviceCommands () {
if (( mode != MODE_ON ) && ( mode != MODE_NORMAL )) {
return WRONG_MODE_FOR_COMMAND ;
}
return RETURN_OK ;
}
2018-07-12 16:29:32 +02:00
void DeviceHandlerBase :: replyRawReplyIfnotWiretapped ( const uint8_t * data ,
size_t len ) {
if (( wiretappingMode == RAW )
&& ( defaultRawReceiver == requestedRawTraffic )) {
//The raw packet was already sent by the wiretapping service
} else {
replyRawData ( data , len , defaultRawReceiver );
}
}
2016-06-15 23:48:41 +02:00
ReturnValue_t DeviceHandlerBase :: handleDeviceHandlerMessage (
CommandMessage * message ) {
ReturnValue_t result ;
switch ( message -> getCommand ()) {
case DeviceHandlerMessage :: CMD_WIRETAPPING :
switch ( DeviceHandlerMessage :: getWiretappingMode ( message )) {
case RAW :
wiretappingMode = RAW ;
2018-07-12 16:29:32 +02:00
requestedRawTraffic = commandQueue -> getLastPartner ();
2016-06-15 23:48:41 +02:00
break ;
case TM :
wiretappingMode = TM ;
2018-07-12 16:29:32 +02:00
requestedRawTraffic = commandQueue -> getLastPartner ();
2016-06-15 23:48:41 +02:00
break ;
case OFF :
wiretappingMode = OFF ;
break ;
default :
replyReturnvalueToCommand ( INVALID_COMMAND_PARAMETER );
wiretappingMode = OFF ;
return RETURN_OK ;
}
replyReturnvalueToCommand ( RETURN_OK );
return RETURN_OK ;
2020-04-19 13:24:10 +02:00
case DeviceHandlerMessage :: CMD_SWITCH_IOBOARD :
2016-06-15 23:48:41 +02:00
if ( mode != MODE_OFF ) {
replyReturnvalueToCommand ( WRONG_MODE_FOR_COMMAND );
} else {
2020-04-19 13:24:10 +02:00
result = switchCookieChannel (
DeviceHandlerMessage :: getIoBoardObjectId ( message ));
2016-06-15 23:48:41 +02:00
if ( result == RETURN_OK ) {
replyReturnvalueToCommand ( RETURN_OK );
} else {
2020-04-19 13:24:10 +02:00
replyReturnvalueToCommand ( CANT_SWITCH_IOBOARD );
2016-06-15 23:48:41 +02:00
}
}
return RETURN_OK ;
case DeviceHandlerMessage :: CMD_RAW :
if (( mode != MODE_RAW )) {
DeviceHandlerMessage :: clear ( message );
replyReturnvalueToCommand ( WRONG_MODE_FOR_COMMAND );
} else {
buildRawDeviceCommand ( message );
}
return RETURN_OK ;
default :
return RETURN_FAILED ;
}
}
void DeviceHandlerBase :: setParentQueue ( MessageQueueId_t parentQueueId ) {
modeHelper . setParentQueue ( parentQueueId );
healthHelper . setParentQeueue ( parentQueueId );
}
bool DeviceHandlerBase :: isAwaitingReply () {
std :: map < DeviceCommandId_t , DeviceReplyInfo >:: iterator iter ;
for ( iter = deviceReplyMap . begin (); iter != deviceReplyMap . end (); ++ iter ) {
if ( iter -> second . delayCycles != 0 ) {
return true ;
}
}
return false ;
}
ReturnValue_t DeviceHandlerBase :: letChildHandleMessage (
CommandMessage * message ) {
return RETURN_FAILED ;
}
void DeviceHandlerBase :: handleDeviceTM ( SerializeIF * data ,
2018-07-12 16:29:32 +02:00
DeviceCommandId_t replyId , bool neverInDataPool , bool forceDirectTm ) {
2016-06-15 23:48:41 +02:00
DeviceReplyMap :: iterator iter = deviceReplyMap . find ( replyId );
if ( iter == deviceReplyMap . end ()) {
triggerEvent ( DEVICE_UNKNOWN_REPLY , replyId );
return ;
}
2018-07-12 16:29:32 +02:00
DeviceTmReportingWrapper wrapper ( getObjectId (), replyId , data );
if ( iter -> second . command != deviceCommandMap . end ()) { //replies to a command
2016-06-15 23:48:41 +02:00
MessageQueueId_t queueId = iter -> second . command -> second . sendReplyTo ;
2018-07-12 16:29:32 +02:00
2016-06-15 23:48:41 +02:00
if ( queueId != NO_COMMANDER ) {
2018-07-12 16:29:32 +02:00
//This may fail, but we'll ignore the fault.
2016-06-15 23:48:41 +02:00
actionHelper . reportData ( queueId , replyId , data );
}
//This check should make sure we get any TM but don't get anything doubled.
2018-07-12 16:29:32 +02:00
if ( wiretappingMode == TM && ( requestedRawTraffic != queueId )) {
actionHelper . reportData ( requestedRawTraffic , replyId , & wrapper );
} else if ( forceDirectTm && ( defaultRawReceiver != queueId )) {
// hiding of sender needed so the service will handle it as unexpected Data, no matter what state
//(progress or completed) it is in
2020-04-19 13:24:10 +02:00
actionHelper . reportData ( defaultRawReceiver , replyId , & wrapper ,
true );
2018-07-12 16:29:32 +02:00
}
} else { //unrequested/aperiodic replies
if ( wiretappingMode == TM ) {
actionHelper . reportData ( requestedRawTraffic , replyId , & wrapper );
} else if ( forceDirectTm ) {
// hiding of sender needed so the service will handle it as unexpected Data, no matter what state
//(progress or completed) it is in
actionHelper . reportData ( defaultRawReceiver , replyId , & wrapper ,
true );
2016-06-15 23:48:41 +02:00
}
}
//Try to cast to DataSet and commit data.
if ( ! neverInDataPool ) {
DataSet * dataSet = dynamic_cast < DataSet *> ( data );
if ( dataSet != NULL ) {
dataSet -> commit ( PoolVariableIF :: VALID );
}
}
}
ReturnValue_t DeviceHandlerBase :: executeAction ( ActionId_t actionId ,
2020-04-19 13:24:10 +02:00
MessageQueueId_t commandedBy , const uint8_t * data , uint32_t size ) {
2016-06-15 23:48:41 +02:00
ReturnValue_t result = acceptExternalDeviceCommands ();
if ( result != HasReturnvaluesIF :: RETURN_OK ) {
return result ;
}
DeviceCommandMap :: iterator iter = deviceCommandMap . find ( actionId );
if ( iter == deviceCommandMap . end ()) {
result = COMMAND_NOT_SUPPORTED ;
} else if ( iter -> second . isExecuting ) {
result = COMMAND_ALREADY_SENT ;
} else {
result = buildCommandFromCommand ( actionId , data , size );
}
if ( result == RETURN_OK ) {
iter -> second . sendReplyTo = commandedBy ;
iter -> second . isExecuting = true ;
cookieInfo . pendingCommand = iter ;
cookieInfo . state = COOKIE_WRITE_READY ;
}
return result ;
}
void DeviceHandlerBase :: buildInternalCommand ( void ) {
2020-04-19 13:24:10 +02:00
//Neither Raw nor Direct could build a command
2016-06-15 23:48:41 +02:00
ReturnValue_t result = NOTHING_TO_SEND ;
DeviceCommandId_t deviceCommandId = NO_COMMAND_ID ;
if ( mode == MODE_NORMAL ) {
result = buildNormalDeviceCommand ( & deviceCommandId );
if ( result == BUSY ) {
debug << std :: hex << getObjectId ()
<< ": DHB::buildInternalCommand busy" << std :: endl ; //so we can track misconfigurations
result = NOTHING_TO_SEND ; //no need to report this
}
} else if ( mode == MODE_RAW ) {
result = buildChildRawCommand ();
deviceCommandId = RAW_COMMAND_ID ;
} else if ( mode & TRANSITION_MODE_CHILD_ACTION_MASK ) {
result = buildTransitionDeviceCommand ( & deviceCommandId );
} else {
return ;
}
if ( result == NOTHING_TO_SEND ) {
return ;
}
if ( result == RETURN_OK ) {
2020-04-19 13:24:10 +02:00
DeviceCommandMap :: iterator iter = deviceCommandMap . find (
deviceCommandId );
2016-06-15 23:48:41 +02:00
if ( iter == deviceCommandMap . end ()) {
result = COMMAND_NOT_SUPPORTED ;
} else if ( iter -> second . isExecuting ) {
debug << std :: hex << getObjectId ()
2018-07-12 16:29:32 +02:00
<< ": DHB::buildInternalCommand: Command "
<< deviceCommandId << " isExecuting" << std :: endl ; //so we can track misconfigurations
2016-06-15 23:48:41 +02:00
return ; //this is an internal command, no need to report a failure here, missed reply will track if a reply is too late, otherwise, it's ok
} else {
iter -> second . sendReplyTo = NO_COMMANDER ;
iter -> second . isExecuting = true ;
cookieInfo . pendingCommand = iter ;
cookieInfo . state = COOKIE_WRITE_READY ;
}
}
if ( result != RETURN_OK ) {
triggerEvent ( DEVICE_BUILDING_COMMAND_FAILED , result , deviceCommandId );
}
}
ReturnValue_t DeviceHandlerBase :: buildChildRawCommand () {
return NOTHING_TO_SEND ;
}
uint8_t DeviceHandlerBase :: getReplyDelayCycles (
DeviceCommandId_t deviceCommand ) {
DeviceReplyMap :: iterator iter = deviceReplyMap . find ( deviceCommand );
if ( iter == deviceReplyMap . end ()) {
return 0 ;
}
return iter -> second . delayCycles ;
}
Mode_t DeviceHandlerBase :: getTransitionSourceMode () const {
return transitionSourceMode ;
}
Submode_t DeviceHandlerBase :: getTransitionSourceSubMode () const {
return transitionSourceSubMode ;
}
void DeviceHandlerBase :: triggerEvent ( Event event , uint32_t parameter1 ,
uint32_t parameter2 ) {
fdirInstance -> triggerEvent ( event , parameter1 , parameter2 );
}
void DeviceHandlerBase :: forwardEvent ( Event event , uint32_t parameter1 ,
uint32_t parameter2 ) const {
fdirInstance -> triggerEvent ( event , parameter1 , parameter2 );
}
void DeviceHandlerBase :: doOffActivity () {
}
ReturnValue_t DeviceHandlerBase :: getParameter ( uint8_t domainId ,
uint16_t parameterId , ParameterWrapper * parameterWrapper ,
const ParameterWrapper * newValues , uint16_t startAtIndex ) {
ReturnValue_t result = fdirInstance -> getParameter ( domainId , parameterId ,
parameterWrapper , newValues , startAtIndex );
if ( result != INVALID_DOMAIN_ID ) {
return result ;
}
return INVALID_DOMAIN_ID ;
}
bool DeviceHandlerBase :: isTransitionalMode () {
2018-07-12 16:29:32 +02:00
return (( mode
& ( TRANSITION_MODE_BASE_ACTION_MASK
| TRANSITION_MODE_CHILD_ACTION_MASK )) != 0 );
2016-06-15 23:48:41 +02:00
}
bool DeviceHandlerBase :: commandIsExecuting ( DeviceCommandId_t commandId ) {
auto iter = deviceCommandMap . find ( commandId );
if ( iter != deviceCommandMap . end ()) {
return iter -> second . isExecuting ;
} else {
return false ;
}
}
2018-07-12 16:29:32 +02:00
void DeviceHandlerBase :: changeHK ( Mode_t mode , Submode_t submode , bool enable ) {
}
2018-07-13 18:28:26 +02:00
void DeviceHandlerBase :: setTaskIF ( PeriodicTaskIF * task_ ){
executingTask = task_ ;
}