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"
|
||||
- Claas in his Diploma Thesis
|
||||
Rouven Witt, who developed the FDIR concept and kept morale high as the team's Spaßbeauftragter.
|
||||
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,
|
||||