Merge branch 'development' into mueller/LocalPoolRefactoring

This commit is contained in:
Robin Müller 2020-12-01 13:54:56 +01:00
commit 24ba716ab2
49 changed files with 295 additions and 268 deletions

View File

@ -1,10 +1,11 @@
#ifndef FSFW_DEFAULTCFG_VERSION_H_
#define FSFW_DEFAULTCFG_VERSION_H_
const char* const FSFW_VERSION_NAME = "fsfw";
const char* const FSFW_VERSION_NAME = "ASTP";
#define FSFW_VERSION 0
#define FSFW_SUBVERSION 0
#define FSFW_REVISION 1

157
README.md
View File

@ -1,4 +1,159 @@
Flight Software Framework (FSFW)
======
I want to be written!
The Flight Software Framework is a C++ Object Oriented Framework for unmanned,
automated systems like Satellites.
The initial version of the Flight Software Framework was developed during
the Flying Laptop Project by the University of Stuttgart in cooperation
with Airbus Defence and Space GmbH.
## Intended Use
The framework is designed for systems, which communicate with external devices, perform control loops, receive telecommands and send telemetry, and need to maintain a high level of availability.
Therefore, a mode and health system provides control over the states of the software and the controlled devices.
In addition, a simple mechanism of event based fault detection, isolation and recovery is implemented as well.
The recommended hardware is a microprocessor with more than 2 MB of RAM and 1 MB of non-volatile Memory.
For reference, current Applications use a Cobham Gaisler UT699 (LEON3FT), a ISISPACE IOBC or a Zynq-7020 SoC.
## Structure
The general structure is driven by the usage of interfaces provided by objects. The FSFW uses C++11 as baseline. The intention behind this is that this C++ Standard should be widely available, even with older compilers.
The FSFW uses dynamic allocation during the initialization but provides static containers during runtime.
This simplifies the instantiation of objects and allows the usage of some standard containers.
Dynamic Allocation after initialization is discouraged and different solutions are provided in the FSFW to achieve that.
The fsfw uses Run-time type information.
Exceptions are not allowed.
### Failure Handling
Functions should return a defined ReturnValue_t to signal to the caller that something is gone wrong.
Returnvalues must be unique. For this the function HasReturnvaluesIF::makeReturnCode or the Macro MAKE_RETURN can be used.
The CLASS_ID is a unique id for that type of object. See returnvalues/FwClassIds.
### OSAL
The FSFW provides operation system abstraction layers for Linux, FreeRTOS and RTEMS. A independent OSAL called "host" is currently not finished. This aims to be running on windows as well.
The OSAL provides periodic tasks, message queues, clocks and Semaphores as well as Mutexes.
### Core Components
Clock:
* This is a class of static functions that can be used at anytime
* Leap Seconds must be set if any time conversions from UTC to other times is used
ObjectManager (must be created):
* The component which handles all references. All SystemObjects register at this component.
* Any SystemObject needs to have a unique ObjectId. Those can be managed like objects::framework_objects.
* A reference to an object can be get by calling the following function. T must be the specific Interface you want to call.
A nullptr check of the returning Pointer must be done. This function is based on Run-time type information.
``` c++
template <typename T> T* ObjectManagerIF::get( object_id_t id )
```
* A typical way to create all objects on startup is a handing a static produce function to the ObjectManager on creation.
By calling objectManager->initialize() the produce function will be called and all SystemObjects will be initialized afterwards.
Event Manager:
* Component which allows routing of events
* Other objects can subscribe to specific events, ranges of events or all events of an object.
* Subscriptions can be done during runtime but should be done during initialization
* Amounts of allowed subscriptions must be configured by setting this parameters:
``` c++
namespace fsfwconfig {
//! Configure the allocated pool sizes for the event manager.
static constexpr size_t FSFW_EVENTMGMR_MATCHTREE_NODES = 240;
static constexpr size_t FSFW_EVENTMGMT_EVENTIDMATCHERS = 120;
static constexpr size_t FSFW_EVENTMGMR_RANGEMATCHERS = 120;
}
```
Health Table:
* A component which holds every health state
* Provides a thread safe way to access all health states without the need of message exchanges
Stores
* The message based communication can only exchange a few bytes of information inside the message itself. Therefore, additional information can be exchanged with Stores. With this, only the store address must be exchanged in the message.
* Internally, the FSFW uses an IPC Store to exchange data between processes. For incoming TCs a TC Store is used. For outgoing TM a TM store is used.
* All of them should use the Thread Safe Class storagemanager/PoolManager
Tasks
There are two different types of tasks:
* The PeriodicTask just executes objects that are of type ExecutableObjectIF in the order of the insertion to the Tasks.
* FixedTimeslotTask executes a list of calls in the order of the given list. This is intended for DeviceHandlers, where polling should be in a defined order. An example can be found in defaultcfg/fsfwconfig/pollingSequence
### Static Ids in the framework
Some parts of the framework use a static routing address for communication.
An example setup of ids can be found in the example config in "defaultcft/fsfwconfig/objects/Factory::setStaticFrameworkObjectIds()".
### Events
Events are tied to objects. EventIds can be generated by calling the Macro MAKE_EVENT. This works analog to the returnvalues.
Every object that needs own EventIds has to get a unique SUBSYSTEM_ID.
Every SystemObject can call triggerEvent from the parent class.
Therefore, event messages contain the specific EventId and the objectId of the object that has triggered.
### Internal Communication
Components communicate mostly over Message through Queues.
Those queues are created by calling the singleton QueueFactory::instance()->create().
### External Communication
The external communication with the mission control system is mostly up to the user implementation.
The FSFW provides PUS Services which can be used to but don't need to be used.
The services can be seen as a conversion from a TC to a message based communication and back.
#### CCSDS Frames, CCSDS Space Packets and PUS
If the communication is based on CCSDS Frames and Space Packets, several classes can be used to distributed the packets to the corresponding services. Those can be found in tcdistribution.
If Space Packets are used, a timestamper must be created.
An example can be found in the timemanager folder, this uses CCSDSTime::CDS_short.
#### DeviceHandling
DeviceHandlers are a core component of the FSFW.
The idea is, to have a software counterpart of every physical device to provide a simple mode, health and commanding interface.
By separating the underlying Communication Interface with DeviceCommunicationIF, a DH can be tested on different hardware.
The DH has mechanisms to monitor the communication with the physical device which allow for FDIR reaction.
A standard FDIR component for the DH will be created automatically but can be overwritten by the user.
#### Modes, Health
The two interfaces HasModesIF and HasHealthIF provide access for commanding and monitoring of components.
On-board Mode Management is implement in hierarchy system.
DeviceHandlers and Controllers are the lowest part of the hierarchy.
The next layer are Assemblies. Those assemblies act as a component which handle redundancies of handlers.
Assemblies share a common core with the next level which are the Subsystems.
Those Assemblies are intended to act as auto-generated components from a database which describes the subsystem modes.
The definitions contain transition and target tables which contain the DH, Assembly and Controller Modes to be commanded.
Transition tables contain as many steps as needed to reach the mode from any other mode, e.g. a switch into any higher AOCS mode might first turn on the sensors, than the actuators and the controller as last component.
The target table is used to describe the state that is checked continuously by the subsystem.
All of this allows System Modes to be generated as Subsystem object as well from the same database.
This System contains list of subsystem modes in the transition and target tables.
Therefore, it allows a modular system to create system modes and easy commanding of those, because only the highest components must be commanded.
The health state represents if the component is able to perform its tasks.
This can be used to signal the system to avoid using this component instead of a redundant one.
The on-board FDIR uses the health state for isolation and recovery.
## Example config
A example config can be found in defaultcfg/fsfwconfig.
## Unit Tests
Unit Tests are provided in the unittest folder. Those use the catch2 framework but do not include catch2 itself.
See README.md in the unittest Folder.

View File

@ -1,5 +1,6 @@
#include "ActionHelper.h"
#include "HasActionsIF.h"
#include "../ipc/MessageQueueSenderIF.h"
#include "../objectmanager/ObjectManagerIF.h"

View File

@ -1,5 +1,5 @@
#ifndef ACTIONMESSAGE_H_
#define ACTIONMESSAGE_H_
#ifndef FSFW_ACTION_ACTIONMESSAGE_H_
#define FSFW_ACTION_ACTIONMESSAGE_H_
#include "../ipc/CommandMessage.h"
#include "../objectmanager/ObjectManagerIF.h"
@ -18,15 +18,19 @@ public:
static const Command_t COMPLETION_SUCCESS = MAKE_COMMAND_ID(5);
static const Command_t COMPLETION_FAILED = MAKE_COMMAND_ID(6);
virtual ~ActionMessage();
static void setCommand(CommandMessage* message, ActionId_t fid, store_address_t parameters);
static void setCommand(CommandMessage* message, ActionId_t fid,
store_address_t parameters);
static ActionId_t getActionId(const CommandMessage* message );
static store_address_t getStoreId(const CommandMessage* message );
static void setStepReply(CommandMessage* message, ActionId_t fid, uint8_t step, ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
static void setStepReply(CommandMessage* message, ActionId_t fid,
uint8_t step, ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
static uint8_t getStep(const CommandMessage* message );
static ReturnValue_t getReturnCode(const CommandMessage* message );
static void setDataReply(CommandMessage* message, ActionId_t actionId, store_address_t data);
static void setCompletionReply(CommandMessage* message, ActionId_t fid, ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
static void setDataReply(CommandMessage* message, ActionId_t actionId,
store_address_t data);
static void setCompletionReply(CommandMessage* message, ActionId_t fid,
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
static void clear(CommandMessage* message);
};
#endif /* ACTIONMESSAGE_H_ */
#endif /* FSFW_ACTION_ACTIONMESSAGE_H_ */

View File

@ -1,5 +1,5 @@
#ifndef COMMANDSACTIONSIF_H_
#define COMMANDSACTIONSIF_H_
#ifndef FSFW_ACTION_COMMANDSACTIONSIF_H_
#define FSFW_ACTION_COMMANDSACTIONSIF_H_
#include "CommandActionHelper.h"
#include "../returnvalues/HasReturnvaluesIF.h"
@ -24,11 +24,14 @@ public:
virtual MessageQueueIF* getCommandQueuePtr() = 0;
protected:
virtual void stepSuccessfulReceived(ActionId_t actionId, uint8_t step) = 0;
virtual void stepFailedReceived(ActionId_t actionId, uint8_t step, ReturnValue_t returnCode) = 0;
virtual void dataReceived(ActionId_t actionId, const uint8_t* data, uint32_t size) = 0;
virtual void stepFailedReceived(ActionId_t actionId, uint8_t step,
ReturnValue_t returnCode) = 0;
virtual void dataReceived(ActionId_t actionId, const uint8_t* data,
uint32_t size) = 0;
virtual void completionSuccessfulReceived(ActionId_t actionId) = 0;
virtual void completionFailedReceived(ActionId_t actionId, ReturnValue_t returnCode) = 0;
virtual void completionFailedReceived(ActionId_t actionId,
ReturnValue_t returnCode) = 0;
};
#endif /* COMMANDSACTIONSIF_H_ */
#endif /* FSFW_ACTION_COMMANDSACTIONSIF_H_ */

View File

@ -3,6 +3,7 @@
#include <FSFWVersion.h>
#include <cstddef>
#include <cstdint>
//! Used to determine whether C++ ostreams are used
//! Those can lead to code bloat.

View File

@ -1,8 +1,8 @@
#ifndef CONFIG_DEVICES_LOGICALADDRESSES_H_
#define CONFIG_DEVICES_LOGICALADDRESSES_H_
#include <config/objects/systemObjectList.h>
#include <fsfw/devicehandlers/CookieIF.h>
#include "../objects/systemObjectList.h"
#include <cstdint>
/**

View File

@ -1,4 +1,5 @@
#include <config/ipc/MissionMessageTypes.h>
#include "missionMessageTypes.h"
#include <fsfw/ipc/CommandMessageIF.h>
void messagetypes::clearMissionMessage(CommandMessage* message) {

View File

@ -11,6 +11,7 @@
#include <fsfw/tmtcpacket/pus/TmPacketStored.h>
#include <fsfw/tmtcservices/CommandingServiceBase.h>
#include <fsfw/tmtcservices/PusServiceBase.h>
#include <internalError/InternalErrorReporter.h>
#include <cstdint>
@ -31,15 +32,15 @@ void Factory::produce(void) {
setStaticFrameworkObjectIds();
new EventManager(objects::EVENT_MANAGER);
new HealthTable(objects::HEALTH_TABLE);
//new InternalErrorReporter(objects::INTERNAL_ERROR_REPORTER);
new InternalErrorReporter(objects::INTERNAL_ERROR_REPORTER);
}
void Factory::setStaticFrameworkObjectIds() {
PusServiceBase::packetSource = objects::PUS_PACKET_DISTRIBUTOR;
PusServiceBase::packetDestination = objects::TM_FUNNEL;
PusServiceBase::packetSource = objects::NO_OBJECT;
PusServiceBase::packetDestination = objects::NO_OBJECT;
CommandingServiceBase::defaultPacketSource = objects::PUS_PACKET_DISTRIBUTOR;
CommandingServiceBase::defaultPacketDestination = objects::TM_FUNNEL;
CommandingServiceBase::defaultPacketSource = objects::NO_OBJECT;
CommandingServiceBase::defaultPacketDestination = objects::NO_OBJECT;
VerificationReporter::messageReceiver = objects::PUS_SERVICE_1_VERIFICATION;
@ -48,7 +49,6 @@ void Factory::setStaticFrameworkObjectIds() {
DeviceHandlerFailureIsolation::powerConfirmationId = objects::NO_OBJECT;
TmPacketStored::timeStamperId = objects::PUS_TIME;
//TmFunnel::downlinkDestination = objects::NO_OBJECT;
TmPacketStored::timeStamperId = objects::NO_OBJECT;
}

View File

@ -18,8 +18,6 @@ public:
static const uint8_t TRANSITION_MODE_CHILD_ACTION_MASK = 0x20;
static const uint8_t TRANSITION_MODE_BASE_ACTION_MASK = 0x10;
static constexpr Command_t NO_COMMAND = 0xffffffff;
/**
* @brief This is the mode the <strong>device handler</strong> is in.
*

View File

@ -4,7 +4,7 @@
#include <stdint.h>
#include "fwSubsystemIdRanges.h"
//could be move to more suitable location
#include <subsystemIdRanges.h>
#include <events/subsystemIdRanges.h>
typedef uint16_t EventId_t;
typedef uint8_t EventSeverity_t;

View File

@ -70,5 +70,3 @@ CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tmtcpacket/packetmatcher/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tmtcpacket/pus/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tmtcservices/*.cpp)
CXXSRC += $(wildcard $(FRAMEWORK_PATH)/pus/*.cpp)
INCLUDES += $(CURRENTPATH)

View File

@ -33,7 +33,7 @@ ReturnValue_t TcUnixUdpPollingTask::performOperation(uint8_t opCode) {
while(1) {
//! Sender Address is cached here.
struct sockaddr_in senderAddress;
socklen_t senderSockLen = 0;
socklen_t senderSockLen = sizeof(senderAddress);
ssize_t bytesReceived = recvfrom(serverUdpSocket,
receptionBuffer.data(), frameSize, receptionFlags,
reinterpret_cast<sockaddr*>(&senderAddress), &senderSockLen);

View File

@ -65,9 +65,13 @@ TmTcUnixUdpBridge::~TmTcUnixUdpBridge() {
ReturnValue_t TmTcUnixUdpBridge::sendTm(const uint8_t *data, size_t dataLen) {
int flags = 0;
MutexHelper lock(mutex, MutexIF::TimeoutType::WAITING, 10);
if(ipAddrAnySet){
clientAddress.sin_addr.s_addr = htons(INADDR_ANY);
//clientAddress.sin_addr.s_addr = inet_addr("127.73.73.1");
clientAddressLen = sizeof(serverAddress);
}
// char ipAddress [15];
// sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET,
@ -85,7 +89,7 @@ ReturnValue_t TmTcUnixUdpBridge::sendTm(const uint8_t *data, size_t dataLen) {
return HasReturnvaluesIF::RETURN_OK;
}
void TmTcUnixUdpBridge::checkAndSetClientAddress(sockaddr_in newAddress) {
void TmTcUnixUdpBridge::checkAndSetClientAddress(sockaddr_in& newAddress) {
MutexHelper lock(mutex, MutexIF::TimeoutType::WAITING, 10);
// char ipAddress [15];
@ -168,3 +172,7 @@ void TmTcUnixUdpBridge::handleSendError() {
}
}
void TmTcUnixUdpBridge::setClientAddressToAny(bool ipAddrAnySet){
this->ipAddrAnySet = ipAddrAnySet;
}

View File

@ -20,8 +20,9 @@ public:
uint16_t serverPort = 0xFFFF,uint16_t clientPort = 0xFFFF);
virtual~ TmTcUnixUdpBridge();
void checkAndSetClientAddress(sockaddr_in clientAddress);
void checkAndSetClientAddress(sockaddr_in& clientAddress);
void setClientAddressToAny(bool ipAddrAnySet);
protected:
virtual ReturnValue_t sendTm(const uint8_t * data, size_t dataLen) override;
@ -36,6 +37,8 @@ private:
struct sockaddr_in serverAddress;
socklen_t serverAddressLen = 0;
bool ipAddrAnySet = false;
//! Access to the client address is mutex protected as it is set
//! by another task.
MutexIF* mutex;

View File

@ -3,7 +3,7 @@
#include <rtems/score/todimpl.h>
uint16_t Clock::leapSeconds = 0;
MutexIF* Clock::timeMutex = NULL;
MutexIF* Clock::timeMutex = nullptr;
uint32_t Clock::getTicksPerSecond(void){
rtems_interval ticks_per_second = rtems_clock_get_ticks_per_second();
@ -40,7 +40,7 @@ ReturnValue_t Clock::setClock(const timeval* time) {
//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
//TODO Second parameter is ISR_lock_Context
_TOD_Set(&newTime,NULL);
_TOD_Set(&newTime,nullptr);
return HasReturnvaluesIF::RETURN_OK;
}
@ -131,7 +131,7 @@ ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) {
ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) {
//SHOULDDO: works not for dates in the past (might have less leap seconds)
if (timeMutex == NULL) {
if (timeMutex == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
@ -157,40 +157,34 @@ ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) {
if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t result = timeMutex->lockMutex(MutexIF::NO_TIMEOUT);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
MutexHelper helper(timeMutex);
leapSeconds = leapSeconds_;
result = timeMutex->unlockMutex();
return result;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) {
if(timeMutex==NULL){
if(timeMutex==nullptr){
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t result = timeMutex->lockMutex(MutexIF::NO_TIMEOUT);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
MutexHelper helper(timeMutex);
*leapSeconds_ = leapSeconds;
result = timeMutex->unlockMutex();
return result;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::checkOrCreateClockMutex(){
if(timeMutex==NULL){
if(timeMutex==nullptr){
MutexFactory* mutexFactory = MutexFactory::instance();
if (mutexFactory == NULL) {
if (mutexFactory == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
timeMutex = mutexFactory->createMutex();
if (timeMutex == NULL) {
if (timeMutex == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
}

View File

@ -158,7 +158,7 @@ uint32_t CpuUsage::ThreadData::getSerializedSize() const {
}
ReturnValue_t CpuUsage::ThreadData::deSerialize(const uint8_t** buffer,
int32_t* size, Endianness streamEndianness) {
size_t* size, Endianness streamEndianness) {
ReturnValue_t result = SerializeAdapter::deSerialize(&id, buffer,
size, streamEndianness);
if (result != HasReturnvaluesIF::RETURN_OK) {

View File

@ -12,8 +12,8 @@ ReturnValue_t InternalErrorCodes::translate(uint8_t code) {
// return INVALID_WORKSPACE_ADDRESS;
case INTERNAL_ERROR_TOO_LITTLE_WORKSPACE:
return TOO_LITTLE_WORKSPACE;
case INTERNAL_ERROR_WORKSPACE_ALLOCATION:
return WORKSPACE_ALLOCATION;
// case INTERNAL_ERROR_WORKSPACE_ALLOCATION:
// return WORKSPACE_ALLOCATION;
// case INTERNAL_ERROR_INTERRUPT_STACK_TOO_SMALL:
// return INTERRUPT_STACK_TOO_SMALL;
case INTERNAL_ERROR_THREAD_EXITTED:

View File

@ -1,86 +0,0 @@
#include "Interrupt.h"
extern "C" {
#include <bsp_flp/hw_timer/hw_timer.h>
#include <bsp_flp/hw_uart/hw_uart.h>
}
#include "RtemsBasic.h"
ReturnValue_t Interrupt::enableInterrupt(InterruptNumber_t interruptNumber) {
volatile uint32_t* irqMask = hw_irq_mask;
uint32_t expectedValue = *irqMask | (1 << interruptNumber);
*irqMask = expectedValue;
uint32_t tempValue = *irqMask;
if (tempValue == expectedValue) {
return HasReturnvaluesIF::RETURN_OK;
} else {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t Interrupt::setInterruptServiceRoutine(IsrHandler_t handler,
InterruptNumber_t interrupt, IsrHandler_t* oldHandler) {
IsrHandler_t oldHandler_local;
if (oldHandler == NULL) {
oldHandler = &oldHandler_local;
}
//+ 0x10 comes because of trap type assignment to IRQs in UT699 processor
rtems_status_code status = rtems_interrupt_catch(handler, interrupt + 0x10,
oldHandler);
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) {
//TODO Not implemented
return HasReturnvaluesIF::RETURN_FAILED;
}
//SHOULDDO: Make default values (edge, polarity) settable?
ReturnValue_t Interrupt::enableGpioInterrupt(InterruptNumber_t interrupt) {
volatile uint32_t* irqMask = hw_irq_mask;
uint32_t expectedValue = *irqMask | (1 << interrupt);
*irqMask = expectedValue;
uint32_t tempValue = *irqMask;
if (tempValue == expectedValue) {
volatile hw_gpio_port_t* ioPorts = hw_gpio_port;
ioPorts->direction &= ~(1 << interrupt); //Direction In
ioPorts->interrupt_edge |= 1 << interrupt; //Edge triggered
ioPorts->interrupt_polarity |= 1 << interrupt; //Trigger on rising edge
ioPorts->interrupt_mask |= 1 << interrupt; //Enable
return HasReturnvaluesIF::RETURN_OK;
} else {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t Interrupt::disableGpioInterrupt(InterruptNumber_t interrupt) {
volatile uint32_t* irqMask = hw_irq_mask;
uint32_t expectedValue = *irqMask & ~(1 << interrupt);
*irqMask = expectedValue;
uint32_t tempValue = *irqMask;
if (tempValue == expectedValue) {
//Disable gpio IRQ
volatile hw_gpio_port_t* ioPorts = hw_gpio_port;
ioPorts->interrupt_mask &= ~(1 << interrupt);
return HasReturnvaluesIF::RETURN_OK;
} else {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
bool Interrupt::isInterruptInProgress() {
return rtems_interrupt_is_in_progress();
}

View File

@ -1,50 +0,0 @@
#ifndef OS_RTEMS_INTERRUPT_H_
#define OS_RTEMS_INTERRUPT_H_
#include "../../returnvalues/HasReturnvaluesIF.h"
#include <cstring>
#include <rtems.h>
typedef rtems_isr_entry IsrHandler_t;
typedef rtems_isr IsrReturn_t;
typedef rtems_vector_number InterruptNumber_t;
class Interrupt {
public:
virtual ~Interrupt(){};
/**
* Establishes a new interrupt service routine.
* @param handler The service routine to establish
* @param interrupt The interrupt (NOT trap type) the routine shall react to.
* @return RETURN_OK on success. Otherwise, the OS failure code is returned.
*/
static ReturnValue_t setInterruptServiceRoutine(IsrHandler_t handler,
InterruptNumber_t interrupt, IsrHandler_t *oldHandler = NULL);
static ReturnValue_t enableInterrupt(InterruptNumber_t interruptNumber);
static ReturnValue_t disableInterrupt(InterruptNumber_t interruptNumber);
/**
* Enables the interrupt given.
* The function tests, if the InterruptMask register was written successfully.
* @param interrupt The interrupt to enable.
* @return RETURN_OK if the interrupt was set successfully. RETURN_FAILED else.
*/
static ReturnValue_t enableGpioInterrupt(InterruptNumber_t interrupt);
/**
* Disables the interrupt given.
* @param interrupt The interrupt to disable.
* @return RETURN_OK if the interrupt was set successfully. RETURN_FAILED else.
*/
static ReturnValue_t disableGpioInterrupt(InterruptNumber_t interrupt);
/**
* Checks if the current executing context is an ISR.
* @return true if handling an interrupt, false else.
*/
static bool isInterruptInProgress();
};
#endif /* OS_RTEMS_INTERRUPT_H_ */

View File

@ -1,14 +1,15 @@
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../objectmanager/ObjectManagerIF.h"
#include "MessageQueue.h"
#include "RtemsBasic.h"
#include <cstring>
MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size) :
id(0), lastPartner(0), defaultDestination(NO_QUEUE), internalErrorReporter(NULL) {
id(0), lastPartner(0), defaultDestination(NO_QUEUE), internalErrorReporter(nullptr) {
rtems_name name = ('Q' << 24) + (queueCounter++ << 8);
rtems_status_code status = rtems_message_queue_create(name, message_depth,
max_message_size, 0, &(this->id));
if (status != RTEMS_SUCCESSFUL) {
error << "MessageQueue::MessageQueue: Creating Queue " << std::hex
sif::error << "MessageQueue::MessageQueue: Creating Queue " << std::hex
<< name << std::dec << " failed with status:"
<< (uint32_t) status << std::endl;
this->id = 0;
@ -20,15 +21,15 @@ MessageQueue::~MessageQueue() {
}
ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo,
MessageQueueMessage* message, bool ignoreFault) {
MessageQueueMessageIF* message, bool ignoreFault) {
return sendMessageFrom(sendTo, message, this->getId(), ignoreFault);
}
ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessage* message) {
ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) {
return sendToDefaultFrom(message, this->getId());
}
ReturnValue_t MessageQueue::reply(MessageQueueMessage* message) {
ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) {
if (this->lastPartner != 0) {
return sendMessage(this->lastPartner, message, this->getId());
} else {
@ -36,27 +37,29 @@ ReturnValue_t MessageQueue::reply(MessageQueueMessage* message) {
}
}
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message,
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message,
MessageQueueId_t* receivedFrom) {
ReturnValue_t status = this->receiveMessage(message);
*receivedFrom = this->lastPartner;
return status;
}
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message) {
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
size_t size = 0;
rtems_status_code status = rtems_message_queue_receive(id,
message->getBuffer(), &(message->messageSize),
message->getBuffer(),&size,
RTEMS_NO_WAIT, 1);
if (status == RTEMS_SUCCESSFUL) {
message->setMessageSize(size);
this->lastPartner = message->getSender();
//Check size of incoming message.
if (message->messageSize < message->getMinimumMessageSize()) {
if (message->getMessageSize() < message->getMinimumMessageSize()) {
return HasReturnvaluesIF::RETURN_FAILED;
}
} 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);
memset(message->getData(), 0, message->getMaximumMessageSize());
}
return convertReturnCode(status);
}
@ -79,20 +82,20 @@ void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) {
}
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo,
MessageQueueMessage* message, MessageQueueId_t sentFrom,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
bool ignoreFault) {
message->setSender(sentFrom);
rtems_status_code result = rtems_message_queue_send(sendTo,
message->getBuffer(), message->messageSize);
message->getBuffer(), message->getMessageSize());
//TODO: Check if we're in ISR.
if (result != RTEMS_SUCCESSFUL && !ignoreFault) {
if (internalErrorReporter == NULL) {
if (internalErrorReporter == nullptr) {
internalErrorReporter = objectManager->get<InternalErrorReporterIF>(
objects::INTERNAL_ERROR_REPORTER);
}
if (internalErrorReporter != NULL) {
if (internalErrorReporter != nullptr) {
internalErrorReporter->queueMessageNotSent();
}
}
@ -105,7 +108,7 @@ ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo,
return returnCode;
}
ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessage* message,
ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message,
MessageQueueId_t sentFrom, bool ignoreFault) {
return sendMessageFrom(defaultDestination, message, sentFrom, ignoreFault);
}

View File

@ -1,14 +1,5 @@
/**
* @file MessageQueue.h
*
* @date 10/02/2012
* @author Bastian Baetz
*
* @brief This file contains the definition of the MessageQueue class.
*/
#ifndef MESSAGEQUEUE_H_
#define MESSAGEQUEUE_H_
#ifndef FSFW_OSAL_RTEMS_MESSAGEQUEUE_H_
#define FSFW_OSAL_RTEMS_MESSAGEQUEUE_H_
#include "../../internalError/InternalErrorReporterIF.h"
#include "../../ipc/MessageQueueIF.h"
@ -60,14 +51,14 @@ public:
* @param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full.
*/
ReturnValue_t sendMessage(MessageQueueId_t sendTo,
MessageQueueMessage* message, bool ignoreFault = false );
MessageQueueMessageIF* 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.
*/
ReturnValue_t sendToDefault( MessageQueueMessage* message );
ReturnValue_t sendToDefault( MessageQueueMessageIF* message );
/**
* @brief This operation sends a message to the last communication partner.
* @details This operation simplifies answering an incoming message by using the stored
@ -75,7 +66,7 @@ public:
* (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 );
ReturnValue_t reply( MessageQueueMessageIF* message );
/**
* @brief This function reads available messages from the message queue and returns the sender.
@ -84,7 +75,7 @@ public:
* @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,
ReturnValue_t receiveMessage(MessageQueueMessageIF* message,
MessageQueueId_t *receivedFrom);
/**
@ -95,7 +86,7 @@ public:
* 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);
ReturnValue_t receiveMessage(MessageQueueMessageIF* message);
/**
* Deletes all pending messages in the queue.
* @param count The number of flushed messages.
@ -121,7 +112,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 sendMessageFrom( MessageQueueId_t sendTo, MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false );
virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, MessageQueueMessageIF* 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.
@ -129,7 +120,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 sendToDefaultFrom( MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false );
virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false );
/**
* \brief This method is a simple setter for the default destination.
*/
@ -178,4 +169,4 @@ private:
static ReturnValue_t convertReturnCode(rtems_status_code inValue);
};
#endif /* MESSAGEQUEUE_H_ */
#endif /* FSFW_OSAL_RTEMS_MESSAGEQUEUE_H_ */

View File

@ -30,7 +30,7 @@ ReturnValue_t MultiObjectTask::startTask() {
rtems_status_code status = rtems_task_start(id, MultiObjectTask::taskEntryPoint,
rtems_task_argument((void *) this));
if (status != RTEMS_SUCCESSFUL) {
error << "ObjectTask::startTask for " << std::hex << this->getId()
sif::error << "ObjectTask::startTask for " << std::hex << this->getId()
<< std::dec << " failed." << std::endl;
}
switch(status){
@ -63,8 +63,8 @@ void MultiObjectTask::taskFunctionality() {
char nameSpace[8] = { 0 };
char* ptr = rtems_object_get_name(getId(), sizeof(nameSpace),
nameSpace);
error << "ObjectTask: " << ptr << " Deadline missed." << std::endl;
if (this->deadlineMissedFunc != NULL) {
sif::error << "ObjectTask: " << ptr << " Deadline missed." << std::endl;
if (this->deadlineMissedFunc != nullptr) {
this->deadlineMissedFunc();
}
}
@ -74,7 +74,7 @@ void MultiObjectTask::taskFunctionality() {
ReturnValue_t MultiObjectTask::addComponent(object_id_t object) {
ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>(
object);
if (newObject == NULL) {
if (newObject == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
objectList.push_back(newObject);

View File

@ -80,7 +80,7 @@ protected:
/**
* @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,
* So, each may react individually on a timing failure. The pointer may be nullptr,
* then nothing happens on missing the deadline. The deadline is equal to the next execution
* of the periodic task.
*/

View File

@ -10,7 +10,7 @@ Mutex::Mutex() :
RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY, 0,
&mutexId);
if (status != RTEMS_SUCCESSFUL) {
error << "Mutex: creation with name, id " << mutexName << ", " << mutexId
sif::error << "Mutex: creation with name, id " << mutexName << ", " << mutexId
<< " failed with " << status << std::endl;
}
}
@ -18,24 +18,25 @@ Mutex::Mutex() :
Mutex::~Mutex() {
rtems_status_code status = rtems_semaphore_delete(mutexId);
if (status != RTEMS_SUCCESSFUL) {
error << "Mutex: deletion for id " << mutexId
sif::error << "Mutex: deletion for id " << mutexId
<< " failed with " << status << std::endl;
}
}
ReturnValue_t Mutex::lockMutex(TimeoutType timeoutType =
TimeoutType::BLOCKING, uint32_t timeoutMs) {
rtems_status_code status = RTEMS_INVALID_ID;
if(timeoutMs == MutexIF::TimeoutType::BLOCKING) {
rtems_status_code status = rtems_semaphore_obtain(mutexId,
status = rtems_semaphore_obtain(mutexId,
RTEMS_WAIT, RTEMS_NO_TIMEOUT);
}
else if(timeoutMs == MutexIF::TimeoutType::POLLING) {
timeoutMs = RTEMS_NO_TIMEOUT;
rtems_status_code status = rtems_semaphore_obtain(mutexId,
status = rtems_semaphore_obtain(mutexId,
RTEMS_NO_WAIT, 0);
}
else {
rtems_status_code status = rtems_semaphore_obtain(mutexId,
status = rtems_semaphore_obtain(mutexId,
RTEMS_WAIT, timeoutMs);
}

View File

@ -1,5 +1,5 @@
#ifndef FRAMEWORK_OSAL_RTEMS_MUTEX_H_
#define FRAMEWORK_OSAL_RTEMS_MUTEX_H_
#ifndef FSFW_OSAL_RTEMS_MUTEX_H_
#define FSFW_OSAL_RTEMS_MUTEX_H_
#include "../../ipc/MutexIF.h"
#include "RtemsBasic.h"
@ -15,4 +15,4 @@ private:
static uint8_t count;
};
#endif /* OS_RTEMS_MUTEX_H_ */
#endif /* FSFW_OSAL_RTEMS_MUTEX_H_ */

View File

@ -2,7 +2,6 @@
#include "Mutex.h"
#include "RtemsBasic.h"
//TODO: Different variant than the lazy loading in QueueFactory. What's better and why?
MutexFactory* MutexFactory::factoryInstance = new MutexFactory();
MutexFactory::MutexFactory() {

View File

@ -1,5 +1,6 @@
#include "../../devicehandlers/FixedSequenceSlot.h"
#include "../../tasks/FixedSequenceSlot.h"
#include "../../objectmanager/SystemObjectIF.h"
#include "../../objectmanager/ObjectManagerIF.h"
#include "PollingTask.h"
#include "RtemsBasic.h"
#include "../../returnvalues/HasReturnvaluesIF.h"
@ -34,14 +35,14 @@ rtems_task PollingTask::taskEntryPoint(rtems_task_argument argument) {
PollingTask *originalTask(reinterpret_cast<PollingTask*>(argument));
//The task's functionality is called.
originalTask->taskFunctionality();
debug << "Polling task " << originalTask->getId()
sif::debug << "Polling task " << originalTask->getId()
<< " returned from taskFunctionality." << std::endl;
}
void PollingTask::missedDeadlineCounter() {
PollingTask::deadlineMissedCount++;
if (PollingTask::deadlineMissedCount % 10 == 0) {
error << "PST missed " << PollingTask::deadlineMissedCount
sif::error << "PST missed " << PollingTask::deadlineMissedCount
<< " deadlines." << std::endl;
}
}
@ -50,7 +51,7 @@ ReturnValue_t PollingTask::startTask() {
rtems_status_code status = rtems_task_start(id, PollingTask::taskEntryPoint,
rtems_task_argument((void *) this));
if (status != RTEMS_SUCCESSFUL) {
error << "PollingTask::startTask for " << std::hex << this->getId()
sif::error << "PollingTask::startTask for " << std::hex << this->getId()
<< std::dec << " failed." << std::endl;
}
switch(status){
@ -68,12 +69,13 @@ ReturnValue_t PollingTask::startTask() {
ReturnValue_t PollingTask::addSlot(object_id_t componentId,
uint32_t slotTimeMs, int8_t executionStep) {
if (objectManager->get<ExecutableObjectIF>(componentId) != nullptr) {
pst.addSlot(componentId, slotTimeMs, executionStep, this);
ExecutableObjectIF* object = objectManager->get<ExecutableObjectIF>(componentId);
if (object != nullptr) {
pst.addSlot(componentId, slotTimeMs, executionStep, object, this);
return HasReturnvaluesIF::RETURN_OK;
}
error << "Component " << std::hex << componentId <<
sif::error << "Component " << std::hex << componentId <<
" not found, not adding it to pst" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
@ -90,11 +92,10 @@ ReturnValue_t PollingTask::checkSequence() const {
void PollingTask::taskFunctionality() {
// A local iterator for the Polling Sequence Table is created to find the start time for the first entry.
std::list<FixedSequenceSlot*>::iterator it = pst.current;
FixedSlotSequence::SlotListIter it = pst.current;
//The start time for the first entry is read.
rtems_interval interval = RtemsBasic::convertMsToTicks(
(*it)->pollingTimeMs);
rtems_interval interval = RtemsBasic::convertMsToTicks(it->pollingTimeMs);
TaskBase::setAndStartPeriod(interval,&periodId);
//The task's "infinite" inner loop is entered.
while (1) {
@ -107,7 +108,7 @@ void PollingTask::taskFunctionality() {
//If the deadline was missed, the deadlineMissedFunc is called.
rtems_status_code status = TaskBase::restartPeriod(interval,periodId);
if (status == RTEMS_TIMEOUT) {
if (this->deadlineMissedFunc != NULL) {
if (this->deadlineMissedFunc != nullptr) {
this->deadlineMissedFunc();
}
}

View File

@ -1,7 +1,7 @@
#ifndef POLLINGTASK_H_
#define POLLINGTASK_H_
#ifndef FSFW_OSAL_RTEMS_POLLINGTASK_H_
#define FSFW_OSAL_RTEMS_POLLINGTASK_H_
#include "../../devicehandlers/FixedSlotSequence.h"
#include "../../tasks/FixedSlotSequence.h"
#include "../../tasks/FixedTimeslotTaskIF.h"
#include "TaskBase.h"
@ -82,4 +82,4 @@ protected:
void taskFunctionality( void );
};
#endif /* POLLINGTASK_H_ */
#endif /* FSFW_OSAL_RTEMS_POLLINGTASK_H_ */

View File

@ -1,16 +1,17 @@
#include "../../ipc/QueueFactory.h"
#include "../../ipc/MessageQueueSenderIF.h"
#include "MessageQueue.h"
#include "RtemsBasic.h"
QueueFactory* QueueFactory::factoryInstance = NULL;
QueueFactory* QueueFactory::factoryInstance = nullptr;
ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo,
MessageQueueMessage* message, MessageQueueId_t sentFrom,bool ignoreFault) {
MessageQueueMessageIF* message, MessageQueueId_t sentFrom,bool ignoreFault) {
//TODO add ignoreFault functionality
message->setSender(sentFrom);
rtems_status_code result = rtems_message_queue_send(sendTo, message->getBuffer(),
message->messageSize);
message->getMessageSize());
switch(result){
case RTEMS_SUCCESSFUL:
//message sent successfully
@ -37,7 +38,7 @@ ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo,
}
QueueFactory* QueueFactory::instance() {
if (factoryInstance == NULL) {
if (factoryInstance == nullptr) {
factoryInstance = new QueueFactory;
}
return factoryInstance;

View File

@ -1,5 +1,5 @@
#ifndef OS_RTEMS_RTEMSBASIC_H_
#define OS_RTEMS_RTEMSBASIC_H_
#ifndef FSFW_OSAL_RTEMS_RTEMSBASIC_H_
#define FSFW_OSAL_RTEMS_RTEMSBASIC_H_
#include "../../returnvalues/HasReturnvaluesIF.h"
#include <rtems.h>
@ -22,4 +22,4 @@ public:
}
};
#endif /* OS_RTEMS_RTEMSBASIC_H_ */
#endif /* FSFW_OSAL_RTEMS_RTEMSBASIC_H_ */

View File

@ -22,7 +22,7 @@ TaskBase::TaskBase(rtems_task_priority set_priority, size_t stack_size,
}
ReturnValue_t result = convertReturnCode(status);
if (result != HasReturnvaluesIF::RETURN_OK) {
error << "TaskBase::TaskBase: createTask with name " << std::hex
sif::error << "TaskBase::TaskBase: createTask with name " << std::hex
<< osalName << std::dec << " failed with return code "
<< (uint32_t) status << std::endl;
this->id = 0;

View File

@ -1,5 +1,5 @@
#ifndef TASKBASE_H_
#define TASKBASE_H_
#ifndef FSFW_OSAL_RTEMS_TASKBASE_H_
#define FSFW_OSAL_RTEMS_TASKBASE_H_
#include "RtemsBasic.h"
#include "../../tasks/PeriodicTaskIF.h"
@ -44,4 +44,4 @@ private:
};
#endif /* TASKBASE_H_ */
#endif /* FSFW_OSAL_RTEMS_TASKBASE_H_ */

View File

@ -2,7 +2,7 @@
#define FRAMEWORK_TIMEMANAGER_CLOCK_H_
#include "../returnvalues/HasReturnvaluesIF.h"
#include "../ipc/MutexFactory.h"
#include "../ipc/MutexHelper.h"
#include "../globalfunctions/timevalOperations.h"
#include <cstdint>