Today's the day. Renamed platform to framework.
This commit is contained in:
parent
40987d0b27
commit
1d22a6c97e
7
THANKYOU
7
THANKYOU
@ -1,4 +1,5 @@
|
|||||||
Class Ziemke, together with Bastian Bätz, started work on the code which would later become the Flight Software Framework in late 2009 as a student at the Institut für Raumfahrtsysteme at Universität Stuttgart.
|
Besides Bastian Bätz and Ulrich Mohr, who were the main developers for Flying Laptop's Onboard Software, the following PhD Students contributed to the project:
|
||||||
|
|
||||||
"A dream would come true if the software framework I developed would be released in the public domain so that it can be used by other projects and to be used for teaching students how to program on-board software in the course of the studies at the IRS"
|
Rouven Witt, who developed the FDIR concept and kept morale high as the team's Spaßbeauftragter.
|
||||||
- Claas in his Diploma Thesis
|
Marek Dittmar, who started work on the ACS code and later tried to keep the development in time.
|
||||||
|
Nico Bucher, who performed software tests and as such was invaluable during the development.
|
||||||
|
92
action/ActionHelper.cpp
Normal file
92
action/ActionHelper.cpp
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
|
||||||
|
#include <framework/action/ActionHelper.h>
|
||||||
|
#include <framework/action/HasActionsIF.h>
|
||||||
|
#include <framework/objectmanager/ObjectManagerIF.h>
|
||||||
|
ActionHelper::ActionHelper(HasActionsIF* setOwner, MessageQueue* useThisQueue) :
|
||||||
|
owner(setOwner), queueToUse(useThisQueue), ipcStore(
|
||||||
|
NULL) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionHelper::~ActionHelper() {
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t ActionHelper::handleActionMessage(CommandMessage* command) {
|
||||||
|
if (command->getCommand() == ActionMessage::EXECUTE_ACTION) {
|
||||||
|
ActionId_t currentAction = ActionMessage::getActionId(command);
|
||||||
|
prepareExecution(command->getSender(), currentAction,
|
||||||
|
ActionMessage::getStoreId(command));
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
} else {
|
||||||
|
return CommandMessage::UNKNOW_COMMAND;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t ActionHelper::initialize() {
|
||||||
|
ipcStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE);
|
||||||
|
if (ipcStore == NULL) {
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionHelper::step(uint8_t step, MessageQueueId_t reportTo, ActionId_t commandId, ReturnValue_t result) {
|
||||||
|
CommandMessage reply;
|
||||||
|
ActionMessage::setStepReply(&reply, commandId, step + STEP_OFFSET, result);
|
||||||
|
queueToUse->sendMessage(reportTo, &reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionHelper::finish(MessageQueueId_t reportTo, ActionId_t commandId, ReturnValue_t result) {
|
||||||
|
CommandMessage reply;
|
||||||
|
ActionMessage::setCompletionReply(&reply, commandId, result);
|
||||||
|
queueToUse->sendMessage(reportTo, &reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId,
|
||||||
|
store_address_t dataAddress) {
|
||||||
|
const uint8_t* dataPtr = NULL;
|
||||||
|
uint32_t size = 0;
|
||||||
|
ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size);
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
CommandMessage reply;
|
||||||
|
ActionMessage::setStepReply(&reply, actionId, 0, result);
|
||||||
|
queueToUse->sendMessage(commandedBy, &reply);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
result = owner->executeAction(actionId, commandedBy, dataPtr, size);
|
||||||
|
ipcStore->deleteData(dataAddress);
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
CommandMessage reply;
|
||||||
|
ActionMessage::setStepReply(&reply, actionId, 0, result);
|
||||||
|
queueToUse->sendMessage(commandedBy, &reply);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionHelper::reportData(MessageQueueId_t reportTo, ActionId_t replyId, SerializeIF* data) {
|
||||||
|
CommandMessage reply;
|
||||||
|
store_address_t storeAddress;
|
||||||
|
uint8_t *dataPtr;
|
||||||
|
uint32_t maxSize = data->getSerializedSize();
|
||||||
|
if (maxSize == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint32_t size = 0;
|
||||||
|
ReturnValue_t result = ipcStore->getFreeElement(&storeAddress, maxSize,
|
||||||
|
&dataPtr);
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
//TODO event?
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
result = data->serialize(&dataPtr, &size, maxSize, true);
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
ipcStore->deleteData(storeAddress);
|
||||||
|
//TODO event?
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ActionMessage::setDataReply(&reply, replyId, storeAddress);
|
||||||
|
if (queueToUse->sendMessage(reportTo, &reply) != HasReturnvaluesIF::RETURN_OK){
|
||||||
|
ipcStore->deleteData(storeAddress);
|
||||||
|
}
|
||||||
|
//We don't neeed the objectId, as we receive REQUESTED data before the completion success message.
|
||||||
|
//True aperiodic replies need to be reported with dedicated DH message.
|
||||||
|
}
|
28
action/ActionHelper.h
Normal file
28
action/ActionHelper.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
|
||||||
|
#ifndef ACTIONHELPER_H_
|
||||||
|
#define ACTIONHELPER_H_
|
||||||
|
|
||||||
|
#include <framework/action/ActionMessage.h>
|
||||||
|
#include <framework/serialize/SerializeIF.h>
|
||||||
|
|
||||||
|
class HasActionsIF;
|
||||||
|
//TODO: Change MessageQueueId usage.
|
||||||
|
class ActionHelper {
|
||||||
|
public:
|
||||||
|
ActionHelper(HasActionsIF* setOwner, MessageQueue* useThisQueue);
|
||||||
|
virtual ~ActionHelper();
|
||||||
|
ReturnValue_t handleActionMessage(CommandMessage* command);
|
||||||
|
ReturnValue_t initialize();
|
||||||
|
void step(uint8_t step, MessageQueueId_t reportTo, ActionId_t commandId, ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
|
||||||
|
void finish(MessageQueueId_t reportTo, ActionId_t commandId, ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
|
||||||
|
void reportData(MessageQueueId_t reportTo, ActionId_t replyId, SerializeIF* data);
|
||||||
|
protected:
|
||||||
|
static const uint8_t STEP_OFFSET = 1;
|
||||||
|
HasActionsIF* owner;
|
||||||
|
MessageQueue* queueToUse;
|
||||||
|
StorageManagerIF* ipcStore;
|
||||||
|
virtual void prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId, store_address_t dataAddress);
|
||||||
|
void resetHelper();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* ACTIONHELPER_H_ */
|
80
action/ActionMessage.cpp
Normal file
80
action/ActionMessage.cpp
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
|
||||||
|
#include <framework/action/ActionMessage.h>
|
||||||
|
#include <framework/objectmanager/ObjectManagerIF.h>
|
||||||
|
#include <framework/storagemanager/StorageManagerIF.h>
|
||||||
|
|
||||||
|
ActionMessage::ActionMessage() {
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionMessage::~ActionMessage() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionMessage::setCommand(CommandMessage* message, ActionId_t fid,
|
||||||
|
store_address_t parameters) {
|
||||||
|
message->setCommand(EXECUTE_ACTION);
|
||||||
|
message->setParameter(fid);
|
||||||
|
message->setParameter2(parameters.raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionId_t ActionMessage::getActionId(const CommandMessage* message) {
|
||||||
|
return ActionId_t(message->getParameter());
|
||||||
|
}
|
||||||
|
|
||||||
|
store_address_t ActionMessage::getStoreId(const CommandMessage* message) {
|
||||||
|
store_address_t temp;
|
||||||
|
temp.raw = message->getParameter2();
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionMessage::setStepReply(CommandMessage* message, ActionId_t fid, uint8_t step,
|
||||||
|
ReturnValue_t result) {
|
||||||
|
if (result == HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
message->setCommand(STEP_SUCCESS);
|
||||||
|
} else {
|
||||||
|
message->setCommand(STEP_FAILED);
|
||||||
|
}
|
||||||
|
message->setParameter(fid);
|
||||||
|
message->setParameter2((step << 16) + result);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ActionMessage::getStep(const CommandMessage* message) {
|
||||||
|
return uint8_t((message->getParameter2() >> 16) & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t ActionMessage::getReturnCode(const CommandMessage* message) {
|
||||||
|
return message->getParameter2() & 0xFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionMessage::setDataReply(CommandMessage* message, ActionId_t actionId,
|
||||||
|
store_address_t data) {
|
||||||
|
message->setCommand(DATA_REPLY);
|
||||||
|
message->setParameter(actionId);
|
||||||
|
message->setParameter2(data.raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionMessage::setCompletionReply(CommandMessage* message,
|
||||||
|
ActionId_t fid, ReturnValue_t result) {
|
||||||
|
if (result == HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
message->setCommand(COMPLETION_SUCCESS);
|
||||||
|
} else {
|
||||||
|
message->setCommand(COMPLETION_FAILED);
|
||||||
|
}
|
||||||
|
message->setParameter(fid);
|
||||||
|
message->setParameter2(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionMessage::clear(CommandMessage* message) {
|
||||||
|
switch(message->getCommand()) {
|
||||||
|
case EXECUTE_ACTION:
|
||||||
|
case DATA_REPLY: {
|
||||||
|
StorageManagerIF *ipcStore = objectManager->get<StorageManagerIF>(
|
||||||
|
objects::IPC_STORE);
|
||||||
|
if (ipcStore != NULL) {
|
||||||
|
ipcStore->deleteData(getStoreId(message));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
33
action/ActionMessage.h
Normal file
33
action/ActionMessage.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
|
||||||
|
#ifndef ACTIONMESSAGE_H_
|
||||||
|
#define ACTIONMESSAGE_H_
|
||||||
|
|
||||||
|
#include <framework/ipc/CommandMessage.h>
|
||||||
|
#include <framework/objectmanager/ObjectManagerIF.h>
|
||||||
|
#include <framework/storagemanager/StorageManagerIF.h>
|
||||||
|
typedef uint32_t ActionId_t;
|
||||||
|
|
||||||
|
class ActionMessage {
|
||||||
|
private:
|
||||||
|
ActionMessage();
|
||||||
|
public:
|
||||||
|
static const uint8_t MESSAGE_ID = FUNCTION_MESSAGE_ID;
|
||||||
|
static const Command_t EXECUTE_ACTION = MAKE_COMMAND_ID(1);
|
||||||
|
static const Command_t STEP_SUCCESS = MAKE_COMMAND_ID(2);
|
||||||
|
static const Command_t STEP_FAILED = MAKE_COMMAND_ID(3);
|
||||||
|
static const Command_t DATA_REPLY = MAKE_COMMAND_ID(4);
|
||||||
|
static const Command_t COMPLETION_SUCCESS = MAKE_COMMAND_ID(5);
|
||||||
|
static const Command_t COMPLETION_FAILED = MAKE_COMMAND_ID(6);
|
||||||
|
virtual ~ActionMessage();
|
||||||
|
static void setCommand(CommandMessage* message, ActionId_t fid, store_address_t parameters);
|
||||||
|
static ActionId_t getActionId(const CommandMessage* message );
|
||||||
|
static store_address_t getStoreId(const CommandMessage* message );
|
||||||
|
static void setStepReply(CommandMessage* message, ActionId_t fid, uint8_t step, ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
|
||||||
|
static uint8_t getStep(const CommandMessage* message );
|
||||||
|
static ReturnValue_t getReturnCode(const CommandMessage* message );
|
||||||
|
static void setDataReply(CommandMessage* message, ActionId_t actionId, store_address_t data);
|
||||||
|
static void setCompletionReply(CommandMessage* message, ActionId_t fid, ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
|
||||||
|
static void clear(CommandMessage* message);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* ACTIONMESSAGE_H_ */
|
120
action/CommandActionHelper.cpp
Normal file
120
action/CommandActionHelper.cpp
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
|
||||||
|
#include <framework/action/ActionMessage.h>
|
||||||
|
#include <framework/action/CommandActionHelper.h>
|
||||||
|
#include <framework/action/CommandsActionsIF.h>
|
||||||
|
#include <framework/action/HasActionsIF.h>
|
||||||
|
#include <framework/objectmanager/ObjectManagerIF.h>
|
||||||
|
|
||||||
|
CommandActionHelper::CommandActionHelper(CommandsActionsIF* setOwner) :
|
||||||
|
owner(setOwner), queueToUse(setOwner->getCommandQueuePtr()), ipcStore(
|
||||||
|
NULL), commandCount(0), lastTarget(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandActionHelper::~CommandActionHelper() {
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t CommandActionHelper::commandAction(object_id_t commandTo,
|
||||||
|
ActionId_t actionId, SerializeIF* data) {
|
||||||
|
HasActionsIF* receiver = objectManager->get<HasActionsIF>(commandTo);
|
||||||
|
if (receiver == NULL) {
|
||||||
|
return CommandsActionsIF::OBJECT_HAS_NO_FUNCTIONS;
|
||||||
|
}
|
||||||
|
store_address_t storeId;
|
||||||
|
uint8_t* storePointer;
|
||||||
|
uint32_t maxSize = data->getSerializedSize();
|
||||||
|
ReturnValue_t result = ipcStore->getFreeElement(&storeId, maxSize,
|
||||||
|
&storePointer);
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
uint32_t size = 0;
|
||||||
|
result = data->serialize(&storePointer, &size, maxSize, true);
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return sendCommand(receiver->getCommandQueue(), actionId, storeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t CommandActionHelper::commandAction(object_id_t commandTo,
|
||||||
|
ActionId_t actionId, const uint8_t* data, uint32_t size) {
|
||||||
|
// if (commandCount != 0) {
|
||||||
|
// return CommandsFunctionsIF::ALREADY_COMMANDING;
|
||||||
|
// }
|
||||||
|
HasActionsIF* receiver = objectManager->get<HasActionsIF>(commandTo);
|
||||||
|
if (receiver == NULL) {
|
||||||
|
return CommandsActionsIF::OBJECT_HAS_NO_FUNCTIONS;
|
||||||
|
}
|
||||||
|
store_address_t storeId;
|
||||||
|
ReturnValue_t result = ipcStore->addData(&storeId, data, size);
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return sendCommand(receiver->getCommandQueue(), actionId, storeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t CommandActionHelper::sendCommand(MessageQueueId_t queueId,
|
||||||
|
ActionId_t actionId, store_address_t storeId) {
|
||||||
|
CommandMessage command;
|
||||||
|
ActionMessage::setCommand(&command, actionId, storeId);
|
||||||
|
ReturnValue_t result = queueToUse->sendMessage(queueId, &command);
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
ipcStore->deleteData(storeId);
|
||||||
|
}
|
||||||
|
lastTarget = queueId;
|
||||||
|
commandCount++;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t CommandActionHelper::initialize() {
|
||||||
|
ipcStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE);
|
||||||
|
if (ipcStore != NULL) {
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
} else {
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t CommandActionHelper::handleReply(CommandMessage* reply) {
|
||||||
|
if (reply->getSender() != lastTarget) {
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
switch (reply->getCommand()) {
|
||||||
|
case ActionMessage::COMPLETION_SUCCESS:
|
||||||
|
commandCount--;
|
||||||
|
owner->completionSuccessfulReceived(ActionMessage::getActionId(reply));
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
case ActionMessage::COMPLETION_FAILED:
|
||||||
|
commandCount--;
|
||||||
|
owner->completionFailedReceived(ActionMessage::getActionId(reply), ActionMessage::getReturnCode(reply));
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
case ActionMessage::STEP_SUCCESS:
|
||||||
|
owner->stepSuccessfulReceived(ActionMessage::getActionId(reply),
|
||||||
|
ActionMessage::getStep(reply));
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
case ActionMessage::STEP_FAILED:
|
||||||
|
commandCount--;
|
||||||
|
owner->stepFailedReceived(ActionMessage::getActionId(reply), ActionMessage::getStep(reply),
|
||||||
|
ActionMessage::getReturnCode(reply));
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
case ActionMessage::DATA_REPLY:
|
||||||
|
extractDataForOwner(ActionMessage::getActionId(reply), ActionMessage::getStoreId(reply));
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
default:
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t CommandActionHelper::getCommandCount() const {
|
||||||
|
return commandCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommandActionHelper::extractDataForOwner(ActionId_t actionId, store_address_t storeId) {
|
||||||
|
const uint8_t * data = NULL;
|
||||||
|
uint32_t size = 0;
|
||||||
|
ReturnValue_t result = ipcStore->getData(storeId, &data, &size);
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
owner->dataReceived(actionId, data, size);
|
||||||
|
ipcStore->deleteData(storeId);
|
||||||
|
}
|
37
action/CommandActionHelper.h
Normal file
37
action/CommandActionHelper.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
|
||||||
|
#ifndef COMMANDACTIONHELPER_H_
|
||||||
|
#define COMMANDACTIONHELPER_H_
|
||||||
|
|
||||||
|
#include <framework/action/ActionMessage.h>
|
||||||
|
#include <framework/ipc/MessageQueue.h>
|
||||||
|
#include <framework/objectmanager/ObjectManagerIF.h>
|
||||||
|
#include <framework/returnvalues/HasReturnvaluesIF.h>
|
||||||
|
#include <framework/serialize/SerializeIF.h>
|
||||||
|
#include <framework/storagemanager/StorageManagerIF.h>
|
||||||
|
|
||||||
|
class CommandsActionsIF;
|
||||||
|
|
||||||
|
class CommandActionHelper {
|
||||||
|
friend class CommandsActionsIF;
|
||||||
|
public:
|
||||||
|
CommandActionHelper(CommandsActionsIF* owner);
|
||||||
|
virtual ~CommandActionHelper();
|
||||||
|
ReturnValue_t commandAction(object_id_t commandTo,
|
||||||
|
ActionId_t actionId, const uint8_t* data, uint32_t size);
|
||||||
|
ReturnValue_t commandAction(object_id_t commandTo,
|
||||||
|
ActionId_t actionId, SerializeIF* data);
|
||||||
|
ReturnValue_t initialize();
|
||||||
|
ReturnValue_t handleReply(CommandMessage* reply);
|
||||||
|
uint8_t getCommandCount() const;
|
||||||
|
private:
|
||||||
|
CommandsActionsIF* owner;
|
||||||
|
MessageQueue* queueToUse;
|
||||||
|
StorageManagerIF* ipcStore;
|
||||||
|
uint8_t commandCount;
|
||||||
|
MessageQueueId_t lastTarget;
|
||||||
|
void extractDataForOwner(ActionId_t actionId, store_address_t storeId);
|
||||||
|
ReturnValue_t sendCommand(MessageQueueId_t queueId, ActionId_t actionId,
|
||||||
|
store_address_t storeId);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* COMMANDACTIONHELPER_H_ */
|
35
action/CommandsActionsIF.h
Normal file
35
action/CommandsActionsIF.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
|
||||||
|
#ifndef COMMANDSACTIONSIF_H_
|
||||||
|
#define COMMANDSACTIONSIF_H_
|
||||||
|
|
||||||
|
#include <framework/action/CommandActionHelper.h>
|
||||||
|
#include <framework/ipc/MessageQueue.h>
|
||||||
|
#include <framework/returnvalues/HasReturnvaluesIF.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface to separate commanding actions of other objects.
|
||||||
|
* In next iteration, IF should be shortened to three calls:
|
||||||
|
* - dataReceived(data)
|
||||||
|
* - successReceived(id, step)
|
||||||
|
* - failureReceived(id, step, cause)
|
||||||
|
* or even
|
||||||
|
* - replyReceived(id, step, cause) (if cause == OK, it's a success).
|
||||||
|
*/
|
||||||
|
class CommandsActionsIF {
|
||||||
|
friend class CommandActionHelper;
|
||||||
|
public:
|
||||||
|
static const uint8_t INTERFACE_ID = COMMANDS_ACTIONS_IF;
|
||||||
|
static const ReturnValue_t OBJECT_HAS_NO_FUNCTIONS = MAKE_RETURN_CODE(1);
|
||||||
|
static const ReturnValue_t ALREADY_COMMANDING = MAKE_RETURN_CODE(2);
|
||||||
|
virtual ~CommandsActionsIF() {}
|
||||||
|
virtual MessageQueue* getCommandQueuePtr() = 0;
|
||||||
|
protected:
|
||||||
|
virtual void stepSuccessfulReceived(ActionId_t actionId, uint8_t step) = 0;
|
||||||
|
virtual void stepFailedReceived(ActionId_t actionId, uint8_t step, ReturnValue_t returnCode) = 0;
|
||||||
|
virtual void dataReceived(ActionId_t actionId, const uint8_t* data, uint32_t size) = 0;
|
||||||
|
virtual void completionSuccessfulReceived(ActionId_t actionId) = 0;
|
||||||
|
virtual void completionFailedReceived(ActionId_t actionId, ReturnValue_t returnCode) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* COMMANDSACTIONSIF_H_ */
|
35
action/HasActionsIF.h
Normal file
35
action/HasActionsIF.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* HasActionsIF.h
|
||||||
|
*
|
||||||
|
* Created on: 20.02.2014
|
||||||
|
* Author: baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HASACTIONSIF_H_
|
||||||
|
#define HASACTIONSIF_H_
|
||||||
|
|
||||||
|
#include <framework/action/ActionHelper.h>
|
||||||
|
#include <framework/action/ActionMessage.h>
|
||||||
|
#include <framework/action/SimpleActionHelper.h>
|
||||||
|
#include <framework/ipc/MessageQueue.h>
|
||||||
|
#include <framework/returnvalues/HasReturnvaluesIF.h>
|
||||||
|
class HasActionsIF {
|
||||||
|
public:
|
||||||
|
static const uint8_t INTERFACE_ID = HAS_ACTIONS_IF;
|
||||||
|
static const ReturnValue_t IS_BUSY = MAKE_RETURN_CODE(1);
|
||||||
|
static const ReturnValue_t INVALID_PARAMETERS = MAKE_RETURN_CODE(2);
|
||||||
|
static const ReturnValue_t EXECUTION_FINISHED = MAKE_RETURN_CODE(3);
|
||||||
|
static const ReturnValue_t INVALID_ACTION_ID = MAKE_RETURN_CODE(4);
|
||||||
|
virtual ~HasActionsIF() { }
|
||||||
|
virtual MessageQueueId_t getCommandQueue() const = 0;
|
||||||
|
/**
|
||||||
|
* Execute or initialize the execution of a certain function.
|
||||||
|
* Returning #EXECUTION_FINISHED or a failure code, nothing else needs to be done.
|
||||||
|
* When needing more steps, return RETURN_OK and issue steps and completion manually. One "step failed" or completion report must
|
||||||
|
* be issued!
|
||||||
|
*/
|
||||||
|
virtual ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy, const uint8_t* data, uint32_t size) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* HASACTIONSIF_H_ */
|
75
action/SimpleActionHelper.cpp
Normal file
75
action/SimpleActionHelper.cpp
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
|
||||||
|
#include <framework/action/HasActionsIF.h>
|
||||||
|
#include <framework/action/SimpleActionHelper.h>
|
||||||
|
SimpleActionHelper::SimpleActionHelper(HasActionsIF* setOwner,
|
||||||
|
MessageQueue* useThisQueue) :
|
||||||
|
ActionHelper(setOwner, useThisQueue), isExecuting(false), lastCommander(
|
||||||
|
0), lastAction(0), stepCount(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleActionHelper::~SimpleActionHelper() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleActionHelper::step(ReturnValue_t result) {
|
||||||
|
//STEP_OFFESET is subtracted to compensate for adding offset in base method, which is not necessary here.
|
||||||
|
ActionHelper::step(stepCount - STEP_OFFSET, lastCommander, lastAction,
|
||||||
|
result);
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
resetHelper();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleActionHelper::finish(ReturnValue_t result) {
|
||||||
|
ActionHelper::finish(lastCommander, lastAction, result);
|
||||||
|
resetHelper();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleActionHelper::reportData(SerializeIF* data) {
|
||||||
|
ActionHelper::reportData(lastCommander, lastAction, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleActionHelper::resetHelper() {
|
||||||
|
stepCount = 0;
|
||||||
|
isExecuting = false;
|
||||||
|
lastAction = 0;
|
||||||
|
lastCommander = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleActionHelper::prepareExecution(MessageQueueId_t commandedBy,
|
||||||
|
ActionId_t actionId, store_address_t dataAddress) {
|
||||||
|
CommandMessage reply;
|
||||||
|
if (isExecuting) {
|
||||||
|
ipcStore->deleteData(dataAddress);
|
||||||
|
ActionMessage::setStepReply(&reply, actionId, 0,
|
||||||
|
HasActionsIF::IS_BUSY);
|
||||||
|
queueToUse->sendMessage(commandedBy, &reply);
|
||||||
|
}
|
||||||
|
const uint8_t* dataPtr = NULL;
|
||||||
|
uint32_t size = 0;
|
||||||
|
ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size);
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
ActionMessage::setStepReply(&reply, actionId, 0, result);
|
||||||
|
queueToUse->sendMessage(commandedBy, &reply);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lastCommander = commandedBy;
|
||||||
|
lastAction = actionId;
|
||||||
|
result = owner->executeAction(actionId, commandedBy, dataPtr, size);
|
||||||
|
ipcStore->deleteData(dataAddress);
|
||||||
|
switch (result) {
|
||||||
|
case HasReturnvaluesIF::RETURN_OK:
|
||||||
|
isExecuting = true;
|
||||||
|
stepCount++;
|
||||||
|
break;
|
||||||
|
case HasActionsIF::EXECUTION_FINISHED:
|
||||||
|
ActionMessage::setCompletionReply(&reply, actionId,
|
||||||
|
HasReturnvaluesIF::RETURN_OK);
|
||||||
|
queueToUse->sendMessage(commandedBy, &reply);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ActionMessage::setStepReply(&reply, actionId, 0, result);
|
||||||
|
queueToUse->sendMessage(commandedBy, &reply);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
24
action/SimpleActionHelper.h
Normal file
24
action/SimpleActionHelper.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
|
||||||
|
#ifndef SIMPLEACTIONHELPER_H_
|
||||||
|
#define SIMPLEACTIONHELPER_H_
|
||||||
|
|
||||||
|
#include <framework/action/ActionHelper.h>
|
||||||
|
|
||||||
|
class SimpleActionHelper: public ActionHelper {
|
||||||
|
public:
|
||||||
|
SimpleActionHelper(HasActionsIF* setOwner, MessageQueue* useThisQueue);
|
||||||
|
virtual ~SimpleActionHelper();
|
||||||
|
void step(ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
|
||||||
|
void finish(ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
|
||||||
|
void reportData(SerializeIF* data);
|
||||||
|
void resetHelper();
|
||||||
|
protected:
|
||||||
|
void prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId, store_address_t dataAddress);
|
||||||
|
private:
|
||||||
|
bool isExecuting;
|
||||||
|
MessageQueueId_t lastCommander;
|
||||||
|
ActionId_t lastAction;
|
||||||
|
uint8_t stepCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* SIMPLEACTIONHELPER_H_ */
|
245
container/ArrayList.h
Normal file
245
container/ArrayList.h
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
#ifndef ARRAYLIST_H_
|
||||||
|
#define ARRAYLIST_H_
|
||||||
|
|
||||||
|
#include <framework/returnvalues/HasReturnvaluesIF.h>
|
||||||
|
#include <framework/serialize/SerializeAdapter.h>
|
||||||
|
#include <framework/serialize/SerializeIF.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A List that stores its values in an array.
|
||||||
|
*
|
||||||
|
* The backend is an array that can be allocated by the class itself or supplied via ctor.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @ingroup container
|
||||||
|
*/
|
||||||
|
template<typename T, typename count_t = uint8_t>
|
||||||
|
class ArrayList {
|
||||||
|
template<typename U, typename count> friend class SerialArrayListAdapter;
|
||||||
|
public:
|
||||||
|
static const uint8_t INTERFACE_ID = ARRAY_LIST;
|
||||||
|
static const ReturnValue_t FULL = MAKE_RETURN_CODE(0x01);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An Iterator to go trough an ArrayList
|
||||||
|
*
|
||||||
|
* It stores a pointer to an element and increments the
|
||||||
|
* pointer when incremented itself.
|
||||||
|
*/
|
||||||
|
class Iterator {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Empty ctor, points to NULL
|
||||||
|
*/
|
||||||
|
Iterator() :
|
||||||
|
value(0) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the Iterator to point to an element
|
||||||
|
*
|
||||||
|
* @param initialize
|
||||||
|
*/
|
||||||
|
Iterator(T *initialize) {
|
||||||
|
value = initialize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current element the iterator points to
|
||||||
|
*/
|
||||||
|
T *value;
|
||||||
|
|
||||||
|
Iterator& operator++() {
|
||||||
|
value++;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator operator++(int) {
|
||||||
|
Iterator tmp(*this);
|
||||||
|
operator++();
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator& operator--() {
|
||||||
|
value--;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator operator--(int) {
|
||||||
|
Iterator tmp(*this);
|
||||||
|
operator--();
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
T operator*() {
|
||||||
|
return *value;
|
||||||
|
}
|
||||||
|
|
||||||
|
T *operator->() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
//SHOULDDO this should be implemented as non-member
|
||||||
|
bool operator==(const typename ArrayList<T, count_t>::Iterator& other) {
|
||||||
|
return (value == other.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//SHOULDDO this should be implemented as non-member
|
||||||
|
bool operator!=(const typename ArrayList<T, count_t>::Iterator& other) {
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of Elements stored in this List
|
||||||
|
*/
|
||||||
|
count_t size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the allocating constructor;
|
||||||
|
*
|
||||||
|
* It allocates an array of the specified size.
|
||||||
|
*
|
||||||
|
* @param maxSize
|
||||||
|
*/
|
||||||
|
ArrayList(count_t maxSize) :
|
||||||
|
size(0), maxSize_(maxSize), allocated(true) {
|
||||||
|
entries = new T[maxSize];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the non-allocating constructor
|
||||||
|
*
|
||||||
|
* It expects a pointer to an array of a certain size and initializes itself to it.
|
||||||
|
*
|
||||||
|
* @param storage the array to use as backend
|
||||||
|
* @param maxSize size of storage
|
||||||
|
*/
|
||||||
|
ArrayList(T *storage, count_t maxSize) :
|
||||||
|
size(0), entries(storage), maxSize_(maxSize), allocated(false) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destructor, if the allocating constructor was used, it deletes the array.
|
||||||
|
*/
|
||||||
|
virtual ~ArrayList() {
|
||||||
|
if (allocated) {
|
||||||
|
delete[] entries;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterator pointing to the first stored elmement
|
||||||
|
*
|
||||||
|
* @return Iterator to the first element
|
||||||
|
*/
|
||||||
|
Iterator begin() const {
|
||||||
|
return Iterator(&entries[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns an Iterator pointing to the element after the last stored entry
|
||||||
|
*
|
||||||
|
* @return Iterator to the element after the last entry
|
||||||
|
*/
|
||||||
|
Iterator end() const {
|
||||||
|
return Iterator(&entries[size]);
|
||||||
|
}
|
||||||
|
|
||||||
|
T & operator[](count_t i) const {
|
||||||
|
return entries[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The first element
|
||||||
|
*
|
||||||
|
* @return pointer to the first stored element
|
||||||
|
*/
|
||||||
|
T *front() {
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The last element
|
||||||
|
*
|
||||||
|
* does not return a valid pointer if called on an empty list.
|
||||||
|
*
|
||||||
|
* @return pointer to the last stored element
|
||||||
|
*/
|
||||||
|
T *back() {
|
||||||
|
return &entries[size - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum number of elements this List can contain
|
||||||
|
*
|
||||||
|
* @return maximum number of elements
|
||||||
|
*/
|
||||||
|
uint32_t maxSize() const {
|
||||||
|
return this->maxSize_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert a new element into the list.
|
||||||
|
*
|
||||||
|
* The new element is inserted after the last stored element.
|
||||||
|
*
|
||||||
|
* @param entry
|
||||||
|
* @return
|
||||||
|
* -@c FULL if the List is full
|
||||||
|
* -@c RETURN_OK else
|
||||||
|
*/
|
||||||
|
ReturnValue_t insert(T entry) {
|
||||||
|
if (size >= maxSize_) {
|
||||||
|
return FULL;
|
||||||
|
}
|
||||||
|
entries[size] = entry;
|
||||||
|
++size;
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clear the List
|
||||||
|
*
|
||||||
|
* This does not actually clear all entries, it only sets the size to 0.
|
||||||
|
*/
|
||||||
|
void clear() {
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
count_t remaining() {
|
||||||
|
return (maxSize_ - size);
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* pointer to the array in which the entries are stored
|
||||||
|
*/
|
||||||
|
T *entries;
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* This is the copy constructor
|
||||||
|
*
|
||||||
|
* It is private, as copying is too ambigous in this case. (Allocate a new backend? Use the same?
|
||||||
|
* What to do in an modifying call?)
|
||||||
|
*
|
||||||
|
* @param other
|
||||||
|
*/
|
||||||
|
ArrayList(const ArrayList& other) :
|
||||||
|
size(other.size), entries(other.entries), maxSize_(other.maxSize_), allocated(
|
||||||
|
false) {
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* remembering the maximum size
|
||||||
|
*/
|
||||||
|
uint32_t maxSize_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* true if the array was allocated and needs to be deleted in the destructor.
|
||||||
|
*/
|
||||||
|
bool allocated;
|
||||||
|
|
||||||
|
};
|
||||||
|
#endif /* ARRAYLIST_H_ */
|
163
container/BinaryTree.h
Normal file
163
container/BinaryTree.h
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
/*
|
||||||
|
* BinaryTree.h
|
||||||
|
*
|
||||||
|
* Created on: 09.03.2015
|
||||||
|
* Author: baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FRAMEWORK_CONTAINER_BINARYTREE_H_
|
||||||
|
#define FRAMEWORK_CONTAINER_BINARYTREE_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <map>
|
||||||
|
template<typename Tp>
|
||||||
|
class BinaryNode {
|
||||||
|
public:
|
||||||
|
BinaryNode(Tp* setValue) :
|
||||||
|
value(setValue), left(NULL), right(NULL), parent(NULL) {
|
||||||
|
}
|
||||||
|
Tp *value;
|
||||||
|
BinaryNode* left;
|
||||||
|
BinaryNode* right;
|
||||||
|
BinaryNode* parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Tp>
|
||||||
|
class ExplicitNodeIterator {
|
||||||
|
public:
|
||||||
|
typedef ExplicitNodeIterator<Tp> _Self;
|
||||||
|
typedef BinaryNode<Tp> _Node;
|
||||||
|
typedef Tp value_type;
|
||||||
|
typedef Tp* pointer;
|
||||||
|
typedef Tp& reference;
|
||||||
|
ExplicitNodeIterator() :
|
||||||
|
element(NULL) {
|
||||||
|
}
|
||||||
|
ExplicitNodeIterator(_Node* node) :
|
||||||
|
element(node) {
|
||||||
|
}
|
||||||
|
BinaryNode<Tp>* element;
|
||||||
|
_Self up() {
|
||||||
|
return _Self(element->parent);
|
||||||
|
}
|
||||||
|
_Self left() {
|
||||||
|
if (element != NULL) {
|
||||||
|
return _Self(element->left);
|
||||||
|
} else {
|
||||||
|
return _Self(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
_Self right() {
|
||||||
|
if (element != NULL) {
|
||||||
|
return _Self(element->right);
|
||||||
|
} else {
|
||||||
|
return _Self(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
bool operator==(const _Self& __x) const {
|
||||||
|
return element == __x.element;
|
||||||
|
}
|
||||||
|
bool operator!=(const _Self& __x) const {
|
||||||
|
return element != __x.element;
|
||||||
|
}
|
||||||
|
pointer
|
||||||
|
operator->() const {
|
||||||
|
if (element != NULL) {
|
||||||
|
return element->value;
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pointer operator*() const {
|
||||||
|
return this->operator->();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pretty rudimentary version of a simple binary tree (not a binary search tree!).
|
||||||
|
*/
|
||||||
|
template<typename Tp>
|
||||||
|
class BinaryTree {
|
||||||
|
public:
|
||||||
|
typedef ExplicitNodeIterator<Tp> iterator;
|
||||||
|
typedef BinaryNode<Tp> Node;
|
||||||
|
typedef std::pair<iterator, iterator> children;
|
||||||
|
BinaryTree() :
|
||||||
|
rootNode(NULL) {
|
||||||
|
}
|
||||||
|
BinaryTree(Node* rootNode) :
|
||||||
|
rootNode(rootNode) {
|
||||||
|
}
|
||||||
|
iterator begin() const {
|
||||||
|
return iterator(rootNode);
|
||||||
|
}
|
||||||
|
static iterator end() {
|
||||||
|
return iterator(NULL);
|
||||||
|
}
|
||||||
|
iterator insert(bool insertLeft, iterator parentNode, Node* newNode ) {
|
||||||
|
newNode->parent = parentNode.element;
|
||||||
|
//TODO: Why do I delete the child references of the node? This kills reconnection :-p
|
||||||
|
// newNode->left = NULL;
|
||||||
|
// newNode->right = NULL;
|
||||||
|
if (parentNode.element != NULL) {
|
||||||
|
if (insertLeft) {
|
||||||
|
parentNode.element->left = newNode;
|
||||||
|
} else {
|
||||||
|
parentNode.element->right = newNode;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//Insert first element.
|
||||||
|
rootNode = newNode;
|
||||||
|
}
|
||||||
|
return iterator(newNode);
|
||||||
|
}
|
||||||
|
//No recursion to children. Needs to be done externally.
|
||||||
|
children erase(iterator node) {
|
||||||
|
if (node.element == rootNode) {
|
||||||
|
//We're root node
|
||||||
|
rootNode = NULL;
|
||||||
|
} else {
|
||||||
|
//Delete parent's reference
|
||||||
|
if (node.up().left() == node) {
|
||||||
|
node.up().element->left = NULL;
|
||||||
|
} else {
|
||||||
|
node.up().element->right = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return children(node.element->left, node.element->right);
|
||||||
|
}
|
||||||
|
static uint32_t countLeft(iterator start) {
|
||||||
|
if (start == end()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
//We also count the start node itself.
|
||||||
|
uint32_t count = 1;
|
||||||
|
while (start.left() != end()) {
|
||||||
|
count++;
|
||||||
|
start = start.left();
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
static uint32_t countRight(iterator start) {
|
||||||
|
if (start == end()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
//We also count the start node itself.
|
||||||
|
uint32_t count = 1;
|
||||||
|
while (start.right() != end()) {
|
||||||
|
count++;
|
||||||
|
start = start.right();
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Node* rootNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* FRAMEWORK_CONTAINER_BINARYTREE_H_ */
|
62
container/FIFO.h
Normal file
62
container/FIFO.h
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
#ifndef FIFO_H_
|
||||||
|
#define FIFO_H_
|
||||||
|
|
||||||
|
#include <framework/returnvalues/HasReturnvaluesIF.h>
|
||||||
|
|
||||||
|
template<typename T, uint8_t capacity>
|
||||||
|
class FIFO {
|
||||||
|
private:
|
||||||
|
uint8_t readIndex, writeIndex, currentSize;
|
||||||
|
T data[capacity];
|
||||||
|
|
||||||
|
uint8_t next(uint8_t current) {
|
||||||
|
++current;
|
||||||
|
if (current == capacity) {
|
||||||
|
current = 0;
|
||||||
|
}
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
FIFO() :
|
||||||
|
readIndex(0), writeIndex(0), currentSize(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool emtpy() {
|
||||||
|
return (currentSize == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool full() {
|
||||||
|
return (currentSize == capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t size(){
|
||||||
|
return currentSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t insert(T value) {
|
||||||
|
if (full()) {
|
||||||
|
return FULL;
|
||||||
|
} else {
|
||||||
|
data[writeIndex] = value;
|
||||||
|
writeIndex = next(writeIndex);
|
||||||
|
++currentSize;
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t retrieve(T *value) {
|
||||||
|
if (emtpy()) {
|
||||||
|
return EMPTY;
|
||||||
|
} else {
|
||||||
|
*value = data[readIndex];
|
||||||
|
readIndex = next(readIndex);
|
||||||
|
--currentSize;
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static const uint8_t INTERFACE_ID = FIFO_CLASS;
|
||||||
|
static const ReturnValue_t FULL = MAKE_RETURN_CODE(1);
|
||||||
|
static const ReturnValue_t EMPTY = MAKE_RETURN_CODE(2);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* FIFO_H_ */
|
32
container/FixedArrayList.h
Normal file
32
container/FixedArrayList.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#ifndef FIXEDARRAYLIST_H_
|
||||||
|
#define FIXEDARRAYLIST_H_
|
||||||
|
|
||||||
|
#include <framework/container/ArrayList.h>
|
||||||
|
|
||||||
|
template<typename T, uint32_t MAX_SIZE, typename count_t = uint8_t>
|
||||||
|
class FixedArrayList: public ArrayList<T, count_t> {
|
||||||
|
private:
|
||||||
|
T data[MAX_SIZE];
|
||||||
|
public:
|
||||||
|
FixedArrayList() :
|
||||||
|
ArrayList<T, count_t>(data, MAX_SIZE) {
|
||||||
|
}
|
||||||
|
|
||||||
|
FixedArrayList(const FixedArrayList& other) :
|
||||||
|
ArrayList<T, count_t>(data, MAX_SIZE) {
|
||||||
|
memcpy(this->data, other.data, sizeof(this->data));
|
||||||
|
this->entries = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
FixedArrayList& operator=(FixedArrayList other) {
|
||||||
|
memcpy(this->data, other.data, sizeof(this->data));
|
||||||
|
this->entries = data;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~FixedArrayList() {
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* FIXEDARRAYLIST_H_ */
|
197
container/FixedMap.h
Normal file
197
container/FixedMap.h
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
#ifndef FIXEDMAP_H_
|
||||||
|
#define FIXEDMAP_H_
|
||||||
|
|
||||||
|
#include <framework/container/ArrayList.h>
|
||||||
|
#include <framework/returnvalues/HasReturnvaluesIF.h>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
|
||||||
|
template<typename key_t, typename T>
|
||||||
|
class FixedMap: public SerializeIF {
|
||||||
|
public:
|
||||||
|
static const uint8_t INTERFACE_ID = FIXED_MAP;
|
||||||
|
static const ReturnValue_t KEY_ALREADY_EXISTS = MAKE_RETURN_CODE(0x01);
|
||||||
|
static const ReturnValue_t MAP_FULL = MAKE_RETURN_CODE(0x02);
|
||||||
|
static const ReturnValue_t KEY_DOES_NOT_EXIST = MAKE_RETURN_CODE(0x03);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const key_t EMPTY_SLOT = -1;
|
||||||
|
ArrayList<std::pair<key_t, T>, uint32_t> theMap;
|
||||||
|
uint32_t _size;
|
||||||
|
|
||||||
|
uint32_t findIndex(key_t key) const {
|
||||||
|
if (_size == 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
uint32_t i = 0;
|
||||||
|
for (i = 0; i < _size; ++i) {
|
||||||
|
if (theMap[i].first == key) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
FixedMap(uint32_t maxSize) :
|
||||||
|
theMap(maxSize), _size(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
class Iterator: public ArrayList<std::pair<key_t, T>, uint32_t>::Iterator {
|
||||||
|
public:
|
||||||
|
Iterator() :
|
||||||
|
ArrayList<std::pair<key_t, T>, uint32_t>::Iterator() {
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator(std::pair<key_t, T> *pair) :
|
||||||
|
ArrayList<std::pair<key_t, T>, uint32_t>::Iterator(pair) {
|
||||||
|
}
|
||||||
|
|
||||||
|
T operator*() {
|
||||||
|
return ArrayList<std::pair<key_t, T>, uint32_t>::Iterator::value->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
T *operator->() {
|
||||||
|
return &ArrayList<std::pair<key_t, T>, uint32_t>::Iterator::value->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
Iterator begin() const {
|
||||||
|
return Iterator(&theMap[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator end() const {
|
||||||
|
return Iterator(&theMap[_size]);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t size() const {
|
||||||
|
return _size;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t insert(key_t key, T value, Iterator *storedValue = NULL) {
|
||||||
|
if (exists(key) == HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
return KEY_ALREADY_EXISTS;
|
||||||
|
}
|
||||||
|
if (_size == theMap.maxSize()) {
|
||||||
|
return MAP_FULL;
|
||||||
|
}
|
||||||
|
theMap[_size].first = key;
|
||||||
|
theMap[_size].second = value;
|
||||||
|
if (storedValue != NULL) {
|
||||||
|
*storedValue = Iterator(&theMap[_size]);
|
||||||
|
}
|
||||||
|
++_size;
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t insert(std::pair<key_t, T> pair) {
|
||||||
|
return insert(pair.fist, pair.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t exists(key_t key) const {
|
||||||
|
ReturnValue_t result = KEY_DOES_NOT_EXIST;
|
||||||
|
if (findIndex(key) < _size) {
|
||||||
|
result = HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t erase(Iterator *iter) {
|
||||||
|
uint32_t i;
|
||||||
|
if ((i = findIndex((*iter).value->first)) >= _size) {
|
||||||
|
return KEY_DOES_NOT_EXIST;
|
||||||
|
}
|
||||||
|
theMap[i] = theMap[_size - 1];
|
||||||
|
--_size;
|
||||||
|
--((*iter).value);
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t erase(key_t key) {
|
||||||
|
uint32_t i;
|
||||||
|
if ((i = findIndex(key)) >= _size) {
|
||||||
|
return KEY_DOES_NOT_EXIST;
|
||||||
|
}
|
||||||
|
theMap[i] = theMap[_size - 1];
|
||||||
|
--_size;
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
T *findValue(key_t key) const {
|
||||||
|
return &theMap[findIndex(key)].second;
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator find(key_t key) const {
|
||||||
|
ReturnValue_t result = exists(key);
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
return end();
|
||||||
|
}
|
||||||
|
return Iterator(&theMap[findIndex(key)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t find(key_t key, T **value) const {
|
||||||
|
ReturnValue_t result = exists(key);
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
*value = &theMap[findIndex(key)].second;
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t maxSize() const {
|
||||||
|
return theMap.maxSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ReturnValue_t serialize(uint8_t** buffer, uint32_t* size,
|
||||||
|
const uint32_t max_size, bool bigEndian) const {
|
||||||
|
ReturnValue_t result = SerializeAdapter<uint32_t>::serialize(&this->_size,
|
||||||
|
buffer, size, max_size, bigEndian);
|
||||||
|
uint32_t i = 0;
|
||||||
|
while ((result == HasReturnvaluesIF::RETURN_OK) && (i < this->_size)) {
|
||||||
|
result = SerializeAdapter<key_t>::serialize(&theMap[i].first, buffer,
|
||||||
|
size, max_size, bigEndian);
|
||||||
|
result = SerializeAdapter<T>::serialize(&theMap[i].second, buffer, size,
|
||||||
|
max_size, bigEndian);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual uint32_t getSerializedSize() const {
|
||||||
|
uint32_t printSize = sizeof(_size);
|
||||||
|
uint32_t i = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < _size; ++i) {
|
||||||
|
printSize += SerializeAdapter<key_t>::getSerializedSize(
|
||||||
|
&theMap[i].first);
|
||||||
|
printSize += SerializeAdapter<T>::getSerializedSize(&theMap[i].second);
|
||||||
|
}
|
||||||
|
|
||||||
|
return printSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size,
|
||||||
|
bool bigEndian) {
|
||||||
|
ReturnValue_t result = SerializeAdapter<uint32_t>::deSerialize(&this->_size,
|
||||||
|
buffer, size, bigEndian);
|
||||||
|
if (this->_size > theMap.maxSize()) {
|
||||||
|
return SerializeIF::TOO_MANY_ELEMENTS;
|
||||||
|
}
|
||||||
|
uint32_t i = 0;
|
||||||
|
while ((result == HasReturnvaluesIF::RETURN_OK) && (i < this->_size)) {
|
||||||
|
result = SerializeAdapter<key_t>::deSerialize(&theMap[i].first, buffer,
|
||||||
|
size, bigEndian);
|
||||||
|
result = SerializeAdapter<T>::deSerialize(&theMap[i].second, buffer, size,
|
||||||
|
bigEndian);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* FIXEDMAP_H_ */
|
186
container/FixedOrderedMultimap.h
Normal file
186
container/FixedOrderedMultimap.h
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
/*
|
||||||
|
* FixedOrderedMultimap.h
|
||||||
|
*
|
||||||
|
* Created on: 22.01.2015
|
||||||
|
* Author: baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FRAMEWORK_CONTAINER_FIXEDORDEREDMULTIMAP_H_
|
||||||
|
#define FRAMEWORK_CONTAINER_FIXEDORDEREDMULTIMAP_H_
|
||||||
|
|
||||||
|
#include <framework/container/ArrayList.h>
|
||||||
|
#include <cstring>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
template<typename key_t, typename T, typename KEY_COMPARE = std::less<key_t>>
|
||||||
|
class FixedOrderedMultimap {
|
||||||
|
public:
|
||||||
|
static const uint8_t INTERFACE_ID = FIXED_MAP;
|
||||||
|
static const ReturnValue_t KEY_ALREADY_EXISTS = MAKE_RETURN_CODE(0x01);
|
||||||
|
static const ReturnValue_t MAP_FULL = MAKE_RETURN_CODE(0x02);
|
||||||
|
static const ReturnValue_t KEY_DOES_NOT_EXIST = MAKE_RETURN_CODE(0x03);
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef KEY_COMPARE compare;
|
||||||
|
compare myComp;
|
||||||
|
ArrayList<std::pair<key_t, T>, uint32_t> theMap;
|
||||||
|
uint32_t _size;
|
||||||
|
|
||||||
|
uint32_t findFirstIndex(key_t key, uint32_t startAt = 0) const {
|
||||||
|
if (startAt >= _size) {
|
||||||
|
return startAt + 1;
|
||||||
|
}
|
||||||
|
uint32_t i = startAt;
|
||||||
|
for (i = startAt; i < _size; ++i) {
|
||||||
|
if (theMap[i].first == key) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t findNicePlace(key_t key) const {
|
||||||
|
uint32_t i = 0;
|
||||||
|
for (i = 0; i < _size; ++i) {
|
||||||
|
if (myComp(key, theMap[i].first)) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeFromPosition(uint32_t position) {
|
||||||
|
if (_size <= position) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memmove(&theMap[position], &theMap[position + 1],
|
||||||
|
(_size - position - 1) * sizeof(std::pair<key_t,T>));
|
||||||
|
--_size;
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
FixedOrderedMultimap(uint32_t maxSize) :
|
||||||
|
theMap(maxSize), _size(0) {
|
||||||
|
}
|
||||||
|
virtual ~FixedOrderedMultimap() {
|
||||||
|
}
|
||||||
|
|
||||||
|
class Iterator: public ArrayList<std::pair<key_t, T>, uint32_t>::Iterator {
|
||||||
|
public:
|
||||||
|
Iterator() :
|
||||||
|
ArrayList<std::pair<key_t, T>, uint32_t>::Iterator() {
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator(std::pair<key_t, T> *pair) :
|
||||||
|
ArrayList<std::pair<key_t, T>, uint32_t>::Iterator(pair) {
|
||||||
|
}
|
||||||
|
|
||||||
|
T operator*() {
|
||||||
|
return ArrayList<std::pair<key_t, T>, uint32_t>::Iterator::value->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
T *operator->() {
|
||||||
|
return &ArrayList<std::pair<key_t, T>, uint32_t>::Iterator::value->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
Iterator begin() const {
|
||||||
|
return Iterator(&theMap[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator end() const {
|
||||||
|
return Iterator(&theMap[_size]);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t size() const {
|
||||||
|
return _size;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t insert(key_t key, T value, Iterator *storedValue = NULL) {
|
||||||
|
if (_size == theMap.maxSize()) {
|
||||||
|
return MAP_FULL;
|
||||||
|
}
|
||||||
|
uint32_t position = findNicePlace(key);
|
||||||
|
memmove(&theMap[position + 1], &theMap[position],
|
||||||
|
(_size - position) * sizeof(std::pair<key_t,T>));
|
||||||
|
theMap[position].first = key;
|
||||||
|
theMap[position].second = value;
|
||||||
|
++_size;
|
||||||
|
if (storedValue != NULL) {
|
||||||
|
*storedValue = Iterator(&theMap[position]);
|
||||||
|
}
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t insert(std::pair<key_t, T> pair) {
|
||||||
|
return insert(pair.fist, pair.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t exists(key_t key) const {
|
||||||
|
ReturnValue_t result = KEY_DOES_NOT_EXIST;
|
||||||
|
if (findFirstIndex(key) < _size) {
|
||||||
|
result = HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t erase(Iterator *iter) {
|
||||||
|
uint32_t i;
|
||||||
|
if ((i = findFirstIndex((*iter).value->first)) >= _size) {
|
||||||
|
return KEY_DOES_NOT_EXIST;
|
||||||
|
}
|
||||||
|
removeFromPosition(i);
|
||||||
|
if (*iter != begin()) {
|
||||||
|
(*iter)--;
|
||||||
|
} else {
|
||||||
|
*iter = begin();
|
||||||
|
}
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t erase(key_t key) {
|
||||||
|
uint32_t i;
|
||||||
|
if ((i = findFirstIndex(key)) >= _size) {
|
||||||
|
return KEY_DOES_NOT_EXIST;
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
removeFromPosition(i);
|
||||||
|
i = findFirstIndex(key, i);
|
||||||
|
} while (i < _size);
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
//This is potentially unsafe
|
||||||
|
// T *findValue(key_t key) const {
|
||||||
|
// return &theMap[findFirstIndex(key)].second;
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
Iterator find(key_t key) const {
|
||||||
|
ReturnValue_t result = exists(key);
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
return end();
|
||||||
|
}
|
||||||
|
return Iterator(&theMap[findFirstIndex(key)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t find(key_t key, T **value) const {
|
||||||
|
ReturnValue_t result = exists(key);
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
*value = &theMap[findFirstIndex(key)].second;
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t maxSize() const {
|
||||||
|
return theMap.maxSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* FRAMEWORK_CONTAINER_FIXEDORDEREDMULTIMAP_H_ */
|
92
container/HybridIterator.h
Normal file
92
container/HybridIterator.h
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
#ifndef HYBRIDITERATOR_H_
|
||||||
|
#define HYBRIDITERATOR_H_
|
||||||
|
|
||||||
|
#include <framework/container/ArrayList.h>
|
||||||
|
#include <framework/container/SinglyLinkedList.h>
|
||||||
|
|
||||||
|
template<typename T, typename count_t = uint8_t>
|
||||||
|
class HybridIterator: public LinkedElement<T>::Iterator,
|
||||||
|
public ArrayList<T, count_t>::Iterator {
|
||||||
|
public:
|
||||||
|
HybridIterator() :
|
||||||
|
value(NULL), linked(NULL), end(NULL) {
|
||||||
|
}
|
||||||
|
|
||||||
|
HybridIterator(typename LinkedElement<T>::Iterator *iter) :
|
||||||
|
LinkedElement<T>::Iterator(*iter), value(
|
||||||
|
iter->value), linked(true), end(NULL) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
HybridIterator(LinkedElement<T> *start) :
|
||||||
|
LinkedElement<T>::Iterator(start), value(
|
||||||
|
start->value), linked(true), end(NULL) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
HybridIterator(typename ArrayList<T, count_t>::Iterator start,
|
||||||
|
typename ArrayList<T, count_t>::Iterator end) :
|
||||||
|
ArrayList<T, count_t>::Iterator(start), value(start.value), linked(
|
||||||
|
false), end(end.value) {
|
||||||
|
if (value == this->end) {
|
||||||
|
value = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HybridIterator(T *firstElement, T *lastElement) :
|
||||||
|
ArrayList<T, count_t>::Iterator(firstElement), value(firstElement), linked(
|
||||||
|
false), end(++lastElement) {
|
||||||
|
if (value == end) {
|
||||||
|
value = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HybridIterator& operator++() {
|
||||||
|
if (linked) {
|
||||||
|
LinkedElement<T>::Iterator::operator++();
|
||||||
|
if (LinkedElement<T>::Iterator::value != NULL) {
|
||||||
|
value = LinkedElement<T>::Iterator::value->value;
|
||||||
|
} else {
|
||||||
|
value = NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ArrayList<T, count_t>::Iterator::operator++();
|
||||||
|
value = ArrayList<T, count_t>::Iterator::value;
|
||||||
|
|
||||||
|
if (value == end) {
|
||||||
|
value = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
HybridIterator operator++(int) {
|
||||||
|
HybridIterator tmp(*this);
|
||||||
|
operator++();
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(HybridIterator other) {
|
||||||
|
return value == other->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(HybridIterator other) {
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
T operator*() {
|
||||||
|
return *value;
|
||||||
|
}
|
||||||
|
|
||||||
|
T *operator->() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
T* value;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool linked;
|
||||||
|
T *end;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* HYBRIDITERATOR_H_ */
|
41
container/IsDerivedFrom.h
Normal file
41
container/IsDerivedFrom.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#ifndef ISDERIVEDFROM_H_
|
||||||
|
#define ISDERIVEDFROM_H_
|
||||||
|
|
||||||
|
template<typename D, typename B>
|
||||||
|
class IsDerivedFrom {
|
||||||
|
class No {
|
||||||
|
};
|
||||||
|
class Yes {
|
||||||
|
No no[3];
|
||||||
|
};
|
||||||
|
|
||||||
|
static Yes Test(B*); // declared, but not defined
|
||||||
|
static No Test(... ); // declared, but not defined
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum {
|
||||||
|
Is = sizeof(Test(static_cast<D*>(0))) == sizeof(Yes)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename, typename>
|
||||||
|
struct is_same {
|
||||||
|
static bool const value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename A>
|
||||||
|
struct is_same<A, A> {
|
||||||
|
static bool const value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<bool C, typename T = void>
|
||||||
|
struct enable_if {
|
||||||
|
typedef T type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct enable_if<false, T> { };
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* ISDERIVEDFROM_H_ */
|
27
container/LinkedElementDecorator.h
Normal file
27
container/LinkedElementDecorator.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* @file LinkedElementDecorator.h
|
||||||
|
* @brief This file defines the LinkedElementDecorator class.
|
||||||
|
* @date 22.07.2014
|
||||||
|
* @author baetz
|
||||||
|
*/
|
||||||
|
#ifndef LINKEDELEMENTDECORATOR_H_
|
||||||
|
#define LINKEDELEMENTDECORATOR_H_
|
||||||
|
|
||||||
|
#include <framework/container/SinglyLinkedList.h>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
//TODO: This generates multiple inheritance from non-IF parents.
|
||||||
|
template<typename T, typename IF_T>
|
||||||
|
class LinkedElementDecorator : public LinkedElement<IF_T>, public T {
|
||||||
|
public:
|
||||||
|
template<typename... Args>
|
||||||
|
LinkedElementDecorator(Args... args) : LinkedElement<IF_T>(this), T(std::forward<Args>(args)...) {
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~LinkedElementDecorator() {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* LINKEDELEMENTDECORATOR_H_ */
|
41
container/PlacementFactory.h
Normal file
41
container/PlacementFactory.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* PlacementFactory.h
|
||||||
|
*
|
||||||
|
* Created on: 10.03.2015
|
||||||
|
* Author: baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FRAMEWORK_CONTAINER_PLACEMENTFACTORY_H_
|
||||||
|
#define FRAMEWORK_CONTAINER_PLACEMENTFACTORY_H_
|
||||||
|
|
||||||
|
#include <framework/storagemanager/StorageManagerIF.h>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
class PlacementFactory {
|
||||||
|
public:
|
||||||
|
PlacementFactory(StorageManagerIF* backend) :
|
||||||
|
dataBackend(backend) {
|
||||||
|
}
|
||||||
|
template<typename T, typename ... Args>
|
||||||
|
T* generate(Args&&... args) {
|
||||||
|
store_address_t tempId;
|
||||||
|
uint8_t* pData = NULL;
|
||||||
|
ReturnValue_t result = dataBackend->getFreeElement(&tempId, sizeof(T),
|
||||||
|
&pData);
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
T* temp = new (pData) T(std::forward<Args>(args)...);
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
template<typename T>
|
||||||
|
ReturnValue_t destroy(T* thisElement) {
|
||||||
|
//TODO: Shouldn't we call the destructor here first, in case something was allocated by the object (shouldn't do that, however).
|
||||||
|
uint8_t* pointer = (uint8_t*) (thisElement);
|
||||||
|
return dataBackend->deleteData(pointer, sizeof(T));
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
StorageManagerIF* dataBackend;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* FRAMEWORK_CONTAINER_PLACEMENTFACTORY_H_ */
|
103
container/RingBufferBase.h
Normal file
103
container/RingBufferBase.h
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* RingBufferBase.h
|
||||||
|
*
|
||||||
|
* Created on: 06.02.2015
|
||||||
|
* Author: baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FRAMEWORK_CONTAINER_RINGBUFFERBASE_H_
|
||||||
|
#define FRAMEWORK_CONTAINER_RINGBUFFERBASE_H_
|
||||||
|
|
||||||
|
#include <framework/returnvalues/HasReturnvaluesIF.h>
|
||||||
|
|
||||||
|
template<uint8_t N_READ_PTRS = 1>
|
||||||
|
class RingBufferBase {
|
||||||
|
public:
|
||||||
|
RingBufferBase(uint32_t startAddress, uint32_t size, bool overwriteOld) :
|
||||||
|
start(startAddress), write(startAddress), size(size), overwriteOld(overwriteOld) {
|
||||||
|
for (uint8_t count = 0; count < N_READ_PTRS; count++) {
|
||||||
|
read[count] = startAddress;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ReturnValue_t readData(uint32_t amount, uint8_t n = 0) {
|
||||||
|
if (availableReadData(n) >= amount) {
|
||||||
|
incrementRead(amount, n);
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
} else {
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ReturnValue_t writeData(uint32_t amount) {
|
||||||
|
if (availableWriteSpace() >= amount || overwriteOld) {
|
||||||
|
incrementWrite(amount);
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
} else {
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint32_t availableReadData(uint8_t n = 0) const {
|
||||||
|
return ((write + size) - read[n]) % size;
|
||||||
|
}
|
||||||
|
uint32_t availableWriteSpace(uint8_t n = 0) const {
|
||||||
|
//One less to avoid ambiguous full/empty problem.
|
||||||
|
return (((read[n] + size) - write - 1) % size);
|
||||||
|
}
|
||||||
|
bool isFull(uint8_t n = 0) {
|
||||||
|
return (availableWriteSpace(n) == 0);
|
||||||
|
}
|
||||||
|
bool isEmpty(uint8_t n = 0) {
|
||||||
|
return (availableReadData(n) == 0);
|
||||||
|
}
|
||||||
|
virtual ~RingBufferBase() {
|
||||||
|
|
||||||
|
}
|
||||||
|
uint32_t getRead(uint8_t n = 0) const {
|
||||||
|
return read[n];
|
||||||
|
}
|
||||||
|
void setRead(uint32_t read, uint8_t n = 0) {
|
||||||
|
if (read >= start && read < (start+size)) {
|
||||||
|
this->read[n] = read;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint32_t getWrite() const {
|
||||||
|
return write;
|
||||||
|
}
|
||||||
|
void setWrite(uint32_t write) {
|
||||||
|
this->write = write;
|
||||||
|
}
|
||||||
|
void clear() {
|
||||||
|
write = start;
|
||||||
|
for (uint8_t count = 0; count < N_READ_PTRS; count++) {
|
||||||
|
read[count] = start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint32_t writeTillWrap() {
|
||||||
|
return (start + size) - write;
|
||||||
|
}
|
||||||
|
uint32_t readTillWrap(uint8_t n = 0) {
|
||||||
|
return (start + size) - read[n];
|
||||||
|
}
|
||||||
|
const uint32_t getStart() const {
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
const bool overwritesOld() const {
|
||||||
|
return overwriteOld;
|
||||||
|
}
|
||||||
|
uint32_t maxSize() const {
|
||||||
|
return size - 1;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
const uint32_t start;
|
||||||
|
uint32_t write;
|
||||||
|
uint32_t read[N_READ_PTRS];
|
||||||
|
const uint32_t size;
|
||||||
|
const bool overwriteOld;
|
||||||
|
void incrementWrite(uint32_t amount) {
|
||||||
|
write = ((write + amount - start) % size) + start;
|
||||||
|
}
|
||||||
|
void incrementRead(uint32_t amount, uint8_t n = 0) {
|
||||||
|
read[n] = ((read[n] + amount - start) % size) + start;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* FRAMEWORK_CONTAINER_RINGBUFFERBASE_H_ */
|
105
container/SinglyLinkedList.h
Normal file
105
container/SinglyLinkedList.h
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
#ifndef SINGLYLINKEDLIST_H_
|
||||||
|
#define SINGLYLINKEDLIST_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class LinkedElement {
|
||||||
|
public:
|
||||||
|
T *value;
|
||||||
|
class Iterator {
|
||||||
|
public:
|
||||||
|
LinkedElement<T> *value;
|
||||||
|
Iterator() :
|
||||||
|
value(NULL) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator(LinkedElement<T> *element) :
|
||||||
|
value(element) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator& operator++() {
|
||||||
|
value = value->getNext();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator operator++(int) {
|
||||||
|
Iterator tmp(*this);
|
||||||
|
operator++();
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(Iterator other) {
|
||||||
|
return value == other.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(Iterator other) {
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
T *operator->() {
|
||||||
|
return value->value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
LinkedElement(T* setElement, LinkedElement<T>* setNext = NULL) : value(setElement),
|
||||||
|
next(setNext) {
|
||||||
|
}
|
||||||
|
virtual ~LinkedElement(){
|
||||||
|
|
||||||
|
}
|
||||||
|
virtual LinkedElement* const getNext() const {
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void setNext(LinkedElement* next) {
|
||||||
|
this->next = next;
|
||||||
|
}
|
||||||
|
LinkedElement* begin() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
LinkedElement* end() {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
LinkedElement *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class SinglyLinkedList {
|
||||||
|
public:
|
||||||
|
SinglyLinkedList() :
|
||||||
|
start(NULL) {
|
||||||
|
}
|
||||||
|
|
||||||
|
SinglyLinkedList(typename LinkedElement<T>::Iterator start) :
|
||||||
|
start(start.value) {
|
||||||
|
}
|
||||||
|
SinglyLinkedList(LinkedElement<T>* startElement) :
|
||||||
|
start(startElement) {
|
||||||
|
}
|
||||||
|
typename LinkedElement<T>::Iterator begin() const {
|
||||||
|
return LinkedElement<T>::Iterator::Iterator(start);
|
||||||
|
}
|
||||||
|
typename LinkedElement<T>::Iterator::Iterator end() const {
|
||||||
|
return LinkedElement<T>::Iterator::Iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t getSize() const {
|
||||||
|
uint32_t size = 0;
|
||||||
|
LinkedElement<T> *element = start;
|
||||||
|
while (element != NULL) {
|
||||||
|
size++;
|
||||||
|
element = element->getNext();
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
void setStart(LinkedElement<T>* setStart) {
|
||||||
|
start = setStart;
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
LinkedElement<T> *start;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* SINGLYLINKEDLIST_H_ */
|
15
container/group.h
Normal file
15
container/group.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef GROUP_H_
|
||||||
|
#define GROUP_H_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup container Container
|
||||||
|
*
|
||||||
|
* General Purpose Container to store various elements.
|
||||||
|
*
|
||||||
|
* Also contains Adapter classes to print elements to a
|
||||||
|
* bytestream and to read them from a bytestream, as well
|
||||||
|
* as an Adapter to swap the endianness.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* GROUP_H_ */
|
365
container/listTest.cpp.ignore
Normal file
365
container/listTest.cpp.ignore
Normal file
@ -0,0 +1,365 @@
|
|||||||
|
#include "FixedArrayList.h"
|
||||||
|
#include "SinglyLinkedList.h"
|
||||||
|
#include "HybridIterator.h"
|
||||||
|
|
||||||
|
#include "FixedMap.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
class Packet: public SinglyLinkedList {
|
||||||
|
public:
|
||||||
|
SinglyLinkedList::Element<uint32_t> element1;
|
||||||
|
SinglyLinkedList::Element<uint32_t> element2;
|
||||||
|
|
||||||
|
Packet() {
|
||||||
|
this->start = &element1;
|
||||||
|
element1.next = &element2;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Packet2: public SinglyLinkedList {
|
||||||
|
public:
|
||||||
|
SinglyLinkedList::Element<uint32_t> element1;
|
||||||
|
SinglyLinkedList::Element<FixedArrayList<FixedArrayList<uint8_t, 5>, 2>> element2;
|
||||||
|
SinglyLinkedList::Element<uint32_t> element3;
|
||||||
|
|
||||||
|
Packet2() {
|
||||||
|
this->start = &element1;
|
||||||
|
element1.next = &element2;
|
||||||
|
element2.next = &element3;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Packet3: public SinglyLinkedList {
|
||||||
|
public:
|
||||||
|
SinglyLinkedList::TypedElement<uint32_t> element1;
|
||||||
|
SinglyLinkedList::TypedElement<uint32_t> element2;
|
||||||
|
|
||||||
|
Packet3() {
|
||||||
|
this->start = &element1;
|
||||||
|
element1.next = &element2;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void arrayList() {
|
||||||
|
puts("** Array List **");
|
||||||
|
FixedArrayList<uint32_t, 10, uint32_t> list;
|
||||||
|
FixedArrayList<uint32_t, 10, uint32_t> list2;
|
||||||
|
|
||||||
|
list.size = 2;
|
||||||
|
|
||||||
|
list[0] = 0xcafecafe;
|
||||||
|
|
||||||
|
list[1] = 0x12345678;
|
||||||
|
|
||||||
|
uint8_t buffer[100];
|
||||||
|
uint8_t *pointer = buffer;
|
||||||
|
uint32_t size = 0;
|
||||||
|
uint32_t maxSize = 100;
|
||||||
|
uint32_t i;
|
||||||
|
int32_t size2;
|
||||||
|
|
||||||
|
printf("printsize: %i\n", list.getPrintSize());
|
||||||
|
|
||||||
|
list.print(&pointer, &size, 100, true);
|
||||||
|
|
||||||
|
printf("buffer(%i):", size);
|
||||||
|
for (i = 0; i < size; ++i) {
|
||||||
|
printf("%02x", buffer[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
pointer = buffer;
|
||||||
|
|
||||||
|
size2 = size;
|
||||||
|
|
||||||
|
printf("list2 read: %x\n", list2.read(&pointer, &size2, true));
|
||||||
|
|
||||||
|
printf("list2(%i):", list2.size);
|
||||||
|
for (ArrayList<uint32_t, uint32_t>::Iterator iter = list2.begin();
|
||||||
|
iter != list2.end(); iter++) {
|
||||||
|
printf("0x%04x ", *iter);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
HybridIterator<uint32_t, uint32_t> hiter(list.begin(),list.end());
|
||||||
|
|
||||||
|
printf("hybrid1: 0x%04x\n", *(hiter++));
|
||||||
|
printf("hybrid2: 0x%04x\n", *hiter);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void allocatingList() {
|
||||||
|
puts("** Allocating List **");
|
||||||
|
ArrayList<uint8_t> myList(3), myList2(2);
|
||||||
|
myList[0] = 0xab;
|
||||||
|
myList[1] = 0xcd;
|
||||||
|
myList.size = 2;
|
||||||
|
|
||||||
|
uint8_t buffer[100];
|
||||||
|
uint8_t *pointer = buffer;
|
||||||
|
uint32_t size = 0;
|
||||||
|
uint32_t maxSize = 100;
|
||||||
|
uint32_t i;
|
||||||
|
int32_t size2;
|
||||||
|
|
||||||
|
myList.print(&pointer, &size, 100, true);
|
||||||
|
|
||||||
|
pointer = buffer;
|
||||||
|
size2 = size;
|
||||||
|
|
||||||
|
printf("Read %x\n", myList2.read(&pointer, &size2, true));
|
||||||
|
|
||||||
|
printf("%x,%x\n", myList2[0], myList2[1]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void linkedList() {
|
||||||
|
puts("** Linked List **");
|
||||||
|
uint8_t buffer[100];
|
||||||
|
uint8_t *pointer = buffer;
|
||||||
|
uint32_t size = 0;
|
||||||
|
uint32_t maxSize = 100;
|
||||||
|
uint32_t i;
|
||||||
|
int32_t size2;
|
||||||
|
|
||||||
|
Packet myPacket;
|
||||||
|
myPacket.element1.entry = 0x12345678;
|
||||||
|
myPacket.element2.entry = 0x9abcdef0;
|
||||||
|
|
||||||
|
pointer = buffer;
|
||||||
|
size = 0;
|
||||||
|
ReturnValue_t result = myPacket.print(&pointer, &size, 100, true);
|
||||||
|
|
||||||
|
printf("result %02x\n", result);
|
||||||
|
|
||||||
|
printf("printsize: %i\n", myPacket.getPrintSize());
|
||||||
|
|
||||||
|
printf("buffer(%i):", size);
|
||||||
|
for (i = 0; i < size; ++i) {
|
||||||
|
printf("%02x", buffer[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
Packet3 myPacket3;
|
||||||
|
|
||||||
|
myPacket3.element1.entry = 0x12345678;
|
||||||
|
myPacket3.element2.entry = 0xabcdeff;
|
||||||
|
|
||||||
|
SinglyLinkedList::TypedIterator<uint32_t> titer(&myPacket3.element1);
|
||||||
|
|
||||||
|
printf("0x%04x\n", *titer);
|
||||||
|
|
||||||
|
HybridIterator<uint32_t, uint32_t> hiter(&myPacket3.element1);
|
||||||
|
|
||||||
|
printf("hybrid1: 0x%04x\n", *hiter);
|
||||||
|
hiter++;
|
||||||
|
printf("hybrid2: 0x%04x\n", *hiter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void complex() {
|
||||||
|
puts("** complex **");
|
||||||
|
uint8_t buffer[100];
|
||||||
|
uint8_t *pointer = buffer;
|
||||||
|
uint32_t size = 0;
|
||||||
|
uint32_t maxSize = 100;
|
||||||
|
uint32_t i;
|
||||||
|
int32_t size2 = size;
|
||||||
|
|
||||||
|
Packet myPacket2;
|
||||||
|
|
||||||
|
size2 = size;
|
||||||
|
pointer = buffer;
|
||||||
|
|
||||||
|
myPacket2.read(&pointer, &size2, true);
|
||||||
|
|
||||||
|
printf("packet: 0x%04x, 0x%04x\n", myPacket2.element1.entry,
|
||||||
|
myPacket2.element2.entry);
|
||||||
|
|
||||||
|
buffer[0] = 0x12;
|
||||||
|
buffer[1] = 0x34;
|
||||||
|
buffer[2] = 0x56;
|
||||||
|
buffer[3] = 0x78;
|
||||||
|
buffer[4] = 0x2;
|
||||||
|
buffer[5] = 0x3;
|
||||||
|
buffer[6] = 0xab;
|
||||||
|
buffer[7] = 0xcd;
|
||||||
|
buffer[8] = 0xef;
|
||||||
|
buffer[9] = 0x2;
|
||||||
|
buffer[10] = 0x11;
|
||||||
|
buffer[11] = 0x22;
|
||||||
|
buffer[12] = 0xca;
|
||||||
|
buffer[13] = 0xfe;
|
||||||
|
buffer[14] = 0x5a;
|
||||||
|
buffer[15] = 0xfe;
|
||||||
|
|
||||||
|
pointer = buffer;
|
||||||
|
size2 = 23;
|
||||||
|
|
||||||
|
Packet2 p2;
|
||||||
|
|
||||||
|
ReturnValue_t result = p2.read(&pointer, &size2, true);
|
||||||
|
printf("result is %02x\n", result);
|
||||||
|
|
||||||
|
printf("%04x; %i: %i: %x %x %x; %i: %x %x;; %04x\n", p2.element1.entry,
|
||||||
|
p2.element2.entry.size, p2.element2.entry[0].size,
|
||||||
|
p2.element2.entry[0][0], p2.element2.entry[0][1],
|
||||||
|
p2.element2.entry[0][2], p2.element2.entry[1].size,
|
||||||
|
p2.element2.entry[1][0], p2.element2.entry[1][1],
|
||||||
|
p2.element3.entry);
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
struct Test {
|
||||||
|
uint32_t a;
|
||||||
|
uint32_t b;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename key_t, typename T>
|
||||||
|
void printMap(FixedMap<key_t, T> *map) {
|
||||||
|
typename FixedMap<key_t, T>::Iterator iter;
|
||||||
|
printf("Map (%i): ", map->getSize());
|
||||||
|
for (iter = map->begin(); iter != map->end(); ++iter) {
|
||||||
|
printf("%x:%08x,%08x ", iter.value->first, (*iter).a, (*iter).b);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void map() {
|
||||||
|
puts("** Map **");
|
||||||
|
typename FixedMap<T, Test>::Iterator iter;
|
||||||
|
ReturnValue_t result;
|
||||||
|
FixedMap<T, Test> myMap(5);
|
||||||
|
|
||||||
|
printMap<T, Test>(&myMap);
|
||||||
|
|
||||||
|
Test a;
|
||||||
|
a.a = 0x01234567;
|
||||||
|
a.b = 0xabcdef89;
|
||||||
|
|
||||||
|
myMap.insert(1, a);
|
||||||
|
printMap<T, Test>(&myMap);
|
||||||
|
|
||||||
|
a.a = 0;
|
||||||
|
|
||||||
|
myMap.insert(2, a);
|
||||||
|
printMap<T, Test>(&myMap);
|
||||||
|
|
||||||
|
printf("2 exists: %x\n", myMap.exists(0x02));
|
||||||
|
|
||||||
|
printf("ff exists: %x\n", myMap.exists(0xff));
|
||||||
|
|
||||||
|
a.a = 1;
|
||||||
|
printf("insert 0x2: %x\n", myMap.insert(2, a));
|
||||||
|
|
||||||
|
result = myMap.insert(0xff, a);
|
||||||
|
a.a = 0x44;
|
||||||
|
result = myMap.insert(0xab, a);
|
||||||
|
result = myMap.insert(0xa, a);
|
||||||
|
|
||||||
|
printMap<T, Test>(&myMap);
|
||||||
|
|
||||||
|
printf("insert 0x5: %x\n", myMap.insert(5, a));
|
||||||
|
|
||||||
|
printf("erase 0xfe: %x\n", myMap.erase(0xfe));
|
||||||
|
|
||||||
|
printf("erase 0x2: %x\n", myMap.erase(0x2));
|
||||||
|
|
||||||
|
printMap<T, Test>(&myMap);
|
||||||
|
|
||||||
|
printf("erase 0xab: %x\n", myMap.erase(0xab));
|
||||||
|
printMap<T, Test>(&myMap);
|
||||||
|
|
||||||
|
printf("insert 0x5: %x\n", myMap.insert(5, a));
|
||||||
|
printMap<T, Test>(&myMap);
|
||||||
|
|
||||||
|
iter = myMap.begin();
|
||||||
|
++iter;
|
||||||
|
++iter;
|
||||||
|
++iter;
|
||||||
|
|
||||||
|
printf("iter: %i: %x,%x\n",iter.value->first, iter->a, iter->b);
|
||||||
|
|
||||||
|
myMap.erase(&iter);
|
||||||
|
|
||||||
|
printf("iter: %i: %x,%x\n",iter.value->first, iter->a, iter->b);
|
||||||
|
printMap<T, Test>(&myMap);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
void mapPrint() {
|
||||||
|
puts("** Map Print **");
|
||||||
|
FixedMap<uint16_t, Packet2> myMap(5);
|
||||||
|
Packet2 myPacket;
|
||||||
|
myPacket.element1.entry = 0x12345678;
|
||||||
|
|
||||||
|
myPacket.element2.entry[0][0] = 0xab;
|
||||||
|
myPacket.element2.entry[0][1] = 0xcd;
|
||||||
|
myPacket.element2.entry[0].size = 2;
|
||||||
|
myPacket.element2.entry.size = 1;
|
||||||
|
|
||||||
|
myPacket.element3.entry = 0xabcdef90;
|
||||||
|
|
||||||
|
myMap.insert(0x1234, myPacket);
|
||||||
|
|
||||||
|
uint8_t buffer[100];
|
||||||
|
uint32_t size = 0, i;
|
||||||
|
uint8_t *pointer = buffer;
|
||||||
|
|
||||||
|
printf("printsize: %i\n", myMap.getPrintSize());
|
||||||
|
|
||||||
|
SerializeAdapter<FixedMap<uint16_t, Packet2>>::print(&myMap, &pointer,
|
||||||
|
&size, 100, false);
|
||||||
|
|
||||||
|
printf("buffer(%i):", size);
|
||||||
|
for (i = 0; i < size; ++i) {
|
||||||
|
printf("%02x", buffer[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
int32_t size2 = size;
|
||||||
|
pointer = buffer;
|
||||||
|
|
||||||
|
FixedMap<uint16_t, Packet2> myMap2(5);
|
||||||
|
|
||||||
|
ReturnValue_t result = SerializeAdapter<FixedMap<uint16_t, Packet2>>::read(
|
||||||
|
&myMap2, &pointer, &size2, false);
|
||||||
|
|
||||||
|
Packet2 *myPacket2 = myMap2.find(0x1234);
|
||||||
|
|
||||||
|
printf("Map (%i): Packet2: %x, Array (%i): Array (%i): %x, %x; %x\n",
|
||||||
|
myMap2.getSize(), myPacket2->element1.entry,
|
||||||
|
myPacket2->element2.entry.size, myPacket2->element2.entry[0].size,
|
||||||
|
myPacket2->element2.entry[0][0], myPacket2->element2.entry[0][1],
|
||||||
|
myPacket2->element3.entry);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void empty() {
|
||||||
|
puts("** Empty **");
|
||||||
|
ArrayList<uint32_t> list(0);
|
||||||
|
printf("%p %p\n", list.front(), list.back());
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
|
||||||
|
// arrayList();
|
||||||
|
// linkedList();
|
||||||
|
// allocatingList();
|
||||||
|
// complex();
|
||||||
|
|
||||||
|
map<uint32_t>();
|
||||||
|
//
|
||||||
|
// mapPrint();
|
||||||
|
|
||||||
|
// empty();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
120
controller/ControllerBase.cpp
Normal file
120
controller/ControllerBase.cpp
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
#include <framework/subsystem/SubsystemBase.h>
|
||||||
|
#include <framework/controller/ControllerBase.h>
|
||||||
|
#include <framework/subsystem/SubsystemBase.h>
|
||||||
|
|
||||||
|
ControllerBase::ControllerBase(uint32_t setObjectId, uint32_t parentId,
|
||||||
|
size_t commandQueueDepth) :
|
||||||
|
SystemObject(setObjectId), parentId(parentId), mode(MODE_OFF), submode(
|
||||||
|
SUBMODE_NONE), commandQueue(commandQueueDepth), modeHelper(
|
||||||
|
this), healthHelper(this, setObjectId) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ControllerBase::~ControllerBase() {
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t ControllerBase::initialize() {
|
||||||
|
ReturnValue_t result = SystemObject::initialize();
|
||||||
|
if (result != 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());
|
||||||
|
}
|
||||||
|
|
||||||
|
result = healthHelper.initialize(parentQueue);
|
||||||
|
if (result != RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = modeHelper.initialize(parentQueue);
|
||||||
|
if (result != RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageQueueId_t ControllerBase::getCommandQueue() const {
|
||||||
|
return commandQueue.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControllerBase::handleQueue() {
|
||||||
|
CommandMessage message;
|
||||||
|
ReturnValue_t result;
|
||||||
|
for (result = commandQueue.receiveMessage(&message); result == RETURN_OK;
|
||||||
|
result = commandQueue.receiveMessage(&message)) {
|
||||||
|
|
||||||
|
result = modeHelper.handleModeCommand(&message);
|
||||||
|
if (result == RETURN_OK) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = healthHelper.handleHealthCommand(&message);
|
||||||
|
if (result == RETURN_OK) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
result = handleCommandMessage(&message);
|
||||||
|
if (result == RETURN_OK) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
message.clearCommandMessage();
|
||||||
|
CommandMessage reply(CommandMessage::REPLY_REJECTED,
|
||||||
|
CommandMessage::UNKNOW_COMMAND, 0);
|
||||||
|
commandQueue.reply(&reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControllerBase::startTransition(Mode_t mode, Submode_t submode) {
|
||||||
|
triggerEvent(CHANGING_MODE, mode, submode);
|
||||||
|
modeHelper.modeChanged(mode, submode);
|
||||||
|
modeChanged(mode, submode);
|
||||||
|
this->mode = mode;
|
||||||
|
this->submode = submode;
|
||||||
|
announceMode(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControllerBase::getMode(Mode_t* mode, Submode_t* submode) {
|
||||||
|
*mode = this->mode;
|
||||||
|
*submode = this->submode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControllerBase::setToExternalControl() {
|
||||||
|
healthHelper.setHealth(EXTERNAL_CONTROL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControllerBase::announceMode(bool recursive) {
|
||||||
|
triggerEvent(MODE_INFO, mode, submode);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t ControllerBase::performOperation() {
|
||||||
|
handleQueue();
|
||||||
|
performControlOperation();
|
||||||
|
return RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControllerBase::modeChanged(Mode_t mode, Submode_t submode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t ControllerBase::setHealth(HealthState health) {
|
||||||
|
switch (health) {
|
||||||
|
case HEALTHY:
|
||||||
|
case EXTERNAL_CONTROL:
|
||||||
|
healthHelper.setHealth(health);
|
||||||
|
return RETURN_OK;
|
||||||
|
default:
|
||||||
|
return INVALID_HEALTH_STATE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HasHealthIF::HealthState ControllerBase::getHealth() {
|
||||||
|
return healthHelper.getHealth();
|
||||||
|
}
|
58
controller/ControllerBase.h
Normal file
58
controller/ControllerBase.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#ifndef CONTROLLERBASE_H_
|
||||||
|
#define CONTROLLERBASE_H_
|
||||||
|
|
||||||
|
#include <framework/health/HasHealthIF.h>
|
||||||
|
#include <framework/health/HealthHelper.h>
|
||||||
|
#include <framework/modes/HasModesIF.h>
|
||||||
|
#include <framework/modes/ModeHelper.h>
|
||||||
|
#include <framework/objectmanager/SystemObject.h>
|
||||||
|
#include <framework/tasks/ExecutableObjectIF.h>
|
||||||
|
|
||||||
|
class ControllerBase: public HasModesIF,
|
||||||
|
public HasHealthIF,
|
||||||
|
public ExecutableObjectIF,
|
||||||
|
public SystemObject,
|
||||||
|
public HasReturnvaluesIF {
|
||||||
|
public:
|
||||||
|
|
||||||
|
static const Mode_t MODE_NORMAL = 2;
|
||||||
|
|
||||||
|
ControllerBase(uint32_t setObjectId, uint32_t parentId, size_t commandQueueDepth = 3);
|
||||||
|
virtual ~ControllerBase();
|
||||||
|
|
||||||
|
ReturnValue_t initialize();
|
||||||
|
|
||||||
|
virtual MessageQueueId_t getCommandQueue() const;
|
||||||
|
|
||||||
|
virtual ReturnValue_t performOperation();
|
||||||
|
|
||||||
|
virtual ReturnValue_t setHealth(HealthState health);
|
||||||
|
|
||||||
|
virtual HasHealthIF::HealthState getHealth();
|
||||||
|
protected:
|
||||||
|
const uint32_t parentId;
|
||||||
|
|
||||||
|
Mode_t mode;
|
||||||
|
|
||||||
|
Submode_t submode;
|
||||||
|
|
||||||
|
MessageQueue commandQueue;
|
||||||
|
|
||||||
|
ModeHelper modeHelper;
|
||||||
|
|
||||||
|
HealthHelper healthHelper;
|
||||||
|
|
||||||
|
void handleQueue();
|
||||||
|
|
||||||
|
virtual ReturnValue_t handleCommandMessage(CommandMessage *message) = 0;
|
||||||
|
virtual void performControlOperation() = 0;
|
||||||
|
virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
||||||
|
uint32_t *msToReachTheMode) = 0;
|
||||||
|
virtual void modeChanged(Mode_t mode, Submode_t submode);
|
||||||
|
virtual void startTransition(Mode_t mode, Submode_t submode);
|
||||||
|
virtual void getMode(Mode_t *mode, Submode_t *submode);
|
||||||
|
virtual void setToExternalControl();
|
||||||
|
virtual void announceMode(bool recursive);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* CONTROLLERBASE_H_ */
|
206
coordinates/CoordinateTransformations.cpp
Normal file
206
coordinates/CoordinateTransformations.cpp
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
#include <framework/coordinates/CoordinateTransformations.h>
|
||||||
|
#include <framework/globalfunctions/constants.h>
|
||||||
|
#include <framework/globalfunctions/math/MatrixOperations.h>
|
||||||
|
#include <framework/globalfunctions/math/VectorOperations.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
|
||||||
|
//TODO move time stuff to OSAL
|
||||||
|
|
||||||
|
void CoordinateTransformations::positionEcfToEci(const double* ecfPosition,
|
||||||
|
double* eciPosition) {
|
||||||
|
ecfToEci(ecfPosition, eciPosition, NULL);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoordinateTransformations::velocityEcfToEci(const double* ecfVelocity,
|
||||||
|
const double* ecfPosition, double* eciVelocity) {
|
||||||
|
ecfToEci(ecfVelocity, eciVelocity, ecfPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
double CoordinateTransformations::getEarthRotationAngle(timeval time) {
|
||||||
|
|
||||||
|
double jD2000UTC = (time.tv_sec - 946728000. + time.tv_usec / 1000000.)
|
||||||
|
/ 24. / 3600.;
|
||||||
|
|
||||||
|
//value of unix time at J2000TT
|
||||||
|
static const double J2000TtUnix = 946727935.816;
|
||||||
|
|
||||||
|
//TT does not have leap seconds
|
||||||
|
//so we need to add the leap seconds since J2000 to our UTC based clock
|
||||||
|
//Conveniently, GPS gives us access to the leap seconds since 1980
|
||||||
|
//between 1980 and 2000 13 leap seconds happened
|
||||||
|
uint8_t leapSecondsSinceJ2000 = utcGpsOffset - 13;
|
||||||
|
|
||||||
|
//Julean centuries since J2000 //TODO fails for dates before now?
|
||||||
|
double TTt2000 = (time.tv_sec + time.tv_usec / 1000000. - J2000TtUnix
|
||||||
|
+ leapSecondsSinceJ2000) / 24. / 3600. / 36525.;
|
||||||
|
|
||||||
|
double theta = 2 * Math::PI
|
||||||
|
* (0.779057273264 + 1.00273781191135448 * jD2000UTC);
|
||||||
|
|
||||||
|
//Correct theta according to IAU 2000 precession-nutation model
|
||||||
|
theta = theta + 7.03270725817493E-008 + 0.0223603701 * TTt2000
|
||||||
|
+ 6.77128219501896E-006 * TTt2000 * TTt2000
|
||||||
|
+ 4.5300990362875E-010 * TTt2000 * TTt2000 * TTt2000
|
||||||
|
+ 9.12419347848147E-011 * TTt2000 * TTt2000 * TTt2000 * TTt2000;
|
||||||
|
return theta;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoordinateTransformations::getEarthRotationMatrix(timeval time,
|
||||||
|
double matrix[][3]) {
|
||||||
|
double theta = getEarthRotationAngle(time);
|
||||||
|
|
||||||
|
matrix[0][0] = cos(theta);
|
||||||
|
matrix[0][1] = sin(theta);
|
||||||
|
matrix[0][2] = 0;
|
||||||
|
matrix[1][0] = -sin(theta);
|
||||||
|
matrix[1][1] = cos(theta);
|
||||||
|
matrix[1][2] = 0;
|
||||||
|
matrix[2][0] = 0;
|
||||||
|
matrix[2][1] = 0;
|
||||||
|
matrix[2][2] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoordinateTransformations::ecfToEci(const double* ecfCoordinates,
|
||||||
|
double* eciCoordinates,
|
||||||
|
const double* ecfPositionIfCoordinatesAreVelocity) {
|
||||||
|
//TODO all calculations only work with a correct time
|
||||||
|
|
||||||
|
timeval time;
|
||||||
|
OSAL::getClock_timeval(&time);
|
||||||
|
|
||||||
|
//value of unix time at J2000TT
|
||||||
|
static const double J2000TtUnix = 946727935.816;
|
||||||
|
|
||||||
|
//we need TT which does not have leap seconds
|
||||||
|
//so we need to add the leap seconds since J2000 to our UTC based clock
|
||||||
|
//Conveniently, GPS gives us access to the leap seconds since 1980
|
||||||
|
//between 1980 and 2000 13 leap seconds happened
|
||||||
|
uint8_t leapSecondsSinceJ2000 = utcGpsOffset - 13;
|
||||||
|
|
||||||
|
//Julean centuries since J2000 //TODO fails for dates before now?
|
||||||
|
double TTt2000 = (time.tv_sec + time.tv_usec / 1000000. - J2000TtUnix
|
||||||
|
+ leapSecondsSinceJ2000) / 24. / 3600. / 36525.;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
// Calculate Precession Matrix
|
||||||
|
|
||||||
|
double zeta = 0.0111808609 * TTt2000
|
||||||
|
+ 1.46355554053347E-006 * TTt2000 * TTt2000
|
||||||
|
+ 8.72567663260943E-008 * TTt2000 * TTt2000 * TTt2000;
|
||||||
|
double theta_p = 0.0097171735 * TTt2000
|
||||||
|
- 2.06845757045384E-006 * TTt2000 * TTt2000
|
||||||
|
- 2.02812107218552E-007 * TTt2000 * TTt2000 * TTt2000;
|
||||||
|
double z = zeta + 3.8436028638364E-006 * TTt2000 * TTt2000
|
||||||
|
+ 0.000000001 * TTt2000 * TTt2000 * TTt2000;
|
||||||
|
|
||||||
|
double mPrecession[3][3];
|
||||||
|
|
||||||
|
mPrecession[0][0] = -sin(z) * sin(zeta) + cos(z) * cos(theta_p) * cos(zeta);
|
||||||
|
mPrecession[1][0] = cos(z) * sin(zeta) + sin(z) * cos(theta_p) * cos(zeta);
|
||||||
|
mPrecession[2][0] = sin(theta_p) * cos(zeta);
|
||||||
|
|
||||||
|
mPrecession[0][1] = -sin(z) * cos(zeta) - cos(z) * cos(theta_p) * sin(zeta);
|
||||||
|
mPrecession[1][1] = cos(z) * cos(zeta) - sin(z) * cos(theta_p) * sin(zeta);
|
||||||
|
mPrecession[2][1] = -sin(theta_p) * sin(zeta);
|
||||||
|
|
||||||
|
mPrecession[0][2] = -cos(z) * sin(theta_p);
|
||||||
|
mPrecession[1][2] = -sin(z) * sin(theta_p);
|
||||||
|
mPrecession[2][2] = cos(theta_p);
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
// Calculate Nutation Matrix
|
||||||
|
|
||||||
|
double omega_moon = 2.1824386244 - 33.7570459338 * TTt2000
|
||||||
|
+ 3.61428599267159E-005 * TTt2000 * TTt2000
|
||||||
|
+ 3.87850944887629E-008 * TTt2000 * TTt2000 * TTt2000;
|
||||||
|
|
||||||
|
double deltaPsi = -0.000083388 * sin(omega_moon);
|
||||||
|
double deltaEpsilon = 4.46174030725106E-005 * cos(omega_moon);
|
||||||
|
|
||||||
|
double epsilon = 0.4090928042 - 0.0002269655 * TTt2000
|
||||||
|
- 2.86040071854626E-009 * TTt2000 * TTt2000
|
||||||
|
+ 8.78967203851589E-009 * TTt2000 * TTt2000 * TTt2000;
|
||||||
|
|
||||||
|
double mNutation[3][3];
|
||||||
|
|
||||||
|
mNutation[0][0] = cos(deltaPsi);
|
||||||
|
mNutation[1][0] = cos(epsilon + deltaEpsilon) * sin(deltaPsi);
|
||||||
|
mNutation[2][0] = sin(epsilon + deltaEpsilon) * sin(deltaPsi);
|
||||||
|
|
||||||
|
mNutation[0][1] = -cos(epsilon) * sin(deltaPsi);
|
||||||
|
mNutation[1][1] = cos(epsilon) * cos(epsilon + deltaEpsilon) * cos(deltaPsi)
|
||||||
|
+ sin(epsilon) * sin(epsilon + deltaEpsilon);
|
||||||
|
mNutation[2][1] = cos(epsilon) * sin(epsilon + deltaEpsilon) * cos(deltaPsi)
|
||||||
|
- sin(epsilon) * cos(epsilon + deltaEpsilon);
|
||||||
|
|
||||||
|
mNutation[0][2] = -sin(epsilon) * sin(deltaPsi);
|
||||||
|
mNutation[1][2] = sin(epsilon) * cos(epsilon + deltaEpsilon) * cos(deltaPsi)
|
||||||
|
- cos(epsilon) * sin(epsilon + deltaEpsilon);
|
||||||
|
mNutation[2][2] = sin(epsilon) * sin(epsilon + deltaEpsilon) * cos(deltaPsi)
|
||||||
|
+ cos(epsilon) * cos(epsilon + deltaEpsilon);
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
// Calculate Earth rotation matrix
|
||||||
|
|
||||||
|
//calculate theta
|
||||||
|
|
||||||
|
double mTheta[3][3];
|
||||||
|
getEarthRotationMatrix(time, mTheta);
|
||||||
|
|
||||||
|
//polar motion is neglected
|
||||||
|
|
||||||
|
double Tfi[3][3];
|
||||||
|
double Ttemp[3][3];
|
||||||
|
double Tif[3][3];
|
||||||
|
|
||||||
|
MatrixOperations<double>::multiply(mNutation[0], mPrecession[0], Ttemp[0],
|
||||||
|
3, 3, 3);
|
||||||
|
MatrixOperations<double>::multiply(mTheta[0], Ttemp[0], Tfi[0], 3, 3, 3);
|
||||||
|
|
||||||
|
MatrixOperations<double>::transpose(Tfi[0], Tif[0], 3);
|
||||||
|
|
||||||
|
MatrixOperations<double>::multiply(Tif[0], ecfCoordinates, eciCoordinates,
|
||||||
|
3, 3, 1);
|
||||||
|
|
||||||
|
if (ecfPositionIfCoordinatesAreVelocity != NULL) {
|
||||||
|
|
||||||
|
double Tdotfi[3][3];
|
||||||
|
double Tdotif[3][3];
|
||||||
|
double Trot[3][3] = { { 0, Earth::OMEGA, 0 },
|
||||||
|
{ 0 - Earth::OMEGA, 0, 0 }, { 0, 0, 0 } };
|
||||||
|
double Ttemp2[3][3];
|
||||||
|
|
||||||
|
MatrixOperations<double>::multiply(mNutation[0], mPrecession[0],
|
||||||
|
Ttemp[0], 3, 3, 3);
|
||||||
|
MatrixOperations<double>::multiply(mTheta[0], Ttemp[0], Ttemp2[0], 3, 3,
|
||||||
|
3);
|
||||||
|
|
||||||
|
MatrixOperations<double>::multiply(Trot[0], Ttemp2[0], Tdotfi[0], 3, 3,
|
||||||
|
3);
|
||||||
|
|
||||||
|
MatrixOperations<double>::transpose(Tdotfi[0], Tdotif[0], 3);
|
||||||
|
|
||||||
|
double velocityCorrection[3];
|
||||||
|
|
||||||
|
MatrixOperations<double>::multiply(Tdotif[0],
|
||||||
|
ecfPositionIfCoordinatesAreVelocity, velocityCorrection, 3, 3,
|
||||||
|
1);
|
||||||
|
|
||||||
|
VectorOperations<double>::add(velocityCorrection, eciCoordinates,
|
||||||
|
eciCoordinates, 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CoordinateTransformations::CoordinateTransformations(uint8_t offset) :
|
||||||
|
utcGpsOffset(offset) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
CoordinateTransformations::~CoordinateTransformations() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoordinateTransformations::setUtcGpsOffset(uint8_t offset) {
|
||||||
|
}
|
29
coordinates/CoordinateTransformations.h
Normal file
29
coordinates/CoordinateTransformations.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#ifndef COORDINATETRANSFORMATIONS_H_
|
||||||
|
#define COORDINATETRANSFORMATIONS_H_
|
||||||
|
|
||||||
|
#include <framework/osal/OSAL.h>
|
||||||
|
|
||||||
|
class CoordinateTransformations {
|
||||||
|
public:
|
||||||
|
CoordinateTransformations(uint8_t utcGpsOffset);
|
||||||
|
|
||||||
|
virtual ~CoordinateTransformations();
|
||||||
|
|
||||||
|
void positionEcfToEci(const double* ecfCoordinates, double* eciCoordinates);
|
||||||
|
|
||||||
|
void velocityEcfToEci(const double* ecfVelocity,
|
||||||
|
const double* ecfPosition,
|
||||||
|
double* eciVelocity);
|
||||||
|
|
||||||
|
double getEarthRotationAngle(timeval time);
|
||||||
|
|
||||||
|
void getEarthRotationMatrix(timeval time, double matrix[][3]);
|
||||||
|
void setUtcGpsOffset(uint8_t offset);
|
||||||
|
private:
|
||||||
|
uint8_t utcGpsOffset;
|
||||||
|
void ecfToEci(const double* ecfCoordinates, double* eciCoordinates,
|
||||||
|
const double* ecfPositionIfCoordinatesAreVelocity);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* COORDINATETRANSFORMATIONS_H_ */
|
228
coordinates/Sgp4Propagator.cpp
Normal file
228
coordinates/Sgp4Propagator.cpp
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
#include <framework/osal/OSAL.h>
|
||||||
|
#include <framework/coordinates/CoordinateTransformations.h>
|
||||||
|
#include <framework/coordinates/Sgp4Propagator.h>
|
||||||
|
#include <framework/globalfunctions/constants.h>
|
||||||
|
#include <framework/globalfunctions/math/MatrixOperations.h>
|
||||||
|
#include <framework/globalfunctions/math/VectorOperations.h>
|
||||||
|
#include <framework/globalfunctions/timevalOperations.h>
|
||||||
|
#include <framework/osal/OSAL.h>
|
||||||
|
|
||||||
|
Sgp4Propagator::Sgp4Propagator() :
|
||||||
|
whichconst(wgs84) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Sgp4Propagator::~Sgp4Propagator() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO move to OSAL
|
||||||
|
void jday(int year, int mon, int day, int hr, int minute, double sec,
|
||||||
|
double& jd) {
|
||||||
|
jd = 367.0 * year - floor((7 * (year + floor((mon + 9) / 12.0))) * 0.25)
|
||||||
|
+ floor(275 * mon / 9.0) + day + 1721013.5
|
||||||
|
+ ((sec / 60.0 + minute) / 60.0 + hr) / 24.0; // ut in days
|
||||||
|
// - 0.5*sgn(100.0*year + mon - 190002.5) + 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO move to OSAL
|
||||||
|
void days2mdhms(int year, double days, int& mon, int& day, int& hr, int& minute,
|
||||||
|
double& sec) {
|
||||||
|
int i, inttemp, dayofyr;
|
||||||
|
double temp;
|
||||||
|
int lmonth[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||||
|
|
||||||
|
dayofyr = (int) floor(days);
|
||||||
|
/* ----------------- find month and day of month ---------------- */
|
||||||
|
if ((year % 4) == 0)
|
||||||
|
lmonth[1] = 29;
|
||||||
|
|
||||||
|
i = 1;
|
||||||
|
inttemp = 0;
|
||||||
|
while ((dayofyr > inttemp + lmonth[i - 1]) && (i < 12)) {
|
||||||
|
inttemp = inttemp + lmonth[i - 1];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
mon = i;
|
||||||
|
day = dayofyr - inttemp;
|
||||||
|
|
||||||
|
/* ----------------- find hours minutes and seconds ------------- */
|
||||||
|
temp = (days - dayofyr) * 24.0;
|
||||||
|
hr = (int) floor(temp);
|
||||||
|
temp = (temp - hr) * 60.0;
|
||||||
|
minute = (int) floor(temp);
|
||||||
|
sec = (temp - minute) * 60.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t Sgp4Propagator::initialize(const uint8_t* line1,
|
||||||
|
const uint8_t* line2) {
|
||||||
|
|
||||||
|
char longstr1[130];
|
||||||
|
char longstr2[130];
|
||||||
|
|
||||||
|
//need some space for decimal points
|
||||||
|
memcpy(longstr1, line1, 69);
|
||||||
|
memcpy(longstr2, line2, 69);
|
||||||
|
|
||||||
|
const double deg2rad = Math::PI / 180.0; // 0.0174532925199433
|
||||||
|
const double xpdotp = 1440.0 / (2.0 * Math::PI); // 229.1831180523293
|
||||||
|
|
||||||
|
double sec, mu, radiusearthkm, tumin, xke, j2, j3, j4, j3oj2;
|
||||||
|
int cardnumb, numb, j;
|
||||||
|
long revnum = 0, elnum = 0;
|
||||||
|
char classification, intldesg[11];
|
||||||
|
int year = 0;
|
||||||
|
int mon, day, hr, minute, nexp, ibexp;
|
||||||
|
|
||||||
|
getgravconst(whichconst, tumin, mu, radiusearthkm, xke, j2, j3, j4, j3oj2);
|
||||||
|
|
||||||
|
satrec.error = 0;
|
||||||
|
|
||||||
|
// set the implied decimal points since doing a formated read
|
||||||
|
// fixes for bad input data values (missing, ...)
|
||||||
|
for (j = 10; j <= 15; j++)
|
||||||
|
if (longstr1[j] == ' ')
|
||||||
|
longstr1[j] = '_';
|
||||||
|
|
||||||
|
if (longstr1[44] != ' ')
|
||||||
|
longstr1[43] = longstr1[44];
|
||||||
|
longstr1[44] = '.';
|
||||||
|
if (longstr1[7] == ' ')
|
||||||
|
longstr1[7] = 'U';
|
||||||
|
if (longstr1[9] == ' ')
|
||||||
|
longstr1[9] = '.';
|
||||||
|
for (j = 45; j <= 49; j++)
|
||||||
|
if (longstr1[j] == ' ')
|
||||||
|
longstr1[j] = '0';
|
||||||
|
if (longstr1[51] == ' ')
|
||||||
|
longstr1[51] = '0';
|
||||||
|
if (longstr1[53] != ' ')
|
||||||
|
longstr1[52] = longstr1[53];
|
||||||
|
longstr1[53] = '.';
|
||||||
|
longstr2[25] = '.';
|
||||||
|
for (j = 26; j <= 32; j++)
|
||||||
|
if (longstr2[j] == ' ')
|
||||||
|
longstr2[j] = '0';
|
||||||
|
if (longstr1[62] == ' ')
|
||||||
|
longstr1[62] = '0';
|
||||||
|
if (longstr1[68] == ' ')
|
||||||
|
longstr1[68] = '0';
|
||||||
|
|
||||||
|
sscanf(longstr1,
|
||||||
|
"%2d %5ld %1c %10s %2d %12lf %11lf %7lf %2d %7lf %2d %2d %6ld ",
|
||||||
|
&cardnumb, &satrec.satnum, &classification, intldesg,
|
||||||
|
&satrec.epochyr, &satrec.epochdays, &satrec.ndot, &satrec.nddot,
|
||||||
|
&nexp, &satrec.bstar, &ibexp, &numb, &elnum);
|
||||||
|
|
||||||
|
if (longstr2[52] == ' ') {
|
||||||
|
sscanf(longstr2, "%2d %5ld %9lf %9lf %8lf %9lf %9lf %10lf %6ld \n",
|
||||||
|
&cardnumb, &satrec.satnum, &satrec.inclo, &satrec.nodeo,
|
||||||
|
&satrec.ecco, &satrec.argpo, &satrec.mo, &satrec.no, &revnum);
|
||||||
|
} else {
|
||||||
|
sscanf(longstr2, "%2d %5ld %9lf %9lf %8lf %9lf %9lf %11lf %6ld \n",
|
||||||
|
&cardnumb, &satrec.satnum, &satrec.inclo, &satrec.nodeo,
|
||||||
|
&satrec.ecco, &satrec.argpo, &satrec.mo, &satrec.no, &revnum);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- find no, ndot, nddot ----
|
||||||
|
satrec.no = satrec.no / xpdotp; //* rad/min
|
||||||
|
satrec.nddot = satrec.nddot * pow(10.0, nexp);
|
||||||
|
satrec.bstar = satrec.bstar * pow(10.0, ibexp);
|
||||||
|
|
||||||
|
// ---- convert to sgp4 units ----
|
||||||
|
satrec.a = pow(satrec.no * tumin, (-2.0 / 3.0));
|
||||||
|
satrec.ndot = satrec.ndot / (xpdotp * 1440.0); //* ? * minperday
|
||||||
|
satrec.nddot = satrec.nddot / (xpdotp * 1440.0 * 1440);
|
||||||
|
|
||||||
|
// ---- find standard orbital elements ----
|
||||||
|
satrec.inclo = satrec.inclo * deg2rad;
|
||||||
|
satrec.nodeo = satrec.nodeo * deg2rad;
|
||||||
|
satrec.argpo = satrec.argpo * deg2rad;
|
||||||
|
satrec.mo = satrec.mo * deg2rad;
|
||||||
|
|
||||||
|
satrec.alta = satrec.a * (1.0 + satrec.ecco) - 1.0;
|
||||||
|
satrec.altp = satrec.a * (1.0 - satrec.ecco) - 1.0;
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------
|
||||||
|
// find sgp4epoch time of element set
|
||||||
|
// remember that sgp4 uses units of days from 0 jan 1950 (sgp4epoch)
|
||||||
|
// and minutes from the epoch (time)
|
||||||
|
// ----------------------------------------------------------------
|
||||||
|
|
||||||
|
// ---------------- temp fix for years from 1957-2056 -------------------
|
||||||
|
// --------- correct fix will occur when year is 4-digit in tle ---------
|
||||||
|
if (satrec.epochyr < 57) {
|
||||||
|
year = satrec.epochyr + 2000;
|
||||||
|
} else {
|
||||||
|
year = satrec.epochyr + 1900;
|
||||||
|
}
|
||||||
|
|
||||||
|
days2mdhms(year, satrec.epochdays, mon, day, hr, minute, sec);
|
||||||
|
jday(year, mon, day, hr, minute, sec, satrec.jdsatepoch);
|
||||||
|
|
||||||
|
double unixSeconds = (satrec.jdsatepoch - 2451544.5) * 24 * 3600
|
||||||
|
+ 946684800;
|
||||||
|
|
||||||
|
epoch.tv_sec = unixSeconds;
|
||||||
|
double subseconds = unixSeconds - epoch.tv_sec;
|
||||||
|
epoch.tv_usec = subseconds * 1000000;
|
||||||
|
|
||||||
|
// ---------------- initialize the orbit at sgp4epoch -------------------
|
||||||
|
uint8_t result = sgp4init(whichconst, satrec.satnum,
|
||||||
|
satrec.jdsatepoch
|
||||||
|
- 2433282.5 /*TODO verify, source says it's 2433281.5*/,
|
||||||
|
satrec.bstar, satrec.ecco, satrec.argpo, satrec.inclo, satrec.mo,
|
||||||
|
satrec.no, satrec.nodeo, satrec);
|
||||||
|
|
||||||
|
if (result != 00) {
|
||||||
|
return MAKE_RETURN_CODE(result);
|
||||||
|
} else {
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t Sgp4Propagator::propagate(double* position, double* velocity,
|
||||||
|
timeval time, uint8_t gpsUtcOffset) {
|
||||||
|
|
||||||
|
//Time since epoch in minutes
|
||||||
|
timeval timeSinceEpoch = time - epoch;
|
||||||
|
double minutesSinceEpoch = timeSinceEpoch.tv_sec / 60. + timeSinceEpoch.tv_usec / 60000000.;
|
||||||
|
|
||||||
|
double yearsSinceEpoch = minutesSinceEpoch / 60 / 24 / 365;
|
||||||
|
|
||||||
|
if ((yearsSinceEpoch > 1) || (yearsSinceEpoch < -1)) {
|
||||||
|
return TLE_TOO_OLD;
|
||||||
|
}
|
||||||
|
|
||||||
|
double positionTEME[3];
|
||||||
|
double velocityTEME[3];
|
||||||
|
|
||||||
|
uint8_t result = sgp4(whichconst, satrec, minutesSinceEpoch, positionTEME,
|
||||||
|
velocityTEME);
|
||||||
|
|
||||||
|
VectorOperations<double>::mulScalar(positionTEME, 1000, positionTEME, 3);
|
||||||
|
VectorOperations<double>::mulScalar(velocityTEME, 1000, velocityTEME, 3);
|
||||||
|
|
||||||
|
//Transform to ECF
|
||||||
|
double earthRotationMatrix[3][3];
|
||||||
|
CoordinateTransformations transform(gpsUtcOffset);
|
||||||
|
transform.getEarthRotationMatrix(time,
|
||||||
|
earthRotationMatrix);
|
||||||
|
|
||||||
|
MatrixOperations<double>::multiply(earthRotationMatrix[0], positionTEME,
|
||||||
|
position, 3, 3, 1);
|
||||||
|
MatrixOperations<double>::multiply(earthRotationMatrix[0], velocityTEME,
|
||||||
|
velocity, 3, 3, 1);
|
||||||
|
|
||||||
|
double omegaEarth[3] = { 0, 0, Earth::OMEGA };
|
||||||
|
double velocityCorrection[3];
|
||||||
|
VectorOperations<double>::cross(omegaEarth, position, velocityCorrection);
|
||||||
|
VectorOperations<double>::subtract(velocity, velocityCorrection, velocity);
|
||||||
|
|
||||||
|
if (result != 0) {
|
||||||
|
return MAKE_RETURN_CODE(result);
|
||||||
|
} else {
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
}
|
42
coordinates/Sgp4Propagator.h
Normal file
42
coordinates/Sgp4Propagator.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#ifndef SGP4PROPAGATOR_H_
|
||||||
|
#define SGP4PROPAGATOR_H_
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <contrib/sgp4/sgp4unit.h>
|
||||||
|
#include <framework/returnvalues/HasReturnvaluesIF.h>
|
||||||
|
|
||||||
|
class Sgp4Propagator {
|
||||||
|
public:
|
||||||
|
static const uint8_t INTERFACE_ID = SGP4PROPAGATOR_CLASS;
|
||||||
|
static const ReturnValue_t INVALID_ECCENTRICITY = MAKE_RETURN_CODE(0x01);
|
||||||
|
static const ReturnValue_t INVALID_MEAN_MOTION = MAKE_RETURN_CODE(0x02);
|
||||||
|
static const ReturnValue_t INVALID_PERTURBATION_ELEMENTS = MAKE_RETURN_CODE(0x03);
|
||||||
|
static const ReturnValue_t INVALID_SEMI_LATUS_RECTUM = MAKE_RETURN_CODE(0x04);
|
||||||
|
static const ReturnValue_t INVALID_EPOCH_ELEMENTS = MAKE_RETURN_CODE(0x05);
|
||||||
|
static const ReturnValue_t SATELLITE_HAS_DECAYED = MAKE_RETURN_CODE(0x06);
|
||||||
|
static const ReturnValue_t TLE_TOO_OLD = MAKE_RETURN_CODE(0xA1);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Sgp4Propagator();
|
||||||
|
virtual ~Sgp4Propagator();
|
||||||
|
|
||||||
|
ReturnValue_t initialize(const uint8_t *line1, const uint8_t *line2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param[out] position in ECF
|
||||||
|
* @param[out] velocity in ECF
|
||||||
|
* @param time to which to propagate
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
ReturnValue_t propagate(double *position, double *velocity, timeval time, uint8_t gpsUtcOffset);
|
||||||
|
|
||||||
|
private:
|
||||||
|
timeval epoch;
|
||||||
|
elsetrec satrec;
|
||||||
|
gravconsttype whichconst;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* SGP4PROPAGATOR_H_ */
|
62
datalinklayer/BCFrame.h
Normal file
62
datalinklayer/BCFrame.h
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/**
|
||||||
|
* @file BCFrame.h
|
||||||
|
* @brief This file defines the BCFrame class.
|
||||||
|
* @date 24.04.2013
|
||||||
|
* @author baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BCFRAME_H_
|
||||||
|
#define BCFRAME_H_
|
||||||
|
|
||||||
|
#include <framework/datalinklayer/CCSDSReturnValuesIF.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Small helper class to identify a BcFrame.
|
||||||
|
* @ingroup ccsds_handling
|
||||||
|
*/
|
||||||
|
class BcFrame: public CCSDSReturnValuesIF {
|
||||||
|
private:
|
||||||
|
static const uint8_t UNLOCK_COMMAND = 0b00000000;//! Identifier for a certain BC Command.
|
||||||
|
static const uint8_t SET_V_R_1 = 0b10000010;//! Identifier for a certain BC Command.
|
||||||
|
static const uint8_t SET_V_R_2 = 0b00000000;//! Identifier for a certain BC Command.
|
||||||
|
|
||||||
|
public:
|
||||||
|
uint8_t byte1; //!< First content byte
|
||||||
|
uint8_t byte2; //!< Second content byte
|
||||||
|
uint8_t vR; //!< vR byte
|
||||||
|
/**
|
||||||
|
* Simple default constructor.
|
||||||
|
*/
|
||||||
|
BcFrame() :
|
||||||
|
byte1(0), byte2(0), vR(0) {
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Main and only useful method of the class.
|
||||||
|
* With the buffer and size information passed, the class passes the content
|
||||||
|
* and checks if it is one of the two valid BC Command Frames.
|
||||||
|
* @param inBuffer Content of the frame to check,
|
||||||
|
* @param inSize Size of the data to check.
|
||||||
|
* @return - #BC_ILLEGAL_COMMAND if it is no command.
|
||||||
|
* - #BC_IS_UNLOCK_COMMAND if it is an unlock command.
|
||||||
|
* - #BC_IS_SET_VR_COMMAND if it is such.
|
||||||
|
*/
|
||||||
|
ReturnValue_t initialize(const uint8_t* inBuffer, uint16_t inSize) {
|
||||||
|
ReturnValue_t returnValue = BC_ILLEGAL_COMMAND;
|
||||||
|
if (inSize == 1) {
|
||||||
|
byte1 = inBuffer[0];
|
||||||
|
if (byte1 == UNLOCK_COMMAND) {
|
||||||
|
returnValue = BC_IS_UNLOCK_COMMAND;
|
||||||
|
}
|
||||||
|
} else if (inSize == 3) {
|
||||||
|
byte1 = inBuffer[0];
|
||||||
|
byte2 = inBuffer[1];
|
||||||
|
vR = inBuffer[2];
|
||||||
|
if (byte1 == SET_V_R_1 && byte2 == SET_V_R_2) {
|
||||||
|
returnValue = BC_IS_SET_VR_COMMAND;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* BCFRAME_H_ */
|
57
datalinklayer/CCSDSReturnValuesIF.h
Normal file
57
datalinklayer/CCSDSReturnValuesIF.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/**
|
||||||
|
* @file CCSDSReturnValuesIF.h
|
||||||
|
* @brief This file defines the CCSDSReturnValuesIF class.
|
||||||
|
* @date 24.04.2013
|
||||||
|
* @author baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CCSDSRETURNVALUESIF_H_
|
||||||
|
#define CCSDSRETURNVALUESIF_H_
|
||||||
|
|
||||||
|
#include <framework/returnvalues/HasReturnvaluesIF.h>
|
||||||
|
/**
|
||||||
|
* This is a helper class to collect special return values that come up during CCSDS Handling.
|
||||||
|
* @ingroup ccsds_handling
|
||||||
|
*/
|
||||||
|
class CCSDSReturnValuesIF: public HasReturnvaluesIF {
|
||||||
|
public:
|
||||||
|
static const uint8_t INTERFACE_ID = CCSDS_HANDLER_IF; //!< Basic ID of the interface.
|
||||||
|
static const ReturnValue_t FRAME_OK = RETURN_OK; //!< A value to indicate that a frame is ok.
|
||||||
|
|
||||||
|
static const ReturnValue_t BC_IS_SET_VR_COMMAND = MAKE_RETURN_CODE( 0x01 ); //!< A value to describe a BC frame.
|
||||||
|
static const ReturnValue_t BC_IS_UNLOCK_COMMAND = MAKE_RETURN_CODE( 0x02 ); //!< A value to describe a BC frame.
|
||||||
|
static const ReturnValue_t BC_ILLEGAL_COMMAND = MAKE_RETURN_CODE( 0xB0 );//!< A value to describe an illegal BC frame.
|
||||||
|
static const ReturnValue_t BOARD_READING_NOT_FINISHED = MAKE_RETURN_CODE( 0xB1 ); //! The CCSDS Board is not yet finished reading, it requires another cycle.
|
||||||
|
|
||||||
|
static const ReturnValue_t NS_POSITIVE_W = MAKE_RETURN_CODE( 0xF0 );//!< NS is in the positive window
|
||||||
|
static const ReturnValue_t NS_NEGATIVE_W = MAKE_RETURN_CODE( 0xF1 );//!< NS is in the negative window
|
||||||
|
static const ReturnValue_t NS_LOCKOUT = MAKE_RETURN_CODE( 0xF2 ); //!< NS is in lockout state
|
||||||
|
static const ReturnValue_t FARM_IN_LOCKOUT = MAKE_RETURN_CODE( 0xF3 );//!< FARM-1 is currently in lockout state
|
||||||
|
static const ReturnValue_t FARM_IN_WAIT = MAKE_RETURN_CODE( 0xF4 ); //!< FARM-1 is currently in wait state
|
||||||
|
|
||||||
|
static const ReturnValue_t WRONG_SYMBOL = MAKE_RETURN_CODE( 0xE0 ); //!< An error code in the FrameFinder.
|
||||||
|
static const ReturnValue_t DOUBLE_START = MAKE_RETURN_CODE( 0xE1 ); //!< An error code in the FrameFinder.
|
||||||
|
static const ReturnValue_t START_SYMBOL_MISSED = MAKE_RETURN_CODE( 0xE2 );//!< An error code in the FrameFinder.
|
||||||
|
static const ReturnValue_t END_WITHOUT_START = MAKE_RETURN_CODE( 0xE3 );//!< An error code in the FrameFinder.
|
||||||
|
static const ReturnValue_t TOO_LARGE = MAKE_RETURN_CODE( 0xE4 );//!< An error code for a frame.
|
||||||
|
static const ReturnValue_t TOO_SHORT = MAKE_RETURN_CODE( 0xE5 );//!< An error code for a frame.
|
||||||
|
static const ReturnValue_t WRONG_TF_VERSION = MAKE_RETURN_CODE( 0xE6 ); //!< An error code for a frame.
|
||||||
|
static const ReturnValue_t WRONG_SPACECRAFT_ID = MAKE_RETURN_CODE( 0xE7 );//!< An error code for a frame.
|
||||||
|
static const ReturnValue_t NO_VALID_FRAME_TYPE = MAKE_RETURN_CODE( 0xE8 );//!< An error code for a frame.
|
||||||
|
static const ReturnValue_t CRC_FAILED = MAKE_RETURN_CODE( 0xE9 );//!< An error code for a frame.
|
||||||
|
static const ReturnValue_t VC_NOT_FOUND = MAKE_RETURN_CODE( 0xEA ); //!< An error code for a frame.
|
||||||
|
static const ReturnValue_t FORWARDING_FAILED = MAKE_RETURN_CODE( 0xEB );//!< An error code for a frame.
|
||||||
|
static const ReturnValue_t CONTENT_TOO_LARGE = MAKE_RETURN_CODE( 0xEC );//!< An error code for a frame.
|
||||||
|
static const ReturnValue_t RESIDUAL_DATA = MAKE_RETURN_CODE( 0xED );//!< An error code for a frame.
|
||||||
|
static const ReturnValue_t DATA_CORRUPTED = MAKE_RETURN_CODE( 0xEE );//!< An error code for a frame.
|
||||||
|
static const ReturnValue_t ILLEGAL_SEGMENTATION_FLAG = MAKE_RETURN_CODE( 0xEF );//!< An error code for a frame.
|
||||||
|
static const ReturnValue_t ILLEGAL_FLAG_COMBINATION = MAKE_RETURN_CODE( 0xD0 ); //!< An error code for a frame.
|
||||||
|
static const ReturnValue_t SHORTER_THAN_HEADER = MAKE_RETURN_CODE( 0xD1 ); //!< An error code for a frame.
|
||||||
|
static const ReturnValue_t TOO_SHORT_BLOCKED_PACKET = MAKE_RETURN_CODE( 0xD2 ); //!< An error code for a frame.
|
||||||
|
static const ReturnValue_t TOO_SHORT_MAP_EXTRACTION = MAKE_RETURN_CODE( 0xD3 ); //!< An error code for a frame.
|
||||||
|
|
||||||
|
virtual ~CCSDSReturnValuesIF() {
|
||||||
|
} //!< Empty virtual destructor
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* CCSDSRETURNVALUESIF_H_ */
|
63
datalinklayer/Clcw.cpp
Normal file
63
datalinklayer/Clcw.cpp
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/**
|
||||||
|
* @file Clcw.cpp
|
||||||
|
* @brief This file defines the Clcw class.
|
||||||
|
* @date 17.04.2013
|
||||||
|
* @author baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <framework/datalinklayer/Clcw.h>
|
||||||
|
#include <framework/serviceinterface/ServiceInterfaceStream.h>
|
||||||
|
|
||||||
|
Clcw::Clcw() {
|
||||||
|
content.raw = 0;
|
||||||
|
content.status = STATUS_FIELD_DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
Clcw::~Clcw() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clcw::setVirtualChannel(uint8_t setChannel) {
|
||||||
|
content.virtualChannelIdSpare = ((setChannel & 0x3F) << 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clcw::setLockoutFlag(bool lockout) {
|
||||||
|
content.flags = (content.flags & LOCKOUT_FLAG_MASK) | (lockout << LOCKOUT_FLAG_POSITION);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clcw::setWaitFlag(bool waitFlag) {
|
||||||
|
content.flags = (content.flags & WAIT_FLAG_MASK) | (waitFlag << WAIT_FLAG_POSITION);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clcw::setRetransmitFlag(bool retransmitFlag) {
|
||||||
|
content.flags = (content.flags & RETRANSMIT_FLAG_MASK) | (retransmitFlag << RETRANSMIT_FLAG_POSITION);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clcw::setFarmBCount(uint8_t count) {
|
||||||
|
content.flags = (content.flags & FARM_B_COUNT_MASK) | ((count & 0x03) << 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clcw::setReceiverFrameSequenceNumber(uint8_t vR) {
|
||||||
|
content.vRValue = vR;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Clcw::getAsWhole() {
|
||||||
|
return content.raw;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clcw::setRFAvailable(bool rfAvailable) {
|
||||||
|
content.flags = (content.flags & NO_RF_AVIALABLE_MASK) | (!rfAvailable << NO_RF_AVIALABLE_POSITION);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clcw::setBitLock(bool bitLock) {
|
||||||
|
content.flags = (content.flags & NO_BIT_LOCK_MASK) | (!bitLock << NO_BIT_LOCK_POSITION);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clcw::print() {
|
||||||
|
debug << "Clcw::print: Clcw is: " << std::hex << getAsWhole() << std::dec << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clcw::setWhole(uint32_t rawClcw) {
|
||||||
|
content.raw = rawClcw;
|
||||||
|
}
|
66
datalinklayer/Clcw.h
Normal file
66
datalinklayer/Clcw.h
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
/**
|
||||||
|
* @file Clcw.h
|
||||||
|
* @brief This file defines the Clcw class.
|
||||||
|
* @date 17.04.2013
|
||||||
|
* @author baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CLCW_H_
|
||||||
|
#define CLCW_H_
|
||||||
|
|
||||||
|
#include <framework/datalinklayer/ClcwIF.h>
|
||||||
|
/**
|
||||||
|
* Small helper method to handle the Clcw values.
|
||||||
|
* It has a content struct that manages the register and can be set externally.
|
||||||
|
* @ingroup ccsds_handling
|
||||||
|
*/
|
||||||
|
class Clcw : public ClcwIF {
|
||||||
|
private:
|
||||||
|
static const uint8_t STATUS_FIELD_DEFAULT = 0b00000001; //!< Default for the status field.
|
||||||
|
static const uint8_t NO_RF_AVIALABLE_POSITION = 7; //!< Position of a flag in the register (starting with 0).
|
||||||
|
static const uint8_t NO_BIT_LOCK_POSITION = 6; //!< Position of a flag in the register (starting with 0).
|
||||||
|
static const uint8_t LOCKOUT_FLAG_POSITION = 5; //!< Position of a flag in the register (starting with 0).
|
||||||
|
static const uint8_t WAIT_FLAG_POSITION = 4; //!< Position of a flag in the register (starting with 0).
|
||||||
|
static const uint8_t RETRANSMIT_FLAG_POSITION = 3; //!< Position of a flag in the register (starting with 0).
|
||||||
|
static const uint8_t NO_RF_AVIALABLE_MASK = 0xFF xor (1 << NO_RF_AVIALABLE_POSITION); //!< Mask for a flag in the register.
|
||||||
|
static const uint8_t NO_BIT_LOCK_MASK = 0xFF xor (1 << NO_BIT_LOCK_POSITION); //!< Mask for a flag in the register.
|
||||||
|
static const uint8_t LOCKOUT_FLAG_MASK = 0xFF xor (1 << LOCKOUT_FLAG_POSITION); //!< Mask for a flag in the register.
|
||||||
|
static const uint8_t WAIT_FLAG_MASK = 0xFF xor (1 << WAIT_FLAG_POSITION); //!< Mask for a flag in the register.
|
||||||
|
static const uint8_t RETRANSMIT_FLAG_MASK = 0xFF xor (1 << RETRANSMIT_FLAG_POSITION); //!< Mask for a flag in the register.
|
||||||
|
static const uint8_t FARM_B_COUNT_MASK = 0b11111001; //!< Mask for a counter in the register.
|
||||||
|
/**
|
||||||
|
* This is the data structure of the CLCW register.
|
||||||
|
*/
|
||||||
|
union clcwContent {
|
||||||
|
uint32_t raw;
|
||||||
|
struct {
|
||||||
|
uint8_t status;
|
||||||
|
uint8_t virtualChannelIdSpare;
|
||||||
|
uint8_t flags;
|
||||||
|
uint8_t vRValue;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
clcwContent content; //!< Represents the content of the register.
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* The constructor sets everything to default values.
|
||||||
|
*/
|
||||||
|
Clcw();
|
||||||
|
/**
|
||||||
|
* Nothing happens in the destructor.
|
||||||
|
*/
|
||||||
|
~Clcw();
|
||||||
|
void setVirtualChannel( uint8_t setChannel );
|
||||||
|
void setLockoutFlag( bool lockout );
|
||||||
|
void setWaitFlag( bool waitFlag );
|
||||||
|
void setRetransmitFlag( bool retransmitFlag );
|
||||||
|
void setFarmBCount( uint8_t count );
|
||||||
|
void setReceiverFrameSequenceNumber( uint8_t vR );
|
||||||
|
void setRFAvailable( bool rfAvailable );
|
||||||
|
void setBitLock( bool bitLock );
|
||||||
|
uint32_t getAsWhole();
|
||||||
|
void setWhole( uint32_t rawClcw );
|
||||||
|
void print();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* CLCW_H_ */
|
70
datalinklayer/ClcwIF.h
Normal file
70
datalinklayer/ClcwIF.h
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
/**
|
||||||
|
* @file ClcwIF.h
|
||||||
|
* @brief This file defines the ClcwIF class.
|
||||||
|
* @date 17.04.2013
|
||||||
|
* @author baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CLCWIF_H_
|
||||||
|
#define CLCWIF_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface to manage a CLCW register.
|
||||||
|
* @ingroup ccsds_handling
|
||||||
|
*/
|
||||||
|
class ClcwIF {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Empty virtual destructor.
|
||||||
|
*/
|
||||||
|
virtual ~ClcwIF() { }
|
||||||
|
/**
|
||||||
|
* Simple setter.
|
||||||
|
* @param setChannel The virtual channel id to set.
|
||||||
|
*/
|
||||||
|
virtual void setVirtualChannel( uint8_t setChannel ) = 0;
|
||||||
|
/**
|
||||||
|
* Simple setter.
|
||||||
|
* @param lockout status of the flag.
|
||||||
|
*/
|
||||||
|
virtual void setLockoutFlag( bool lockout ) = 0;
|
||||||
|
/**
|
||||||
|
* Simple setter.
|
||||||
|
* @param waitFlag status of the flag.
|
||||||
|
*/
|
||||||
|
virtual void setWaitFlag( bool waitFlag ) = 0;
|
||||||
|
/**
|
||||||
|
* Simple setter.
|
||||||
|
* @param retransmitFlag status of the flag.
|
||||||
|
*/
|
||||||
|
virtual void setRetransmitFlag( bool retransmitFlag ) = 0;
|
||||||
|
/**
|
||||||
|
* Sets the farm B count.
|
||||||
|
* @param count A full 8bit counter value can be passed. Only the last three bits are used.
|
||||||
|
*/
|
||||||
|
virtual void setFarmBCount( uint8_t count ) = 0;
|
||||||
|
/**
|
||||||
|
* Simple setter.
|
||||||
|
* @param vR Value of vR.
|
||||||
|
*/
|
||||||
|
virtual void setReceiverFrameSequenceNumber( uint8_t vR ) = 0;
|
||||||
|
/**
|
||||||
|
* Returns the register as a full 32bit value.
|
||||||
|
* @return The value.
|
||||||
|
*/
|
||||||
|
virtual uint32_t getAsWhole() = 0;
|
||||||
|
/**
|
||||||
|
* Sets the whole content to this value.
|
||||||
|
* @param rawClcw The value to set the content.
|
||||||
|
*/
|
||||||
|
virtual void setWhole( uint32_t rawClcw ) = 0;
|
||||||
|
/**
|
||||||
|
* Debug method to print the CLCW.
|
||||||
|
*/
|
||||||
|
virtual void print() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* CLCWIF_H_ */
|
147
datalinklayer/DataLinkLayer.cpp
Normal file
147
datalinklayer/DataLinkLayer.cpp
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
* DataLinkLayer.cpp
|
||||||
|
*
|
||||||
|
* Created on: 02.03.2012
|
||||||
|
* Author: baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <framework/datalinklayer/DataLinkLayer.h>
|
||||||
|
#include <framework/globalfunctions/crc_ccitt.h>
|
||||||
|
#include <framework/osal/OSAL.h>
|
||||||
|
#include <framework/serviceinterface/ServiceInterfaceStream.h>
|
||||||
|
|
||||||
|
DataLinkLayer::DataLinkLayer(uint8_t* set_frame_buffer, ClcwIF* setClcw,
|
||||||
|
uint8_t set_start_sequence_length, uint16_t set_scid) :
|
||||||
|
spacecraftId(set_scid), frameBuffer(set_frame_buffer), clcw(setClcw), receivedDataLength(0), currentFrame(
|
||||||
|
NULL), startSequenceLength(set_start_sequence_length) {
|
||||||
|
//Nothing to do except from setting the values above.
|
||||||
|
}
|
||||||
|
|
||||||
|
DataLinkLayer::~DataLinkLayer() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t DataLinkLayer::frameDelimitingAndFillRemoval() {
|
||||||
|
if ((receivedDataLength - startSequenceLength) < FRAME_PRIMARY_HEADER_LENGTH) {
|
||||||
|
return SHORTER_THAN_HEADER;
|
||||||
|
}
|
||||||
|
//Removing start sequence
|
||||||
|
//TODO: What does the start sequence look like? Better search for the pattern.
|
||||||
|
while ( *frameBuffer == START_SEQUENCE_PATTERN ) {
|
||||||
|
frameBuffer++;
|
||||||
|
}
|
||||||
|
TcTransferFrame frame_candidate(frameBuffer);
|
||||||
|
this->currentFrame = frame_candidate; //should work with shallow copy.
|
||||||
|
|
||||||
|
return FRAME_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t DataLinkLayer::frameValidationCheck() {
|
||||||
|
//Check TF_version number
|
||||||
|
if (this->currentFrame.getVersionNumber() != FRAME_VERSION_NUMBER_DEFAULT) {
|
||||||
|
return WRONG_TF_VERSION;
|
||||||
|
}
|
||||||
|
//Check SpaceCraft ID
|
||||||
|
if (this->currentFrame.getSpacecraftId() != this->spacecraftId) {
|
||||||
|
return WRONG_SPACECRAFT_ID;
|
||||||
|
}
|
||||||
|
//Check other header limitations:
|
||||||
|
if (!this->currentFrame.bypassFlagSet() && this->currentFrame.controlCommandFlagSet()) {
|
||||||
|
return NO_VALID_FRAME_TYPE;
|
||||||
|
}
|
||||||
|
//- Spares are zero
|
||||||
|
if (!this->currentFrame.spareIsZero()) {
|
||||||
|
return NO_VALID_FRAME_TYPE;
|
||||||
|
}
|
||||||
|
//Compare detected frame length with the one in the header
|
||||||
|
uint16_t length = currentFrame.getFullSize();
|
||||||
|
if (length > receivedDataLength) {
|
||||||
|
//Frame is too long or just right
|
||||||
|
// error << "frameValidationCheck: Too short.";
|
||||||
|
// currentFrame.print();
|
||||||
|
return TOO_SHORT;
|
||||||
|
}
|
||||||
|
if (USE_CRC) {
|
||||||
|
return this->frameCheckCRC();
|
||||||
|
}
|
||||||
|
return FRAME_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t DataLinkLayer::frameCheckCRC() {
|
||||||
|
uint16_t checkValue = ::Calculate_CRC(this->currentFrame.getFullFrame(),
|
||||||
|
this->currentFrame.getFullSize());
|
||||||
|
if (checkValue == 0) {
|
||||||
|
return FRAME_OK;
|
||||||
|
} else {
|
||||||
|
return CRC_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t DataLinkLayer::allFramesReception() {
|
||||||
|
ReturnValue_t status = this->frameDelimitingAndFillRemoval();
|
||||||
|
if (status != FRAME_OK) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
return this->frameValidationCheck();
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t DataLinkLayer::masterChannelDemultiplexing() {
|
||||||
|
//Nothing to do at present. Ideally, there would be a map of MCID's identifying which MC to use.
|
||||||
|
return virtualChannelDemultiplexing();
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t DataLinkLayer::virtualChannelDemultiplexing() {
|
||||||
|
uint8_t vcId = currentFrame.getVirtualChannelId();
|
||||||
|
virtualChannelIterator iter = virtualChannels.find(vcId);
|
||||||
|
if (iter == virtualChannels.end()) {
|
||||||
|
//Do not report because passive board will get this error all the time.
|
||||||
|
return FRAME_OK;
|
||||||
|
} else {
|
||||||
|
return (iter->second)->frameAcceptanceAndReportingMechanism(¤tFrame, clcw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t DataLinkLayer::processFrame(uint16_t length) {
|
||||||
|
receivedDataLength = length;
|
||||||
|
ReturnValue_t status = allFramesReception();
|
||||||
|
if (status != FRAME_OK) {
|
||||||
|
error << "DataLinkLayer::processFrame: frame reception failed. Error code: " << std::hex
|
||||||
|
<< status << std::dec << std::endl;
|
||||||
|
// currentFrame.print();
|
||||||
|
return status;
|
||||||
|
} else {
|
||||||
|
return masterChannelDemultiplexing();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t DataLinkLayer::addVirtualChannel(uint8_t virtualChannelId,
|
||||||
|
VirtualChannelReceptionIF* object) {
|
||||||
|
std::pair<virtualChannelIterator, bool> returnValue = virtualChannels.insert(
|
||||||
|
std::pair<uint8_t, VirtualChannelReceptionIF*>(virtualChannelId, object));
|
||||||
|
if (returnValue.second == true) {
|
||||||
|
return RETURN_OK;
|
||||||
|
} else {
|
||||||
|
return RETURN_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t DataLinkLayer::initialize() {
|
||||||
|
ReturnValue_t returnValue = RETURN_FAILED;
|
||||||
|
//Set Virtual Channel ID to first virtual channel instance in this DataLinkLayer instance to avoid faulty information (e.g. 0) in the VCID.
|
||||||
|
if ( virtualChannels.begin() != virtualChannels.end() ) {
|
||||||
|
clcw->setVirtualChannel( virtualChannels.begin()->second->getChannelId() );
|
||||||
|
} else {
|
||||||
|
error << "DataLinkLayer::initialize: No VC assigned to this DLL instance! " << std::endl;
|
||||||
|
return RETURN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (virtualChannelIterator iterator = virtualChannels.begin();
|
||||||
|
iterator != virtualChannels.end(); iterator++) {
|
||||||
|
returnValue = iterator->second->initialize();
|
||||||
|
if (returnValue != RETURN_OK)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return returnValue;
|
||||||
|
|
||||||
|
}
|
119
datalinklayer/DataLinkLayer.h
Normal file
119
datalinklayer/DataLinkLayer.h
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
* DataLinkLayer.h
|
||||||
|
*
|
||||||
|
* Created on: Feb 29, 2012
|
||||||
|
* Author: baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DATALINKLAYER_H_
|
||||||
|
#define DATALINKLAYER_H_
|
||||||
|
|
||||||
|
#include <framework/datalinklayer/CCSDSReturnValuesIF.h>
|
||||||
|
#include <framework/datalinklayer/ClcwIF.h>
|
||||||
|
#include <framework/datalinklayer/TcTransferFrame.h>
|
||||||
|
#include <framework/datalinklayer/VirtualChannelReceptionIF.h>
|
||||||
|
#include <framework/events/Event.h>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
|
||||||
|
class VirtualChannelReception;
|
||||||
|
/**
|
||||||
|
* A complete representation of the CCSDS Data Link Layer.
|
||||||
|
* The operations of this layer are defined in the CCSDS TC Space Data Link Protocol
|
||||||
|
* document. It is configured to handle a VC Demultiplexing function. All reception
|
||||||
|
* steps are performed.
|
||||||
|
*/
|
||||||
|
class DataLinkLayer : public CCSDSReturnValuesIF {
|
||||||
|
public:
|
||||||
|
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_1;
|
||||||
|
static const Event RF_AVAILABLE = MAKE_EVENT(0, SEVERITY::INFO); //!< The CCSDS Board detected a RF available signal.
|
||||||
|
static const Event RF_LOST = MAKE_EVENT(1, SEVERITY::INFO); //!< The CCSDS Board lost a previously found RF available signal.
|
||||||
|
static const Event BIT_LOCK = MAKE_EVENT(2, SEVERITY::INFO); //!< The CCSDS Board detected a Bit Lock signal.
|
||||||
|
static const Event BIT_LOCK_LOST = MAKE_EVENT(3, SEVERITY::INFO); //!< The CCSDS Board lost a previously found Bit Lock signal.
|
||||||
|
static const Event RF_CHAIN_LOST = MAKE_EVENT(4, SEVERITY::INFO); //!< The CCSDS Board detected that either bit lock or RF available or both are lost.
|
||||||
|
static const Event FRAME_PROCESSING_FAILED = MAKE_EVENT(5, SEVERITY::LOW); //!< The CCSDS Board could not interpret a TC
|
||||||
|
/**
|
||||||
|
* The Constructor sets the passed parameters and nothing else.
|
||||||
|
* @param set_frame_buffer The buffer in which incoming frame candidates are stored.
|
||||||
|
* @param setClcw The CLCW class to work on when returning CLCW information.
|
||||||
|
* @param set_start_sequence_length Length of the Start sequence in front of every TC Transfer Frame.
|
||||||
|
* @param set_scid The SCID to operate on.
|
||||||
|
*/
|
||||||
|
DataLinkLayer( uint8_t* set_frame_buffer, ClcwIF* setClcw, uint8_t set_start_sequence_length, uint16_t set_scid );
|
||||||
|
/**
|
||||||
|
* Empty virtual destructor.
|
||||||
|
*/
|
||||||
|
~DataLinkLayer();
|
||||||
|
/**
|
||||||
|
* This method tries to process a frame that is placed in #frameBuffer.
|
||||||
|
* The procedures described in the Standard are performed.
|
||||||
|
* @param length Length of the incoming frame candidate.
|
||||||
|
* @return @c RETURN_OK on successful handling, otherwise the return codes of the higher methods.
|
||||||
|
*/
|
||||||
|
ReturnValue_t processFrame( uint16_t length );
|
||||||
|
/**
|
||||||
|
* Configuration method to add a new TC Virtual Channel.
|
||||||
|
* Shall only be called during initialization. As soon as the method was called, the layer can
|
||||||
|
* handle Frames directed to this VC.
|
||||||
|
* @param virtualChannelId Id of the VC. Shall be smaller than 64.
|
||||||
|
* @param object Reference to the object that handles the Frame.
|
||||||
|
* @return @c RETURN_OK on success, @c RETURN_FAILED otherwise.
|
||||||
|
*/
|
||||||
|
ReturnValue_t addVirtualChannel( uint8_t virtualChannelId, VirtualChannelReceptionIF* object );
|
||||||
|
/**
|
||||||
|
* The initialization method calls the @c initialize routine of all virtual channels.
|
||||||
|
* @return The return code of the first failed VC initialization or @c RETURN_OK.
|
||||||
|
*/
|
||||||
|
ReturnValue_t initialize();
|
||||||
|
private:
|
||||||
|
typedef std::map<uint8_t, VirtualChannelReceptionIF*>::iterator virtualChannelIterator; //!< Typedef to simplify handling the #virtualChannels map.
|
||||||
|
static const uint8_t FRAME_VERSION_NUMBER_DEFAULT = 0x00; //!< Constant for the default value of Frame Version Numbers.
|
||||||
|
static const uint8_t FRAME_PRIMARY_HEADER_LENGTH = 5; //!< Length of the frame's primary header.
|
||||||
|
static const uint8_t START_SEQUENCE_PATTERN = 0x00; //!< The start sequence pattern which might be with the frame.
|
||||||
|
static const bool USE_CRC = true; //!< A global, so called "Managed Parameter" that identifies if incoming frames have CRC's or not.
|
||||||
|
uint16_t spacecraftId; //!< The Space Craft Identifier (SCID) configured.
|
||||||
|
uint8_t* frameBuffer; //!< A pointer to point to the current incoming frame.
|
||||||
|
ClcwIF* clcw; //!< Pointer to store the CLCW to work on.
|
||||||
|
uint16_t receivedDataLength; //!< Stores the length of the currently processed frame.
|
||||||
|
TcTransferFrame currentFrame; //!< Stores a more convenient access to the current frame.
|
||||||
|
uint8_t startSequenceLength; //!< Configured length of the start sequence. Maybe this must be done more variable.
|
||||||
|
std::map<uint8_t, VirtualChannelReceptionIF*> virtualChannels; //!< Map of all virtual channels assigned.
|
||||||
|
/**
|
||||||
|
* Method that performs all possible frame validity checks (as specified).
|
||||||
|
* @return Various error codes or @c FRAME_OK on success.
|
||||||
|
*/
|
||||||
|
ReturnValue_t frameValidationCheck();
|
||||||
|
/**
|
||||||
|
* First method to call.
|
||||||
|
* Removes start sequence bytes and checks if the complete frame was received.
|
||||||
|
* TODO: Maybe handling the start sequence must be done more variable.
|
||||||
|
* @return @c FRAME_OK or @c TOO_SHORT.
|
||||||
|
*/
|
||||||
|
ReturnValue_t frameDelimitingAndFillRemoval();
|
||||||
|
/**
|
||||||
|
* Small helper method to check the CRC of the Frame.
|
||||||
|
* @return @c FRAME_OK or @c CRC_FAILED.
|
||||||
|
*/
|
||||||
|
ReturnValue_t frameCheckCRC();
|
||||||
|
/**
|
||||||
|
* Method that groups the reception process of all Frames.
|
||||||
|
* Calls #frameDelimitingAndFillRemoval and #frameValidationCheck.
|
||||||
|
* @return The return codes of the sub calls.
|
||||||
|
*/
|
||||||
|
ReturnValue_t allFramesReception();
|
||||||
|
/**
|
||||||
|
* Dummy method for master channel demultiplexing.
|
||||||
|
* As there's only one Master Channel here, the method calls #virtualChannelDemultiplexing.
|
||||||
|
* @return The return codes of #virtualChannelDemultiplexing.
|
||||||
|
*/
|
||||||
|
ReturnValue_t masterChannelDemultiplexing();
|
||||||
|
/**
|
||||||
|
* Method to demultiplex the Frames to Virtual Channels (VC's).
|
||||||
|
* Looks up the requested VC in #virtualChannels and forwards the Frame to its
|
||||||
|
* #frameAcceptanceAndReportingMechanism method, if found.
|
||||||
|
* @return The higher method codes or @c VC_NOT_FOUND.
|
||||||
|
*/
|
||||||
|
ReturnValue_t virtualChannelDemultiplexing();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DATALINKLAYER_H_ */
|
54
datalinklayer/Farm1StateIF.h
Normal file
54
datalinklayer/Farm1StateIF.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
/**
|
||||||
|
* @file Farm1StateIF.h
|
||||||
|
* @brief This file defines the Farm1StateIF class.
|
||||||
|
* @date 24.04.2013
|
||||||
|
* @author baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FARM1STATEIF_H_
|
||||||
|
#define FARM1STATEIF_H_
|
||||||
|
|
||||||
|
#include <framework/datalinklayer/CCSDSReturnValuesIF.h>
|
||||||
|
class VirtualChannelReception;
|
||||||
|
class TcTransferFrame;
|
||||||
|
class ClcwIF;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the interface for states of the FARM-1 state machine.
|
||||||
|
* Classes implementing this interface can be used as FARM-1 states. This is a simple implementation
|
||||||
|
* of the state pattern.
|
||||||
|
*/
|
||||||
|
class Farm1StateIF : public CCSDSReturnValuesIF {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* A method that shall handle an incoming frame as AD Frame.
|
||||||
|
* @param frame The frame to handle.
|
||||||
|
* @param clcw Any changes to the CLCW shall be done with the help of this interface.
|
||||||
|
* @return If forwarding to a MAP Channel is required, the return value shall be #FRAME_OK.
|
||||||
|
* Otherwise, an appropriate return value or error code shall be generated.
|
||||||
|
*/
|
||||||
|
virtual ReturnValue_t handleADFrame( TcTransferFrame* frame, ClcwIF* clcw ) = 0;
|
||||||
|
/**
|
||||||
|
* This method shall handle frames that have been successfully identified as BC Unlock frames.
|
||||||
|
* @param clcw Any changes to the CLCW shall be done with the help of this interface.
|
||||||
|
* @return If forwarding to a MAP Channel is required, the return value shall be #FRAME_OK.
|
||||||
|
* Otherwise, an appropriate return value or error code shall be generated.
|
||||||
|
*/
|
||||||
|
virtual ReturnValue_t handleBCUnlockCommand( ClcwIF* clcw ) = 0;
|
||||||
|
/**
|
||||||
|
* This method shall handle frames that have been successfully identified as BC Set VR frames.
|
||||||
|
* @param clcw Any changes to the CLCW shall be done with the help of this interface.
|
||||||
|
* @param vr The V(r) value found in the frame.
|
||||||
|
* @return If forwarding to a MAP Channel is required, the return value shall be #FRAME_OK.
|
||||||
|
* Otherwise, an appropriate return value or error code shall be generated.
|
||||||
|
*/
|
||||||
|
virtual ReturnValue_t handleBCSetVrCommand( ClcwIF* clcw, uint8_t vr ) = 0;
|
||||||
|
/**
|
||||||
|
* Empty virtual destructor.
|
||||||
|
*/
|
||||||
|
virtual ~Farm1StateIF() {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* FARM1STATEIF_H_ */
|
35
datalinklayer/Farm1StateLockout.cpp
Normal file
35
datalinklayer/Farm1StateLockout.cpp
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* @file Farm1StateLockout.cpp
|
||||||
|
* @brief This file defines the Farm1StateLockout class.
|
||||||
|
* @date 24.04.2013
|
||||||
|
* @author baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <framework/datalinklayer/ClcwIF.h>
|
||||||
|
#include <framework/datalinklayer/Farm1StateLockout.h>
|
||||||
|
#include <framework/datalinklayer/TcTransferFrame.h>
|
||||||
|
#include <framework/datalinklayer/VirtualChannelReception.h>
|
||||||
|
Farm1StateLockout::Farm1StateLockout(VirtualChannelReception* setMyVC) : myVC(setMyVC) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t Farm1StateLockout::handleADFrame(TcTransferFrame* frame,
|
||||||
|
ClcwIF* clcw) {
|
||||||
|
return FARM_IN_LOCKOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t Farm1StateLockout::handleBCUnlockCommand(ClcwIF* clcw) {
|
||||||
|
myVC->farmBCounter++;
|
||||||
|
clcw->setRetransmitFlag(false);
|
||||||
|
clcw->setLockoutFlag( false );
|
||||||
|
clcw->setWaitFlag( false );
|
||||||
|
myVC->currentState = &(myVC->openState);
|
||||||
|
return BC_IS_UNLOCK_COMMAND;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t Farm1StateLockout::handleBCSetVrCommand(ClcwIF* clcw,
|
||||||
|
uint8_t vr) {
|
||||||
|
myVC->farmBCounter++;
|
||||||
|
return BC_IS_SET_VR_COMMAND;
|
||||||
|
}
|
59
datalinklayer/Farm1StateLockout.h
Normal file
59
datalinklayer/Farm1StateLockout.h
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/**
|
||||||
|
* @file Farm1StateLockout.h
|
||||||
|
* @brief This file defines the Farm1StateLockout class.
|
||||||
|
* @date 24.04.2013
|
||||||
|
* @author baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FARM1STATELOCKOUT_H_
|
||||||
|
#define FARM1STATELOCKOUT_H_
|
||||||
|
|
||||||
|
#include <framework/datalinklayer/Farm1StateIF.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents the FARM-1 "Lockout" State.
|
||||||
|
* The Lockout state is reached if the received Transfer Frame Sequence Number is completely wrong
|
||||||
|
* (i.e. within the Lockout Window). No AD Frames are forwarded. To leave the State, a BC Unlock
|
||||||
|
* command is required.
|
||||||
|
*/
|
||||||
|
class Farm1StateLockout : public Farm1StateIF {
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* This is a reference to the "owner" class the State works on.
|
||||||
|
*/
|
||||||
|
VirtualChannelReception* myVC;
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* The default constructor if the State.
|
||||||
|
* Sets the "owner" of the State.
|
||||||
|
* @param setMyVC The "owner" class.
|
||||||
|
*/
|
||||||
|
Farm1StateLockout( VirtualChannelReception* setMyVC );
|
||||||
|
/**
|
||||||
|
* All AD Frames are rejected with FARM_IN_LOCKOUT
|
||||||
|
* @param frame The frame to handle.
|
||||||
|
* @param clcw Any changes to the CLCW shall be done with the help of this interface.
|
||||||
|
* @return FARM_IN_LOCKOUT
|
||||||
|
*/
|
||||||
|
ReturnValue_t handleADFrame( TcTransferFrame* frame, ClcwIF* clcw );
|
||||||
|
/**
|
||||||
|
* These commands are handled as specified.
|
||||||
|
* State changes to Farm1StateOpen.
|
||||||
|
* @param clcw Any changes to the CLCW shall be done with the help of this interface.
|
||||||
|
* @return As the frame needs no forwarding to a MAP Channel, #BC_IS_UNLOCK_COMMAND
|
||||||
|
* is returned.
|
||||||
|
*/
|
||||||
|
ReturnValue_t handleBCUnlockCommand( ClcwIF* clcw );
|
||||||
|
/**
|
||||||
|
* These commands are handled as specified.
|
||||||
|
* The V(r) value is not set in Lockout State, even though the Command itself is accepted.
|
||||||
|
* @param clcw Any changes to the CLCW shall be done with the help of this interface.
|
||||||
|
* @param vr The V(r) value found in the frame.
|
||||||
|
* @return As the frame needs no forwarding to a MAP Channel, #BC_IS_SET_VR_COMMAND
|
||||||
|
* is returned.
|
||||||
|
*/
|
||||||
|
ReturnValue_t handleBCSetVrCommand( ClcwIF* clcw, uint8_t vr );
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* FARM1STATELOCKOUT_H_ */
|
49
datalinklayer/Farm1StateOpen.cpp
Normal file
49
datalinklayer/Farm1StateOpen.cpp
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
/**
|
||||||
|
* @file Farm1StateOpen.cpp
|
||||||
|
* @brief This file defines the Farm1StateOpen class.
|
||||||
|
* @date 24.04.2013
|
||||||
|
* @author baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <framework/datalinklayer/ClcwIF.h>
|
||||||
|
#include <framework/datalinklayer/Farm1StateOpen.h>
|
||||||
|
#include <framework/datalinklayer/TcTransferFrame.h>
|
||||||
|
#include <framework/datalinklayer/VirtualChannelReception.h>
|
||||||
|
|
||||||
|
Farm1StateOpen::Farm1StateOpen(VirtualChannelReception* setMyVC) : myVC(setMyVC) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t Farm1StateOpen::handleADFrame(TcTransferFrame* frame,
|
||||||
|
ClcwIF* clcw) {
|
||||||
|
int8_t diff = frame->getSequenceNumber() - myVC->vR;
|
||||||
|
if (diff == 0 ) {
|
||||||
|
myVC->vR++;
|
||||||
|
clcw->setRetransmitFlag(false);
|
||||||
|
return FRAME_OK;
|
||||||
|
} else if (diff < myVC->positiveWindow && diff > 0 ) {
|
||||||
|
clcw->setRetransmitFlag(true);
|
||||||
|
return NS_POSITIVE_W;
|
||||||
|
} else if (diff < 0 && diff >= -myVC->negativeWindow) {
|
||||||
|
return NS_NEGATIVE_W;
|
||||||
|
} else {
|
||||||
|
clcw->setLockoutFlag(true);
|
||||||
|
myVC->currentState = &(myVC->lockoutState);
|
||||||
|
return NS_LOCKOUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t Farm1StateOpen::handleBCUnlockCommand( ClcwIF* clcw ) {
|
||||||
|
myVC->farmBCounter++;
|
||||||
|
clcw->setRetransmitFlag(false);
|
||||||
|
return BC_IS_UNLOCK_COMMAND;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t Farm1StateOpen::handleBCSetVrCommand( ClcwIF* clcw, uint8_t vr ) {
|
||||||
|
myVC->farmBCounter++;
|
||||||
|
clcw->setRetransmitFlag(false);
|
||||||
|
myVC->vR = vr;
|
||||||
|
return BC_IS_SET_VR_COMMAND;
|
||||||
|
}
|
62
datalinklayer/Farm1StateOpen.h
Normal file
62
datalinklayer/Farm1StateOpen.h
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/**
|
||||||
|
* @file Farm1StateOpen.h
|
||||||
|
* @brief This file defines the Farm1StateOpen class.
|
||||||
|
* @date 24.04.2013
|
||||||
|
* @author baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FARM1STATEOPEN_H_
|
||||||
|
#define FARM1STATEOPEN_H_
|
||||||
|
|
||||||
|
#include <framework/datalinklayer/Farm1StateIF.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents the FARM-1 "Open" State.
|
||||||
|
* The Open state is the state of normal operation. It handles all types of frames,
|
||||||
|
* including AD Frames. If a wrong Frame Sequence Number is detected in an AD Frame, the
|
||||||
|
* State reacts as specified.
|
||||||
|
*/
|
||||||
|
class Farm1StateOpen : public Farm1StateIF {
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* This is a reference to the "owner" class the State works on.
|
||||||
|
*/
|
||||||
|
VirtualChannelReception* myVC;
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* The default constructor if the State.
|
||||||
|
* Sets the "owner" of the State.
|
||||||
|
* @param setMyVC The "owner" class.
|
||||||
|
*/
|
||||||
|
Farm1StateOpen( VirtualChannelReception* setMyVC );
|
||||||
|
/**
|
||||||
|
* Method to check the validity of AD Frames.
|
||||||
|
* It checks the Frame Sequence Number and reacts as specified in the standard. The state may
|
||||||
|
* change to Farm1StateLockout.
|
||||||
|
* @param frame The frame to handle.
|
||||||
|
* @param clcw Any changes to the CLCW shall be done with the help of this interface.
|
||||||
|
* @return If the Sequence Number is ok, it returns #FRAME_OK. Otherwise either #NS_POSITIVE_W,
|
||||||
|
* #NS_NEGATIVE_W or NS_LOCKOUT is returned.
|
||||||
|
*/
|
||||||
|
ReturnValue_t handleADFrame( TcTransferFrame* frame, ClcwIF* clcw );
|
||||||
|
/**
|
||||||
|
* These commands are handled as specified.
|
||||||
|
* State does not change.
|
||||||
|
* @param clcw Any changes to the CLCW shall be done with the help of this interface.
|
||||||
|
* @return As the frame needs no forwarding to a MAP Channel, #BC_IS_UNLOCK_COMMAND
|
||||||
|
* is returned.
|
||||||
|
*/
|
||||||
|
ReturnValue_t handleBCUnlockCommand( ClcwIF* clcw );
|
||||||
|
/**
|
||||||
|
* These commands are handled as specified.
|
||||||
|
* State does not change.
|
||||||
|
* @param clcw Any changes to the CLCW shall be done with the help of this interface.
|
||||||
|
* @param vr The V(r) value found in the frame.
|
||||||
|
* @return As the frame needs no forwarding to a MAP Channel, #BC_IS_SET_VR_COMMAND
|
||||||
|
* is returned.
|
||||||
|
*/
|
||||||
|
ReturnValue_t handleBCSetVrCommand( ClcwIF* clcw, uint8_t vr );
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* FARM1STATEOPEN_H_ */
|
43
datalinklayer/Farm1StateWait.cpp
Normal file
43
datalinklayer/Farm1StateWait.cpp
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/**
|
||||||
|
* @file Farm1StateWait.cpp
|
||||||
|
* @brief This file defines the Farm1StateWait class.
|
||||||
|
* @date 24.04.2013
|
||||||
|
* @author baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <framework/datalinklayer/ClcwIF.h>
|
||||||
|
#include <framework/datalinklayer/Farm1StateWait.h>
|
||||||
|
#include <framework/datalinklayer/TcTransferFrame.h>
|
||||||
|
#include <framework/datalinklayer/VirtualChannelReception.h>
|
||||||
|
|
||||||
|
Farm1StateWait::Farm1StateWait(VirtualChannelReception* setMyVC) : myVC(setMyVC) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t Farm1StateWait::handleADFrame(TcTransferFrame* frame,
|
||||||
|
ClcwIF* clcw) {
|
||||||
|
|
||||||
|
int8_t diff = frame->getSequenceNumber() - myVC->vR;
|
||||||
|
if ( diff < -myVC->negativeWindow || diff >= myVC->positiveWindow ) {
|
||||||
|
clcw->setLockoutFlag(true);
|
||||||
|
myVC->currentState = &(myVC->lockoutState);
|
||||||
|
}
|
||||||
|
return FARM_IN_WAIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t Farm1StateWait::handleBCUnlockCommand(ClcwIF* clcw) {
|
||||||
|
myVC->farmBCounter++;
|
||||||
|
clcw->setRetransmitFlag(false);
|
||||||
|
clcw->setWaitFlag( false );
|
||||||
|
myVC->currentState = &(myVC->openState);
|
||||||
|
return BC_IS_UNLOCK_COMMAND;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t Farm1StateWait::handleBCSetVrCommand(ClcwIF* clcw, uint8_t vr) {
|
||||||
|
myVC->farmBCounter++;
|
||||||
|
clcw->setWaitFlag( false );
|
||||||
|
clcw->setRetransmitFlag(false);
|
||||||
|
myVC->vR = vr;
|
||||||
|
myVC->currentState = &(myVC->openState);
|
||||||
|
return BC_IS_SET_VR_COMMAND;
|
||||||
|
}
|
58
datalinklayer/Farm1StateWait.h
Normal file
58
datalinklayer/Farm1StateWait.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/**
|
||||||
|
* @file Farm1StateWait.h
|
||||||
|
* @brief This file defines the Farm1StateWait class.
|
||||||
|
* @date 24.04.2013
|
||||||
|
* @author baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FARM1STATEWAIT_H_
|
||||||
|
#define FARM1STATEWAIT_H_
|
||||||
|
|
||||||
|
#include <framework/datalinklayer/Farm1StateIF.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents the FARM-1 "Wait" State.
|
||||||
|
* The Wait state is reached if higher level procedures inform the FARM-1 Machine to wait
|
||||||
|
* for a certain period. Currently, it is not in use.
|
||||||
|
*/
|
||||||
|
class Farm1StateWait : public Farm1StateIF {
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* This is a reference to the "owner" class the State works on.
|
||||||
|
*/
|
||||||
|
VirtualChannelReception* myVC;
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* The default constructor if the State.
|
||||||
|
* Sets the "owner" of the State.
|
||||||
|
* @param setMyVC The "owner" class.
|
||||||
|
*/
|
||||||
|
Farm1StateWait( VirtualChannelReception* setMyVC );
|
||||||
|
/**
|
||||||
|
* AD Frames are always discarded.
|
||||||
|
* If the frame number is in the lockout window, the state changes to Farm1StateLockout.
|
||||||
|
* @param frame The frame to handle.
|
||||||
|
* @param clcw Any changes to the CLCW shall be done with the help of this interface.
|
||||||
|
* @return Always returns FARM_IN_WAIT.
|
||||||
|
*/
|
||||||
|
ReturnValue_t handleADFrame( TcTransferFrame* frame, ClcwIF* clcw );
|
||||||
|
/**
|
||||||
|
* These commands are handled as specified.
|
||||||
|
* State changes to Farm1StateOpen.
|
||||||
|
* @param clcw Any changes to the CLCW shall be done with the help of this interface.
|
||||||
|
* @return As the frame needs no forwarding to a MAP Channel, #BC_IS_UNLOCK_COMMAND
|
||||||
|
* is returned.
|
||||||
|
*/
|
||||||
|
ReturnValue_t handleBCUnlockCommand( ClcwIF* clcw );
|
||||||
|
/**
|
||||||
|
* These commands are handled as specified.
|
||||||
|
* @param clcw Any changes to the CLCW shall be done with the help of this interface.
|
||||||
|
* @param vr The V(r) value found in the frame.
|
||||||
|
* @return As the frame needs no forwarding to a MAP Channel, #BC_IS_SET_VR_COMMAND
|
||||||
|
* is returned.
|
||||||
|
*/
|
||||||
|
ReturnValue_t handleBCSetVrCommand( ClcwIF* clcw, uint8_t vr );
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* FARM1STATEWAIT_H_ */
|
152
datalinklayer/MapPacketExtraction.cpp
Normal file
152
datalinklayer/MapPacketExtraction.cpp
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
/**
|
||||||
|
* @file MapPacketExtraction.cpp
|
||||||
|
* @brief This file defines the MapPacketExtraction class.
|
||||||
|
* @date 26.03.2013
|
||||||
|
* @author baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <framework/datalinklayer/MapPacketExtraction.h>
|
||||||
|
#include <framework/serviceinterface/ServiceInterfaceStream.h>
|
||||||
|
#include <framework/storagemanager/StorageManagerIF.h>
|
||||||
|
#include <framework/tmtcpacket/SpacePacketBase.h>
|
||||||
|
#include <framework/tmtcservices/AcceptsTelecommandsIF.h>
|
||||||
|
#include <framework/tmtcservices/TmTcMessage.h>
|
||||||
|
|
||||||
|
MapPacketExtraction::MapPacketExtraction(uint8_t setMapId,
|
||||||
|
object_id_t setPacketDestination) :
|
||||||
|
lastSegmentationFlag(NO_SEGMENTATION), mapId(setMapId), packetLength(0), bufferPosition(
|
||||||
|
packetBuffer), packetDestination(setPacketDestination), packetStore(
|
||||||
|
NULL) {
|
||||||
|
memset(packetBuffer, 0, sizeof(packetBuffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t MapPacketExtraction::extractPackets(TcTransferFrame* frame) {
|
||||||
|
uint8_t segmentationFlag = frame->getSequenceFlags();
|
||||||
|
ReturnValue_t status = TOO_SHORT_MAP_EXTRACTION;
|
||||||
|
switch (segmentationFlag) {
|
||||||
|
case NO_SEGMENTATION:
|
||||||
|
status = unpackBlockingPackets(frame);
|
||||||
|
break;
|
||||||
|
case FIRST_PORTION:
|
||||||
|
packetLength = frame->getDataLength();
|
||||||
|
if (packetLength <= MAX_PACKET_SIZE) {
|
||||||
|
memcpy(packetBuffer, frame->getDataField(), packetLength);
|
||||||
|
bufferPosition = &packetBuffer[packetLength];
|
||||||
|
status = FRAME_OK;
|
||||||
|
} else {
|
||||||
|
error
|
||||||
|
<< "MapPacketExtraction::extractPackets. Packet too large! Size: "
|
||||||
|
<< packetLength << std::endl;
|
||||||
|
clearBuffers();
|
||||||
|
status = CONTENT_TOO_LARGE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CONTINUING_PORTION:
|
||||||
|
case LAST_PORTION:
|
||||||
|
if (lastSegmentationFlag == FIRST_PORTION
|
||||||
|
|| lastSegmentationFlag == CONTINUING_PORTION) {
|
||||||
|
packetLength += frame->getDataLength();
|
||||||
|
if (packetLength <= MAX_PACKET_SIZE) {
|
||||||
|
memcpy(bufferPosition, frame->getDataField(),
|
||||||
|
frame->getDataLength());
|
||||||
|
bufferPosition = &packetBuffer[packetLength];
|
||||||
|
if (segmentationFlag == LAST_PORTION) {
|
||||||
|
status = sendCompletePacket(packetBuffer, packetLength);
|
||||||
|
clearBuffers();
|
||||||
|
}
|
||||||
|
status = FRAME_OK;
|
||||||
|
} else {
|
||||||
|
error
|
||||||
|
<< "MapPacketExtraction::extractPackets. Packet too large! Size: "
|
||||||
|
<< packetLength << std::endl;
|
||||||
|
clearBuffers();
|
||||||
|
status = CONTENT_TOO_LARGE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error
|
||||||
|
<< "MapPacketExtraction::extractPackets. Illegal segment! Last flag: "
|
||||||
|
<< (int) lastSegmentationFlag << std::endl;
|
||||||
|
clearBuffers();
|
||||||
|
status = ILLEGAL_SEGMENTATION_FLAG;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error
|
||||||
|
<< "MapPacketExtraction::extractPackets. Illegal segmentationFlag: "
|
||||||
|
<< (int) segmentationFlag << std::endl;
|
||||||
|
clearBuffers();
|
||||||
|
status = DATA_CORRUPTED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
lastSegmentationFlag = segmentationFlag;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t MapPacketExtraction::unpackBlockingPackets(
|
||||||
|
TcTransferFrame* frame) {
|
||||||
|
ReturnValue_t status = TOO_SHORT_BLOCKED_PACKET;
|
||||||
|
uint32_t totalLength = frame->getDataLength();
|
||||||
|
if (totalLength > MAX_PACKET_SIZE)
|
||||||
|
return CONTENT_TOO_LARGE;
|
||||||
|
uint8_t* position = frame->getDataField();
|
||||||
|
while ((totalLength > SpacePacketBase::MINIMUM_SIZE)) {
|
||||||
|
SpacePacketBase packet(position);
|
||||||
|
uint32_t packetSize = packet.getFullSize();
|
||||||
|
if (packetSize <= totalLength) {
|
||||||
|
status = sendCompletePacket(packet.getWholeData(),
|
||||||
|
packet.getFullSize());
|
||||||
|
totalLength -= packet.getFullSize();
|
||||||
|
position += packet.getFullSize();
|
||||||
|
status = FRAME_OK;
|
||||||
|
} else {
|
||||||
|
status = DATA_CORRUPTED;
|
||||||
|
totalLength = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (totalLength > 0) {
|
||||||
|
status = RESIDUAL_DATA;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t MapPacketExtraction::sendCompletePacket(uint8_t* data,
|
||||||
|
uint32_t size) {
|
||||||
|
store_address_t store_id;
|
||||||
|
ReturnValue_t status = this->packetStore->addData(&store_id, data, size);
|
||||||
|
if (status == RETURN_OK) {
|
||||||
|
TmTcMessage message(store_id);
|
||||||
|
status = this->tcQueue.sendToDefault(&message);
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapPacketExtraction::clearBuffers() {
|
||||||
|
memset(packetBuffer, 0, sizeof(packetBuffer));
|
||||||
|
bufferPosition = packetBuffer;
|
||||||
|
packetLength = 0;
|
||||||
|
lastSegmentationFlag = NO_SEGMENTATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t MapPacketExtraction::initialize() {
|
||||||
|
packetStore = objectManager->get<StorageManagerIF>(objects::TC_STORE);
|
||||||
|
AcceptsTelecommandsIF* distributor = objectManager->get<
|
||||||
|
AcceptsTelecommandsIF>(packetDestination);
|
||||||
|
if ((packetStore != NULL) && (distributor != NULL)) {
|
||||||
|
tcQueue.setDefaultDestination(distributor->getRequestQueue());
|
||||||
|
return RETURN_OK;
|
||||||
|
} else {
|
||||||
|
return RETURN_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapPacketExtraction::printPacketBuffer(void) {
|
||||||
|
debug << "DLL: packet_buffer contains: " << std::endl;
|
||||||
|
for (uint32_t i = 0; i < this->packetLength; ++i) {
|
||||||
|
debug << "packet_buffer[" << std::dec << i << "]: 0x" << std::hex
|
||||||
|
<< (uint16_t) this->packetBuffer[i] << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t MapPacketExtraction::getMapId() const {
|
||||||
|
return mapId;
|
||||||
|
}
|
77
datalinklayer/MapPacketExtraction.h
Normal file
77
datalinklayer/MapPacketExtraction.h
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
/**
|
||||||
|
* @file MapPacketExtraction.h
|
||||||
|
* @brief This file defines the MapPacketExtraction class.
|
||||||
|
* @date 26.03.2013
|
||||||
|
* @author baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MAPPACKETEXTRACTION_H_
|
||||||
|
#define MAPPACKETEXTRACTION_H_
|
||||||
|
|
||||||
|
#include <framework/datalinklayer/MapPacketExtractionIF.h>
|
||||||
|
#include <framework/ipc/MessageQueueSender.h>
|
||||||
|
#include <framework/objectmanager/ObjectManagerIF.h>
|
||||||
|
#include <framework/returnvalues/HasReturnvaluesIF.h>
|
||||||
|
class StorageManagerIF;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of a MAP Packet Extraction class.
|
||||||
|
* The class implements the full MAP Packet Extraction functionality as described in the CCSDS
|
||||||
|
* TC Space Data Link Protocol. It internally stores incomplete segmented packets until they are
|
||||||
|
* fully received. All found packets are forwarded to a single distribution entity.
|
||||||
|
*/
|
||||||
|
class MapPacketExtraction: public MapPacketExtractionIF {
|
||||||
|
private:
|
||||||
|
static const uint32_t MAX_PACKET_SIZE = 4096;
|
||||||
|
uint8_t lastSegmentationFlag; //!< The segmentation flag of the last received frame.
|
||||||
|
uint8_t mapId; //!< MAP ID of this MAP Channel.
|
||||||
|
uint32_t packetLength; //!< Complete length of the current Space Packet.
|
||||||
|
uint8_t* bufferPosition; //!< Position to write to in the internal Packet buffer.
|
||||||
|
uint8_t packetBuffer[MAX_PACKET_SIZE]; //!< The internal Space Packet Buffer.
|
||||||
|
object_id_t packetDestination;
|
||||||
|
StorageManagerIF* packetStore; //!< Pointer to the store where full TC packets are stored.
|
||||||
|
MessageQueueSender tcQueue; //!< Sender Queue to send found packets to the distributor.
|
||||||
|
/**
|
||||||
|
* Debug method to print the packet Buffer's content.
|
||||||
|
*/
|
||||||
|
void printPacketBuffer();
|
||||||
|
/**
|
||||||
|
* Method that is called if the segmentation flag is @c NO_SEGMENTATION.
|
||||||
|
* The method extracts one or more packets within the frame and forwards them to the OBSW.
|
||||||
|
* @param frame The TC Transfer Frame to work on.
|
||||||
|
* @return @c FRAME_OK if all Packets were extracted. If something is entirely wrong,
|
||||||
|
* @c DATA_CORRUPTED is returned, if some bytes are left over @c RESIDUAL_DATA.
|
||||||
|
*/
|
||||||
|
ReturnValue_t unpackBlockingPackets(TcTransferFrame* frame);
|
||||||
|
/**
|
||||||
|
* Helper method to forward a complete packet to the OBSW.
|
||||||
|
* @param data Pointer to the data, either directly from the frame or from the packetBuffer.
|
||||||
|
* @param size Complete total size of the packet.
|
||||||
|
* @return Return Code of the Packet Store or the Message Queue.
|
||||||
|
*/
|
||||||
|
ReturnValue_t sendCompletePacket( uint8_t* data, uint32_t size );
|
||||||
|
/**
|
||||||
|
* Helper method to reset the internal buffer.
|
||||||
|
*/
|
||||||
|
void clearBuffers();
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Default constructor.
|
||||||
|
* Members are set to default values.
|
||||||
|
* @param setMapId The MAP ID of the instance.
|
||||||
|
*/
|
||||||
|
MapPacketExtraction( uint8_t setMapId, object_id_t setPacketDestination );
|
||||||
|
ReturnValue_t extractPackets(TcTransferFrame* frame);
|
||||||
|
/**
|
||||||
|
* The #packetStore and the default destination of #tcQueue are initialized here.
|
||||||
|
* @return @c RETURN_OK on success, @c RETURN_FAILED otherwise.
|
||||||
|
*/
|
||||||
|
ReturnValue_t initialize();
|
||||||
|
/**
|
||||||
|
* Getter.
|
||||||
|
* @return The MAP ID of this instance.
|
||||||
|
*/
|
||||||
|
uint8_t getMapId() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* MAPPACKETEXTRACTION_H_ */
|
47
datalinklayer/MapPacketExtractionIF.h
Normal file
47
datalinklayer/MapPacketExtractionIF.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/**
|
||||||
|
* @file MapPacketExtractionIF.h
|
||||||
|
* @brief This file defines the MapPacketExtractionIF class.
|
||||||
|
* @date 25.03.2013
|
||||||
|
* @author baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MAPPACKETEXTRACTIONIF_H_
|
||||||
|
#define MAPPACKETEXTRACTIONIF_H_
|
||||||
|
|
||||||
|
#include <framework/datalinklayer/CCSDSReturnValuesIF.h>
|
||||||
|
#include <framework/datalinklayer/TcTransferFrame.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the interface for MAP Packet Extraction classes.
|
||||||
|
* All classes implementing this interface shall be able to extract blocked or segmented Space
|
||||||
|
* Packets on a certain MAP channel. This is done in accordance with the CCSDS TC Space Data Link
|
||||||
|
* Protocol.
|
||||||
|
*/
|
||||||
|
class MapPacketExtractionIF : public CCSDSReturnValuesIF {
|
||||||
|
protected:
|
||||||
|
static const uint8_t FIRST_PORTION = 0b01; //!< Identification of the first part of a segmented Packet.
|
||||||
|
static const uint8_t CONTINUING_PORTION = 0b00; //!< Identification of a continuing part of segmented Packets.
|
||||||
|
static const uint8_t LAST_PORTION = 0b10; //!< The last portion of a segmented Packet.
|
||||||
|
static const uint8_t NO_SEGMENTATION = 0b11; //!< A Frame without segmentation but maybe with blocking.
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Empty virtual destructor.
|
||||||
|
*/
|
||||||
|
virtual ~MapPacketExtractionIF() {
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Method to call to handle a single Transfer Frame.
|
||||||
|
* The method tries to extract Packets from the frame as stated in the Standard.
|
||||||
|
* @param frame
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
virtual ReturnValue_t extractPackets( TcTransferFrame* frame ) = 0;
|
||||||
|
/**
|
||||||
|
* Any post-instantiation initialization shall be done in this method.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
virtual ReturnValue_t initialize() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* MAPPACKETEXTRACTIONIF_H_ */
|
102
datalinklayer/TcTransferFrame.cpp
Normal file
102
datalinklayer/TcTransferFrame.cpp
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
/**
|
||||||
|
* @file TcTransferFrame.cpp
|
||||||
|
* @brief This file defines the TcTransferFrame class.
|
||||||
|
* @date 27.04.2013
|
||||||
|
* @author baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <framework/datalinklayer/TcTransferFrame.h>
|
||||||
|
#include <framework/serviceinterface/ServiceInterfaceStream.h>
|
||||||
|
|
||||||
|
TcTransferFrame::TcTransferFrame() {
|
||||||
|
frame = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
TcTransferFrame::TcTransferFrame(uint8_t* setData) {
|
||||||
|
this->frame = (tc_transfer_frame*)setData;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t TcTransferFrame::getVersionNumber() {
|
||||||
|
return (this->frame->header.flagsAndScid & 0b11000000) >> 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TcTransferFrame::bypassFlagSet() {
|
||||||
|
return (this->frame->header.flagsAndScid & 0b00100000) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TcTransferFrame::controlCommandFlagSet() {
|
||||||
|
return (this->frame->header.flagsAndScid & 0b00010000) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TcTransferFrame::spareIsZero() {
|
||||||
|
return ( (this->frame->header.flagsAndScid & 0b00001100) == 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t TcTransferFrame::getSpacecraftId() {
|
||||||
|
return ( (this->frame->header.flagsAndScid & 0b00000011) << 8 ) + this->frame->header.spacecraftId_l;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t TcTransferFrame::getVirtualChannelId() {
|
||||||
|
return (this->frame->header.vcidAndLength_h & 0b11111100) >> 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t TcTransferFrame::getFrameLength() {
|
||||||
|
return ( (this->frame->header.vcidAndLength_h & 0b00000011) << 8 ) + this->frame->header.length_l;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t TcTransferFrame::getDataLength() {
|
||||||
|
return this->getFrameLength() - this->getHeaderSize() -1 - FRAME_CRC_SIZE + 1; // -1 for the segment header.
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t TcTransferFrame::getSequenceNumber() {
|
||||||
|
return this->frame->header.sequenceNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t TcTransferFrame::getSequenceFlags() {
|
||||||
|
return (this->frame->dataField & 0b11000000)>>6;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t TcTransferFrame::getMAPId() {
|
||||||
|
return this->frame->dataField & 0b00111111;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* TcTransferFrame::getDataField() {
|
||||||
|
return &(this->frame->dataField) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* TcTransferFrame::getFullFrame() {
|
||||||
|
return (uint8_t*)this->frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t TcTransferFrame::getFullSize() {
|
||||||
|
return this->getFrameLength() + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t TcTransferFrame::getHeaderSize() {
|
||||||
|
return sizeof(frame->header);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t TcTransferFrame::getFullDataLength() {
|
||||||
|
return this->getFrameLength() - this->getHeaderSize() - FRAME_CRC_SIZE + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* TcTransferFrame::getFullDataField() {
|
||||||
|
return &frame->dataField;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcTransferFrame::print() {
|
||||||
|
debug << "Raw Frame: " << std::hex << std::endl;
|
||||||
|
for (uint16_t count = 0; count < this->getFullSize(); count++ ) {
|
||||||
|
debug << (uint16_t)this->getFullFrame()[count] << " ";
|
||||||
|
}
|
||||||
|
debug << std::dec << std::endl;
|
||||||
|
// debug << "Frame Header:" << std::endl;
|
||||||
|
// debug << "Version Number: " << std::hex << (uint16_t)this->current_frame.getVersionNumber() << std::endl;
|
||||||
|
// debug << "Bypass Flag set?| Ctrl Cmd Flag set?: " << (uint16_t)this->current_frame.bypassFlagSet() << " | " << (uint16_t)this->current_frame.controlCommandFlagSet() << std::endl;
|
||||||
|
// debug << "SCID : " << this->current_frame.getSpacecraftId() << std::endl;
|
||||||
|
// debug << "VCID : " << (uint16_t)this->current_frame.getVirtualChannelId() << std::endl;
|
||||||
|
// debug << "Frame length: " << std::dec << this->current_frame.getFrameLength() << std::endl;
|
||||||
|
// debug << "Sequence Number: " << (uint16_t)this->current_frame.getSequenceNumber() << std::endl;
|
||||||
|
}
|
137
datalinklayer/TcTransferFrame.h
Normal file
137
datalinklayer/TcTransferFrame.h
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
#ifndef TCTRANSFERFRAME_H_
|
||||||
|
#define TCTRANSFERFRAME_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The TcTransferFrame class simplifies handling of such Frames.
|
||||||
|
* It operates on any buffer passed on construction. The data length
|
||||||
|
* is determined by the length field in the frame itself.
|
||||||
|
* It has a lot of getters for convenient access to the content.
|
||||||
|
* @ingroup ccsds_handling
|
||||||
|
*/
|
||||||
|
class TcTransferFrame {
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* The struct that defines the Frame's Primary Header.
|
||||||
|
*/
|
||||||
|
struct TcTransferFramePrimaryHeader {
|
||||||
|
uint8_t flagsAndScid; //!< Highest byte with Flags and part of SCID.
|
||||||
|
uint8_t spacecraftId_l; //!< Byte with rest of SCID
|
||||||
|
uint8_t vcidAndLength_h; //!< Byte with VCID and part of length.
|
||||||
|
uint8_t length_l; //!< Byte with rest of length.
|
||||||
|
uint8_t sequenceNumber; //!< Lowest byte with Frame Sequence Number N(S).
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* The struct defining the whole Transfer Frame.
|
||||||
|
*/
|
||||||
|
struct tc_transfer_frame {
|
||||||
|
TcTransferFramePrimaryHeader header; //!< The header struct.
|
||||||
|
uint8_t dataField; //!< The data field of the Transfer Frame.
|
||||||
|
};
|
||||||
|
tc_transfer_frame* frame; //!< Pointer to a buffer where a Frame is placed.
|
||||||
|
public:
|
||||||
|
static const uint8_t FRAME_CRC_SIZE = 2; //!< Constant for the CRC size.
|
||||||
|
/**
|
||||||
|
* Empty Constructor that sets the data pointer to NULL.
|
||||||
|
*/
|
||||||
|
TcTransferFrame();
|
||||||
|
/**
|
||||||
|
* The data pointer passed in this Constructor is casted to the #tc_transfer_frame struct.
|
||||||
|
* @param setData The data on which the class shall operate.
|
||||||
|
*/
|
||||||
|
TcTransferFrame(uint8_t* setData);
|
||||||
|
/**
|
||||||
|
* Getter.
|
||||||
|
* @return The Version number.
|
||||||
|
*/
|
||||||
|
uint8_t getVersionNumber();
|
||||||
|
/**
|
||||||
|
* Getter.
|
||||||
|
* @return If the bypass flag is set or not.
|
||||||
|
*/
|
||||||
|
bool bypassFlagSet();
|
||||||
|
/**
|
||||||
|
* Getter.
|
||||||
|
* @return If the control command flag is set or not.
|
||||||
|
*/
|
||||||
|
bool controlCommandFlagSet();
|
||||||
|
/**
|
||||||
|
* Getter.
|
||||||
|
* @return If the spare bits in the Header are zero or not.
|
||||||
|
*/
|
||||||
|
bool spareIsZero();
|
||||||
|
/**
|
||||||
|
* Getter.
|
||||||
|
* @return The Spacecraft Identifier.
|
||||||
|
*/
|
||||||
|
uint16_t getSpacecraftId();
|
||||||
|
/**
|
||||||
|
* Getter.
|
||||||
|
* @return The Virtual Channel Identifier.
|
||||||
|
*/
|
||||||
|
uint8_t getVirtualChannelId();
|
||||||
|
/**
|
||||||
|
* Getter.
|
||||||
|
* @return The Frame length as stored in the Header.
|
||||||
|
*/
|
||||||
|
uint16_t getFrameLength();
|
||||||
|
/**
|
||||||
|
* Getter.
|
||||||
|
* @return The length of pure data (without CRC), assuming that a Segment Header is present.
|
||||||
|
*/
|
||||||
|
uint16_t getDataLength();
|
||||||
|
/**
|
||||||
|
* Getter.
|
||||||
|
* @return The length of pure data (without CRC), assuming that no Segment Header is present (for BC Frames).
|
||||||
|
*/
|
||||||
|
uint16_t getFullDataLength();
|
||||||
|
/**
|
||||||
|
* Getter.
|
||||||
|
* @return The sequence number from the header.
|
||||||
|
*/
|
||||||
|
uint8_t getSequenceNumber();
|
||||||
|
/**
|
||||||
|
* Getter.
|
||||||
|
* @return The Sequence Flags in the Segment Header byte (right aligned).
|
||||||
|
*/
|
||||||
|
uint8_t getSequenceFlags();
|
||||||
|
/**
|
||||||
|
* Getter.
|
||||||
|
* @return The Multiplexer Access Point Identifier from the Segment Header byte.
|
||||||
|
*/
|
||||||
|
uint8_t getMAPId();
|
||||||
|
/**
|
||||||
|
* Getter.
|
||||||
|
* @return A pointer to the date field AFTER a Segment Header.
|
||||||
|
*/
|
||||||
|
uint8_t* getDataField();
|
||||||
|
/**
|
||||||
|
* Getter.
|
||||||
|
* @return A pointer to the first byte in the Data Field (ignoring potential Segment Headers, for BC Frames).
|
||||||
|
*/
|
||||||
|
uint8_t* getFullDataField();
|
||||||
|
/**
|
||||||
|
* Getter.
|
||||||
|
* @return A pointer to the beginning of the Frame.
|
||||||
|
*/
|
||||||
|
uint8_t* getFullFrame();
|
||||||
|
/**
|
||||||
|
* Getter
|
||||||
|
* @return The total size of the Frame, which is the size stated in the Header + 1.
|
||||||
|
*/
|
||||||
|
uint16_t getFullSize();
|
||||||
|
/**
|
||||||
|
* Getter.
|
||||||
|
* @return Size of the #TcTransferFramePrimaryHeader.
|
||||||
|
*/
|
||||||
|
uint16_t getHeaderSize();
|
||||||
|
/**
|
||||||
|
* Debug method to print the whole Frame to screen.
|
||||||
|
*/
|
||||||
|
void print();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* TCTRANSFERFRAME_H_ */
|
49
datalinklayer/TcTransferFrameLocal.cpp
Normal file
49
datalinklayer/TcTransferFrameLocal.cpp
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
/**
|
||||||
|
* @file TcTransferFrameLocal.cpp
|
||||||
|
* @brief This file defines the TcTransferFrameLocal class.
|
||||||
|
* @date 27.04.2013
|
||||||
|
* @author baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <framework/datalinklayer/TcTransferFrameLocal.h>
|
||||||
|
#include <framework/globalfunctions/crc_ccitt.h>
|
||||||
|
#include <framework/serviceinterface/ServiceInterfaceStream.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
TcTransferFrameLocal::TcTransferFrameLocal(bool bypass, bool controlCommand, uint16_t scid,
|
||||||
|
uint8_t vcId, uint8_t sequenceNumber, uint8_t setSegmentHeader, uint8_t* data, uint16_t dataSize, uint16_t forceCrc) {
|
||||||
|
this->frame = (tc_transfer_frame*)&localData;
|
||||||
|
frame->header.flagsAndScid = (bypass << 5) + (controlCommand << 4) + ((scid & 0x0300) >> 8);
|
||||||
|
frame->header.spacecraftId_l = (scid & 0x00FF);
|
||||||
|
frame->header.vcidAndLength_h = (vcId & 0b00111111) << 2;
|
||||||
|
frame->header.length_l = sizeof(TcTransferFramePrimaryHeader) -1;
|
||||||
|
frame->header.sequenceNumber = sequenceNumber;
|
||||||
|
frame->dataField = setSegmentHeader;
|
||||||
|
if (data != NULL) {
|
||||||
|
if (bypass && controlCommand) {
|
||||||
|
memcpy(&(frame->dataField), data, dataSize);
|
||||||
|
uint16_t totalSize = sizeof(TcTransferFramePrimaryHeader) + dataSize + FRAME_CRC_SIZE -1;
|
||||||
|
frame->header.vcidAndLength_h |= (totalSize & 0x0300) >> 8;
|
||||||
|
frame->header.length_l = (totalSize & 0x00FF);
|
||||||
|
uint16_t crc = ::Calculate_CRC(getFullFrame(), getFullSize() -2);
|
||||||
|
this->getFullFrame()[getFullSize()-2] = (crc & 0xFF00) >> 8;
|
||||||
|
this->getFullFrame()[getFullSize()-1] = (crc & 0x00FF);
|
||||||
|
} else if (dataSize <= 1016) {
|
||||||
|
memcpy(&(frame->dataField) +1, data, dataSize);
|
||||||
|
uint16_t dataCrcSize = sizeof(TcTransferFramePrimaryHeader) + 1 + dataSize + FRAME_CRC_SIZE -1;
|
||||||
|
frame->header.vcidAndLength_h |= (dataCrcSize & 0x0300) >> 8;
|
||||||
|
frame->header.length_l = (dataCrcSize & 0x00FF);
|
||||||
|
uint16_t crc = ::Calculate_CRC(getFullFrame(), getFullSize() -2);
|
||||||
|
this->getFullFrame()[getFullSize()-2] = (crc & 0xFF00) >> 8;
|
||||||
|
this->getFullFrame()[getFullSize()-1] = (crc & 0x00FF);
|
||||||
|
} else {
|
||||||
|
debug << "TcTransferFrameLocal: dataSize too large: " << dataSize << std::endl;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//No data in frame
|
||||||
|
}
|
||||||
|
if (forceCrc != 0 ) {
|
||||||
|
localData.data[getFullSize()-2] = (forceCrc & 0xFF00) >> 8;
|
||||||
|
localData.data[getFullSize()-1] = (forceCrc & 0x00FF);
|
||||||
|
}
|
||||||
|
}
|
49
datalinklayer/TcTransferFrameLocal.h
Normal file
49
datalinklayer/TcTransferFrameLocal.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
/**
|
||||||
|
* @file TcTransferFrameLocal.h
|
||||||
|
* @brief This file defines the TcTransferFrameLocal class.
|
||||||
|
* @date 27.04.2013
|
||||||
|
* @author baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TCTRANSFERFRAMELOCAL_H_
|
||||||
|
#define TCTRANSFERFRAMELOCAL_H_
|
||||||
|
|
||||||
|
#include <framework/datalinklayer/TcTransferFrame.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a helper class to locally create TC Transfer Frames.
|
||||||
|
* This is mainly required for testing purposes and therefore not very sophisticated.
|
||||||
|
* @ingroup ccsds_handling
|
||||||
|
*/
|
||||||
|
class TcTransferFrameLocal : public TcTransferFrame {
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* A stuct to locally store the complete data.
|
||||||
|
*/
|
||||||
|
struct frameData {
|
||||||
|
TcTransferFramePrimaryHeader header; //!< The primary header.
|
||||||
|
uint8_t data[1019]; //!< The data field.
|
||||||
|
};
|
||||||
|
public:
|
||||||
|
frameData localData; //!< The local data in the Frame.
|
||||||
|
/**
|
||||||
|
* The default Constructor.
|
||||||
|
* All parameters in the Header are passed.
|
||||||
|
* If a BC Frame is detected no segment header is created.
|
||||||
|
* Otherwise (AD and BD), the Segment Header is set.
|
||||||
|
* @param bypass The bypass flag.
|
||||||
|
* @param controlCommand The Control Command flag.
|
||||||
|
* @param scid The SCID.
|
||||||
|
* @param vcId The VCID.
|
||||||
|
* @param sequenceNumber The Frame Sequence Number N(s)
|
||||||
|
* @param setSegmentHeader A value for the Segment Header.
|
||||||
|
* @param data Data to put into the Frame Data Field.
|
||||||
|
* @param dataSize Size of the Data.
|
||||||
|
* @param forceCrc if != 0, the value is used as CRC.
|
||||||
|
*/
|
||||||
|
TcTransferFrameLocal(bool bypass, bool controlCommand, uint16_t scid, uint8_t vcId, uint8_t sequenceNumber,
|
||||||
|
uint8_t setSegmentHeader = 0xC0, uint8_t* data = NULL, uint16_t dataSize = 0, uint16_t forceCrc = 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* TCTRANSFERFRAMELOCAL_H_ */
|
114
datalinklayer/VirtualChannelReception.cpp
Normal file
114
datalinklayer/VirtualChannelReception.cpp
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
/**
|
||||||
|
* @file VirtualChannelReception.cpp
|
||||||
|
* @brief This file defines the VirtualChannelReception class.
|
||||||
|
* @date 26.03.2013
|
||||||
|
* @author baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <framework/datalinklayer/BCFrame.h>
|
||||||
|
#include <framework/datalinklayer/VirtualChannelReception.h>
|
||||||
|
#include <framework/serviceinterface/ServiceInterfaceStream.h>
|
||||||
|
|
||||||
|
VirtualChannelReception::VirtualChannelReception(uint8_t setChannelId,
|
||||||
|
uint8_t setSlidingWindowWidth) :
|
||||||
|
channelId(setChannelId), slidingWindowWidth(setSlidingWindowWidth), positiveWindow(
|
||||||
|
setSlidingWindowWidth / 2), negativeWindow(setSlidingWindowWidth / 2), currentState(
|
||||||
|
&openState), openState(this), waitState(this), lockoutState(this), vR(0), farmBCounter(
|
||||||
|
0) {
|
||||||
|
internalClcw.setVirtualChannel(channelId);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t VirtualChannelReception::mapDemultiplexing(TcTransferFrame* frame) {
|
||||||
|
uint8_t mapId = frame->getMAPId();
|
||||||
|
mapChannelIterator iter = mapChannels.find(mapId);
|
||||||
|
if (iter == mapChannels.end()) {
|
||||||
|
// error << "VirtualChannelReception::mapDemultiplexing on VC " << std::hex << (int) channelId
|
||||||
|
// << ": MapChannel " << (int) mapId << std::dec << " not found." << std::endl;
|
||||||
|
return VC_NOT_FOUND;
|
||||||
|
} else {
|
||||||
|
return (iter->second)->extractPackets(frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t VirtualChannelReception::doFARM(TcTransferFrame* frame, ClcwIF* clcw) {
|
||||||
|
uint8_t bypass = frame->bypassFlagSet();
|
||||||
|
uint8_t controlCommand = frame->controlCommandFlagSet();
|
||||||
|
uint8_t typeValue = (bypass << 1) + controlCommand;
|
||||||
|
switch (typeValue) {
|
||||||
|
case AD_FRAME:
|
||||||
|
return currentState->handleADFrame(frame, clcw);
|
||||||
|
case BD_FRAME:
|
||||||
|
return handleBDFrame(frame, clcw);
|
||||||
|
case BC_FRAME:
|
||||||
|
return handleBCFrame(frame, clcw);
|
||||||
|
default:
|
||||||
|
return ILLEGAL_FLAG_COMBINATION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t VirtualChannelReception::frameAcceptanceAndReportingMechanism(TcTransferFrame* frame,
|
||||||
|
ClcwIF* clcw) {
|
||||||
|
ReturnValue_t status = FRAME_OK;
|
||||||
|
status = doFARM(frame, &internalClcw);
|
||||||
|
internalClcw.setReceiverFrameSequenceNumber(vR);
|
||||||
|
internalClcw.setFarmBCount(farmBCounter);
|
||||||
|
clcw->setWhole(internalClcw.getAsWhole());
|
||||||
|
if (status == FRAME_OK) {
|
||||||
|
status = mapDemultiplexing(frame);
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t VirtualChannelReception::addMapChannel(uint8_t mapId, MapPacketExtractionIF* object) {
|
||||||
|
std::pair<mapChannelIterator, bool> returnValue = mapChannels.insert(
|
||||||
|
std::pair<uint8_t, MapPacketExtractionIF*>(mapId, object));
|
||||||
|
if (returnValue.second == true) {
|
||||||
|
return RETURN_OK;
|
||||||
|
} else {
|
||||||
|
return RETURN_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t VirtualChannelReception::handleBDFrame(TcTransferFrame* frame, ClcwIF* clcw) {
|
||||||
|
farmBCounter++;
|
||||||
|
return FRAME_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t VirtualChannelReception::handleBCFrame(TcTransferFrame* frame, ClcwIF* clcw) {
|
||||||
|
BcFrame content;
|
||||||
|
ReturnValue_t returnValue = content.initialize(frame->getFullDataField(),
|
||||||
|
frame->getFullDataLength());
|
||||||
|
if (returnValue == BC_IS_UNLOCK_COMMAND) {
|
||||||
|
returnValue = currentState->handleBCUnlockCommand(clcw);
|
||||||
|
} else if (returnValue == BC_IS_SET_VR_COMMAND) {
|
||||||
|
returnValue = currentState->handleBCSetVrCommand(clcw, content.vR);
|
||||||
|
} else {
|
||||||
|
//Do nothing
|
||||||
|
}
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t VirtualChannelReception::getChannelId() const {
|
||||||
|
return channelId;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t VirtualChannelReception::initialize() {
|
||||||
|
ReturnValue_t returnValue = RETURN_FAILED;
|
||||||
|
if ((slidingWindowWidth > 254) || (slidingWindowWidth % 2 != 0)) {
|
||||||
|
error << "VirtualChannelReception::initialize: Illegal sliding window width: "
|
||||||
|
<< (int) slidingWindowWidth << std::endl;
|
||||||
|
return RETURN_FAILED;
|
||||||
|
}
|
||||||
|
for (mapChannelIterator iterator = mapChannels.begin(); iterator != mapChannels.end();
|
||||||
|
iterator++) {
|
||||||
|
returnValue = iterator->second->initialize();
|
||||||
|
if (returnValue != RETURN_OK)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualChannelReception::setToWaitState() {
|
||||||
|
internalClcw.setWaitFlag(true);
|
||||||
|
this->currentState = &waitState;
|
||||||
|
}
|
114
datalinklayer/VirtualChannelReception.h
Normal file
114
datalinklayer/VirtualChannelReception.h
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
/**
|
||||||
|
* @file VirtualChannelReception.h
|
||||||
|
* @brief This file defines the VirtualChannelReception class.
|
||||||
|
* @date 25.03.2013
|
||||||
|
* @author baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef VIRTUALCHANNELRECEPTION_H_
|
||||||
|
#define VIRTUALCHANNELRECEPTION_H_
|
||||||
|
|
||||||
|
#include <framework/datalinklayer/CCSDSReturnValuesIF.h>
|
||||||
|
#include <framework/datalinklayer/Clcw.h>
|
||||||
|
#include <framework/datalinklayer/Farm1StateIF.h>
|
||||||
|
#include <framework/datalinklayer/Farm1StateLockout.h>
|
||||||
|
#include <framework/datalinklayer/Farm1StateOpen.h>
|
||||||
|
#include <framework/datalinklayer/Farm1StateWait.h>
|
||||||
|
#include <framework/datalinklayer/MapPacketExtractionIF.h>
|
||||||
|
#include <framework/datalinklayer/VirtualChannelReceptionIF.h>
|
||||||
|
#include <map>
|
||||||
|
/**
|
||||||
|
* Implementation of a TC Virtual Channel.
|
||||||
|
* This is a full implementation of a virtual channel as specified in the CCSDS TC Space Data Link
|
||||||
|
* Protocol. It is designed to operate within an instance of the @c DataLinkLayer class.
|
||||||
|
* Features:
|
||||||
|
* - any (6bit) Virtual Channel ID is assignable.
|
||||||
|
* - Supports an arbitrary number of MAP Channels (with a map).
|
||||||
|
* - Has a complete FARM-1 Machine built-in.
|
||||||
|
*
|
||||||
|
* The FARM-1 state machine uses the State Pattern.
|
||||||
|
*/
|
||||||
|
class VirtualChannelReception : public VirtualChannelReceptionIF, public CCSDSReturnValuesIF {
|
||||||
|
friend class Farm1StateOpen;
|
||||||
|
friend class Farm1StateWait;
|
||||||
|
friend class Farm1StateLockout;
|
||||||
|
private:
|
||||||
|
uint8_t channelId; //!< Stores the VCID that was assigned on construction.
|
||||||
|
uint8_t slidingWindowWidth; //!< A constant to set the FARM-1 sliding window width.
|
||||||
|
uint8_t positiveWindow; //!< The positive window for the FARM-1 machine.
|
||||||
|
uint8_t negativeWindow; //!< The negative window for the FARM-1 machine.
|
||||||
|
protected:
|
||||||
|
Farm1StateIF* currentState; //!< The current state. To change, one of the other states must be assigned to this pointer.
|
||||||
|
Farm1StateOpen openState; //!< Instance of the FARM-1 State "Open".
|
||||||
|
Farm1StateWait waitState; //!< Instance of the FARM-1 State "Wait".
|
||||||
|
Farm1StateLockout lockoutState; //!< Instance of the FARM-1 State "Lockout".
|
||||||
|
Clcw internalClcw; //!< A CLCW class to internally set the values before writing them back to the TTC System.
|
||||||
|
uint8_t vR; //!< The Receiver Frame Sequence Number V(R) as it shall be maintained for every Virtual Channel.
|
||||||
|
uint8_t farmBCounter; //!< The FARM-B COunter as it shall be maintained for every Virtual Channel.
|
||||||
|
typedef std::map<uint8_t, MapPacketExtractionIF*>::iterator mapChannelIterator; //!< Typedef to simplify handling of the mapChannels map.
|
||||||
|
std::map<uint8_t, MapPacketExtractionIF*> mapChannels; //!< A map that maintains all map Channels. Channels must be configured on initialization. MAy be omitted in a simplified version.
|
||||||
|
/**
|
||||||
|
* This method handles demultiplexing to different map channels.
|
||||||
|
* It parses the entries of #mapChannels and forwards the Frame to a found MAP Channel.
|
||||||
|
* @param frame The frame to forward.
|
||||||
|
* @return #VC_NOT_FOUND or the return value of the map channel extraction.
|
||||||
|
*/
|
||||||
|
ReturnValue_t mapDemultiplexing( TcTransferFrame* frame );
|
||||||
|
/**
|
||||||
|
* A sub-method that actually does the FARM-1 handling for different Frame types.
|
||||||
|
* @param frame The Tc Transfer Frame to handle.
|
||||||
|
* @param clcw Any changes on the CLCW shall be done with this method.
|
||||||
|
* @return The return code of higher methods or @c ILLEGAL_FLAG_COMBINATION.
|
||||||
|
*/
|
||||||
|
ReturnValue_t doFARM(TcTransferFrame* frame, ClcwIF* clcw);
|
||||||
|
/**
|
||||||
|
* Handles incoming BD Frames.
|
||||||
|
* Handling these Frames is independent of the State, so no subcall to #currentState is
|
||||||
|
* required.
|
||||||
|
* @param frame The Tc Transfer Frame to handle.
|
||||||
|
* @param clcw Any changes on the CLCW shall be done with this method.
|
||||||
|
* @return Always returns @c FRAME_OK.
|
||||||
|
*/
|
||||||
|
ReturnValue_t handleBDFrame( TcTransferFrame* frame, ClcwIF* clcw );
|
||||||
|
/**
|
||||||
|
* Handles incoming BC Frames.
|
||||||
|
* The type of the BC Frame is detected and checked first, then methods of #currentState are called.
|
||||||
|
* @param frame The Tc Transfer Frame to handle.
|
||||||
|
* @param clcw Any changes on the CLCW shall be done with this method.
|
||||||
|
* @return The failure code of BC Frame interpretation or the return code of higher methods.
|
||||||
|
*/
|
||||||
|
ReturnValue_t handleBCFrame( TcTransferFrame* frame, ClcwIF* clcw );
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Default constructor.
|
||||||
|
* Only sets the channelId of the channel. Setting the Sliding Window width is possible as well.
|
||||||
|
* @param setChannelId Virtual Channel Identifier (VCID) of the channel.
|
||||||
|
*/
|
||||||
|
VirtualChannelReception( uint8_t setChannelId, uint8_t setSlidingWindowWidth );
|
||||||
|
ReturnValue_t frameAcceptanceAndReportingMechanism( TcTransferFrame* frame, ClcwIF* clcw );
|
||||||
|
/**
|
||||||
|
* Helper method to simplify adding a mapChannel during construction.
|
||||||
|
* @param mapId The mapId of the object to add.
|
||||||
|
* @param object Pointer to the MapPacketExtraction object itself.
|
||||||
|
* @return @c RETURN_OK if the channel was successfully inserted, @c RETURN_FAILED otherwise.
|
||||||
|
*/
|
||||||
|
ReturnValue_t addMapChannel( uint8_t mapId, MapPacketExtractionIF* object );
|
||||||
|
/**
|
||||||
|
* The initialization routine checks the set #slidingWindowWidth and initializes all MAP
|
||||||
|
* channels.
|
||||||
|
* @return @c RETURN_OK on successful initialization, @c RETURN_FAILED otherwise.
|
||||||
|
*/
|
||||||
|
ReturnValue_t initialize();
|
||||||
|
/**
|
||||||
|
* Getter for the VCID.
|
||||||
|
* @return The #channelId.
|
||||||
|
*/
|
||||||
|
uint8_t getChannelId() const;
|
||||||
|
/**
|
||||||
|
* Small method to set the state to Farm1StateWait.
|
||||||
|
*/
|
||||||
|
void setToWaitState();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* VIRTUALCHANNELRECEPTION_H_ */
|
57
datalinklayer/VirtualChannelReceptionIF.h
Normal file
57
datalinklayer/VirtualChannelReceptionIF.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/**
|
||||||
|
* @file VirtualChannelReceptionIF.h
|
||||||
|
* @brief This file defines the VirtualChannelReceptionIF class.
|
||||||
|
* @date 25.03.2013
|
||||||
|
* @author baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef VIRTUALCHANNELRECEPTIONIF_H_
|
||||||
|
#define VIRTUALCHANNELRECEPTIONIF_H_
|
||||||
|
|
||||||
|
#include <framework/datalinklayer/ClcwIF.h>
|
||||||
|
#include <framework/datalinklayer/TcTransferFrame.h>
|
||||||
|
#include <framework/returnvalues/HasReturnvaluesIF.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the interface for Virtual Channel reception classes.
|
||||||
|
* It represents a single TC Virtual Channel that operates on one IO
|
||||||
|
*/
|
||||||
|
class VirtualChannelReceptionIF {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Enum including all valid types of frames.
|
||||||
|
* The type is made up by two flags, so 0b1111 is definitely illegal.
|
||||||
|
*/
|
||||||
|
enum frameType {
|
||||||
|
AD_FRAME = 0b00,
|
||||||
|
BC_FRAME = 0b11,
|
||||||
|
BD_FRAME = 0b10,
|
||||||
|
ILLEGAL_FRAME = 0b1111
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Empty virtual destructor.
|
||||||
|
*/
|
||||||
|
virtual ~VirtualChannelReceptionIF() {
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This method shall accept frames and do all FARM-1 stuff.
|
||||||
|
* Handling the Frame includes forwarding to higher-level procedures.
|
||||||
|
* @param frame The Tc Transfer Frame that was received and checked.
|
||||||
|
* @param clcw Any changes to the CLCW value are forwarded by using this parameter.
|
||||||
|
* @return The return Value shall indicate successful processing with @c FRAME_OK.
|
||||||
|
*/
|
||||||
|
virtual ReturnValue_t frameAcceptanceAndReportingMechanism( TcTransferFrame* frame, ClcwIF* clcw ) = 0;
|
||||||
|
/**
|
||||||
|
* If any other System Objects are required for operation they shall be initialized here.
|
||||||
|
* @return @c RETURN_OK for successful initialization.
|
||||||
|
*/
|
||||||
|
virtual ReturnValue_t initialize() = 0;
|
||||||
|
/**
|
||||||
|
* Getter for the VCID.
|
||||||
|
* @return The #channelId.
|
||||||
|
*/
|
||||||
|
virtual uint8_t getChannelId() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* VIRTUALCHANNELRECEPTIONIF_H_ */
|
136
datapool/DataPool.cpp
Normal file
136
datapool/DataPool.cpp
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
* DataPool.cpp
|
||||||
|
*
|
||||||
|
* Created on: 17.10.2012
|
||||||
|
* Author: baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <framework/datapool/DataPool.h>
|
||||||
|
#include <framework/serviceinterface/ServiceInterfaceStream.h>
|
||||||
|
DataPool::DataPool( void ( *initFunction )( std::map<uint32_t, PoolEntryIF*>* pool_map ) ) {
|
||||||
|
this->mutex = new MutexId_t;
|
||||||
|
OSAL::createMutex( OSAL::buildName('M','T','X','0'), ( this->mutex ) );
|
||||||
|
if (initFunction != NULL ) {
|
||||||
|
initFunction( &this->data_pool );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DataPool::~DataPool() {
|
||||||
|
OSAL::deleteMutex( this->mutex );
|
||||||
|
delete this->mutex;
|
||||||
|
for ( std::map<uint32_t, PoolEntryIF*>::iterator it = this->data_pool.begin(); it != this->data_pool.end(); ++it ) {
|
||||||
|
delete it->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//The function checks PID, type and array length before returning a copy of the PoolEntry. In failure case, it returns a temp-Entry with size 0 and NULL-ptr.
|
||||||
|
template <typename T> PoolEntry<T>* DataPool::getData( uint32_t data_pool_id, uint8_t sizeOrPosition ) {
|
||||||
|
std::map<uint32_t, PoolEntryIF*>::iterator it = this->data_pool.find( data_pool_id );
|
||||||
|
if ( it != this->data_pool.end() ) {
|
||||||
|
PoolEntry<T>* entry = dynamic_cast< PoolEntry<T>* >( it->second );
|
||||||
|
if (entry != NULL ) {
|
||||||
|
if ( sizeOrPosition <= entry->length ) {
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
PoolEntryIF* DataPool::getRawData( uint32_t data_pool_id ) {
|
||||||
|
std::map<uint32_t, PoolEntryIF*>::iterator it = this->data_pool.find( data_pool_id );
|
||||||
|
if ( it != this->data_pool.end() ) {
|
||||||
|
return it->second;
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//uint8_t DataPool::getRawData( uint32_t data_pool_id, uint8_t* address, uint16_t* size, uint32_t max_size ) {
|
||||||
|
// std::map<uint32_t, PoolEntryIF*>::iterator it = this->data_pool.find( data_pool_id );
|
||||||
|
// if ( it != this->data_pool.end() ) {
|
||||||
|
// if ( it->second->getByteSize() <= max_size ) {
|
||||||
|
// *size = it->second->getByteSize();
|
||||||
|
// memcpy( address, it->second->getRawData(), *size );
|
||||||
|
// return DP_SUCCESSFUL;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// *size = 0;
|
||||||
|
// return DP_FAILURE;
|
||||||
|
//}
|
||||||
|
|
||||||
|
ReturnValue_t DataPool::freeDataPoolLock() {
|
||||||
|
ReturnValue_t status = OSAL::unlockMutex( this->mutex );
|
||||||
|
if ( status != RETURN_OK ) {
|
||||||
|
error << "DataPool::DataPool: unlock of mutex failed with error code: " << status << std::endl;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t DataPool::lockDataPool() {
|
||||||
|
ReturnValue_t status = OSAL::lockMutex( this->mutex, OSAL::NO_TIMEOUT );
|
||||||
|
if ( status != RETURN_OK ) {
|
||||||
|
error << "DataPool::DataPool: lock of mutex failed with error code: " << status << std::endl;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataPool::print() {
|
||||||
|
debug << "DataPool contains: " << std::endl;
|
||||||
|
std::map<uint32_t, PoolEntryIF*>::iterator dataPoolIt;
|
||||||
|
dataPoolIt = this->data_pool.begin();
|
||||||
|
while( dataPoolIt != this->data_pool.end() ) {
|
||||||
|
debug << std::hex << dataPoolIt->first << std::dec << " |";
|
||||||
|
dataPoolIt->second->print();
|
||||||
|
dataPoolIt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template PoolEntry<uint8_t>* DataPool::getData<uint8_t>( uint32_t data_pool_id, uint8_t size );
|
||||||
|
template PoolEntry<uint16_t>* DataPool::getData<uint16_t>( uint32_t data_pool_id, uint8_t size );
|
||||||
|
template PoolEntry<uint32_t>* DataPool::getData<uint32_t>( uint32_t data_pool_id, uint8_t size );
|
||||||
|
template PoolEntry<uint64_t>* DataPool::getData<uint64_t>(uint32_t data_pool_id,
|
||||||
|
uint8_t size);
|
||||||
|
template PoolEntry<int8_t>* DataPool::getData<int8_t>( uint32_t data_pool_id, uint8_t size );
|
||||||
|
template PoolEntry<int16_t>* DataPool::getData<int16_t>( uint32_t data_pool_id, uint8_t size );
|
||||||
|
template PoolEntry<int32_t>* DataPool::getData<int32_t>( uint32_t data_pool_id, uint8_t size );
|
||||||
|
template PoolEntry<float>* DataPool::getData<float>( uint32_t data_pool_id, uint8_t size );
|
||||||
|
template PoolEntry<double>* DataPool::getData<double>(uint32_t data_pool_id,
|
||||||
|
uint8_t size);
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t DataPool::PIDToDataPoolId(uint32_t parameter_id) {
|
||||||
|
return (parameter_id >> 8) & 0x00FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t DataPool::PIDToArrayIndex(uint32_t parameter_id) {
|
||||||
|
return (parameter_id & 0x000000FF);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t DataPool::poolIdAndPositionToPid(uint32_t poolId, uint8_t index) {
|
||||||
|
return (poolId << 8) + index;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: This is not 100% clean. Should return returnValue and type by passing...
|
||||||
|
//TODO: Do we need a mutex lock here... I don't think so, as we only check static const values of elements in a list that do not change.
|
||||||
|
Type DataPool::getType(uint32_t parameter_id) {
|
||||||
|
std::map<uint32_t, PoolEntryIF*>::iterator it = this->data_pool.find( PIDToDataPoolId(parameter_id));
|
||||||
|
if ( it != this->data_pool.end() ) {
|
||||||
|
return it->second->getType();
|
||||||
|
} else {
|
||||||
|
return Type::UNKNOWN_TYPE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DataPool::exists(uint32_t parameterId) {
|
||||||
|
uint32_t poolId = PIDToDataPoolId(parameterId);
|
||||||
|
uint32_t index = PIDToArrayIndex(parameterId);
|
||||||
|
std::map<uint32_t, PoolEntryIF*>::iterator it = this->data_pool.find( poolId );
|
||||||
|
if (it != data_pool.end()) {
|
||||||
|
if (it->second->getSize() >= index) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
129
datapool/DataPool.h
Normal file
129
datapool/DataPool.h
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
/**
|
||||||
|
* \file DataPool.h
|
||||||
|
*
|
||||||
|
* \date 10/17/2012
|
||||||
|
* \author Bastian Baetz
|
||||||
|
*
|
||||||
|
* \brief This file contains the definition of the DataPool class and (temporarily)
|
||||||
|
* the "extern" definition of the global dataPool instance.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DATAPOOL_H_
|
||||||
|
#define DATAPOOL_H_
|
||||||
|
|
||||||
|
#include <framework/datapool/PoolEntry.h>
|
||||||
|
#include <framework/globalfunctions/Type.h>
|
||||||
|
#include <framework/osal/OSAL.h>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \defgroup data_pool Data Pool
|
||||||
|
* This is the group, where all classes associated with Data Pool Handling belong to.
|
||||||
|
* This includes classes to access Data Pool variables.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DP_SUCCESSFUL 0
|
||||||
|
#define DP_FAILURE 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief This class represents the OBSW global data-pool.
|
||||||
|
*
|
||||||
|
* \details All variables are registered and space is allocated in an initialization
|
||||||
|
* function, which is passed do the constructor.
|
||||||
|
* Space for the variables is allocated on the heap (with a new call).
|
||||||
|
* The data is found by a data pool id, which uniquely represents a variable.
|
||||||
|
* Data pool variables should be used with a blackboard logic in mind,
|
||||||
|
* which means read data is valid (if flagged so), but not necessarily up-to-date.
|
||||||
|
* Variables are either single values or arrays.
|
||||||
|
* \ingroup data_pool
|
||||||
|
*/
|
||||||
|
class DataPool : public HasReturnvaluesIF {
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* \brief This is the actual data pool itself.
|
||||||
|
* \details It is represented by a map
|
||||||
|
* with the data pool id as index and a pointer to a single PoolEntry as value.
|
||||||
|
*/
|
||||||
|
std::map<uint32_t, PoolEntryIF*> data_pool;
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* \brief The mutex is created in the constructor and makes access mutual exclusive.
|
||||||
|
* \details Locking and unlocking the pool is only done by the DataSet class.
|
||||||
|
*/
|
||||||
|
MutexId_t* mutex;
|
||||||
|
/**
|
||||||
|
* \brief In the classes constructor, the passed initialization function is called.
|
||||||
|
* \details To enable filling the pool,
|
||||||
|
* a pointer to the map is passed, allowing direct access to the pool's content.
|
||||||
|
* On runtime, adding or removing variables is forbidden.
|
||||||
|
*/
|
||||||
|
DataPool( void ( *initFunction )( std::map<uint32_t, PoolEntryIF*>* pool_map ) );
|
||||||
|
/**
|
||||||
|
* \brief The destructor iterates through the data_pool map and calls all Entries destructors to clean up the heap.
|
||||||
|
*/
|
||||||
|
~DataPool();
|
||||||
|
/**
|
||||||
|
* \brief This is the default call to access the pool.
|
||||||
|
* \details A pointer to the PoolEntry object is returned.
|
||||||
|
* The call checks data pool id, type and array size. Returns NULL in case of failure.
|
||||||
|
* \param data_pool_id The data pool id to search.
|
||||||
|
* \param sizeOrPosition The array size (not byte size!) of the pool entry, or the position the user wants to read.
|
||||||
|
* If smaller than the entry size, everything's ok.
|
||||||
|
*/
|
||||||
|
template <typename T> PoolEntry<T>* getData( uint32_t data_pool_id, uint8_t sizeOrPosition );
|
||||||
|
/**
|
||||||
|
* \brief An alternative call to get a data pool entry in case the type is not implicitly known
|
||||||
|
* (i.e. in Housekeeping Telemetry).
|
||||||
|
* \details It returns a basic interface and does NOT perform
|
||||||
|
* a size check. The caller has to assure he does not copy too much data.
|
||||||
|
* Returns NULL in case the entry is not found.
|
||||||
|
* \param data_pool_id The data pool id to search.
|
||||||
|
*/
|
||||||
|
PoolEntryIF* getRawData( uint32_t data_pool_id );
|
||||||
|
/**
|
||||||
|
* \brief This is a small helper function to facilitate locking the global data pool.
|
||||||
|
* \details It fetches the pool's mutex id and tries to acquire the mutex.
|
||||||
|
*/
|
||||||
|
ReturnValue_t lockDataPool();
|
||||||
|
/**
|
||||||
|
* \brief This is a small helper function to facilitate unlocking the global data pool.
|
||||||
|
* \details It fetches the pool's mutex id and tries to free the mutex.
|
||||||
|
*/
|
||||||
|
ReturnValue_t freeDataPoolLock();
|
||||||
|
/**
|
||||||
|
* \brief The print call is a simple debug method.
|
||||||
|
* \details It prints the current content of the data pool.
|
||||||
|
* It iterates through the data_pool map and calls each entry's print() method.
|
||||||
|
*/
|
||||||
|
void print();
|
||||||
|
/**
|
||||||
|
* Extracts the data pool id from a SCOS 2000 PID.
|
||||||
|
* @param parameter_id The passed Parameter ID.
|
||||||
|
* @return The data pool id as used within the OBSW.
|
||||||
|
*/
|
||||||
|
static uint32_t PIDToDataPoolId( uint32_t parameter_id );
|
||||||
|
/**
|
||||||
|
* Extracts an array index out of a SCOS 2000 PID.
|
||||||
|
* @param parameter_id The passed Parameter ID.
|
||||||
|
* @return The index of the corresponding data pool entry.
|
||||||
|
*/
|
||||||
|
static uint8_t PIDToArrayIndex( uint32_t parameter_id );
|
||||||
|
/**
|
||||||
|
* Retransforms a data pool id and an array index to a SCOS 2000 PID.
|
||||||
|
*/
|
||||||
|
static uint32_t poolIdAndPositionToPid( uint32_t poolId, uint8_t index );
|
||||||
|
|
||||||
|
Type getType( uint32_t parameter_id );
|
||||||
|
/**
|
||||||
|
* Method to check if a PID exists.
|
||||||
|
* Does not lock, as there's no possibility to alter the list that is checked during run-time.
|
||||||
|
* @param parameterId The PID (not pool id!) of a parameter.
|
||||||
|
* @return true if exists, false else.
|
||||||
|
*/
|
||||||
|
bool exists(uint32_t parameterId);
|
||||||
|
};
|
||||||
|
|
||||||
|
//TODO: Remove this, if data pool is get by Satellite Manager
|
||||||
|
//Better make clean Singleton.
|
||||||
|
extern DataPool dataPool;
|
||||||
|
#endif /* DATAPOOL_H_ */
|
112
datapool/DataPoolAdmin.cpp
Normal file
112
datapool/DataPoolAdmin.cpp
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* DataPoolAdmin.cpp
|
||||||
|
*
|
||||||
|
* Created on: 05.12.2013
|
||||||
|
* Author: baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <framework/datapool/DataPool.h>
|
||||||
|
#include <framework/datapool/DataPoolAdmin.h>
|
||||||
|
#include <framework/datapool/DataSet.h>
|
||||||
|
#include <framework/datapool/PoolRawAccess.h>
|
||||||
|
#include <framework/ipc/CommandMessage.h>
|
||||||
|
|
||||||
|
|
||||||
|
DataPoolAdmin::DataPoolAdmin(object_id_t objectId ) : SystemObject(objectId), commandQueue(), memoryHelper(this, &commandQueue){
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t DataPoolAdmin::performOperation() {
|
||||||
|
handleCommand();
|
||||||
|
return RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageQueueId_t DataPoolAdmin::getCommandQueue() const {
|
||||||
|
return commandQueue.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataPoolAdmin::handleCommand() {
|
||||||
|
CommandMessage command;
|
||||||
|
ReturnValue_t result = commandQueue.receiveMessage(&command);
|
||||||
|
if (result != RETURN_OK) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
result = memoryHelper.handleMemoryCommand(&command);
|
||||||
|
if (result != RETURN_OK) {
|
||||||
|
command.setToUnknownCommand(command.getCommand());
|
||||||
|
commandQueue.reply( &command );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t DataPoolAdmin::handleMemoryLoad(uint32_t address,
|
||||||
|
const uint8_t* data, uint32_t size, uint8_t** dataPointer) {
|
||||||
|
uint32_t poolId = ::dataPool.PIDToDataPoolId( address );
|
||||||
|
uint8_t arrayIndex = ::dataPool.PIDToArrayIndex( address );
|
||||||
|
DataSet testSet;
|
||||||
|
PoolRawAccess varToGetSize( poolId, arrayIndex, &testSet, PoolVariableIF::VAR_READ );
|
||||||
|
ReturnValue_t status = testSet.read();
|
||||||
|
if (status != RETURN_OK) {
|
||||||
|
return INVALID_ADDRESS;
|
||||||
|
}
|
||||||
|
uint8_t typeSize = varToGetSize.getSizeOfType();
|
||||||
|
if ( size > varToGetSize.getSizeTillEnd() ) {
|
||||||
|
return INVALID_SIZE;
|
||||||
|
}
|
||||||
|
const uint8_t* readPosition = data;
|
||||||
|
for ( ; size > 0; size -= typeSize ) {
|
||||||
|
DataSet rawSet;
|
||||||
|
PoolRawAccess variable( poolId, arrayIndex, &rawSet, PoolVariableIF::VAR_READ_WRITE );
|
||||||
|
status = rawSet.read();
|
||||||
|
if (status == RETURN_OK) {
|
||||||
|
status = variable.setEntryFromBigEndian( readPosition, typeSize );
|
||||||
|
if (status == RETURN_OK) {
|
||||||
|
status = rawSet.commit(PoolVariableIF::VALID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
arrayIndex += 1;
|
||||||
|
readPosition += typeSize;
|
||||||
|
}
|
||||||
|
return ACTIVITY_COMPLETED;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t DataPoolAdmin::handleMemoryDump(uint32_t address, uint32_t size,
|
||||||
|
uint8_t** dataPointer, uint8_t* copyHere) {
|
||||||
|
uint32_t poolId = ::dataPool.PIDToDataPoolId( address );
|
||||||
|
uint8_t arrayIndex = ::dataPool.PIDToArrayIndex( address );
|
||||||
|
DataSet testSet;
|
||||||
|
PoolRawAccess varToGetSize( poolId, arrayIndex, &testSet, PoolVariableIF::VAR_READ );
|
||||||
|
ReturnValue_t status = testSet.read();
|
||||||
|
if (status != RETURN_OK) {
|
||||||
|
return INVALID_ADDRESS;
|
||||||
|
}
|
||||||
|
uint8_t typeSize = varToGetSize.getSizeOfType();
|
||||||
|
if ( size > varToGetSize.getSizeTillEnd() ) {
|
||||||
|
return INVALID_SIZE;
|
||||||
|
}
|
||||||
|
uint8_t* ptrToCopy = copyHere;
|
||||||
|
for ( ; size > 0; size -= typeSize ) {
|
||||||
|
DataSet rawSet;
|
||||||
|
PoolRawAccess variable( poolId, arrayIndex, &rawSet, PoolVariableIF::VAR_READ );
|
||||||
|
status = rawSet.read();
|
||||||
|
if (status == RETURN_OK) {
|
||||||
|
uint32_t temp = 0;
|
||||||
|
status = variable.getEntryEndianSafe( ptrToCopy, &temp, size);
|
||||||
|
if ( status != RETURN_OK ) {
|
||||||
|
return RETURN_FAILED;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//Error reading parameter.
|
||||||
|
}
|
||||||
|
arrayIndex += 1;
|
||||||
|
ptrToCopy += typeSize;
|
||||||
|
}
|
||||||
|
return ACTIVITY_COMPLETED;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t DataPoolAdmin::initialize() {
|
||||||
|
if (memoryHelper.initialize() == RETURN_OK) {
|
||||||
|
return SystemObject::initialize();
|
||||||
|
}
|
||||||
|
return RETURN_FAILED;
|
||||||
|
}
|
35
datapool/DataPoolAdmin.h
Normal file
35
datapool/DataPoolAdmin.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* DataPoolAdmin.h
|
||||||
|
*
|
||||||
|
* Created on: 05.12.2013
|
||||||
|
* Author: baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DATAPOOLADMIN_H_
|
||||||
|
#define DATAPOOLADMIN_H_
|
||||||
|
|
||||||
|
#include <framework/ipc/MessageQueue.h>
|
||||||
|
#include <framework/memory/MemoryHelper.h>
|
||||||
|
#include <framework/objectmanager/SystemObject.h>
|
||||||
|
#include <framework/returnvalues/HasReturnvaluesIF.h>
|
||||||
|
#include <framework/tasks/ExecutableObjectIF.h>
|
||||||
|
|
||||||
|
class DataPoolAdmin : public ExecutableObjectIF, public AcceptsMemoryMessagesIF, public HasReturnvaluesIF, public SystemObject {
|
||||||
|
private:
|
||||||
|
MessageQueue commandQueue;
|
||||||
|
MemoryHelper memoryHelper;
|
||||||
|
void handleCommand();
|
||||||
|
public:
|
||||||
|
DataPoolAdmin(object_id_t objectId);
|
||||||
|
|
||||||
|
ReturnValue_t performOperation();
|
||||||
|
|
||||||
|
MessageQueueId_t getCommandQueue() const;
|
||||||
|
|
||||||
|
ReturnValue_t handleMemoryLoad(uint32_t address, const uint8_t* data, uint32_t size, uint8_t** dataPointer);
|
||||||
|
ReturnValue_t handleMemoryDump(uint32_t address, uint32_t size, uint8_t** dataPointer, uint8_t* copyHere );
|
||||||
|
ReturnValue_t initialize();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* DATAPOOLADMIN_H_ */
|
153
datapool/DataSet.cpp
Normal file
153
datapool/DataSet.cpp
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
/*
|
||||||
|
* DataSet.cpp
|
||||||
|
*
|
||||||
|
* Created on: 24.10.2012
|
||||||
|
* Author: baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <framework/datapool/DataSet.h>
|
||||||
|
#include <framework/serviceinterface/ServiceInterfaceStream.h>
|
||||||
|
|
||||||
|
DataSet::DataSet() :
|
||||||
|
fill_count(0), state(DATA_SET_UNINITIALISED) {
|
||||||
|
for (unsigned count = 0; count < DATA_SET_MAX_SIZE; count++) {
|
||||||
|
registeredVariables[count] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DataSet::~DataSet() {
|
||||||
|
//Don't do anything with your variables, they are dead already! (Destructor is already called)
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t DataSet::read() {
|
||||||
|
ReturnValue_t result = RETURN_OK;
|
||||||
|
if (state == DATA_SET_UNINITIALISED) {
|
||||||
|
lockDataPool();
|
||||||
|
for (uint16_t count = 0; count < fill_count; count++) {
|
||||||
|
if (registeredVariables[count]->getReadWriteMode()
|
||||||
|
!= PoolVariableIF::VAR_WRITE
|
||||||
|
&& registeredVariables[count]->getDataPoolId()
|
||||||
|
!= PoolVariableIF::NO_PARAMETER) {
|
||||||
|
ReturnValue_t status = registeredVariables[count]->read();
|
||||||
|
if (status != RETURN_OK) {
|
||||||
|
result = INVALID_PARAMETER_DEFINITION;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state = DATA_SET_WAS_READ;
|
||||||
|
freeDataPoolLock();
|
||||||
|
} else {
|
||||||
|
error << "DataSet::read(): Call made in wrong position." << std::endl;
|
||||||
|
result = SET_WAS_ALREADY_READ;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t DataSet::commit(uint8_t valid) {
|
||||||
|
for (uint16_t count = 0; count < fill_count; count++) {
|
||||||
|
if (registeredVariables[count]->getReadWriteMode()
|
||||||
|
!= PoolVariableIF::VAR_READ) {
|
||||||
|
registeredVariables[count]->setValid(valid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t DataSet::commit() {
|
||||||
|
if (state == DATA_SET_WAS_READ) {
|
||||||
|
lockDataPool();
|
||||||
|
for (uint16_t count = 0; count < fill_count; count++) {
|
||||||
|
if (registeredVariables[count]->getReadWriteMode()
|
||||||
|
!= PoolVariableIF::VAR_READ
|
||||||
|
&& registeredVariables[count]->getDataPoolId()
|
||||||
|
!= PoolVariableIF::NO_PARAMETER) {
|
||||||
|
registeredVariables[count]->commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state = DATA_SET_UNINITIALISED;
|
||||||
|
freeDataPoolLock();
|
||||||
|
return RETURN_OK;
|
||||||
|
} else {
|
||||||
|
ReturnValue_t result = RETURN_OK;
|
||||||
|
lockDataPool();
|
||||||
|
for (uint16_t count = 0; count < fill_count; count++) {
|
||||||
|
if (registeredVariables[count]->getReadWriteMode()
|
||||||
|
== PoolVariableIF::VAR_WRITE
|
||||||
|
&& registeredVariables[count]->getDataPoolId()
|
||||||
|
!= PoolVariableIF::NO_PARAMETER) {
|
||||||
|
registeredVariables[count]->commit();
|
||||||
|
} else if (registeredVariables[count]->getDataPoolId()
|
||||||
|
!= PoolVariableIF::NO_PARAMETER) {
|
||||||
|
if (result != COMMITING_WITHOUT_READING) {
|
||||||
|
error
|
||||||
|
<< "DataSet::commit(): commit-without-read call made with non write-only variable."
|
||||||
|
<< std::endl;
|
||||||
|
result = COMMITING_WITHOUT_READING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state = DATA_SET_UNINITIALISED;
|
||||||
|
freeDataPoolLock();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataSet::registerVariable(PoolVariableIF* variable) {
|
||||||
|
if (state == DATA_SET_UNINITIALISED) {
|
||||||
|
if (variable != NULL) {
|
||||||
|
if (fill_count < DATA_SET_MAX_SIZE) {
|
||||||
|
registeredVariables[fill_count] = variable;
|
||||||
|
fill_count++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
error
|
||||||
|
<< "DataSet::registerVariable: failed. Either NULL, or set is full, or call made in wrong position."
|
||||||
|
<< std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t DataSet::freeDataPoolLock() {
|
||||||
|
return ::dataPool.freeDataPoolLock();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t DataSet::lockDataPool() {
|
||||||
|
return ::dataPool.lockDataPool();
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t DataSet::serialize(uint8_t** buffer, uint32_t* size,
|
||||||
|
const uint32_t max_size, bool bigEndian) const {
|
||||||
|
ReturnValue_t result = RETURN_FAILED;
|
||||||
|
for (uint16_t count = 0; count < fill_count; count++) {
|
||||||
|
result = registeredVariables[count]->serialize(buffer, size, max_size,
|
||||||
|
bigEndian);
|
||||||
|
if (result != RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t DataSet::getSerializedSize() const {
|
||||||
|
uint32_t size = 0;
|
||||||
|
for (uint16_t count = 0; count < fill_count; count++) {
|
||||||
|
size += registeredVariables[count]->getSerializedSize();
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t DataSet::deSerialize(const uint8_t** buffer, int32_t* size,
|
||||||
|
bool bigEndian) {
|
||||||
|
ReturnValue_t result = RETURN_FAILED;
|
||||||
|
for (uint16_t count = 0; count < fill_count; count++) {
|
||||||
|
result = registeredVariables[count]->deSerialize(buffer, size,
|
||||||
|
bigEndian);
|
||||||
|
if (result != RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
152
datapool/DataSet.h
Normal file
152
datapool/DataSet.h
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
* \file DataSet.h
|
||||||
|
*
|
||||||
|
* \brief This file contains the DataSet class and a small structure called DataSetContent.
|
||||||
|
*
|
||||||
|
* \date 10/17/2012
|
||||||
|
*
|
||||||
|
* \author Bastian Baetz
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DATASET_H_
|
||||||
|
#define DATASET_H_
|
||||||
|
|
||||||
|
#include <framework/datapool/DataPool.h>
|
||||||
|
#include <framework/datapool/DataSetIF.h>
|
||||||
|
#include <framework/datapool/PoolRawAccess.h>
|
||||||
|
#include <framework/datapool/PoolVariable.h>
|
||||||
|
#include <framework/datapool/PoolVarList.h>
|
||||||
|
#include <framework/datapool/PoolVector.h>
|
||||||
|
#include <framework/serialize/SerializeAdapter.h>
|
||||||
|
/**
|
||||||
|
* \brief The DataSet class manages a set of locally checked out variables.
|
||||||
|
*
|
||||||
|
* \details This class manages a list, where a set of local variables (or pool variables) are
|
||||||
|
* registered. They are checked-out (i.e. their values are looked up and copied)
|
||||||
|
* with the read call. After the user finishes working with the pool variables,
|
||||||
|
* he can write back all variable values to the pool with the commit call.
|
||||||
|
* The data set manages locking and freeing the data pool, to ensure that all values
|
||||||
|
* are read and written back at once.
|
||||||
|
* An internal state manages usage of this class. Variables may only be registered before
|
||||||
|
* the read call is made, and the commit call only after the read call.
|
||||||
|
* If pool variables are writable and not committed until destruction of the set, the
|
||||||
|
* DataSet class automatically sets the valid flag in the data pool to invalid (without)
|
||||||
|
* changing the variable's value.
|
||||||
|
*
|
||||||
|
* \ingroup data_pool
|
||||||
|
*/
|
||||||
|
class DataSet: public DataSetIF, public HasReturnvaluesIF, public SerializeIF {
|
||||||
|
private:
|
||||||
|
//TODO we could use a linked list of datapool variables
|
||||||
|
static const uint8_t DATA_SET_MAX_SIZE = 63; //!< This definition sets the maximum number of variables to register in one DataSet.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief This array represents all pool variables registered in this set.
|
||||||
|
* \details It has a maximum size of DATA_SET_MAX_SIZE.
|
||||||
|
*/
|
||||||
|
PoolVariableIF* registeredVariables[DATA_SET_MAX_SIZE];
|
||||||
|
/**
|
||||||
|
* \brief The fill_count attribute ensures that the variables register in the correct array
|
||||||
|
* position and that the maximum number of variables is not exceeded.
|
||||||
|
*/
|
||||||
|
uint16_t fill_count;
|
||||||
|
/**
|
||||||
|
* States of the seet.
|
||||||
|
*/
|
||||||
|
enum States {
|
||||||
|
DATA_SET_UNINITIALISED, //!< DATA_SET_UNINITIALISED
|
||||||
|
DATA_SET_WAS_READ //!< DATA_SET_WAS_READ
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* \brief state manages the internal state of the data set, which is important e.g. for the
|
||||||
|
* behavior on destruction.
|
||||||
|
*/
|
||||||
|
States state;
|
||||||
|
/**
|
||||||
|
* \brief This is a small helper function to facilitate locking the global data pool.
|
||||||
|
* \details It makes use of the lockDataPool method offered by the DataPool class.
|
||||||
|
*/
|
||||||
|
uint8_t lockDataPool();
|
||||||
|
/**
|
||||||
|
* \brief This is a small helper function to facilitate unlocking the global data pool.
|
||||||
|
* \details It makes use of the freeDataPoolLock method offered by the DataPool class.
|
||||||
|
*/
|
||||||
|
uint8_t freeDataPoolLock();
|
||||||
|
|
||||||
|
public:
|
||||||
|
static const uint8_t INTERFACE_ID = DATA_SET_CLASS;
|
||||||
|
static const ReturnValue_t INVALID_PARAMETER_DEFINITION =
|
||||||
|
MAKE_RETURN_CODE( 0x01 );
|
||||||
|
static const ReturnValue_t SET_WAS_ALREADY_READ = MAKE_RETURN_CODE( 0x02 );
|
||||||
|
static const ReturnValue_t COMMITING_WITHOUT_READING =
|
||||||
|
MAKE_RETURN_CODE(0x03);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief The constructor simply sets the fill_count to zero and sets the state to "uninitialized".
|
||||||
|
*/
|
||||||
|
DataSet();
|
||||||
|
/**
|
||||||
|
* \brief The destructor automatically manages writing the valid information of variables.
|
||||||
|
* \details In case the data set was read out, but not committed (indicated by state),
|
||||||
|
* the destructor parses all variables that are still registered to the set.
|
||||||
|
* For each, the valid flag in the data pool is set to "invalid".
|
||||||
|
*/
|
||||||
|
~DataSet();
|
||||||
|
/**
|
||||||
|
* \brief The read call initializes reading out all registered variables.
|
||||||
|
* \details It iterates through the list of registered variables and calls all read()
|
||||||
|
* functions of the registered pool variables (which read out their values from the
|
||||||
|
* data pool) which are not write-only. In case of an error (e.g. a wrong data type,
|
||||||
|
* or an invalid data pool id), the operation is aborted and
|
||||||
|
* \c INVALID_PARAMETER_DEFINITION returned.
|
||||||
|
* The data pool is locked during the whole read operation and freed afterwards.
|
||||||
|
* The state changes to "was written" after this operation.
|
||||||
|
* \return - \c RETURN_OK if all variables were read successfully.
|
||||||
|
* - \c INVALID_PARAMETER_DEFINITION if PID, size or type of the
|
||||||
|
* requested variable is invalid.
|
||||||
|
* - \c SET_WAS_ALREADY_READ if read() is called twice without calling
|
||||||
|
* commit() in between
|
||||||
|
*/
|
||||||
|
ReturnValue_t read();
|
||||||
|
/**
|
||||||
|
* \brief The commit call initializes writing back the registered variables.
|
||||||
|
* \details It iterates through the list of registered variables and calls
|
||||||
|
* the commit() method of the remaining registered variables (which write back
|
||||||
|
* their values to the pool).
|
||||||
|
* The data pool is locked during the whole commit operation and freed afterwards.
|
||||||
|
* The state changes to "was committed" after this operation.
|
||||||
|
* If the set does contain at least one variable which is not write-only commit()
|
||||||
|
* can only be called after read(). If the set only contains variables which are
|
||||||
|
* write only, commit() can be called without a preceding read() call.
|
||||||
|
* \return - \c RETURN_OK if all variables were read successfully.
|
||||||
|
* - \c COMMITING_WITHOUT_READING if set was not read yet and contains non write-only
|
||||||
|
* variables
|
||||||
|
*/
|
||||||
|
ReturnValue_t commit(void);
|
||||||
|
/**
|
||||||
|
* Variant of method above which sets validity of all elements of the set.
|
||||||
|
* @param valid Validity information from PoolVariableIF.
|
||||||
|
* \return - \c RETURN_OK if all variables were read successfully.
|
||||||
|
* - \c COMMITING_WITHOUT_READING if set was not read yet and contains non write-only
|
||||||
|
* variables
|
||||||
|
*/
|
||||||
|
ReturnValue_t commit(uint8_t valid);
|
||||||
|
/**
|
||||||
|
* \brief This operation is used to register the local variables in the set.
|
||||||
|
* \details It copies all required information to the currently
|
||||||
|
* free space in the registeredVariables list.
|
||||||
|
*/
|
||||||
|
void registerVariable(PoolVariableIF* variable);
|
||||||
|
|
||||||
|
ReturnValue_t serialize(uint8_t** buffer, uint32_t* size,
|
||||||
|
const uint32_t max_size, bool bigEndian) const;
|
||||||
|
|
||||||
|
uint32_t getSerializedSize() const;
|
||||||
|
|
||||||
|
ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size,
|
||||||
|
bool bigEndian);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DATASET_H_ */
|
42
datapool/DataSetIF.h
Normal file
42
datapool/DataSetIF.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/**
|
||||||
|
* \file DataSetIF.h
|
||||||
|
*
|
||||||
|
* \brief This file contains the small interface to access the DataSet class.
|
||||||
|
*
|
||||||
|
* \date 10/23/2012
|
||||||
|
*
|
||||||
|
* \author Bastian Baetz
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DATASETIF_H_
|
||||||
|
#define DATASETIF_H_
|
||||||
|
|
||||||
|
|
||||||
|
#include <framework/osal/OSAL.h>
|
||||||
|
|
||||||
|
class PoolVariableIF;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief This class defines a small interface to register on a DataSet.
|
||||||
|
*
|
||||||
|
* \details Currently, the only purpose of this interface is to provide a method for locally
|
||||||
|
* checked-out variables to register on a data set. Still, it may become useful for
|
||||||
|
* other purposes as well.
|
||||||
|
*
|
||||||
|
* \ingroup data_pool
|
||||||
|
*/
|
||||||
|
class DataSetIF {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* \brief This is an empty virtual destructor, as it is proposed for C++ interfaces.
|
||||||
|
*/
|
||||||
|
virtual ~DataSetIF() {}
|
||||||
|
/**
|
||||||
|
* \brief This operation provides a method to register local data pool variables
|
||||||
|
* to register in a data set by passing itself to this DataSet operation.
|
||||||
|
*/
|
||||||
|
virtual void registerVariable( PoolVariableIF* variable ) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DATASETIF_H_ */
|
25
datapool/Makefile
Executable file
25
datapool/Makefile
Executable file
@ -0,0 +1,25 @@
|
|||||||
|
#!/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)/OPUSDataPool.o \
|
||||||
|
$(BUILDDIR)/OPUSDataPoolItem.o \
|
||||||
|
$(BUILDDIR)/OPUSDataSet.o \
|
||||||
|
$(BUILDDIR)/OPUSRegVar.o
|
||||||
|
|
||||||
|
all: $(OBJ)
|
||||||
|
|
||||||
|
$(BUILDDIR)/%.o: %.cpp %.h
|
||||||
|
$(CPP) $(CFLAGS) $(DEFINES) $(CCOPT) ${INCLUDE} -c $< -o $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) *.o *.gcno *.gcda
|
152
datapool/PIDReader.h
Normal file
152
datapool/PIDReader.h
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
* PIDReader.h
|
||||||
|
*
|
||||||
|
* Created on: 14.05.2014
|
||||||
|
* Author: baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PIDREADER_H_
|
||||||
|
#define PIDREADER_H_
|
||||||
|
#include <framework/datapool/DataPool.h>
|
||||||
|
#include <framework/datapool/DataSetIF.h>
|
||||||
|
#include <framework/datapool/PoolEntry.h>
|
||||||
|
#include <framework/datapool/PoolVariableIF.h>
|
||||||
|
#include <framework/serialize/SerializeAdapter.h>
|
||||||
|
#include <framework/serviceinterface/ServiceInterfaceStream.h>
|
||||||
|
|
||||||
|
template<typename U, uint8_t n_var> class PIDReaderList;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class PIDReader: public PoolVariableIF {
|
||||||
|
template<typename U, uint8_t n_var> friend class PIDReaderList;
|
||||||
|
protected:
|
||||||
|
uint32_t parameterId;
|
||||||
|
uint8_t valid;
|
||||||
|
ReturnValue_t read() {
|
||||||
|
uint8_t arrayIndex = DataPool::PIDToArrayIndex(parameterId);
|
||||||
|
PoolEntry<T>* read_out = ::dataPool.getData<T>(
|
||||||
|
DataPool::PIDToDataPoolId(parameterId), arrayIndex);
|
||||||
|
if (read_out != NULL) {
|
||||||
|
valid = read_out->valid;
|
||||||
|
value = read_out->address[arrayIndex];
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
} else {
|
||||||
|
value = 0;
|
||||||
|
valid = false;
|
||||||
|
error << "PIDReader: read of PID 0x" << std::hex << parameterId
|
||||||
|
<< std::dec << " failed." << std::endl;
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Never commit, is read-only.
|
||||||
|
* Reason is the possibility to access a single DP vector element, but if we commit,
|
||||||
|
* we set validity of the whole vector.
|
||||||
|
*/
|
||||||
|
ReturnValue_t commit() {
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Empty ctor for List initialization
|
||||||
|
*/
|
||||||
|
PIDReader() :
|
||||||
|
parameterId(PoolVariableIF::NO_PARAMETER), valid(PoolVariableIF::INVALID), value(0) {
|
||||||
|
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* \brief This is the local copy of the data pool entry.
|
||||||
|
*/
|
||||||
|
T value;
|
||||||
|
/**
|
||||||
|
* \brief In the constructor, the variable can register itself in a DataSet (if not NULL is
|
||||||
|
* passed).
|
||||||
|
* \details It DOES NOT fetch the current value from the data pool, but sets the value
|
||||||
|
* attribute to default (0). The value is fetched within the read() operation.
|
||||||
|
* \param set_id This is the id in the global data pool this instance of the access class
|
||||||
|
* corresponds to.
|
||||||
|
* \param dataSet The data set in which the variable shall register itself. If NULL,
|
||||||
|
* the variable is not registered.
|
||||||
|
* \param setWritable If this flag is set to true, changes in the value attribute can be
|
||||||
|
* written back to the data pool, otherwise not.
|
||||||
|
*/
|
||||||
|
PIDReader(uint32_t setParameterId, DataSetIF* dataSet) :
|
||||||
|
parameterId(setParameterId), valid(
|
||||||
|
PoolVariableIF::INVALID), value(0) {
|
||||||
|
if (dataSet != NULL) {
|
||||||
|
dataSet->registerVariable(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy ctor to copy classes containing Pool Variables.
|
||||||
|
*/
|
||||||
|
PIDReader(const PIDReader& rhs) :
|
||||||
|
parameterId(rhs.parameterId), valid(rhs.valid), value(rhs.value) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief The classes destructor is empty.
|
||||||
|
*/
|
||||||
|
~PIDReader() {
|
||||||
|
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* \brief This operation returns the data pool id of the variable.
|
||||||
|
*/
|
||||||
|
uint32_t getDataPoolId() const {
|
||||||
|
return DataPool::PIDToDataPoolId(parameterId);
|
||||||
|
}
|
||||||
|
uint32_t getParameterId() const {
|
||||||
|
return parameterId;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This method returns if the variable is write-only, read-write or read-only.
|
||||||
|
*/
|
||||||
|
ReadWriteMode_t getReadWriteMode() const {
|
||||||
|
return VAR_READ;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* \brief With this call, the valid information of the variable is returned.
|
||||||
|
*/
|
||||||
|
bool isValid() const {
|
||||||
|
if (valid)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t getValid() {
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setValid(uint8_t valid) {
|
||||||
|
this->valid = valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
operator T() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
PIDReader<T> &operator=(T newValue) {
|
||||||
|
value = newValue;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ReturnValue_t serialize(uint8_t** buffer, uint32_t* size,
|
||||||
|
const uint32_t max_size, bool bigEndian) const {
|
||||||
|
return SerializeAdapter<T>::serialize(&value, buffer, size, max_size,
|
||||||
|
bigEndian);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual uint32_t getSerializedSize() const {
|
||||||
|
return SerializeAdapter<T>::getSerializedSize(&value);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size,
|
||||||
|
bool bigEndian) {
|
||||||
|
return SerializeAdapter<T>::deSerialize(&value, buffer, size, bigEndian);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* PIDREADER_H_ */
|
34
datapool/PIDReaderList.h
Normal file
34
datapool/PIDReaderList.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* PIDReaderList.h
|
||||||
|
*
|
||||||
|
* Created on: 15.07.2015
|
||||||
|
* Author: baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FRAMEWORK_DATAPOOL_PIDREADERLIST_H_
|
||||||
|
#define FRAMEWORK_DATAPOOL_PIDREADERLIST_H_
|
||||||
|
|
||||||
|
#include <framework/datapool/PIDReader.h>
|
||||||
|
#include <framework/datapool/PoolVariableIF.h>
|
||||||
|
template <class T, uint8_t n_var>
|
||||||
|
class PIDReaderList {
|
||||||
|
private:
|
||||||
|
PIDReader<T> variables[n_var];
|
||||||
|
public:
|
||||||
|
PIDReaderList( const uint32_t setPid[n_var], DataSetIF* dataSet) {
|
||||||
|
//I really should have a look at the new init list c++ syntax.
|
||||||
|
if (dataSet == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (uint8_t count = 0; count < n_var; count++) {
|
||||||
|
variables[count].parameterId = setPid[count];
|
||||||
|
dataSet->registerVariable(&variables[count]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PIDReader<T> &operator [](int i) { return variables[i]; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* FRAMEWORK_DATAPOOL_PIDREADERLIST_H_ */
|
73
datapool/PoolEntry.cpp
Normal file
73
datapool/PoolEntry.cpp
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* PoolEntry.cpp
|
||||||
|
*
|
||||||
|
* Created on: Oct 25, 2012
|
||||||
|
* Author: baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <framework/datapool/PoolEntry.h>
|
||||||
|
#include <framework/serviceinterface/ServiceInterfaceStream.h>
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
PoolEntry<T>::PoolEntry( T* initValue, uint8_t set_length, uint8_t set_valid ) : length(set_length), valid(set_valid) {
|
||||||
|
this->address = new T[this->length];
|
||||||
|
if (initValue != NULL) {
|
||||||
|
memcpy(this->address, initValue, this->getByteSize() );
|
||||||
|
} else {
|
||||||
|
memset(this->address, 0, this->getByteSize() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//As the data pool is global, this dtor is only be called on program exit.
|
||||||
|
//Warning! Never copy pool entries!
|
||||||
|
template <typename T>
|
||||||
|
PoolEntry<T>::~PoolEntry() {
|
||||||
|
delete[] this->address;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
uint16_t PoolEntry<T>::getByteSize() {
|
||||||
|
return ( sizeof(T) * this->length );
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
uint8_t PoolEntry<T>::getSize() {
|
||||||
|
return this->length;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void* PoolEntry<T>::getRawData() {
|
||||||
|
return this->address;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void PoolEntry<T>::setValid( uint8_t isValid ) {
|
||||||
|
this->valid = isValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
uint8_t PoolEntry<T>::getValid() {
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void PoolEntry<T>::print() {
|
||||||
|
for (uint8_t size = 0; size < this->length; size++ ) {
|
||||||
|
debug << "| " << std::hex << (double)this->address[size] << (this->valid? " (valid) " : " (invalid) ");
|
||||||
|
}
|
||||||
|
debug << std::dec << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
Type PoolEntry<T>::getType() {
|
||||||
|
return PodTypeConversion<T>::type;
|
||||||
|
}
|
||||||
|
|
||||||
|
template class PoolEntry<uint8_t>;
|
||||||
|
template class PoolEntry<uint16_t>;
|
||||||
|
template class PoolEntry<uint32_t>;
|
||||||
|
template class PoolEntry<int8_t>;
|
||||||
|
template class PoolEntry<int16_t>;
|
||||||
|
template class PoolEntry<int32_t>;
|
||||||
|
template class PoolEntry<float>;
|
||||||
|
template class PoolEntry<double>;
|
84
datapool/PoolEntry.h
Normal file
84
datapool/PoolEntry.h
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
#ifndef POOLENTRY_H_
|
||||||
|
#define POOLENTRY_H_
|
||||||
|
|
||||||
|
|
||||||
|
#include <framework/datapool/PoolEntryIF.h>
|
||||||
|
#include <framework/osal/OSAL.h>
|
||||||
|
/**
|
||||||
|
* \brief This is a small helper class that defines a single data pool entry.
|
||||||
|
*
|
||||||
|
* \details The helper is used to store all information together with the data as a single data pool entry.
|
||||||
|
* The content's type is defined by the template argument.
|
||||||
|
* It is prepared for use with plain old data types,
|
||||||
|
* but may be extended to complex types if necessary.
|
||||||
|
* It can be initialized with a certain value, size and validity flag.
|
||||||
|
* It holds a pointer to the real data and offers methods to access this data and to acquire
|
||||||
|
* additional information (such as validity and array/byte size).
|
||||||
|
* It is NOT intended to be used outside the DataPool class.
|
||||||
|
*
|
||||||
|
* \ingroup data_pool
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
class PoolEntry : public PoolEntryIF {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* \brief In the classe's constructor, space is allocated on the heap and
|
||||||
|
* potential init values are copied to that space.
|
||||||
|
* \param initValue A pointer to the single value or array that holds the init value.
|
||||||
|
* With the default value (NULL), the entry is initalized with all 0.
|
||||||
|
* \param set_length Defines the array length of this entry.
|
||||||
|
* \param set_valid Sets the initialization flag. It is invalid (0) by default.
|
||||||
|
*/
|
||||||
|
PoolEntry( T* initValue = NULL, uint8_t set_length = 1, uint8_t set_valid = 0 );
|
||||||
|
/**
|
||||||
|
* \brief The allocated memory for the variable is freed in the destructor.
|
||||||
|
* \details As the data pool is global, this dtor is only called on program exit.
|
||||||
|
* PoolEntries shall never be copied, as a copy might delete the variable on the heap.
|
||||||
|
*/
|
||||||
|
~PoolEntry();
|
||||||
|
/**
|
||||||
|
* \brief This is the address pointing to the allocated memory.
|
||||||
|
*/
|
||||||
|
T* address;
|
||||||
|
/**
|
||||||
|
* \brief This attribute stores the length information.
|
||||||
|
*/
|
||||||
|
uint8_t length;
|
||||||
|
/**
|
||||||
|
* \brief Here, the validity information for a variable is stored.
|
||||||
|
* Every entry (single variable or vector) has one valid flag.
|
||||||
|
*/
|
||||||
|
uint8_t valid;
|
||||||
|
/**
|
||||||
|
* \brief getSize returns the array size of the entry.
|
||||||
|
* \details A single parameter has size 1.
|
||||||
|
*/
|
||||||
|
uint8_t getSize();
|
||||||
|
/**
|
||||||
|
* \brief This operation returns the size in bytes.
|
||||||
|
* \details The size is calculated by sizeof(type) * array_size.
|
||||||
|
*/
|
||||||
|
uint16_t getByteSize();
|
||||||
|
/**
|
||||||
|
* \brief This operation returns a the address pointer casted to void*.
|
||||||
|
*/
|
||||||
|
void* getRawData();
|
||||||
|
/**
|
||||||
|
* \brief This method allows to set the valid information of the pool entry.
|
||||||
|
*/
|
||||||
|
void setValid( uint8_t isValid );
|
||||||
|
/**
|
||||||
|
* \brief This method allows to get the valid information of the pool entry.
|
||||||
|
*/
|
||||||
|
uint8_t getValid();
|
||||||
|
/**
|
||||||
|
* \brief This is a debug method that prints all values and the valid information to the screen.
|
||||||
|
* It prints all array entries in a row.
|
||||||
|
*/
|
||||||
|
void print();
|
||||||
|
|
||||||
|
Type getType();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* POOLENTRY_H_ */
|
67
datapool/PoolEntryIF.h
Normal file
67
datapool/PoolEntryIF.h
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
/**
|
||||||
|
* \file PoolEntryIF.h
|
||||||
|
*
|
||||||
|
* \brief This file holds the class that defines the Interface for Pool Entry elements.
|
||||||
|
*
|
||||||
|
* \date 10/18/2012
|
||||||
|
*
|
||||||
|
* \author Bastian Baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef POOLENTRYIF_H_
|
||||||
|
#define POOLENTRYIF_H_
|
||||||
|
|
||||||
|
#include <framework/globalfunctions/Type.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief This interface defines the access possibilities to a single data pool entry.
|
||||||
|
*
|
||||||
|
* \details The interface provides methods to determine the size and the validity information of a value.
|
||||||
|
* It also defines a method to receive a pointer to the raw data content.
|
||||||
|
* It is mainly used by DataPool itself, but also as a return pointer.
|
||||||
|
*
|
||||||
|
* \ingroup data_pool
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class PoolEntryIF {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* \brief This is an empty virtual destructor, as it is proposed for C++ interfaces.
|
||||||
|
*/
|
||||||
|
virtual ~PoolEntryIF() {
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* \brief getSize returns the array size of the entry. A single variable parameter has size 1.
|
||||||
|
*/
|
||||||
|
virtual uint8_t getSize() = 0;
|
||||||
|
/**
|
||||||
|
* \brief This operation returns the size in bytes, which is calculated by
|
||||||
|
* sizeof(type) * array_size.
|
||||||
|
*/
|
||||||
|
virtual uint16_t getByteSize() = 0;
|
||||||
|
/**
|
||||||
|
* \brief This operation returns a the address pointer casted to void*.
|
||||||
|
*/
|
||||||
|
virtual void* getRawData() = 0;
|
||||||
|
/**
|
||||||
|
* \brief This method allows to set the valid information of the pool entry.
|
||||||
|
*/
|
||||||
|
virtual void setValid(uint8_t isValid) = 0;
|
||||||
|
/**
|
||||||
|
* \brief This method allows to set the valid information of the pool entry.
|
||||||
|
*/
|
||||||
|
virtual uint8_t getValid() = 0;
|
||||||
|
/**
|
||||||
|
* \brief This is a debug method that prints all values and the valid information to the screen.
|
||||||
|
* It prints all array entries in a row.
|
||||||
|
*/
|
||||||
|
virtual void print() = 0;
|
||||||
|
/**
|
||||||
|
* Returns the type of the entry.
|
||||||
|
*/
|
||||||
|
virtual Type getType() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* POOLENTRYIF_H_ */
|
194
datapool/PoolRawAccess.cpp
Normal file
194
datapool/PoolRawAccess.cpp
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
/*
|
||||||
|
* PoolRawAccess.cpp
|
||||||
|
*
|
||||||
|
* Created on: 29.10.2012
|
||||||
|
* Author: baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <framework/datapool/DataPool.h>
|
||||||
|
#include <framework/datapool/PoolEntryIF.h>
|
||||||
|
#include <framework/datapool/PoolRawAccess.h>
|
||||||
|
#include <framework/serviceinterface/ServiceInterfaceStream.h>
|
||||||
|
PoolRawAccess::PoolRawAccess(uint32_t set_id, uint8_t setArrayEntry,
|
||||||
|
DataSetIF* data_set, ReadWriteMode_t setReadWriteMode) :
|
||||||
|
dataPoolId(set_id), arrayEntry(setArrayEntry), valid(false), typeSize(
|
||||||
|
0), sizeTillEnd(0), readWriteMode(setReadWriteMode) {
|
||||||
|
memset(value, 0, sizeof(value));
|
||||||
|
if (data_set != NULL) {
|
||||||
|
data_set->registerVariable(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PoolRawAccess::~PoolRawAccess() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t PoolRawAccess::read() {
|
||||||
|
PoolEntryIF* read_out = ::dataPool.getRawData(dataPoolId);
|
||||||
|
if (read_out != NULL) {
|
||||||
|
valid = read_out->getValid();
|
||||||
|
if (read_out->getSize() > arrayEntry) {
|
||||||
|
typeSize = read_out->getByteSize() / read_out->getSize();
|
||||||
|
if (typeSize <= sizeof(value)) {
|
||||||
|
uint16_t arrayPosition = arrayEntry * typeSize;
|
||||||
|
sizeTillEnd = read_out->getByteSize() - arrayPosition;
|
||||||
|
uint8_t* ptr =
|
||||||
|
&((uint8_t*) read_out->getRawData())[arrayPosition];
|
||||||
|
memcpy(value, ptr, typeSize);
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
} else {
|
||||||
|
//Error value type too large.
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//Error index requested too large
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//Error entry does not exist.
|
||||||
|
}
|
||||||
|
error << "PoolRawAccess: read of DP Variable 0x" << std::hex << dataPoolId
|
||||||
|
<< std::dec << " failed." << std::endl;
|
||||||
|
valid = INVALID;
|
||||||
|
typeSize = 0;
|
||||||
|
sizeTillEnd = 0;
|
||||||
|
memset(value, 0, sizeof(value));
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t PoolRawAccess::commit() {
|
||||||
|
PoolEntryIF* write_back = ::dataPool.getRawData(dataPoolId);
|
||||||
|
if ((write_back != NULL) && (readWriteMode != VAR_READ)) {
|
||||||
|
write_back->setValid(valid);
|
||||||
|
uint8_t array_position = arrayEntry * typeSize;
|
||||||
|
uint8_t* ptr = &((uint8_t*) write_back->getRawData())[array_position];
|
||||||
|
memcpy(ptr, value, typeSize);
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
} else {
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* PoolRawAccess::getEntry() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t PoolRawAccess::getEntryEndianSafe(uint8_t* buffer,
|
||||||
|
uint32_t* writtenBytes, uint32_t max_size) {
|
||||||
|
uint8_t* data_ptr = getEntry();
|
||||||
|
// debug << "PoolRawAccess::getEntry: Array position: " << index * size_of_type << " Size of T: " << (int)size_of_type << " ByteSize: " << byte_size << " Position: " << *size << std::endl;
|
||||||
|
if (typeSize == 0)
|
||||||
|
return DATA_POOL_ACCESS_FAILED;
|
||||||
|
if (typeSize > max_size)
|
||||||
|
return INCORRECT_SIZE;
|
||||||
|
#ifndef BYTE_ORDER
|
||||||
|
#error BYTE_ORDER not defined
|
||||||
|
#elif BYTE_ORDER == LITTLE_ENDIAN
|
||||||
|
for (uint8_t count = 0; count < typeSize; count++) {
|
||||||
|
buffer[count] = data_ptr[typeSize - count - 1];
|
||||||
|
}
|
||||||
|
#elif BYTE_ORDER == BIG_ENDIAN
|
||||||
|
memcpy(buffer, data_ptr, typeSize);
|
||||||
|
#endif
|
||||||
|
*writtenBytes = typeSize;
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t PoolRawAccess::getSizeOfType() {
|
||||||
|
return typeSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t PoolRawAccess::getDataPoolId() const {
|
||||||
|
return dataPoolId;
|
||||||
|
}
|
||||||
|
|
||||||
|
PoolVariableIF::ReadWriteMode_t PoolRawAccess::getReadWriteMode() const {
|
||||||
|
return readWriteMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t PoolRawAccess::setEntryFromBigEndian(const uint8_t* buffer,
|
||||||
|
uint32_t setSize) {
|
||||||
|
if (typeSize == setSize) {
|
||||||
|
#ifndef BYTE_ORDER
|
||||||
|
#error BYTE_ORDER not defined
|
||||||
|
#elif BYTE_ORDER == LITTLE_ENDIAN
|
||||||
|
for (uint8_t count = 0; count < typeSize; count++) {
|
||||||
|
value[count] = buffer[typeSize - count - 1];
|
||||||
|
}
|
||||||
|
#elif BYTE_ORDER == BIG_ENDIAN
|
||||||
|
memcpy(value, buffer, typeSize);
|
||||||
|
#endif
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
} else {
|
||||||
|
error << "PoolRawAccess::setEntryFromBigEndian: Illegal sizes: Internal"
|
||||||
|
<< (uint32_t) typeSize << ", Requested: " << setSize
|
||||||
|
<< std::endl;
|
||||||
|
return INCORRECT_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PoolRawAccess::isValid() const {
|
||||||
|
if (valid != INVALID)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PoolRawAccess::setValid(uint8_t valid) {
|
||||||
|
this->valid = valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t PoolRawAccess::getSizeTillEnd() const {
|
||||||
|
return sizeTillEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t PoolRawAccess::serialize(uint8_t** buffer, uint32_t* size,
|
||||||
|
const uint32_t max_size, bool bigEndian) const {
|
||||||
|
if (typeSize + *size <= max_size) {
|
||||||
|
if (bigEndian) {
|
||||||
|
#ifndef BYTE_ORDER
|
||||||
|
#error BYTE_ORDER not defined
|
||||||
|
#elif BYTE_ORDER == LITTLE_ENDIAN
|
||||||
|
for (uint8_t count = 0; count < typeSize; count++) {
|
||||||
|
(*buffer)[count] = value[typeSize - count - 1];
|
||||||
|
}
|
||||||
|
#elif BYTE_ORDER == BIG_ENDIAN
|
||||||
|
memcpy(*buffer, value, typeSize);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
memcpy(*buffer, value, typeSize);
|
||||||
|
}
|
||||||
|
*size += typeSize;
|
||||||
|
(*buffer) += typeSize;
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
} else {
|
||||||
|
return SerializeIF::BUFFER_TOO_SHORT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t PoolRawAccess::getSerializedSize() const {
|
||||||
|
return typeSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t PoolRawAccess::deSerialize(const uint8_t** buffer, int32_t* size,
|
||||||
|
bool bigEndian) {
|
||||||
|
*size -= typeSize;
|
||||||
|
if (*size >= 0) {
|
||||||
|
|
||||||
|
if (bigEndian) {
|
||||||
|
#ifndef BYTE_ORDER
|
||||||
|
#error BYTE_ORDER not defined
|
||||||
|
#elif BYTE_ORDER == LITTLE_ENDIAN
|
||||||
|
for (uint8_t count = 0; count < typeSize; count++) {
|
||||||
|
value[count] = (*buffer)[typeSize - count - 1];
|
||||||
|
}
|
||||||
|
#elif BYTE_ORDER == BIG_ENDIAN
|
||||||
|
memcpy(value, *buffer, typeSize);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
memcpy(value, *buffer, typeSize);
|
||||||
|
}
|
||||||
|
*buffer += typeSize;
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
} else {
|
||||||
|
return SerializeIF::STREAM_TOO_SHORT;
|
||||||
|
}
|
||||||
|
}
|
135
datapool/PoolRawAccess.h
Normal file
135
datapool/PoolRawAccess.h
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
#ifndef POOLRAWACCESS_H_
|
||||||
|
#define POOLRAWACCESS_H_
|
||||||
|
|
||||||
|
#include <framework/datapool/DataSetIF.h>
|
||||||
|
#include <framework/datapool/PoolVariableIF.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class allows accessing Data Pool variables as raw bytes.
|
||||||
|
* This is necessary to have an access method for HK data, as the PID's alone do not
|
||||||
|
* provide a type information.
|
||||||
|
* \ingroup data_pool
|
||||||
|
*/
|
||||||
|
class PoolRawAccess: public PoolVariableIF {
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* \brief To access the correct data pool entry on read and commit calls, the data pool id
|
||||||
|
* is stored.
|
||||||
|
*/
|
||||||
|
uint32_t dataPoolId;
|
||||||
|
/**
|
||||||
|
* \brief The array entry that is fetched from the data pool.
|
||||||
|
*/
|
||||||
|
uint8_t arrayEntry;
|
||||||
|
/**
|
||||||
|
* \brief The valid information as it was stored in the data pool is copied to this attribute.
|
||||||
|
*/
|
||||||
|
uint8_t valid;
|
||||||
|
/**
|
||||||
|
* \brief This value contains the size of the data pool entry in bytes.
|
||||||
|
*/
|
||||||
|
uint8_t typeSize;
|
||||||
|
/**
|
||||||
|
* The size (in bytes) from the selected entry till the end of this DataPool variable.
|
||||||
|
*/
|
||||||
|
uint16_t sizeTillEnd;
|
||||||
|
/**
|
||||||
|
* \brief The information whether the class is read-write or read-only is stored here.
|
||||||
|
*/
|
||||||
|
ReadWriteMode_t readWriteMode;
|
||||||
|
static const uint8_t RAW_MAX_SIZE = sizeof(double);
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* \brief This is a call to read the value from the global data pool.
|
||||||
|
* \details When executed, this operation tries to fetch the pool entry with matching
|
||||||
|
* data pool id from the global data pool and copies the value and the valid
|
||||||
|
* information to its local attributes. In case of a failure (wrong type or
|
||||||
|
* pool id not found), the variable is set to zero and invalid.
|
||||||
|
* The operation does NOT provide any mutual exclusive protection by itself.
|
||||||
|
*/
|
||||||
|
ReturnValue_t read();
|
||||||
|
/**
|
||||||
|
* \brief The commit call writes back the variable's value to the data pool.
|
||||||
|
* \details It checks type and size, as well as if the variable is writable. If so,
|
||||||
|
* the value is copied and the valid flag is automatically set to "valid".
|
||||||
|
* The operation does NOT provide any mutual exclusive protection by itself.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
ReturnValue_t commit();
|
||||||
|
public:
|
||||||
|
static const uint8_t INTERFACE_ID = POOL_RAW_ACCESS_CLASS;
|
||||||
|
static const ReturnValue_t INCORRECT_SIZE = MAKE_RETURN_CODE(0x01);
|
||||||
|
static const ReturnValue_t DATA_POOL_ACCESS_FAILED = MAKE_RETURN_CODE(0x02);
|
||||||
|
uint8_t value[RAW_MAX_SIZE];
|
||||||
|
PoolRawAccess(uint32_t data_pool_id, uint8_t arrayEntry,
|
||||||
|
DataSetIF* data_set, ReadWriteMode_t setReadWriteMode =
|
||||||
|
PoolVariableIF::VAR_READ);
|
||||||
|
/**
|
||||||
|
* \brief The classes destructor is empty. If commit() was not called, the local value is
|
||||||
|
* discarded and not written back to the data pool.
|
||||||
|
*/
|
||||||
|
~PoolRawAccess();
|
||||||
|
/**
|
||||||
|
* \brief This operation returns a pointer to the entry fetched.
|
||||||
|
* \details This means, it does not return a pointer to byte "index", but to the start byte of
|
||||||
|
* array entry "index". Example: If the original data pool array consists of an double
|
||||||
|
* array of size four, getEntry(1) returns &(this->value[8]).
|
||||||
|
*/
|
||||||
|
uint8_t* getEntry();
|
||||||
|
/**
|
||||||
|
* \brief This operation returns the fetched entry from the data pool and
|
||||||
|
* flips the bytes, if necessary.
|
||||||
|
* \details It makes use of the getEntry call of this function, but additionally flips the
|
||||||
|
* bytes to big endian, which is the default for external communication (as House-
|
||||||
|
* keeping telemetry). To achieve this, the data is copied directly to the passed
|
||||||
|
* buffer, if it fits in the given max_size.
|
||||||
|
* \param buffer A pointer to a buffer to write to
|
||||||
|
* \param writtenBytes The number of bytes written is returned with this value.
|
||||||
|
* \param max_size The maximum size that the function may write to buffer.
|
||||||
|
* \return - \c RETURN_OK if entry could be acquired
|
||||||
|
* - \c RETURN_FAILED else.
|
||||||
|
*/
|
||||||
|
ReturnValue_t getEntryEndianSafe(uint8_t* buffer, uint32_t* size,
|
||||||
|
uint32_t max_size);
|
||||||
|
/**
|
||||||
|
* With this method, the content can be set from a big endian buffer safely.
|
||||||
|
* @param buffer Pointer to the data to set
|
||||||
|
* @param size Size of the data to write. Must fit this->size.
|
||||||
|
* @return - \c RETURN_OK on success
|
||||||
|
* - \c RETURN_FAILED on failure
|
||||||
|
*/
|
||||||
|
ReturnValue_t setEntryFromBigEndian(const uint8_t* buffer,
|
||||||
|
uint32_t setSize);
|
||||||
|
/**
|
||||||
|
* \brief This operation returns the size of the entry currently stored.
|
||||||
|
*/
|
||||||
|
uint8_t getSizeOfType();
|
||||||
|
/**
|
||||||
|
* \brief This operation returns the data pool id of the variable.
|
||||||
|
*/
|
||||||
|
uint32_t getDataPoolId() const;
|
||||||
|
/**
|
||||||
|
* This method returns if the variable is read-write or read-only.
|
||||||
|
*/
|
||||||
|
ReadWriteMode_t getReadWriteMode() const;
|
||||||
|
/**
|
||||||
|
* \brief With this call, the valid information of the variable is returned.
|
||||||
|
*/
|
||||||
|
bool isValid() const;
|
||||||
|
|
||||||
|
void setValid(uint8_t valid);
|
||||||
|
/**
|
||||||
|
* Getter for the remaining size.
|
||||||
|
*/
|
||||||
|
uint16_t getSizeTillEnd() const;
|
||||||
|
|
||||||
|
ReturnValue_t serialize(uint8_t** buffer, uint32_t* size,
|
||||||
|
const uint32_t max_size, bool bigEndian) const;
|
||||||
|
|
||||||
|
uint32_t getSerializedSize() const;
|
||||||
|
|
||||||
|
ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size,
|
||||||
|
bool bigEndian);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* POOLRAWACCESS_H_ */
|
35
datapool/PoolVarList.h
Normal file
35
datapool/PoolVarList.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* PoolVarList.h
|
||||||
|
*
|
||||||
|
* Created on: 06.03.2014
|
||||||
|
* Author: baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef POOLVARLIST_H_
|
||||||
|
#define POOLVARLIST_H_
|
||||||
|
|
||||||
|
#include <framework/datapool/PoolVariable.h>
|
||||||
|
#include <framework/datapool/PoolVariableIF.h>
|
||||||
|
template <class T, uint8_t n_var>
|
||||||
|
class PoolVarList {
|
||||||
|
private:
|
||||||
|
PoolVariable<T> variables[n_var];
|
||||||
|
public:
|
||||||
|
PoolVarList( const uint32_t set_id[n_var], DataSetIF* dataSet, PoolVariableIF::ReadWriteMode_t setReadWriteMode ) {
|
||||||
|
//I really should have a look at the new init list c++ syntax.
|
||||||
|
if (dataSet == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (uint8_t count = 0; count < n_var; count++) {
|
||||||
|
variables[count].dataPoolId = set_id[count];
|
||||||
|
variables[count].readWriteMode = setReadWriteMode;
|
||||||
|
dataSet->registerVariable(&variables[count]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PoolVariable<T> &operator [](int i) { return variables[i]; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* POOLVARLIST_H_ */
|
295
datapool/PoolVariable.h
Normal file
295
datapool/PoolVariable.h
Normal file
@ -0,0 +1,295 @@
|
|||||||
|
/*
|
||||||
|
* \file PoolVariable.h
|
||||||
|
*
|
||||||
|
* \brief This file contains the PoolVariable class, which locally represents a non-array data pool variable.
|
||||||
|
*
|
||||||
|
* \date 10/17/2012
|
||||||
|
*
|
||||||
|
* \author Bastian Baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef POOLVARIABLE_H_
|
||||||
|
#define POOLVARIABLE_H_
|
||||||
|
|
||||||
|
#include <framework/datapool/DataSetIF.h>
|
||||||
|
#include <framework/datapool/PoolEntry.h>
|
||||||
|
#include <framework/datapool/PoolVariableIF.h>
|
||||||
|
#include <framework/serialize/SerializeAdapter.h>
|
||||||
|
#include <framework/serviceinterface/ServiceInterfaceStream.h>
|
||||||
|
|
||||||
|
template<typename T, uint8_t n_var> class PoolVarList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief This is the access class for non-array data pool entries.
|
||||||
|
*
|
||||||
|
* \details To ensure safe usage of the data pool, operation is not done directly on the data pool
|
||||||
|
* entries, but on local copies. This class provides simple type-safe access to single
|
||||||
|
* data pool entries (i.e. entries with length = 1).
|
||||||
|
* The class can be instantiated as read-write and read only.
|
||||||
|
* It provides a commit-and-roll-back semantic, which means that the variable's value in
|
||||||
|
* the data pool is not changed until the commit call is executed.
|
||||||
|
* \tparam T The template parameter sets the type of the variable. Currently, all plain data types
|
||||||
|
* are supported, but in principle any type is possible.
|
||||||
|
* \ingroup data_pool
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
class PoolVariable: public PoolVariableIF {
|
||||||
|
template<typename U, uint8_t n_var> friend class PoolVarList;
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* \brief To access the correct data pool entry on read and commit calls, the data pool id
|
||||||
|
* is stored.
|
||||||
|
*/
|
||||||
|
uint32_t dataPoolId;
|
||||||
|
/**
|
||||||
|
* \brief The valid information as it was stored in the data pool is copied to this attribute.
|
||||||
|
*/
|
||||||
|
uint8_t valid;
|
||||||
|
/**
|
||||||
|
* \brief The information whether the class is read-write or read-only is stored here.
|
||||||
|
*/
|
||||||
|
ReadWriteMode_t readWriteMode;
|
||||||
|
/**
|
||||||
|
* \brief This is a call to read the value from the global data pool.
|
||||||
|
* \details When executed, this operation tries to fetch the pool entry with matching
|
||||||
|
* data pool id from the global data pool and copies the value and the valid
|
||||||
|
* information to its local attributes. In case of a failure (wrong type or
|
||||||
|
* pool id not found), the variable is set to zero and invalid.
|
||||||
|
* The operation does NOT provide any mutual exclusive protection by itself.
|
||||||
|
*/
|
||||||
|
ReturnValue_t read() {
|
||||||
|
PoolEntry<T>* read_out = ::dataPool.getData<T>(dataPoolId, 1);
|
||||||
|
if (read_out != NULL) {
|
||||||
|
valid = read_out->valid;
|
||||||
|
value = *(read_out->address);
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
} else {
|
||||||
|
value = 0;
|
||||||
|
valid = false;
|
||||||
|
error << "PoolVariable: read of DP Variable 0x" << std::hex
|
||||||
|
<< dataPoolId << std::dec << " failed." << std::endl;
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* \brief The commit call writes back the variable's value to the data pool.
|
||||||
|
* \details It checks type and size, as well as if the variable is writable. If so,
|
||||||
|
* the value is copied and the valid flag is automatically set to "valid".
|
||||||
|
* The operation does NOT provide any mutual exclusive protection by itself.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
ReturnValue_t commit() {
|
||||||
|
PoolEntry<T>* write_back = ::dataPool.getData<T>(dataPoolId, 1);
|
||||||
|
if ((write_back != NULL) && (readWriteMode != VAR_READ)) {
|
||||||
|
write_back->valid = valid;
|
||||||
|
*(write_back->address) = value;
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
} else {
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Empty ctor for List initialization
|
||||||
|
*/
|
||||||
|
PoolVariable() :
|
||||||
|
dataPoolId(PoolVariableIF::NO_PARAMETER), valid(
|
||||||
|
PoolVariableIF::INVALID), readWriteMode(VAR_READ), value(0) {
|
||||||
|
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* \brief This is the local copy of the data pool entry.
|
||||||
|
* \details The user can work on this attribute
|
||||||
|
* just like he would on a simple local variable.
|
||||||
|
*/
|
||||||
|
T value;
|
||||||
|
/**
|
||||||
|
* \brief In the constructor, the variable can register itself in a DataSet (if not NULL is
|
||||||
|
* passed).
|
||||||
|
* \details It DOES NOT fetch the current value from the data pool, but sets the value
|
||||||
|
* attribute to default (0). The value is fetched within the read() operation.
|
||||||
|
* \param set_id This is the id in the global data pool this instance of the access class
|
||||||
|
* corresponds to.
|
||||||
|
* \param dataSet The data set in which the variable shall register itself. If NULL,
|
||||||
|
* the variable is not registered.
|
||||||
|
* \param setWritable If this flag is set to true, changes in the value attribute can be
|
||||||
|
* written back to the data pool, otherwise not.
|
||||||
|
*/
|
||||||
|
PoolVariable(uint32_t set_id, DataSetIF* dataSet,
|
||||||
|
ReadWriteMode_t setReadWriteMode) :
|
||||||
|
dataPoolId(set_id), valid(PoolVariableIF::INVALID), readWriteMode(
|
||||||
|
setReadWriteMode), value(0) {
|
||||||
|
if (dataSet != NULL) {
|
||||||
|
dataSet->registerVariable(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Copy ctor to copy classes containing Pool Variables.
|
||||||
|
*/
|
||||||
|
PoolVariable(const PoolVariable& rhs) :
|
||||||
|
dataPoolId(rhs.dataPoolId), valid(rhs.valid), readWriteMode(
|
||||||
|
rhs.readWriteMode), value(rhs.value) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief The classes destructor is empty.
|
||||||
|
* \details If commit() was not called, the local value is
|
||||||
|
* discarded and not written back to the data pool.
|
||||||
|
*/
|
||||||
|
~PoolVariable() {
|
||||||
|
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* \brief This operation returns the data pool id of the variable.
|
||||||
|
*/
|
||||||
|
uint32_t getDataPoolId() const {
|
||||||
|
return dataPoolId;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This operation sets the data pool id of the variable.
|
||||||
|
* The method is necessary to set id's of data pool member variables with bad initialization.
|
||||||
|
*/
|
||||||
|
void setDataPoolId(uint32_t poolId) {
|
||||||
|
dataPoolId = poolId;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This method returns if the variable is write-only, read-write or read-only.
|
||||||
|
*/
|
||||||
|
ReadWriteMode_t getReadWriteMode() const {
|
||||||
|
return readWriteMode;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* \brief With this call, the valid information of the variable is returned.
|
||||||
|
*/
|
||||||
|
bool isValid() const {
|
||||||
|
if (valid)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t getValid() {
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setValid(uint8_t valid) {
|
||||||
|
this->valid = valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
operator T() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
operator T() const {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
PoolVariable<T> &operator=(T newValue) {
|
||||||
|
value = newValue;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
PoolVariable<T> &operator=(PoolVariable<T> newPoolVariable) {
|
||||||
|
value = newPoolVariable.value;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ReturnValue_t serialize(uint8_t** buffer, uint32_t* size,
|
||||||
|
const uint32_t max_size, bool bigEndian) const {
|
||||||
|
return SerializeAdapter<T>::serialize(&value, buffer, size, max_size,
|
||||||
|
bigEndian);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual uint32_t getSerializedSize() const {
|
||||||
|
return SerializeAdapter<T>::getSerializedSize(&value);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size,
|
||||||
|
bool bigEndian) {
|
||||||
|
return SerializeAdapter<T>::deSerialize(&value, buffer, size, bigEndian);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef PoolVariable<uint8_t> db_uint8_t;
|
||||||
|
typedef PoolVariable<uint16_t> db_uint16_t;
|
||||||
|
typedef PoolVariable<uint32_t> db_uint32_t;
|
||||||
|
typedef PoolVariable<int8_t> db_int8_t;
|
||||||
|
typedef PoolVariable<int16_t> db_int16_t;
|
||||||
|
typedef PoolVariable<int32_t> db_int32_t;
|
||||||
|
typedef PoolVariable<uint8_t> db_bool_t;
|
||||||
|
typedef PoolVariable<float> db_float_t;
|
||||||
|
typedef PoolVariable<double> db_double_t;
|
||||||
|
//Alternative (but I thing this is not as useful: code duplication, differences too small):
|
||||||
|
|
||||||
|
//template <typename T>
|
||||||
|
//class PoolReader : public PoolVariableIF {
|
||||||
|
//private:
|
||||||
|
// uint32_t parameter_id;
|
||||||
|
// uint8_t valid;
|
||||||
|
//public:
|
||||||
|
// T value;
|
||||||
|
// PoolReader( uint32_t set_id, DataSetIF* set ) : parameter_id(set_id), valid(false), value(0) {
|
||||||
|
// set->registerVariable( this );
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// ~PoolReader() {};
|
||||||
|
//
|
||||||
|
// uint8_t commit() {
|
||||||
|
// return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// uint8_t read() {
|
||||||
|
// PoolEntry<T>* read_out = ::dataPool.getData<T>( parameter_id, 1 );
|
||||||
|
// if ( read_out != NULL ) {
|
||||||
|
// valid = read_out->valid;
|
||||||
|
// value = *(read_out->address);
|
||||||
|
// return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
// } else {
|
||||||
|
// value = 0;
|
||||||
|
// valid = false;
|
||||||
|
// return CHECKOUT_FAILED;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// uint32_t getParameterId() { return parameter_id; }
|
||||||
|
// bool isWritable() { return false; };
|
||||||
|
// bool isValid() { if (valid) return true; else return false; }
|
||||||
|
//};
|
||||||
|
//
|
||||||
|
//template <typename T>
|
||||||
|
//class PoolWriter : public PoolVariableIF {
|
||||||
|
//private:
|
||||||
|
// uint32_t parameter_id;
|
||||||
|
//public:
|
||||||
|
// T value;
|
||||||
|
// PoolWriter( uint32_t set_id, DataSetIF* set ) : parameter_id(set_id), value(0) {
|
||||||
|
// set->registerVariable( this );
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// ~PoolWriter() {};
|
||||||
|
//
|
||||||
|
// uint8_t commit() {
|
||||||
|
// PoolEntry<T>* write_back = ::dataPool.getData<T>( parameter_id, 1 );
|
||||||
|
// if ( write_back != NULL ) {
|
||||||
|
// write_back->valid = true;
|
||||||
|
// *(write_back->address) = value;
|
||||||
|
// return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
// } else {
|
||||||
|
// return CHECKOUT_FAILED;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// uint8_t read() {
|
||||||
|
// PoolEntry<T>* read_out = ::dataPool.getData<T>( parameter_id, 1 );
|
||||||
|
// if ( read_out != NULL ) {
|
||||||
|
// value = *(read_out->address);
|
||||||
|
// return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
// } else {
|
||||||
|
// value = 0;
|
||||||
|
// return CHECKOUT_FAILED;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// uint32_t getParameterId() { return parameter_id; }
|
||||||
|
// bool isWritable() { return true; };
|
||||||
|
// bool isValid() { return false; }
|
||||||
|
//};
|
||||||
|
|
||||||
|
#endif /* POOLVARIABLE_H_ */
|
71
datapool/PoolVariableIF.h
Normal file
71
datapool/PoolVariableIF.h
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* \file PoolVariableIF.h
|
||||||
|
*
|
||||||
|
* \brief This file contains the interface definition for pool variables.
|
||||||
|
*
|
||||||
|
* \date 10/17/2012
|
||||||
|
*
|
||||||
|
* \author Bastian Baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef POOLVARIABLEIF_H_
|
||||||
|
#define POOLVARIABLEIF_H_
|
||||||
|
|
||||||
|
#include <framework/returnvalues/HasReturnvaluesIF.h>
|
||||||
|
#include <framework/serialize/SerializeIF.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief This interface is used to control local data pool variable representations.
|
||||||
|
*
|
||||||
|
* \details To securely handle data pool variables, all pool entries are locally managed by
|
||||||
|
* data pool variable access classes, which are called pool variables. To ensure a
|
||||||
|
* common state of a set of variables needed in a function, these local pool variables
|
||||||
|
* again are managed by other classes, e.g. the DataSet. This interface provides unified
|
||||||
|
* access to local pool variables for such manager classes.
|
||||||
|
* \ingroup data_pool
|
||||||
|
*/
|
||||||
|
class PoolVariableIF : public SerializeIF {
|
||||||
|
friend class DataSet;
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* \brief The commit call shall write back a newly calculated local value to the data pool.
|
||||||
|
*/
|
||||||
|
virtual ReturnValue_t commit() = 0;
|
||||||
|
/**
|
||||||
|
* \brief The read call shall read the value of this parameter from the data pool and store
|
||||||
|
* the content locally.
|
||||||
|
*/
|
||||||
|
virtual ReturnValue_t read() = 0;
|
||||||
|
public:
|
||||||
|
static const uint8_t VALID = 1;
|
||||||
|
static const uint8_t INVALID = 0;
|
||||||
|
static const uint32_t NO_PARAMETER = 0;
|
||||||
|
enum ReadWriteMode_t {
|
||||||
|
VAR_READ, VAR_WRITE, VAR_READ_WRITE
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief This is an empty virtual destructor, as it is proposed for C++ interfaces.
|
||||||
|
*/
|
||||||
|
virtual ~PoolVariableIF() {
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* \brief This method returns if the variable is write-only, read-write or read-only.
|
||||||
|
*/
|
||||||
|
virtual ReadWriteMode_t getReadWriteMode() const = 0;
|
||||||
|
/**
|
||||||
|
* \brief This operation shall return the data pool id of the variable.
|
||||||
|
*/
|
||||||
|
virtual uint32_t getDataPoolId() const = 0;
|
||||||
|
/**
|
||||||
|
* \brief With this call, the valid information of the variable is returned.
|
||||||
|
*/
|
||||||
|
virtual bool isValid() const = 0;
|
||||||
|
/**
|
||||||
|
* \brief With this call, the valid information of the variable is set.
|
||||||
|
*/
|
||||||
|
virtual void setValid(uint8_t validity) = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* POOLVARIABLEIF_H_ */
|
233
datapool/PoolVector.h
Normal file
233
datapool/PoolVector.h
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
/*
|
||||||
|
* \file PoolVector.h
|
||||||
|
*
|
||||||
|
* \brief This file contains the PoolVector class, the header only class to handle data pool vectors.
|
||||||
|
*
|
||||||
|
* \date 10/23/2012
|
||||||
|
*
|
||||||
|
* \author Bastian Baetz
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef POOLVECTOR_H_
|
||||||
|
#define POOLVECTOR_H_
|
||||||
|
|
||||||
|
#include <framework/datapool/DataSetIF.h>
|
||||||
|
#include <framework/datapool/PoolEntry.h>
|
||||||
|
#include <framework/datapool/PoolVariableIF.h>
|
||||||
|
#include <framework/serialize/SerializeAdapter.h>
|
||||||
|
#include <framework/serviceinterface/ServiceInterfaceStream.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief This is the access class for array-type data pool entries.
|
||||||
|
*
|
||||||
|
* \details To ensure safe usage of the data pool, operation is not done directly on the data pool
|
||||||
|
* entries, but on local copies. This class provides simple type- and length-safe access
|
||||||
|
* to vector-style data pool entries (i.e. entries with length > 1).
|
||||||
|
* The class can be instantiated as read-write and read only.
|
||||||
|
* It provides a commit-and-roll-back semantic, which means that no array entry in
|
||||||
|
* the data pool is changed until the commit call is executed.
|
||||||
|
* There are two template parameters:
|
||||||
|
* \tparam T This template parameter specifies the data type of an array entry. Currently, all
|
||||||
|
* plain data types are supported, but in principle any type is possible.
|
||||||
|
* \tparam vector_size This template parameter specifies the vector size of this entry.
|
||||||
|
* Using a template parameter for this is not perfect, but avoids dynamic memory allocation.
|
||||||
|
* \ingroup data_pool
|
||||||
|
*/
|
||||||
|
template<typename T, uint16_t vector_size>
|
||||||
|
class PoolVector: public PoolVariableIF {
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* \brief To access the correct data pool entry on read and commit calls, the data pool id
|
||||||
|
* is stored.
|
||||||
|
*/
|
||||||
|
uint32_t dataPoolId;
|
||||||
|
/**
|
||||||
|
* \brief The valid information as it was stored in the data pool is copied to this attribute.
|
||||||
|
*/
|
||||||
|
uint8_t valid;
|
||||||
|
/**
|
||||||
|
* \brief The information whether the class is read-write or read-only is stored here.
|
||||||
|
*/
|
||||||
|
ReadWriteMode_t readWriteMode;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* \brief This is a call to read the array's values from the global data pool.
|
||||||
|
* \details When executed, this operation tries to fetch the pool entry with matching
|
||||||
|
* data pool id from the global data pool and copies all array values and the valid
|
||||||
|
* information to its local attributes. In case of a failure (wrong type, size or
|
||||||
|
* pool id not found), the variable is set to zero and invalid.
|
||||||
|
* The operation does NOT provide any mutual exclusive protection by itself.
|
||||||
|
*/
|
||||||
|
ReturnValue_t read() {
|
||||||
|
PoolEntry<T>* read_out = ::dataPool.getData<T>(this->dataPoolId,
|
||||||
|
vector_size);
|
||||||
|
if (read_out != NULL) {
|
||||||
|
this->valid = read_out->valid;
|
||||||
|
memcpy(this->value, read_out->address, read_out->getByteSize());
|
||||||
|
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
memset(this->value, 0, vector_size * sizeof(T));
|
||||||
|
error << "PoolVector: read of DP Variable 0x" << std::hex
|
||||||
|
<< dataPoolId << std::dec << " failed." << std::endl;
|
||||||
|
this->valid = INVALID;
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* \brief The commit call copies the array values back to the data pool.
|
||||||
|
* \details It checks type and size, as well as if the variable is writable. If so,
|
||||||
|
* the value is copied and the valid flag is automatically set to "valid".
|
||||||
|
* The operation does NOT provide any mutual exclusive protection by itself.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
ReturnValue_t commit() {
|
||||||
|
PoolEntry<T>* write_back = ::dataPool.getData<T>(this->dataPoolId,
|
||||||
|
vector_size);
|
||||||
|
if ((write_back != NULL) && (this->readWriteMode != VAR_READ)) {
|
||||||
|
write_back->valid = valid;
|
||||||
|
memcpy(write_back->address, this->value, write_back->getByteSize());
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
} else {
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* \brief This is the local copy of the data pool entry.
|
||||||
|
* \detials The user can work on this attribute
|
||||||
|
* just like he would on a local array of this type.
|
||||||
|
*/
|
||||||
|
T value[vector_size];
|
||||||
|
/**
|
||||||
|
* \brief In the constructor, the variable can register itself in a DataSet (if not NULL is
|
||||||
|
* passed).
|
||||||
|
* \details It DOES NOT fetch the current value from the data pool, but sets the value
|
||||||
|
* attribute to default (0). The value is fetched within the read() operation.
|
||||||
|
* \param set_id This is the id in the global data pool this instance of the access class
|
||||||
|
* corresponds to.
|
||||||
|
* \param dataSet The data set in which the variable shall register itself. If NULL,
|
||||||
|
* the variable is not registered.
|
||||||
|
* \param setWritable If this flag is set to true, changes in the value attribute can be
|
||||||
|
* written back to the data pool, otherwise not.
|
||||||
|
*/
|
||||||
|
PoolVector(uint32_t set_id, DataSetIF* set,
|
||||||
|
ReadWriteMode_t setReadWriteMode) :
|
||||||
|
dataPoolId(set_id), valid(false), readWriteMode(setReadWriteMode) {
|
||||||
|
memset(this->value, 0, vector_size * sizeof(T));
|
||||||
|
if (set != NULL) {
|
||||||
|
set->registerVariable(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Copy ctor to copy classes containing Pool Variables.
|
||||||
|
*/
|
||||||
|
// PoolVector(const PoolVector& rhs) {
|
||||||
|
// PoolVector<T, vector_size> temp(rhs.dataPoolId, rhs.)
|
||||||
|
// memcpy(value, rhs.value, sizeof(T)*vector_size);
|
||||||
|
// }
|
||||||
|
/**
|
||||||
|
* \brief The classes destructor is empty.
|
||||||
|
* \details If commit() was not called, the local value is
|
||||||
|
* discarded and not written back to the data pool.
|
||||||
|
*/
|
||||||
|
~PoolVector() {
|
||||||
|
}
|
||||||
|
;
|
||||||
|
/**
|
||||||
|
* \brief The operation returns the number of array entries in this variable.
|
||||||
|
*/
|
||||||
|
uint8_t getSize() {
|
||||||
|
return vector_size;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* \brief This operation returns the data pool id of the variable.
|
||||||
|
*/
|
||||||
|
uint32_t getDataPoolId() const {
|
||||||
|
return dataPoolId;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This operation sets the data pool id of the variable.
|
||||||
|
* The method is necessary to set id's of data pool member variables with bad initialization.
|
||||||
|
*/
|
||||||
|
void setDataPoolId(uint32_t poolId) {
|
||||||
|
dataPoolId = poolId;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This method returns if the variable is write-only, read-write or read-only.
|
||||||
|
*/
|
||||||
|
ReadWriteMode_t getReadWriteMode() const {
|
||||||
|
return readWriteMode;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
/**
|
||||||
|
* \brief With this call, the valid information of the variable is returned.
|
||||||
|
*/
|
||||||
|
bool isValid() const {
|
||||||
|
if (valid != INVALID)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setValid(uint8_t valid) {
|
||||||
|
this->valid = valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t getValid() {
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
T &operator [](int i) {
|
||||||
|
return value[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
const T &operator [](int i) const {
|
||||||
|
return value[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
PoolVector<T, vector_size> &operator=(
|
||||||
|
PoolVector<T, vector_size> newPoolVector) {
|
||||||
|
|
||||||
|
for (uint16_t i = 0; i < vector_size; i++) {
|
||||||
|
this->value[i] = newPoolVector.value[i];
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ReturnValue_t serialize(uint8_t** buffer, uint32_t* size,
|
||||||
|
const uint32_t max_size, bool bigEndian) const {
|
||||||
|
uint16_t i;
|
||||||
|
ReturnValue_t result;
|
||||||
|
for (i = 0; i < vector_size; i++) {
|
||||||
|
result = SerializeAdapter<T>::serialize(&(value[i]), buffer, size,
|
||||||
|
max_size, bigEndian);
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual uint32_t getSerializedSize() const {
|
||||||
|
return vector_size * SerializeAdapter<T>::getSerializedSize(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size,
|
||||||
|
bool bigEndian) {
|
||||||
|
uint16_t i;
|
||||||
|
ReturnValue_t result;
|
||||||
|
for (i = 0; i < vector_size; i++) {
|
||||||
|
result = SerializeAdapter<T>::deSerialize(&(value[i]), buffer, size,
|
||||||
|
bigEndian);
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* POOLVECTOR_H_ */
|
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) );
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user