Today's the day. Renamed platform to framework.
This commit is contained in:
280
devicehandlers/AssemblyBase.cpp
Normal file
280
devicehandlers/AssemblyBase.cpp
Normal file
@ -0,0 +1,280 @@
|
||||
#include <framework/devicehandlers/AssemblyBase.h>
|
||||
|
||||
AssemblyBase::AssemblyBase(object_id_t objectId, object_id_t parentId,
|
||||
uint16_t commandQueueDepth) :
|
||||
SubsystemBase(objectId, parentId, MODE_OFF, commandQueueDepth), internalState(
|
||||
STATE_NONE), recoveryState(RECOVERY_IDLE), recoveringDevice(
|
||||
childrenMap.end()), targetMode(MODE_OFF), targetSubmode(
|
||||
SUBMODE_NONE) {
|
||||
recoveryOffTimer.setTimeout(POWER_OFF_TIME_MS);
|
||||
}
|
||||
|
||||
AssemblyBase::~AssemblyBase() {
|
||||
}
|
||||
|
||||
ReturnValue_t AssemblyBase::handleCommandMessage(CommandMessage* message) {
|
||||
return handleHealthReply(message);
|
||||
}
|
||||
|
||||
void AssemblyBase::performChildOperation() {
|
||||
if (isInTransition()) {
|
||||
handleChildrenTransition();
|
||||
} else {
|
||||
handleChildrenChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void AssemblyBase::startTransition(Mode_t mode, Submode_t submode) {
|
||||
doStartTransition(mode, submode);
|
||||
if (modeHelper.isForced()) {
|
||||
triggerEvent(FORCING_MODE, mode, submode);
|
||||
} else {
|
||||
triggerEvent(CHANGING_MODE, mode, submode);
|
||||
}
|
||||
}
|
||||
|
||||
void AssemblyBase::doStartTransition(Mode_t mode, Submode_t submode) {
|
||||
targetMode = mode;
|
||||
targetSubmode = submode;
|
||||
internalState = STATE_SINGLE_STEP;
|
||||
ReturnValue_t result = commandChildren(mode, submode);
|
||||
if (result == NEED_SECOND_STEP) {
|
||||
internalState = STATE_NEED_SECOND_STEP;
|
||||
} else if (result != RETURN_OK) {
|
||||
//TODO: Debug
|
||||
debug << std::hex << getObjectId()
|
||||
<< ": AssemblyBase::commandChildren returned: " << result
|
||||
<< std::dec << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
bool AssemblyBase::isInTransition() {
|
||||
return (internalState != STATE_NONE) || (recoveryState != RECOVERY_IDLE);
|
||||
}
|
||||
|
||||
bool AssemblyBase::handleChildrenChanged() {
|
||||
if (childrenChangedMode) {
|
||||
ReturnValue_t result = checkChildrenState();
|
||||
if (result != RETURN_OK) {
|
||||
handleChildrenLostMode(result);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return handleChildrenChangedHealth();
|
||||
}
|
||||
}
|
||||
|
||||
void AssemblyBase::handleChildrenLostMode(ReturnValue_t result) {
|
||||
triggerEvent(CANT_KEEP_MODE, mode, submode);
|
||||
startTransition(MODE_OFF, SUBMODE_NONE);
|
||||
}
|
||||
|
||||
bool AssemblyBase::handleChildrenChangedHealth() {
|
||||
auto iter = childrenMap.begin();
|
||||
for (; iter != childrenMap.end(); iter++) {
|
||||
if (iter->second.healthChanged) {
|
||||
iter->second.healthChanged = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (iter == childrenMap.end()) {
|
||||
return false;
|
||||
}
|
||||
HealthState healthState = healthHelper.healthTable->getHealth(iter->first);
|
||||
if (healthState == HasHealthIF::NEEDS_RECOVERY) {
|
||||
triggerEvent(TRYING_RECOVERY);
|
||||
recoveryState = RECOVERY_STARTED;
|
||||
recoveringDevice = iter;
|
||||
doStartTransition(targetMode, targetSubmode);
|
||||
} else {
|
||||
triggerEvent(CHILD_CHANGED_HEALTH);
|
||||
doStartTransition(mode, submode);
|
||||
}
|
||||
if (modeHelper.isForced()) {
|
||||
triggerEvent(FORCING_MODE, targetMode, targetSubmode);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void AssemblyBase::handleChildrenTransition() {
|
||||
if (commandsOutstanding <= 0) {
|
||||
switch (internalState) {
|
||||
case STATE_NEED_SECOND_STEP:
|
||||
internalState = STATE_SECOND_STEP;
|
||||
commandChildren(targetMode, targetSubmode);
|
||||
return;
|
||||
case STATE_OVERWRITE_HEALTH: {
|
||||
internalState = STATE_SINGLE_STEP;
|
||||
ReturnValue_t result = commandChildren(mode, submode);
|
||||
if (result == NEED_SECOND_STEP) {
|
||||
internalState = STATE_NEED_SECOND_STEP;
|
||||
}
|
||||
return;
|
||||
}
|
||||
case STATE_NONE:
|
||||
//Valid state, used in recovery.
|
||||
case STATE_SINGLE_STEP:
|
||||
case STATE_SECOND_STEP:
|
||||
if (checkAndHandleRecovery()) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
ReturnValue_t result = checkChildrenState();
|
||||
if (result == RETURN_OK) {
|
||||
handleModeReached();
|
||||
} else {
|
||||
handleModeTransitionFailed(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AssemblyBase::handleModeReached() {
|
||||
internalState = STATE_NONE;
|
||||
setMode(targetMode, targetSubmode);
|
||||
}
|
||||
|
||||
void AssemblyBase::handleModeTransitionFailed(ReturnValue_t result) {
|
||||
//always accept transition to OFF, there is nothing we can do except sending an info event
|
||||
//In theory this should never happen, but we would risk an infinite loop otherwise
|
||||
if (targetMode == MODE_OFF) {
|
||||
triggerEvent(CHILD_PROBLEMS, result);
|
||||
internalState = STATE_NONE;
|
||||
//TODO: Maybe go to ERROR_ON here. Does this cause problems in subsystem?
|
||||
setMode(targetMode, targetSubmode);
|
||||
} else {
|
||||
if (handleChildrenChangedHealth()) {
|
||||
//If any health change is pending, handle that first.
|
||||
return;
|
||||
}
|
||||
triggerEvent(MODE_TRANSITION_FAILED, result);
|
||||
startTransition(MODE_OFF, SUBMODE_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
void AssemblyBase::sendHealthCommand(MessageQueueId_t sendTo,
|
||||
HealthState health) {
|
||||
CommandMessage command;
|
||||
HealthMessage::setHealthMessage(&command, HealthMessage::HEALTH_SET,
|
||||
health);
|
||||
if (commandQueue.sendMessage(sendTo, &command) == RETURN_OK) {
|
||||
commandsOutstanding++;
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t AssemblyBase::checkChildrenState() {
|
||||
if (targetMode == MODE_OFF) {
|
||||
return checkChildrenStateOff();
|
||||
} else {
|
||||
return checkChildrenStateOn(targetMode, targetSubmode);
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t AssemblyBase::checkChildrenStateOff() {
|
||||
for (std::map<object_id_t, ChildInfo>::iterator iter = childrenMap.begin();
|
||||
iter != childrenMap.end(); iter++) {
|
||||
if (checkChildOff(iter->first) != RETURN_OK) {
|
||||
return NOT_ENOUGH_CHILDREN_IN_CORRECT_STATE;
|
||||
}
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t AssemblyBase::checkChildOff(uint32_t objectId) {
|
||||
ChildInfo childInfo = childrenMap.find(objectId)->second;
|
||||
if (healthHelper.healthTable->isCommandable(objectId)) {
|
||||
if (childInfo.submode != SUBMODE_NONE) {
|
||||
return RETURN_FAILED;
|
||||
} else {
|
||||
if ((childInfo.mode != MODE_OFF)
|
||||
&& (childInfo.mode != DeviceHandlerIF::MODE_ERROR_ON)) {
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t AssemblyBase::checkModeCommand(Mode_t mode, Submode_t submode,
|
||||
uint32_t* msToReachTheMode) {
|
||||
|
||||
//always accept transition to OFF
|
||||
if (mode == MODE_OFF) {
|
||||
if (submode != SUBMODE_NONE) {
|
||||
return INVALID_SUBMODE;
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
if ((mode != MODE_ON) && (mode != DeviceHandlerIF::MODE_NORMAL)) {
|
||||
return INVALID_MODE;
|
||||
}
|
||||
|
||||
if (internalState != STATE_NONE) {
|
||||
return IN_TRANSITION;
|
||||
}
|
||||
|
||||
return isModeCombinationValid(mode, submode);
|
||||
}
|
||||
|
||||
ReturnValue_t AssemblyBase::handleHealthReply(CommandMessage* message) {
|
||||
if (message->getCommand() == HealthMessage::HEALTH_INFO) {
|
||||
HealthState health = HealthMessage::getHealth(message);
|
||||
if (health != EXTERNAL_CONTROL) {
|
||||
updateChildChangedHealth(message->getSender(), true);
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
if (message->getCommand() == HealthMessage::REPLY_HEALTH_SET
|
||||
|| (message->getCommand() == CommandMessage::REPLY_REJECTED
|
||||
&& message->getParameter2() == HealthMessage::HEALTH_SET)) {
|
||||
if (isInTransition()) {
|
||||
commandsOutstanding--;
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
|
||||
bool AssemblyBase::checkAndHandleRecovery() {
|
||||
switch (recoveryState) {
|
||||
case RECOVERY_STARTED:
|
||||
recoveryState = RECOVERY_WAIT;
|
||||
recoveryOffTimer.resetTimer();
|
||||
return true;
|
||||
case RECOVERY_WAIT:
|
||||
if (recoveryOffTimer.isBusy()) {
|
||||
return true;
|
||||
}
|
||||
triggerEvent(RECOVERY_STEP, 0);
|
||||
sendHealthCommand(recoveringDevice->second.commandQueue, HEALTHY);
|
||||
internalState = STATE_NONE;
|
||||
recoveryState = RECOVERY_ONGOING;
|
||||
//Don't check state!
|
||||
return true;
|
||||
case RECOVERY_ONGOING:
|
||||
triggerEvent(RECOVERY_STEP, 1);
|
||||
recoveryState = RECOVERY_ONGOING_2;
|
||||
recoveringDevice->second.healthChanged = false;
|
||||
//Device should be healthy again, so restart a transition.
|
||||
//Might be including second step, but that's already handled.
|
||||
doStartTransition(targetMode, targetSubmode);
|
||||
return true;
|
||||
case RECOVERY_ONGOING_2:
|
||||
triggerEvent(RECOVERY_DONE);
|
||||
//Now we're through, but not sure if it was successful.
|
||||
recoveryState = RECOVERY_IDLE;
|
||||
return false;
|
||||
case RECOVERY_IDLE:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void AssemblyBase::overwriteDeviceHealth(object_id_t objectId,
|
||||
HasHealthIF::HealthState oldHealth) {
|
||||
triggerEvent(OVERWRITING_HEALTH, objectId, oldHealth);
|
||||
internalState = STATE_OVERWRITE_HEALTH;
|
||||
modeHelper.setForced(true);
|
||||
sendHealthCommand(childrenMap[objectId].commandQueue, EXTERNAL_CONTROL);
|
||||
}
|
132
devicehandlers/AssemblyBase.h
Normal file
132
devicehandlers/AssemblyBase.h
Normal file
@ -0,0 +1,132 @@
|
||||
#ifndef ASSEMBLYBASE_H_
|
||||
#define ASSEMBLYBASE_H_
|
||||
|
||||
#include <framework/container/FixedArrayList.h>
|
||||
#include <framework/devicehandlers/DeviceHandlerBase.h>
|
||||
#include <framework/subsystem/SubsystemBase.h>
|
||||
|
||||
class AssemblyBase: public SubsystemBase {
|
||||
public:
|
||||
static const uint8_t INTERFACE_ID = ASSEMBLY_BASE;
|
||||
static const ReturnValue_t NEED_SECOND_STEP = MAKE_RETURN_CODE(0x01);
|
||||
static const ReturnValue_t NEED_TO_RECONFIGURE = MAKE_RETURN_CODE(0x02);
|
||||
static const ReturnValue_t MODE_FALLBACK = MAKE_RETURN_CODE(0x03);
|
||||
static const ReturnValue_t CHILD_NOT_COMMANDABLE = MAKE_RETURN_CODE(0x04);
|
||||
static const ReturnValue_t NEED_TO_CHANGE_HEALTH = MAKE_RETURN_CODE(0x05);
|
||||
static const ReturnValue_t NOT_ENOUGH_CHILDREN_IN_CORRECT_STATE =
|
||||
MAKE_RETURN_CODE(0xa1);
|
||||
|
||||
AssemblyBase(object_id_t objectId, object_id_t parentId, uint16_t commandQueueDepth = 8);
|
||||
virtual ~AssemblyBase();
|
||||
|
||||
protected:
|
||||
enum InternalState {
|
||||
STATE_NONE,
|
||||
STATE_OVERWRITE_HEALTH,
|
||||
STATE_NEED_SECOND_STEP,
|
||||
STATE_SINGLE_STEP,
|
||||
STATE_SECOND_STEP,
|
||||
} internalState;
|
||||
|
||||
enum RecoveryState {
|
||||
RECOVERY_IDLE,
|
||||
RECOVERY_STARTED,
|
||||
RECOVERY_ONGOING,
|
||||
RECOVERY_ONGOING_2,
|
||||
RECOVERY_WAIT
|
||||
} recoveryState; //!< Indicates if one of the children requested a recovery.
|
||||
ChildrenMap::iterator recoveringDevice;
|
||||
/**
|
||||
* the mode the current transition is trying to achieve.
|
||||
* Can be different from the modehelper.commandedMode!
|
||||
*/
|
||||
Mode_t targetMode;
|
||||
|
||||
/**
|
||||
* the submode the current transition is trying to achieve.
|
||||
* Can be different from the modehelper.commandedSubmode!
|
||||
*/
|
||||
Submode_t targetSubmode;
|
||||
|
||||
Countdown recoveryOffTimer;
|
||||
|
||||
static const uint32_t POWER_OFF_TIME_MS = 1000;
|
||||
|
||||
virtual ReturnValue_t handleCommandMessage(CommandMessage *message);
|
||||
|
||||
virtual ReturnValue_t handleHealthReply(CommandMessage *message);
|
||||
|
||||
virtual void performChildOperation();
|
||||
|
||||
bool handleChildrenChanged();
|
||||
|
||||
/**
|
||||
* This method is called if the children changed its mode in a way that the current
|
||||
* mode can't be kept.
|
||||
* Default behavior is to go to MODE_OFF.
|
||||
* @param result The failure code which was returned by checkChildrenState.
|
||||
*/
|
||||
virtual void handleChildrenLostMode(ReturnValue_t result);
|
||||
|
||||
bool handleChildrenChangedHealth();
|
||||
|
||||
virtual void handleChildrenTransition();
|
||||
|
||||
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
||||
uint32_t *msToReachTheMode);
|
||||
|
||||
virtual ReturnValue_t isModeCombinationValid(Mode_t mode,
|
||||
Submode_t submode) = 0;
|
||||
|
||||
virtual void startTransition(Mode_t mode, Submode_t submode);
|
||||
|
||||
virtual void doStartTransition(Mode_t mode, Submode_t submode);
|
||||
|
||||
virtual bool isInTransition();
|
||||
|
||||
virtual void handleModeReached();
|
||||
|
||||
virtual void handleModeTransitionFailed(ReturnValue_t result);
|
||||
|
||||
void sendHealthCommand(MessageQueueId_t sendTo, HealthState health);
|
||||
|
||||
//SHOULDDO: Change that OVERWRITE_HEALTH may be returned (or return internalState directly?)
|
||||
/**
|
||||
* command children to reach mode,submode
|
||||
*
|
||||
* set #commandsOutstanding correctly, or use executeTable()
|
||||
*
|
||||
* @param mode
|
||||
* @param submode
|
||||
* @return
|
||||
* - @c RETURN_OK if ok
|
||||
* - @c NEED_SECOND_STEP if children need to be commanded again
|
||||
*/
|
||||
virtual ReturnValue_t commandChildren(Mode_t mode, Submode_t submode) = 0;
|
||||
|
||||
//SHOULDDO: Remove wantedMode, wantedSubmode, as targetMode/submode is available?
|
||||
virtual ReturnValue_t checkChildrenStateOn(Mode_t wantedMode,
|
||||
Submode_t wantedSubmode) = 0;
|
||||
|
||||
virtual ReturnValue_t checkChildrenStateOff();
|
||||
|
||||
ReturnValue_t checkChildrenState();
|
||||
|
||||
virtual ReturnValue_t checkChildOff(uint32_t objectId);
|
||||
|
||||
/**
|
||||
* Manages recovery of a device
|
||||
* @return true if recovery is still ongoing, false else.
|
||||
*/
|
||||
bool checkAndHandleRecovery();
|
||||
|
||||
/**
|
||||
* Helper method to overwrite health state of one of the children.
|
||||
* Also sets state to STATE_OVERWRITE_HEATH.
|
||||
* @param objectId Must be a registered child.
|
||||
*/
|
||||
void overwriteDeviceHealth(object_id_t objectId, HasHealthIF::HealthState oldHealth);
|
||||
|
||||
};
|
||||
|
||||
#endif /* ASSEMBLYBASE_H_ */
|
42
devicehandlers/ChildHandlerBase.cpp
Normal file
42
devicehandlers/ChildHandlerBase.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
#include <framework/subsystem/SubsystemBase.h>
|
||||
#include <framework/devicehandlers/ChildHandlerBase.h>
|
||||
#include <framework/subsystem/SubsystemBase.h>
|
||||
|
||||
ChildHandlerBase::ChildHandlerBase(uint32_t ioBoardAddress,
|
||||
object_id_t setObjectId, object_id_t deviceCommunication,
|
||||
uint32_t maxDeviceReplyLen, uint8_t setDeviceSwitch,
|
||||
uint32_t thermalStatePoolId, uint32_t thermalRequestPoolId,
|
||||
uint32_t parent, FDIRBase* customFdir, uint32_t cmdQueueSize) :
|
||||
DeviceHandlerBase(ioBoardAddress, setObjectId, maxDeviceReplyLen,
|
||||
setDeviceSwitch, deviceCommunication, thermalStatePoolId,
|
||||
thermalRequestPoolId, (customFdir == NULL? &childHandlerFdir : customFdir), cmdQueueSize), parentId(
|
||||
parent), childHandlerFdir(setObjectId) {
|
||||
}
|
||||
|
||||
ChildHandlerBase::~ChildHandlerBase() {
|
||||
}
|
||||
|
||||
ReturnValue_t ChildHandlerBase::initialize() {
|
||||
ReturnValue_t result = DeviceHandlerBase::initialize();
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
MessageQueueId_t parentQueue = 0;
|
||||
|
||||
if (parentId != 0) {
|
||||
SubsystemBase *parent = objectManager->get<SubsystemBase>(parentId);
|
||||
if (parent == NULL) {
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
parentQueue = parent->getCommandQueue();
|
||||
|
||||
parent->registerChild(getObjectId());
|
||||
}
|
||||
|
||||
healthHelper.setParentQeueue(parentQueue);
|
||||
|
||||
modeHelper.setParentQueue(parentQueue);
|
||||
|
||||
return RETURN_OK;
|
||||
}
|
25
devicehandlers/ChildHandlerBase.h
Normal file
25
devicehandlers/ChildHandlerBase.h
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef PAYLOADHANDLERBASE_H_
|
||||
#define PAYLOADHANDLERBASE_H_
|
||||
|
||||
#include <framework/devicehandlers/ChildHandlerFDIR.h>
|
||||
#include <framework/devicehandlers/DeviceHandlerBase.h>
|
||||
|
||||
class ChildHandlerBase: public DeviceHandlerBase {
|
||||
public:
|
||||
ChildHandlerBase(uint32_t ioBoardAddress, object_id_t setObjectId,
|
||||
object_id_t deviceCommunication, uint32_t maxDeviceReplyLen,
|
||||
uint8_t setDeviceSwitch, uint32_t thermalStatePoolId,
|
||||
uint32_t thermalRequestPoolId, uint32_t parent,
|
||||
FDIRBase* customFdir = NULL,
|
||||
uint32_t cmdQueueSize = 20);
|
||||
virtual ~ChildHandlerBase();
|
||||
|
||||
virtual ReturnValue_t initialize();
|
||||
|
||||
protected:
|
||||
const uint32_t parentId;
|
||||
ChildHandlerFDIR childHandlerFdir;
|
||||
|
||||
};
|
||||
|
||||
#endif /* PAYLOADHANDLERBASE_H_ */
|
17
devicehandlers/ChildHandlerFDIR.cpp
Normal file
17
devicehandlers/ChildHandlerFDIR.cpp
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* ChildHandlerFDIR.cpp
|
||||
*
|
||||
* Created on: 08.02.2016
|
||||
* Author: baetz
|
||||
*/
|
||||
|
||||
#include <framework/devicehandlers/ChildHandlerFDIR.h>
|
||||
|
||||
ChildHandlerFDIR::ChildHandlerFDIR(object_id_t owner, object_id_t faultTreeParent, uint32_t recoveryCount) :
|
||||
DeviceHandlerFDIR(owner, faultTreeParent) {
|
||||
recoveryCounter.setFailureThreshold(recoveryCount);
|
||||
}
|
||||
|
||||
ChildHandlerFDIR::~ChildHandlerFDIR() {
|
||||
}
|
||||
|
27
devicehandlers/ChildHandlerFDIR.h
Normal file
27
devicehandlers/ChildHandlerFDIR.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* ChildHandlerFDIR.h
|
||||
*
|
||||
* Created on: 08.02.2016
|
||||
* Author: baetz
|
||||
*/
|
||||
|
||||
#ifndef FRAMEWORK_DEVICEHANDLERS_CHILDHANDLERFDIR_H_
|
||||
#define FRAMEWORK_DEVICEHANDLERS_CHILDHANDLERFDIR_H_
|
||||
|
||||
#include <framework/devicehandlers/DeviceHandlerFDIR.h>
|
||||
|
||||
/**
|
||||
* Very simple extension to normal FDIR.
|
||||
* Does not have a default fault tree parent and
|
||||
* allows to make the recovery count settable to 0.
|
||||
*/
|
||||
class ChildHandlerFDIR: public DeviceHandlerFDIR {
|
||||
public:
|
||||
ChildHandlerFDIR(object_id_t owner, object_id_t faultTreeParent =
|
||||
NO_FAULT_TREE_PARENT, uint32_t recoveryCount = 0);
|
||||
~ChildHandlerFDIR();
|
||||
protected:
|
||||
static const object_id_t NO_FAULT_TREE_PARENT = 0;
|
||||
};
|
||||
|
||||
#endif /* FRAMEWORK_DEVICEHANDLERS_CHILDHANDLERFDIR_H_ */
|
10
devicehandlers/Cookie.h
Normal file
10
devicehandlers/Cookie.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef COOKIE_H_
|
||||
#define COOKIE_H_
|
||||
|
||||
class Cookie{
|
||||
public:
|
||||
virtual ~Cookie(){}
|
||||
};
|
||||
|
||||
|
||||
#endif /* COOKIE_H_ */
|
63
devicehandlers/DeviceCommunicationIF.h
Normal file
63
devicehandlers/DeviceCommunicationIF.h
Normal file
@ -0,0 +1,63 @@
|
||||
#ifndef DEVICECOMMUNICATIONIF_H_
|
||||
#define DEVICECOMMUNICATIONIF_H_
|
||||
|
||||
#include <framework/devicehandlers/Cookie.h>
|
||||
#include <framework/returnvalues/HasReturnvaluesIF.h>
|
||||
|
||||
class DeviceCommunicationIF: public HasReturnvaluesIF {
|
||||
public:
|
||||
static const uint8_t INTERFACE_ID = DEVICE_COMMUNICATION_IF;
|
||||
|
||||
static const ReturnValue_t INVALID_COOKIE_TYPE = MAKE_RETURN_CODE(0x01);
|
||||
static const ReturnValue_t NOT_ACTIVE = MAKE_RETURN_CODE(0x02);
|
||||
static const ReturnValue_t INVALID_ADDRESS = MAKE_RETURN_CODE(0x03);
|
||||
static const ReturnValue_t TOO_MUCH_DATA = MAKE_RETURN_CODE(0x04);
|
||||
static const ReturnValue_t NULLPOINTER = MAKE_RETURN_CODE(0x05);
|
||||
static const ReturnValue_t PROTOCOL_ERROR = MAKE_RETURN_CODE(0x06);
|
||||
static const ReturnValue_t CANT_CHANGE_REPLY_LEN = MAKE_RETURN_CODE(0x07);
|
||||
|
||||
virtual ~DeviceCommunicationIF() {
|
||||
|
||||
}
|
||||
|
||||
virtual ReturnValue_t open(Cookie **cookie, uint32_t address,
|
||||
uint32_t maxReplyLen) = 0;
|
||||
|
||||
/**
|
||||
* Use an existing cookie to open a connection to a new DeviceCommunication.
|
||||
* The previous connection must not be closed.
|
||||
* If the returnvalue is not RETURN_OK, the cookie is unchanged and
|
||||
* can be used with the previous connection.
|
||||
*
|
||||
* @param cookie
|
||||
* @param address
|
||||
* @param maxReplyLen
|
||||
* @return
|
||||
*/
|
||||
virtual ReturnValue_t reOpen(Cookie *cookie, uint32_t address,
|
||||
uint32_t maxReplyLen) = 0;
|
||||
|
||||
virtual void close(Cookie *cookie) = 0;
|
||||
|
||||
//TODO can data be const?
|
||||
virtual ReturnValue_t sendMessage(Cookie *cookie, uint8_t *data,
|
||||
uint32_t len) = 0;
|
||||
|
||||
virtual ReturnValue_t getSendSuccess(Cookie *cookie) = 0;
|
||||
|
||||
virtual ReturnValue_t requestReceiveMessage(Cookie *cookie) = 0;
|
||||
|
||||
virtual ReturnValue_t readReceivedMessage(Cookie *cookie, uint8_t **buffer,
|
||||
uint32_t *size) = 0;
|
||||
|
||||
virtual ReturnValue_t setAddress(Cookie *cookie, uint32_t address) = 0;
|
||||
|
||||
virtual uint32_t getAddress(Cookie *cookie) = 0;
|
||||
|
||||
virtual ReturnValue_t setParameter(Cookie *cookie, uint32_t parameter) = 0;
|
||||
|
||||
virtual uint32_t getParameter(Cookie *cookie) = 0;
|
||||
|
||||
};
|
||||
|
||||
#endif /* DEVICECOMMUNICATIONIF_H_ */
|
1246
devicehandlers/DeviceHandlerBase.cpp
Normal file
1246
devicehandlers/DeviceHandlerBase.cpp
Normal file
File diff suppressed because it is too large
Load Diff
971
devicehandlers/DeviceHandlerBase.h
Normal file
971
devicehandlers/DeviceHandlerBase.h
Normal file
@ -0,0 +1,971 @@
|
||||
#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/DeviceHandlerFDIR.h>
|
||||
#include <framework/devicehandlers/DeviceHandlerIF.h>
|
||||
#include <framework/devicehandlers/PollingSequenceExecutableIF.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>
|
||||
#include <map>
|
||||
|
||||
class StorageManagerIF;
|
||||
|
||||
/**
|
||||
* This is the abstract base class for device handlers.
|
||||
*
|
||||
* It features handling of @link DeviceHandlerIF::Mode_t Modes @endlink, the RMAP communication and the
|
||||
* communication with commanding objects.
|
||||
* It inherits SystemObject and thus can be created by the ObjectManagerIF.
|
||||
*
|
||||
* This class is called by the PollingSequenceTable periodically. Thus, the execution is divided into PST cycles and steps within a cycle.
|
||||
* For each step an RMAP action is selected and executed. If data has been received (eg in case of an RMAP 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 (Read-getRead-write-getWrite) structure,
|
||||
* a default implementation is provided.
|
||||
*
|
||||
* Device handler instances should extend this class and implement the abstract functions.
|
||||
*/
|
||||
class DeviceHandlerBase: public DeviceHandlerIF,
|
||||
public HasReturnvaluesIF,
|
||||
public PollingSequenceExecutableIF,
|
||||
public SystemObject,
|
||||
public HasModesIF,
|
||||
public HasHealthIF,
|
||||
public HasActionsIF,
|
||||
public ReceivesParameterMessagesIF {
|
||||
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()
|
||||
*/
|
||||
DeviceHandlerBase(uint32_t ioBoardAddress, object_id_t setObjectId,
|
||||
uint32_t maxDeviceReplyLen, uint8_t setDeviceSwitch,
|
||||
object_id_t deviceCommunication, uint32_t thermalStatePoolId =
|
||||
PoolVariableIF::NO_PARAMETER,
|
||||
uint32_t thermalRequestPoolId = PoolVariableIF::NO_PARAMETER, FDIRBase* fdirInstance = NULL, uint32_t cmdQueueSize = 20);
|
||||
|
||||
virtual MessageQueueId_t getCommandQueue(void) const;
|
||||
|
||||
virtual void performInPST(uint8_t counter);
|
||||
|
||||
virtual ReturnValue_t initialize();
|
||||
|
||||
/**
|
||||
* MUST be called after initialize(), not before! TODO: Is this statement still valid?
|
||||
*
|
||||
* @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,
|
||||
ParameterWrapper *parameterWrapper,
|
||||
const ParameterWrapper *newValues, uint16_t startAtIndex);
|
||||
protected:
|
||||
/**
|
||||
* The Returnvalues id of this class, required by HasReturnvaluesIF
|
||||
*/
|
||||
static const uint8_t INTERFACE_ID = DEVICE_HANDLER_BASE;
|
||||
|
||||
static const ReturnValue_t INVALID_CHANNEL = MAKE_RETURN_CODE(4);
|
||||
static const ReturnValue_t APERIODIC_REPLY = MAKE_RETURN_CODE(5);
|
||||
static const ReturnValue_t IGNORE_REPLY_DATA = MAKE_RETURN_CODE(6);
|
||||
// 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;
|
||||
|
||||
/**
|
||||
* RMAP Action that will be executed.
|
||||
*
|
||||
* This is used by the child class to tell the base class what to do.
|
||||
*/
|
||||
enum RmapAction_t {
|
||||
SEND_WRITE, //!< RMAP send write
|
||||
GET_WRITE, //!< RMAP get write
|
||||
SEND_READ, //!< RMAP send read
|
||||
GET_READ, //!< RMAP get read
|
||||
NOTHING //!< Do nothing.
|
||||
};
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* This is the counter value from performInPST().
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* the message queue which commanded raw mode
|
||||
*
|
||||
* This is the one to receive raw replies
|
||||
*/
|
||||
MessageQueueId_t theOneWhoReceivesRawTraffic;
|
||||
|
||||
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
|
||||
*/
|
||||
MessageQueueId_t theOneWhoWantsToReadRawTraffic;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
MessageQueue commandQueue;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
||||
FDIRBase* fdirInstance; //!< Pointer to the used FDIR instance. If not provided by child, default class is instantiated.
|
||||
|
||||
bool defaultFDIRUsed; //!< To correctly delete the default instance.
|
||||
|
||||
bool switchOffWasReported; //!< Indicates if SWITCH_WENT_OFF was already thrown.
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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,
|
||||
uint16_t maxDelayCycles, uint8_t periodic = 0,
|
||||
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.
|
||||
*/
|
||||
ReturnValue_t insertInCommandMap(DeviceCommandId_t deviceCommand);
|
||||
/**
|
||||
* 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);
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param start start of data
|
||||
* @param len length of data
|
||||
* @param[out] foundId the id of the packet starting at @c start
|
||||
* @param[out] foundLen length of the packet found
|
||||
* @return
|
||||
* - @c RETURN_OK a valid packet was found at @c start, @c foundLen is valid
|
||||
* - @c NO_VALID_REPLY no reply could be found starting at @c start, implies @c foundLen is not valid, base class will call scanForReply() again with ++start
|
||||
* - @c INVALID_REPLY a packet was found but it is invalid, eg checksum error, implies @c foundLen is valid, can be used to skip some bytes
|
||||
* - @c TOO_SHORT @c len is too short for any valid packet
|
||||
* - @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
|
||||
* a TM packet or stores the data in the DataPool depending on whether the it was an external command.
|
||||
* No packet length is given, as it should be defined implicitly by the id.
|
||||
*
|
||||
* @param id the id found by scanForReply()
|
||||
* @param packet
|
||||
* @param commander the one who initiated the command, is 0 if not external commanded
|
||||
* @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,
|
||||
const uint8_t *packet) = 0;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
uint8_t expectedReplies; //!< Dynamic value to indicate how many replies are expected.
|
||||
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,
|
||||
uint8_t expectedReplies = 1, bool useAlternateId = false,
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
Mode_t getBaseMode(Mode_t transitionMode);
|
||||
|
||||
bool isAwaitingReply();
|
||||
|
||||
void handleDeviceTM(SerializeIF *dataSet, DeviceCommandId_t commandId,
|
||||
bool neverInDataPool = false);
|
||||
|
||||
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);
|
||||
private:
|
||||
|
||||
/**
|
||||
* Information about commands
|
||||
*/
|
||||
DeviceCommandMap deviceCommandMap;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
};
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* cached from ctor for initialize()
|
||||
*/
|
||||
const uint32_t ioBoardAddress;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
ActionHelper actionHelper;
|
||||
|
||||
/**
|
||||
* 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).
|
||||
*/
|
||||
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
|
||||
*/
|
||||
void handleReply(const uint8_t *data, DeviceCommandId_t id);
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
#endif /* DEVICEHANDLERBASE_H_ */
|
||||
|
239
devicehandlers/DeviceHandlerFDIR.cpp
Normal file
239
devicehandlers/DeviceHandlerFDIR.cpp
Normal file
@ -0,0 +1,239 @@
|
||||
/*
|
||||
* DeviceHandlerFDIR.cpp
|
||||
*
|
||||
* Created on: 09.09.2015
|
||||
* Author: baetz
|
||||
*/
|
||||
|
||||
#include <framework/devicehandlers/DeviceHandlerBase.h>
|
||||
#include <framework/devicehandlers/DeviceHandlerFDIR.h>
|
||||
#include <framework/health/HealthTableIF.h>
|
||||
#include <framework/serviceinterface/ServiceInterfaceStream.h>
|
||||
#include <mission/controllers/power/Fuse.h>
|
||||
#include <mission/controllers/tcs/ThermalComponentIF.h>
|
||||
|
||||
//TODO: Mechanisms have no power FDIR..
|
||||
DeviceHandlerFDIR::DeviceHandlerFDIR(object_id_t owner, object_id_t parent) :
|
||||
FDIRBase(owner, parent), strangeReplyCount(MAX_STRANGE_REPLIES,
|
||||
STRANGE_REPLIES_TIME_MS, parameterDomainBase++), missedReplyCount(
|
||||
MAX_MISSED_REPLY_COUNT, MISSED_REPLY_TIME_MS,
|
||||
parameterDomainBase++), recoveryCounter(MAX_REBOOT,
|
||||
REBOOT_TIME_MS, parameterDomainBase++), fdirState(NONE), powerConfirmation(
|
||||
0) {
|
||||
}
|
||||
|
||||
DeviceHandlerFDIR::~DeviceHandlerFDIR() {
|
||||
}
|
||||
|
||||
ReturnValue_t DeviceHandlerFDIR::eventReceived(EventMessage* event) {
|
||||
if (fdirState != NONE) {
|
||||
//Only wait for those events, ignore all others.
|
||||
if (event->getParameter1() == HasHealthIF::HEALTHY
|
||||
&& event->getEvent() == HasHealthIF::HEALTH_INFO) {
|
||||
setFdirState(NONE);
|
||||
}
|
||||
if (event->getEvent() == HasModesIF::MODE_INFO
|
||||
&& fdirState != RECOVERY_ONGOING) {
|
||||
setFdirState(NONE);
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
if (owner->getHealth() == HasHealthIF::FAULTY
|
||||
|| owner->getHealth() == HasHealthIF::PERMANENT_FAULTY) {
|
||||
//Ignore all events in case device is already faulty.
|
||||
return RETURN_OK;
|
||||
}
|
||||
ReturnValue_t result = RETURN_FAILED;
|
||||
switch (event->getEvent()) {
|
||||
case HasModesIF::MODE_TRANSITION_FAILED:
|
||||
case HasModesIF::OBJECT_IN_INVALID_MODE:
|
||||
//We'll try a recovery as long as defined in MAX_REBOOT.
|
||||
//Might cause some AssemblyBase cycles, so keep number low.
|
||||
handleRecovery(event->getEvent());
|
||||
break;
|
||||
case DeviceHandlerIF::DEVICE_INTERPRETING_REPLY_FAILED:
|
||||
case DeviceHandlerIF::DEVICE_READING_REPLY_FAILED:
|
||||
case DeviceHandlerIF::DEVICE_UNREQUESTED_REPLY:
|
||||
case DeviceHandlerIF::DEVICE_UNKNOWN_REPLY: //Some DH's generate generic reply-ids.
|
||||
case DeviceHandlerIF::DEVICE_BUILDING_COMMAND_FAILED:
|
||||
//These faults all mean that there were stupid replies from a device.
|
||||
if (strangeReplyCount.incrementAndCheck()) {
|
||||
handleRecovery(event->getEvent());
|
||||
}
|
||||
break;
|
||||
case DeviceHandlerIF::DEVICE_SENDING_COMMAND_FAILED:
|
||||
case DeviceHandlerIF::DEVICE_REQUESTING_REPLY_FAILED:
|
||||
//The two above should never be confirmed.
|
||||
case DeviceHandlerIF::DEVICE_MISSED_REPLY:
|
||||
result = sendConfirmationRequest(event);
|
||||
if (result == HasReturnvaluesIF::RETURN_OK) {
|
||||
break;
|
||||
}
|
||||
//else
|
||||
if (missedReplyCount.incrementAndCheck()) {
|
||||
handleRecovery(event->getEvent());
|
||||
}
|
||||
break;
|
||||
case StorageManagerIF::GET_DATA_FAILED:
|
||||
case StorageManagerIF::STORE_DATA_FAILED:
|
||||
case MessageQueue::SEND_MSG_FAILED:
|
||||
//Rather strange bugs, occur in RAW mode only. TODO:? By now: Ignore.
|
||||
break;
|
||||
case DeviceHandlerIF::INVALID_DEVICE_COMMAND:
|
||||
//Ignore, is bad configuration. We can't do anything in flight.
|
||||
break;
|
||||
case DeviceHandlerIF::MONITORING_AMBIGUOUS:
|
||||
case HasHealthIF::HEALTH_INFO:
|
||||
case HasModesIF::MODE_INFO:
|
||||
case HasModesIF::CHANGING_MODE:
|
||||
//Do nothing, but mark as handled.
|
||||
break;
|
||||
//****Power*****
|
||||
case PowerSwitchIF::SWITCH_WENT_OFF:
|
||||
result = sendConfirmationRequest(event, powerConfirmation);
|
||||
if (result == RETURN_OK) {
|
||||
setFdirState(DEVICE_MIGHT_BE_OFF);
|
||||
}
|
||||
break;
|
||||
case Fuse::FUSE_WENT_OFF:
|
||||
//Not so good, because PCDU reacted.
|
||||
case Fuse::POWER_ABOVE_HIGH_LIMIT:
|
||||
//Better, because software detected over-current.
|
||||
setFaulty(event->getEvent());
|
||||
break;
|
||||
case Fuse::POWER_BELOW_LOW_LIMIT:
|
||||
//Device might got stuck during boot, retry.
|
||||
handleRecovery(event->getEvent());
|
||||
break;
|
||||
//****Thermal*****
|
||||
case ThermalComponentIF::COMPONENT_TEMP_LOW:
|
||||
case ThermalComponentIF::COMPONENT_TEMP_HIGH:
|
||||
case ThermalComponentIF::COMPONENT_TEMP_OOL_LOW:
|
||||
case ThermalComponentIF::COMPONENT_TEMP_OOL_HIGH:
|
||||
//Well, the device is not really faulty, but it is required to stay off as long as possible.
|
||||
//*******ACS*****
|
||||
case DeviceHandlerIF::MONITORING_LIMIT_EXCEEDED:
|
||||
setFaulty(event->getEvent());
|
||||
break;
|
||||
case ThermalComponentIF::TEMP_NOT_IN_OP_RANGE:
|
||||
//Ignore, is information only.
|
||||
break;
|
||||
default:
|
||||
//We don't know the event, someone else should handle it.
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
void DeviceHandlerFDIR::eventConfirmed(EventMessage* event) {
|
||||
switch (event->getEvent()) {
|
||||
case DeviceHandlerIF::DEVICE_SENDING_COMMAND_FAILED:
|
||||
case DeviceHandlerIF::DEVICE_REQUESTING_REPLY_FAILED:
|
||||
case DeviceHandlerIF::DEVICE_MISSED_REPLY:
|
||||
if (missedReplyCount.incrementAndCheck()) {
|
||||
handleRecovery(event->getEvent());
|
||||
}
|
||||
break;
|
||||
case PowerSwitchIF::SWITCH_WENT_OFF:
|
||||
//This means the switch went off only for one device.
|
||||
handleRecovery(event->getEvent());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceHandlerFDIR::decrementFaultCounters() {
|
||||
strangeReplyCount.checkForDecrement();
|
||||
missedReplyCount.checkForDecrement();
|
||||
recoveryCounter.checkForDecrement();
|
||||
}
|
||||
|
||||
void DeviceHandlerFDIR::handleRecovery(Event reason) {
|
||||
clearFaultCounters();
|
||||
if (!recoveryCounter.incrementAndCheck()) {
|
||||
startRecovery(reason);
|
||||
} else {
|
||||
setFaulty(reason);
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceHandlerFDIR::wasParentsFault(EventMessage* event) {
|
||||
//We'll better ignore the SWITCH_WENT_OFF event and await a system-wide reset.
|
||||
//This means, no fault message will come through until a MODE_ or HEALTH_INFO message comes through -> Is that ok?
|
||||
//Same issue in TxFailureIsolation!
|
||||
// if ((event->getEvent() == PowerSwitchIF::SWITCH_WENT_OFF)
|
||||
// && (fdirState != RECOVERY_ONGOING)) {
|
||||
// setFdirState(NONE);
|
||||
// }
|
||||
}
|
||||
|
||||
void DeviceHandlerFDIR::clearFaultCounters() {
|
||||
strangeReplyCount.clear();
|
||||
missedReplyCount.clear();
|
||||
}
|
||||
|
||||
ReturnValue_t DeviceHandlerFDIR::initialize() {
|
||||
ReturnValue_t result = FDIRBase::initialize();
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
ConfirmsFailuresIF* power = objectManager->get<ConfirmsFailuresIF>(
|
||||
objects::PCDU_HANDLER);
|
||||
if (power == NULL) {
|
||||
return RETURN_FAILED;
|
||||
}
|
||||
powerConfirmation = power->getEventReceptionQueue();
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
void DeviceHandlerFDIR::setFdirState(FDIRState state) {
|
||||
FDIRBase::throwFdirEvent(FDIR_CHANGED_STATE, state, fdirState);
|
||||
fdirState = state;
|
||||
}
|
||||
|
||||
void DeviceHandlerFDIR::triggerEvent(Event event, uint32_t parameter1,
|
||||
uint32_t parameter2) {
|
||||
//Do not throw error events if fdirState != none.
|
||||
//This will still forward MODE and HEALTH INFO events in any case.
|
||||
if (fdirState == NONE || EVENT::getSeverity(event) == SEVERITY::INFO) {
|
||||
FDIRBase::triggerEvent(event, parameter1, parameter2);
|
||||
}
|
||||
}
|
||||
|
||||
bool DeviceHandlerFDIR::isFdirActionInProgress() {
|
||||
return (fdirState != NONE);
|
||||
}
|
||||
|
||||
void DeviceHandlerFDIR::startRecovery(Event reason) {
|
||||
throwFdirEvent(FDIR_STARTS_RECOVERY, EVENT::getEventId(reason));
|
||||
setOwnerHealth(HasHealthIF::NEEDS_RECOVERY);
|
||||
setFdirState(RECOVERY_ONGOING);
|
||||
}
|
||||
|
||||
ReturnValue_t DeviceHandlerFDIR::getParameter(uint8_t domainId,
|
||||
uint16_t parameterId, ParameterWrapper* parameterWrapper,
|
||||
const ParameterWrapper* newValues, uint16_t startAtIndex) {
|
||||
ReturnValue_t result = strangeReplyCount.getParameter(domainId, parameterId,
|
||||
parameterWrapper, newValues, startAtIndex);
|
||||
if (result != INVALID_DOMAIN_ID) {
|
||||
return result;
|
||||
}
|
||||
result = missedReplyCount.getParameter(domainId, parameterId,
|
||||
parameterWrapper, newValues, startAtIndex);
|
||||
if (result != INVALID_DOMAIN_ID) {
|
||||
return result;
|
||||
}
|
||||
result = recoveryCounter.getParameter(domainId, parameterId,
|
||||
parameterWrapper, newValues, startAtIndex);
|
||||
if (result != INVALID_DOMAIN_ID) {
|
||||
return result;
|
||||
}
|
||||
return INVALID_DOMAIN_ID;
|
||||
}
|
||||
|
||||
void DeviceHandlerFDIR::setFaulty(Event reason) {
|
||||
throwFdirEvent(FDIR_TURNS_OFF_DEVICE, EVENT::getEventId(reason));
|
||||
setOwnerHealth(HasHealthIF::FAULTY);
|
||||
setFdirState(AWAIT_SHUTDOWN);
|
||||
}
|
54
devicehandlers/DeviceHandlerFDIR.h
Normal file
54
devicehandlers/DeviceHandlerFDIR.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* DeviceHandlerFDIR.h
|
||||
*
|
||||
* Created on: 09.09.2015
|
||||
* Author: baetz
|
||||
*/
|
||||
|
||||
#ifndef FRAMEWORK_DEVICEHANDLERS_DEVICEHANDLERFDIR_H_
|
||||
#define FRAMEWORK_DEVICEHANDLERS_DEVICEHANDLERFDIR_H_
|
||||
|
||||
#include <framework/fdir/FaultCounter.h>
|
||||
#include <framework/fdir/FDIRBase.h>
|
||||
|
||||
class DeviceHandlerFDIR: public FDIRBase {
|
||||
public:
|
||||
DeviceHandlerFDIR(object_id_t owner, object_id_t parent = objects::IO_ASSEMBLY);
|
||||
~DeviceHandlerFDIR();
|
||||
virtual ReturnValue_t eventReceived(EventMessage* event);
|
||||
void eventConfirmed(EventMessage* event);
|
||||
void wasParentsFault(EventMessage* event);
|
||||
void decrementFaultCounters();
|
||||
ReturnValue_t initialize();
|
||||
void triggerEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0);
|
||||
bool isFdirActionInProgress();
|
||||
virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId,
|
||||
ParameterWrapper *parameterWrapper,
|
||||
const ParameterWrapper *newValues, uint16_t startAtIndex);
|
||||
protected:
|
||||
FaultCounter strangeReplyCount;
|
||||
FaultCounter missedReplyCount;
|
||||
FaultCounter recoveryCounter;
|
||||
enum FDIRState {
|
||||
NONE,
|
||||
RECOVERY_ONGOING,
|
||||
DEVICE_MIGHT_BE_OFF,
|
||||
AWAIT_SHUTDOWN
|
||||
};
|
||||
FDIRState fdirState;
|
||||
MessageQueueId_t powerConfirmation;
|
||||
//TODO: Arbitrary numbers! Adjust!
|
||||
static const uint32_t MAX_REBOOT = 1;
|
||||
static const uint32_t REBOOT_TIME_MS = 180000;
|
||||
static const uint32_t MAX_STRANGE_REPLIES = 10;
|
||||
static const uint32_t STRANGE_REPLIES_TIME_MS = 10000;
|
||||
static const uint32_t MAX_MISSED_REPLY_COUNT = 5;
|
||||
static const uint32_t MISSED_REPLY_TIME_MS = 10000;
|
||||
void handleRecovery(Event reason);
|
||||
virtual void clearFaultCounters();
|
||||
void setFdirState(FDIRState state);
|
||||
void startRecovery(Event reason);
|
||||
void setFaulty(Event reason);
|
||||
};
|
||||
|
||||
#endif /* FRAMEWORK_DEVICEHANDLERS_DEVICEHANDLERFDIR_H_ */
|
104
devicehandlers/DeviceHandlerIF.h
Normal file
104
devicehandlers/DeviceHandlerIF.h
Normal file
@ -0,0 +1,104 @@
|
||||
#ifndef DEVICEHANDLERIF_H_
|
||||
#define DEVICEHANDLERIF_H_
|
||||
|
||||
#include <framework/action/HasActionsIF.h>
|
||||
#include <framework/devicehandlers/DeviceHandlerMessage.h>
|
||||
#include <framework/events/Event.h>
|
||||
#include <framework/ipc/MessageQueue.h>
|
||||
#include <framework/modes/HasModesIF.h>
|
||||
|
||||
/**
|
||||
* This is the Interface used to communicate with a device handler.
|
||||
*
|
||||
*/
|
||||
class DeviceHandlerIF {
|
||||
public:
|
||||
|
||||
static const uint8_t TRANSITION_MODE_CHILD_ACTION_MASK = 0x20;
|
||||
static const uint8_t TRANSITION_MODE_BASE_ACTION_MASK = 0x10;
|
||||
|
||||
/**
|
||||
* @brief This is the mode the <strong>device handler</strong> is in.
|
||||
*
|
||||
* @details The mode of the device handler must not be confused with the mode the device is in.
|
||||
* The mode of the device itself is transparent to the user but related to the mode of the handler.
|
||||
*/
|
||||
// MODE_ON = 0, //!< The device is powered and ready to perform operations. In this mode, no commands are sent by the device handler itself, but direct commands van be commanded and will be interpreted
|
||||
// MODE_OFF = 1, //!< The device is powered off. The only command accepted in this mode is a mode change to on.
|
||||
static const Mode_t MODE_NORMAL = 2; //!< The device is powered on and the device handler periodically sends commands. The commands to be sent are selected by the handler according to the submode.
|
||||
static const Mode_t MODE_RAW = 3; //!< The device is powered on and ready to perform operations. In this mode, raw commands can be sent. The device handler will send all replies received from the command back to the commanding object.
|
||||
static const Mode_t MODE_ERROR_ON = 4; //!4< The device is shut down but the switch could not be turned off, so the device still is powered. In this mode, only a mode change to @c MODE_OFF can be commanded, which tries to switch off the device again.
|
||||
static const Mode_t _MODE_START_UP = TRANSITION_MODE_CHILD_ACTION_MASK | 5; //!< This is a transitional state which can not be commanded. The device handler performs all commands to get the device in a state ready to perform commands. When this is completed, the mode changes to @c MODE_ON.
|
||||
static const Mode_t _MODE_SHUT_DOWN = TRANSITION_MODE_CHILD_ACTION_MASK | 6; //!< This is a transitional state which can not be commanded. The device handler performs all actions and commands to get the device shut down. When the device is off, the mode changes to @c MODE_OFF.
|
||||
static const Mode_t _MODE_TO_ON = TRANSITION_MODE_CHILD_ACTION_MASK | HasModesIF::MODE_ON;
|
||||
static const Mode_t _MODE_TO_RAW = TRANSITION_MODE_CHILD_ACTION_MASK | MODE_RAW;
|
||||
static const Mode_t _MODE_TO_NORMAL = TRANSITION_MODE_CHILD_ACTION_MASK | MODE_NORMAL;
|
||||
static const Mode_t _MODE_POWER_DOWN = TRANSITION_MODE_BASE_ACTION_MASK | 1; //!< This is a transitional state which can not be commanded. The device is shut down and ready to be switched off. After the command to set the switch off has been sent, the mode changes to @c MODE_WAIT_OFF
|
||||
static const Mode_t _MODE_POWER_ON = TRANSITION_MODE_BASE_ACTION_MASK | 2; //!< This is a transitional state which can not be commanded. The device will be switched on in this state. After the command to set the switch on has been sent, the mode changes to @c MODE_WAIT_ON
|
||||
static const Mode_t _MODE_WAIT_OFF = TRANSITION_MODE_BASE_ACTION_MASK | 3; //!< This is a transitional state which can not be commanded. The switch has been commanded off and the handler waits for it to be off. When the switch is off, the mode changes to @c MODE_OFF.
|
||||
static const Mode_t _MODE_WAIT_ON = TRANSITION_MODE_BASE_ACTION_MASK | 4; //!< This is a transitional state which can not be commanded. The switch has been commanded on and the handler waits for it to be on. When the switch is on, the mode changes to @c MODE_TO_ON.
|
||||
static const Mode_t _MODE_SWITCH_IS_OFF = TRANSITION_MODE_BASE_ACTION_MASK | 5; //!< This is a transitional state which can not be commanded. The switch has been commanded off and is off now. This state is only to do an RMAP cycle once more where the doSendRead() function will set the mode to MODE_OFF. The reason to do this is to get rid of stuck packets in the IO Board
|
||||
|
||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::CDH;
|
||||
static const Event DEVICE_BUILDING_COMMAND_FAILED = MAKE_EVENT(0, SEVERITY::LOW);
|
||||
static const Event DEVICE_SENDING_COMMAND_FAILED = MAKE_EVENT(1, SEVERITY::LOW);
|
||||
static const Event DEVICE_REQUESTING_REPLY_FAILED = MAKE_EVENT(2, SEVERITY::LOW);
|
||||
static const Event DEVICE_READING_REPLY_FAILED = MAKE_EVENT(3, SEVERITY::LOW);
|
||||
static const Event DEVICE_INTERPRETING_REPLY_FAILED = MAKE_EVENT(4, SEVERITY::LOW);
|
||||
static const Event DEVICE_MISSED_REPLY = MAKE_EVENT(5, SEVERITY::LOW);
|
||||
static const Event DEVICE_UNKNOWN_REPLY = MAKE_EVENT(6, SEVERITY::LOW);
|
||||
static const Event DEVICE_UNREQUESTED_REPLY = MAKE_EVENT(7, SEVERITY::LOW);
|
||||
static const Event INVALID_DEVICE_COMMAND = MAKE_EVENT(8, SEVERITY::LOW); //!< Indicates a SW bug in child class.
|
||||
static const Event MONITORING_LIMIT_EXCEEDED = MAKE_EVENT(9, SEVERITY::LOW);
|
||||
static const Event MONITORING_AMBIGUOUS = MAKE_EVENT(10, SEVERITY::HIGH);
|
||||
|
||||
static const uint8_t INTERFACE_ID = DEVICE_HANDLER_IF;
|
||||
static const ReturnValue_t NO_COMMAND_DATA = MAKE_RETURN_CODE(0xA0);
|
||||
static const ReturnValue_t COMMAND_NOT_SUPPORTED = MAKE_RETURN_CODE(0xA1);
|
||||
static const ReturnValue_t COMMAND_ALREADY_SENT = MAKE_RETURN_CODE(0xA2);
|
||||
static const ReturnValue_t COMMAND_WAS_NOT_SENT = MAKE_RETURN_CODE(0xA3);
|
||||
static const ReturnValue_t CANT_SWITCH_IOBOARD = MAKE_RETURN_CODE(0xA4);
|
||||
static const ReturnValue_t WRONG_MODE_FOR_COMMAND = MAKE_RETURN_CODE(0xA5);
|
||||
static const ReturnValue_t TIMEOUT = MAKE_RETURN_CODE(0xA6);
|
||||
static const ReturnValue_t BUSY = MAKE_RETURN_CODE(0xA7);
|
||||
static const ReturnValue_t NO_REPLY_EXPECTED = MAKE_RETURN_CODE(0xA8); //!< Used to indicate that this is a command-only command.
|
||||
static const ReturnValue_t NON_OP_TEMPERATURE = MAKE_RETURN_CODE(0xA9);
|
||||
|
||||
//standard codes used in scan for reply
|
||||
// static const ReturnValue_t TOO_SHORT = MAKE_RETURN_CODE(0xB1);
|
||||
static const ReturnValue_t CHECKSUM_ERROR = MAKE_RETURN_CODE(0xB2);
|
||||
static const ReturnValue_t LENGTH_MISSMATCH = MAKE_RETURN_CODE(0xB3);
|
||||
static const ReturnValue_t INVALID_DATA = MAKE_RETURN_CODE(0xB4);
|
||||
static const ReturnValue_t PROTOCOL_ERROR = MAKE_RETURN_CODE(0xB5);
|
||||
|
||||
//standard codes used in interpret device reply
|
||||
static const ReturnValue_t DEVICE_DID_NOT_EXECUTE = MAKE_RETURN_CODE(0xC1); //the device reported, that it did not execute the command
|
||||
static const ReturnValue_t DEVICE_REPORTED_ERROR = MAKE_RETURN_CODE(0xC2);
|
||||
static const ReturnValue_t UNKNOW_DEVICE_REPLY = MAKE_RETURN_CODE(0xC3); //the deviceCommandId reported by scanforReply is unknown
|
||||
static const ReturnValue_t DEVICE_REPLY_INVALID = MAKE_RETURN_CODE(0xC4); //syntax etc is correct but still not ok, eg parameters where none are expected
|
||||
|
||||
//Standard codes used in buildCommandFromCommand
|
||||
static const ReturnValue_t INVALID_COMMAND_PARAMETER = MAKE_RETURN_CODE(
|
||||
0xD0);
|
||||
static const ReturnValue_t INVALID_NUMBER_OR_LENGTH_OF_PARAMETERS =
|
||||
MAKE_RETURN_CODE(0xD1);
|
||||
/**
|
||||
* Default Destructor
|
||||
*/
|
||||
virtual ~DeviceHandlerIF() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This MessageQueue is used to command the device handler.
|
||||
*
|
||||
* To command a device handler, a DeviceHandlerCommandMessage can be sent to this Queue.
|
||||
* The handler replies with a DeviceHandlerCommandMessage containing the DeviceHandlerCommand_t reply.
|
||||
*
|
||||
* @return the id of the MessageQueue
|
||||
*/
|
||||
virtual MessageQueueId_t getCommandQueue() const = 0;
|
||||
|
||||
};
|
||||
|
||||
#endif /* DEVICEHANDLERIF_H_ */
|
101
devicehandlers/DeviceHandlerMessage.cpp
Normal file
101
devicehandlers/DeviceHandlerMessage.cpp
Normal file
@ -0,0 +1,101 @@
|
||||
#include <framework/objectmanager/ObjectManagerIF.h>
|
||||
#include <framework/devicehandlers/DeviceHandlerMessage.h>
|
||||
#include <framework/objectmanager/ObjectManagerIF.h>
|
||||
|
||||
DeviceHandlerMessage::DeviceHandlerMessage() {
|
||||
}
|
||||
|
||||
store_address_t DeviceHandlerMessage::getStoreAddress(
|
||||
const CommandMessage* message) {
|
||||
return store_address_t(message->getParameter2());
|
||||
}
|
||||
|
||||
uint32_t DeviceHandlerMessage::getDeviceCommandId(
|
||||
const CommandMessage* message) {
|
||||
return message->getParameter();
|
||||
}
|
||||
|
||||
object_id_t DeviceHandlerMessage::getIoBoardObjectId(
|
||||
const CommandMessage* message) {
|
||||
return message->getParameter();
|
||||
}
|
||||
|
||||
uint8_t DeviceHandlerMessage::getWiretappingMode(
|
||||
const CommandMessage* message) {
|
||||
return message->getParameter();
|
||||
}
|
||||
|
||||
//void DeviceHandlerMessage::setDeviceHandlerDirectCommandMessage(
|
||||
// CommandMessage* message, DeviceCommandId_t deviceCommand,
|
||||
// store_address_t commandParametersStoreId) {
|
||||
// message->setCommand(CMD_DIRECT);
|
||||
// message->setParameter(deviceCommand);
|
||||
// message->setParameter2(commandParametersStoreId.raw);
|
||||
//}
|
||||
|
||||
void DeviceHandlerMessage::setDeviceHandlerRawCommandMessage(
|
||||
CommandMessage* message, store_address_t rawPacketStoreId) {
|
||||
message->setCommand(CMD_RAW);
|
||||
message->setParameter2(rawPacketStoreId.raw);
|
||||
}
|
||||
|
||||
void DeviceHandlerMessage::setDeviceHandlerWiretappingMessage(
|
||||
CommandMessage* message, uint8_t wiretappingMode) {
|
||||
message->setCommand(CMD_WIRETAPPING);
|
||||
message->setParameter(wiretappingMode);
|
||||
}
|
||||
|
||||
void DeviceHandlerMessage::setDeviceHandlerSwitchIoBoardMessage(
|
||||
CommandMessage* message, uint32_t ioBoardIdentifier) {
|
||||
message->setCommand(CMD_SWITCH_IOBOARD);
|
||||
message->setParameter(ioBoardIdentifier);
|
||||
}
|
||||
|
||||
object_id_t DeviceHandlerMessage::getDeviceObjectId(
|
||||
const CommandMessage* message) {
|
||||
return message->getParameter();
|
||||
}
|
||||
|
||||
void DeviceHandlerMessage::setDeviceHandlerRawReplayMessage(
|
||||
CommandMessage* message, object_id_t deviceObjectid,
|
||||
store_address_t rawPacketStoreId, bool isCommand) {
|
||||
if (isCommand) {
|
||||
message->setCommand(REPLY_RAW_COMMAND);
|
||||
} else {
|
||||
message->setCommand(REPLY_RAW_REPLY);
|
||||
}
|
||||
message->setParameter(deviceObjectid);
|
||||
message->setParameter2(rawPacketStoreId.raw);
|
||||
}
|
||||
|
||||
void DeviceHandlerMessage::setDeviceHandlerDirectCommandReply(
|
||||
CommandMessage* message, object_id_t deviceObjectid,
|
||||
store_address_t commandParametersStoreId) {
|
||||
message->setCommand(REPLY_DIRECT_COMMAND_DATA);
|
||||
message->setParameter(deviceObjectid);
|
||||
message->setParameter2(commandParametersStoreId.raw);
|
||||
}
|
||||
|
||||
void DeviceHandlerMessage::clear(CommandMessage* message) {
|
||||
switch (message->getCommand()) {
|
||||
case CMD_RAW:
|
||||
// case CMD_DIRECT:
|
||||
case REPLY_RAW_COMMAND:
|
||||
case REPLY_RAW_REPLY:
|
||||
case REPLY_DIRECT_COMMAND_DATA: {
|
||||
StorageManagerIF *ipcStore = objectManager->get<StorageManagerIF>(
|
||||
objects::IPC_STORE);
|
||||
if (ipcStore != NULL) {
|
||||
ipcStore->deleteData(getStoreAddress(message));
|
||||
}
|
||||
}
|
||||
/* NO BREAK*/
|
||||
case CMD_SWITCH_IOBOARD:
|
||||
case CMD_WIRETAPPING:
|
||||
message->setCommand(CommandMessage::CMD_NONE);
|
||||
message->setParameter(0);
|
||||
message->setParameter2(0);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
91
devicehandlers/DeviceHandlerMessage.h
Normal file
91
devicehandlers/DeviceHandlerMessage.h
Normal file
@ -0,0 +1,91 @@
|
||||
#ifndef DEVICEHANDLERMESSAGE_H_
|
||||
#define DEVICEHANDLERMESSAGE_H_
|
||||
|
||||
#include <framework/action/ActionMessage.h>
|
||||
#include <framework/ipc/CommandMessage.h>
|
||||
#include <framework/objectmanager/SystemObjectIF.h>
|
||||
#include <framework/storagemanager/StorageManagerIF.h>
|
||||
//TODO: rework the static constructors to name the type of command they are building, maybe even hide setting the commandID.
|
||||
|
||||
/**
|
||||
* This is used to uniquely identify commands that are sent to a device
|
||||
*
|
||||
* The values are defined in the device-specific implementations
|
||||
*/
|
||||
typedef uint32_t DeviceCommandId_t;
|
||||
|
||||
/**
|
||||
* The DeviceHandlerMessage is used to send Commands to a DeviceHandlerIF
|
||||
*/
|
||||
class DeviceHandlerMessage {
|
||||
private:
|
||||
DeviceHandlerMessage();
|
||||
public:
|
||||
|
||||
/**
|
||||
* These are the commands that can be sent to a DeviceHandlerBase
|
||||
*/
|
||||
static const uint8_t MESSAGE_ID = DEVICE_HANDLER_COMMAND_MESSAGE_ID;
|
||||
static const Command_t CMD_RAW = MAKE_COMMAND_ID( 1 ); //!< Sends a raw command, setParameter is a ::store_id_t containing the raw packet to send
|
||||
// static const Command_t CMD_DIRECT = MAKE_COMMAND_ID( 2 ); //!< Sends a direct command, setParameter is a ::DeviceCommandId_t, setParameter2 is a ::store_id_t containing the data needed for the command
|
||||
static const Command_t CMD_SWITCH_IOBOARD = MAKE_COMMAND_ID( 3 ); //!< Requests a IO-Board switch, setParameter() is the IO-Board identifier
|
||||
static const Command_t CMD_WIRETAPPING = MAKE_COMMAND_ID( 4 ); //!< (De)Activates the monitoring of all raw traffic in DeviceHandlers, setParameter is 0 to deactivate, 1 to activate
|
||||
|
||||
/*static const Command_t REPLY_SWITCHED_IOBOARD = MAKE_COMMAND_ID(1 );//!< Reply to a @c CMD_SWITCH_IOBOARD, indicates switch was successful, getParameter() contains the board switched to (0: nominal, 1: redundant)
|
||||
static const Command_t REPLY_CANT_SWITCH_IOBOARD = MAKE_COMMAND_ID( 2); //!< Reply to a @c CMD_SWITCH_IOBOARD, indicating the switch could not be performed, getParameter() contains the error message
|
||||
static const Command_t REPLY_WIRETAPPING = MAKE_COMMAND_ID( 3); //!< Reply to a @c CMD_WIRETAPPING, getParameter() is the current state, 1 enabled, 0 disabled
|
||||
|
||||
static const Command_t REPLY_COMMAND_WAS_SENT = MAKE_COMMAND_ID(4 );//!< Reply to a @c CMD_RAW or @c CMD_DIRECT, indicates the command was successfully sent to the device, getParameter() contains the ::DeviceCommandId_t
|
||||
static const Command_t REPLY_COMMAND_NOT_SUPPORTED = MAKE_COMMAND_ID(5 );//!< Reply to a @c CMD_DIRECT, the requested ::DeviceCommand_t is not supported, getParameter() contains the requested ::DeviceCommand_t, getParameter2() contains the ::DeviceCommandId_t
|
||||
static const Command_t REPLY_COMMAND_WAS_NOT_SENT = MAKE_COMMAND_ID(6 );//!< Reply to a @c CMD_RAW or @c CMD_DIRECT, indicates the command was not sent, getParameter contains the RMAP Return code (@see rmap.h), getParameter2() contains the ::DeviceCommandId_t
|
||||
|
||||
static const Command_t REPLY_COMMAND_ALREADY_SENT = MAKE_COMMAND_ID(7 );//!< Reply to a @c CMD_DIRECT, the requested ::DeviceCommand_t has already been sent to the device and not ye been answered
|
||||
static const Command_t REPLY_WRONG_MODE_FOR_CMD = MAKE_COMMAND_ID(8 );//!< Reply to a @c CMD_RAW or @c CMD_DIRECT, indicates that the requested command can not be sent in the curent mode, getParameter() contains the DeviceHandlerCommand_t
|
||||
static const Command_t REPLY_NO_DATA = MAKE_COMMAND_ID(9 ); //!< Reply to a CMD_RAW or @c CMD_DIRECT, indicates that the ::store_id_t was invalid, getParameter() contains the ::DeviceCommandId_t, getPrameter2() contains the error code
|
||||
*/
|
||||
static const Command_t REPLY_DIRECT_COMMAND_SENT = ActionMessage::STEP_SUCCESS; //!< Signals that a direct command was sent
|
||||
static const Command_t REPLY_RAW_COMMAND = MAKE_COMMAND_ID(0x11 ); //!< Contains a raw command sent to the Device
|
||||
static const Command_t REPLY_RAW_REPLY = MAKE_COMMAND_ID( 0x12); //!< Contains a raw reply from the Device, getParameter() is the ObjcetId of the sender, getParameter2() is a ::store_id_t containing the raw packet received
|
||||
static const Command_t REPLY_DIRECT_COMMAND_DATA = ActionMessage::DATA_REPLY;
|
||||
|
||||
/**
|
||||
* Default Destructor
|
||||
*/
|
||||
virtual ~DeviceHandlerMessage() {
|
||||
}
|
||||
|
||||
static store_address_t getStoreAddress(const CommandMessage* message);
|
||||
static uint32_t getDeviceCommandId(const CommandMessage* message);
|
||||
static object_id_t getDeviceObjectId(const CommandMessage *message);
|
||||
static object_id_t getIoBoardObjectId(const CommandMessage* message);
|
||||
static uint8_t getWiretappingMode(const CommandMessage* message);
|
||||
|
||||
// static void setDeviceHandlerDirectCommandMessage(CommandMessage* message,
|
||||
// DeviceCommandId_t deviceCommand,
|
||||
// store_address_t commandParametersStoreId);
|
||||
|
||||
static void setDeviceHandlerDirectCommandReply(CommandMessage* message,
|
||||
object_id_t deviceObjectid,
|
||||
store_address_t commandParametersStoreId);
|
||||
|
||||
static void setDeviceHandlerRawCommandMessage(CommandMessage* message,
|
||||
store_address_t rawPacketStoreId);
|
||||
|
||||
static void setDeviceHandlerRawReplayMessage(CommandMessage* message,
|
||||
object_id_t deviceObjectid, store_address_t rawPacketStoreId,
|
||||
bool isCommand);
|
||||
|
||||
// static void setDeviceHandlerMessage(CommandMessage* message,
|
||||
// Command_t command, DeviceCommandId_t deviceCommand,
|
||||
// store_address_t commandParametersStoreId);
|
||||
// static void setDeviceHandlerMessage(CommandMessage* message,
|
||||
// Command_t command, store_address_t rawPacketStoreId);
|
||||
static void setDeviceHandlerWiretappingMessage(CommandMessage* message,
|
||||
uint8_t wiretappingMode);
|
||||
static void setDeviceHandlerSwitchIoBoardMessage(CommandMessage* message,
|
||||
object_id_t ioBoardIdentifier);
|
||||
|
||||
static void clear(CommandMessage* message);
|
||||
};
|
||||
|
||||
#endif /* DEVICEHANDLERMESSAGE_H_ */
|
46
devicehandlers/DeviceTmReportingWrapper.cpp
Normal file
46
devicehandlers/DeviceTmReportingWrapper.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
#include <framework/serialize/SerializeAdapter.h>
|
||||
#include <framework/devicehandlers/DeviceTmReportingWrapper.h>
|
||||
#include <framework/serialize/SerializeAdapter.h>
|
||||
|
||||
DeviceTmReportingWrapper::DeviceTmReportingWrapper(object_id_t objectId,
|
||||
ActionId_t actionId, SerializeIF* data) :
|
||||
objectId(objectId), actionId(actionId), data(data) {
|
||||
}
|
||||
|
||||
DeviceTmReportingWrapper::~DeviceTmReportingWrapper() {
|
||||
|
||||
}
|
||||
|
||||
ReturnValue_t DeviceTmReportingWrapper::serialize(uint8_t** buffer,
|
||||
uint32_t* size, const uint32_t max_size, bool bigEndian) const {
|
||||
ReturnValue_t result = SerializeAdapter<object_id_t>::serialize(&objectId,
|
||||
buffer, size, max_size, bigEndian);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
result = SerializeAdapter<ActionId_t>::serialize(&actionId, buffer,
|
||||
size, max_size, bigEndian);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
return data->serialize(buffer, size, max_size, bigEndian);
|
||||
}
|
||||
|
||||
uint32_t DeviceTmReportingWrapper::getSerializedSize() const {
|
||||
return sizeof(objectId) + sizeof(ActionId_t) + data->getSerializedSize();
|
||||
}
|
||||
|
||||
ReturnValue_t DeviceTmReportingWrapper::deSerialize(const uint8_t** buffer,
|
||||
int32_t* size, bool bigEndian) {
|
||||
ReturnValue_t result = SerializeAdapter<object_id_t>::deSerialize(&objectId,
|
||||
buffer, size, bigEndian);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
result = SerializeAdapter<ActionId_t>::deSerialize(&actionId, buffer,
|
||||
size, bigEndian);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
return data->deSerialize(buffer, size, bigEndian);
|
||||
}
|
27
devicehandlers/DeviceTmReportingWrapper.h
Normal file
27
devicehandlers/DeviceTmReportingWrapper.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef DEVICETMREPORTINGWRAPPER_H_
|
||||
#define DEVICETMREPORTINGWRAPPER_H_
|
||||
|
||||
#include <framework/action/HasActionsIF.h>
|
||||
#include <framework/objectmanager/SystemObjectIF.h>
|
||||
#include <framework/serialize/SerializeIF.h>
|
||||
|
||||
class DeviceTmReportingWrapper: public SerializeIF {
|
||||
public:
|
||||
DeviceTmReportingWrapper(object_id_t objectId, ActionId_t actionId,
|
||||
SerializeIF *data);
|
||||
virtual ~DeviceTmReportingWrapper();
|
||||
|
||||
virtual ReturnValue_t serialize(uint8_t** buffer, uint32_t* size,
|
||||
const uint32_t max_size, bool bigEndian) const;
|
||||
|
||||
virtual uint32_t getSerializedSize() const;
|
||||
|
||||
virtual ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size,
|
||||
bool bigEndian);
|
||||
private:
|
||||
object_id_t objectId;
|
||||
ActionId_t actionId;
|
||||
SerializeIF *data;
|
||||
};
|
||||
|
||||
#endif /* DEVICETMREPORTINGWRAPPER_H_ */
|
57
devicehandlers/HealthDevice.cpp
Normal file
57
devicehandlers/HealthDevice.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
#include <framework/devicehandlers/HealthDevice.h>
|
||||
|
||||
HealthDevice::HealthDevice(object_id_t setObjectId,
|
||||
MessageQueueId_t parentQueue) :
|
||||
SystemObject(setObjectId), lastHealth(HEALTHY), parentQueue(
|
||||
parentQueue), commandQueue(3,
|
||||
CommandMessage::COMMAND_MESSAGE_SIZE), healthHelper(this, setObjectId) {
|
||||
}
|
||||
|
||||
HealthDevice::~HealthDevice() {
|
||||
}
|
||||
|
||||
ReturnValue_t HealthDevice::performOperation() {
|
||||
CommandMessage message;
|
||||
ReturnValue_t result = commandQueue.receiveMessage(&message);
|
||||
if (result == HasReturnvaluesIF::RETURN_OK) {
|
||||
healthHelper.handleHealthCommand(&message);
|
||||
}
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t HealthDevice::initialize() {
|
||||
ReturnValue_t result = SystemObject::initialize();
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
if (parentQueue != 0) {
|
||||
return healthHelper.initialize(parentQueue);
|
||||
} else {
|
||||
return healthHelper.initialize();
|
||||
}
|
||||
}
|
||||
|
||||
MessageQueueId_t HealthDevice::getCommandQueue() const {
|
||||
return commandQueue.getId();
|
||||
}
|
||||
|
||||
void HealthDevice::setParentQueue(MessageQueueId_t parentQueue) {
|
||||
healthHelper.setParentQeueue(parentQueue);
|
||||
}
|
||||
|
||||
bool HealthDevice::hasHealthChanged() {
|
||||
bool changed;
|
||||
HealthState currentHealth = healthHelper.getHealth();
|
||||
changed = currentHealth != lastHealth;
|
||||
lastHealth = currentHealth;
|
||||
return changed;
|
||||
}
|
||||
|
||||
ReturnValue_t HealthDevice::setHealth(HealthState health) {
|
||||
healthHelper.setHealth(health);
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
HasHealthIF::HealthState HealthDevice::getHealth() {
|
||||
return healthHelper.getHealth();
|
||||
}
|
39
devicehandlers/HealthDevice.h
Normal file
39
devicehandlers/HealthDevice.h
Normal file
@ -0,0 +1,39 @@
|
||||
#ifndef HEALTHDEVICE_H_
|
||||
#define HEALTHDEVICE_H_
|
||||
|
||||
#include <framework/health/HasHealthIF.h>
|
||||
#include <framework/health/HealthHelper.h>
|
||||
#include <framework/objectmanager/SystemObject.h>
|
||||
#include <framework/tasks/ExecutableObjectIF.h>
|
||||
|
||||
class HealthDevice: public SystemObject,
|
||||
public ExecutableObjectIF,
|
||||
public HasHealthIF {
|
||||
public:
|
||||
HealthDevice(object_id_t setObjectId, MessageQueueId_t parentQueue);
|
||||
virtual ~HealthDevice();
|
||||
|
||||
ReturnValue_t performOperation();
|
||||
|
||||
ReturnValue_t initialize();
|
||||
|
||||
virtual MessageQueueId_t getCommandQueue() const;
|
||||
|
||||
void setParentQueue(MessageQueueId_t parentQueue);
|
||||
|
||||
bool hasHealthChanged();
|
||||
|
||||
virtual ReturnValue_t setHealth(HealthState health);
|
||||
|
||||
virtual HealthState getHealth();
|
||||
|
||||
protected:
|
||||
HealthState lastHealth;
|
||||
|
||||
MessageQueueId_t parentQueue;
|
||||
MessageQueue commandQueue;
|
||||
public:
|
||||
HealthHelper healthHelper;
|
||||
};
|
||||
|
||||
#endif /* HEALTHDEVICE_H_ */
|
28
devicehandlers/Makefile
Executable file
28
devicehandlers/Makefile
Executable file
@ -0,0 +1,28 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# OPUS makefile
|
||||
#
|
||||
# Created on: Mar 04, 2010
|
||||
# Author: ziemke
|
||||
# Author: Claas Ziemke
|
||||
# Copyright 2010, Claas Ziemke <claas.ziemke@gmx.net>
|
||||
#
|
||||
|
||||
BASEDIR=../../
|
||||
include $(BASEDIR)options.mk
|
||||
|
||||
OBJ = $(BUILDDIR)/ChannelResetHandler.o \
|
||||
$(BUILDDIR)/RawCommandHandler.o \
|
||||
$(BUILDDIR)/RawDataHandler.o \
|
||||
$(BUILDDIR)/OPUSPollingSequence.o \
|
||||
$(BUILDDIR)/PollingTask.o \
|
||||
$(BUILDDIR)/Device.o \
|
||||
$(BUILDDIR)/RmapCookie.o \
|
||||
|
||||
all: $(OBJ)
|
||||
|
||||
$(BUILDDIR)/%.o: %.cpp %.h
|
||||
$(CPP) $(CFLAGS) $(DEFINES) $(CCOPT) ${INCLUDE} -c $< -o $@
|
||||
|
||||
clean:
|
||||
$(RM) *.o *.gcno *.gcda
|
115
devicehandlers/PollingSequence.cpp
Normal file
115
devicehandlers/PollingSequence.cpp
Normal file
@ -0,0 +1,115 @@
|
||||
/**
|
||||
* @file PollingSequence.cpp
|
||||
* @brief This file defines the PollingSequence class.
|
||||
* @date 19.12.2012
|
||||
* @author baetz
|
||||
*/
|
||||
|
||||
#include <framework/devicehandlers/PollingSequence.h>
|
||||
#include <framework/serviceinterface/ServiceInterfaceStream.h>
|
||||
|
||||
|
||||
uint32_t PollingSequenceExecutableIF::pollingSequenceLengthMs = 0;
|
||||
uint32_t PollingSequenceExecutableIF::payloadSequenceLengthMs = 0;
|
||||
|
||||
PollingSequence::PollingSequence(object_id_t setObjectId, Interval_t setLength, ReturnValue_t (*initFunction)(PollingSequence *thisSequence)) : SystemObject( setObjectId ),
|
||||
initFunction(initFunction){
|
||||
this->length = setLength;
|
||||
// PollingSequenceExecutableIF::pollingSequenceLengthMs = (setLength * 1000)
|
||||
// / OSAL::getTicksPerSecond();
|
||||
current = slotList.begin();
|
||||
}
|
||||
|
||||
PollingSequence::~PollingSequence() {
|
||||
std::list<PollingSlot*>::iterator slotIt;
|
||||
//Iterate through slotList and delete all entries.
|
||||
slotIt = this->slotList.begin();
|
||||
while (slotIt != this->slotList.end()) {
|
||||
delete (*slotIt);
|
||||
slotIt++;
|
||||
}
|
||||
}
|
||||
|
||||
void PollingSequence::addSlot(PollingSlot* setSlot) {
|
||||
//The slot is added to the end of the list.
|
||||
this->slotList.push_back(setSlot);
|
||||
this->current = slotList.begin();
|
||||
}
|
||||
|
||||
void PollingSequence::pollAndAdvance() {
|
||||
// (*this->current)->print();
|
||||
(*this->current)->handler->performInPST( (*this->current)->opcode );
|
||||
// if (returnValue != RETURN_OK) {
|
||||
// this->sendErrorMessage( returnValue );
|
||||
// }
|
||||
//Increment the polling Sequence iterator
|
||||
this->current++;
|
||||
//Set it to the beginning, if the list's end is reached.
|
||||
if (this->current == this->slotList.end()) {
|
||||
this->current = this->slotList.begin();
|
||||
}
|
||||
}
|
||||
|
||||
Interval_t PollingSequence::getInterval() {
|
||||
Interval_t oldTime;
|
||||
std::list<PollingSlot*>::iterator it;
|
||||
it = this->current;
|
||||
// Get the pollingTime of the current slot object.
|
||||
oldTime = (*it)->pollingTime;
|
||||
// Advance to the next object.
|
||||
it++;
|
||||
// Find the next interval which is not 0.
|
||||
while ( it != slotList.end() ) {
|
||||
if ( oldTime != (*it)->pollingTime ) {
|
||||
return (*it)->pollingTime - oldTime;
|
||||
} else {
|
||||
it++;
|
||||
}
|
||||
}
|
||||
// If the list end is reached (this is definitely an interval != 0),
|
||||
// the interval is calculated by subtracting the remaining time of the PST
|
||||
// and adding the start time of the first handler in the list.
|
||||
it = slotList.begin();
|
||||
return this->length - oldTime + (*it)->pollingTime;
|
||||
}
|
||||
|
||||
bool PollingSequence::slotFollowsImmediately() {
|
||||
Interval_t currentTime = (*current)->pollingTime;
|
||||
std::list<PollingSlot*>::iterator it;
|
||||
it = this->current;
|
||||
// Get the pollingTime of the current slot object.
|
||||
if ( it == slotList.begin() ) return false;
|
||||
it--;
|
||||
if ( (*it)->pollingTime == currentTime ) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Interval_t PollingSequence::getLength() {
|
||||
return this->length;
|
||||
}
|
||||
|
||||
void PollingSequence::print() {
|
||||
debug << "Polling sequence contains:" << std::endl;
|
||||
|
||||
//Iterate through slotList and start all PollingSlot::print() methods.
|
||||
do {
|
||||
(*current)->print();
|
||||
current++;
|
||||
} while (current != slotList.end());
|
||||
current = slotList.begin();
|
||||
}
|
||||
|
||||
//std::string PollingSequence::getObjectTypeAsString() {
|
||||
// return "PollingSequence";
|
||||
//}
|
||||
|
||||
ReturnValue_t PollingSequence::initialize() {
|
||||
ReturnValue_t result = SystemObject::initialize();
|
||||
if (result != HasReturnvaluesIF::RETURN_OK){
|
||||
return result;
|
||||
}
|
||||
return initFunction(this);
|
||||
}
|
149
devicehandlers/PollingSequence.h
Normal file
149
devicehandlers/PollingSequence.h
Normal file
@ -0,0 +1,149 @@
|
||||
/**
|
||||
* @file PollingSequence.h
|
||||
* @brief This file defines the PollingSequence class.
|
||||
* @date 19.12.2012
|
||||
* @author baetz
|
||||
*/
|
||||
|
||||
#ifndef POLLINGSEQUENCE_H_
|
||||
#define POLLINGSEQUENCE_H_
|
||||
|
||||
#include <framework/devicehandlers/PollingSequenceExecutableIF.h>
|
||||
#include <framework/devicehandlers/PollingSlot.h>
|
||||
#include <framework/objectmanager/SystemObject.h>
|
||||
#include <framework/osal/OSAL.h>
|
||||
#include<list>
|
||||
|
||||
|
||||
/**
|
||||
* \brief This class is the representation of a Polling Sequence Table in software.
|
||||
*
|
||||
* \details The PollingSequence object maintains the dynamic execution of device handler objects.
|
||||
* The main idea is to create a list of device handlers, to announce all handlers to the
|
||||
* polling sequence and to maintain a list of polling slot objects. This slot list represents the
|
||||
* Polling Sequence Table in software. Each polling slot contains information to indicate when and
|
||||
* which device handler shall be executed within a given polling period.
|
||||
* The sequence is then executed by iterating through this slot list.
|
||||
* Handlers are invoking by calling a certain function stored in the handler list.
|
||||
*/
|
||||
class PollingSequence : public SystemObject {
|
||||
friend class PollingTask;
|
||||
friend ReturnValue_t pollingSequenceInitFunction(PollingSequence *thisSequence);
|
||||
friend ReturnValue_t payloadSequenceInitFunction(PollingSequence *thisSequence);
|
||||
protected:
|
||||
|
||||
/**
|
||||
* \brief This list contains all OPUSPollingSlot objects, defining order and execution time of the
|
||||
* device handler objects.
|
||||
*
|
||||
* \details The slot list is a std:list object that contains all created OPUSPollingSlot instances.
|
||||
* They are NOT ordered automatically, so by adding entries, the correct order needs to be ensured.
|
||||
* By iterating through this list the polling sequence is executed. Two entries with identical
|
||||
* polling times are executed immediately one after another.
|
||||
*/
|
||||
std::list<PollingSlot*> slotList;
|
||||
|
||||
/**
|
||||
* \brief An iterator that indicates the current polling slot to execute.
|
||||
*
|
||||
* \details This is an iterator for slotList and always points to the polling slot which is executed next.
|
||||
*/
|
||||
std::list<PollingSlot*>::iterator current;
|
||||
|
||||
/**
|
||||
* \brief The period of the Polling Sequence Table in clock ticks.
|
||||
*
|
||||
* \details This attribute is set within the constructor, defining the main period length of the
|
||||
* Polling Sequence Table. The length is expressed in clock ticks.
|
||||
*
|
||||
*/
|
||||
Interval_t length;
|
||||
|
||||
/**
|
||||
* \brief The init function passed by the ctor
|
||||
*
|
||||
* \details This function will be called during initialize()
|
||||
*
|
||||
*/
|
||||
ReturnValue_t (*initFunction)(PollingSequence *thisSequence);
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* \brief The constructor of the PollingSequence object.
|
||||
*
|
||||
* \details The constructor takes two arguments, the period length and the init function.
|
||||
*
|
||||
* \param setLength The period length, expressed in clock ticks.
|
||||
*/
|
||||
PollingSequence( object_id_t setObjectId, Interval_t setLength, ReturnValue_t (*initFunction)(PollingSequence *thisSequence) );
|
||||
|
||||
/**
|
||||
* \brief The destructor of the PollingSequence object.
|
||||
*
|
||||
* \details The destructor frees all allocated memory by iterating through
|
||||
* handlerMap and slotList and deleting all allocated resources.
|
||||
*/
|
||||
virtual ~PollingSequence();
|
||||
|
||||
/**
|
||||
* \brief This is a method to add an OPUSPollingSlot object to slotList.
|
||||
*
|
||||
* \details Here, a polling slot object is added to the slot list. It is appended
|
||||
* to the end of the list. The list is currently NOT reordered.
|
||||
* Afterwards, the iterator current is set to the beginning of the list.
|
||||
*
|
||||
* \param setSlot This is a pointer to a OPUSPollingSlot object.
|
||||
*/
|
||||
void addSlot( PollingSlot* setSlot );
|
||||
|
||||
/**
|
||||
* Checks if the current slot shall be executed immediately after the one before.
|
||||
* This allows to distinguish between grouped and not grouped handlers.
|
||||
* @return - @c true if the slot has the same polling time as the previous
|
||||
* - @c false else
|
||||
*/
|
||||
bool slotFollowsImmediately();
|
||||
|
||||
/**
|
||||
* \brief This method returns the time until the next device handler object is invoked.
|
||||
*
|
||||
* \details This method is vitally important for the operation of the PST. By fetching the polling time
|
||||
* of the current slot and that of the next one (or the first one, if the list end is reached)
|
||||
* it calculates and returns the interval in clock ticks within which the handler execution
|
||||
* shall take place.
|
||||
*/
|
||||
Interval_t getInterval();
|
||||
|
||||
/**
|
||||
* \brief This method returns the length of this PollingSequence instance.
|
||||
*/
|
||||
Interval_t getLength();
|
||||
|
||||
/**
|
||||
* \brief The method to execute the device handler entered in the current OPUSPollingSlot object.
|
||||
*
|
||||
* \details Within this method the device handler object to be executed is chosen by looking up the
|
||||
* handler address of the current slot in the handlerMap. Either the device handler's
|
||||
* talkToInterface or its listenToInterface method is invoked, depending on the isTalking flag
|
||||
* of the polling slot. After execution the iterator current is increased or, by reaching the
|
||||
* end of slotList, reset to the beginning.
|
||||
*/
|
||||
void pollAndAdvance();
|
||||
|
||||
/**
|
||||
* \brief This is a method to print debug output.
|
||||
*
|
||||
* \details print is a simple debug method to print the whole polling sequence to the debug interface.
|
||||
* It iterates through slotList and calls all print()} functions of the announced polling slot
|
||||
* instances.
|
||||
*
|
||||
*/
|
||||
void print();
|
||||
|
||||
ReturnValue_t initialize();
|
||||
//std::string getObjectTypeAsString();
|
||||
};
|
||||
|
||||
|
||||
#endif /* POLLINGSEQUENCE_H_ */
|
30
devicehandlers/PollingSequenceExecutableIF.h
Normal file
30
devicehandlers/PollingSequenceExecutableIF.h
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* PollingSequenceExecutableIF.h
|
||||
*
|
||||
* Created on: Mar 30, 2012
|
||||
* Author: baetz
|
||||
*/
|
||||
|
||||
#ifndef POLLINGSEQUENCEEXECUTABLE_H_
|
||||
#define POLLINGSEQUENCEEXECUTABLE_H_
|
||||
|
||||
//TODO clean this whole file up
|
||||
|
||||
//TODO maybe define a type to make it look cleaner and use it in the PST
|
||||
#define SEND_WRITE_CMD 0
|
||||
#define GET_WRITE_REPLY 1
|
||||
#define SEND_READ_CMD 2
|
||||
#define GET_READ_REPLY 3
|
||||
|
||||
|
||||
#include <framework/osal/OSAL.h>
|
||||
|
||||
class PollingSequenceExecutableIF {
|
||||
public:
|
||||
static uint32_t pollingSequenceLengthMs;
|
||||
static uint32_t payloadSequenceLengthMs;
|
||||
virtual void performInPST( uint8_t ) = 0;
|
||||
virtual ~PollingSequenceExecutableIF() { }
|
||||
};
|
||||
|
||||
#endif /* POLLINGSEQUENCEEXECUTABLE_H_ */
|
29
devicehandlers/PollingSlot.cpp
Normal file
29
devicehandlers/PollingSlot.cpp
Normal file
@ -0,0 +1,29 @@
|
||||
/**
|
||||
* @file PollingSlot.cpp
|
||||
* @brief This file defines the PollingSlot class.
|
||||
* @date 19.12.2012
|
||||
* @author baetz
|
||||
*/
|
||||
|
||||
#include <framework/devicehandlers/PollingSlot.h>
|
||||
#include <framework/objectmanager/SystemObjectIF.h>
|
||||
#include <framework/serviceinterface/ServiceInterfaceStream.h>
|
||||
|
||||
PollingSlot::PollingSlot( object_id_t handlerId, Interval_t setTime, int8_t setSequenceId ) {
|
||||
//Set all attributes directly on object creation.
|
||||
this->handler = objectManager->get<PollingSequenceExecutableIF>( handlerId );
|
||||
this->pollingTime = setTime;
|
||||
this->opcode = setSequenceId;
|
||||
}
|
||||
|
||||
PollingSlot::~PollingSlot() {
|
||||
}
|
||||
|
||||
void PollingSlot::print() const {
|
||||
SystemObjectIF * systemObject = dynamic_cast<SystemObjectIF *>(handler);
|
||||
object_id_t id = (systemObject == NULL) ? 0xffffffff : systemObject->getObjectId();
|
||||
debug << "HandlerID: " << std::hex << id << std::dec << "; Polling Time: "
|
||||
<< this->pollingTime << "; Opcode: " << (uint16_t) this->opcode
|
||||
<< std::endl;
|
||||
}
|
||||
|
61
devicehandlers/PollingSlot.h
Normal file
61
devicehandlers/PollingSlot.h
Normal file
@ -0,0 +1,61 @@
|
||||
/**
|
||||
* @file PollingSlot.h
|
||||
* @brief This file defines the PollingSlot class.
|
||||
* @date 19.12.2012
|
||||
* @author baetz
|
||||
*/
|
||||
|
||||
#ifndef POLLINGSLOT_H_
|
||||
#define POLLINGSLOT_H_
|
||||
|
||||
#include <framework/devicehandlers/PollingSequenceExecutableIF.h>
|
||||
#include <framework/objectmanager/ObjectManagerIF.h>
|
||||
#include <framework/osal/OSAL.h>
|
||||
|
||||
class PollingSequence;
|
||||
|
||||
/**
|
||||
* \brief This class is the representation of a single polling sequence table entry.
|
||||
*
|
||||
* \details The PollingSlot class is the representation of a single polling sequence table entry.
|
||||
* It contains three attributes and a debug method to print its content.
|
||||
*/
|
||||
class PollingSlot {
|
||||
friend class PollingSequence;
|
||||
friend class PollingTask;
|
||||
friend ReturnValue_t pollingSequenceInitFunction(PollingSequence *thisSequence);
|
||||
friend ReturnValue_t payloadSequenceInitFunction(PollingSequence *thisSequence);
|
||||
protected:
|
||||
/**
|
||||
* \brief \c handler identifies which device handler object is executed in this slot.
|
||||
*/
|
||||
PollingSequenceExecutableIF* handler;
|
||||
|
||||
/**
|
||||
* \brief This attribute defines when a device handler object is executed.
|
||||
*
|
||||
* \details The pollingTime attribute identifies the time the handler is executed in clock ticks. It must be
|
||||
* smaller than the period length of the polling sequence, what is ensured by automated calculation
|
||||
* from a database.
|
||||
*/
|
||||
Interval_t pollingTime;
|
||||
|
||||
/**
|
||||
* \brief This value defines the type of device communication.
|
||||
*
|
||||
* \details The state of this value decides what communication routine is called in the PST executable or the device handler object.
|
||||
*/
|
||||
uint8_t opcode;
|
||||
|
||||
public:
|
||||
PollingSlot( object_id_t handlerId, Interval_t setTime, int8_t setSequenceId );
|
||||
virtual ~PollingSlot();
|
||||
|
||||
/**
|
||||
* \brief This is a small debug method to print the PollingSlot's content to a debug interface.
|
||||
*/
|
||||
void print() const;
|
||||
};
|
||||
|
||||
|
||||
#endif /* POLLINGSLOT_H_ */
|
103
devicehandlers/PollingTask.cpp
Normal file
103
devicehandlers/PollingTask.cpp
Normal file
@ -0,0 +1,103 @@
|
||||
/**
|
||||
* \file OPUSPollingTask.cpp
|
||||
*
|
||||
* \brief This file contains the implementation for the OPUSPollingTask class.
|
||||
*
|
||||
* \author Bastian Baetz
|
||||
*
|
||||
* \date 17.03.2011
|
||||
*
|
||||
*/
|
||||
|
||||
#include <framework/devicehandlers/PollingTask.h>
|
||||
#include <framework/serviceinterface/ServiceInterfaceStream.h>
|
||||
|
||||
uint32_t PollingTask::deadlineMissedCount = 0;
|
||||
|
||||
PollingTask::PollingTask( const char *name, TaskPriority_t setPriority, size_t setStack, void (*setDeadlineMissedFunc)(), object_id_t getPst ) :
|
||||
TaskBase( setPriority, setStack, name ), periodId(0) {
|
||||
// All additional attributes are applied to the object.
|
||||
this->deadlineMissedFunc = setDeadlineMissedFunc;
|
||||
this->pst = objectManager->get<PollingSequence>( getPst );
|
||||
}
|
||||
|
||||
PollingTask::~PollingTask() {
|
||||
// The PollingSequence destructor is called, if a sequence is announced.
|
||||
if ( this->pst != NULL ) {
|
||||
this->pst->~PollingSequence();
|
||||
} else {
|
||||
// There was no memory allocation, so there's nothing to do.
|
||||
}
|
||||
}
|
||||
|
||||
TaskReturn_t PollingTask::taskEntryPoint( TaskArgument_t argument ) {
|
||||
|
||||
//The argument is re-interpreted as PollingTask.
|
||||
PollingTask *originalTask( reinterpret_cast<PollingTask*>( argument ) );
|
||||
if ( originalTask->pst != NULL ) {
|
||||
//The task's functionality is called.
|
||||
originalTask->taskFunctionality();
|
||||
} else {
|
||||
|
||||
}
|
||||
debug << "Polling task " << originalTask->getId() << " returned from taskFunctionality." << std::endl;
|
||||
}
|
||||
|
||||
void PollingTask::missedDeadlineCounter() {
|
||||
PollingTask::deadlineMissedCount++;
|
||||
if (PollingTask::deadlineMissedCount%10 == 0) {
|
||||
error << "PST missed " << PollingTask::deadlineMissedCount << " deadlines." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t PollingTask::startTask() {
|
||||
this->setRunning( true );
|
||||
ReturnValue_t status;
|
||||
status = OSAL::startTask( &( this->id ), PollingTask::taskEntryPoint, TaskArgument_t( ( void *)this ) );
|
||||
if( status != RETURN_OK ) {
|
||||
//TODO: Call any FDIR routine?
|
||||
error << "PollingTask::startTask for " << std::hex << this->getId() << std::dec << " failed." << std::endl;
|
||||
} else {
|
||||
// debug << "PollingTask::startTask for " << std::hex << this->getId() << std::dec << " successful" << std::endl;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
void PollingTask::taskFunctionality() {
|
||||
ReturnValue_t status = OSAL::TIMEOUT;
|
||||
Interval_t interval;
|
||||
// A local iterator for the Polling Sequence Table is created to find the start time for the first entry.
|
||||
std::list<PollingSlot*>::iterator it;
|
||||
|
||||
it = this->pst->current;
|
||||
//The start time for the first entry is read.
|
||||
interval = ( *it )->pollingTime;
|
||||
//The period is set up and started with the system call.
|
||||
status = OSAL::setAndStartPeriod( interval, &( this->periodId ) );
|
||||
if( status == RETURN_OK ) {
|
||||
//The task's "infinite" inner loop is entered.
|
||||
while( this->isRunning ) {
|
||||
if ( pst->slotFollowsImmediately() ) {
|
||||
//Do nothing
|
||||
} else {
|
||||
//The interval for the next polling slot is selected.
|
||||
interval = this->pst->getInterval();
|
||||
//The period is checked and restarted with the new interval.
|
||||
//If the deadline was missed, the deadlineMissedFunc is called.
|
||||
status = OSAL::checkAndRestartPeriod( this->periodId, interval );
|
||||
if( status == OSAL::TIMEOUT ) {
|
||||
if( this->deadlineMissedFunc != NULL ) {
|
||||
this->deadlineMissedFunc();
|
||||
}
|
||||
}
|
||||
}
|
||||
//The device handler for this slot is executed and the next one is chosen.
|
||||
this->pst->pollAndAdvance();
|
||||
}
|
||||
} else {
|
||||
error << "PollingTask::setAndStartPeriod failed with status "<< status << std::endl;
|
||||
}
|
||||
//Any operating system object for periodic execution is deleted.
|
||||
debug << "Deleting the PollingTask's period." << std::endl;
|
||||
OSAL::deletePeriod( &(this->id) );
|
||||
}
|
115
devicehandlers/PollingTask.h
Normal file
115
devicehandlers/PollingTask.h
Normal file
@ -0,0 +1,115 @@
|
||||
/**
|
||||
* @file PollingTask.h
|
||||
*
|
||||
* @brief This file contains the definition for the PollingTask class.
|
||||
*
|
||||
* @author Claas Ziemke, Bastian Baetz
|
||||
*
|
||||
* @date 17.03.2011
|
||||
*
|
||||
* Copyright 2009,2010, Claas Ziemke <claas.ziemke@gmx.net>
|
||||
* All rights reserved
|
||||
*
|
||||
*/
|
||||
#ifndef POLLINGTASK_H_
|
||||
#define POLLINGTASK_H_
|
||||
|
||||
#include <framework/devicehandlers/PollingSequence.h>
|
||||
#include <framework/tasks/TaskBase.h>
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief This class represents a specialized thread to execute polling sequences.
|
||||
*
|
||||
* @image latex seq_PST_dynamic.eps "Sequence diagram of polling sequence operation" width=1@textwidth
|
||||
* @image html seq_PST_dynamic.png "Sequence diagram of polling sequence operation"
|
||||
*
|
||||
* @details The Polling Sequence Table is executed in a task of special type, called PollingTask.
|
||||
* After creation the polling task initializes the PST and starts taskFunctionality.
|
||||
* An infinite loop is entered within which the iteration through the PST is done by repetitive calls of
|
||||
* getInterval() and pollAndAdvance().
|
||||
* @ingroup task_handling
|
||||
*/
|
||||
class PollingTask: public TaskBase {
|
||||
protected:
|
||||
/**
|
||||
* @brief id of the associated OS period
|
||||
*/
|
||||
PeriodId_t periodId;
|
||||
|
||||
/**
|
||||
* @brief This attribute is the pointer to the complete polling sequence table object.
|
||||
*
|
||||
* @details The most important attribute of the thread object.
|
||||
* It holds a pointer to the complete polling sequence table object.
|
||||
*/
|
||||
PollingSequence* pst;
|
||||
|
||||
/**
|
||||
* @brief This attribute holds a function pointer that is executed when a deadline was missed.
|
||||
*
|
||||
* @details Another function may be announced to determine the actions to perform when a deadline was missed.
|
||||
* Currently, only one function for missing any deadline is allowed.
|
||||
* If not used, it shall be declared NULL.
|
||||
*/
|
||||
void ( *deadlineMissedFunc )( void );
|
||||
/**
|
||||
* @brief This is the entry point in a new polling thread.
|
||||
*
|
||||
* @details This method, that is the general entry point in the new thread, is here set to generate
|
||||
* and link the Polling Sequence Table to the thread object and start taskFunctionality()
|
||||
* on success. If operation of the task is ended for some reason,
|
||||
* the destructor is called to free allocated memory.
|
||||
*/
|
||||
static TaskReturn_t taskEntryPoint( TaskArgument_t argument );
|
||||
|
||||
/**
|
||||
* @brief This function holds the main functionality of the thread.
|
||||
*
|
||||
*
|
||||
* @details Holding the main functionality of the task, this method is most important.
|
||||
* It links the functionalities provided by PollingSequence with the OS's System Calls
|
||||
* to keep the timing of the periods.
|
||||
*/
|
||||
void taskFunctionality( void );
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief The standard constructor of the class.
|
||||
*
|
||||
* @details This is the general constructor of the class. In addition to the TaskBase parameters,
|
||||
* the following variables are passed:
|
||||
*
|
||||
* @param (*setDeadlineMissedFunc)() The function pointer to the deadline missed function that shall be assigned.
|
||||
*
|
||||
* @param getPst The object id of the completely initialized polling sequence.
|
||||
*/
|
||||
PollingTask( const char *name, TaskPriority_t setPriority, size_t setStack, void (*setDeadlineMissedFunc)(), object_id_t getPst );
|
||||
|
||||
/**
|
||||
* @brief The destructor of the class.
|
||||
*
|
||||
* @details The destructor frees all heap memory that was allocated on thread initialization for the PST and
|
||||
* the device handlers. This is done by calling the PST's destructor.
|
||||
*/
|
||||
virtual ~PollingTask( void );
|
||||
|
||||
/**
|
||||
* @brief The function to actually start a new task.
|
||||
*
|
||||
* @details As described in TaskBase this method invokes the operating systems method to start a new task.
|
||||
* Entry point is taskEntryPoint().
|
||||
*/
|
||||
ReturnValue_t startTask( void );
|
||||
/**
|
||||
* This static function can be used as #deadlineMissedFunc.
|
||||
* It counts missedDeadlines and prints the number of missed deadlines every 10th time.
|
||||
*/
|
||||
static void missedDeadlineCounter();
|
||||
/**
|
||||
* A helper variable to count missed deadlines.
|
||||
*/
|
||||
static uint32_t deadlineMissedCount;
|
||||
};
|
||||
|
||||
#endif /* POLLINGTASK_H_ */
|
Reference in New Issue
Block a user