From fd782b20c07d8a7874e0fc506e123db7ff01c9d2 Mon Sep 17 00:00:00 2001 From: Steffen Gaisser Date: Fri, 13 Jul 2018 18:28:26 +0200 Subject: [PATCH] Adding Code for Linux --- action/ActionHelper.cpp | 7 +- action/ActionHelper.h | 78 +- action/CommandActionHelper.cpp | 12 +- action/HasActionsIF.h | 24 +- action/SimpleActionHelper.h | 3 +- controller/ControllerBase.cpp | 5 +- controller/ControllerBase.h | 15 + coordinates/CoordinateTransformations.h | 1 + datapool/DataPoolAdmin.cpp | 6 +- datapool/HkSwitchHelper.h | 2 + datapool/PoolRawAccess.cpp | 32 +- devicehandlers/DeviceHandlerBase.cpp | 24 +- devicehandlers/DeviceHandlerBase.h | 14 +- devicehandlers/FixedSlotSequence.cpp | 1 - events/EventManager.h | 1 - framework.mk | 7 +- globalfunctions/conversion.cpp | 17 +- internalError/InternalErrorReporter.h | 1 - ipc/MessageQueueIF.h | 33 +- ipc/MutexHelper.h | 24 + ipc/MutexIF.h | 51 ++ memory/LocalMemory.cpp | 4 +- memory/MemoryHelper.cpp | 10 + memory/MemoryHelper.h | 3 +- monitoring/TwoValueLimitMonitor.h | 4 +- osal/Endiness.h | 11 +- osal/FreeRTOS/MessageQueue.cpp | 18 +- osal/FreeRTOS/MessageQueue.h | 4 +- osal/FreeRTOS/main.cpp | 61 +- osal/OperatingSystemIF.h | 144 ---- osal/{Linux => linux}/Clock.cpp | 111 ++- osal/linux/FixedTimeslotTask.cpp | 89 +++ osal/linux/FixedTimeslotTask.h | 58 ++ osal/linux/InternalErrorCodes.cpp | 14 + osal/linux/MessageQueue.cpp | 258 +++++++ osal/linux/MessageQueue.h | 169 +++++ osal/linux/Mutex.cpp | 98 +++ osal/linux/Mutex.h | 18 + osal/linux/MutexFactory.cpp | 23 + osal/linux/PeriodicPosixTask.cpp | 72 ++ osal/linux/PeriodicPosixTask.h | 76 ++ osal/linux/PosixThread.cpp | 188 +++++ osal/linux/PosixThread.h | 74 ++ osal/linux/QueueFactory.cpp | 68 ++ osal/linux/TaskFactory.cpp | 34 + osal/linux/Timer.cpp | 41 ++ osal/linux/Timer.h | 45 ++ osal/rtems/Clock.cpp | 89 ++- osal/rtems/CpuUsage.cpp | 4 +- osal/rtems/InitTask.cpp | 16 - osal/rtems/InitTask.h | 11 +- osal/rtems/InternalErrorCodes.cpp | 33 +- osal/rtems/Interrupt.cpp | 20 +- osal/rtems/MessageQueue.cpp | 50 +- osal/rtems/MessageQueue.h | 11 +- osal/rtems/MultiObjectTask.cpp | 30 +- osal/rtems/Mutex.cpp | 34 +- osal/rtems/PollingTask.cpp | 48 +- osal/rtems/QueueFactory.cpp | 24 +- osal/rtems/RtemsBasic.cpp | 134 ++-- osal/rtems/RtemsBasic.h | 20 +- osal/rtems/TaskBase.cpp | 45 +- osal/rtems/TaskBase.h | 4 + osal/rtems/TaskFactory.cpp | 11 +- parameters/ParameterHelper.cpp | 5 +- returnvalues/FwClassIds.h | 3 + rmap/RMAP.cpp | 12 +- rmap/RMAPChannelIF.h | 11 +- rmap/RMAPCookie.cpp | 32 +- rmap/RMAPCookie.h | 25 +- rmap/RmapDeviceCommunicationIF.cpp | 47 ++ rmap/RmapDeviceCommunicationIF.h | 80 +++ rmap/RmapSPWChannel.cpp | 744 -------------------- rmap/RmapSPWChannel.h | 135 ---- rmap/rmapStructs.h | 43 +- serialize/EndianSwapper.h | 18 +- serviceinterface/ServiceInterfaceBuffer.cpp | 4 + serviceinterface/ServiceInterfaceBuffer.h | 4 +- storagemanager/PoolManager.h | 51 +- subsystem/SubsystemBase.cpp | 2 +- tasks/ExecutableObjectIF.h | 15 +- tasks/PeriodicTaskIF.h | 5 +- tasks/Typedef.h | 2 +- tcdistribution/PUSDistributor.cpp | 3 +- tcdistribution/TcDistributor.cpp | 2 +- tcdistribution/TcDistributor.h | 1 - timemanager/CCSDSTime.cpp | 4 +- tmtcservices/CommandingServiceBase.h | 17 +- tmtcservices/PusServiceBase.cpp | 2 +- tmtcservices/SourceSequenceCounter.h | 4 +- 90 files changed, 2411 insertions(+), 1497 deletions(-) create mode 100644 ipc/MutexHelper.h delete mode 100644 osal/OperatingSystemIF.h rename osal/{Linux => linux}/Clock.cpp (64%) create mode 100644 osal/linux/FixedTimeslotTask.cpp create mode 100644 osal/linux/FixedTimeslotTask.h create mode 100644 osal/linux/InternalErrorCodes.cpp create mode 100644 osal/linux/MessageQueue.cpp create mode 100644 osal/linux/MessageQueue.h create mode 100644 osal/linux/Mutex.cpp create mode 100644 osal/linux/Mutex.h create mode 100644 osal/linux/MutexFactory.cpp create mode 100644 osal/linux/PeriodicPosixTask.cpp create mode 100644 osal/linux/PeriodicPosixTask.h create mode 100644 osal/linux/PosixThread.cpp create mode 100644 osal/linux/PosixThread.h create mode 100644 osal/linux/QueueFactory.cpp create mode 100644 osal/linux/TaskFactory.cpp create mode 100644 osal/linux/Timer.cpp create mode 100644 osal/linux/Timer.h create mode 100644 rmap/RmapDeviceCommunicationIF.cpp create mode 100644 rmap/RmapDeviceCommunicationIF.h delete mode 100644 rmap/RmapSPWChannel.cpp delete mode 100644 rmap/RmapSPWChannel.h diff --git a/action/ActionHelper.cpp b/action/ActionHelper.cpp index fa1c904b..9c1475f1 100644 --- a/action/ActionHelper.cpp +++ b/action/ActionHelper.cpp @@ -20,11 +20,13 @@ ReturnValue_t ActionHelper::handleActionMessage(CommandMessage* command) { } } -ReturnValue_t ActionHelper::initialize() { +ReturnValue_t ActionHelper::initialize(MessageQueueIF* queueToUse_) { ipcStore = objectManager->get(objects::IPC_STORE); if (ipcStore == NULL) { return HasReturnvaluesIF::RETURN_FAILED; } + setQueueToUse(queueToUse_); + return HasReturnvaluesIF::RETURN_OK; } @@ -100,3 +102,6 @@ ReturnValue_t ActionHelper::reportData(MessageQueueId_t reportTo, ActionId_t rep } return result; } + +void ActionHelper::resetHelper() { +} diff --git a/action/ActionHelper.h b/action/ActionHelper.h index 99ca4ce0..6ba6dd89 100644 --- a/action/ActionHelper.h +++ b/action/ActionHelper.h @@ -4,26 +4,90 @@ #include #include #include - +/** + * \brief Action Helper is a helper class which handles action messages + * + * Components which use the HasActionIF this helper can be used to handle the action messages. + * It does handle step messages as well as other answers to action calls. It uses the executeAction function + * of its owner as callback. The call of the initialize function is mandatory and it needs a valid messageQueueIF pointer! + */ class HasActionsIF; class ActionHelper { public: + /** + * Constructor of the action helper + * @param setOwner Pointer to the owner of the interface + * @param useThisQueue messageQueue to be used, can be set during initialize function as well. + */ ActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue); + virtual ~ActionHelper(); + /** + * Function to be called from the owner with a new command message + * + * If the message is a valid action message the helper will use the executeAction function from HasActionsIF. + * If the message is invalid or the callback fails a message reply will be send to the sender of the message automatically. + * + * @param command Pointer to a command message received by the owner + * @return HasReturnvaluesIF::RETURN_OK if the message is a action message, CommandMessage::UNKNOW_COMMAND if this message ID is unkown + */ ReturnValue_t handleActionMessage(CommandMessage* command); - ReturnValue_t initialize(); + /** + * Helper initialize function. Must be called before use of any other helper function + * @param queueToUse_ Pointer to the messageQueue to be used + * @return Returns RETURN_OK if successful + */ + ReturnValue_t initialize(MessageQueueIF* queueToUse_); + /** + * Function to be called from the owner to send a step message. Success or failure will be determined by the result value. + * + * @param step Number of steps already done + * @param reportTo The messageQueueId to report the step message to + * @param commandId ID of the executed command + * @param result Result of the execution + */ void step(uint8_t step, MessageQueueId_t reportTo, ActionId_t commandId, ReturnValue_t result = HasReturnvaluesIF::RETURN_OK); + /** + * Function to be called by the owner to send a action completion message + * + * @param reportTo MessageQueueId_t to report the action completion message to + * @param commandId ID of the executed command + * @param result Result of the execution + */ void finish(MessageQueueId_t reportTo, ActionId_t commandId, ReturnValue_t result = HasReturnvaluesIF::RETURN_OK); + /** + * Function to be called by the owner if an action does report data + * + * @param reportTo MessageQueueId_t to report the action completion message to + * @param replyId ID of the executed command + * @param data Pointer to the data + * @return Returns RETURN_OK if successful, otherwise failure code + */ ReturnValue_t reportData(MessageQueueId_t reportTo, ActionId_t replyId, SerializeIF* data, bool hideSender = false); + /** + * Function to setup the MessageQueueIF* of the helper. Can be used to set the messageQueueIF* if + * message queue is unavailable at construction and initialize but must be setup before first call of other functions. + * @param queue Queue to be used by the helper + */ void setQueueToUse(MessageQueueIF *queue); protected: - static const uint8_t STEP_OFFSET = 1; - HasActionsIF* owner; - MessageQueueIF* queueToUse; - StorageManagerIF* ipcStore; + static const uint8_t STEP_OFFSET = 1;//!< Increase of value of this per step + HasActionsIF* owner;//!< Pointer to the owner + MessageQueueIF* queueToUse;//!< Queue to be used as response sender, has to be set with + StorageManagerIF* ipcStore;//!< Pointer to an IPC Store, initialized during construction or initialize(MessageQueueIF* queueToUse_) or with setQueueToUse(MessageQueueIF *queue) + /** + *Internal function called by handleActionMessage(CommandMessage* command) + * + * @param commandedBy MessageQueueID of Commander + * @param actionId ID of action to be done + * @param dataAddress Address of additional data in IPC Store + */ virtual void prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId, store_address_t dataAddress); - void resetHelper(); + /** + * + */ + virtual void resetHelper(); }; #endif /* ACTIONHELPER_H_ */ diff --git a/action/CommandActionHelper.cpp b/action/CommandActionHelper.cpp index b643c2e3..05eb9346 100644 --- a/action/CommandActionHelper.cpp +++ b/action/CommandActionHelper.cpp @@ -5,7 +5,7 @@ #include CommandActionHelper::CommandActionHelper(CommandsActionsIF* setOwner) : - owner(setOwner), queueToUse(setOwner->getCommandQueuePtr()), ipcStore( + owner(setOwner), queueToUse(NULL), ipcStore( NULL), commandCount(0), lastTarget(0) { } @@ -66,11 +66,15 @@ ReturnValue_t CommandActionHelper::sendCommand(MessageQueueId_t queueId, ReturnValue_t CommandActionHelper::initialize() { ipcStore = objectManager->get(objects::IPC_STORE); - if (ipcStore != NULL) { - return HasReturnvaluesIF::RETURN_OK; - } else { + if (ipcStore == NULL) { return HasReturnvaluesIF::RETURN_FAILED; } + + queueToUse = owner->getCommandQueuePtr(); + if(queueToUse == NULL){ + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t CommandActionHelper::handleReply(CommandMessage* reply) { diff --git a/action/HasActionsIF.h b/action/HasActionsIF.h index fb86b790..f30fcb45 100644 --- a/action/HasActionsIF.h +++ b/action/HasActionsIF.h @@ -6,14 +6,36 @@ #include #include #include +/** + * \brief Interface for component which uses actions + * + * This interface is used to execute actions in the component. Actions, in the sense of this interface, are activities with a well-defined beginning and + * end in time. They may adjust sub-states of components, but are not supposed to change + * the main mode of operation, which is handled with the HasModesIF described below. + * + * The HasActionsIF allows components to define such actions and make them available + * for other components to use. Implementing the interface is straightforward: There’s a + * single executeAction call, which provides an identifier for the action to execute, as well + * as arbitrary parameters for input. Aside from direct, software-based + * actions, it is used in device handler components as an interface to forward commands to + * devices. + * Implementing components of the interface are supposed to check identifier (ID) and + * parameters and immediately start execution of the action. It is, however, not required to + * immediately finish execution. Instead, this may be deferred to a later point in time, at + * which the component needs to inform the caller about finished or failed execution. + */ class HasActionsIF { public: static const uint8_t INTERFACE_ID = CLASS_ID::HAS_ACTIONS_IF; - static const ReturnValue_t IS_BUSY = MAKE_RETURN_CODE(1); + 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() { } + /** + * Function to get the MessageQueueId_t of the implementing object + * @return MessageQueueId_t of the object + */ virtual MessageQueueId_t getCommandQueue() const = 0; /** * Execute or initialize the execution of a certain function. diff --git a/action/SimpleActionHelper.h b/action/SimpleActionHelper.h index 953001d5..71e73c5a 100644 --- a/action/SimpleActionHelper.h +++ b/action/SimpleActionHelper.h @@ -10,9 +10,10 @@ public: void step(ReturnValue_t result = HasReturnvaluesIF::RETURN_OK); void finish(ReturnValue_t result = HasReturnvaluesIF::RETURN_OK); ReturnValue_t reportData(SerializeIF* data); - void resetHelper(); + protected: void prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId, store_address_t dataAddress); + virtual void resetHelper(); private: bool isExecuting; MessageQueueId_t lastCommander; diff --git a/controller/ControllerBase.cpp b/controller/ControllerBase.cpp index a6d70088..7b11bdfa 100644 --- a/controller/ControllerBase.cpp +++ b/controller/ControllerBase.cpp @@ -8,7 +8,7 @@ ControllerBase::ControllerBase(uint32_t setObjectId, uint32_t parentId, size_t commandQueueDepth) : SystemObject(setObjectId), parentId(parentId), mode(MODE_OFF), submode( SUBMODE_NONE), commandQueue(NULL), modeHelper( - this), healthHelper(this, setObjectId),hkSwitcher(this) { + this), healthHelper(this, setObjectId),hkSwitcher(this),executingTask(NULL) { commandQueue = QueueFactory::instance()->createMessageQueue(commandQueueDepth); } @@ -129,6 +129,9 @@ ReturnValue_t ControllerBase::setHealth(HealthState health) { HasHealthIF::HealthState ControllerBase::getHealth() { return healthHelper.getHealth(); } +void ControllerBase::setTaskIF(PeriodicTaskIF* task_){ + executingTask = task_; +} void ControllerBase::changeHK(Mode_t mode, Submode_t submode, bool enable) { } diff --git a/controller/ControllerBase.h b/controller/ControllerBase.h index 56e116ec..804bc7c2 100644 --- a/controller/ControllerBase.h +++ b/controller/ControllerBase.h @@ -32,6 +32,16 @@ public: virtual ReturnValue_t setHealth(HealthState health); virtual HasHealthIF::HealthState getHealth(); + + /** + * Implementation of ExecutableObjectIF function + * + * Used to setup the reference of the task, that executes this component + * @param task_ Pointer to the taskIF of this task + */ + virtual void setTaskIF(PeriodicTaskIF* task_); + + protected: const uint32_t parentId; @@ -47,6 +57,11 @@ protected: HkSwitchHelper hkSwitcher; + /** + * Pointer to the task which executes this component, is invalid before setTaskIF was called. + */ + PeriodicTaskIF* executingTask; + void handleQueue(); virtual ReturnValue_t handleCommandMessage(CommandMessage *message) = 0; diff --git a/coordinates/CoordinateTransformations.h b/coordinates/CoordinateTransformations.h index b19c58f9..b072271f 100644 --- a/coordinates/CoordinateTransformations.h +++ b/coordinates/CoordinateTransformations.h @@ -2,6 +2,7 @@ #define COORDINATETRANSFORMATIONS_H_ #include +#include class CoordinateTransformations { public: diff --git a/datapool/DataPoolAdmin.cpp b/datapool/DataPoolAdmin.cpp index 71a347f9..fe6b9215 100644 --- a/datapool/DataPoolAdmin.cpp +++ b/datapool/DataPoolAdmin.cpp @@ -8,7 +8,7 @@ DataPoolAdmin::DataPoolAdmin(object_id_t objectId) : SystemObject(objectId), storage(NULL), commandQueue(NULL), memoryHelper( - this, commandQueue), actionHelper(this, commandQueue) { + this, NULL), actionHelper(this, NULL) { commandQueue = QueueFactory::instance()->createMessageQueue(); } @@ -171,7 +171,7 @@ ReturnValue_t DataPoolAdmin::initialize() { return result; } - result = memoryHelper.initialize(); + result = memoryHelper.initialize(commandQueue); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } @@ -181,7 +181,7 @@ ReturnValue_t DataPoolAdmin::initialize() { return HasReturnvaluesIF::RETURN_FAILED; } - result = actionHelper.initialize(); + result = actionHelper.initialize(commandQueue); return result; } diff --git a/datapool/HkSwitchHelper.h b/datapool/HkSwitchHelper.h index 067ab88d..1a3b6275 100644 --- a/datapool/HkSwitchHelper.h +++ b/datapool/HkSwitchHelper.h @@ -24,6 +24,8 @@ public: ReturnValue_t switchHK(SerializeIF *sids, bool enable); + virtual void setTaskIF(PeriodicTaskIF* task_){}; + protected: virtual void stepSuccessfulReceived(ActionId_t actionId, uint8_t step); virtual void stepFailedReceived(ActionId_t actionId, uint8_t step, diff --git a/datapool/PoolRawAccess.cpp b/datapool/PoolRawAccess.cpp index ead7676e..555896bb 100644 --- a/datapool/PoolRawAccess.cpp +++ b/datapool/PoolRawAccess.cpp @@ -76,13 +76,13 @@ ReturnValue_t PoolRawAccess::getEntryEndianSafe(uint8_t* buffer, 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 +#ifndef BYTE_ORDER_SYSTEM +#error BYTE_ORDER_SYSTEM not defined +#elif BYTE_ORDER_SYSTEM == LITTLE_ENDIAN for (uint8_t count = 0; count < typeSize; count++) { buffer[count] = data_ptr[typeSize - count - 1]; } -#elif BYTE_ORDER == BIG_ENDIAN +#elif BYTE_ORDER_SYSTEM == BIG_ENDIAN memcpy(buffer, data_ptr, typeSize); #endif *writtenBytes = typeSize; @@ -112,13 +112,13 @@ PoolVariableIF::ReadWriteMode_t PoolRawAccess::getReadWriteMode() const { 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 +#ifndef BYTE_ORDER_SYSTEM +#error BYTE_ORDER_SYSTEM not defined +#elif BYTE_ORDER_SYSTEM == LITTLE_ENDIAN for (uint8_t count = 0; count < typeSize; count++) { value[count] = buffer[typeSize - count - 1]; } -#elif BYTE_ORDER == BIG_ENDIAN +#elif BYTE_ORDER_SYSTEM == BIG_ENDIAN memcpy(value, buffer, typeSize); #endif return HasReturnvaluesIF::RETURN_OK; @@ -149,13 +149,13 @@ 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 +#ifndef BYTE_ORDER_SYSTEM +#error BYTE_ORDER_SYSTEM not defined +#elif BYTE_ORDER_SYSTEM == LITTLE_ENDIAN for (uint8_t count = 0; count < typeSize; count++) { (*buffer)[count] = value[typeSize - count - 1]; } -#elif BYTE_ORDER == BIG_ENDIAN +#elif BYTE_ORDER_SYSTEM == BIG_ENDIAN memcpy(*buffer, value, typeSize); #endif } else { @@ -179,13 +179,13 @@ ReturnValue_t PoolRawAccess::deSerialize(const uint8_t** buffer, int32_t* size, if (*size >= 0) { if (bigEndian) { -#ifndef BYTE_ORDER -#error BYTE_ORDER not defined -#elif BYTE_ORDER == LITTLE_ENDIAN +#ifndef BYTE_ORDER_SYSTEM +#error BYTE_ORDER_SYSTEM not defined +#elif BYTE_ORDER_SYSTEM == LITTLE_ENDIAN for (uint8_t count = 0; count < typeSize; count++) { value[count] = (*buffer)[typeSize - count - 1]; } -#elif BYTE_ORDER == BIG_ENDIAN +#elif BYTE_ORDER_SYSTEM == BIG_ENDIAN memcpy(value, *buffer, typeSize); #endif } else { diff --git a/devicehandlers/DeviceHandlerBase.cpp b/devicehandlers/DeviceHandlerBase.cpp index 2bb9e6c5..2f7fa670 100644 --- a/devicehandlers/DeviceHandlerBase.cpp +++ b/devicehandlers/DeviceHandlerBase.cpp @@ -30,19 +30,7 @@ DeviceHandlerBase::DeviceHandlerBase(uint32_t ioBoardAddress, thermalRequestPoolId), healthHelper(this, setObjectId), modeHelper( this), parameterHelper(this), childTransitionFailure(RETURN_OK), ignoreMissedRepliesCount( 0), fdirInstance(fdirInstance), hkSwitcher(this), defaultFDIRUsed( - fdirInstance == NULL), switchOffWasReported(false), executingTask( - NULL), actionHelper(this, commandQueue), cookieInfo(), ioBoardAddress( -//======= -// NULL), IPCStore(NULL), deviceCommunicationId(deviceCommunication), communicationInterface( -// NULL), cookie( -// NULL), commandQueue(cmdQueueSize, CommandMessage::MAX_MESSAGE_SIZE), deviceThermalStatePoolId( -// thermalStatePoolId), deviceThermalRequestPoolId( -// thermalRequestPoolId), healthHelper(this, setObjectId), modeHelper( -// this), parameterHelper(this), childTransitionFailure(RETURN_OK), ignoreMissedRepliesCount( -// 0), fdirInstance(fdirInstance), defaultFDIRUsed( -// fdirInstance == NULL), switchOffWasReported(false), actionHelper( -// this, &commandQueue), cookieInfo(), ioBoardAddress( -//>>>>>>> makefile + fdirInstance == NULL), switchOffWasReported(false),executingTask(NULL), actionHelper(this, NULL), cookieInfo(), ioBoardAddress( ioBoardAddress), timeoutStart(0), childTransitionDelay(5000), transitionSourceMode( _MODE_POWER_DOWN), transitionSourceSubMode(SUBMODE_NONE), deviceSwitch( setDeviceSwitch) { @@ -636,7 +624,7 @@ ReturnValue_t DeviceHandlerBase::initialize() { if (result != RETURN_OK) { return result; } - result = actionHelper.initialize(); + result = actionHelper.initialize(commandQueue); if (result != RETURN_OK) { return result; } @@ -1021,10 +1009,6 @@ ReturnValue_t DeviceHandlerBase::acceptExternalDeviceCommands() { return RETURN_OK; } -void DeviceHandlerBase::setTaskIF(PeriodicTaskIF* interface) { - executingTask = interface; -} - void DeviceHandlerBase::replyRawReplyIfnotWiretapped(const uint8_t* data, size_t len) { if ((wiretappingMode == RAW) @@ -1281,3 +1265,7 @@ bool DeviceHandlerBase::commandIsExecuting(DeviceCommandId_t commandId) { void DeviceHandlerBase::changeHK(Mode_t mode, Submode_t submode, bool enable) { } + +void DeviceHandlerBase::setTaskIF(PeriodicTaskIF* task_){ + executingTask = task_; +} diff --git a/devicehandlers/DeviceHandlerBase.h b/devicehandlers/DeviceHandlerBase.h index 78efa657..b6e479ce 100644 --- a/devicehandlers/DeviceHandlerBase.h +++ b/devicehandlers/DeviceHandlerBase.h @@ -92,8 +92,13 @@ public: virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, ParameterWrapper *parameterWrapper, const ParameterWrapper *newValues, uint16_t startAtIndex); - - void setTaskIF(PeriodicTaskIF* interface); + /** + * Implementation of ExecutableObjectIF function + * + * Used to setup the reference of the task, that executes this component + * @param task_ Pointer to the taskIF of this task + */ + virtual void setTaskIF(PeriodicTaskIF* task_); protected: /** * The Returnvalues id of this class, required by HasReturnvaluesIF @@ -248,13 +253,13 @@ protected: bool switchOffWasReported; //!< Indicates if SWITCH_WENT_OFF was already thrown. + PeriodicTaskIF* executingTask;//!< Pointer to the task which executes this component, is invalid before setTaskIF was called. + static object_id_t powerSwitcherId; //!< Object which switches power on and off. static object_id_t rawDataReceiverId; //!< Object which receives RAW data by default. static object_id_t defaultFDIRParentId; //!< Object which may be the root cause of an identified fault. - - PeriodicTaskIF* executingTask; /** * Helper function to report a missed reply * @@ -787,7 +792,6 @@ protected: DeviceCommandMap deviceCommandMap; ActionHelper actionHelper; - private: /** diff --git a/devicehandlers/FixedSlotSequence.cpp b/devicehandlers/FixedSlotSequence.cpp index 3b10dea2..a65dd929 100644 --- a/devicehandlers/FixedSlotSequence.cpp +++ b/devicehandlers/FixedSlotSequence.cpp @@ -17,7 +17,6 @@ FixedSlotSequence::~FixedSlotSequence() { } void FixedSlotSequence::executeAndAdvance() { -// (*this->current)->print(); (*this->current)->handler->performOperation((*this->current)->opcode); // if (returnValue != RETURN_OK) { // this->sendErrorMessage( returnValue ); diff --git a/events/EventManager.h b/events/EventManager.h index 35711b58..76dde9f8 100644 --- a/events/EventManager.h +++ b/events/EventManager.h @@ -34,7 +34,6 @@ public: object_id_t reporterFrom = 0, object_id_t reporterTo = 0, bool reporterInverted = false); ReturnValue_t performOperation(uint8_t opCode); - protected: MessageQueueIF* eventReportQueue; diff --git a/framework.mk b/framework.mk index b38c133e..a5a65364 100644 --- a/framework.mk +++ b/framework.mk @@ -39,10 +39,7 @@ endif CXXSRC += $(wildcard $(FRAMEWORK_PATH)/parameters/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/power/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/returnvalues/*.cpp) - -# easier without it for now -#CXXSRC += $(wildcard $(FRAMEWORK_PATH)/rmap/*.cpp) - +CXXSRC += $(wildcard $(FRAMEWORK_PATH)/rmap/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/serialize/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/serviceinterface/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/storagemanager/*.cpp) @@ -56,4 +53,4 @@ CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tmstorage/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tmtcpacket/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tmtcpacket/packetmatcher/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tmtcpacket/pus/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tmtcservices/*.cpp) \ No newline at end of file +CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tmtcservices/*.cpp) diff --git a/globalfunctions/conversion.cpp b/globalfunctions/conversion.cpp index 8f2f1eb6..d4f542bd 100644 --- a/globalfunctions/conversion.cpp +++ b/globalfunctions/conversion.cpp @@ -1,5 +1,4 @@ #include -//TODO REMOVE. Needed because of BYTE_ORDER #include #include @@ -59,9 +58,9 @@ void convertToByteStream( int32_t value, uint8_t* buffer, uint32_t* size ) { //} void convertToByteStream( float in_value, uint8_t* buffer, uint32_t* size ) { -#ifndef BYTE_ORDER - #error BYTE_ORDER not defined -#elif BYTE_ORDER == LITTLE_ENDIAN +#ifndef BYTE_ORDER_SYSTEM + #error BYTE_ORDER_SYSTEM not defined +#elif BYTE_ORDER_SYSTEM == LITTLE_ENDIAN union float_union { float value; uint8_t chars[4]; @@ -73,16 +72,16 @@ void convertToByteStream( float in_value, uint8_t* buffer, uint32_t* size ) { buffer[2] = temp.chars[1]; buffer[3] = temp.chars[0]; *size += 4; -#elif BYTE_ORDER == BIG_ENDIAN +#elif BYTE_ORDER_SYSTEM == BIG_ENDIAN memcpy(buffer, &in_value, sizeof(in_value)); *size += sizeof(in_value); #endif } void convertToByteStream( double in_value, uint8_t* buffer, uint32_t* size ) { -#ifndef BYTE_ORDER - #error Endianess not defined -#elif BYTE_ORDER == LITTLE_ENDIAN +#ifndef BYTE_ORDER_SYSTEM + #error BYTE_ORDER_SYSTEM not defined +#elif BYTE_ORDER_SYSTEM == LITTLE_ENDIAN union double_union { double value; uint8_t chars[8]; @@ -98,7 +97,7 @@ void convertToByteStream( double in_value, uint8_t* buffer, uint32_t* size ) { buffer[6] = temp.chars[1]; buffer[7] = temp.chars[0]; *size += 8; -#elif BYTE_ORDER == BIG_ENDIAN +#elif BYTE_ORDER_SYSTEM == BIG_ENDIAN memcpy(buffer, &in_value, sizeof(in_value)); *size += sizeof(in_value); #endif diff --git a/internalError/InternalErrorReporter.h b/internalError/InternalErrorReporter.h index ed26350e..7c1df6a7 100644 --- a/internalError/InternalErrorReporter.h +++ b/internalError/InternalErrorReporter.h @@ -22,7 +22,6 @@ public: virtual void lostTm(); virtual void storeFull(); - protected: MutexIF* mutex; diff --git a/ipc/MessageQueueIF.h b/ipc/MessageQueueIF.h index bbe2f0ef..99e3bc98 100644 --- a/ipc/MessageQueueIF.h +++ b/ipc/MessageQueueIF.h @@ -5,11 +5,22 @@ #include #include +#include class MessageQueueIF { public: static const MessageQueueId_t NO_QUEUE = MessageQueueSenderIF::NO_QUEUE; //!< Ugly hack. + static const uint8_t INTERFACE_ID = CLASS_ID::MESSAGE_QUEUE_IF; + /** + * No new messages on the queue + */ + static const ReturnValue_t EMPTY = MAKE_RETURN_CODE(1); + /** + * No space left for more messages + */ + static const ReturnValue_t FULL = MAKE_RETURN_CODE(2); + virtual ~MessageQueueIF() {} /** * @brief This operation sends a message to the last communication partner. @@ -65,16 +76,32 @@ public: * This variable is set to zero by default. * \param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full (if implemented). */ - virtual ReturnValue_t sendMessage( MessageQueueId_t sendTo, MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ) = 0; + virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, MessageQueueMessage* message, MessageQueueId_t sentFrom, bool ignoreFault = false ) = 0; + /** + * @brief This operation sends a message to the given destination. + * @details It directly uses the sendMessage call of the MessageQueueSender parent, but passes its + * queue id as "sentFrom" parameter. + * @param sendTo This parameter specifies the message queue id of the destination message queue. + * @param message A pointer to a previously created message, which is sent. + * @param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. + */ + virtual ReturnValue_t sendMessage( MessageQueueId_t sendTo, MessageQueueMessage* message, bool ignoreFault = false ) = 0; /** - * \brief The sendToDefault method sends a queue message to the default destination. + * \brief The sendToDefaultFrom method sends a queue message to the default destination. * \details In all other aspects, it works identical to the sendMessage method. * \param message This is a pointer to a previously created message, which is sent. * \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. * This variable is set to zero by default. */ - virtual ReturnValue_t sendToDefault( MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ) = 0; + virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessage* message, MessageQueueId_t sentFrom, bool ignoreFault = false ) = 0; + /** + * @brief This operation sends a message to the default destination. + * @details As in the sendMessage method, this function uses the sendToDefault call of the + * Implementation class and adds its queue id as "sentFrom" information. + * @param message A pointer to a previously created message, which is sent. + */ + virtual ReturnValue_t sendToDefault( MessageQueueMessage* message ) = 0; /** * \brief This method is a simple setter for the default destination. */ diff --git a/ipc/MutexHelper.h b/ipc/MutexHelper.h new file mode 100644 index 00000000..64fabd64 --- /dev/null +++ b/ipc/MutexHelper.h @@ -0,0 +1,24 @@ +#ifndef FRAMEWORK_IPC_MUTEXHELPER_H_ +#define FRAMEWORK_IPC_MUTEXHELPER_H_ + +#include +#include + +class MutexHelper { +public: + MutexHelper(MutexIF* mutex, uint32_t timeoutMs) : + internalMutex(mutex) { + ReturnValue_t status = mutex->lockMutex(timeoutMs); + if(status != HasReturnvaluesIF::RETURN_OK){ + error << "MutexHelper: Lock of Mutex failed " << status << std::endl; + } + } + + + ~MutexHelper() { + internalMutex->unlockMutex(); + } +private: + MutexIF* internalMutex; +}; +#endif /* FRAMEWORK_IPC_MUTEXHELPER_H_ */ diff --git a/ipc/MutexIF.h b/ipc/MutexIF.h index da7a7c52..35786d6a 100644 --- a/ipc/MutexIF.h +++ b/ipc/MutexIF.h @@ -6,6 +6,57 @@ class MutexIF { public: static const uint32_t NO_TIMEOUT; //!< Needs to be defined in implementation. + + static const uint8_t INTERFACE_ID = CLASS_ID::MUTEX_IF; + /** + * The system lacked the necessary resources (other than memory) to initialize another mutex. + */ + static const ReturnValue_t NOT_ENOUGH_RESOURCES = MAKE_RETURN_CODE(1); + /** + * Insufficient memory to create or init Mutex + */ + static const ReturnValue_t INSUFFICIENT_MEMORY = MAKE_RETURN_CODE(2); + /** + * Caller does not have enough or right privilege + */ + static const ReturnValue_t NO_PRIVILEGE = MAKE_RETURN_CODE(3); + /** + * Wrong Attribute Setting + */ + static const ReturnValue_t WRONG_ATTRIBUTE_SETTING = MAKE_RETURN_CODE(4); + /** + * The mutex is already locked + */ + static const ReturnValue_t MUTEX_ALREADY_LOCKED = MAKE_RETURN_CODE(5); + /** + * Mutex object not found + */ + static const ReturnValue_t MUTEX_NOT_FOUND = MAKE_RETURN_CODE(6); + /** + * Mutex could not be locked because max amount of recursive locks + */ + static const ReturnValue_t MUTEX_MAX_LOCKS = MAKE_RETURN_CODE(7); + /** + * The current thread already owns this mutex + */ + static const ReturnValue_t CURR_THREAD_ALREADY_OWNS_MUTEX = MAKE_RETURN_CODE(8); + /** + * Current thread does not own this mutex + */ + static const ReturnValue_t CURR_THREAD_DOES_NOT_OWN_MUTEX = MAKE_RETURN_CODE(9); + /** + * The Mutex could not be blocked before timeout + */ + static const ReturnValue_t MUTEX_TIMEOUT = MAKE_RETURN_CODE(10); + /** + * Invalid Mutex ID + */ + static const ReturnValue_t MUTEX_INVALID_ID = MAKE_RETURN_CODE(11); + /** + * Mutex destroyed while waiting + */ + static const ReturnValue_t MUTEX_DESTROYED_WHILE_WAITING = MAKE_RETURN_CODE(12); + virtual ~MutexIF() {} virtual ReturnValue_t lockMutex(uint32_t timeoutMs) = 0; virtual ReturnValue_t unlockMutex() = 0; diff --git a/memory/LocalMemory.cpp b/memory/LocalMemory.cpp index e82d3ea2..2e97e5b9 100644 --- a/memory/LocalMemory.cpp +++ b/memory/LocalMemory.cpp @@ -8,7 +8,7 @@ LocalMemory::LocalMemory(object_id_t setObjectId) : SystemObject(setObjectId), commandQueue(NULL), memoryHelper(this, - commandQueue) { + NULL) { commandQueue = QueueFactory::instance()->createMessageQueue(); } @@ -52,7 +52,7 @@ ReturnValue_t LocalMemory::handleMemoryDump(uint32_t address, uint32_t size, } ReturnValue_t LocalMemory::initialize() { - return memoryHelper.initialize(); + return memoryHelper.initialize(commandQueue); } MessageQueueId_t LocalMemory::getCommandQueue() const { diff --git a/memory/MemoryHelper.cpp b/memory/MemoryHelper.cpp index 3dfd2b8b..4905875e 100644 --- a/memory/MemoryHelper.cpp +++ b/memory/MemoryHelper.cpp @@ -183,3 +183,13 @@ void MemoryHelper::handleMemoryCheckOrDump(CommandMessage* message) { queueToUse->sendMessage(lastSender, &reply); } } + +ReturnValue_t MemoryHelper::initialize(MessageQueueIF* queueToUse_) { + if(queueToUse_!=NULL){ + this->queueToUse = queueToUse_; + }else{ + return MessageQueueIF::NO_QUEUE; + } + + return initialize(); +} diff --git a/memory/MemoryHelper.h b/memory/MemoryHelper.h index d62774bf..2ff82eb3 100644 --- a/memory/MemoryHelper.h +++ b/memory/MemoryHelper.h @@ -24,12 +24,13 @@ private: bool busy; void handleMemoryLoad(CommandMessage* message); void handleMemoryCheckOrDump(CommandMessage* message); + ReturnValue_t initialize(); public: ReturnValue_t handleMemoryCommand(CommandMessage* message); void completeLoad( ReturnValue_t errorCode, const uint8_t* dataToCopy = NULL, const uint32_t size = 0, uint8_t* copyHere = NULL ); void completeDump( ReturnValue_t errorCode, const uint8_t* dataToCopy = NULL, const uint32_t size = 0); void swapMatrixCopy( uint8_t *out, const uint8_t *in, uint32_t totalSize, uint8_t datatypeSize); - ReturnValue_t initialize(); + ReturnValue_t initialize(MessageQueueIF* queueToUse_); MemoryHelper( HasMemoryIF* workOnThis, MessageQueueIF* useThisQueue ); ~MemoryHelper(); }; diff --git a/monitoring/TwoValueLimitMonitor.h b/monitoring/TwoValueLimitMonitor.h index 1e924856..c17ad433 100644 --- a/monitoring/TwoValueLimitMonitor.h +++ b/monitoring/TwoValueLimitMonitor.h @@ -19,11 +19,11 @@ public: } ReturnValue_t doCheck(T lowSample, T highSample) { T crossedLimit; - ReturnValue_t currentState = checkSample(lowSample, &crossedLimit); + ReturnValue_t currentState = this->checkSample(lowSample, &crossedLimit); if (currentState != HasReturnvaluesIF::RETURN_OK) { return this->monitorStateIs(currentState, lowSample, crossedLimit); } - currentState = checkSample(highSample, &crossedLimit); + currentState = this->checkSample(highSample, &crossedLimit); return this->monitorStateIs(currentState, highSample, crossedLimit); } protected: diff --git a/osal/Endiness.h b/osal/Endiness.h index 4d236ba0..65cc0a10 100644 --- a/osal/Endiness.h +++ b/osal/Endiness.h @@ -12,16 +12,19 @@ #define LITTLE_ENDIAN 1234 #endif - // This is a GCC C extension -#ifndef BYTE_ORDER +#ifndef BYTE_ORDER_SYSTEM +#ifdef __BYTE_ORDER__ #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -#define BYTE_ORDER BIG_ENDIAN +#define BYTE_ORDER_SYSTEM LITTLE_ENDIAN #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ -#define BYTE_ORDER LITTLE_ENDIAN +#define BYTE_ORDER_SYSTEM BIG_ENDIAN #else #error "Can't decide which end is which!" #endif +#else +#error __BYTE_ORDER__ not defined +#endif #endif diff --git a/osal/FreeRTOS/MessageQueue.cpp b/osal/FreeRTOS/MessageQueue.cpp index 0811188a..75505670 100644 --- a/osal/FreeRTOS/MessageQueue.cpp +++ b/osal/FreeRTOS/MessageQueue.cpp @@ -21,16 +21,16 @@ MessageQueue::~MessageQueue() { ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, MessageQueueMessage* message, bool ignoreFault) { - return sendMessage(sendTo, message, this->getId(), ignoreFault); + return sendMessageFrom(sendTo, message, this->getId(), ignoreFault); } ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessage* message) { - return sendToDefault(message, this->getId()); + return sendToDefaultFrom(message, this->getId()); } ReturnValue_t MessageQueue::reply(MessageQueueMessage* message) { if (this->lastPartner != 0) { - return sendMessage(this->lastPartner, message, this->getId()); + return sendMessageFrom(this->lastPartner, message, this->getId()); } else { //TODO: Good returnCode return HasReturnvaluesIF::RETURN_FAILED; @@ -49,8 +49,7 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message) { if (result == pdPASS){ return HasReturnvaluesIF::RETURN_OK; } else { - //TODO Queue Empty - return HasReturnvaluesIF::RETURN_FAILED; + return MessageQueueIF::EMPTY; } } @@ -73,7 +72,7 @@ void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) { this->defaultDestination = defaultDestination; } -ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, +ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessage* message, MessageQueueId_t sentFrom, bool ignoreFault) { message->setSender(sentFrom); @@ -83,15 +82,14 @@ ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, if (!ignoreFault) { //TODO errr reporter } - //TODO queue is full - return HasReturnvaluesIF::RETURN_FAILED; + return MessageQueueIF::FULL; } return HasReturnvaluesIF::RETURN_OK; } -ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessage* message, +ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessage* message, MessageQueueId_t sentFrom, bool ignoreFault) { - return 0; + return sendMessageFrom(defaultDestination,message,sentFrom,ignoreFault); } MessageQueueId_t MessageQueue::getDefaultDestination() const { diff --git a/osal/FreeRTOS/MessageQueue.h b/osal/FreeRTOS/MessageQueue.h index 1fdb96a4..ee237e29 100644 --- a/osal/FreeRTOS/MessageQueue.h +++ b/osal/FreeRTOS/MessageQueue.h @@ -117,7 +117,7 @@ public: * This variable is set to zero by default. * \param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. */ - virtual ReturnValue_t sendMessage( MessageQueueId_t sendTo, MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); + virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); /** * \brief The sendToDefault method sends a queue message to the default destination. * \details In all other aspects, it works identical to the sendMessage method. @@ -125,7 +125,7 @@ public: * \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. * This variable is set to zero by default. */ - virtual ReturnValue_t sendToDefault( MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); + virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); /** * \brief This method is a simple setter for the default destination. */ diff --git a/osal/FreeRTOS/main.cpp b/osal/FreeRTOS/main.cpp index 3e760984..39b87c06 100644 --- a/osal/FreeRTOS/main.cpp +++ b/osal/FreeRTOS/main.cpp @@ -1,31 +1,32 @@ //entry point into "bsp" -void init(void); - -#include -#include -#include "task.h" - - -void initTask(void *parameters) { - init(); -} - -int main(void) { - - if ( pdPASS - != xTaskCreate(initTask, "init", 512, NULL, - configMAX_PRIORITIES - 1, NULL)) { - //print_uart0("Could not create task1\r\n"); - } - - vTaskStartScheduler(); - - //Scheduler should never return - - //print_uart0("This is bad\n"); - - for (;;) - ; - - return 0; -} +//TODO This can be done mission dependent and some low level calls before vTaskStartScheduler might be important +//void init(void); +// +//#include +//#include +//#include "task.h" +// +// +//void initTask(void *parameters) { +// init(); +//} +// +//int main(void) { +// +// if ( pdPASS +// != xTaskCreate(initTask, "init", 512, NULL, +// configMAX_PRIORITIES - 1, NULL)) { +// //print_uart0("Could not create task1\r\n"); +// } +// +// vTaskStartScheduler(); +// +// //Scheduler should never return +// +// //print_uart0("This is bad\n"); +// +// for (;;) +// ; +// +// return 0; +//} diff --git a/osal/OperatingSystemIF.h b/osal/OperatingSystemIF.h deleted file mode 100644 index 7e7948f6..00000000 --- a/osal/OperatingSystemIF.h +++ /dev/null @@ -1,144 +0,0 @@ -#ifndef FRAMEWORK_OSAL_OPERATINGSYSTEMIF_H_ -#define FRAMEWORK_OSAL_OPERATINGSYSTEMIF_H_ - -#include - -class OperatingSystemIF { -public: - static const uint8_t INTERFACE_ID = CLASS_ID::OPERATING_SYSTEM_ABSTRACTION; - - //API Status codes, must be implemented by the Operating System (TODO comments based on rtems status.h): - - /** - * This is the status to indicate successful completion. - */ - static const ReturnValue_t SUCCESSFUL = MAKE_RETURN_CODE(0); - /** - * This is the status to indicate that a thread exited. - */ - static const ReturnValue_t TASK_EXITTED = MAKE_RETURN_CODE(1); - /** - * This is the status to indicate multiprocessing is not configured. - */ - static const ReturnValue_t MP_NOT_CONFIGURED = MAKE_RETURN_CODE(2); - /** - * This is the status to indicate that the object name was invalid. - */ - static const ReturnValue_t INVALID_NAME = MAKE_RETURN_CODE(3); - /** - * This is the status to indicate that the object Id was invalid. - */ - static const ReturnValue_t INVALID_ID = MAKE_RETURN_CODE(4); - /** - * This is the status to indicate you have attempted to create too many - * instances of a particular object class. - * - * Used for full messages Queues as well - */ - static const ReturnValue_t TOO_MANY = MAKE_RETURN_CODE(5); - /** - * This is the status to indicate that a blocking directive timed out. - */ - static const ReturnValue_t TIMEOUT = MAKE_RETURN_CODE(6); - /** - * This is the status to indicate the the object was deleted - * while the task was blocked waiting. - */ - static const ReturnValue_t OBJECT_WAS_DELETED = MAKE_RETURN_CODE(7); - /** - * This is the status to indicate that the specified size was invalid. - */ - static const ReturnValue_t INVALID_SIZE = MAKE_RETURN_CODE(8); - /** - * This is the status to indicate that the specified address is invalid. - */ - static const ReturnValue_t INVALID_ADDRESS = MAKE_RETURN_CODE(9); - /** - * This is the status to indicate that the specified number was invalid. - */ - static const ReturnValue_t INVALID_NUMBER = MAKE_RETURN_CODE(10); - /** - * This is the status to indicate that the item has not been initialized. - */ - static const ReturnValue_t NOT_DEFINED =MAKE_RETURN_CODE(11); - /** - * This is the status to indicate that the object still has - * resources in use. - */ - static const ReturnValue_t RESOURCE_IN_USE =MAKE_RETURN_CODE(12); - /** - * This is the status to indicate that the request was not satisfied. - */ - static const ReturnValue_t UNSATISFIED =MAKE_RETURN_CODE(13); - /** - * Indicates that a Message Queue is empty (unable to allocate it) - */ - static const ReturnValue_t QUEUE_EMPTY =MAKE_RETURN_CODE(14); - /** - * This is the status to indicate that a thread is in wrong state - * was in the wrong execution state for the requested operation. - */ - static const ReturnValue_t INCORRECT_STATE =MAKE_RETURN_CODE(15); - /** - * This is the status to indicate thread was already suspended. - */ - static const ReturnValue_t ALREADY_SUSPENDED = MAKE_RETURN_CODE(16); - /** - * This is the status to indicate that the operation is illegal - * on calling thread. - */ - static const ReturnValue_t ILLEGAL_ON_SELF =MAKE_RETURN_CODE(17); - /** - * This is the status to indicate illegal for remote object. - */ - static const ReturnValue_t ILLEGAL_ON_REMOTE_OBJECT=MAKE_RETURN_CODE(18); - /** - * This is the status to indicate that the operation should not be - * called from from this excecution environment. - */ - static const ReturnValue_t CALLED_FROM_ISR=MAKE_RETURN_CODE(19); - /** - * This is the status to indicate that an invalid thread priority - * was provided. - */ - static const ReturnValue_t INVALID_PRIORITY=MAKE_RETURN_CODE(20); - /** - * This is the status to indicate that the specified date/time was invalid. - */ - static const ReturnValue_t INVALID_CLOCK=MAKE_RETURN_CODE(21); - /** - * This is the status to indicate that the specified node Id was invalid. - */ - static const ReturnValue_t INVALID_NODE=MAKE_RETURN_CODE(22); - /** - * This is the status to indicate that the directive was not configured. - */ - static const ReturnValue_t NOT_CONFIGURED=MAKE_RETURN_CODE(23); - /** - * This is the status to indicate that the caller is not the - * owner of the resource. - */ - static const ReturnValue_t NOT_OWNER_OF_RESOURCE=MAKE_RETURN_CODE(24); - /** - * This is the status to indicate the the directive or requested - * portion of the directive is not implemented. - */ - static const ReturnValue_t NOT_IMPLEMENTED=MAKE_RETURN_CODE(25); - /** - * This is the status to indicate that an internal RTEMS inconsistency - * was detected. - */ - static const ReturnValue_t INTERNAL_ERROR=MAKE_RETURN_CODE(26); - /** - * This is the status to indicate that the directive attempted to allocate - * memory but was unable to do so. - */ - static const ReturnValue_t NO_MEMORY=MAKE_RETURN_CODE(27); - /** - * This is the status to indicate an driver IO error. - */ - static const ReturnValue_t IO_ERROR=MAKE_RETURN_CODE(28); - - virtual ~OperatingSystemIF() {}; -}; -#endif /* FRAMEWORK_OSAL_OPERATINGSYSTEMIF_H_ */ diff --git a/osal/Linux/Clock.cpp b/osal/linux/Clock.cpp similarity index 64% rename from osal/Linux/Clock.cpp rename to osal/linux/Clock.cpp index d2ce166f..e24a4fe4 100644 --- a/osal/Linux/Clock.cpp +++ b/osal/linux/Clock.cpp @@ -8,25 +8,21 @@ #include //#include - +uint16_t Clock::leapSeconds = 0; +MutexIF* Clock::timeMutex = NULL; uint32_t Clock::getTicksPerSecond(void){ - //TODO This function returns the ticks per second for thread ticks not clock ticks -// timespec ticks; -// int status = clock_getres(CLOCK_REALTIME,&ticks); -// -// if(status!=0){ -// //TODO errno -// return 0xFFFFFFFF; -// } -// uint32_t resolution = 1e9 / ticks.tv_nsec; - uint32_t resolution = sysconf(_SC_CLK_TCK); - return resolution; + uint32_t ticks = sysconf(_SC_CLK_TCK); + return ticks; } ReturnValue_t Clock::setClock(const TimeOfDay_t* time) { - //TODO timeOfDay conversion timespec timeUnix; + timeval timeTimeval; + convertTimeOfDayToTimeval(time,&timeTimeval); + timeUnix.tv_sec = timeTimeval.tv_sec; + timeUnix.tv_nsec = (__syscall_slong_t) timeTimeval.tv_usec * 1000; + int status = clock_settime(CLOCK_REALTIME,&timeUnix); if(status!=0){ //TODO errno @@ -109,14 +105,6 @@ ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) { //TODO errno return HasReturnvaluesIF::RETURN_FAILED; } - timespec ticks; - status = clock_getres(CLOCK_REALTIME,&ticks); - if(status!=0){ - //TODO errno - return HasReturnvaluesIF::RETURN_FAILED; - } - uint32_t resolution = 1e9 / ticks.tv_nsec; - struct tm* timeInfo; timeInfo = gmtime(&timeUnix.tv_sec); @@ -126,7 +114,7 @@ ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) { time->hour = timeInfo->tm_hour; time->minute = timeInfo->tm_min; time->second = timeInfo->tm_sec; - time->ticks = (timeUnix.tv_nsec / (double) 1e9) * resolution; + time->usecond = timeUnix.tv_nsec / 1000.0; return HasReturnvaluesIF::RETURN_OK; } @@ -143,34 +131,81 @@ ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, fromTm.tm_min = from->minute; fromTm.tm_sec = from->second; - timespec ticks; - uint32_t status = clock_getres(CLOCK_REALTIME,&ticks); - if(status!=0){ - //TODO errno - return HasReturnvaluesIF::RETURN_FAILED; - } - uint32_t resolution = 1e9 / ticks.tv_nsec; - to->tv_sec = mktime(&fromTm); - to->tv_usec = (from->ticks /(double) resolution) * 1e6; - - - + to->tv_usec = from->usecond; return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) { - return HasReturnvaluesIF::RETURN_FAILED; + *JD2000 = (time.tv_sec - 946728000. + time.tv_usec / 1000000.) / 24. + / 3600.; + return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) { - return HasReturnvaluesIF::RETURN_FAILED; + //SHOULDDO: works not for dates in the past (might have less leap seconds) + if (timeMutex == NULL) { + return HasReturnvaluesIF::RETURN_FAILED; + } + + uint16_t leapSeconds; + ReturnValue_t result = getLeapSeconds(&leapSeconds); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + timeval leapSeconds_timeval = { 0, 0 }; + leapSeconds_timeval.tv_sec = leapSeconds; + + //initial offset between UTC and TAI + timeval UTCtoTAI1972 = { 10, 0 }; + + timeval TAItoTT = { 32, 184000 }; + + *tt = utc + leapSeconds_timeval + UTCtoTAI1972 + TAItoTT; + + return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) { - return HasReturnvaluesIF::RETURN_FAILED; + if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){ + return HasReturnvaluesIF::RETURN_FAILED; + } + ReturnValue_t result = timeMutex->lockMutex(MutexIF::NO_TIMEOUT); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + leapSeconds = leapSeconds_; + + result = timeMutex->unlockMutex(); + return result; } ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) { - return HasReturnvaluesIF::RETURN_FAILED; + if(timeMutex==NULL){ + return HasReturnvaluesIF::RETURN_FAILED; + } + ReturnValue_t result = timeMutex->lockMutex(MutexIF::NO_TIMEOUT); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + *leapSeconds_ = leapSeconds; + + result = timeMutex->unlockMutex(); + return result; +} + +ReturnValue_t Clock::checkOrCreateClockMutex(){ + if(timeMutex==NULL){ + MutexFactory* mutexFactory = MutexFactory::instance(); + if (mutexFactory == NULL) { + return HasReturnvaluesIF::RETURN_FAILED; + } + timeMutex = mutexFactory->createMutex(); + if (timeMutex == NULL) { + return HasReturnvaluesIF::RETURN_FAILED; + } + } + return HasReturnvaluesIF::RETURN_OK; } diff --git a/osal/linux/FixedTimeslotTask.cpp b/osal/linux/FixedTimeslotTask.cpp new file mode 100644 index 00000000..67a2b2d6 --- /dev/null +++ b/osal/linux/FixedTimeslotTask.cpp @@ -0,0 +1,89 @@ +#include +#include +#include +#include +#include +#include + + +uint32_t FixedTimeslotTask::deadlineMissedCount = 0; +const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = PTHREAD_STACK_MIN; + +FixedTimeslotTask::FixedTimeslotTask(const char* name_, int priority_, size_t stackSize_, uint32_t periodMs_):PosixThread(name_,priority_,stackSize_),pst(periodMs_),started(false) { +} + +FixedTimeslotTask::~FixedTimeslotTask() { + +} + +void* FixedTimeslotTask::taskEntryPoint(void* arg) { + //The argument is re-interpreted as PollingTask. + FixedTimeslotTask *originalTask(reinterpret_cast(arg)); + //The task's functionality is called. + originalTask->taskFunctionality(); + return NULL; +} + +ReturnValue_t FixedTimeslotTask::startTask() { + started = true; + createTask(&taskEntryPoint,this); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) { + return PosixThread::sleep((uint64_t)ms*1000000); +} + +uint32_t FixedTimeslotTask::getPeriodMs() const { + return pst.getLengthMs(); +} + +ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, + uint32_t slotTimeMs, int8_t executionStep) { + pst.addSlot(componentId, slotTimeMs, executionStep, this); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t FixedTimeslotTask::checkSequence() const { + return pst.checkSequence(); +} + +void FixedTimeslotTask::taskFunctionality() { + //Like FreeRTOS pthreads are running as soon as they are created + if (!started) { + suspend(); + } + // A local iterator for the Polling Sequence Table is created to find the start time for the first entry. + std::list::iterator it = pst.current; + + //The start time for the first entry is read. + uint64_t lastWakeTime = getCurrentMonotonicTimeMs(); + uint64_t interval = pst.getIntervalToNextSlotMs(); + + + //The task's "infinite" inner loop is entered. + while (1) { + if (pst.slotFollowsImmediately()) { + //Do nothing + } else { + //The interval for the next polling slot is selected. + interval = this->pst.getIntervalToPreviousSlotMs(); + //The period is checked and restarted with the new interval. + //If the deadline was missed, the deadlineMissedFunc is called. + if(!PosixThread::delayUntil(&lastWakeTime,interval)) { + //No time left on timer -> we missed the deadline + missedDeadlineCounter(); + } + } + //The device handler for this slot is executed and the next one is chosen. + this->pst.executeAndAdvance(); + } +} + +void FixedTimeslotTask::missedDeadlineCounter() { + FixedTimeslotTask::deadlineMissedCount++; + if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) { + error << "PST missed " << FixedTimeslotTask::deadlineMissedCount + << " deadlines." << std::endl; + } +} diff --git a/osal/linux/FixedTimeslotTask.h b/osal/linux/FixedTimeslotTask.h new file mode 100644 index 00000000..6350f347 --- /dev/null +++ b/osal/linux/FixedTimeslotTask.h @@ -0,0 +1,58 @@ +#ifndef FRAMEWORK_OSAL_LINUX_FIXEDTIMESLOTTASK_H_ +#define FRAMEWORK_OSAL_LINUX_FIXEDTIMESLOTTASK_H_ + +#include +#include +#include +#include + +class FixedTimeslotTask: public FixedTimeslotTaskIF, public PosixThread { +public: + FixedTimeslotTask(const char* name_, int priority_, size_t stackSize_, uint32_t periodMs_); + virtual ~FixedTimeslotTask(); + + virtual ReturnValue_t startTask(); + + virtual ReturnValue_t sleepFor(uint32_t ms); + + virtual uint32_t getPeriodMs() const; + + virtual ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs, int8_t executionStep); + virtual ReturnValue_t checkSequence() const; + + /** + * This static function can be used as #deadlineMissedFunc. + * It counts missedDeadlines and prints the number of missed deadlines every 10th time. + */ + static void missedDeadlineCounter(); + + /** + * A helper variable to count missed deadlines. + */ + static uint32_t deadlineMissedCount; + +protected: + /** + * @brief This function holds the main functionality of the thread. + * + * + * @details Holding the main functionality of the task, this method is most important. + * It links the functionalities provided by FixedSlotSequence with the OS's System Calls + * to keep the timing of the periods. + */ + virtual void taskFunctionality(); + +private: + /** + * @brief This is the entry point in a new thread. + * + * @details This method, that is the entry point in the new thread and calls taskFunctionality of the child class. + * Needs a valid pointer to the derived class. + */ + static void* taskEntryPoint(void* arg); + FixedSlotSequence pst; + + bool started; +}; + +#endif /* FRAMEWORK_OSAL_LINUX_FIXEDTIMESLOTTASK_H_ */ diff --git a/osal/linux/InternalErrorCodes.cpp b/osal/linux/InternalErrorCodes.cpp new file mode 100644 index 00000000..7f83663b --- /dev/null +++ b/osal/linux/InternalErrorCodes.cpp @@ -0,0 +1,14 @@ +#include + +ReturnValue_t InternalErrorCodes::translate(uint8_t code) { + //TODO This class can be removed + return HasReturnvaluesIF::RETURN_FAILED; +} + +InternalErrorCodes::InternalErrorCodes() { +} + +InternalErrorCodes::~InternalErrorCodes() { + +} + diff --git a/osal/linux/MessageQueue.cpp b/osal/linux/MessageQueue.cpp new file mode 100644 index 00000000..ab07935e --- /dev/null +++ b/osal/linux/MessageQueue.cpp @@ -0,0 +1,258 @@ +#include +#include /* For O_* constants */ +#include /* For mode constants */ +#include +#include +#include +#include + + +MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size) : + id(0), lastPartner(0), defaultDestination(NO_QUEUE), internalErrorReporter( + NULL) { + //debug << "MessageQueue::MessageQueue: Creating a queue" << std::endl; + mq_attr attributes; + this->id = 0; + //Set attributes + attributes.mq_curmsgs = 0; + attributes.mq_maxmsg = message_depth; + attributes.mq_msgsize = max_message_size; + attributes.mq_flags = 0; //Flags are ignored on Linux during mq_open + + //Set the name of the queue + sprintf(name, "/Q%u\n", queueCounter++); + + //Create a nonblocking queue if the name is available (the queue is Read and writable for the owner as well as the group) + mqd_t tempId = mq_open(name, O_NONBLOCK | O_RDWR | O_CREAT | O_EXCL, + S_IWUSR | S_IREAD | S_IWGRP | S_IRGRP | S_IROTH | S_IWOTH, &attributes); + if (tempId == -1) { + //An error occured during open + //We need to distinguish if it is caused by an already created queue + if (errno == EEXIST) { + //There's another queue with the same name + //We unlink the other queue + int status = mq_unlink(name); + if (status != 0) { + error << "mq_unlink Failed with status: " << strerror(errno) + << std::endl; + } else { + //Successful unlinking, try to open again + mqd_t tempId = mq_open(name, + O_NONBLOCK | O_RDWR | O_CREAT | O_EXCL, + S_IWUSR | S_IREAD | S_IWGRP | S_IRGRP, &attributes); + if (tempId != -1) { + //Successful mq_open + this->id = tempId; + return; + } + } + } + //Failed either the first time or the second time + error << "MessageQueue::MessageQueue: Creating Queue " << std::hex + << name << std::dec << " failed with status: " + << strerror(errno) << std::endl; + } else { + //Successful mq_open call + this->id = tempId; + } +} + +MessageQueue::~MessageQueue() { + int status = mq_close(this->id); + if(status != 0){ + error << "MessageQueue::Destructor: mq_close Failed with status: " << strerror(errno) <getId(), false); +} + +ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessage* message) { + return sendToDefaultFrom(message, this->getId()); +} + +ReturnValue_t MessageQueue::reply(MessageQueueMessage* message) { + if (this->lastPartner != 0) { + return sendMessageFrom(this->lastPartner, message, this->getId()); + } else { + //TODO: Good returnCode + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message, + MessageQueueId_t* receivedFrom) { + ReturnValue_t status = this->receiveMessage(message); + *receivedFrom = this->lastPartner; + return status; +} + +ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message) { + unsigned int messagePriority = 0; + int status = mq_receive(id,reinterpret_cast(message->getBuffer()),message->MAX_MESSAGE_SIZE,&messagePriority); + if (status > 0) { + this->lastPartner = message->getSender(); + //Check size of incoming message. + if (message->messageSize < message->getMinimumMessageSize()) { + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; + }else if(status==0){ + //Success but no message received + return MessageQueueIF::EMPTY; + } else { + //No message was received. Keep lastPartner anyway, I might send something later. + //But still, delete packet content. + memset(message->getData(), 0, message->MAX_DATA_SIZE); + switch(errno){ + case EAGAIN: + //O_NONBLOCK or MQ_NONBLOCK was set and there are no messages currently on the specified queue. + return MessageQueueIF::EMPTY; + case EBADF: + //mqdes doesn't represent a valid queue open for reading. + error << "MessageQueue::receive: configuration error " << strerror(errno) << std::endl; + /*NO BREAK*/ + case EINVAL: + /* + * This value indicates one of the following: + * * The pointer to the buffer for storing the received message, msg_ptr, is NULL. + * * The number of bytes requested, msg_len is less than zero. + * * msg_len is anything other than the mq_msgsize of the specified queue, and the QNX extended option MQ_READBUF_DYNAMIC hasn't been set in the queue's mq_flags. + */ + error << "MessageQueue::receive: configuration error " << strerror(errno) << std::endl; + /*NO BREAK*/ + case EMSGSIZE: + /* + * This value indicates one of the following: + * * the QNX extended option MQ_READBUF_DYNAMIC hasn't been set, and the given msg_len is shorter than the mq_msgsize for the given queue. + * * the extended option MQ_READBUF_DYNAMIC has been set, but the given msg_len is too short for the message that would have been received. + */ + error << "MessageQueue::receive: configuration error " << strerror(errno) << std::endl; + /*NO BREAK*/ + case EINTR: + //The operation was interrupted by a signal. + default: + + return HasReturnvaluesIF::RETURN_FAILED; + } + + } +} + +MessageQueueId_t MessageQueue::getLastPartner() const { + return this->lastPartner; +} + +ReturnValue_t MessageQueue::flush(uint32_t* count) { + mq_attr attrib; + int status = mq_getattr(id,&attrib); + if(status != 0){ + switch(errno){ + case EBADF: + //mqdes doesn't represent a valid message queue. + error << "MessageQueue::flush configuration error, called flush with an invalid queue ID" << std::endl; + /*NO BREAK*/ + case EINVAL: + //mq_attr is NULL + default: + return HasReturnvaluesIF::RETURN_FAILED; + } + } + *count = attrib.mq_curmsgs; + attrib.mq_curmsgs = 0; + status = mq_setattr(id,&attrib,NULL); + if(status != 0){ + switch(errno){ + case EBADF: + //mqdes doesn't represent a valid message queue. + error << "MessageQueue::flush configuration error, called flush with an invalid queue ID" << std::endl; + /*NO BREAK*/ + case EINVAL: + /* + * This value indicates one of the following: + * * mq_attr is NULL. + * * MQ_MULT_NOTIFY had been set for this queue, and the given mq_flags includes a 0 in the MQ_MULT_NOTIFY bit. Once MQ_MULT_NOTIFY has been turned on, it may never be turned off. + * + */ + default: + return HasReturnvaluesIF::RETURN_FAILED; + } + } + return HasReturnvaluesIF::RETURN_OK; +} + +MessageQueueId_t MessageQueue::getId() const { + return this->id; +} + +void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) { + this->defaultDestination = defaultDestination; +} + +ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, + MessageQueueMessage* message, MessageQueueId_t sentFrom, + bool ignoreFault) { + + message->setSender(sentFrom); + int result = mq_send(sendTo, + reinterpret_cast(message->getBuffer()), message->messageSize,0); + + //TODO: Check if we're in ISR. + if (result != 0 && !ignoreFault) { + if (internalErrorReporter == NULL) { + internalErrorReporter = objectManager->get( + objects::INTERNAL_ERROR_REPORTER); + } + if (internalErrorReporter != NULL) { + internalErrorReporter->queueMessageNotSent(); + } + switch(errno){ + case EAGAIN: + //The O_NONBLOCK flag was set when opening the queue, or the MQ_NONBLOCK flag was set in its attributes, and the specified queue is full. + return MessageQueueIF::FULL; + case EBADF: + //mq_des doesn't represent a valid message queue descriptor, or mq_des wasn't opened for writing. + error << "MessageQueue::sendMessage: Configuration error " << strerror(errno) << " in mq_send mqSendTo: " << sendTo << " sent from " << sentFrom << std::endl; + /*NO BREAK*/ + case EINTR: + //The call was interrupted by a signal. + case EINVAL: + /* + * This value indicates one of the following: + * * msg_ptr is NULL. + * * msg_len is negative. + * * msg_prio is greater than MQ_PRIO_MAX. + * * msg_prio is less than 0. + * * MQ_PRIO_RESTRICT is set in the mq_attr of mq_des, and msg_prio is greater than the priority of the calling process. + * */ + error << "MessageQueue::sendMessage: Configuration error " << strerror(errno) << " in mq_send" << std::endl; + /*NO BREAK*/ + case EMSGSIZE: + //The msg_len is greater than the msgsize associated with the specified queue. + default: + return HasReturnvaluesIF::RETURN_FAILED; + } + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessage* message, + MessageQueueId_t sentFrom, bool ignoreFault) { + return sendMessageFrom(defaultDestination, message, sentFrom, ignoreFault); +} + +MessageQueueId_t MessageQueue::getDefaultDestination() const { + return this->defaultDestination; +} + +bool MessageQueue::isDefaultDestinationSet() const { + return (defaultDestination != NO_QUEUE); +} + +uint16_t MessageQueue::queueCounter = 0; diff --git a/osal/linux/MessageQueue.h b/osal/linux/MessageQueue.h new file mode 100644 index 00000000..ec3fa78e --- /dev/null +++ b/osal/linux/MessageQueue.h @@ -0,0 +1,169 @@ +#ifndef MESSAGEQUEUE_H_ +#define MESSAGEQUEUE_H_ + +#include +#include +#include +/** + * @brief This class manages sending and receiving of message queue messages. + * + * @details Message queues are used to pass asynchronous messages between processes. + * They work like post boxes, where all incoming messages are stored in FIFO + * order. This class creates a new receiving queue and provides methods to fetch + * received messages. Being a child of MessageQueueSender, this class also provides + * methods to send a message to a user-defined or a default destination. In addition + * it also provides a reply method to answer to the queue it received its last message + * from. + * The MessageQueue should be used as "post box" for a single owning object. So all + * message queue communication is "n-to-one". + * For creating the queue, as well as sending and receiving messages, the class makes + * use of the operating system calls provided. + * \ingroup message_queue + */ +class MessageQueue : public MessageQueueIF { +public: + /** + * @brief The constructor initializes and configures the message queue. + * @details By making use of the according operating system call, a message queue is created + * and initialized. The message depth - the maximum number of messages to be + * buffered - may be set with the help of a parameter, whereas the message size is + * automatically set to the maximum message queue message size. The operating system + * sets the message queue id, or i case of failure, it is set to zero. + * @param message_depth The number of messages to be buffered before passing an error to the + * sender. Default is three. + * @param max_message_size With this parameter, the maximum message size can be adjusted. + * This should be left default. + */ + MessageQueue( size_t message_depth = 3, size_t max_message_size = MessageQueueMessage::MAX_MESSAGE_SIZE ); + /** + * @brief The destructor deletes the formerly created message queue. + * @details This is accomplished by using the delete call provided by the operating system. + */ + virtual ~MessageQueue(); + /** + * @brief This operation sends a message to the given destination. + * @details It directly uses the sendMessage call of the MessageQueueSender parent, but passes its + * queue id as "sentFrom" parameter. + * @param sendTo This parameter specifies the message queue id of the destination message queue. + * @param message A pointer to a previously created message, which is sent. + * @param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. + */ + virtual ReturnValue_t sendMessage(MessageQueueId_t sendTo, + MessageQueueMessage* message, bool ignoreFault = false ); + /** + * @brief This operation sends a message to the default destination. + * @details As in the sendMessage method, this function uses the sendToDefault call of the + * MessageQueueSender parent class and adds its queue id as "sentFrom" information. + * @param message A pointer to a previously created message, which is sent. + */ + virtual ReturnValue_t sendToDefault( MessageQueueMessage* message ); + /** + * @brief This operation sends a message to the last communication partner. + * @details This operation simplifies answering an incoming message by using the stored + * lastParnter information as destination. If there was no message received yet + * (i.e. lastPartner is zero), an error code is returned. + * @param message A pointer to a previously created message, which is sent. + */ + ReturnValue_t reply( MessageQueueMessage* message ); + + /** + * @brief This function reads available messages from the message queue and returns the sender. + * @details It works identically to the other receiveMessage call, but in addition returns the + * sender's queue id. + * @param message A pointer to a message in which the received data is stored. + * @param receivedFrom A pointer to a queue id in which the sender's id is stored. + */ + ReturnValue_t receiveMessage(MessageQueueMessage* message, + MessageQueueId_t *receivedFrom); + + /** + * @brief This function reads available messages from the message queue. + * @details If data is available it is stored in the passed message pointer. The message's + * original content is overwritten and the sendFrom information is stored in the + * lastPartner attribute. Else, the lastPartner information remains untouched, the + * message's content is cleared and the function returns immediately. + * @param message A pointer to a message in which the received data is stored. + */ + ReturnValue_t receiveMessage(MessageQueueMessage* message); + /** + * Deletes all pending messages in the queue. + * @param count The number of flushed messages. + * @return RETURN_OK on success. + */ + ReturnValue_t flush(uint32_t* count); + /** + * @brief This method returns the message queue id of the last communication partner. + */ + MessageQueueId_t getLastPartner() const; + /** + * @brief This method returns the message queue id of this class's message queue. + */ + MessageQueueId_t getId() const; + /** + * \brief With the sendMessage call, a queue message is sent to a receiving queue. + * \details This method takes the message provided, adds the sentFrom information and passes + * it on to the destination provided with an operating system call. The OS's return + * value is returned. + * \param sendTo This parameter specifies the message queue id to send the message to. + * \param message This is a pointer to a previously created message, which is sent. + * \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. + * This variable is set to zero by default. + * \param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. + */ + virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, MessageQueueMessage* message, MessageQueueId_t sentFrom, bool ignoreFault = false ); + /** + * \brief The sendToDefault method sends a queue message to the default destination. + * \details In all other aspects, it works identical to the sendMessage method. + * \param message This is a pointer to a previously created message, which is sent. + * \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. + * This variable is set to zero by default. + */ + virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); + /** + * \brief This method is a simple setter for the default destination. + */ + void setDefaultDestination(MessageQueueId_t defaultDestination); + /** + * \brief This method is a simple getter for the default destination. + */ + MessageQueueId_t getDefaultDestination() const; + + bool isDefaultDestinationSet() const; +private: + /** + * @brief The class stores the queue id it got assigned from the operating system in this attribute. + * If initialization fails, the queue id is set to zero. + */ + MessageQueueId_t id; + /** + * @brief In this attribute, the queue id of the last communication partner is stored + * to allow for replying. + */ + MessageQueueId_t lastPartner; + /** + * @brief The message queue's name -a user specific information for the operating system- is + * generated automatically with the help of this static counter. + */ + /** + * \brief This attribute stores a default destination to send messages to. + * \details It is stored to simplify sending to always-the-same receiver. The attribute may + * be set in the constructor or by a setter call to setDefaultDestination. + */ + MessageQueueId_t defaultDestination; + + /** + * \brief This attribute stores a reference to the internal error reporter for reporting full queues. + * \details In the event of a full destination queue, the reporter will be notified. The reference is set + * by lazy loading + */ + InternalErrorReporterIF *internalErrorReporter; + + /** + * The name of the message queue, stored for unlinking + */ + char name[5]; + + static uint16_t queueCounter; +}; + +#endif /* MESSAGEQUEUE_H_ */ diff --git a/osal/linux/Mutex.cpp b/osal/linux/Mutex.cpp new file mode 100644 index 00000000..055270b3 --- /dev/null +++ b/osal/linux/Mutex.cpp @@ -0,0 +1,98 @@ +#include +#include +#include + +const uint32_t MutexIF::NO_TIMEOUT = 0; +uint8_t Mutex::count = 0; + + +#include +#include + +Mutex::Mutex() { + pthread_mutexattr_t mutexAttr; + int status = pthread_mutexattr_init(&mutexAttr); + if (status != 0) { + error << "Mutex: Attribute init failed with: " << strerror(status) << std::endl; + } + status = pthread_mutexattr_setprotocol(&mutexAttr, PTHREAD_PRIO_INHERIT); + if (status != 0) { + error << "Mutex: Attribute set PRIO_INHERIT failed with: " << strerror(status) + << std::endl; + } + status = pthread_mutex_init(&mutex, &mutexAttr); + if (status != 0) { + error << "Mutex: creation with name, id " << mutex.__data.__count + << ", " << " failed with " << strerror(status) << std::endl; + } + //After a mutex attributes object has been used to initialize one or more mutexes, any function affecting the attributes object (including destruction) shall not affect any previously initialized mutexes. + status = pthread_mutexattr_destroy(&mutexAttr); + if (status != 0) { + error << "Mutex: Attribute destroy failed with " << strerror(status) << std::endl; + } +} + +Mutex::~Mutex() { + //No Status check yet + pthread_mutex_destroy(&mutex); +} + +ReturnValue_t Mutex::lockMutex(uint32_t timeoutMs) { + int status = 0; + if (timeoutMs != MutexIF::NO_TIMEOUT) { + timespec timeOut; + clock_gettime(CLOCK_REALTIME, &timeOut); + uint64_t nseconds = timeOut.tv_sec * 1000000000 + timeOut.tv_nsec; + nseconds += timeoutMs * 1000000; + timeOut.tv_sec = nseconds / 1000000000; + timeOut.tv_nsec = nseconds - timeOut.tv_sec * 1000000000; + status = pthread_mutex_timedlock(&mutex, &timeOut); + } else { + status = pthread_mutex_lock(&mutex); + } + switch (status) { + case EINVAL: + //The mutex was created with the protocol attribute having the value PTHREAD_PRIO_PROTECT and the calling thread's priority is higher than the mutex's current priority ceiling. + return WRONG_ATTRIBUTE_SETTING; + //The process or thread would have blocked, and the abs_timeout parameter specified a nanoseconds field value less than zero or greater than or equal to 1000 million. + //The value specified by mutex does not refer to an initialized mutex object. + //return MUTEX_NOT_FOUND; + case EBUSY: + //The mutex could not be acquired because it was already locked. + return MUTEX_ALREADY_LOCKED; + case ETIMEDOUT: + //The mutex could not be locked before the specified timeout expired. + return MUTEX_TIMEOUT; + case EAGAIN: + //The mutex could not be acquired because the maximum number of recursive locks for mutex has been exceeded. + return MUTEX_MAX_LOCKS; + case EDEADLK: + //A deadlock condition was detected or the current thread already owns the mutex. + return CURR_THREAD_ALREADY_OWNS_MUTEX; + case 0: + //Success + return HasReturnvaluesIF::RETURN_OK; + default: + return HasReturnvaluesIF::RETURN_FAILED; + }; +} + +ReturnValue_t Mutex::unlockMutex() { + int status = pthread_mutex_unlock(&mutex); + switch (status) { + case EINVAL: + //The value specified by mutex does not refer to an initialized mutex object. + return MUTEX_NOT_FOUND; + case EAGAIN: + //The mutex could not be acquired because the maximum number of recursive locks for mutex has been exceeded. + return MUTEX_MAX_LOCKS; + case EPERM: + //The current thread does not own the mutex. + return CURR_THREAD_DOES_NOT_OWN_MUTEX; + case 0: + //Success + return HasReturnvaluesIF::RETURN_OK; + default: + return HasReturnvaluesIF::RETURN_FAILED; + }; +} diff --git a/osal/linux/Mutex.h b/osal/linux/Mutex.h new file mode 100644 index 00000000..d02d008f --- /dev/null +++ b/osal/linux/Mutex.h @@ -0,0 +1,18 @@ +#ifndef OS_RTEMS_MUTEX_H_ +#define OS_RTEMS_MUTEX_H_ + +#include +#include + +class Mutex : public MutexIF { +public: + Mutex(); + virtual ~Mutex(); + virtual ReturnValue_t lockMutex(uint32_t timeoutMs); + virtual ReturnValue_t unlockMutex(); +private: + pthread_mutex_t mutex; + static uint8_t count; +}; + +#endif /* OS_RTEMS_MUTEX_H_ */ diff --git a/osal/linux/MutexFactory.cpp b/osal/linux/MutexFactory.cpp new file mode 100644 index 00000000..d769cc33 --- /dev/null +++ b/osal/linux/MutexFactory.cpp @@ -0,0 +1,23 @@ +#include +#include + +//TODO: Different variant than the lazy loading in QueueFactory. What's better and why? +MutexFactory* MutexFactory::factoryInstance = new MutexFactory(); + +MutexFactory::MutexFactory() { +} + +MutexFactory::~MutexFactory() { +} + +MutexFactory* MutexFactory::instance() { + return MutexFactory::factoryInstance; +} + +MutexIF* MutexFactory::createMutex() { + return new Mutex(); +} + +void MutexFactory::deleteMutex(MutexIF* mutex) { + delete mutex; +} diff --git a/osal/linux/PeriodicPosixTask.cpp b/osal/linux/PeriodicPosixTask.cpp new file mode 100644 index 00000000..ee3c5c4a --- /dev/null +++ b/osal/linux/PeriodicPosixTask.cpp @@ -0,0 +1,72 @@ +#include +#include +#include +#include + +PeriodicPosixTask::PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_, uint32_t period_, void(deadlineMissedFunc_)()):PosixThread(name_,priority_,stackSize_),objectList(),started(false),periodMs(period_),deadlineMissedFunc( + deadlineMissedFunc_) { + +} + +PeriodicPosixTask::~PeriodicPosixTask() { + //Not Implemented +} + +void* PeriodicPosixTask::taskEntryPoint(void* arg) { + //The argument is re-interpreted as PollingTask. + PeriodicPosixTask *originalTask(reinterpret_cast(arg)); + //The task's functionality is called. + originalTask->taskFunctionality(); + return NULL; +} + +ReturnValue_t PeriodicPosixTask::addComponent(object_id_t object) { + ExecutableObjectIF* newObject = objectManager->get( + object); + if (newObject == NULL) { + return HasReturnvaluesIF::RETURN_FAILED; + } + objectList.push_back(newObject); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t PeriodicPosixTask::sleepFor(uint32_t ms) { + return PosixThread::sleep((uint64_t)ms*1000000); +} + + +ReturnValue_t PeriodicPosixTask::startTask(void){ + started = true; + createTask(&taskEntryPoint,this); + return HasReturnvaluesIF::RETURN_OK; +} + +void PeriodicPosixTask::taskFunctionality(void){ + if(!started){ + suspend(); + } + uint64_t lastWakeTime = getCurrentMonotonicTimeMs(); + //The task's "infinite" inner loop is entered. + while (1) { + for (ObjectList::iterator it = objectList.begin(); + it != objectList.end(); ++it) { + (*it)->performOperation(); + } + if(!PosixThread::delayUntil(&lastWakeTime,periodMs)){ + char name[20] = {0}; + int status = pthread_getname_np(pthread_self(),name,sizeof(name)); + if(status==0){ + error << "ObjectTask: " << name << " Deadline missed." << std::endl; + }else{ + error << "ObjectTask: X Deadline missed. " << status << std::endl; + } + if (this->deadlineMissedFunc != NULL) { + this->deadlineMissedFunc(); + } + } + } +} + +uint32_t PeriodicPosixTask::getPeriodMs() const { + return periodMs; +} diff --git a/osal/linux/PeriodicPosixTask.h b/osal/linux/PeriodicPosixTask.h new file mode 100644 index 00000000..e3fa5722 --- /dev/null +++ b/osal/linux/PeriodicPosixTask.h @@ -0,0 +1,76 @@ +#ifndef FRAMEWORK_OSAL_LINUX_PERIODICPOSIXTASK_H_ +#define FRAMEWORK_OSAL_LINUX_PERIODICPOSIXTASK_H_ + +#include +#include +#include +#include +#include + +class PeriodicPosixTask: public PosixThread, public PeriodicTaskIF { +public: + PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_, uint32_t period_, void(*deadlineMissedFunc_)()); + virtual ~PeriodicPosixTask(); + /** + * @brief The method to start the task. + * @details The method starts the task with the respective system call. + * Entry point is the taskEntryPoint method described below. + * The address of the task object is passed as an argument + * to the system call. + */ + ReturnValue_t startTask(void); + /** + * Adds an object to the list of objects to be executed. + * The objects are executed in the order added. + * @param object Id of the object to add. + * @return RETURN_OK on success, RETURN_FAILED if the object could not be added. + */ + ReturnValue_t addComponent(object_id_t object); + + uint32_t getPeriodMs() const; + + ReturnValue_t sleepFor(uint32_t ms); + +private: + typedef std::vector ObjectList; //!< Typedef for the List of objects. + /** + * @brief This attribute holds a list of objects to be executed. + */ + ObjectList objectList; + + /** + * @brief Flag to indicate that the task was started and is allowed to run + */ + bool started; + + + /** + * @brief Period of the task in milliseconds + */ + uint32_t periodMs; + /** + * @brief The function containing the actual functionality of the task. + * @details The method sets and starts + * the task's period, then enters a loop that is repeated indefinitely. Within the loop, all performOperation methods of the added + * objects are called. Afterwards the task will be blocked until the next period. + * On missing the deadline, the deadlineMissedFunction is executed. + */ + virtual void taskFunctionality(void); + /** + * @brief This is the entry point in a new thread. + * + * @details This method, that is the entry point in the new thread and calls taskFunctionality of the child class. + * Needs a valid pointer to the derived class. + */ + static void* taskEntryPoint(void* arg); + /** + * @brief The pointer to the deadline-missed function. + * @details This pointer stores the function that is executed if the task's deadline is missed. + * So, each may react individually on a timing failure. The pointer may be NULL, + * then nothing happens on missing the deadline. The deadline is equal to the next execution + * of the periodic task. + */ + void (*deadlineMissedFunc)(); +}; + +#endif /* FRAMEWORK_OSAL_LINUX_PERIODICPOSIXTASK_H_ */ diff --git a/osal/linux/PosixThread.cpp b/osal/linux/PosixThread.cpp new file mode 100644 index 00000000..2f0176c9 --- /dev/null +++ b/osal/linux/PosixThread.cpp @@ -0,0 +1,188 @@ +#include +#include +#include +#include + + +PosixThread::~PosixThread() { + //No deletion and no free of Stack Pointer +} + +ReturnValue_t PosixThread::sleep(uint64_t ns) { + //TODO sleep might be better with timer instead of sleep() + timespec time; + time.tv_sec = ns/1000000000; + time.tv_nsec = ns - time.tv_sec*1e9; + + //Remaining Time is not set here + int status = nanosleep(&time,NULL); + if(status != 0){ + switch(errno){ + case EINTR: + //The nanosleep() function was interrupted by a signal. + return HasReturnvaluesIF::RETURN_FAILED; + case EINVAL: + //The rqtp argument specified a nanosecond value less than zero or greater than or equal to 1000 million. + return HasReturnvaluesIF::RETURN_FAILED; + default: + return HasReturnvaluesIF::RETURN_FAILED; + } + + } + return HasReturnvaluesIF::RETURN_OK; +} + +void PosixThread::suspend() { + //Wait for SIGUSR1 + int caughtSig = 0; + sigset_t waitSignal; + sigemptyset(&waitSignal); + sigaddset(&waitSignal, SIGUSR1); + sigwait(&waitSignal, &caughtSig); + if (caughtSig != SIGUSR1) { + error << "FixedTimeslotTask: Unknown Signal received: " << caughtSig + << std::endl; + } +} + +void PosixThread::resume(){ + /* Signal the thread to start. Makes sense to call kill to start or? ;) + * + * According to Posix raise(signal) will call pthread_kill(pthread_self(), sig), + * but as the call must be done from the thread itsself this is not possible here + */ + pthread_kill(thread,SIGUSR1); +} + + + + + +bool PosixThread::delayUntil(uint64_t* const prevoiusWakeTime_ms, + const uint64_t delayTime_ms) { + uint64_t nextTimeToWake_ms; + bool shouldDelay = false; + //Get current Time + const uint64_t currentTime_ms = getCurrentMonotonicTimeMs(); + /* Generate the tick time at which the task wants to wake. */ + nextTimeToWake_ms = (*prevoiusWakeTime_ms) + delayTime_ms; + + if (currentTime_ms < *prevoiusWakeTime_ms) { + /* The tick count has overflowed since this function was + lasted called. In this case the only time we should ever + actually delay is if the wake time has also overflowed, + and the wake time is greater than the tick time. When this + is the case it is as if neither time had overflowed. */ + if ((nextTimeToWake_ms < *prevoiusWakeTime_ms) + && (nextTimeToWake_ms > currentTime_ms)) { + shouldDelay = true; + } + } else { + /* The tick time has not overflowed. In this case we will + delay if either the wake time has overflowed, and/or the + tick time is less than the wake time. */ + if ((nextTimeToWake_ms < *prevoiusWakeTime_ms) + || (nextTimeToWake_ms > currentTime_ms)) { + shouldDelay = true; + } + } + + /* Update the wake time ready for the next call. */ + + (*prevoiusWakeTime_ms) = nextTimeToWake_ms; + + if (shouldDelay) { + uint64_t sleepTime = nextTimeToWake_ms - currentTime_ms; + PosixThread::sleep(sleepTime * 1000000ull); + return true; + } + //We are shifting the time in case the deadline was missed like rtems + (*prevoiusWakeTime_ms) = currentTime_ms; + return false; + +} + + +uint64_t PosixThread::getCurrentMonotonicTimeMs(){ + timespec timeNow; + clock_gettime(CLOCK_MONOTONIC_RAW, &timeNow); + uint64_t currentTime_ms = (uint64_t) timeNow.tv_sec * 1000 + + timeNow.tv_nsec / 1000000; + + return currentTime_ms; +} + +PosixThread::PosixThread(const char* name_, int priority_, size_t stackSize_):thread(0),priority(priority_),stackSize(stackSize_) { + strcpy(name,name_); +} + + + +void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) { + debug << "PosixThread::createTask" << std::endl; + /* + * The attr argument points to a pthread_attr_t structure whose contents + are used at thread creation time to determine attributes for the new + thread; this structure is initialized using pthread_attr_init(3) and + related functions. If attr is NULL, then the thread is created with + default attributes. + */ + pthread_attr_t attributes; + int status = pthread_attr_init(&attributes); + if(status != 0){ + error << "Posix Thread attribute init failed with: " << strerror(status) << std::endl; + } + void* sp; + status = posix_memalign(&sp, sysconf(_SC_PAGESIZE), stackSize); + if(status != 0){ + error << "Posix Thread stack init failed with: " << strerror(status) << std::endl; + } + + status = pthread_attr_setstack(&attributes, sp, stackSize); + if(status != 0){ + error << "Posix Thread attribute setStack failed with: " << strerror(status) << std::endl; + } + + status = pthread_attr_setinheritsched(&attributes, PTHREAD_EXPLICIT_SCHED); + if(status != 0){ + error << "Posix Thread attribute setinheritsched failed with: " << strerror(status) << std::endl; + } + +//TODO FIFO -> This needs root privileges for the process + status = pthread_attr_setschedpolicy(&attributes,SCHED_FIFO); + if(status != 0){ + error << "Posix Thread attribute schedule policy failed with: " << strerror(status) << std::endl; + } + + sched_param scheduleParams; + scheduleParams.__sched_priority = priority; + status = pthread_attr_setschedparam(&attributes, &scheduleParams); + if(status != 0){ + error << "Posix Thread attribute schedule params failed with: " << strerror(status) << std::endl; + } + + //Set Signal Mask for suspend until startTask is called + sigset_t waitSignal; + sigemptyset(&waitSignal); + sigaddset(&waitSignal, SIGUSR1); + status = pthread_sigmask(SIG_BLOCK, &waitSignal, NULL); + if(status != 0){ + error << "Posix Thread sigmask failed failed with: " << strerror(status) << " errno: " << strerror(errno) << std::endl; + } + + + status = pthread_create(&thread,&attributes,fnc_,arg_); + if(status != 0){ + error << "Posix Thread create failed with: " << strerror(status) << std::endl; + } + + status = pthread_setname_np(thread,name); + if(status != 0){ + error << "Posix Thread setname failed with: " << strerror(status) << std::endl; + } + + status = pthread_attr_destroy(&attributes); + if(status!=0){ + error << "Posix Thread attribute destroy failed with: " << strerror(status) << std::endl; + } +} diff --git a/osal/linux/PosixThread.h b/osal/linux/PosixThread.h new file mode 100644 index 00000000..d96c4156 --- /dev/null +++ b/osal/linux/PosixThread.h @@ -0,0 +1,74 @@ +#ifndef FRAMEWORK_OSAL_LINUX_POSIXTHREAD_H_ +#define FRAMEWORK_OSAL_LINUX_POSIXTHREAD_H_ + +#include +#include +#include +#include +#include +#include + +class PosixThread { +public: + PosixThread(const char* name_, int priority_, size_t stackSize_); + virtual ~PosixThread(); + /** + * Set the Thread to sleep state + * @param ns Nanosecond sleep time + * @return Returns Failed if sleep fails + */ + static ReturnValue_t sleep(uint64_t ns); + /** + * @brief Function to suspend the task until SIGUSR1 was received + * + * @details Will be called in the beginning to suspend execution until startTask() is called explicitly. + */ + void suspend(); + + /** + * @brief Function to allow a other thread to start the thread again from suspend state + * + * @details Restarts the Thread after suspend call + */ + void resume(); + + + /** + * Delay function similar to FreeRtos delayUntil function + * + * @param prevoiusWakeTime_ms Needs the previous wake time and returns the next wakeup time + * @param delayTime_ms Time period to delay + * + * @return False If deadline was missed; True if task was delayed + */ + static bool delayUntil(uint64_t* const prevoiusWakeTime_ms, const uint64_t delayTime_ms); + + /** + * Returns the current time in milliseconds from CLOCK_MONOTONIC + * + * @return current time in milliseconds from CLOCK_MONOTONIC + */ + static uint64_t getCurrentMonotonicTimeMs(); + +protected: + pthread_t thread; + + /** + * @brief Function that has to be called by derived class because the derived class pointer has to be valid as argument + * @details This function creates a pthread with the given parameters. As the function requires a pointer to the derived object + * it has to be called after the this pointer of the derived object is valid. Sets the taskEntryPoint as + * function to be called by new a thread. + * @param name_ Name of the task + * @param priority_ Priority of the task according to POSIX + * @param stackSize_ Size of the stack attached to that task + * @param arg_ argument of the taskEntryPoint function, needs to be this pointer of derived class + */ + void createTask(void* (*fnc_)(void*),void* arg_); + +private: + char name[10]; + int priority; + size_t stackSize; +}; + +#endif /* FRAMEWORK_OSAL_LINUX_POSIXTHREAD_H_ */ diff --git a/osal/linux/QueueFactory.cpp b/osal/linux/QueueFactory.cpp new file mode 100644 index 00000000..d9ec14ad --- /dev/null +++ b/osal/linux/QueueFactory.cpp @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include +#include + +QueueFactory* QueueFactory::factoryInstance = NULL; + + +ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo, + MessageQueueMessage* message, MessageQueueId_t sentFrom) { + message->setSender(sentFrom); + int result = mq_send(sendTo, + reinterpret_cast(message->getBuffer()), message->messageSize,0); + + //TODO: Check if we're in ISR. + if (result != 0) { + //TODO Translate error + switch(errno){ + case EAGAIN: + //The O_NONBLOCK flag was set when opening the queue, or the MQ_NONBLOCK flag was set in its attributes, and the specified queue is full. + return MessageQueueIF::FULL; + case EBADF: + //mq_des doesn't represent a valid message queue descriptor, or mq_des wasn't opened for writing. + error << "MessageQueueSenderIF::sendMessage: Configuration error " << strerror(errno) << " in mq_send mqSendTo: " << sendTo << " sent from " << sentFrom << std::endl; + /*NO BREAK*/ + case EINTR: + //The call was interrupted by a signal. + case EINVAL: + /* + * This value indicates one of the following: + * * msg_ptr is NULL. + * * msg_len is negative. + * * msg_prio is greater than MQ_PRIO_MAX. + * * msg_prio is less than 0. + * * MQ_PRIO_RESTRICT is set in the mq_attr of mq_des, and msg_prio is greater than the priority of the calling process. + * */ + case EMSGSIZE: + //The msg_len is greater than the msgsize associated with the specified queue. + default: + return HasReturnvaluesIF::RETURN_FAILED; + } + } + return HasReturnvaluesIF::RETURN_OK; +} + +QueueFactory* QueueFactory::instance() { + if (factoryInstance == NULL) { + factoryInstance = new QueueFactory; + } + return factoryInstance; +} + +QueueFactory::QueueFactory() { +} + +QueueFactory::~QueueFactory() { +} + +MessageQueueIF* QueueFactory::createMessageQueue(uint32_t message_depth, + uint32_t max_message_size) { + return new MessageQueue(message_depth, max_message_size); +} + +void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { + delete queue; +} diff --git a/osal/linux/TaskFactory.cpp b/osal/linux/TaskFactory.cpp new file mode 100644 index 00000000..44f46d90 --- /dev/null +++ b/osal/linux/TaskFactory.cpp @@ -0,0 +1,34 @@ +#include +#include +#include +#include + +//TODO: Different variant than the lazy loading in QueueFactory. What's better and why? +TaskFactory* TaskFactory::factoryInstance = new TaskFactory(); + +TaskFactory::~TaskFactory() { +} + +TaskFactory* TaskFactory::instance() { + return TaskFactory::factoryInstance; +} + +PeriodicTaskIF* TaskFactory::createPeriodicTask(TaskName name_,TaskPriority taskPriority_,TaskStackSize stackSize_,TaskPeriod periodInSeconds_,TaskDeadlineMissedFunction deadLineMissedFunction_) { + return static_cast(new PeriodicPosixTask(name_, taskPriority_,stackSize_,periodInSeconds_ * 1000,deadLineMissedFunction_)); +} + +FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(TaskName name_,TaskPriority taskPriority_,TaskStackSize stackSize_,TaskPeriod periodInSeconds_,TaskDeadlineMissedFunction deadLineMissedFunction_) { + return static_cast(new FixedTimeslotTask(name_, taskPriority_,stackSize_,periodInSeconds_*1000)); +} + +ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) { + //TODO not implemented + return HasReturnvaluesIF::RETURN_FAILED; +} + +ReturnValue_t TaskFactory::delayTask(uint32_t delayMs){ + return PosixThread::sleep(delayMs*1000000ull); +} + +TaskFactory::TaskFactory() { +} diff --git a/osal/linux/Timer.cpp b/osal/linux/Timer.cpp new file mode 100644 index 00000000..2347e39d --- /dev/null +++ b/osal/linux/Timer.cpp @@ -0,0 +1,41 @@ +#include +#include +#include + +Timer::Timer() { + sigevent sigEvent; + sigEvent.sigev_notify = SIGEV_NONE; + sigEvent.sigev_signo = 0; + sigEvent.sigev_value.sival_ptr = &timerId; + int status = timer_create(CLOCK_MONOTONIC, &sigEvent, &timerId); + if(status!=0){ + error << "Timer creation failed with: " << status << " errno: " << errno << std::endl; + } +} + +Timer::~Timer() { + timer_delete(timerId); +} + +int Timer::setTimer(uint32_t intervalMs) { + itimerspec timer; + timer.it_value.tv_sec = intervalMs / 1000; + timer.it_value.tv_nsec = (intervalMs * 1000000) % (1000000000); + timer.it_interval.tv_sec = 0; + timer.it_interval.tv_nsec = 0; + return timer_settime(timerId, 0, &timer, NULL); +} + + +int Timer::getTimer(uint32_t* remainingTimeMs){ + itimerspec timer; + timer.it_value.tv_sec = 0; + timer.it_value.tv_nsec = 0; + timer.it_interval.tv_sec = 0; + timer.it_interval.tv_nsec = 0; + int status = timer_gettime(timerId, &timer); + + *remainingTimeMs = timer.it_value.tv_sec * 1000 + timer.it_value.tv_nsec / 1000000; + + return status; +} diff --git a/osal/linux/Timer.h b/osal/linux/Timer.h new file mode 100644 index 00000000..f94bca59 --- /dev/null +++ b/osal/linux/Timer.h @@ -0,0 +1,45 @@ +#ifndef FRAMEWORK_OSAL_LINUX_TIMER_H_ +#define FRAMEWORK_OSAL_LINUX_TIMER_H_ + +#include +#include +#include + +/** + * This class is a helper for the creation of a Clock Monotonic timer which does not trigger a signal + */ +class Timer { +public: + /** + * Creates the Timer sets the timerId Member + */ + Timer(); + /** + * Deletes the timer + * + * Careful! According to POSIX documentation: + * The treatment of any pending signal generated by the deleted timer is unspecified. + */ + virtual ~Timer(); + + /** + * Set the timer given in timerId to the given interval + * + * @param intervalMs Interval in ms to be set + * @return 0 on Success 1 else + */ + int setTimer(uint32_t intervalMs); + + /** + * Get the remaining time of the timer + * + * @param remainingTimeMs Pointer to integer value which is used to return the remaining time + * @return 0 on Success 1 else (see timer_getime documentation of posix function) + */ + int getTimer(uint32_t* remainingTimeMs); + +private: + timer_t timerId; +}; + +#endif /* FRAMEWORK_OSAL_LINUX_TIMER_H_ */ diff --git a/osal/rtems/Clock.cpp b/osal/rtems/Clock.cpp index af7ea2ee..98198dd3 100644 --- a/osal/rtems/Clock.cpp +++ b/osal/rtems/Clock.cpp @@ -1,72 +1,125 @@ #include #include "RtemsBasic.h" +#include uint16_t Clock::leapSeconds = 0; MutexIF* Clock::timeMutex = NULL; uint32_t Clock::getTicksPerSecond(void){ - rtems_interval ticks_per_second; - (void) rtems_clock_get(RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticks_per_second); - return ticks_per_second; + rtems_interval ticks_per_second = rtems_clock_get_ticks_per_second(); + return static_cast(ticks_per_second); } ReturnValue_t Clock::setClock(const TimeOfDay_t* time) { - //We need to cast to rtems internal time of day type here. Both structs have the same structure - //rtems provides no const guarantee, so we need to cast the const away - //TODO Check if this can be done safely - rtems_time_of_day* timeRtems = reinterpret_cast(const_cast(time)); - rtems_status_code status = rtems_clock_set(timeRtems); - return RtemsBasic::convertReturnCode(status); + rtems_time_of_day timeRtems; + timeRtems.year = time->year; + timeRtems.month = time->month; + timeRtems.day = time->day; + timeRtems.hour = time->hour; + timeRtems.minute = time->minute; + timeRtems.second = time->second; + timeRtems.ticks = time->usecond * getTicksPerSecond() / 1e6; + rtems_status_code status = rtems_clock_set(&timeRtems); + switch(status){ + case RTEMS_SUCCESSFUL: + return HasReturnvaluesIF::RETURN_OK; + case RTEMS_INVALID_ADDRESS: + return HasReturnvaluesIF::RETURN_FAILED; + case RTEMS_INVALID_CLOCK: + return HasReturnvaluesIF::RETURN_FAILED; + default: + return HasReturnvaluesIF::RETURN_FAILED; + } } ReturnValue_t Clock::setClock(const timeval* time) { + //TODO This routine uses _TOD_Set which is not timespec newTime; newTime.tv_sec = time->tv_sec; newTime.tv_nsec = time->tv_usec * TOD_NANOSECONDS_PER_MICROSECOND; //SHOULDDO: Not sure if we need to protect this call somehow (by thread lock or something). //Uli: rtems docu says you can call this from an ISR, not sure if this means no protetion needed - _TOD_Set(&newTime); + //TODO Second parameter is ISR_lock_Context + _TOD_Set(&newTime,NULL); return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t Clock::getClock_timeval(timeval* time) { + //Callable from ISR rtems_status_code status = rtems_clock_get_tod_timeval(time); - return RtemsBasic::convertReturnCode(status); + switch(status){ + case RTEMS_SUCCESSFUL: + return HasReturnvaluesIF::RETURN_OK; + case RTEMS_NOT_DEFINED: + return HasReturnvaluesIF::RETURN_FAILED; + default: + return HasReturnvaluesIF::RETURN_FAILED; + } } ReturnValue_t Clock::getUptime(timeval* uptime) { + //According to docs.rtems.org for rtems 5 this method is more accurate than rtems_clock_get_ticks_since_boot timespec time; rtems_status_code status = rtems_clock_get_uptime(&time); uptime->tv_sec = time.tv_sec; time.tv_nsec = time.tv_nsec / 1000; uptime->tv_usec = time.tv_nsec; - return RtemsBasic::convertReturnCode(status); + switch(status){ + case RTEMS_SUCCESSFUL: + return HasReturnvaluesIF::RETURN_OK; + default: + return HasReturnvaluesIF::RETURN_FAILED; + } } ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) { + //This counter overflows after 50 days *uptimeMs = rtems_clock_get_ticks_since_boot(); - return RtemsBasic::convertReturnCode(RTEMS_SUCCESSFUL); + return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t Clock::getClock_usecs(uint64_t* time) { timeval temp_time; rtems_status_code returnValue = rtems_clock_get_tod_timeval(&temp_time); *time = ((uint64_t) temp_time.tv_sec * 1000000) + temp_time.tv_usec; - return RtemsBasic::convertReturnCode(returnValue); + switch(returnValue){ + case RTEMS_SUCCESSFUL: + return HasReturnvaluesIF::RETURN_OK; + default: + return HasReturnvaluesIF::RETURN_FAILED; + } } ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) { rtems_time_of_day* timeRtems = reinterpret_cast(time); rtems_status_code status = rtems_clock_get_tod(timeRtems); - return RtemsBasic::convertReturnCode(status); + switch (status) { + case RTEMS_SUCCESSFUL: + return HasReturnvaluesIF::RETURN_OK; + case RTEMS_NOT_DEFINED: + //system date and time is not set + return HasReturnvaluesIF::RETURN_FAILED; + case RTEMS_INVALID_ADDRESS: + //time_buffer is NULL + return HasReturnvaluesIF::RETURN_FAILED; + default: + return HasReturnvaluesIF::RETURN_FAILED; + } } ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, timeval* to) { //Fails in 2038.. - const rtems_time_of_day* timeRtems = reinterpret_cast(from); - to->tv_sec = _TOD_To_seconds(timeRtems); - to->tv_usec = timeRtems->ticks * 1000; + rtems_time_of_day timeRtems; + timeRtems.year = from->year; + timeRtems.month = from->month; + timeRtems.day = from->day; + timeRtems.hour = from->hour; + timeRtems.minute = from->minute; + timeRtems.second = from->second; + timeRtems.ticks = from->usecond * getTicksPerSecond() / 1e6; + to->tv_sec = _TOD_To_seconds(&timeRtems); + to->tv_usec = from->usecond; return HasReturnvaluesIF::RETURN_OK; } diff --git a/osal/rtems/CpuUsage.cpp b/osal/rtems/CpuUsage.cpp index 40ac34aa..9fc34ff1 100644 --- a/osal/rtems/CpuUsage.cpp +++ b/osal/rtems/CpuUsage.cpp @@ -1,4 +1,4 @@ -#include +#include "CpuUsage.h" #include #include #include @@ -80,7 +80,7 @@ void CpuUsage::resetCpuUsage() { } void CpuUsage::read() { - rtems_cpu_usage_report_with_plugin(this, &handlePrint); + //rtems_cpu_usage_report_with_plugin(this, &handlePrint); } void CpuUsage::clear() { diff --git a/osal/rtems/InitTask.cpp b/osal/rtems/InitTask.cpp index fe48e8d9..80afed3d 100644 --- a/osal/rtems/InitTask.cpp +++ b/osal/rtems/InitTask.cpp @@ -7,21 +7,5 @@ InitTask::InitTask() { } InitTask::~InitTask() { -} - -void InitTask::deleteTask(){ rtems_task_delete(RTEMS_SELF); } - -ReturnValue_t InitTask::startTask() { - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t InitTask::sleepFor(uint32_t ms) { - rtems_status_code status = rtems_task_wake_after(RtemsBasic::convertMsToTicks(ms)); - return RtemsBasic::convertReturnCode(status); -} - -uint32_t InitTask::getPeriodMs() const { - return 0; -} diff --git a/osal/rtems/InitTask.h b/osal/rtems/InitTask.h index 121734e5..2c8c0c6a 100644 --- a/osal/rtems/InitTask.h +++ b/osal/rtems/InitTask.h @@ -1,8 +1,6 @@ #ifndef OS_RTEMS_INITTASK_H_ #define OS_RTEMS_INITTASK_H_ -#include - //TODO move into static function in TaskIF /** @@ -12,17 +10,10 @@ * Warning: The init task is deleted with this stub, i.e. the destructor * calls rtems_task_delete(RTEMS_SELF) */ -class InitTask: public PeriodicTaskIF { +class InitTask { public: InitTask(); virtual ~InitTask(); - ReturnValue_t startTask(); - - ReturnValue_t sleepFor(uint32_t ms); - - uint32_t getPeriodMs() const; - - void deleteTask(); }; #endif /* OS_RTEMS_INITTASK_H_ */ diff --git a/osal/rtems/InternalErrorCodes.cpp b/osal/rtems/InternalErrorCodes.cpp index 4be890dc..bc062f1d 100644 --- a/osal/rtems/InternalErrorCodes.cpp +++ b/osal/rtems/InternalErrorCodes.cpp @@ -3,12 +3,13 @@ ReturnValue_t InternalErrorCodes::translate(uint8_t code) { switch (code) { - case INTERNAL_ERROR_NO_CONFIGURATION_TABLE: - return NO_CONFIGURATION_TABLE; - case INTERNAL_ERROR_NO_CPU_TABLE: - return NO_CPU_TABLE; - case INTERNAL_ERROR_INVALID_WORKSPACE_ADDRESS: - return INVALID_WORKSPACE_ADDRESS; + //TODO It looks like RTEMS-5 does not provide the same error codes +// case INTERNAL_ERROR_NO_CONFIGURATION_TABLE: +// return NO_CONFIGURATION_TABLE; +// case INTERNAL_ERROR_NO_CPU_TABLE: +// return NO_CPU_TABLE; +// case INTERNAL_ERROR_INVALID_WORKSPACE_ADDRESS: +// return INVALID_WORKSPACE_ADDRESS; case INTERNAL_ERROR_TOO_LITTLE_WORKSPACE: return TOO_LITTLE_WORKSPACE; case INTERNAL_ERROR_WORKSPACE_ALLOCATION: @@ -35,16 +36,16 @@ ReturnValue_t InternalErrorCodes::translate(uint8_t code) { return INVALID_GLOBAL_ID; case INTERNAL_ERROR_BAD_STACK_HOOK: return BAD_STACK_HOOK; - case INTERNAL_ERROR_BAD_ATTRIBUTES: - return BAD_ATTRIBUTES; - case INTERNAL_ERROR_IMPLEMENTATION_KEY_CREATE_INCONSISTENCY: - return IMPLEMENTATION_KEY_CREATE_INCONSISTENCY; - case INTERNAL_ERROR_IMPLEMENTATION_BLOCKING_OPERATION_CANCEL: - return IMPLEMENTATION_BLOCKING_OPERATION_CANCEL; - case INTERNAL_ERROR_MUTEX_OBTAIN_FROM_BAD_STATE: - return MUTEX_OBTAIN_FROM_BAD_STATE; - case INTERNAL_ERROR_UNLIMITED_AND_MAXIMUM_IS_0: - return UNLIMITED_AND_MAXIMUM_IS_0; +// case INTERNAL_ERROR_BAD_ATTRIBUTES: +// return BAD_ATTRIBUTES; +// case INTERNAL_ERROR_IMPLEMENTATION_KEY_CREATE_INCONSISTENCY: +// return IMPLEMENTATION_KEY_CREATE_INCONSISTENCY; +// case INTERNAL_ERROR_IMPLEMENTATION_BLOCKING_OPERATION_CANCEL: +// return IMPLEMENTATION_BLOCKING_OPERATION_CANCEL; +// case INTERNAL_ERROR_MUTEX_OBTAIN_FROM_BAD_STATE: +// return MUTEX_OBTAIN_FROM_BAD_STATE; +// case INTERNAL_ERROR_UNLIMITED_AND_MAXIMUM_IS_0: +// return UNLIMITED_AND_MAXIMUM_IS_0; default: return HasReturnvaluesIF::RETURN_FAILED; } diff --git a/osal/rtems/Interrupt.cpp b/osal/rtems/Interrupt.cpp index b6277499..b740f1ca 100644 --- a/osal/rtems/Interrupt.cpp +++ b/osal/rtems/Interrupt.cpp @@ -1,5 +1,8 @@ #include "Interrupt.h" -#include +extern "C" { +#include +#include +} #include "RtemsBasic.h" @@ -24,7 +27,20 @@ ReturnValue_t Interrupt::setInterruptServiceRoutine(IsrHandler_t handler, //+ 0x10 comes because of trap type assignment to IRQs in UT699 processor rtems_status_code status = rtems_interrupt_catch(handler, interrupt + 0x10, oldHandler); - return RtemsBasic::convertReturnCode(status); + switch(status){ + case RTEMS_SUCCESSFUL: + //ISR established successfully + return HasReturnvaluesIF::RETURN_OK; + case RTEMS_INVALID_NUMBER: + //illegal vector number + return HasReturnvaluesIF::RETURN_FAILED; + case RTEMS_INVALID_ADDRESS: + //illegal ISR entry point or invalid old_isr_handler + return HasReturnvaluesIF::RETURN_FAILED; + default: + return HasReturnvaluesIF::RETURN_FAILED; + } + } ReturnValue_t Interrupt::disableInterrupt(InterruptNumber_t interruptNumber) { diff --git a/osal/rtems/MessageQueue.cpp b/osal/rtems/MessageQueue.cpp index 4f8198dd..af73ca77 100644 --- a/osal/rtems/MessageQueue.cpp +++ b/osal/rtems/MessageQueue.cpp @@ -1,7 +1,7 @@ #include #include "MessageQueue.h" #include "RtemsBasic.h" - +#include MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size) : id(0), lastPartner(0), defaultDestination(NO_QUEUE), internalErrorReporter(NULL) { rtems_name name = ('Q' << 24) + (queueCounter++ << 8); @@ -21,11 +21,11 @@ MessageQueue::~MessageQueue() { ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, MessageQueueMessage* message, bool ignoreFault) { - return sendMessage(sendTo, message, this->getId(), ignoreFault); + return sendMessageFrom(sendTo, message, this->getId(), ignoreFault); } ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessage* message) { - return sendToDefault(message, this->getId()); + return sendToDefaultFrom(message, this->getId()); } ReturnValue_t MessageQueue::reply(MessageQueueMessage* message) { @@ -59,7 +59,7 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message) { //But still, delete packet content. memset(message->getData(), 0, message->MAX_DATA_SIZE); } - return RtemsBasic::convertReturnCode(status); + return convertReturnCode(status); } MessageQueueId_t MessageQueue::getLastPartner() const { @@ -68,7 +68,7 @@ MessageQueueId_t MessageQueue::getLastPartner() const { ReturnValue_t MessageQueue::flush(uint32_t* count) { rtems_status_code status = rtems_message_queue_flush(id, count); - return RtemsBasic::convertReturnCode(status); + return convertReturnCode(status); } MessageQueueId_t MessageQueue::getId() const { @@ -79,7 +79,7 @@ void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) { this->defaultDestination = defaultDestination; } -ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, +ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessage* message, MessageQueueId_t sentFrom, bool ignoreFault) { @@ -97,12 +97,18 @@ ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, internalErrorReporter->queueMessageNotSent(); } } - return result; + + ReturnValue_t returnCode = convertReturnCode(result); + if(result == MessageQueueIF::EMPTY){ + return HasReturnvaluesIF::RETURN_FAILED; + } + + return returnCode; } -ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessage* message, +ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessage* message, MessageQueueId_t sentFrom, bool ignoreFault) { - return sendMessage(defaultDestination, message, sentFrom, ignoreFault); + return sendMessageFrom(defaultDestination, message, sentFrom, ignoreFault); } MessageQueueId_t MessageQueue::getDefaultDestination() const { @@ -113,4 +119,30 @@ bool MessageQueue::isDefaultDestinationSet() const { return (defaultDestination != NO_QUEUE); } +ReturnValue_t MessageQueue::convertReturnCode(rtems_status_code inValue){ + switch(inValue){ + case RTEMS_SUCCESSFUL: + return HasReturnvaluesIF::RETURN_OK; + case RTEMS_INVALID_ID: + return HasReturnvaluesIF::RETURN_FAILED; + case RTEMS_TIMEOUT: + return HasReturnvaluesIF::RETURN_FAILED; + case RTEMS_OBJECT_WAS_DELETED: + return HasReturnvaluesIF::RETURN_FAILED; + case RTEMS_INVALID_ADDRESS: + return HasReturnvaluesIF::RETURN_FAILED; + case RTEMS_INVALID_SIZE: + return HasReturnvaluesIF::RETURN_FAILED; + case RTEMS_TOO_MANY: + return MessageQueueIF::FULL; + case RTEMS_UNSATISFIED: + return MessageQueueIF::EMPTY; + default: + return HasReturnvaluesIF::RETURN_FAILED; + } + +} + + + uint16_t MessageQueue::queueCounter = 0; diff --git a/osal/rtems/MessageQueue.h b/osal/rtems/MessageQueue.h index 0a8805ef..9bdce7ca 100644 --- a/osal/rtems/MessageQueue.h +++ b/osal/rtems/MessageQueue.h @@ -13,6 +13,7 @@ #include #include #include +#include "RtemsBasic.h" /** * @brief This class manages sending and receiving of message queue messages. @@ -120,7 +121,7 @@ public: * This variable is set to zero by default. * \param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. */ - virtual ReturnValue_t sendMessage( MessageQueueId_t sendTo, MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); + virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); /** * \brief The sendToDefault method sends a queue message to the default destination. * \details In all other aspects, it works identical to the sendMessage method. @@ -128,7 +129,7 @@ public: * \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. * This variable is set to zero by default. */ - virtual ReturnValue_t sendToDefault( MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); + virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); /** * \brief This method is a simple setter for the default destination. */ @@ -169,6 +170,12 @@ private: InternalErrorReporterIF *internalErrorReporter; static uint16_t queueCounter; + /** + * A method to convert an OS-specific return code to the frameworks return value concept. + * @param inValue The return code coming from the OS. + * @return The converted return value. + */ + static ReturnValue_t convertReturnCode(rtems_status_code inValue); }; #endif /* MESSAGEQUEUE_H_ */ diff --git a/osal/rtems/MultiObjectTask.cpp b/osal/rtems/MultiObjectTask.cpp index af853cb3..bb8c2c81 100644 --- a/osal/rtems/MultiObjectTask.cpp +++ b/osal/rtems/MultiObjectTask.cpp @@ -14,13 +14,6 @@ MultiObjectTask::MultiObjectTask(const char *name, rtems_task_priority setPriori TaskBase(setPriority, setStack, name), periodTicks( RtemsBasic::convertMsToTicks(setPeriod)), periodId(0), deadlineMissedFunc( setDeadlineMissedFunc) { - rtems_name periodName = (('P' << 24) + ('e' << 16) + ('r' << 8) + 'd'); - rtems_status_code status = rtems_rate_monotonic_create(periodName, - &periodId); - if (status != RTEMS_SUCCESSFUL) { - error << "ObjectTask::period create failed with status " << status - << std::endl; - } } MultiObjectTask::~MultiObjectTask(void) { @@ -40,7 +33,17 @@ ReturnValue_t MultiObjectTask::startTask() { error << "ObjectTask::startTask for " << std::hex << this->getId() << std::dec << " failed." << std::endl; } - return RtemsBasic::convertReturnCode(status); + switch(status){ + case RTEMS_SUCCESSFUL: + //ask started successfully + return HasReturnvaluesIF::RETURN_OK; + default: +/* RTEMS_INVALID_ADDRESS - invalid task entry point + RTEMS_INVALID_ID - invalid task id + RTEMS_INCORRECT_STATE - task not in the dormant state + RTEMS_ILLEGAL_ON_REMOTE_OBJECT - cannot start remote task */ + return HasReturnvaluesIF::RETURN_FAILED; + } } ReturnValue_t MultiObjectTask::sleepFor(uint32_t ms) { @@ -48,21 +51,14 @@ ReturnValue_t MultiObjectTask::sleepFor(uint32_t ms) { } void MultiObjectTask::taskFunctionality() { - //The +1 is necessary to avoid a call with period = 0, which does not start the period. - rtems_status_code status = rtems_rate_monotonic_period(periodId, - periodTicks + 1); - if (status != RTEMS_SUCCESSFUL) { - error << "ObjectTask::period start failed with status " << status - << std::endl; - return; - } + TaskBase::setAndStartPeriod(periodTicks,&periodId); //The task's "infinite" inner loop is entered. while (1) { for (ObjectList::iterator it = objectList.begin(); it != objectList.end(); ++it) { (*it)->performOperation(); } - status = rtems_rate_monotonic_period(periodId, periodTicks + 1); + rtems_status_code status = TaskBase::restartPeriod(periodTicks,periodId); if (status == RTEMS_TIMEOUT) { char nameSpace[8] = { 0 }; char* ptr = rtems_object_get_name(getId(), sizeof(nameSpace), diff --git a/osal/rtems/Mutex.cpp b/osal/rtems/Mutex.cpp index 3f559ad1..d094e1dc 100644 --- a/osal/rtems/Mutex.cpp +++ b/osal/rtems/Mutex.cpp @@ -26,10 +26,40 @@ Mutex::~Mutex() { ReturnValue_t Mutex::lockMutex(uint32_t timeoutMs) { rtems_status_code status = rtems_semaphore_obtain(mutexId, RTEMS_WAIT, timeoutMs); - return RtemsBasic::convertReturnCode(status); + switch(status){ + case RTEMS_SUCCESSFUL: + //semaphore obtained successfully + return HasReturnvaluesIF::RETURN_OK; + case RTEMS_UNSATISFIED: + //semaphore not available + return MUTEX_NOT_FOUND; + case RTEMS_TIMEOUT: + //timed out waiting for semaphore + return MUTEX_TIMEOUT; + case RTEMS_OBJECT_WAS_DELETED: + //semaphore deleted while waiting + return MUTEX_DESTROYED_WHILE_WAITING; + case RTEMS_INVALID_ID: + //invalid semaphore id + return MUTEX_INVALID_ID; + default: + return HasReturnvaluesIF::RETURN_FAILED; + } } ReturnValue_t Mutex::unlockMutex() { rtems_status_code status = rtems_semaphore_release(mutexId); - return RtemsBasic::convertReturnCode(status); + switch(status){ + case RTEMS_SUCCESSFUL: + //semaphore obtained successfully + return HasReturnvaluesIF::RETURN_OK; + case RTEMS_NOT_OWNER_OF_RESOURCE: + //semaphore not available + return CURR_THREAD_DOES_NOT_OWN_MUTEX; + case RTEMS_INVALID_ID: + //invalid semaphore id + return MUTEX_INVALID_ID; + default: + return HasReturnvaluesIF::RETURN_FAILED; + } } diff --git a/osal/rtems/PollingTask.cpp b/osal/rtems/PollingTask.cpp index 13174ac3..c2dc629b 100644 --- a/osal/rtems/PollingTask.cpp +++ b/osal/rtems/PollingTask.cpp @@ -1,5 +1,18 @@ +#include +#include +#include +#include +#include #include -#include "PollingTask.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include uint32_t PollingTask::deadlineMissedCount = 0; @@ -10,13 +23,6 @@ PollingTask::PollingTask(const char *name, rtems_task_priority setPriority, setOverallPeriod) { // All additional attributes are applied to the object. this->deadlineMissedFunc = setDeadlineMissedFunc; - rtems_name periodName = (('P' << 24) + ('e' << 16) + ('r' << 8) + 'd'); - rtems_status_code status = rtems_rate_monotonic_create(periodName, - &periodId); - if (status != RTEMS_SUCCESSFUL) { - error << "PollingTask::period create failed with status " << status - << std::endl; - } } PollingTask::~PollingTask() { @@ -47,7 +53,17 @@ ReturnValue_t PollingTask::startTask() { error << "PollingTask::startTask for " << std::hex << this->getId() << std::dec << " failed." << std::endl; } - return RtemsBasic::convertReturnCode(status); + switch(status){ + case RTEMS_SUCCESSFUL: + //ask started successfully + return HasReturnvaluesIF::RETURN_OK; + default: +/* RTEMS_INVALID_ADDRESS - invalid task entry point + RTEMS_INVALID_ID - invalid task id + RTEMS_INCORRECT_STATE - task not in the dormant state + RTEMS_ILLEGAL_ON_REMOTE_OBJECT - cannot start remote task */ + return HasReturnvaluesIF::RETURN_FAILED; + } } ReturnValue_t PollingTask::addSlot(object_id_t componentId, uint32_t slotTimeMs, @@ -64,6 +80,8 @@ ReturnValue_t PollingTask::checkSequence() const { return pst.checkSequence(); } +#include + void PollingTask::taskFunctionality() { // A local iterator for the Polling Sequence Table is created to find the start time for the first entry. std::list::iterator it = pst.current; @@ -71,15 +89,7 @@ void PollingTask::taskFunctionality() { //The start time for the first entry is read. rtems_interval interval = RtemsBasic::convertMsToTicks( (*it)->pollingTimeMs); - //The period is set up and started with the system call. - //The +1 is necessary to avoid a call with period = 0, which does not start the period. - rtems_status_code status = rtems_rate_monotonic_period(periodId, - interval + 1); - if (status != RTEMS_SUCCESSFUL) { - error << "PollingTask::period start failed with status " << status - << std::endl; - return; - } + TaskBase::setAndStartPeriod(interval,&periodId); //The task's "infinite" inner loop is entered. while (1) { if (pst.slotFollowsImmediately()) { @@ -89,7 +99,7 @@ void PollingTask::taskFunctionality() { interval = RtemsBasic::convertMsToTicks(this->pst.getIntervalToNextSlotMs()); //The period is checked and restarted with the new interval. //If the deadline was missed, the deadlineMissedFunc is called. - status = rtems_rate_monotonic_period(periodId, interval); + rtems_status_code status = TaskBase::restartPeriod(interval,periodId); if (status == RTEMS_TIMEOUT) { if (this->deadlineMissedFunc != NULL) { this->deadlineMissedFunc(); diff --git a/osal/rtems/QueueFactory.cpp b/osal/rtems/QueueFactory.cpp index edb4844d..05f73f6e 100644 --- a/osal/rtems/QueueFactory.cpp +++ b/osal/rtems/QueueFactory.cpp @@ -10,7 +10,29 @@ ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo, message->setSender(sentFrom); rtems_status_code result = rtems_message_queue_send(sendTo, message->getBuffer(), message->messageSize); - return RtemsBasic::convertReturnCode(result); + switch(result){ + case RTEMS_SUCCESSFUL: + //message sent successfully + return HasReturnvaluesIF::RETURN_OK; + case RTEMS_INVALID_ID: + //invalid queue id + return HasReturnvaluesIF::RETURN_FAILED; + case RTEMS_INVALID_SIZE: + // invalid message size + return HasReturnvaluesIF::RETURN_FAILED; + case RTEMS_INVALID_ADDRESS: + //buffer is NULL + return HasReturnvaluesIF::RETURN_FAILED; + case RTEMS_UNSATISFIED: + //out of message buffers + return HasReturnvaluesIF::RETURN_FAILED; + case RTEMS_TOO_MANY: + //queue's limit has been reached + return MessageQueueIF::FULL; + + default: + return HasReturnvaluesIF::RETURN_FAILED; + } } QueueFactory* QueueFactory::instance() { diff --git a/osal/rtems/RtemsBasic.cpp b/osal/rtems/RtemsBasic.cpp index 0f8c538f..17cb3458 100644 --- a/osal/rtems/RtemsBasic.cpp +++ b/osal/rtems/RtemsBasic.cpp @@ -1,70 +1,70 @@ #include "RtemsBasic.h" -ReturnValue_t RtemsBasic::convertReturnCode(rtems_status_code inValue) { - if (inValue == RTEMS_SUCCESSFUL) { - return HasReturnvaluesIF::RETURN_OK; - } else { - switch(inValue){ - case RTEMS_SUCCESSFUL: - return OperatingSystemIF::SUCCESSFUL; - case RTEMS_TASK_EXITTED: - return OperatingSystemIF::TASK_EXITTED; - case RTEMS_MP_NOT_CONFIGURED: - return OperatingSystemIF::MP_NOT_CONFIGURED; - case RTEMS_INVALID_NAME: - return OperatingSystemIF::INVALID_NAME; - case RTEMS_INVALID_ID: - return OperatingSystemIF::INVALID_ID; - case RTEMS_TOO_MANY: - return OperatingSystemIF::TOO_MANY; - case RTEMS_TIMEOUT: - return OperatingSystemIF::TIMEOUT; - case RTEMS_OBJECT_WAS_DELETED: - return OperatingSystemIF::OBJECT_WAS_DELETED; - case RTEMS_INVALID_SIZE: - return OperatingSystemIF::INVALID_SIZE; - case RTEMS_INVALID_ADDRESS: - return OperatingSystemIF::INVALID_ADDRESS; - case RTEMS_INVALID_NUMBER: - return OperatingSystemIF::INVALID_NUMBER; - case RTEMS_NOT_DEFINED: - return OperatingSystemIF::NOT_DEFINED; - case RTEMS_RESOURCE_IN_USE: - return OperatingSystemIF::RESOURCE_IN_USE; - //TODO RTEMS_UNSATISFIED is double mapped for FLP so it will only return Queue_empty and not unsatisfied - case RTEMS_UNSATISFIED: - return OperatingSystemIF::QUEUE_EMPTY; - case RTEMS_INCORRECT_STATE: - return OperatingSystemIF::INCORRECT_STATE; - case RTEMS_ALREADY_SUSPENDED: - return OperatingSystemIF::ALREADY_SUSPENDED; - case RTEMS_ILLEGAL_ON_SELF: - return OperatingSystemIF::ILLEGAL_ON_SELF; - case RTEMS_ILLEGAL_ON_REMOTE_OBJECT: - return OperatingSystemIF::ILLEGAL_ON_REMOTE_OBJECT; - case RTEMS_CALLED_FROM_ISR: - return OperatingSystemIF::CALLED_FROM_ISR; - case RTEMS_INVALID_PRIORITY: - return OperatingSystemIF::INVALID_PRIORITY; - case RTEMS_INVALID_CLOCK: - return OperatingSystemIF::INVALID_CLOCK; - case RTEMS_INVALID_NODE: - return OperatingSystemIF::INVALID_NODE; - case RTEMS_NOT_CONFIGURED: - return OperatingSystemIF::NOT_CONFIGURED; - case RTEMS_NOT_OWNER_OF_RESOURCE: - return OperatingSystemIF::NOT_OWNER_OF_RESOURCE; - case RTEMS_NOT_IMPLEMENTED: - return OperatingSystemIF::NOT_IMPLEMENTED; - case RTEMS_INTERNAL_ERROR: - return OperatingSystemIF::INTERNAL_ERROR; - case RTEMS_NO_MEMORY: - return OperatingSystemIF::NO_MEMORY; - case RTEMS_IO_ERROR: - return OperatingSystemIF::IO_ERROR; - default: - return HasReturnvaluesIF::RETURN_FAILED; - } - } -} +//ReturnValue_t RtemsBasic::convertReturnCode(rtems_status_code inValue) { +// if (inValue == RTEMS_SUCCESSFUL) { +// return HasReturnvaluesIF::RETURN_OK; +// } else { +// switch(inValue){ +// case RTEMS_SUCCESSFUL: +// return OperatingSystemIF::SUCCESSFUL; +// case RTEMS_TASK_EXITTED: +// return OperatingSystemIF::TASK_EXITTED; +// case RTEMS_MP_NOT_CONFIGURED: +// return OperatingSystemIF::MP_NOT_CONFIGURED; +// case RTEMS_INVALID_NAME: +// return OperatingSystemIF::INVALID_NAME; +// case RTEMS_INVALID_ID: +// return OperatingSystemIF::INVALID_ID; +// case RTEMS_TOO_MANY: +// return OperatingSystemIF::TOO_MANY; +// case RTEMS_TIMEOUT: +// return OperatingSystemIF::TIMEOUT; +// case RTEMS_OBJECT_WAS_DELETED: +// return OperatingSystemIF::OBJECT_WAS_DELETED; +// case RTEMS_INVALID_SIZE: +// return OperatingSystemIF::INVALID_SIZE; +// case RTEMS_INVALID_ADDRESS: +// return OperatingSystemIF::INVALID_ADDRESS; +// case RTEMS_INVALID_NUMBER: +// return OperatingSystemIF::INVALID_NUMBER; +// case RTEMS_NOT_DEFINED: +// return OperatingSystemIF::NOT_DEFINED; +// case RTEMS_RESOURCE_IN_USE: +// return OperatingSystemIF::RESOURCE_IN_USE; +// //TODO RTEMS_UNSATISFIED is double mapped for FLP so it will only return Queue_empty and not unsatisfied +// case RTEMS_UNSATISFIED: +// return OperatingSystemIF::QUEUE_EMPTY; +// case RTEMS_INCORRECT_STATE: +// return OperatingSystemIF::INCORRECT_STATE; +// case RTEMS_ALREADY_SUSPENDED: +// return OperatingSystemIF::ALREADY_SUSPENDED; +// case RTEMS_ILLEGAL_ON_SELF: +// return OperatingSystemIF::ILLEGAL_ON_SELF; +// case RTEMS_ILLEGAL_ON_REMOTE_OBJECT: +// return OperatingSystemIF::ILLEGAL_ON_REMOTE_OBJECT; +// case RTEMS_CALLED_FROM_ISR: +// return OperatingSystemIF::CALLED_FROM_ISR; +// case RTEMS_INVALID_PRIORITY: +// return OperatingSystemIF::INVALID_PRIORITY; +// case RTEMS_INVALID_CLOCK: +// return OperatingSystemIF::INVALID_CLOCK; +// case RTEMS_INVALID_NODE: +// return OperatingSystemIF::INVALID_NODE; +// case RTEMS_NOT_CONFIGURED: +// return OperatingSystemIF::NOT_CONFIGURED; +// case RTEMS_NOT_OWNER_OF_RESOURCE: +// return OperatingSystemIF::NOT_OWNER_OF_RESOURCE; +// case RTEMS_NOT_IMPLEMENTED: +// return OperatingSystemIF::NOT_IMPLEMENTED; +// case RTEMS_INTERNAL_ERROR: +// return OperatingSystemIF::INTERNAL_ERROR; +// case RTEMS_NO_MEMORY: +// return OperatingSystemIF::NO_MEMORY; +// case RTEMS_IO_ERROR: +// return OperatingSystemIF::IO_ERROR; +// default: +// return HasReturnvaluesIF::RETURN_FAILED; +// } +// } +//} diff --git a/osal/rtems/RtemsBasic.h b/osal/rtems/RtemsBasic.h index 37b75f6f..f7ab8614 100644 --- a/osal/rtems/RtemsBasic.h +++ b/osal/rtems/RtemsBasic.h @@ -2,11 +2,6 @@ #define OS_RTEMS_RTEMSBASIC_H_ #include -#include -extern "C" { -#include -} -#include #include #include #include @@ -14,24 +9,15 @@ extern "C" { #include -class RtemsBasic: public OperatingSystemIF { +class RtemsBasic { public: - /** - * A method to convert an OS-specific return code to the frameworks return value concept. - * @param inValue The return code coming from the OS. - * @return The converted return value. - */ - static ReturnValue_t convertReturnCode(rtems_status_code inValue); - static rtems_interval convertMsToTicks(uint32_t msIn) { - rtems_interval ticks_per_second; - rtems_clock_get(RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticks_per_second); + rtems_interval ticks_per_second = rtems_clock_get_ticks_per_second(); return (ticks_per_second * msIn) / 1000; } static rtems_interval convertTicksToMs(rtems_interval ticksIn) { - rtems_interval ticks_per_second; - rtems_clock_get(RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticks_per_second); + rtems_interval ticks_per_second = rtems_clock_get_ticks_per_second(); return (ticksIn * 1000) / ticks_per_second; } }; diff --git a/osal/rtems/TaskBase.cpp b/osal/rtems/TaskBase.cpp index 178e1c12..ad795645 100644 --- a/osal/rtems/TaskBase.cpp +++ b/osal/rtems/TaskBase.cpp @@ -1,7 +1,7 @@ #include #include "TaskBase.h" -const uint64_t PeriodicTaskIF::MINIMUM_STACK_SIZE=RTEMS_MINIMUM_STACK_SIZE; +const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE=RTEMS_MINIMUM_STACK_SIZE; TaskBase::TaskBase(rtems_task_priority set_priority, size_t stack_size, const char *name) { @@ -20,7 +20,7 @@ TaskBase::TaskBase(rtems_task_priority set_priority, size_t stack_size, RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR, RTEMS_FLOATING_POINT, &id); } - ReturnValue_t result = RtemsBasic::convertReturnCode(status); + ReturnValue_t result = convertReturnCode(status); if (result != HasReturnvaluesIF::RETURN_OK) { error << "TaskBase::TaskBase: createTask with name " << std::hex << osalName << std::dec << " failed with return code " @@ -39,5 +39,44 @@ rtems_id TaskBase::getId() { ReturnValue_t TaskBase::sleepFor(uint32_t ms) { rtems_status_code status = rtems_task_wake_after(RtemsBasic::convertMsToTicks(ms)); - return RtemsBasic::convertReturnCode(status); + return convertReturnCode(status); +} + + +ReturnValue_t TaskBase::convertReturnCode(rtems_status_code inValue) { + switch (inValue) { + case RTEMS_SUCCESSFUL: + return HasReturnvaluesIF::RETURN_OK; + case RTEMS_MP_NOT_CONFIGURED: + return HasReturnvaluesIF::RETURN_FAILED; + case RTEMS_INVALID_NAME: + return HasReturnvaluesIF::RETURN_FAILED; + case RTEMS_TOO_MANY: + return HasReturnvaluesIF::RETURN_FAILED; + case RTEMS_INVALID_ADDRESS: + return HasReturnvaluesIF::RETURN_FAILED; + case RTEMS_UNSATISFIED: + return HasReturnvaluesIF::RETURN_FAILED; + case RTEMS_INVALID_PRIORITY: + return HasReturnvaluesIF::RETURN_FAILED; + default: + return HasReturnvaluesIF::RETURN_FAILED; + } + +} + + +ReturnValue_t TaskBase::setAndStartPeriod(rtems_interval period, rtems_id *periodId) { + rtems_name periodName = (('P' << 24) + ('e' << 16) + ('r' << 8) + 'd'); + rtems_status_code status = rtems_rate_monotonic_create(periodName, periodId); + if (status == RTEMS_SUCCESSFUL) { + status = restartPeriod(period,*periodId); + } + return convertReturnCode(status); +} + +rtems_status_code TaskBase::restartPeriod(rtems_interval period, rtems_id periodId){ + //This is necessary to avoid a call with period = 0, which does not start the period. + rtems_status_code status = rtems_rate_monotonic_period(periodId, period + 1); + return status; } diff --git a/osal/rtems/TaskBase.h b/osal/rtems/TaskBase.h index af081fad..b9c1192a 100644 --- a/osal/rtems/TaskBase.h +++ b/osal/rtems/TaskBase.h @@ -37,6 +37,10 @@ public: rtems_id getId(); ReturnValue_t sleepFor(uint32_t ms); + static ReturnValue_t setAndStartPeriod(rtems_interval period, rtems_id *periodId); + static rtems_status_code restartPeriod(rtems_interval period, rtems_id periodId); +private: + static ReturnValue_t convertReturnCode(rtems_status_code inValue); }; diff --git a/osal/rtems/TaskFactory.cpp b/osal/rtems/TaskFactory.cpp index 82fb0dc3..2bee19c7 100644 --- a/osal/rtems/TaskFactory.cpp +++ b/osal/rtems/TaskFactory.cpp @@ -2,6 +2,7 @@ #include "MultiObjectTask.h" #include "PollingTask.h" #include "InitTask.h" +#include "RtemsBasic.h" #include //TODO: Different variant than the lazy loading in QueueFactory. What's better and why? @@ -14,13 +15,13 @@ TaskFactory* TaskFactory::instance() { return TaskFactory::factoryInstance; } -PeriodicTaskIF* TaskFactory::createPeriodicTask(OSAL::TaskName name_,OSAL::TaskPriority taskPriority_,OSAL::TaskStackSize stackSize_,OSAL::TaskPeriod periodInSeconds_,OSAL::TaskDeadlineMissedFunction deadLineMissedFunction_) { +PeriodicTaskIF* TaskFactory::createPeriodicTask(TaskName name_,TaskPriority taskPriority_,TaskStackSize stackSize_,TaskPeriod periodInSeconds_,TaskDeadlineMissedFunction deadLineMissedFunction_) { rtems_interval taskPeriod = periodInSeconds_ * Clock::getTicksPerSecond(); return static_cast(new MultiObjectTask(name_,taskPriority_,stackSize_,taskPeriod,deadLineMissedFunction_)); } -FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(OSAL::TaskName name_,OSAL::TaskPriority taskPriority_,OSAL::TaskStackSize stackSize_,OSAL::TaskPeriod periodInSeconds_,OSAL::TaskDeadlineMissedFunction deadLineMissedFunction_) { +FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(TaskName name_,TaskPriority taskPriority_,TaskStackSize stackSize_,TaskPeriod periodInSeconds_,TaskDeadlineMissedFunction deadLineMissedFunction_) { rtems_interval taskPeriod = periodInSeconds_ * Clock::getTicksPerSecond(); return static_cast(new PollingTask(name_,taskPriority_,stackSize_,taskPeriod,deadLineMissedFunction_)); } @@ -30,5 +31,11 @@ ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) { return HasReturnvaluesIF::RETURN_FAILED; } +ReturnValue_t TaskFactory::delayTask(uint32_t delayMs){ + rtems_task_wake_after(RtemsBasic::convertMsToTicks(delayMs)); + //Only return value is "RTEMS_SUCCESSFUL - always successful" so it has been neglected + return HasReturnvaluesIF::RETURN_OK; +} + TaskFactory::TaskFactory() { } diff --git a/parameters/ParameterHelper.cpp b/parameters/ParameterHelper.cpp index 6425ec40..75b71a7e 100644 --- a/parameters/ParameterHelper.cpp +++ b/parameters/ParameterHelper.cpp @@ -4,7 +4,7 @@ ParameterHelper::ParameterHelper(ReceivesParameterMessagesIF* owner) : owner(owner), storage(NULL) { - ownerQueueId = owner->getCommandQueue(); + } ParameterHelper::~ParameterHelper() { @@ -114,6 +114,9 @@ ReturnValue_t ParameterHelper::sendParameter(MessageQueueId_t to, uint32_t id, } ReturnValue_t ParameterHelper::initialize() { + ownerQueueId = owner->getCommandQueue(); + + storage = objectManager->get(objects::IPC_STORE); if (storage == NULL) { return HasReturnvaluesIF::RETURN_FAILED; diff --git a/returnvalues/FwClassIds.h b/returnvalues/FwClassIds.h index 64d1cb35..d21861c0 100644 --- a/returnvalues/FwClassIds.h +++ b/returnvalues/FwClassIds.h @@ -55,7 +55,10 @@ enum { DEVICE_COMMUNICATION_IF, //DC BSP, //BSP TIME_STAMPER_IF, //TSI 52 + //TODO This will shift all IDs for FLP SGP4PROPAGATOR_CLASS, //SGP4 53 + MUTEX_IF, //MUX 54 + MESSAGE_QUEUE_IF,//MQI 55 FW_CLASS_ID_COUNT //is actually count + 1 ! }; diff --git a/rmap/RMAP.cpp b/rmap/RMAP.cpp index 3f55e88b..4c95f6c9 100644 --- a/rmap/RMAP.cpp +++ b/rmap/RMAP.cpp @@ -5,7 +5,7 @@ #include ReturnValue_t RMAP::reset(RMAPCookie* cookie) { - return cookie->channel->reset(); + return cookie->getChannel()->reset(); } RMAP::RMAP(){ @@ -22,7 +22,7 @@ ReturnValue_t RMAP::sendWriteCommand(RMAPCookie *cookie, uint8_t* buffer, if (cookie->getChannel() == NULL) { return COMMAND_NO_CHANNEL; } - instruction = RMAP_COMMAND_WRITE | cookie->command_mask; + instruction = RMAPIds::RMAP_COMMAND_WRITE | cookie->getCommandMask(); return cookie->getChannel()->sendCommand(cookie, instruction, buffer, length); @@ -32,7 +32,7 @@ ReturnValue_t RMAP::getWriteReply(RMAPCookie *cookie) { if (cookie->getChannel() == NULL) { return COMMAND_NO_CHANNEL; } - if (cookie->header.instruction & (1 << RMAP_COMMAND_BIT_WRITE)) { + if (cookie->getHeader()->instruction & (1 << RMAPIds::RMAP_COMMAND_BIT_WRITE)) { return cookie->getChannel()->getReply(cookie, NULL, NULL); } else { return REPLY_MISSMATCH; @@ -53,8 +53,8 @@ ReturnValue_t RMAP::sendReadCommand(RMAPCookie *cookie, uint32_t expLength) { if (cookie->getChannel() == NULL) { return COMMAND_NO_CHANNEL; } - command = RMAP_COMMAND_READ - | (cookie->command_mask & ~(1 << RMAP_COMMAND_BIT_VERIFY)); + command = RMAPIds::RMAP_COMMAND_READ + | (cookie->getCommandMask() & ~(1 << RMAPIds::RMAP_COMMAND_BIT_VERIFY)); return cookie->getChannel()->sendCommand(cookie, command, NULL, expLength); @@ -68,7 +68,7 @@ ReturnValue_t RMAP::getReadReply(RMAPCookie *cookie, uint8_t **buffer, if (buffer == NULL || size == NULL) { return DeviceCommunicationIF::NULLPOINTER; } - if (cookie->header.instruction & (1 << RMAP_COMMAND_BIT_WRITE)) { + if (cookie->getHeader()->instruction & (1 << RMAPIds::RMAP_COMMAND_BIT_WRITE)) { return REPLY_MISSMATCH; } else { return cookie->getChannel()->getReply(cookie, buffer, size); diff --git a/rmap/RMAPChannelIF.h b/rmap/RMAPChannelIF.h index 11cf5256..6549c8ef 100644 --- a/rmap/RMAPChannelIF.h +++ b/rmap/RMAPChannelIF.h @@ -1,11 +1,12 @@ #ifndef RMAPCHANNELIF_H_ #define RMAPCHANNELIF_H_ -#include -#include +#include +#include -class RMAPChannelIF: public RMAP { +class RMAPChannelIF { public: + virtual ~RMAPChannelIF(){}; /** * Reset an RMAP channel * @@ -42,7 +43,7 @@ public: * - @c COMMAND_PORT_OUT_OF_RANGE if the port is invalid */ virtual ReturnValue_t setPort(int8_t port, uint8_t dest_addr, - uint8_t src_addr, PeriodicTaskIF* currentTask)=0; + uint8_t src_addr)=0; /** * Assign a SpaceWire port to the Channel @@ -54,7 +55,7 @@ public: * - @c COMMAND_OK if port was changed * - @c COMMAND_PORT_OUT_OF_RANGE if the port is invalid */ - virtual ReturnValue_t setPort(int8_t port, PeriodicTaskIF* currentTask)=0; + virtual ReturnValue_t setPort(int8_t port)=0; /** * Send an RMAP command diff --git a/rmap/RMAPCookie.cpp b/rmap/RMAPCookie.cpp index 2e9be1b5..5bf2ba9f 100644 --- a/rmap/RMAPCookie.cpp +++ b/rmap/RMAPCookie.cpp @@ -20,13 +20,11 @@ RMAPCookie::RMAPCookie() { this->header.datalen_m = 0; this->header.datalen_l = 0; this->header.header_crc = 0; - - - this->txdesc = NULL; - this->rxdesc_index = 0; this->channel = NULL; this->command_mask = 0; + this->dataCRC = 0; + this->maxReplyLen = 0; } @@ -47,11 +45,9 @@ RMAPCookie::RMAPCookie(uint32_t set_address, uint8_t set_extended_address, this->header.datalen_m = 0; this->header.datalen_l = 0; this->header.header_crc = 0; - - this->txdesc = NULL; - this->rxdesc_index = 0; this->channel = set_channel; this->command_mask = set_command_mask; + this->dataCRC = 0; this->maxReplyLen = maxReplyLen; } @@ -104,3 +100,25 @@ uint32_t RMAPCookie::getMaxReplyLen() const { void RMAPCookie::setMaxReplyLen(uint32_t maxReplyLen) { this->maxReplyLen = maxReplyLen; } + +RMAPStructs::rmap_cmd_header* RMAPCookie::getHeader(){ + return &this->header; +} + +uint16_t RMAPCookie::getTransactionIdentifier() const { + return static_cast((header.tid_h << 8) | (header.tid_l)); +} + +void RMAPCookie::setTransactionIdentifier(uint16_t id_) { + header.tid_l = id_ & 0xFF; + header.tid_h = (id_ >> 8 ) & 0xFF; +} + +uint32_t RMAPCookie::getDataLength() const { + return static_cast(header.datalen_h << 16 | header.datalen_m << 8 | header.datalen_l); +} +void RMAPCookie::setDataLength(uint32_t length_) { + header.datalen_l = length_ & 0xff; + header.datalen_m = (length_ >> 8) & 0xff; + header.datalen_h = (length_ >> 16) & 0xff; +} diff --git a/rmap/RMAPCookie.h b/rmap/RMAPCookie.h index 9918d4b4..c091ba18 100644 --- a/rmap/RMAPCookie.h +++ b/rmap/RMAPCookie.h @@ -7,8 +7,6 @@ class RMAPChannelIF; class RMAPCookie : public Cookie{ - friend class RMAP; - friend class RmapSPWChannel; public: //To Uli: Sorry, I need an empty ctor to initialize an array of cookies. RMAPCookie(); @@ -20,24 +18,41 @@ public: void setAddress(uint32_t address); uint32_t getAddress(); + void setExtendedAddress(uint8_t); uint8_t getExtendedAddress(); + void setChannel(RMAPChannelIF *channel); RMAPChannelIF *getChannel(); + void setCommandMask(uint8_t commandMask); uint8_t getCommandMask(); + uint32_t getMaxReplyLen() const; void setMaxReplyLen(uint32_t maxReplyLen); - //rmap_cookie* getDeviceDescriptor(); + uint16_t getTransactionIdentifier() const; + void setTransactionIdentifier(uint16_t id_); + + RMAPStructs::rmap_cmd_header* getHeader(); + + uint32_t getDataLength() const; + void setDataLength(uint32_t lenght_); + + uint8_t getDataCrc() const { + return dataCRC; + } + + void setDataCrc(uint8_t dataCrc) { + dataCRC = dataCrc; + } protected: RMAPStructs::rmap_cmd_header header; - void *txdesc; - uint8_t rxdesc_index; RMAPChannelIF *channel; uint8_t command_mask; uint32_t maxReplyLen; + uint8_t dataCRC; }; #endif /* RMAPCOOKIE_H_ */ diff --git a/rmap/RmapDeviceCommunicationIF.cpp b/rmap/RmapDeviceCommunicationIF.cpp new file mode 100644 index 00000000..4958b3ed --- /dev/null +++ b/rmap/RmapDeviceCommunicationIF.cpp @@ -0,0 +1,47 @@ +#include +#include + +//TODO Cast here are all potential bugs +RmapDeviceCommunicationIF::~RmapDeviceCommunicationIF() { +} + +ReturnValue_t RmapDeviceCommunicationIF::sendMessage(Cookie* cookie, + uint8_t* data, uint32_t len) { + return RMAP::sendWriteCommand((RMAPCookie *) cookie, data, len); +} + +ReturnValue_t RmapDeviceCommunicationIF::getSendSuccess(Cookie* cookie) { + return RMAP::getWriteReply((RMAPCookie *) cookie); +} + +ReturnValue_t RmapDeviceCommunicationIF::requestReceiveMessage( + Cookie* cookie) { + return RMAP::sendReadCommand((RMAPCookie *) cookie, + ((RMAPCookie *) cookie)->getMaxReplyLen()); +} + +ReturnValue_t RmapDeviceCommunicationIF::readReceivedMessage(Cookie* cookie, + uint8_t** buffer, uint32_t* size) { + return RMAP::getReadReply((RMAPCookie *) cookie, buffer, size); +} + +ReturnValue_t RmapDeviceCommunicationIF::setAddress(Cookie* cookie, + uint32_t address) { + + ((RMAPCookie *) cookie)->setAddress(address); + return HasReturnvaluesIF::RETURN_OK; +} + +uint32_t RmapDeviceCommunicationIF::getAddress(Cookie* cookie) { + return ((RMAPCookie *) cookie)->getAddress(); +} + +ReturnValue_t RmapDeviceCommunicationIF::setParameter(Cookie* cookie, + uint32_t parameter) { + //TODO Empty? + return HasReturnvaluesIF::RETURN_FAILED; +} + +uint32_t RmapDeviceCommunicationIF::getParameter(Cookie* cookie) { + return 0; +} diff --git a/rmap/RmapDeviceCommunicationIF.h b/rmap/RmapDeviceCommunicationIF.h new file mode 100644 index 00000000..12ae67e4 --- /dev/null +++ b/rmap/RmapDeviceCommunicationIF.h @@ -0,0 +1,80 @@ +#ifndef MISSION_RMAP_RMAPDEVICECOMMUNICATIONINTERFACE_H_ +#define MISSION_RMAP_RMAPDEVICECOMMUNICATIONINTERFACE_H_ + +#include + +/** + * @brief This class is a implementation of a DeviceCommunicationIF for RMAP calls. It expects RMAPCookies or a derived class of RMAPCookies + * + * @details The open, close and reOpen calls are mission specific + * The open call might return any child of RMAPCookies + * + * \ingroup rmap + */ +class RmapDeviceCommunicationIF: public DeviceCommunicationIF { + +public: + virtual ~RmapDeviceCommunicationIF(); + + + /** + * This method is mission specific as the open call will return a mission specific cookie + * + * @param cookie A cookie, can be mission specific subclass of RMAP Cookie + * @param address The address of the RMAP Cookie + * @param maxReplyLen Maximum length of expected reply + * @return + */ + virtual ReturnValue_t open(Cookie **cookie, uint32_t address, + uint32_t maxReplyLen) = 0; + + /** + * Use an existing cookie to open a connection to a new DeviceCommunication. + * The previous connection must not be closed. + * If the returnvalue is not RETURN_OK, the cookie is unchanged and + * can be used with the previous connection. + * + * @param cookie + * @param address + * @param maxReplyLen + * @return + */ + virtual ReturnValue_t reOpen(Cookie *cookie, uint32_t address, + uint32_t maxReplyLen) = 0; + + + /** + * Closing call of connection and memory free of cookie. Mission dependent call + * @param cookie + */ + virtual void close(Cookie *cookie) = 0; + + //SHOULDDO can data be const? + /** + * + * + * @param cookie Expects an RMAPCookie or derived from RMAPCookie Class + * @param data Data to be send + * @param len Length of the data to be send + * @return - Return codes of RMAP::sendWriteCommand() + */ + virtual ReturnValue_t sendMessage(Cookie *cookie, uint8_t *data, + uint32_t len); + + virtual ReturnValue_t getSendSuccess(Cookie *cookie); + + virtual ReturnValue_t requestReceiveMessage(Cookie *cookie); + + virtual ReturnValue_t readReceivedMessage(Cookie *cookie, uint8_t **buffer, + uint32_t *size); + + virtual ReturnValue_t setAddress(Cookie *cookie, uint32_t address); + + virtual uint32_t getAddress(Cookie *cookie); + + virtual ReturnValue_t setParameter(Cookie *cookie, uint32_t parameter); + + virtual uint32_t getParameter(Cookie *cookie); +}; + +#endif /* MISSION_RMAP_RMAPDEVICECOMMUNICATIONINTERFACE_H_ */ diff --git a/rmap/RmapSPWChannel.cpp b/rmap/RmapSPWChannel.cpp deleted file mode 100644 index d82166d1..00000000 --- a/rmap/RmapSPWChannel.cpp +++ /dev/null @@ -1,744 +0,0 @@ -#include -extern "C" { -#include -#include -} - -#include -#include - -////////////////////////////////////////////////////////////////////////////////// -//bits for the failure table -#define RMAP_RX_FAIL_CHECKED 0 -#define RMAP_RX_FAIL_EEP 1 -#define RMAP_RX_FAIL_TRUNC 2 -#define RMAP_RX_FAIL_LEN 3 -#define RMAP_RX_FAIL_CRC 4 -#define RMAP_RX_FAIL_DST_ADDR 5 -#define RMAP_RX_FAIL_PROTO 6 -#define RMAP_RX_FAIL_INSTR_TYPE 7 //this is when the instruction byte is really wrong (must be caused by device) -#define RMAP_RX_FAIL_INSTR 8 //this is when a wrong instruction byte was caused by a wrong instruction sent by the host and detected by the device -#define RMAP_RX_FAIL_SRC_ADDR 9 -#define RMAP_RX_FAIL_LEN_MISSMATCH 10 -#define RMAP_RX_FAIL_WRONG_REPLY 11 //a read command was answered by a write reply or the other way round -//pad a number so it is word aligned (32bit) -#define BYTES2WORDS(number) (((number) +3)/4) - -RmapSPWChannel::RmapSPWChannel(object_id_t setObjectId, - uint16_t buffersize_words, uint32_t maxPacketSize, int8_t portNr, - uint8_t dest_addr, uint8_t src_addr, PeriodicTaskIF* currentTask, - datapool::opus_variable_id portVariable) : - SystemObject(setObjectId), port(NULL), rx_index(0), max_rx(128), tx_index( - 0), max_tx(64), src_addr(src_addr), dest_addr(dest_addr), portPoolId( - portVariable) { - buffer = new uint32_t[buffersize_words]; - buffer_pointer = buffer; - end_of_buffer = &buffer[buffersize_words]; - max_packet_len = maxPacketSize & 0x1FFFFFC; - tid = 0; - failure_table = new uint16_t[128]; - setPort(portNr, dest_addr, src_addr, currentTask); -} - -RmapSPWChannel::~RmapSPWChannel() { - delete[] buffer; - delete[] failure_table; -} - -ReturnValue_t RmapSPWChannel::reset() { - uint8_t link_down = 0; - uint8_t missed, i; - uint32_t state; - - //check if channel has a port - if (port == NULL) { - return COMMAND_CHANNEL_DEACTIVATED; - } - - //check state of SPW - state = spw_get_state(port); - if (state != SPW_STATE_RUN) { - triggerEvent(SPW_LINK_DOWN, getCurrentPortNr()); - link_down++; - } - //SPW link errors - if ((state = (port->SPWSTR & 0x1de)) != 0) { - reportSpwstr(state); - } - //check DMA errors - if ((state = (port->SPWCHN & 0x180)) != 0) { - triggerEvent(SPW_ERROR, SPW_DMA, state); - } - - //hard reset spw - //only safe way to reset the descriptors - - spw_reset(port); - - spw_reset_rxdesc_table(port); - spw_reset_txdesc_table(port); - - //reset internal buffer - buffer_pointer = buffer; - -#ifdef LEON - asm("flush"); -#endif - - //check how many packets were received - missed = 0; - - if ((rx_index != 0) - && (rx_descriptor_table[rx_index - 1].word0 - & (1 << SPW_DESC_RX_ENABLE))) { - // printf("word 0 = %08lx\n", - // rx_descriptor_table[rx_index - 1].word0); - for (missed = 1; missed < rx_index; missed++) { - if (!(rx_descriptor_table[rx_index - 1 - missed].word0 - & (1 << SPW_DESC_RX_ENABLE))) - break; - } - triggerEvent(RMAP_MISSED_REPLIES, missed); - //missed is number of missed replies - - } - if (missed == rx_index) { - link_down++; - } - - for (i = rx_index - missed; i > 0; i--) { - if (!(failure_table[i - 1] & 1)) { - checkRxDescPacket(&(rx_descriptor_table[i - 1]), - &(failure_table[i - 1])); - } - if (failure_table[i - 1] & 0xFFFE) { - reportFailures(failure_table[i - 1], i - 1); - } - } - - //reset descriptor counter - rx_index = 0; - tx_index = 0; - - //clear all descriptors to get rid of unused ones - spw_rx_desc *rx_desc; - i = 0; - for (rx_desc = rx_descriptor_table; rx_desc < &rx_descriptor_table[max_rx]; - rx_desc++) { - rx_desc->word0 = 0; - failure_table[i++] = 0; - } - spw_tx_desc *tx_desc; - for (tx_desc = tx_descriptor_table; tx_desc < &tx_descriptor_table[max_tx]; - tx_desc++) { - tx_desc->word0 = 0; - } - - //restart spw - spw_start(port); - - if (link_down > 1) { - return LINK_DOWN; - } - return RETURN_OK; - -} - -ReturnValue_t RmapSPWChannel::isActive() { - if (port == NULL) { - return COMMAND_CHANNEL_DEACTIVATED; - } - uint32_t state = spw_get_state(port); - if (state != SPW_STATE_RUN) { - return LINK_DOWN; - } - return RETURN_OK; - -} - -ReturnValue_t RmapSPWChannel::setPort(int8_t portNr, uint8_t dest_addr, - uint8_t src_addr, PeriodicTaskIF* currentTask) { - - SPW_dev *new_port; - - //only accept ports from a list or -1, which disables channel - if (portNr >= SPW_devices.len && portNr < -1) { - return COMMAND_PORT_OUT_OF_RANGE; - } - - //check if crc is enabled - - if (portNr != -1) { - new_port = SPW_devices.devices[portNr]; - if (!spw_crc_enabled(new_port)) { - return NO_HW_CRC; - } - } else { - new_port = NULL; - } - - //anounce change - triggerEvent(RMAP_SWITCHED_PORT, portNr, getCurrentPortNr()); - if (portPoolId != 0) { - DataSet mySet; - PoolVariable channel(portPoolId, &mySet, - PoolVariableIF::VAR_WRITE); - mySet.read(); - channel = portNr; - mySet.commit(PoolVariableIF::VALID); - } - - //reset the old port to clear pending errors etc - reset(); - //assign new port - this->port = new_port; - - if (new_port == NULL) { - return RETURN_OK; - } - -//stop the new port - spw_stop(new_port); -//make sure the new port has the max len set - new_port->SPWRXL = max_packet_len; -//set the addresses - this->dest_addr = dest_addr; - this->src_addr = src_addr; - new_port->SPWNDR = src_addr; -//set descriptor table - tx_descriptor_table = spw_get_tx_descriptor_table(new_port); - rx_descriptor_table = spw_get_rx_descriptor_table(new_port); - spw_reset_rxdesc_table(new_port); - spw_reset_txdesc_table(new_port); -//reset the channel - spw_start(new_port); - currentTask->sleepFor(10); - reset(); - return RETURN_OK; -} - -ReturnValue_t RmapSPWChannel::setPort(int8_t port, PeriodicTaskIF* currentTask) { - return setPort(port, this->dest_addr, this->src_addr, currentTask); -} - -spw_rx_desc* RmapSPWChannel::findReply(RMAPCookie* cookie) { - spw_rx_desc *rxdesc; - uint8_t i; - -//look downwards - for (i = cookie->rxdesc_index; i < 200; i--) { - if ((rxdesc = checkRxDesc(cookie, i)) != NULL) { - return rxdesc; - } - } -//look upwards - for (i = cookie->rxdesc_index + 1; i < max_rx; i++) { - if ((rxdesc = checkRxDesc(cookie, i)) != NULL) { - return rxdesc; - } - } - - return NULL; - -} - -ReturnValue_t RmapSPWChannel::sendCommand(RMAPCookie* cookie, - uint8_t instruction, uint8_t* data, uint32_t datalen) { - - uint8_t headerlen = RMAP_COMMAND_HEADER_LEN - 1; - -//check if channel has a port - if (port == NULL) { - return COMMAND_CHANNEL_DEACTIVATED; - } - -//max send limit - if ((instruction & (1 << RMAP_COMMAND_BIT_WRITE)) - && (datalen & ~0xFFFFFF)) { - printf("application wants to send to much data with cookie at %p\n", - cookie); - return TOO_MUCH_DATA; - } -//max receive limit - if ((!(instruction & (1 << RMAP_COMMAND_BIT_WRITE))) - && (datalen + 1 + RMAP_READ_REPLY_HEADER_LEN > max_packet_len)) { - printf("application wants to read too much data with cookie at %p\n", - cookie); - return TOO_MUCH_DATA; - } - -//check if enough space is left in the buffer -//must be checked against max_packet_len, as you can not tell what hw will do, -//except that it will write this number at most - if ((buffer_pointer + BYTES2WORDS(max_packet_len)) - > end_of_buffer) { - printf("buffer is full, cookie is %p\n", cookie); - return COMMAND_BUFFER_FULL; - } - -//we allow tx descriptor wrap at user discretion, but check we have rx descriptors available -//as we dont wrap them -//note: [tr]x_index will be incremented when done - if (rx_index >= max_rx) { - triggerEvent(RMAP_NO_RX_DESCRIPTORS, 0); - return COMMAND_NO_DESCRIPTORS_AVAILABLE; - } - if (tx_index >= max_tx) { - if (max_tx == 64) { - tx_index = 0; - } else { - triggerEvent(RMAP_NO_TX_DESCRIPTORS, 0); - return COMMAND_NO_DESCRIPTORS_AVAILABLE; - } - } - -//check if tx descriptor is activated, which means we wrapped the table -//and came to a descriptor not yet sent -#ifdef LEON - asm("flush"); -#endif - if (tx_descriptor_table[tx_index].word0 & (1 << SPW_DESC_TX_ENABLE)) { - return COMMAND_NO_DESCRIPTORS_AVAILABLE; - } - -//prepare header -//set addresses - cookie->header.source_address = src_addr; - cookie->header.dest_address = dest_addr; -//set instruction - cookie->header.instruction = instruction; -//set the tid - cookie->header.tid_l = tid & 0xff; - cookie->header.tid_h = (tid >> 8) & 0xff; - tid++; -//set datalen - cookie->header.datalen_l = datalen & 0xff; - cookie->header.datalen_m = (datalen >> 8) & 0xff; - cookie->header.datalen_h = (datalen >> 16) & 0xff; - -//configure rx_descriptor - rx_descriptor_table[rx_index].word1 = (uint32_t) buffer_pointer; - rx_descriptor_table[rx_index].word0 = (1 << SPW_DESC_RX_ENABLE); - -//inc buffer - if (instruction & (1 << RMAP_COMMAND_BIT_WRITE)) { - buffer_pointer += BYTES2WORDS(RMAP_WRITE_REPLY_HEADER_LEN); - } else { - buffer_pointer += BYTES2WORDS(RMAP_READ_REPLY_HEADER_LEN + datalen + 1); //+1 for crc - } - -//configure tx_descriptor - tx_descriptor_table[tx_index].word1 = (uint32_t) &cookie->header; - if (instruction & (1 << RMAP_COMMAND_BIT_WRITE)) { - tx_descriptor_table[tx_index].word2 = datalen & 0xFFFFFF; - } else { - tx_descriptor_table[tx_index].word2 = 0; - } - tx_descriptor_table[tx_index].word3 = (uint32_t) data; - - if (instruction & (1 << RMAP_COMMAND_BIT_WRITE)) { - tx_descriptor_table[tx_index].word0 = headerlen - | (1 << SPW_DESC_TX_ENABLE) | (1 << SPW_DESC_TX_CRC_DATA) - | (1 << SPW_DESC_TX_CRC_HEADER); - } else { - tx_descriptor_table[tx_index].word0 = headerlen - | (1 << SPW_DESC_TX_ENABLE) | (1 << SPW_DESC_TX_CRC_HEADER); - } - -//remember descriptors to find them faster when looking for the reply - cookie->txdesc = &(tx_descriptor_table[tx_index]); - cookie->rxdesc_index = rx_index; - - tx_index++; - rx_index++; - -//inform the hw about the new descriptors - spw_new_rxdesc(port); - spw_new_txdesc(port); - - return RETURN_OK; - -} - -ReturnValue_t RmapSPWChannel::getReply(RMAPCookie* cookie, uint8_t** databuffer, - uint32_t* len) { - spw_rx_desc *rxdesc; - ReturnValue_t result; - uint32_t packetlen; -//was the command sent right - result = checkTxDesc(cookie); - if (result != RETURN_OK) { - return result; - } -//command was sent -//find the rx descriptor - if ((rxdesc = findReply(cookie)) == NULL) { - return REPLY_NO_REPLY; - } -//reply_header = (rmap_write_reply_header *) rxdesc->word1; - if (databuffer != NULL) { - packetlen = (rxdesc->word0 & 0x1FFFFFF); - *databuffer = ((uint8_t *) rxdesc->word1) + RMAP_READ_REPLY_HEADER_LEN; - *len = packetlen - RMAP_READ_REPLY_HEADER_LEN - 1; - } - result = ((RMAPStructs::rmap_write_reply_header *) (rxdesc->word1))->status; - //result is an RMAP standard return code, not a ReturnValue_t, thus we check against 0 - //and do MAKE_RETURN_CODE(), or set to RETURN_OK respectively - //if RETURN_OK == 0, this is not neccessary, but we should not make assumptions on the - //value of ReturnValues - if (result != 0) { - result = ((RMAP::INTERFACE_ID << 8) + (result)); - } else { - result = RETURN_OK; - } - return result; - -} - -ReturnValue_t RmapSPWChannel::checkTxDesc(RMAPCookie* cookie) { - RMAPStructs::rmap_cmd_header *header_desc; - uint16_t tid_desc, tid_cookie; - uint32_t status; -#ifdef LEON - asm("flush"); -#endif - if (cookie->txdesc == NULL) { - return REPLY_NOT_SENT; - } - header_desc = - (RMAPStructs::rmap_cmd_header *) ((spw_tx_desc *) cookie->txdesc)->word1; - status = ((spw_tx_desc *) cookie->txdesc)->word0 - & ((1 << SPW_DESC_TX_ENABLE) | (1 << SPW_DESC_TX_LINK_ERROR)); - tid_cookie = (cookie->header.tid_l) | (cookie->header.tid_h << 8); - tid_desc = (header_desc->tid_l) | (header_desc->tid_h << 8); - if (tid_cookie != tid_desc) { - //tx descriptor was reused, we have no info so let's assume the best - return RETURN_OK; - } -//was command sent or an error seen? - if (status == (1 << SPW_DESC_TX_ENABLE)) { - return REPLY_NOT_YET_SENT; - } - if (status & (1 << SPW_DESC_TX_LINK_ERROR)) { - triggerEvent(SPW_ERROR, SPW_LINK_ERROR, 0); - return REPLY_NOT_SENT; - } - return RETURN_OK; -} - -spw_rx_desc* RmapSPWChannel::checkRxDesc(RMAPCookie* cookie, - uint8_t rxdesc_index) { - uint16_t *failureEntry, tid_desc, tid_cookie; - spw_rx_desc *rxdesc; - RMAPStructs::rmap_read_reply_header *reply_header; - - rxdesc = &rx_descriptor_table[rxdesc_index]; - failureEntry = &failure_table[rxdesc_index]; - - if (!(*failureEntry)) { - checkRxDescPacket(rxdesc, failureEntry); - } - if (*failureEntry != 1 << RMAP_RX_FAIL_CHECKED) { - return NULL; - } -//the packet has been checked and is formally correct -//only thing left is to check tid and instruction: - - reply_header = (RMAPStructs::rmap_read_reply_header *) rxdesc->word1; - - tid_cookie = cookie->header.tid_l | (cookie->header.tid_h << 8); - tid_desc = reply_header->tid_l | (reply_header->tid_h << 8); - if (tid_desc != tid_cookie) { - return NULL; - } - - if ((cookie->header.instruction & 0x3F) != reply_header->instruction) { - *failureEntry |= (1 << RMAP_RX_FAIL_WRONG_REPLY); - return NULL; - } - return rxdesc; - -} - -void RmapSPWChannel::checkRxDescPacket(spw_rx_desc* rxdesc, - uint16_t* failureEntry) { - uint32_t statusword, len; - -#ifdef LEON - asm("flush"); -#endif - - statusword = rxdesc->word0; - - if ((statusword & (1 << SPW_DESC_RX_ENABLE)) || (statusword == 0)) { - return; - } - - *failureEntry = 1 << RMAP_RX_FAIL_CHECKED; - - if (statusword & (1 << SPW_DESC_RX_EEP)) { - *failureEntry |= (1 << RMAP_RX_FAIL_EEP); - return; - } - - if (statusword & (1 << SPW_DESC_RX_TRUNCATED)) { - *failureEntry |= (1 << RMAP_RX_FAIL_TRUNC); - return; - } - - len = statusword & 0x1FFFFFF; - if (!(len >= 13 || len == 8)) { - *failureEntry |= (1 << RMAP_RX_FAIL_LEN); - return; - } - if (checkCrc((uint8_t*) rxdesc->word1, len) != RETURN_OK) { - *failureEntry |= (1 << RMAP_RX_FAIL_CRC); - return; - } - - checkRmapHeader((void *) rxdesc->word1, len, failureEntry); - -} - -ReturnValue_t RmapSPWChannel::checkCrc(uint8_t* packet, uint32_t len) { - if (len == 8) { - if (crc_calculate(packet, len) == 0) { - return RETURN_OK; - } else { - return RETURN_FAILED; - } - } else { - if ((crc_calculate(packet, RMAP_READ_REPLY_HEADER_LEN) == 0) - && (crc_calculate(packet, len) == 0)) { - return RETURN_OK; - } else { - return RETURN_FAILED; - } - } -} - -void RmapSPWChannel::checkRmapHeader(void* _header, uint32_t len, - uint16_t* failureEntry) { - RMAPStructs::rmap_read_reply_header *header = - (RMAPStructs::rmap_read_reply_header *) _header; - uint32_t datalen; - - if (header->dest_address != src_addr) { - *failureEntry |= (1 << RMAP_RX_FAIL_DST_ADDR); - } - - if (header->protocol != 0x01) { - *failureEntry |= (1 << RMAP_RX_FAIL_PROTO); - } - - if (header->instruction & 0xC0) { - *failureEntry |= (1 << RMAP_RX_FAIL_INSTR_TYPE); - } else { //hope that works... - if ((!(header->instruction & (1 << RMAP_COMMAND_BIT_REPLY))) - || ((header->instruction & (1 << RMAP_COMMAND_BIT_VERIFY)) - && (!(header->instruction - & (1 << RMAP_COMMAND_BIT_WRITE)))) - || (header->instruction & 3)) { - if (header->status == REPLY_UNUSED_PACKET_TYPE_OR_COMMAND_CODE) { - *failureEntry |= (1 << RMAP_RX_FAIL_INSTR); - } else { - *failureEntry |= (1 << RMAP_RX_FAIL_INSTR_TYPE); - } - } - } - - if (header->instruction & (1 << RMAP_COMMAND_BIT_WRITE)) { - if (len != 8) { - *failureEntry |= (1 << RMAP_RX_FAIL_INSTR_TYPE); - } - } else { - if (len == 8) { - *failureEntry |= (1 << RMAP_RX_FAIL_INSTR_TYPE); - } - } - - if (header->source_address != dest_addr) { - *failureEntry |= (1 << RMAP_RX_FAIL_SRC_ADDR); - } - - if (len != 8) { - datalen = header->datalen_l | (header->datalen_m << 8) - | (header->datalen_h << 16); - if (datalen + RMAP_READ_REPLY_HEADER_LEN + 1 != len) { - *failureEntry |= (1 << RMAP_RX_FAIL_LEN_MISSMATCH); - } - } -} - -ReturnValue_t RmapSPWChannel::sendCommandBlocking(RMAPCookie *cookie, - uint8_t *data, uint32_t datalen, uint8_t **databuffer, uint32_t *len, - uint32_t timeout_us) { - uint32_t time; - ReturnValue_t result; - if (databuffer != NULL) { - result = sendReadCommand(cookie, datalen); - } else { - result = sendWriteCommand(cookie, data, datalen); - } - if (result != RETURN_OK) { - return result; - } - time = hw_timer_get_us(); - while (time - hw_timer_get_us() < timeout_us) { - result = getReply(cookie, databuffer, len); - if (!((result == REPLY_NOT_YET_SENT) || (result == REPLY_NO_REPLY))) { - return result; - } - } - if (result == REPLY_NOT_YET_SENT) { - return result; - } - return REPLY_TIMEOUT; -} - -//SHOULDDO find a better way to inject the Extended address -#include -ReturnValue_t RmapSPWChannel::open(Cookie **cookie, uint32_t address, - uint32_t maxReplyLen) { - *cookie = new RMAPCookie(address, IoBoardExtendedAddresses::DEVICE_BUFFER, - this, 0, maxReplyLen); - return RETURN_OK; -} - -ReturnValue_t RmapSPWChannel::reOpen(Cookie* cookie, uint32_t address, - uint32_t maxReplyLen) { - ReturnValue_t result = isActive(); - if (result != RETURN_OK) { - return result; - } - RMAPCookie *rCookie = dynamic_cast(cookie); - if (rCookie == NULL) { - return INVALID_COOKIE_TYPE; - } - rCookie->setAddress(address); - rCookie->setChannel(this); - rCookie->setCommandMask(0); - rCookie->setExtendedAddress(IoBoardExtendedAddresses::DEVICE_BUFFER); - rCookie->setMaxReplyLen(maxReplyLen); - return RETURN_OK; -} - -void RmapSPWChannel::close(Cookie* cookie) { - delete cookie; -} - -ReturnValue_t RmapSPWChannel::sendMessage(Cookie* cookie, uint8_t* data, - uint32_t len) { - return sendWriteCommand((RMAPCookie *) cookie, data, len); -} - -ReturnValue_t RmapSPWChannel::getSendSuccess(Cookie* cookie) { - return getWriteReply((RMAPCookie *) cookie); -} - -ReturnValue_t RmapSPWChannel::requestReceiveMessage(Cookie* cookie) { - return sendReadCommand((RMAPCookie *) cookie, - ((RMAPCookie *) cookie)->getMaxReplyLen()); -} - -ReturnValue_t RmapSPWChannel::readReceivedMessage(Cookie* cookie, - uint8_t** buffer, uint32_t* size) { - return getReadReply((RMAPCookie *) cookie, buffer, size); -} - -ReturnValue_t RmapSPWChannel::setAddress(Cookie* cookie, uint32_t address) { - ((RMAPCookie *) cookie)->setAddress(address); - return HasReturnvaluesIF::RETURN_OK; -} - -uint32_t RmapSPWChannel::getAddress(Cookie* cookie) { - return ((RMAPCookie *) cookie)->getAddress(); -} - -ReturnValue_t RmapSPWChannel::setParameter(Cookie* cookie, uint32_t parameter) { - return RETURN_FAILED; -} - -uint32_t RmapSPWChannel::getParameter(Cookie* cookie) { - return 0; -} - -void RmapSPWChannel::reportFailures(uint16_t failureEntry, - uint8_t descriptorNr) { - if (failureEntry & (1 << RMAP_RX_FAIL_CRC)) { - triggerEvent(RMAP_PROTOCOL_ERROR, REPLY_INVALID_DATA_CRC, descriptorNr); - } - if (failureEntry & (1 << RMAP_RX_FAIL_DST_ADDR)) { - triggerEvent(RMAP_PROTOCOL_ERROR, REPLY_INVALID_TARGET_LOGICAL_ADDRESS, - descriptorNr); - } - if (failureEntry & (1 << RMAP_RX_FAIL_EEP)) { - triggerEvent(RMAP_PROTOCOL_ERROR, REPLY_EEP, descriptorNr); - } - if (failureEntry & (1 << RMAP_RX_FAIL_INSTR)) { - triggerEvent(RMAP_PROTOCOL_ERROR, - REPLY_COMMAND_NOT_IMPLEMENTED_OR_NOT_AUTHORISED, descriptorNr); - } - if (failureEntry & (1 << RMAP_RX_FAIL_INSTR_TYPE)) { - triggerEvent(RMAP_PROTOCOL_ERROR, REPLY_RESERVED, descriptorNr); - } - if (failureEntry & (1 << RMAP_RX_FAIL_LEN)) { - triggerEvent(RMAP_PROTOCOL_ERROR, REPLY_TOO_MUCH_DATA, descriptorNr); - } - if (failureEntry & (1 << RMAP_RX_FAIL_LEN_MISSMATCH)) { - triggerEvent(RMAP_PROTOCOL_ERROR, REPLY_INVALID_DATA, descriptorNr); - } - if (failureEntry & (1 << RMAP_RX_FAIL_PROTO)) { - triggerEvent(RMAP_PROTOCOL_ERROR, REPLY_GENERAL_ERROR_CODE, - descriptorNr); - } - if (failureEntry & (1 << RMAP_RX_FAIL_SRC_ADDR)) { - triggerEvent(RMAP_PROTOCOL_ERROR, REPLY_GENERAL_ERROR_CODE, - descriptorNr); - } - if (failureEntry & (1 << RMAP_RX_FAIL_TRUNC)) { - triggerEvent(RMAP_PROTOCOL_ERROR, REPLY_TRANSMISSION_ERROR, - descriptorNr); - } - if (failureEntry & (1 << RMAP_RX_FAIL_WRONG_REPLY)) { - triggerEvent(RMAP_PROTOCOL_ERROR, REPLY_INVALID_KEY, descriptorNr); - } - -} - -void RmapSPWChannel::reportSpwstr(uint32_t spwstr) { - if (spwstr & (1 << SPW_SPWSTR_CE)) { - triggerEvent(SPW_ERROR, SPW_CREDIT); - } - if (spwstr & (1 << SPW_SPWSTR_ER)) { - triggerEvent(SPW_ERROR, SPW_ESCAPE); - } - if (spwstr & (1 << SPW_SPWSTR_DE)) { - triggerEvent(SPW_ERROR, SPW_DISCONNECT); - } - if (spwstr & (1 << SPW_SPWSTR_PE)) { - triggerEvent(SPW_ERROR, SPW_PARITY); - } - if (spwstr & (1 << SPW_SPWSTR_WE)) { - triggerEvent(SPW_ERROR, SPW_WRITE_SYNC); - } - if (spwstr & (1 << SPW_SPWSTR_IA)) { - triggerEvent(SPW_ERROR, SPW_INVALID_ADDRESS); - } - if (spwstr & (1 << SPW_SPWSTR_EE)) { - triggerEvent(SPW_ERROR, SPW_EARLY_EOP); - } -} - -uint8_t RmapSPWChannel::null_crc = 0; - -int8_t RmapSPWChannel::getCurrentPortNr() { - uint8_t i; - int8_t oldport = -1; - for (i = 0; i < SPW_devices.len; ++i) { - if (SPW_devices.devices[i] == this->port) { - oldport = i; - } - } - return oldport; -} diff --git a/rmap/RmapSPWChannel.h b/rmap/RmapSPWChannel.h deleted file mode 100644 index 4f097ac3..00000000 --- a/rmap/RmapSPWChannel.h +++ /dev/null @@ -1,135 +0,0 @@ -#ifndef RMAPCHANNEL_H_ -#define RMAPCHANNEL_H_ - -#include -#include -extern "C" { -#include -} -#include -#include -#include -#include - -class RmapSPWChannel: public SystemObject, - public RMAPChannelIF, - public DeviceCommunicationIF { -public: - static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::CDH_1; - static const Event SPW_ERROR = MAKE_EVENT(0, SEVERITY::LOW); - static const Event SPW_LINK_DOWN = MAKE_EVENT(1, SEVERITY::LOW); -// static const Event SPW_CREDIT = MAKE_EVENT(1, SEVERITY::LOW); -// static const Event SPW_ESCAPE = MAKE_EVENT(2, SEVERITY::LOW); -// static const Event SPW_DISCONNECT = MAKE_EVENT(3, SEVERITY::LOW); -// static const Event SPW_PARITY = MAKE_EVENT(4, SEVERITY::LOW); -// static const Event SPW_WRITE_SYNC = MAKE_EVENT(5, SEVERITY::LOW); -// static const Event SPW_INVALID_ADDRESS = MAKE_EVENT(6, SEVERITY::LOW); -// static const Event SPW_EARLY_EOP = MAKE_EVENT(7, SEVERITY::LOW); -// static const Event SPW_DMA = MAKE_EVENT(8, SEVERITY::LOW); -// static const Event SPW_LINK_ERROR = MAKE_EVENT(9, SEVERITY::LOW); - static const Event RMAP_PROTOCOL_ERROR = MAKE_EVENT(10, SEVERITY::LOW); -// static const Event RMAP_CRC = MAKE_EVENT(10, SEVERITY::LOW); -// static const Event RMAP_DST_ADDR = MAKE_EVENT(11, SEVERITY::LOW); -// static const Event RMAP_EEP = MAKE_EVENT(12, SEVERITY::LOW); -// static const Event RMAP_INSTR = MAKE_EVENT(13, SEVERITY::LOW); -// static const Event RMAP_INSTR_TYPE = MAKE_EVENT(14, SEVERITY::LOW); -// static const Event RMAP_LEN = MAKE_EVENT(15, SEVERITY::LOW); -// static const Event RMAP_LEN_MISSMATCH = MAKE_EVENT(16, SEVERITY::LOW); -// static const Event RMAP_PROTO = MAKE_EVENT(17, SEVERITY::LOW); -// static const Event RMAP_SRC_ADDR = MAKE_EVENT(18, SEVERITY::LOW); -// static const Event RMAP_TRUNC = MAKE_EVENT(19, SEVERITY::LOW); -// static const Event RMAP_WRONG_REPLY = MAKE_EVENT(20, SEVERITY::LOW); - static const Event RMAP_MISSED_REPLIES = MAKE_EVENT(21, SEVERITY::LOW); - static const Event RMAP_NO_RX_DESCRIPTORS = MAKE_EVENT(22, SEVERITY::LOW); - static const Event RMAP_NO_TX_DESCRIPTORS = MAKE_EVENT(23, SEVERITY::LOW); - static const Event RMAP_SWITCHED_PORT = MAKE_EVENT(24, SEVERITY::INFO); - - RmapSPWChannel(object_id_t setObjectId, uint16_t buffersize_words, - uint32_t maxPacketSize, int8_t portNr, uint8_t dest_addr, - uint8_t src_addr, PeriodicTaskIF* currentTask, datapool::opus_variable_id portVariable = - datapool::NO_PARAMETER); - - virtual ~RmapSPWChannel(); - - virtual ReturnValue_t reset(); - - virtual ReturnValue_t isActive(); - - virtual ReturnValue_t setPort(int8_t port, uint8_t dest_addr, - uint8_t src_addr, PeriodicTaskIF* currentTask); - - virtual ReturnValue_t setPort(int8_t port, PeriodicTaskIF* currentTask); - - virtual ReturnValue_t sendCommand(RMAPCookie *cookie, uint8_t instruction, - uint8_t *data, uint32_t datalen); - virtual ReturnValue_t getReply(RMAPCookie *cookie, uint8_t **databuffer, - uint32_t *len); - virtual ReturnValue_t sendCommandBlocking(RMAPCookie *cookie, uint8_t *data, - uint32_t datalen, uint8_t **databuffer, uint32_t *len, - uint32_t timeout_us); - - virtual ReturnValue_t open(Cookie **cookie, uint32_t address, - uint32_t maxReplyLen); - - virtual ReturnValue_t reOpen(Cookie *cookie, uint32_t address, - uint32_t maxReplyLen); - - virtual void close(Cookie *cookie); - - virtual ReturnValue_t sendMessage(Cookie *cookie, uint8_t *data, - uint32_t len); - - virtual ReturnValue_t getSendSuccess(Cookie *cookie); - - virtual ReturnValue_t requestReceiveMessage(Cookie *cookie); - - virtual ReturnValue_t readReceivedMessage(Cookie *cookie, uint8_t **buffer, - uint32_t *size); - - virtual ReturnValue_t setAddress(Cookie *cookie, uint32_t address); - - virtual uint32_t getAddress(Cookie *cookie); - - virtual ReturnValue_t setParameter(Cookie *cookie, uint32_t parameter); - - virtual uint32_t getParameter(Cookie *cookie); - -private: - - SPW_dev *port; - uint32_t *buffer; - uint32_t *buffer_pointer; //points to the next free space in the buffer - uint32_t *end_of_buffer; //points to the word AFTER the buffer - spw_tx_desc *tx_descriptor_table; - spw_rx_desc *rx_descriptor_table; - uint16_t *failure_table; - uint32_t max_packet_len; - uint16_t tid; -// uint8_t port_has_crc; - uint8_t rx_index; //index of the next unused rx descriptor - uint8_t max_rx; - uint8_t tx_index; //index of the next unused tx descriptor - uint8_t max_tx; - uint8_t src_addr; - uint8_t dest_addr; - - datapool::opus_variable_id portPoolId; - - static uint8_t null_crc; - - spw_rx_desc *findReply(RMAPCookie *cookie); - ReturnValue_t checkTxDesc(RMAPCookie *cookie); - spw_rx_desc *checkRxDesc(RMAPCookie *cookie, uint8_t rxdesc_index); - void checkRxDescPacket(spw_rx_desc *rxdesc, uint16_t *failureEntry); - - ReturnValue_t checkCrc(uint8_t *packet, uint32_t len); - - void checkRmapHeader(void *_header, uint32_t len, uint16_t *failureEntry); - - void reportFailures(uint16_t failureEntry, uint8_t descriptorNr); - void reportSpwstr(uint32_t spwstr); - int8_t getCurrentPortNr(); - -}; - -#endif /* RMAPCHANNEL_H_ */ diff --git a/rmap/rmapStructs.h b/rmap/rmapStructs.h index aa609143..bf0fb260 100644 --- a/rmap/rmapStructs.h +++ b/rmap/rmapStructs.h @@ -7,28 +7,45 @@ ////////////////////////////////////////////////////////////////////////////////// // RMAP command bits -#define RMAP_COMMAND_BIT_INCREMENT 2 -#define RMAP_COMMAND_BIT_REPLY 3 -#define RMAP_COMMAND_BIT_WRITE 5 -#define RMAP_COMMAND_BIT_VERIFY 4 -#define RMAP_COMMAND_BIT 6 +//#define RMAP_COMMAND_BIT_INCREMENT 2 +//#define RMAP_COMMAND_BIT_REPLY 3 +//#define RMAP_COMMAND_BIT_WRITE 5 +//#define RMAP_COMMAND_BIT_VERIFY 4 +//#define RMAP_COMMAND_BIT 6 + +namespace RMAPIds{ + +static const uint8_t RMAP_COMMAND_BIT_INCREMENT = 2; +static const uint8_t RMAP_COMMAND_BIT_REPLY = 3; +static const uint8_t RMAP_COMMAND_BIT_WRITE = 5; +static const uint8_t RMAP_COMMAND_BIT_VERIFY = 4; +static const uint8_t RMAP_COMMAND_BIT = 6; ////////////////////////////////////////////////////////////////////////////////// // RMAP commands - -#define RMAP_COMMAND_WRITE ((1< //for testing on x86 #include #include +#include class EndianSwapper { private: @@ -13,9 +13,9 @@ private: public: template static T swap(T in) { -#ifndef BYTE_ORDER -#error BYTE_ORDER not defined -#elif BYTE_ORDER == LITTLE_ENDIAN +#ifndef BYTE_ORDER_SYSTEM +#error BYTE_ORDER_SYSTEM not defined +#elif BYTE_ORDER_SYSTEM == LITTLE_ENDIAN T tmp; uint8_t *pointerOut = (uint8_t *) &tmp; uint8_t *pointerIn = (uint8_t *) ∈ @@ -23,21 +23,21 @@ public: pointerOut[sizeof(T) - count - 1] = pointerIn[count]; } return tmp; -#elif BYTE_ORDER == BIG_ENDIAN +#elif BYTE_ORDER_SYSTEM == BIG_ENDIAN return in; #else #error Unknown Byte Order #endif } static void swap(uint8_t* out, const uint8_t* in, uint32_t size) { -#ifndef BYTE_ORDER -#error BYTE_ORDER not defined -#elif BYTE_ORDER == LITTLE_ENDIAN +#ifndef BYTE_ORDER_SYSTEM +#error BYTE_ORDER_SYSTEM not defined +#elif BYTE_ORDER_SYSTEM == LITTLE_ENDIAN for (uint8_t count = 0; count < size; count++) { out[size - count - 1] = in[count]; } return; -#elif BYTE_ORDER == BIG_ENDIAN +#elif BYTE_ORDER_SYSTEM == BIG_ENDIAN memcpy(out, in, size); return; #endif diff --git a/serviceinterface/ServiceInterfaceBuffer.cpp b/serviceinterface/ServiceInterfaceBuffer.cpp index 4bab4016..58065994 100644 --- a/serviceinterface/ServiceInterfaceBuffer.cpp +++ b/serviceinterface/ServiceInterfaceBuffer.cpp @@ -39,6 +39,7 @@ int ServiceInterfaceBuffer::sync(void) { return 0; } +#ifndef UT699 ServiceInterfaceBuffer::ServiceInterfaceBuffer(std::string set_message, uint16_t port) { this->log_message = set_message; @@ -59,8 +60,11 @@ void ServiceInterfaceBuffer::putChars(char const* begin, char const* end) { } } +#endif #ifdef UT699 +#include + ServiceInterfaceBuffer::ServiceInterfaceBuffer(std::string set_message, uint16_t port) { this->log_message = set_message; this->isActive = true; diff --git a/serviceinterface/ServiceInterfaceBuffer.h b/serviceinterface/ServiceInterfaceBuffer.h index 672d238e..b42c8a19 100644 --- a/serviceinterface/ServiceInterfaceBuffer.h +++ b/serviceinterface/ServiceInterfaceBuffer.h @@ -6,7 +6,7 @@ #include #include - +#ifndef UT699 class ServiceInterfaceBuffer: public std::basic_streambuf > { friend class ServiceInterfaceStream; @@ -36,7 +36,7 @@ private: // In this function, the characters are parsed. void putChars(char const* begin, char const* end); }; - +#endif diff --git a/storagemanager/PoolManager.h b/storagemanager/PoolManager.h index da22d24b..68a7addc 100644 --- a/storagemanager/PoolManager.h +++ b/storagemanager/PoolManager.h @@ -12,8 +12,7 @@ #include -#include -#include +#include /** * @brief The PoolManager class provides an intermediate data storage with @@ -50,19 +49,9 @@ public: template inline ReturnValue_t PoolManager::reserveSpace(const uint32_t size, store_address_t* address, bool ignoreFault) { - ReturnValue_t mutexStatus = mutex->lockMutex(MutexIF::NO_TIMEOUT); - ReturnValue_t status = this->DATA_STORAGE_FULL; - if ( mutexStatus == this->RETURN_OK ) { - status = LocalPool::reserveSpace(size,address,ignoreFault); - } else { - error << "PoolManager::findEmpty: Mutex could not be acquired. Error code: " << mutexStatus << std::endl; - } - mutexStatus = mutex->lockMutex(MutexIF::NO_TIMEOUT); - if (mutexStatus != this->RETURN_OK) { - return mutexStatus; - } else { - return status; - } + MutexHelper mutexHelper(mutex,MutexIF::NO_TIMEOUT); + ReturnValue_t status = LocalPool::reserveSpace(size,address,ignoreFault); + return status; } template @@ -81,37 +70,17 @@ template inline ReturnValue_t PoolManager::deleteData( store_address_t packet_id) { // debug << "PoolManager( " << translateObject(getObjectId()) << " )::deleteData from store " << packet_id.pool_index << ". id is " << packet_id.packet_index << std::endl; - ReturnValue_t mutexStatus = mutex->lockMutex(MutexIF::NO_TIMEOUT); - ReturnValue_t status = this->RETURN_OK; - if ( mutexStatus == this->RETURN_OK ) { - LocalPool::deleteData(packet_id); - } else { - error << "PoolManager:deleteData: Mutex could not be acquired. Error code: " << status << std::endl; - } - mutexStatus = mutex->lockMutex(MutexIF::NO_TIMEOUT); - if (mutexStatus != this->RETURN_OK) { - return mutexStatus; - } else { - return status; - } + MutexHelper mutexHelper(mutex,MutexIF::NO_TIMEOUT); + ReturnValue_t status = LocalPool::deleteData(packet_id); + return status; } template inline ReturnValue_t PoolManager::deleteData(uint8_t* buffer, uint32_t size, store_address_t* storeId) { - ReturnValue_t mutexStatus = mutex->lockMutex(MutexIF::NO_TIMEOUT); - ReturnValue_t status = this->RETURN_OK; - if ( mutexStatus == this->RETURN_OK ) { - LocalPool::deleteData(buffer, size, storeId); - } else { - error << "PoolManager:deleteData: Mutex could not be acquired. Error code: " << status << std::endl; - } - mutexStatus = mutex->lockMutex(MutexIF::NO_TIMEOUT); - if (mutexStatus != this->RETURN_OK) { - return mutexStatus; - } else { - return status; - } + MutexHelper mutexHelper(mutex,MutexIF::NO_TIMEOUT); + ReturnValue_t status = LocalPool::deleteData(buffer, size, storeId); + return status; } #endif /* POOLMANAGER_H_ */ diff --git a/subsystem/SubsystemBase.cpp b/subsystem/SubsystemBase.cpp index 42a41335..76430b56 100644 --- a/subsystem/SubsystemBase.cpp +++ b/subsystem/SubsystemBase.cpp @@ -8,7 +8,7 @@ SubsystemBase::SubsystemBase(object_id_t setObjectId, object_id_t parent, SystemObject(setObjectId), mode(initialMode), submode(SUBMODE_NONE), childrenChangedMode( false), commandsOutstanding(0), commandQueue(NULL), healthHelper(this, setObjectId), modeHelper(this), parentId(parent) { - QueueFactory::instance()->createMessageQueue(commandQueueDepth, + commandQueue = QueueFactory::instance()->createMessageQueue(commandQueueDepth, CommandMessage::MAX_MESSAGE_SIZE); } diff --git a/tasks/ExecutableObjectIF.h b/tasks/ExecutableObjectIF.h index 22273259..5c5955c1 100644 --- a/tasks/ExecutableObjectIF.h +++ b/tasks/ExecutableObjectIF.h @@ -11,10 +11,11 @@ #ifndef EXECUTABLEOBJECTIF_H_ #define EXECUTABLEOBJECTIF_H_ - -#include class PeriodicTaskIF; +#include + +#include /** * @brief The interface provides a method to execute objects within a task. * @details The performOperation method, that is required by the interface is @@ -34,7 +35,15 @@ public: */ virtual ReturnValue_t performOperation(uint8_t operationCode = 0) = 0; - virtual void setTaskIF(PeriodicTaskIF* interface) {}; + /** + * @brief Function called during setup assignment of object to task + * @details Has to be called from the function that assigns the object to a task and + * enables the object implementation to overwrite this function and get a reference to the executing task + * @param task_ Pointer to the taskIF of this task + */ + virtual void setTaskIF(PeriodicTaskIF* task_) { + + } }; #endif /* EXECUTABLEOBJECTIF_H_ */ diff --git a/tasks/PeriodicTaskIF.h b/tasks/PeriodicTaskIF.h index 1415d7f6..304a7de6 100644 --- a/tasks/PeriodicTaskIF.h +++ b/tasks/PeriodicTaskIF.h @@ -2,6 +2,7 @@ #define PERIODICTASKIF_H_ #include +#include class ExecutableObjectIF; /** * New version of TaskIF @@ -10,7 +11,7 @@ class ExecutableObjectIF; */ class PeriodicTaskIF { public: - static const uint64_t MINIMUM_STACK_SIZE; + static const size_t MINIMUM_STACK_SIZE; /** * @brief A virtual destructor as it is mandatory for interfaces. */ @@ -20,7 +21,7 @@ public: */ virtual ReturnValue_t startTask() = 0; - virtual ReturnValue_t addComponent(object_id_t) {return HasReturnvaluesIF::RETURN_FAILED;}; + virtual ReturnValue_t addComponent(object_id_t object) {return HasReturnvaluesIF::RETURN_FAILED;}; virtual ReturnValue_t sleepFor(uint32_t ms) = 0; diff --git a/tasks/Typedef.h b/tasks/Typedef.h index 190d05d7..b393ee1e 100644 --- a/tasks/Typedef.h +++ b/tasks/Typedef.h @@ -4,7 +4,7 @@ //TODO more generic? typedef const char* TaskName; typedef uint8_t TaskPriority; -typedef uint16_t TaskStackSize; +typedef size_t TaskStackSize; typedef double TaskPeriod; typedef void (*TaskDeadlineMissedFunction)(); diff --git a/tcdistribution/PUSDistributor.cpp b/tcdistribution/PUSDistributor.cpp index ab87c571..a209620f 100644 --- a/tcdistribution/PUSDistributor.cpp +++ b/tcdistribution/PUSDistributor.cpp @@ -52,7 +52,8 @@ ReturnValue_t PUSDistributor::registerService(AcceptsTelecommandsIF* service) { errorCode = this->queueMap.insert( std::pair(serviceId, queue)).second; if (errorCode == false) { - returnValue = OperatingSystemIF::RESOURCE_IN_USE; + //TODO Return Code + returnValue = MessageQueueIF::NO_QUEUE; } return returnValue; } diff --git a/tcdistribution/TcDistributor.cpp b/tcdistribution/TcDistributor.cpp index 8c4ff16f..a463ea77 100644 --- a/tcdistribution/TcDistributor.cpp +++ b/tcdistribution/TcDistributor.cpp @@ -20,7 +20,7 @@ ReturnValue_t TcDistributor::performOperation(uint8_t opCode) { status = tcQueue->receiveMessage(¤tMessage)) { status = handlePacket(); } - if (status == OperatingSystemIF::QUEUE_EMPTY) { + if (status == MessageQueueIF::EMPTY) { return RETURN_OK; } else { return status; diff --git a/tcdistribution/TcDistributor.h b/tcdistribution/TcDistributor.h index fa3a7584..b80f08e6 100644 --- a/tcdistribution/TcDistributor.h +++ b/tcdistribution/TcDistributor.h @@ -2,7 +2,6 @@ #define TCDISTRIBUTOR_H_ #include #include -#include #include #include #include diff --git a/timemanager/CCSDSTime.cpp b/timemanager/CCSDSTime.cpp index 171db377..32032716 100644 --- a/timemanager/CCSDSTime.cpp +++ b/timemanager/CCSDSTime.cpp @@ -45,7 +45,7 @@ ReturnValue_t CCSDSTime::convertToCcsds(Ccs_mseconds* to, to->minute = from->minute; to->second = from->second; to->secondEminus2 = from->usecond / 10000; - to->secondEminus4 = (from->usecond % 10) * 10 / 1000; + to->secondEminus4 = (from->usecond % 10000) / 100; return RETURN_OK; } @@ -142,7 +142,7 @@ ReturnValue_t CCSDSTime::convertFromCCS(Clock::TimeOfDay_t* to, const uint8_t* f if (temp->secondEminus4 >= 100) { return INVALID_TIME_FORMAT; } - to->usecond += temp->secondEminus4 / 10 * 1000; + to->usecond += temp->secondEminus4 * 100; } return RETURN_OK; diff --git a/tmtcservices/CommandingServiceBase.h b/tmtcservices/CommandingServiceBase.h index ecc8b52f..aace0e21 100644 --- a/tmtcservices/CommandingServiceBase.h +++ b/tmtcservices/CommandingServiceBase.h @@ -49,6 +49,16 @@ public: virtual ReturnValue_t initialize(); + /** + * Implementation of ExecutableObjectIF function + * + * Used to setup the reference of the task, that executes this component + * @param task_ Pointer to the taskIF of this task + */ + virtual void setTaskIF(PeriodicTaskIF* task_){ + executingTask = task_; + }; + protected: struct CommandInfo { struct tcInfo { @@ -92,6 +102,11 @@ protected: object_id_t packetDestination; + /** + * Pointer to the task which executes this component, is invalid before setTaskIF was called. + */ + PeriodicTaskIF* executingTask; + void sendTmPacket(uint8_t subservice, const uint8_t *data, uint32_t dataLen, const uint8_t* headerData = NULL, uint32_t headerSize = 0); void sendTmPacket(uint8_t subservice, object_id_t objectId, @@ -147,7 +162,7 @@ CommandingServiceBase::CommandingServiceBase(object_id_t setObjectId, NULL), commandQueue(NULL), requestQueue(NULL), commandMap( numberOfParallelCommands), failureParameter1(0), failureParameter2( 0), packetSource(setPacketSource), packetDestination( - setPacketDestination) { + setPacketDestination),executingTask(NULL) { commandQueue = QueueFactory::instance()->createMessageQueue(queueDepth); requestQueue = QueueFactory::instance()->createMessageQueue(20); //TODO: Funny magic number. } diff --git a/tmtcservices/PusServiceBase.cpp b/tmtcservices/PusServiceBase.cpp index b5eca15e..c8f6accf 100644 --- a/tmtcservices/PusServiceBase.cpp +++ b/tmtcservices/PusServiceBase.cpp @@ -42,7 +42,7 @@ ReturnValue_t PusServiceBase::performOperation(uint8_t opCode) { this->currentPacket.deletePacket(); errorParameter1 = 0; errorParameter2 = 0; - } else if (status == OperatingSystemIF::QUEUE_EMPTY) { + } else if (status == MessageQueueIF::EMPTY) { status = RETURN_OK; // debug << "PusService " << (uint16_t)this->serviceId << ": no new packet." << std::endl; break; diff --git a/tmtcservices/SourceSequenceCounter.h b/tmtcservices/SourceSequenceCounter.h index b5885dfd..b92a5c84 100644 --- a/tmtcservices/SourceSequenceCounter.h +++ b/tmtcservices/SourceSequenceCounter.h @@ -15,10 +15,10 @@ private: public: SourceSequenceCounter() : sequenceCount(0) {} void increment() { - this->sequenceCount = (++this->sequenceCount) % (SpacePacketBase::LIMIT_SEQUENCE_COUNT); + sequenceCount = (sequenceCount+1) % (SpacePacketBase::LIMIT_SEQUENCE_COUNT); } void decrement() { - this->sequenceCount = (--this->sequenceCount) % (SpacePacketBase::LIMIT_SEQUENCE_COUNT); + sequenceCount = (sequenceCount-1) % (SpacePacketBase::LIMIT_SEQUENCE_COUNT); } uint16_t get() { return this->sequenceCount; } void reset(uint16_t toValue = 0) {