1
0
forked from fsfw/fsfw

updating code from Flying Laptop

This is the framework of Flying Laptop OBSW version A.13.0.
This commit is contained in:
2018-07-12 16:29:32 +02:00
parent 1d22a6c97e
commit 575f70ba03
395 changed files with 12807 additions and 8404 deletions

13
osal/Endiness.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef FRAMEWORK_OSAL_ENDINESS_H_
#define FRAMEWORK_OSAL_ENDINESS_H_
//We have to define BYTE_ORDER for that specific OS/Hardware so this must be done somewhere
#ifndef API
#error Please specify Operating System API. Supported: API=RTEMS_API
#elif API == RTEMS_API
#include "rtems/RtemsBasic.h"
#endif
#endif /* FRAMEWORK_OSAL_ENDINESS_H_ */

View File

@ -5,7 +5,7 @@
class InternalErrorCodes {
public:
static const uint8_t INTERFACE_ID = INTERNAL_ERROR_CODES;
static const uint8_t INTERFACE_ID = CLASS_ID::INTERNAL_ERROR_CODES;
static const ReturnValue_t NO_CONFIGURATION_TABLE = MAKE_RETURN_CODE(0x01 );
static const ReturnValue_t NO_CPU_TABLE = MAKE_RETURN_CODE(0x02 );

176
osal/Linux/Clock.cpp Normal file
View File

@ -0,0 +1,176 @@
#include <sys/time.h>
#include <time.h>
#include <framework/timemanager/Clock.h>
#include <sys/sysinfo.h>
#include <linux/sysinfo.h>
#include <unistd.h>
//#include <fstream>
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;
}
ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {
//TODO timeOfDay conversion
timespec timeUnix;
int status = clock_settime(CLOCK_REALTIME,&timeUnix);
if(status!=0){
//TODO errno
return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::setClock(const timeval* time) {
timespec timeUnix;
timeUnix.tv_sec = time->tv_sec;
timeUnix.tv_nsec = (__syscall_slong_t) time->tv_usec * 1000;
int status = clock_settime(CLOCK_REALTIME,&timeUnix);
if(status!=0){
//TODO errno
return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::getClock_timeval(timeval* time) {
timespec timeUnix;
int status = clock_gettime(CLOCK_REALTIME,&timeUnix);
if(status!=0){
return HasReturnvaluesIF::RETURN_FAILED;
}
time->tv_sec = timeUnix.tv_sec;
time->tv_usec = timeUnix.tv_nsec / 1000.0;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
timeval timeVal;
ReturnValue_t result = getClock_timeval(&timeVal);
if(result != HasReturnvaluesIF::RETURN_OK){
return result;
}
*time = (uint64_t)timeVal.tv_sec*1e6 + timeVal.tv_usec;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::getUptime(timeval* uptime) {
//TODO This is not posix compatible and delivers only seconds precision
struct sysinfo sysInfo;
int result = sysinfo(&sysInfo);
if(result != 0){
return HasReturnvaluesIF::RETURN_FAILED;
}
uptime->tv_sec = sysInfo.uptime;
uptime->tv_usec = 0;
//Linux specific file read but more precise
// double uptimeSeconds;
// if(std::ifstream("/proc/uptime",std::ios::in) >> uptimeSeconds){
// uptime->tv_sec = uptimeSeconds;
// uptime->tv_usec = uptimeSeconds *(double) 1e6 - (uptime->tv_sec *1e6);
// }
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) {
timeval uptime;
ReturnValue_t result = getUptime(&uptime);
if(result != HasReturnvaluesIF::RETURN_OK){
return result;
}
*uptimeMs = uptime.tv_sec * 1e3 + uptime.tv_usec / 1e3;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
timespec timeUnix;
int status = clock_gettime(CLOCK_REALTIME,&timeUnix);
if(status != 0){
//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);
time->year = timeInfo->tm_year + 1900;
time->month = timeInfo->tm_mon+1;
time->day = timeInfo->tm_mday;
time->hour = timeInfo->tm_hour;
time->minute = timeInfo->tm_min;
time->second = timeInfo->tm_sec;
time->ticks = (timeUnix.tv_nsec / (double) 1e9) * resolution;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from,
timeval* to) {
tm fromTm;
//Note: Fails for years before AD
fromTm.tm_year = from->year - 1900;
fromTm.tm_mon = from->month - 1;
fromTm.tm_mday = from->day;
fromTm.tm_hour = from->hour;
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;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) {
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) {
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) {
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) {
return HasReturnvaluesIF::RETURN_FAILED;
}

View File

@ -1,282 +0,0 @@
/**
* @file OSAL.cpp
* @brief This file defines the OSAL class.
* @date 19.12.2012
* @author baetz
*/
#include <framework/osal/OSAL.h>
#ifndef API
#error Please specify Operating System API. Supported: API=RTEMS_API
#elif API == RTEMS_API
#include <bsp_flp/bsp_flp.h>
//#include <bsp_flp/rmap/RMAPCookie.h>
ReturnValue_t OSAL::convertReturnCode(uint8_t inValue) {
if (inValue == RTEMS_SUCCESSFUL) {
return OSAL::RETURN_OK;
} else {
return MAKE_RETURN_CODE(inValue);
}
}
Name_t OSAL::buildName(uint8_t c1, uint8_t c2, uint8_t c3, uint8_t c4) {
return rtems_build_name(c1, c2, c3, c4);
}
Interval_t OSAL::getTicksPerSecond() {
Interval_t ticks_per_second;
(void) rtems_clock_get(RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticks_per_second);
return ticks_per_second;
}
ReturnValue_t OSAL::setClock(TimeOfDay_t* time) {
ReturnValue_t status = rtems_clock_set(time);
status = convertReturnCode(status);
return status;
}
ReturnValue_t OSAL::setClock(timeval* time) {
timespec newTime;
newTime.tv_sec = time->tv_sec;
newTime.tv_nsec = time->tv_usec * TOD_NANOSECONDS_PER_MICROSECOND;
//TODO: Not sure if we need to protect this call somehow (by thread lock or something).
_TOD_Set(&newTime);
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t OSAL::getClock_timeval(timeval* time) {
ReturnValue_t status = rtems_clock_get_tod_timeval(time);
status = convertReturnCode(status);
return status;
}
ReturnValue_t OSAL::getClock_usecs(uint64_t* time) {
timeval temp_time;
uint8_t returnValue = rtems_clock_get_tod_timeval(&temp_time);
*time = ((uint64_t) temp_time.tv_sec * 1000000) + temp_time.tv_usec;
return OSAL::convertReturnCode(returnValue);
}
ReturnValue_t OSAL::getDateAndTime(TimeOfDay_t* time) {
ReturnValue_t status = rtems_clock_get_tod(time);
status = convertReturnCode(status);
return status;
}
ReturnValue_t OSAL::sleepFor(Interval_t ticks) {
ReturnValue_t status = rtems_task_wake_after(ticks);
status = convertReturnCode(status);
return status;
}
ReturnValue_t OSAL::createTask(Name_t name, TaskPriority_t initial_priority,
size_t stack_size, OpusMode_t initial_modes, Attribute_t attribute_set,
TaskId_t* id) {
if (initial_priority >= 0 && initial_priority <= 99) {
ReturnValue_t status = rtems_task_create(name,
(0xFF - 2 * initial_priority), stack_size, initial_modes,
attribute_set, id);
status = convertReturnCode(status);
return status;
} else {
return OSAL::UNSATISFIED;
}
}
ReturnValue_t OSAL::findTask(Name_t name, TaskId_t* id) {
ReturnValue_t status = rtems_task_ident(name, RTEMS_SEARCH_ALL_NODES, id);
status = convertReturnCode(status);
return status;
}
ReturnValue_t OSAL::startTask(TaskId_t* id, TaskEntry_t entry_point,
TaskArgument_t argument) {
return rtems_task_start(*id, entry_point, argument);
}
ReturnValue_t OSAL::deleteTask(TaskId_t* id) {
if (id == RTEMS_SELF) {
return rtems_task_delete(RTEMS_SELF);
} else {
return rtems_task_delete(*id);
}
}
ReturnValue_t OSAL::setAndStartPeriod(Interval_t period, PeriodId_t *periodId,
Name_t name) {
uint8_t status;
status = rtems_rate_monotonic_create(name, periodId);
if (status == RTEMS_SUCCESSFUL) {
//This is necessary to avoid a call with period = 0, which does not start the period.
status = rtems_rate_monotonic_period(*periodId, period + 1);
}
return OSAL::convertReturnCode(status);
}
ReturnValue_t OSAL::checkAndRestartPeriod(PeriodId_t periodId,
Interval_t period) {
ReturnValue_t status = rtems_rate_monotonic_period(periodId, period);
status = convertReturnCode(status);
return status;
}
ReturnValue_t OSAL::deletePeriod(TaskId_t* id) {
rtems_name period_name;
rtems_id period_id;
rtems_object_get_classic_name(*id, &period_name);
period_name = (period_name & 0xFFFFFF00) + 0x50;
rtems_rate_monotonic_ident(period_name, &period_id);
ReturnValue_t status = rtems_rate_monotonic_delete(period_id);
status = convertReturnCode(status);
return status;
}
ReturnValue_t OSAL::reportPeriodStatistics() {
rtems_rate_monotonic_report_statistics();
return OSAL::SUCCESSFUL;
}
ReturnValue_t OSAL::createMessageQueue(Name_t name, uint32_t count,
size_t max_message_size, Attribute_t attribute_set,
MessageQueueId_t* id) {
ReturnValue_t status = rtems_message_queue_create(name, count,
max_message_size, attribute_set, id);
status = convertReturnCode(status);
return status;
}
ReturnValue_t OSAL::findMessageQueue(Name_t name, MessageQueueId_t* id) {
ReturnValue_t status = rtems_message_queue_ident(name,
RTEMS_SEARCH_ALL_NODES, id);
status = convertReturnCode(status);
return status;
}
ReturnValue_t OSAL::sendMessage(MessageQueueId_t id, const void* buffer,
size_t size) {
ReturnValue_t status = rtems_message_queue_send(id, buffer, size);
return OSAL::convertReturnCode(status);
}
ReturnValue_t OSAL::receiveMessage(MessageQueueId_t id, void* buffer,
size_t bufSize, size_t* recSize, Option_t option_set,
Interval_t timeout) {
ReturnValue_t status = rtems_message_queue_receive(id, buffer, recSize,
option_set, timeout);
status = convertReturnCode(status);
return status;
}
ReturnValue_t OSAL::flushMessageQueue(MessageQueueId_t id, uint32_t* count) {
ReturnValue_t status = rtems_message_queue_flush(id, count);
status = convertReturnCode(status);
return status;
}
ReturnValue_t OSAL::deleteMessageQueue(MessageQueueId_t* id) {
ReturnValue_t status = rtems_message_queue_delete(*id);
status = convertReturnCode(status);
return status;
}
ReturnValue_t OSAL::createMutex(Name_t name, MutexId_t* id) {
ReturnValue_t status = rtems_semaphore_create(name, 1,
RTEMS_SIMPLE_BINARY_SEMAPHORE, 0, id);
status = convertReturnCode(status);
return status;
}
ReturnValue_t OSAL::deleteMutex(MutexId_t* id) {
ReturnValue_t status = rtems_semaphore_delete(*id);
status = convertReturnCode(status);
return status;
}
ReturnValue_t OSAL::lockMutex(MutexId_t* id, Interval_t timeout) {
ReturnValue_t status = rtems_semaphore_obtain(*id, WAIT, timeout);
status = convertReturnCode(status);
return status;
}
ReturnValue_t OSAL::getUptime(timeval* uptime) {
timespec time;
ReturnValue_t 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;
status = convertReturnCode(status);
return status;
}
ReturnValue_t OSAL::getUptime(uint32_t* uptimeMs) {
*uptimeMs = rtems_clock_get_ticks_since_boot();
return RTEMS_SUCCESSFUL;
}
ReturnValue_t OSAL::unlockMutex(MutexId_t* id) {
ReturnValue_t status = rtems_semaphore_release(*id);
status = convertReturnCode(status);
return status;
}
ReturnValue_t OSAL::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
ReturnValue_t status = rtems_interrupt_catch(handler, interrupt + 0x10,
oldHandler);
status = convertReturnCode(status);
return status;
}
//TODO: Make default values (edge, polarity) settable?
ReturnValue_t OSAL::enableInterrupt(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 RETURN_OK;
} else {
return RETURN_FAILED;
}
}
ReturnValue_t OSAL::disableInterrupt(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 RETURN_OK;
} else {
return RETURN_FAILED;
}
}
bool OSAL::isInterruptInProgress() {
return rtems_interrupt_is_in_progress();
}
ReturnValue_t OSAL::convertTimeOfDayToTimeval(const TimeOfDay_t* from,
timeval* to) {
//Fails in 2038..
to->tv_sec = _TOD_To_seconds(from);
to->tv_usec = 0;
return RETURN_OK;
}
#endif /* API */

View File

@ -1,430 +0,0 @@
/**
* @file OSAL.h
* @brief This file defines the OSAL class.
* @date 19.12.2012
* @author baetz
*/
#ifndef OSAL_H_
#define OSAL_H_
#include <framework/returnvalues/HasReturnvaluesIF.h>
#define RTEMS_API 1
#ifndef API
#error Please specify Operating System API. Supported: API=RTEMS_API
#elif API == RTEMS_API
#include <rtems/endian.h>
#include <rtems.h>
#include <rtems/libio.h>
#include <rtems/error.h>
#include <rtems/stackchk.h>
#include <stdint.h>
//include RMAP
#define opus_main Init2
#define opus_main_arguments rtems_task_argument
//Typedefs for RTEMS: //TODO: these are global, shouldn't they have some prefix?
/**
* A typedef to pass options to RTEMS elements.
*/
typedef rtems_option Option_t;
/**
* A typedef to pass attributes to RTEMS elements.
*/
typedef rtems_attribute Attribute_t;
/**
* A typedef for RTEMS task modes.
*/
typedef rtems_mode OpusMode_t;
/**
* A typedef for time intervals. In clock ticks.
*/
typedef rtems_interval Interval_t;
typedef rtems_time_of_day TimeOfDay_t;
typedef rtems_id TaskId_t;
typedef rtems_id PeriodId_t;
typedef rtems_id MutexId_t;
typedef rtems_id MessageQueueId_t;
typedef rtems_name Name_t;
typedef rtems_task_argument TaskArgument_t;
typedef rtems_task_entry TaskEntry_t;
typedef rtems_task TaskReturn_t;
typedef rtems_task_priority TaskPriority_t;
typedef rtems_isr_entry IsrHandler_t;
typedef rtems_isr IsrReturn_t;
typedef rtems_vector_number InterruptNumber_t;
/**
* This class contains encapsulates all System Calls to the Operating System.
* It is currently tailored to the RTEMS Operating system, but should in general
* support different OS.
* For more detailed information on the Operating System calls, please refer to the
* RTEMS documentation at www.rtems.org .
*/
class OSAL: public HasReturnvaluesIF {
private:
/**
* 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(uint8_t inValue);
public:
static const uint8_t INTERFACE_ID = OPERATING_SYSTEM_ABSTRACTION;
//Interrupts:
static const uint32_t INTERRUPT_MASK_REGISTER_ADDRESS = 0x80000240;
//API Status codes:
static const ReturnValue_t SUCCESSFUL = RTEMS_SUCCESSFUL;
static const ReturnValue_t TASK_EXITTED =
MAKE_RETURN_CODE( RTEMS_TASK_EXITTED );
static const ReturnValue_t MP_NOT_CONFIGURED =
MAKE_RETURN_CODE( RTEMS_MP_NOT_CONFIGURED );
static const ReturnValue_t INVALID_NAME =
MAKE_RETURN_CODE( RTEMS_INVALID_NAME );
static const ReturnValue_t INVALID_ID = MAKE_RETURN_CODE( RTEMS_INVALID_ID );
static const ReturnValue_t TOO_MANY = MAKE_RETURN_CODE( RTEMS_TOO_MANY );
static const ReturnValue_t TIMEOUT = MAKE_RETURN_CODE( RTEMS_TIMEOUT );
static const ReturnValue_t OBJECT_WAS_DELETED =
MAKE_RETURN_CODE( RTEMS_OBJECT_WAS_DELETED );
static const ReturnValue_t INVALID_SIZE =
MAKE_RETURN_CODE( RTEMS_INVALID_SIZE );
static const ReturnValue_t INVALID_ADDRESS =
MAKE_RETURN_CODE( RTEMS_INVALID_ADDRESS );
static const ReturnValue_t INVALID_NUMBER =
MAKE_RETURN_CODE( RTEMS_INVALID_NUMBER );
static const ReturnValue_t NOT_DEFINED =
MAKE_RETURN_CODE( RTEMS_NOT_DEFINED );
static const ReturnValue_t RESOURCE_IN_USE =
MAKE_RETURN_CODE( RTEMS_RESOURCE_IN_USE );
static const ReturnValue_t UNSATISFIED =
MAKE_RETURN_CODE( RTEMS_UNSATISFIED );
static const ReturnValue_t QUEUE_EMPTY =
MAKE_RETURN_CODE( RTEMS_UNSATISFIED );
static const ReturnValue_t INCORRECT_STATE =
MAKE_RETURN_CODE( RTEMS_INCORRECT_STATE );
static const ReturnValue_t ALREADY_SUSPENDED =
MAKE_RETURN_CODE( RTEMS_ALREADY_SUSPENDED );
static const ReturnValue_t ILLEGAL_ON_SELF =
MAKE_RETURN_CODE( RTEMS_ILLEGAL_ON_SELF );
static const ReturnValue_t ILLEGAL_ON_REMOTE_OBJECT =
MAKE_RETURN_CODE( RTEMS_ILLEGAL_ON_REMOTE_OBJECT );
static const ReturnValue_t CALLED_FROM_ISR =
MAKE_RETURN_CODE( RTEMS_CALLED_FROM_ISR );
static const ReturnValue_t INVALID_PRIORITY =
MAKE_RETURN_CODE( RTEMS_INVALID_PRIORITY );
static const ReturnValue_t INVALID_CLOCK =
MAKE_RETURN_CODE( RTEMS_INVALID_CLOCK );
static const ReturnValue_t INVALID_NODE =
MAKE_RETURN_CODE( RTEMS_INVALID_NODE );
static const ReturnValue_t NOT_CONFIGURED =
MAKE_RETURN_CODE( RTEMS_NOT_CONFIGURED );
static const ReturnValue_t NOT_OWNER_OF_RESOURCE =
MAKE_RETURN_CODE( RTEMS_NOT_OWNER_OF_RESOURCE );
static const ReturnValue_t NOT_IMPLEMENTED =
MAKE_RETURN_CODE( RTEMS_NOT_IMPLEMENTED );
static const ReturnValue_t INTERNAL_ERROR =
MAKE_RETURN_CODE( RTEMS_INTERNAL_ERROR );
static const ReturnValue_t NO_MEMORY = MAKE_RETURN_CODE( RTEMS_NO_MEMORY );
static const ReturnValue_t IO_ERROR = MAKE_RETURN_CODE( RTEMS_IO_ERROR );
//API options:
static const Option_t DEFAULT_OPTIONS = RTEMS_DEFAULT_OPTIONS;
static const Option_t WAIT = RTEMS_WAIT;
static const Option_t NO_WAIT = RTEMS_NO_WAIT;
static const Option_t EVENT_ALL = RTEMS_EVENT_ALL;
static const Option_t EVENT_ANY = RTEMS_EVENT_ANY;
//API Attributes:
static const Attribute_t DEFAULT_ATTRIBUTES = RTEMS_DEFAULT_ATTRIBUTES;
static const Attribute_t LOCAL = RTEMS_LOCAL;
static const Attribute_t GLOBAL = RTEMS_GLOBAL;
static const Attribute_t FIFO = RTEMS_FIFO;
static const Attribute_t PRIORITY = RTEMS_PRIORITY;
static const Attribute_t NO_FLOATING_POINT = RTEMS_NO_FLOATING_POINT;
static const Attribute_t FLOATING_POINT = RTEMS_FLOATING_POINT;
//API Modes:
static const OpusMode_t ALL_MODE_MASKS = RTEMS_ALL_MODE_MASKS;
static const OpusMode_t DEFAULT_MODES = RTEMS_DEFAULT_MODES;
static const OpusMode_t CURRENT_MODE = RTEMS_CURRENT_MODE;
static const OpusMode_t PREEMPT = RTEMS_PREEMPT;
static const OpusMode_t NO_PREEMPT = RTEMS_NO_PREEMPT;
static const OpusMode_t NO_TIMESLICE = RTEMS_NO_TIMESLICE;
static const OpusMode_t TIMESLICE = RTEMS_TIMESLICE;
static const OpusMode_t ASR = RTEMS_ASR;
static const OpusMode_t NO_ASR = RTEMS_NO_ASR;
//API Time and Timing
static const Interval_t MILISECOND_WAIT = 1;
static const Interval_t NO_TIMEOUT = RTEMS_NO_TIMEOUT;
static const TaskId_t TASK_MYSELF = RTEMS_SELF;
static const size_t MINIMUM_STACK_SIZE = RTEMS_MINIMUM_STACK_SIZE;
/**
* This is a helper method to build a qualified name out of single characters
* @param c1 The first character
* @param c2 The second character
* @param c3 The third character
* @param c4 The fourth character
* @return A name suitable for use for the Operating System
*/
static Name_t buildName(uint8_t c1, uint8_t c2, uint8_t c3, uint8_t c4);
/**
* This method returns the number of clock ticks per second.
* In RTEMS, this is typically 1000.
* @return The number of ticks.
*/
static Interval_t getTicksPerSecond(void);
/**
* This system call sets the system time.
* To set the time, it uses a TimeOfDay_t struct.
* @param time The struct with the time settings to set.
* @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
*/
static ReturnValue_t setClock(TimeOfDay_t* time);
/**
* This system call sets the system time.
* To set the time, it uses a timeval struct.
* @param time The struct with the time settings to set.
* @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
*/
static ReturnValue_t setClock(timeval* time);
/**
* This system call returns the current system clock in timeval format.
* The timval format has the fields \c tv_sec with seconds and \c tv_usec with
* microseconds since an OS-defined epoch.
* @param time A pointer to a timeval struct where the current time is stored.
* @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
*/
static ReturnValue_t getClock_timeval(timeval* time);
/**
* Get the time since boot in a timeval struct
*
* @param[out] time A pointer to a timeval struct where the uptime is stored.
* @return\c RETURN_OK on success. Otherwise, the OS failure code is returned.
*/
static ReturnValue_t getUptime(timeval* uptime);
/**
* Get the time since boot in milliseconds
*
* This value can overflow! Still, it can be used to calculate time intervalls
* between two calls up to 49 days by always using uint32_t in the calculation
*
* @param ms uptime in ms
* @return RETURN_OK on success. Otherwise, the OS failure code is returned.
*/
static ReturnValue_t getUptime(uint32_t* uptimeMs);
/**
* Returns the time in microseconds since an OS-defined epoch.
* The time is returned in a 64 bit unsigned integer.
* @param time A pointer to a 64 bit unisigned integer where the data is stored.
* @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
*/
static ReturnValue_t getClock_usecs(uint64_t* time);
/**
* Returns the time in a TimeOfDay_t struct.
* @param time A pointer to a TimeOfDay_t struct.
* @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
*/
static ReturnValue_t getDateAndTime(TimeOfDay_t* time);
/**
* Converts a time of day struct to POSIX seconds.
* @param time The time of day as input
* @param timeval The corresponding seconds since the epoch.
* @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
*/
static ReturnValue_t convertTimeOfDayToTimeval(const TimeOfDay_t* from, timeval* to);
/**
* Commands the calling task to sleep for a certain number of clock ticks.
* Typically other tasks are executed then.
* @param ticks The number of clock ticks to sleep.
* @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
*/
static ReturnValue_t sleepFor(Interval_t ticks);
/**
* With this call, a new task is created.
* The task is created (its resources are acquired), but it is not started.
* @param name A name as specified in the OS.
* @param initial_priority The task's priority. Ranging from 0 (lowest) to 99 (highest).
* @param stack_size The stack size reserved for this task.
* @param initial_modes Options for the task's mode (preemptible, time slicing, etc..)
* @param attribute_set Options for the task's attributes (floating point, local/global)
* @param id The OS returns the task id, that uniquely identifies the task.
* @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
*/
static ReturnValue_t createTask(Name_t name,
TaskPriority_t initial_priority, size_t stack_size,
OpusMode_t initial_modes, Attribute_t attribute_set, TaskId_t *id);
/**
* Finds a task with the help of its name.
* @param name Name of the task to find
* @param id The OS returns the task id, that uniquely identifies the task.
* @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
*/
static ReturnValue_t findTask(Name_t name, TaskId_t *id);
/**
* Starts a task.
* The task immediately starts running.
* @param id The task id.
* @param entry_point A pointer to the (static) method that is executed by the task.
* @param argument One argument (a void* pointer) may be passed to the task.
* @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
*/
static ReturnValue_t startTask(TaskId_t *id, TaskEntry_t entry_point,
TaskArgument_t argument);
/**
* With this call, tasks are deleted from the system
* @param id The task id.
* @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
*/
static ReturnValue_t deleteTask(TaskId_t *id);
/**
* Checks if the current executing context is an ISR.
* @return true if handling an interrupt, false else.
*/
static bool isInterruptInProgress();
/**
* An task is not executed periodically by default.
* This is activated with this call. This is managed internally.
* @param period The task's period in clock ticks.
* @param[out] periodId The newly created period's id
* @param name optional name for the period
* @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
*/
static ReturnValue_t setAndStartPeriod(Interval_t period, PeriodId_t *periodId, Name_t name = (('P' << 24) + ('e' << 16) + ('r' << 8) + 'd'));
/**
* This call must be made in a periodic task, when activities of one cycle are finished.
* This is managed internally.
* @param periodId Id of the period as returned by setAndStartPeriod()
* @param period The period duration for the next cycle.
* @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
*/
static ReturnValue_t checkAndRestartPeriod(PeriodId_t periodId, Interval_t period);
/**
* This call deletes the period.
* This is managed internally.
* @param id Pointer to the task identifier the period belongs to.
* @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
*/
static ReturnValue_t deletePeriod(TaskId_t *id);
/**
* With this call the period statistics (and therefore the periodic task
* statistics) are printed to the screen.
* @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
*/
static ReturnValue_t reportPeriodStatistics();
/**
* With this call, a new message queue is created.
* @param name A qualified name for the message queue.
* @param count Number of messages the queue can store before it rejects new messages.
* @param max_message_size Maximum size of a single message.
* @param attribute_set Attributes for the message queue (fifo/priority, local/global)
* @param id A unique message queue identifier returned by the OS.
* @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
*/
static ReturnValue_t createMessageQueue(Name_t name, uint32_t count,
size_t max_message_size, Attribute_t attribute_set,
MessageQueueId_t *id);
/**
* Returns a message queue id by its name.
* @param name The queue's name.
* @param id A pointer to the queue id to return to.
* @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
*/
static ReturnValue_t findMessageQueue(Name_t name, MessageQueueId_t *id);
/**
* Sends a message to the queue given by id.
* @param id Id of the queue to send to
* @param buffer A pointer to any kind of data to send over the queue.
* @param size Size of the data to send.
* @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
*/
static ReturnValue_t sendMessage(MessageQueueId_t id, const void *buffer,
size_t size);
/**
* Checks, if a message was received by a queue with identifier id.
* @param id The id of the checked task.
* @param buffer Pointer to the buffer to store to.
* @param bufSize Maximum size of the buffer.
* @param recSize The actual message size is returned here.
* @param option_set Specifies, if the task waits for a message (WAIT/ NO_WAIT).
* @param timeout If the task waits, this interval specifies how long (in clock ticks).
* @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
*/
static ReturnValue_t receiveMessage(MessageQueueId_t id, void *buffer,
size_t bufSize, size_t *recSize, Option_t option_set,
Interval_t timeout);
/**
* Deletes all pending messages in a certain queue.
* @param id Id of the queue to flush
* @param count Number of flushed messages.
* @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
*/
static ReturnValue_t flushMessageQueue( MessageQueueId_t id, uint32_t* count );
/**
* Deletes a message queue from the system.
* @param id Id of the queue to delete.
* @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
*/
static ReturnValue_t deleteMessageQueue(MessageQueueId_t *id);
/**
* Creates a new mutual exclusive lock (or semaphore).
* With these locks, concurrent access to system resources (data pool, ...) can be
* controlled.
* @param name A qualified name for the mutex.
* @param id The mutex's id as returned by the OS.
* @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
*/
static ReturnValue_t createMutex(Name_t name, MutexId_t *id);
/**
* Deletes the mutex identified by id.
* @param id Id of the mutex to delete.
* @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
*/
static ReturnValue_t deleteMutex(MutexId_t *id);
/**
* With this call, a task tries to acquire the mutex.
* Must be used in conjunction with unlockMutex.
* @param id Id of the mutex to acquire.
* @param timeout Specifies how long a task waits for the mutex. Default is NO_TIMEOUT.
* @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
*/
static ReturnValue_t lockMutex(MutexId_t *id, Interval_t timeout);
/**
* Releases a mutex.
* Must be used in conjunction with lockMutex.
* @param id Id of the mutex to release.
* @return \c RETURN_OK on success. Otherwise, the OS failure code is returned.
*/
static ReturnValue_t unlockMutex(MutexId_t *id);
/**
* 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 );
/**
* 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 enableInterrupt( 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 disableInterrupt( InterruptNumber_t interrupt );
};
#endif /* API */
#endif /* OSAL_H_ */

144
osal/OperatingSystemIF.h Normal file
View File

@ -0,0 +1,144 @@
#ifndef FRAMEWORK_OSAL_OPERATINGSYSTEMIF_H_
#define FRAMEWORK_OSAL_OPERATINGSYSTEMIF_H_
#include <framework/returnvalues/HasReturnvaluesIF.h>
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_ */

145
osal/rtems/Clock.cpp Normal file
View File

@ -0,0 +1,145 @@
#include <framework/timemanager/Clock.h>
#include "RtemsBasic.h"
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;
}
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<rtems_time_of_day*>(const_cast<TimeOfDay_t*>(time));
rtems_status_code status = rtems_clock_set(timeRtems);
return RtemsBasic::convertReturnCode(status);
}
ReturnValue_t Clock::setClock(const timeval* time) {
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);
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::getClock_timeval(timeval* time) {
rtems_status_code status = rtems_clock_get_tod_timeval(time);
return RtemsBasic::convertReturnCode(status);
}
ReturnValue_t Clock::getUptime(timeval* uptime) {
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);
}
ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) {
*uptimeMs = rtems_clock_get_ticks_since_boot();
return RtemsBasic::convertReturnCode(RTEMS_SUCCESSFUL);
}
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);
}
ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
rtems_time_of_day* timeRtems = reinterpret_cast<rtems_time_of_day*>(time);
rtems_status_code status = rtems_clock_get_tod(timeRtems);
return RtemsBasic::convertReturnCode(status);
}
ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from,
timeval* to) {
//Fails in 2038..
const rtems_time_of_day* timeRtems = reinterpret_cast<const rtems_time_of_day*>(from);
to->tv_sec = _TOD_To_seconds(timeRtems);
to->tv_usec = timeRtems->ticks * 1000;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) {
*JD2000 = (time.tv_sec - 946728000. + time.tv_usec / 1000000.) / 24.
/ 3600.;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) {
//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_) {
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_) {
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;
}

27
osal/rtems/InitTask.cpp Normal file
View File

@ -0,0 +1,27 @@
#include "InitTask.h"
#include "RtemsBasic.h"
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;
}

28
osal/rtems/InitTask.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef OS_RTEMS_INITTASK_H_
#define OS_RTEMS_INITTASK_H_
#include <framework/tasks/PeriodicTaskIF.h>
//TODO move into static function in TaskIF
/**
* The init task is created automatically by RTEMS.
* As one may need to control it (e.g. suspending it for a while),
* this dummy class provides an implementation of TaskIF to do so.
* Warning: The init task is deleted with this stub, i.e. the destructor
* calls rtems_task_delete(RTEMS_SELF)
*/
class InitTask: public PeriodicTaskIF {
public:
InitTask();
virtual ~InitTask();
ReturnValue_t startTask();
ReturnValue_t sleepFor(uint32_t ms);
uint32_t getPeriodMs() const;
void deleteTask();
};
#endif /* OS_RTEMS_INITTASK_H_ */

70
osal/rtems/Interrupt.cpp Normal file
View File

@ -0,0 +1,70 @@
#include "Interrupt.h"
#include <bsp_flp/bsp_flp.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);
return RtemsBasic::convertReturnCode(status);
}
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();
}

50
osal/rtems/Interrupt.h Normal file
View File

@ -0,0 +1,50 @@
#ifndef OS_RTEMS_INTERRUPT_H_
#define OS_RTEMS_INTERRUPT_H_
#include <framework/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_ */

116
osal/rtems/MessageQueue.cpp Normal file
View File

@ -0,0 +1,116 @@
#include <framework/serviceinterface/ServiceInterfaceStream.h>
#include "MessageQueue.h"
#include "RtemsBasic.h"
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);
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
<< name << std::dec << " failed with status:"
<< (uint32_t) status << std::endl;
this->id = 0;
}
}
MessageQueue::~MessageQueue() {
rtems_message_queue_delete(id);
}
ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo,
MessageQueueMessage* message, bool ignoreFault) {
return sendMessage(sendTo, message, this->getId(), ignoreFault);
}
ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessage* message) {
return sendToDefault(message, this->getId());
}
ReturnValue_t MessageQueue::reply(MessageQueueMessage* message) {
if (this->lastPartner != 0) {
return sendMessage(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) {
rtems_status_code status = rtems_message_queue_receive(id,
message->getBuffer(), &(message->messageSize),
RTEMS_NO_WAIT, 1);
if (status == RTEMS_SUCCESSFUL) {
this->lastPartner = message->getSender();
//Check size of incoming message.
if (message->messageSize < 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);
}
return RtemsBasic::convertReturnCode(status);
}
MessageQueueId_t MessageQueue::getLastPartner() const {
return this->lastPartner;
}
ReturnValue_t MessageQueue::flush(uint32_t* count) {
rtems_status_code status = rtems_message_queue_flush(id, count);
return RtemsBasic::convertReturnCode(status);
}
MessageQueueId_t MessageQueue::getId() const {
return this->id;
}
void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) {
this->defaultDestination = defaultDestination;
}
ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo,
MessageQueueMessage* message, MessageQueueId_t sentFrom,
bool ignoreFault) {
message->setSender(sentFrom);
rtems_status_code result = rtems_message_queue_send(sendTo,
message->getBuffer(), message->messageSize);
//TODO: Check if we're in ISR.
if (result != RTEMS_SUCCESSFUL && !ignoreFault) {
if (internalErrorReporter == NULL) {
internalErrorReporter = objectManager->get<InternalErrorReporterIF>(
objects::INTERNAL_ERROR_REPORTER);
}
if (internalErrorReporter != NULL) {
internalErrorReporter->queueMessageNotSent();
}
}
return result;
}
ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessage* message,
MessageQueueId_t sentFrom, bool ignoreFault) {
return sendMessage(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;

174
osal/rtems/MessageQueue.h Normal file
View File

@ -0,0 +1,174 @@
/**
* @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_
#include <framework/internalError/InternalErrorReporterIF.h>
#include <framework/ipc/MessageQueueIF.h>
#include <framework/ipc/MessageQueueMessage.h>
/**
* @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.
*/
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.
*/
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 sendMessage( 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.
* \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 );
/**
* \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;
static uint16_t queueCounter;
};
#endif /* MESSAGEQUEUE_H_ */

View File

@ -0,0 +1,90 @@
/**
* @file MultiObjectTask.cpp
* @brief This file defines the MultiObjectTask class.
* @date 30.01.2014
* @author baetz
*/
#include <framework/serviceinterface/ServiceInterfaceStream.h>
#include <framework/tasks/ExecutableObjectIF.h>
#include "MultiObjectTask.h"
MultiObjectTask::MultiObjectTask(const char *name, rtems_task_priority setPriority,
size_t setStack, rtems_interval setPeriod, void (*setDeadlineMissedFunc)()) :
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) {
//Do not delete objects, we were responsible for ptrs only.
rtems_rate_monotonic_delete(periodId);
}
rtems_task MultiObjectTask::taskEntryPoint(rtems_task_argument argument) {
//The argument is re-interpreted as MultiObjectTask. The Task object is global, so it is found from any place.
MultiObjectTask *originalTask(reinterpret_cast<MultiObjectTask*>(argument));
originalTask->taskFunctionality();
}
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()
<< std::dec << " failed." << std::endl;
}
return RtemsBasic::convertReturnCode(status);
}
ReturnValue_t MultiObjectTask::sleepFor(uint32_t ms) {
return TaskBase::sleepFor(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;
}
//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);
if (status == RTEMS_TIMEOUT) {
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) {
this->deadlineMissedFunc();
}
}
}
}
ReturnValue_t MultiObjectTask::addComponent(object_id_t object) {
ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>(
object);
if (newObject == NULL) {
return HasReturnvaluesIF::RETURN_FAILED;
}
objectList.push_back(newObject);
return HasReturnvaluesIF::RETURN_OK;
}
uint32_t MultiObjectTask::getPeriodMs() const {
return RtemsBasic::convertTicksToMs(periodTicks);
}

View File

@ -0,0 +1,113 @@
/**
* @file MultiObjectTask.h
* @brief This file defines the MultiObjectTask class.
* @date 30.01.2014
* @author baetz
*/
#ifndef MULTIOBJECTTASK_H_
#define MULTIOBJECTTASK_H_
#include <framework/objectmanager/ObjectManagerIF.h>
#include <framework/tasks/PeriodicTaskIF.h>
#include "TaskBase.h"
#include <vector>
class ExecutableObjectIF;
/**
* @brief This class represents a specialized task for periodic activities of multiple objects.
*
* @details MultiObjectTask is an extension to ObjectTask in the way that it is able to execute
* multiple objects that implement the ExecutableObjectIF interface. The objects must be
* added prior to starting the task.
*
* @ingroup task_handling
*/
class MultiObjectTask: public TaskBase, public PeriodicTaskIF {
public:
/**
* @brief Standard constructor of the class.
* @details The class is initialized without allocated objects. These need to be added
* with #addObject.
* In the underlying TaskBase class, a new operating system task is created.
* In addition to the TaskBase parameters, the period, the pointer to the
* aforementioned initialization function and an optional "deadline-missed"
* function pointer is passed.
* @param priority Sets the priority of a task. Values range from a low 0 to a high 99.
* @param stack_size The stack size reserved by the operating system for the task.
* @param setPeriod The length of the period with which the task's functionality will be
* executed. It is expressed in clock ticks.
* @param setDeadlineMissedFunc The function pointer to the deadline missed function
* that shall be assigned.
*/
MultiObjectTask(const char *name, rtems_task_priority setPriority, size_t setStack, rtems_interval setPeriod,
void (*setDeadlineMissedFunc)());
/**
* @brief Currently, the executed object's lifetime is not coupled with the task object's
* lifetime, so the destructor is empty.
*/
virtual ~MultiObjectTask(void);
/**
* @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);
protected:
typedef std::vector<ExecutableObjectIF*> ObjectList; //!< Typedef for the List of objects.
/**
* @brief This attribute holds a list of objects to be executed.
*/
ObjectList objectList;
/**
* @brief The period of the task.
* @details The period determines the frequency of the task's execution. It is expressed in clock ticks.
*/
rtems_interval periodTicks;
/**
* @brief id of the associated OS period
*/
rtems_id periodId;
/**
* @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)(void);
/**
* @brief This is the function executed in the new task's context.
* @details It converts the argument back to the thread object type and copies the class instance
* to the task context. The taskFunctionality method is called afterwards.
* @param A pointer to the task object itself is passed as argument.
*/
static rtems_task taskEntryPoint(rtems_task_argument argument);
/**
* @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 as long as the isRunning
* attribute is true. Within the loop, all performOperation methods of the added
* objects are called. Afterwards the checkAndRestartPeriod system call blocks the task
* until the next period.
* On missing the deadline, the deadlineMissedFunction is executed.
*/
void taskFunctionality(void);
};
#endif /* MULTIOBJECTTASK_H_ */

35
osal/rtems/Mutex.cpp Normal file
View File

@ -0,0 +1,35 @@
#include "Mutex.h"
#include <framework/serviceinterface/ServiceInterfaceStream.h>
const uint32_t MutexIF::NO_TIMEOUT = RTEMS_NO_TIMEOUT;
uint8_t Mutex::count = 0;
Mutex::Mutex() :
mutexId(0) {
rtems_name mutexName = ('M' << 24) + ('T' << 16) + ('X' << 8) + count++;
rtems_status_code status = rtems_semaphore_create(mutexName, 1,
RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY, 0,
&mutexId);
if (status != RTEMS_SUCCESSFUL) {
error << "Mutex: creation with name, id " << mutexName << ", " << mutexId
<< " failed with " << status << std::endl;
}
}
Mutex::~Mutex() {
rtems_status_code status = rtems_semaphore_delete(mutexId);
if (status != RTEMS_SUCCESSFUL) {
error << "Mutex: deletion for id " << mutexId
<< " failed with " << status << std::endl;
}
}
ReturnValue_t Mutex::lockMutex(uint32_t timeoutMs) {
rtems_status_code status = rtems_semaphore_obtain(mutexId, RTEMS_WAIT, timeoutMs);
return RtemsBasic::convertReturnCode(status);
}
ReturnValue_t Mutex::unlockMutex() {
rtems_status_code status = rtems_semaphore_release(mutexId);
return RtemsBasic::convertReturnCode(status);
}

18
osal/rtems/Mutex.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef OS_RTEMS_MUTEX_H_
#define OS_RTEMS_MUTEX_H_
#include <framework/ipc/MutexIF.h>
#include "RtemsBasic.h"
class Mutex : public MutexIF {
public:
Mutex();
~Mutex();
ReturnValue_t lockMutex(uint32_t timeoutMs);
ReturnValue_t unlockMutex();
private:
rtems_id mutexId;
static uint8_t count;
};
#endif /* OS_RTEMS_MUTEX_H_ */

View File

@ -0,0 +1,24 @@
#include <framework/ipc/MutexFactory.h>
#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() {
}
MutexFactory::~MutexFactory() {
}
MutexFactory* MutexFactory::instance() {
return MutexFactory::factoryInstance;
}
MutexIF* MutexFactory::createMutex() {
return new Mutex();
}
void MutexFactory::deleteMutex(MutexIF* mutex) {
delete mutex;
}

106
osal/rtems/PollingTask.cpp Normal file
View File

@ -0,0 +1,106 @@
#include <framework/serviceinterface/ServiceInterfaceStream.h>
#include "PollingTask.h"
uint32_t PollingTask::deadlineMissedCount = 0;
PollingTask::PollingTask(const char *name, rtems_task_priority setPriority,
size_t setStack, uint32_t setOverallPeriod,
void (*setDeadlineMissedFunc)()) :
TaskBase(setPriority, setStack, name), periodId(0), pst(
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() {
}
rtems_task PollingTask::taskEntryPoint(rtems_task_argument argument) {
//The argument is re-interpreted as PollingTask.
PollingTask *originalTask(reinterpret_cast<PollingTask*>(argument));
//The task's functionality is called.
originalTask->taskFunctionality();
debug << "Polling task " << originalTask->getId()
<< " returned from taskFunctionality." << std::endl;
}
void PollingTask::missedDeadlineCounter() {
PollingTask::deadlineMissedCount++;
if (PollingTask::deadlineMissedCount % 10 == 0) {
error << "PST missed " << PollingTask::deadlineMissedCount
<< " deadlines." << std::endl;
}
}
ReturnValue_t PollingTask::startTask() {
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()
<< std::dec << " failed." << std::endl;
}
return RtemsBasic::convertReturnCode(status);
}
ReturnValue_t PollingTask::addSlot(object_id_t componentId, uint32_t slotTimeMs,
int8_t executionStep) {
pst.addSlot(componentId, slotTimeMs, executionStep, this);
return HasReturnvaluesIF::RETURN_OK;
}
uint32_t PollingTask::getPeriodMs() const {
return pst.getLengthMs();
}
ReturnValue_t PollingTask::checkSequence() const {
return pst.checkSequence();
}
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;
//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;
}
//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.getIntervalMs();
//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);
if (status == RTEMS_TIMEOUT) {
if (this->deadlineMissedFunc != NULL) {
this->deadlineMissedFunc();
}
}
}
//The device handler for this slot is executed and the next one is chosen.
this->pst.executeAndAdvance();
}
}
ReturnValue_t PollingTask::sleepFor(uint32_t ms){
return TaskBase::sleepFor(ms);
};

85
osal/rtems/PollingTask.h Normal file
View File

@ -0,0 +1,85 @@
#ifndef POLLINGTASK_H_
#define POLLINGTASK_H_
#include <framework/devicehandlers/FixedSlotSequence.h>
#include <framework/tasks/FixedTimeslotTaskIF.h>
#include "TaskBase.h"
class PollingTask: public TaskBase, public FixedTimeslotTaskIF {
public:
/**
* @brief The standard constructor of the class.
*
* @details This is the general constructor of the class. In addition to the TaskBase parameters,
* the following variables are passed:
*
* @param (*setDeadlineMissedFunc)() The function pointer to the deadline missed function that shall be assigned.
*
* @param getPst The object id of the completely initialized polling sequence.
*/
PollingTask( const char *name, rtems_task_priority setPriority, size_t setStackSize, uint32_t overallPeriod, void (*setDeadlineMissedFunc)());
/**
* @brief The destructor of the class.
*
* @details The destructor frees all heap memory that was allocated on thread initialization for the PST and
* the device handlers. This is done by calling the PST's destructor.
*/
virtual ~PollingTask( void );
ReturnValue_t startTask( void );
/**
* This static function can be used as #deadlineMissedFunc.
* It counts missedDeadlines and prints the number of missed deadlines every 10th time.
*/
static void missedDeadlineCounter();
/**
* A helper variable to count missed deadlines.
*/
static uint32_t deadlineMissedCount;
ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs, int8_t executionStep);
uint32_t getPeriodMs() const;
ReturnValue_t checkSequence() const;
ReturnValue_t sleepFor(uint32_t ms);
protected:
/**
* @brief id of the associated OS period
*/
rtems_id periodId;
FixedSlotSequence pst;
/**
* @brief This attribute holds a function pointer that is executed when a deadline was missed.
*
* @details Another function may be announced to determine the actions to perform when a deadline was missed.
* Currently, only one function for missing any deadline is allowed.
* If not used, it shall be declared NULL.
*/
void ( *deadlineMissedFunc )( void );
/**
* @brief This is the entry point in a new polling thread.
*
* @details This method, that is the generalOSAL::checkAndRestartPeriod( this->periodId, interval ); entry point in the new thread, is here set to generate
* and link the Polling Sequence Table to the thread object and start taskFunctionality()
* on success. If operation of the task is ended for some reason,
* the destructor is called to free allocated memory.
*/
static rtems_task taskEntryPoint( rtems_task_argument argument );
/**
* @brief This function holds the main functionality of the thread.
*
*
* @details Holding the main functionality of the task, this method is most important.
* It links the functionalities provided by FixedSlotSequence with the OS's System Calls
* to keep the timing of the periods.
*/
void taskFunctionality( void );
};
#endif /* POLLINGTASK_H_ */

View File

@ -0,0 +1,36 @@
#include <framework/ipc/QueueFactory.h>
#include "MessageQueue.h"
#include "RtemsBasic.h"
QueueFactory* QueueFactory::factoryInstance = NULL;
ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo,
MessageQueueMessage* message, MessageQueueId_t sentFrom) {
message->setSender(sentFrom);
rtems_status_code result = rtems_message_queue_send(sendTo, message->getBuffer(),
message->messageSize);
return RtemsBasic::convertReturnCode(result);
}
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;
}

70
osal/rtems/RtemsBasic.cpp Normal file
View File

@ -0,0 +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;
}
}
}

39
osal/rtems/RtemsBasic.h Normal file
View File

@ -0,0 +1,39 @@
#ifndef OS_RTEMS_RTEMSBASIC_H_
#define OS_RTEMS_RTEMSBASIC_H_
#include <framework/returnvalues/HasReturnvaluesIF.h>
#include <framework/osal/OperatingSystemIF.h>
extern "C" {
#include <bsp_flp/rtems_config.h>
}
#include <rtems/endian.h>
#include <rtems.h>
#include <rtems/libio.h>
#include <rtems/error.h>
#include <rtems/stackchk.h>
#include <stddef.h>
class RtemsBasic: public OperatingSystemIF {
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);
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);
return (ticksIn * 1000) / ticks_per_second;
}
};
#endif /* OS_RTEMS_RTEMSBASIC_H_ */

43
osal/rtems/TaskBase.cpp Normal file
View File

@ -0,0 +1,43 @@
#include <framework/serviceinterface/ServiceInterfaceStream.h>
#include "TaskBase.h"
const uint64_t PeriodicTaskIF::MINIMUM_STACK_SIZE=RTEMS_MINIMUM_STACK_SIZE;
TaskBase::TaskBase(rtems_task_priority set_priority, size_t stack_size,
const char *name) {
rtems_name osalName = 0;
for (uint8_t i = 0; i < 4; i++) {
if (name[i] == 0) {
break;
}
osalName += name[i] << (8 * (3 - i));
}
//The task is created with the operating system's system call.
rtems_status_code status = RTEMS_UNSATISFIED;
if (set_priority >= 0 && set_priority <= 99) {
status = rtems_task_create(osalName,
(0xFF - 2 * set_priority), stack_size,
RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR,
RTEMS_FLOATING_POINT, &id);
}
ReturnValue_t result = RtemsBasic::convertReturnCode(status);
if (result != HasReturnvaluesIF::RETURN_OK) {
error << "TaskBase::TaskBase: createTask with name " << std::hex
<< osalName << std::dec << " failed with return code "
<< (uint32_t) status << std::endl;
this->id = 0;
}
}
TaskBase::~TaskBase() {
rtems_task_delete(id);
}
rtems_id TaskBase::getId() {
return this->id;
}
ReturnValue_t TaskBase::sleepFor(uint32_t ms) {
rtems_status_code status = rtems_task_wake_after(RtemsBasic::convertMsToTicks(ms));
return RtemsBasic::convertReturnCode(status);
}

43
osal/rtems/TaskBase.h Normal file
View File

@ -0,0 +1,43 @@
#ifndef TASKBASE_H_
#define TASKBASE_H_
#include "RtemsBasic.h"
#include <framework/tasks/PeriodicTaskIF.h>
/**
* @brief This is the basic task handling class for rtems.
*
* @details Task creation base class for rtems.
*/
class TaskBase {
protected:
/**
* @brief The class stores the task id it got assigned from the operating system in this attribute.
* If initialization fails, the id is set to zero.
*/
rtems_id id;
public:
/**
* @brief The constructor creates and initializes a task.
* @details This is accomplished by using the operating system call to create a task. The name is
* created automatically with the help od taskCounter. Priority and stack size are
* adjustable, all other attributes are set with default values.
* @param priority Sets the priority of a task. Values range from a low 0 to a high 99.
* @param stack_size The stack size reserved by the operating system for the task.
* @param nam The name of the Task, as a null-terminated String. Currently max 4 chars supported (excluding Null-terminator), rest will be truncated
*/
TaskBase( rtems_task_priority priority, size_t stack_size, const char *name);
/**
* @brief In the destructor, the created task is deleted.
*/
virtual ~TaskBase();
/**
* @brief This method returns the task id of this class.
*/
rtems_id getId();
ReturnValue_t sleepFor(uint32_t ms);
};
#endif /* TASKBASE_H_ */

View File

@ -0,0 +1,34 @@
#include <framework/tasks/TaskFactory.h>
#include "MultiObjectTask.h"
#include "PollingTask.h"
#include "InitTask.h"
#include <framework/returnvalues/HasReturnvaluesIF.h>
//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(OSAL::TaskName name_,OSAL::TaskPriority taskPriority_,OSAL::TaskStackSize stackSize_,OSAL::TaskPeriod periodInSeconds_,OSAL::TaskDeadlineMissedFunction deadLineMissedFunction_) {
rtems_interval taskPeriod = periodInSeconds_ * Clock::getTicksPerSecond();
return static_cast<PeriodicTaskIF*>(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_) {
rtems_interval taskPeriod = periodInSeconds_ * Clock::getTicksPerSecond();
return static_cast<FixedTimeslotTaskIF*>(new PollingTask(name_,taskPriority_,stackSize_,taskPeriod,deadLineMissedFunction_));
}
ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) {
//TODO not implemented
return HasReturnvaluesIF::RETURN_FAILED;
}
TaskFactory::TaskFactory() {
}