1
0
forked from fsfw/fsfw

renormalized line endings

This commit is contained in:
2020-08-28 18:33:29 +02:00
parent 9abd796e6f
commit 1b9c8446b7
381 changed files with 38723 additions and 38723 deletions

View File

@ -1,149 +1,149 @@
#include "../../osal/linux/BinarySemaphore.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
extern "C" {
#include <errno.h>
#include <string.h>
}
BinarySemaphore::BinarySemaphore() {
// Using unnamed semaphores for now
initSemaphore();
}
BinarySemaphore::~BinarySemaphore() {
sem_destroy(&handle);
}
BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) {
initSemaphore();
}
BinarySemaphore& BinarySemaphore::operator =(
BinarySemaphore&& s) {
initSemaphore();
return * this;
}
ReturnValue_t BinarySemaphore::acquire(TimeoutType timeoutType,
uint32_t timeoutMs) {
int result = 0;
if(timeoutType == TimeoutType::POLLING) {
result = sem_trywait(&handle);
}
else if(timeoutType == TimeoutType::BLOCKING) {
result = sem_wait(&handle);
}
else if(timeoutType == TimeoutType::WAITING){
timespec timeOut;
clock_gettime(CLOCK_REALTIME, &timeOut);
uint64_t nseconds = timeOut.tv_sec * 1000000000 + timeOut.tv_nsec;
nseconds += timeoutMs * 1000000;
timeOut.tv_sec = nseconds / 1000000000;
timeOut.tv_nsec = nseconds - timeOut.tv_sec * 1000000000;
result = sem_timedwait(&handle, &timeOut);
if(result != 0 and errno == EINVAL) {
sif::debug << "BinarySemaphore::acquire: Invalid time value possible"
<< std::endl;
}
}
if(result == 0) {
return HasReturnvaluesIF::RETURN_OK;
}
switch(errno) {
case(EAGAIN):
// Operation could not be performed without blocking (for sem_trywait)
case(ETIMEDOUT):
// Semaphore is 0
return SemaphoreIF::SEMAPHORE_TIMEOUT;
case(EINVAL):
// Semaphore invalid
return SemaphoreIF::SEMAPHORE_INVALID;
case(EINTR):
// Call was interrupted by signal handler
sif::debug << "BinarySemaphore::acquire: Signal handler interrupted."
"Code " << strerror(errno) << std::endl;
/* No break */
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t BinarySemaphore::release() {
return BinarySemaphore::release(&this->handle);
}
ReturnValue_t BinarySemaphore::release(sem_t *handle) {
ReturnValue_t countResult = checkCount(handle, 1);
if(countResult != HasReturnvaluesIF::RETURN_OK) {
return countResult;
}
int result = sem_post(handle);
if(result == 0) {
return HasReturnvaluesIF::RETURN_OK;
}
switch(errno) {
case(EINVAL):
// Semaphore invalid
return SemaphoreIF::SEMAPHORE_INVALID;
case(EOVERFLOW):
// SEM_MAX_VALUE overflow. This should never happen
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
uint8_t BinarySemaphore::getSemaphoreCounter() const {
// And another ugly cast :-D
return getSemaphoreCounter(const_cast<sem_t*>(&this->handle));
}
uint8_t BinarySemaphore::getSemaphoreCounter(sem_t *handle) {
int value = 0;
int result = sem_getvalue(handle, &value);
if (result == 0) {
return value;
}
else if(result != 0 and errno == EINVAL) {
// Could be called from interrupt, use lightweight printf
printf("BinarySemaphore::getSemaphoreCounter: Invalid semaphore\n");
return 0;
}
else {
// This should never happen.
return 0;
}
}
void BinarySemaphore::initSemaphore(uint8_t initCount) {
auto result = sem_init(&handle, true, initCount);
if(result == -1) {
switch(errno) {
case(EINVAL):
// Value exceeds SEM_VALUE_MAX
case(ENOSYS):
// System does not support process-shared semaphores
sif::error << "BinarySemaphore: Init failed with" << strerror(errno)
<< std::endl;
}
}
}
ReturnValue_t BinarySemaphore::checkCount(sem_t* handle, uint8_t maxCount) {
int value = getSemaphoreCounter(handle);
if(value >= maxCount) {
if(maxCount == 1 and value > 1) {
// Binary Semaphore special case.
// This is a config error use lightweight printf is this is called
// from an interrupt
printf("BinarySemaphore::release: Value of binary semaphore greater"
" than 1!\n");
return HasReturnvaluesIF::RETURN_FAILED;
}
return SemaphoreIF::SEMAPHORE_NOT_OWNED;
}
return HasReturnvaluesIF::RETURN_OK;
}
#include "../../osal/linux/BinarySemaphore.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
extern "C" {
#include <errno.h>
#include <string.h>
}
BinarySemaphore::BinarySemaphore() {
// Using unnamed semaphores for now
initSemaphore();
}
BinarySemaphore::~BinarySemaphore() {
sem_destroy(&handle);
}
BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) {
initSemaphore();
}
BinarySemaphore& BinarySemaphore::operator =(
BinarySemaphore&& s) {
initSemaphore();
return * this;
}
ReturnValue_t BinarySemaphore::acquire(TimeoutType timeoutType,
uint32_t timeoutMs) {
int result = 0;
if(timeoutType == TimeoutType::POLLING) {
result = sem_trywait(&handle);
}
else if(timeoutType == TimeoutType::BLOCKING) {
result = sem_wait(&handle);
}
else if(timeoutType == TimeoutType::WAITING){
timespec timeOut;
clock_gettime(CLOCK_REALTIME, &timeOut);
uint64_t nseconds = timeOut.tv_sec * 1000000000 + timeOut.tv_nsec;
nseconds += timeoutMs * 1000000;
timeOut.tv_sec = nseconds / 1000000000;
timeOut.tv_nsec = nseconds - timeOut.tv_sec * 1000000000;
result = sem_timedwait(&handle, &timeOut);
if(result != 0 and errno == EINVAL) {
sif::debug << "BinarySemaphore::acquire: Invalid time value possible"
<< std::endl;
}
}
if(result == 0) {
return HasReturnvaluesIF::RETURN_OK;
}
switch(errno) {
case(EAGAIN):
// Operation could not be performed without blocking (for sem_trywait)
case(ETIMEDOUT):
// Semaphore is 0
return SemaphoreIF::SEMAPHORE_TIMEOUT;
case(EINVAL):
// Semaphore invalid
return SemaphoreIF::SEMAPHORE_INVALID;
case(EINTR):
// Call was interrupted by signal handler
sif::debug << "BinarySemaphore::acquire: Signal handler interrupted."
"Code " << strerror(errno) << std::endl;
/* No break */
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t BinarySemaphore::release() {
return BinarySemaphore::release(&this->handle);
}
ReturnValue_t BinarySemaphore::release(sem_t *handle) {
ReturnValue_t countResult = checkCount(handle, 1);
if(countResult != HasReturnvaluesIF::RETURN_OK) {
return countResult;
}
int result = sem_post(handle);
if(result == 0) {
return HasReturnvaluesIF::RETURN_OK;
}
switch(errno) {
case(EINVAL):
// Semaphore invalid
return SemaphoreIF::SEMAPHORE_INVALID;
case(EOVERFLOW):
// SEM_MAX_VALUE overflow. This should never happen
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
uint8_t BinarySemaphore::getSemaphoreCounter() const {
// And another ugly cast :-D
return getSemaphoreCounter(const_cast<sem_t*>(&this->handle));
}
uint8_t BinarySemaphore::getSemaphoreCounter(sem_t *handle) {
int value = 0;
int result = sem_getvalue(handle, &value);
if (result == 0) {
return value;
}
else if(result != 0 and errno == EINVAL) {
// Could be called from interrupt, use lightweight printf
printf("BinarySemaphore::getSemaphoreCounter: Invalid semaphore\n");
return 0;
}
else {
// This should never happen.
return 0;
}
}
void BinarySemaphore::initSemaphore(uint8_t initCount) {
auto result = sem_init(&handle, true, initCount);
if(result == -1) {
switch(errno) {
case(EINVAL):
// Value exceeds SEM_VALUE_MAX
case(ENOSYS):
// System does not support process-shared semaphores
sif::error << "BinarySemaphore: Init failed with" << strerror(errno)
<< std::endl;
}
}
}
ReturnValue_t BinarySemaphore::checkCount(sem_t* handle, uint8_t maxCount) {
int value = getSemaphoreCounter(handle);
if(value >= maxCount) {
if(maxCount == 1 and value > 1) {
// Binary Semaphore special case.
// This is a config error use lightweight printf is this is called
// from an interrupt
printf("BinarySemaphore::release: Value of binary semaphore greater"
" than 1!\n");
return HasReturnvaluesIF::RETURN_FAILED;
}
return SemaphoreIF::SEMAPHORE_NOT_OWNED;
}
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -1,81 +1,81 @@
#ifndef FRAMEWORK_OSAL_LINUX_BINARYSEMPAHORE_H_
#define FRAMEWORK_OSAL_LINUX_BINARYSEMPAHORE_H_
#include "../../returnvalues/HasReturnvaluesIF.h"
#include "../../tasks/SemaphoreIF.h"
extern "C" {
#include <semaphore.h>
}
/**
* @brief OS Tool to achieve synchronization of between tasks or between
* task and ISR. The default semaphore implementation creates a
* binary semaphore, which can only be taken once.
* @details
* See: http://www.man7.org/linux/man-pages/man7/sem_overview.7.html
* @author R. Mueller
* @ingroup osal
*/
class BinarySemaphore: public SemaphoreIF,
public HasReturnvaluesIF {
public:
static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF;
//! @brief Default ctor
BinarySemaphore();
//! @brief Copy ctor, deleted explicitely.
BinarySemaphore(const BinarySemaphore&) = delete;
//! @brief Copy assignment, deleted explicitely.
BinarySemaphore& operator=(const BinarySemaphore&) = delete;
//! @brief Move ctor
BinarySemaphore (BinarySemaphore &&);
//! @brief Move assignment
BinarySemaphore & operator=(BinarySemaphore &&);
//! @brief Destructor
virtual ~BinarySemaphore();
void initSemaphore(uint8_t initCount = 1);
uint8_t getSemaphoreCounter() const override;
static uint8_t getSemaphoreCounter(sem_t* handle);
/**
* Take the binary semaphore.
* If the semaphore has already been taken, the task will be blocked
* for a maximum of #timeoutMs or until the semaphore is given back,
* for example by an ISR or another task.
* @param timeoutMs
* @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout
*/
ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING,
uint32_t timeoutMs = 0) override;
/**
* Release the binary semaphore.
* @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is
* already available.
*/
virtual ReturnValue_t release() override;
/**
* This static function can be used to release a semaphore by providing
* its handle.
* @param handle
* @return
*/
static ReturnValue_t release(sem_t* handle);
/** Checks the validity of the semaphore count against a specified
* known maxCount
* @param handle
* @param maxCount
* @return
*/
static ReturnValue_t checkCount(sem_t* handle, uint8_t maxCount);
protected:
sem_t handle;
};
#endif /* FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ */
#ifndef FRAMEWORK_OSAL_LINUX_BINARYSEMPAHORE_H_
#define FRAMEWORK_OSAL_LINUX_BINARYSEMPAHORE_H_
#include "../../returnvalues/HasReturnvaluesIF.h"
#include "../../tasks/SemaphoreIF.h"
extern "C" {
#include <semaphore.h>
}
/**
* @brief OS Tool to achieve synchronization of between tasks or between
* task and ISR. The default semaphore implementation creates a
* binary semaphore, which can only be taken once.
* @details
* See: http://www.man7.org/linux/man-pages/man7/sem_overview.7.html
* @author R. Mueller
* @ingroup osal
*/
class BinarySemaphore: public SemaphoreIF,
public HasReturnvaluesIF {
public:
static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF;
//! @brief Default ctor
BinarySemaphore();
//! @brief Copy ctor, deleted explicitely.
BinarySemaphore(const BinarySemaphore&) = delete;
//! @brief Copy assignment, deleted explicitely.
BinarySemaphore& operator=(const BinarySemaphore&) = delete;
//! @brief Move ctor
BinarySemaphore (BinarySemaphore &&);
//! @brief Move assignment
BinarySemaphore & operator=(BinarySemaphore &&);
//! @brief Destructor
virtual ~BinarySemaphore();
void initSemaphore(uint8_t initCount = 1);
uint8_t getSemaphoreCounter() const override;
static uint8_t getSemaphoreCounter(sem_t* handle);
/**
* Take the binary semaphore.
* If the semaphore has already been taken, the task will be blocked
* for a maximum of #timeoutMs or until the semaphore is given back,
* for example by an ISR or another task.
* @param timeoutMs
* @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout
*/
ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING,
uint32_t timeoutMs = 0) override;
/**
* Release the binary semaphore.
* @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is
* already available.
*/
virtual ReturnValue_t release() override;
/**
* This static function can be used to release a semaphore by providing
* its handle.
* @param handle
* @return
*/
static ReturnValue_t release(sem_t* handle);
/** Checks the validity of the semaphore count against a specified
* known maxCount
* @param handle
* @param maxCount
* @return
*/
static ReturnValue_t checkCount(sem_t* handle, uint8_t maxCount);
protected:
sem_t handle;
};
#endif /* FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ */

View File

@ -1,220 +1,220 @@
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../timemanager/Clock.h"
#include <sys/time.h>
#include <sys/sysinfo.h>
#include <linux/sysinfo.h>
#include <time.h>
#include <unistd.h>
//#include <fstream>
uint16_t Clock::leapSeconds = 0;
MutexIF* Clock::timeMutex = NULL;
uint32_t Clock::getTicksPerSecond(void){
uint32_t ticks = sysconf(_SC_CLK_TCK);
return ticks;
}
ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {
timespec timeUnix;
timeval timeTimeval;
convertTimeOfDayToTimeval(time,&timeTimeval);
timeUnix.tv_sec = timeTimeval.tv_sec;
timeUnix.tv_nsec = (__syscall_slong_t) timeTimeval.tv_usec * 1000;
int status = clock_settime(CLOCK_REALTIME,&timeUnix);
if(status!=0){
//TODO errno
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;
}
timeval Clock::getUptime() {
timeval uptime;
auto result = getUptime(&uptime);
if(result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "Clock::getUptime: Error getting uptime" << std::endl;
}
return uptime;
}
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;
}
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->usecond = timeUnix.tv_nsec / 1000.0;
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;
to->tv_sec = mktime(&fromTm);
to->tv_usec = from->usecond;
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::BLOCKING);
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::BLOCKING);
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;
}
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../timemanager/Clock.h"
#include <sys/time.h>
#include <sys/sysinfo.h>
#include <linux/sysinfo.h>
#include <time.h>
#include <unistd.h>
//#include <fstream>
uint16_t Clock::leapSeconds = 0;
MutexIF* Clock::timeMutex = NULL;
uint32_t Clock::getTicksPerSecond(void){
uint32_t ticks = sysconf(_SC_CLK_TCK);
return ticks;
}
ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {
timespec timeUnix;
timeval timeTimeval;
convertTimeOfDayToTimeval(time,&timeTimeval);
timeUnix.tv_sec = timeTimeval.tv_sec;
timeUnix.tv_nsec = (__syscall_slong_t) timeTimeval.tv_usec * 1000;
int status = clock_settime(CLOCK_REALTIME,&timeUnix);
if(status!=0){
//TODO errno
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;
}
timeval Clock::getUptime() {
timeval uptime;
auto result = getUptime(&uptime);
if(result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "Clock::getUptime: Error getting uptime" << std::endl;
}
return uptime;
}
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;
}
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->usecond = timeUnix.tv_nsec / 1000.0;
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;
to->tv_sec = mktime(&fromTm);
to->tv_usec = from->usecond;
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::BLOCKING);
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::BLOCKING);
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;
}

View File

@ -1,54 +1,54 @@
#include "../../osal/linux/CountingSemaphore.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
CountingSemaphore::CountingSemaphore(const uint8_t maxCount, uint8_t initCount):
maxCount(maxCount), initCount(initCount) {
if(initCount > maxCount) {
sif::error << "CountingSemaphoreUsingTask: Max count bigger than "
"intial cout. Setting initial count to max count." << std::endl;
initCount = maxCount;
}
initSemaphore(initCount);
}
CountingSemaphore::CountingSemaphore(CountingSemaphore&& other):
maxCount(other.maxCount), initCount(other.initCount) {
initSemaphore(initCount);
}
CountingSemaphore& CountingSemaphore::operator =(
CountingSemaphore&& other) {
initSemaphore(other.initCount);
return * this;
}
ReturnValue_t CountingSemaphore::release() {
ReturnValue_t result = checkCount(&handle, maxCount);
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
return CountingSemaphore::release(&this->handle);
}
ReturnValue_t CountingSemaphore::release(sem_t* handle) {
int result = sem_post(handle);
if(result == 0) {
return HasReturnvaluesIF::RETURN_OK;
}
switch(errno) {
case(EINVAL):
// Semaphore invalid
return SemaphoreIF::SEMAPHORE_INVALID;
case(EOVERFLOW):
// SEM_MAX_VALUE overflow. This should never happen
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
uint8_t CountingSemaphore::getMaxCount() const {
return maxCount;
}
#include "../../osal/linux/CountingSemaphore.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
CountingSemaphore::CountingSemaphore(const uint8_t maxCount, uint8_t initCount):
maxCount(maxCount), initCount(initCount) {
if(initCount > maxCount) {
sif::error << "CountingSemaphoreUsingTask: Max count bigger than "
"intial cout. Setting initial count to max count." << std::endl;
initCount = maxCount;
}
initSemaphore(initCount);
}
CountingSemaphore::CountingSemaphore(CountingSemaphore&& other):
maxCount(other.maxCount), initCount(other.initCount) {
initSemaphore(initCount);
}
CountingSemaphore& CountingSemaphore::operator =(
CountingSemaphore&& other) {
initSemaphore(other.initCount);
return * this;
}
ReturnValue_t CountingSemaphore::release() {
ReturnValue_t result = checkCount(&handle, maxCount);
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
return CountingSemaphore::release(&this->handle);
}
ReturnValue_t CountingSemaphore::release(sem_t* handle) {
int result = sem_post(handle);
if(result == 0) {
return HasReturnvaluesIF::RETURN_OK;
}
switch(errno) {
case(EINVAL):
// Semaphore invalid
return SemaphoreIF::SEMAPHORE_INVALID;
case(EOVERFLOW):
// SEM_MAX_VALUE overflow. This should never happen
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
uint8_t CountingSemaphore::getMaxCount() const {
return maxCount;
}

View File

@ -1,37 +1,37 @@
#ifndef FRAMEWORK_OSAL_LINUX_COUNTINGSEMAPHORE_H_
#define FRAMEWORK_OSAL_LINUX_COUNTINGSEMAPHORE_H_
#include "../../osal/linux/BinarySemaphore.h"
/**
* @brief Counting semaphores, which can be acquired more than once.
* @details
* See: https://www.freertos.org/CreateCounting.html
* API of counting semaphores is almost identical to binary semaphores,
* so we just inherit from binary semaphore and provide the respective
* constructors.
*/
class CountingSemaphore: public BinarySemaphore {
public:
CountingSemaphore(const uint8_t maxCount, uint8_t initCount);
//! @brief Copy ctor, disabled
CountingSemaphore(const CountingSemaphore&) = delete;
//! @brief Copy assignment, disabled
CountingSemaphore& operator=(const CountingSemaphore&) = delete;
//! @brief Move ctor
CountingSemaphore (CountingSemaphore &&);
//! @brief Move assignment
CountingSemaphore & operator=(CountingSemaphore &&);
ReturnValue_t release() override;
static ReturnValue_t release(sem_t* sem);
/* Same API as binary semaphore otherwise. acquire() can be called
* until there are not semaphores left and release() can be called
* until maxCount is reached. */
uint8_t getMaxCount() const;
private:
const uint8_t maxCount;
uint8_t initCount = 0;
};
#endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ */
#ifndef FRAMEWORK_OSAL_LINUX_COUNTINGSEMAPHORE_H_
#define FRAMEWORK_OSAL_LINUX_COUNTINGSEMAPHORE_H_
#include "../../osal/linux/BinarySemaphore.h"
/**
* @brief Counting semaphores, which can be acquired more than once.
* @details
* See: https://www.freertos.org/CreateCounting.html
* API of counting semaphores is almost identical to binary semaphores,
* so we just inherit from binary semaphore and provide the respective
* constructors.
*/
class CountingSemaphore: public BinarySemaphore {
public:
CountingSemaphore(const uint8_t maxCount, uint8_t initCount);
//! @brief Copy ctor, disabled
CountingSemaphore(const CountingSemaphore&) = delete;
//! @brief Copy assignment, disabled
CountingSemaphore& operator=(const CountingSemaphore&) = delete;
//! @brief Move ctor
CountingSemaphore (CountingSemaphore &&);
//! @brief Move assignment
CountingSemaphore & operator=(CountingSemaphore &&);
ReturnValue_t release() override;
static ReturnValue_t release(sem_t* sem);
/* Same API as binary semaphore otherwise. acquire() can be called
* until there are not semaphores left and release() can be called
* until maxCount is reached. */
uint8_t getMaxCount() const;
private:
const uint8_t maxCount;
uint8_t initCount = 0;
};
#endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ */

View File

@ -1,96 +1,96 @@
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../osal/linux/FixedTimeslotTask.h"
#include <limits.h>
uint32_t FixedTimeslotTask::deadlineMissedCount = 0;
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = PTHREAD_STACK_MIN;
FixedTimeslotTask::FixedTimeslotTask(const char* name_, int priority_,
size_t stackSize_, uint32_t periodMs_):
PosixThread(name_,priority_,stackSize_),pst(periodMs_),started(false) {
}
FixedTimeslotTask::~FixedTimeslotTask() {
}
void* FixedTimeslotTask::taskEntryPoint(void* arg) {
//The argument is re-interpreted as PollingTask.
FixedTimeslotTask *originalTask(reinterpret_cast<FixedTimeslotTask*>(arg));
//The task's functionality is called.
originalTask->taskFunctionality();
return nullptr;
}
ReturnValue_t FixedTimeslotTask::startTask() {
started = true;
createTask(&taskEntryPoint,this);
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) {
return PosixThread::sleep((uint64_t)ms*1000000);
}
uint32_t FixedTimeslotTask::getPeriodMs() const {
return pst.getLengthMs();
}
ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId,
uint32_t slotTimeMs, int8_t executionStep) {
ExecutableObjectIF* executableObject =
objectManager->get<ExecutableObjectIF>(componentId);
if (executableObject != nullptr) {
pst.addSlot(componentId, slotTimeMs, executionStep,
executableObject,this);
return HasReturnvaluesIF::RETURN_OK;
}
sif::error << "Component " << std::hex << componentId <<
" not found, not adding it to pst" << std::dec << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t FixedTimeslotTask::checkSequence() const {
return pst.checkSequence();
}
void FixedTimeslotTask::taskFunctionality() {
//Like FreeRTOS pthreads are running as soon as they are created
if (!started) {
suspend();
}
pst.intializeSequenceAfterTaskCreation();
//The start time for the first entry is read.
uint64_t lastWakeTime = getCurrentMonotonicTimeMs();
uint64_t interval = pst.getIntervalToNextSlotMs();
//The task's "infinite" inner loop is entered.
while (1) {
if (pst.slotFollowsImmediately()) {
//Do nothing
} else {
//The interval for the next polling slot is selected.
interval = this->pst.getIntervalToPreviousSlotMs();
//The period is checked and restarted with the new interval.
//If the deadline was missed, the deadlineMissedFunc is called.
if(!PosixThread::delayUntil(&lastWakeTime,interval)) {
//No time left on timer -> we missed the deadline
missedDeadlineCounter();
}
}
//The device handler for this slot is executed and the next one is chosen.
this->pst.executeAndAdvance();
}
}
void FixedTimeslotTask::missedDeadlineCounter() {
FixedTimeslotTask::deadlineMissedCount++;
if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) {
sif::error << "PST missed " << FixedTimeslotTask::deadlineMissedCount
<< " deadlines." << std::endl;
}
}
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../osal/linux/FixedTimeslotTask.h"
#include <limits.h>
uint32_t FixedTimeslotTask::deadlineMissedCount = 0;
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = PTHREAD_STACK_MIN;
FixedTimeslotTask::FixedTimeslotTask(const char* name_, int priority_,
size_t stackSize_, uint32_t periodMs_):
PosixThread(name_,priority_,stackSize_),pst(periodMs_),started(false) {
}
FixedTimeslotTask::~FixedTimeslotTask() {
}
void* FixedTimeslotTask::taskEntryPoint(void* arg) {
//The argument is re-interpreted as PollingTask.
FixedTimeslotTask *originalTask(reinterpret_cast<FixedTimeslotTask*>(arg));
//The task's functionality is called.
originalTask->taskFunctionality();
return nullptr;
}
ReturnValue_t FixedTimeslotTask::startTask() {
started = true;
createTask(&taskEntryPoint,this);
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) {
return PosixThread::sleep((uint64_t)ms*1000000);
}
uint32_t FixedTimeslotTask::getPeriodMs() const {
return pst.getLengthMs();
}
ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId,
uint32_t slotTimeMs, int8_t executionStep) {
ExecutableObjectIF* executableObject =
objectManager->get<ExecutableObjectIF>(componentId);
if (executableObject != nullptr) {
pst.addSlot(componentId, slotTimeMs, executionStep,
executableObject,this);
return HasReturnvaluesIF::RETURN_OK;
}
sif::error << "Component " << std::hex << componentId <<
" not found, not adding it to pst" << std::dec << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t FixedTimeslotTask::checkSequence() const {
return pst.checkSequence();
}
void FixedTimeslotTask::taskFunctionality() {
//Like FreeRTOS pthreads are running as soon as they are created
if (!started) {
suspend();
}
pst.intializeSequenceAfterTaskCreation();
//The start time for the first entry is read.
uint64_t lastWakeTime = getCurrentMonotonicTimeMs();
uint64_t interval = pst.getIntervalToNextSlotMs();
//The task's "infinite" inner loop is entered.
while (1) {
if (pst.slotFollowsImmediately()) {
//Do nothing
} else {
//The interval for the next polling slot is selected.
interval = this->pst.getIntervalToPreviousSlotMs();
//The period is checked and restarted with the new interval.
//If the deadline was missed, the deadlineMissedFunc is called.
if(!PosixThread::delayUntil(&lastWakeTime,interval)) {
//No time left on timer -> we missed the deadline
missedDeadlineCounter();
}
}
//The device handler for this slot is executed and the next one is chosen.
this->pst.executeAndAdvance();
}
}
void FixedTimeslotTask::missedDeadlineCounter() {
FixedTimeslotTask::deadlineMissedCount++;
if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) {
sif::error << "PST missed " << FixedTimeslotTask::deadlineMissedCount
<< " deadlines." << std::endl;
}
}

View File

@ -1,77 +1,77 @@
#ifndef FRAMEWORK_OSAL_LINUX_FIXEDTIMESLOTTASK_H_
#define FRAMEWORK_OSAL_LINUX_FIXEDTIMESLOTTASK_H_
#include "../../tasks/FixedTimeslotTaskIF.h"
#include "../../tasks/FixedSlotSequence.h"
#include "../../osal/linux/PosixThread.h"
#include <pthread.h>
class FixedTimeslotTask: public FixedTimeslotTaskIF, public PosixThread {
public:
/**
* Create a generic periodic task.
* @param name_
* Name, maximum allowed size of linux is 16 chars, everything else will
* be truncated.
* @param priority_
* Real-time priority, ranges from 1 to 99 for Linux.
* See: https://man7.org/linux/man-pages/man7/sched.7.html
* @param stackSize_
* @param period_
* @param deadlineMissedFunc_
*/
FixedTimeslotTask(const char* name_, int priority_, size_t stackSize_,
uint32_t periodMs_);
virtual ~FixedTimeslotTask();
virtual ReturnValue_t startTask();
virtual ReturnValue_t sleepFor(uint32_t ms);
virtual uint32_t getPeriodMs() const;
virtual ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs,
int8_t executionStep);
virtual ReturnValue_t checkSequence() const;
/**
* This static function can be used as #deadlineMissedFunc.
* It counts missedDeadlines and prints the number of missed deadlines every 10th time.
*/
static void missedDeadlineCounter();
/**
* A helper variable to count missed deadlines.
*/
static uint32_t deadlineMissedCount;
protected:
/**
* @brief This function holds the main functionality of the thread.
* @details
* Holding the main functionality of the task, this method is most important.
* It links the functionalities provided by FixedSlotSequence with the
* OS's System Calls to keep the timing of the periods.
*/
virtual void taskFunctionality();
private:
/**
* @brief This is the entry point in a new thread.
*
* @details
* This method, that is the entry point in the new thread and calls
* taskFunctionality of the child class. Needs a valid pointer to the
* derived class.
*
* The void* returnvalue is not used yet but could be used to return
* arbitrary data.
*/
static void* taskEntryPoint(void* arg);
FixedSlotSequence pst;
bool started;
};
#endif /* FRAMEWORK_OSAL_LINUX_FIXEDTIMESLOTTASK_H_ */
#ifndef FRAMEWORK_OSAL_LINUX_FIXEDTIMESLOTTASK_H_
#define FRAMEWORK_OSAL_LINUX_FIXEDTIMESLOTTASK_H_
#include "../../tasks/FixedTimeslotTaskIF.h"
#include "../../tasks/FixedSlotSequence.h"
#include "../../osal/linux/PosixThread.h"
#include <pthread.h>
class FixedTimeslotTask: public FixedTimeslotTaskIF, public PosixThread {
public:
/**
* Create a generic periodic task.
* @param name_
* Name, maximum allowed size of linux is 16 chars, everything else will
* be truncated.
* @param priority_
* Real-time priority, ranges from 1 to 99 for Linux.
* See: https://man7.org/linux/man-pages/man7/sched.7.html
* @param stackSize_
* @param period_
* @param deadlineMissedFunc_
*/
FixedTimeslotTask(const char* name_, int priority_, size_t stackSize_,
uint32_t periodMs_);
virtual ~FixedTimeslotTask();
virtual ReturnValue_t startTask();
virtual ReturnValue_t sleepFor(uint32_t ms);
virtual uint32_t getPeriodMs() const;
virtual ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs,
int8_t executionStep);
virtual ReturnValue_t checkSequence() const;
/**
* This static function can be used as #deadlineMissedFunc.
* It counts missedDeadlines and prints the number of missed deadlines every 10th time.
*/
static void missedDeadlineCounter();
/**
* A helper variable to count missed deadlines.
*/
static uint32_t deadlineMissedCount;
protected:
/**
* @brief This function holds the main functionality of the thread.
* @details
* Holding the main functionality of the task, this method is most important.
* It links the functionalities provided by FixedSlotSequence with the
* OS's System Calls to keep the timing of the periods.
*/
virtual void taskFunctionality();
private:
/**
* @brief This is the entry point in a new thread.
*
* @details
* This method, that is the entry point in the new thread and calls
* taskFunctionality of the child class. Needs a valid pointer to the
* derived class.
*
* The void* returnvalue is not used yet but could be used to return
* arbitrary data.
*/
static void* taskEntryPoint(void* arg);
FixedSlotSequence pst;
bool started;
};
#endif /* FRAMEWORK_OSAL_LINUX_FIXEDTIMESLOTTASK_H_ */

View File

@ -1,14 +1,14 @@
#include "../../osal/InternalErrorCodes.h"
ReturnValue_t InternalErrorCodes::translate(uint8_t code) {
//TODO This class can be removed
return HasReturnvaluesIF::RETURN_FAILED;
}
InternalErrorCodes::InternalErrorCodes() {
}
InternalErrorCodes::~InternalErrorCodes() {
}
#include "../../osal/InternalErrorCodes.h"
ReturnValue_t InternalErrorCodes::translate(uint8_t code) {
//TODO This class can be removed
return HasReturnvaluesIF::RETURN_FAILED;
}
InternalErrorCodes::InternalErrorCodes() {
}
InternalErrorCodes::~InternalErrorCodes() {
}

View File

@ -1,369 +1,369 @@
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../osal/linux/MessageQueue.h"
#include <fstream>
#include <fcntl.h> /* For O_* constants */
#include <sys/stat.h> /* For mode constants */
#include <cstring>
#include <errno.h>
MessageQueue::MessageQueue(uint32_t messageDepth, size_t maxMessageSize):
id(MessageQueueIF::NO_QUEUE),lastPartner(MessageQueueIF::NO_QUEUE),
defaultDestination(MessageQueueIF::NO_QUEUE),
maxMessageSize(maxMessageSize) {
//debug << "MessageQueue::MessageQueue: Creating a queue" << std::endl;
mq_attr attributes;
this->id = 0;
//Set attributes
attributes.mq_curmsgs = 0;
attributes.mq_maxmsg = messageDepth;
attributes.mq_msgsize = maxMessageSize;
attributes.mq_flags = 0; //Flags are ignored on Linux during mq_open
//Set the name of the queue. The slash is mandatory!
sprintf(name, "/FSFW_MQ%u\n", queueCounter++);
// Create a nonblocking queue if the name is available (the queue is read
// and writable for the owner as well as the group)
int oflag = O_NONBLOCK | O_RDWR | O_CREAT | O_EXCL;
mode_t mode = S_IWUSR | S_IREAD | S_IWGRP | S_IRGRP | S_IROTH | S_IWOTH;
mqd_t tempId = mq_open(name, oflag, mode, &attributes);
if (tempId == -1) {
handleError(&attributes, messageDepth);
}
else {
//Successful mq_open call
this->id = tempId;
}
}
MessageQueue::~MessageQueue() {
int status = mq_close(this->id);
if(status != 0){
sif::error << "MessageQueue::Destructor: mq_close Failed with status: "
<< strerror(errno) <<std::endl;
}
status = mq_unlink(name);
if(status != 0){
sif::error << "MessageQueue::Destructor: mq_unlink Failed with status: "
<< strerror(errno) << std::endl;
}
}
ReturnValue_t MessageQueue::handleError(mq_attr* attributes,
uint32_t messageDepth) {
switch(errno) {
case(EINVAL): {
sif::error << "MessageQueue::MessageQueue: Invalid name or attributes"
" for message size" << std::endl;
size_t defaultMqMaxMsg = 0;
// Not POSIX conformant, but should work for all UNIX systems.
// Just an additional helpful printout :-)
if(std::ifstream("/proc/sys/fs/mqueue/msg_max",std::ios::in) >>
defaultMqMaxMsg and defaultMqMaxMsg < messageDepth) {
/*
See: https://www.man7.org/linux/man-pages/man3/mq_open.3.html
This happens if the msg_max value is not large enough
It is ignored if the executable is run in privileged mode.
Run the unlockRealtime script or grant the mode manually by using:
sudo setcap 'CAP_SYS_RESOURCE=+ep' <pathToBinary>
Persistent solution for session:
echo <newMsgMax> | sudo tee /proc/sys/fs/mqueue/msg_max
Permanent solution:
sudo nano /etc/sysctl.conf
Append at end: fs/mqueue/msg_max = <newMsgMaxLen>
Apply changes with: sudo sysctl -p
*/
sif::error << "MessageQueue::MessageQueue: Default MQ size "
<< defaultMqMaxMsg << " is too small for requested size "
<< messageDepth << std::endl;
sif::error << "This error can be fixed by setting the maximum "
"allowed message size higher!" << std::endl;
}
break;
}
case(EEXIST): {
// An error occured during open
// We need to distinguish if it is caused by an already created queue
//There's another queue with the same name
//We unlink the other queue
int status = mq_unlink(name);
if (status != 0) {
sif::error << "mq_unlink Failed with status: " << strerror(errno)
<< std::endl;
}
else {
// Successful unlinking, try to open again
mqd_t tempId = mq_open(name,
O_NONBLOCK | O_RDWR | O_CREAT | O_EXCL,
S_IWUSR | S_IREAD | S_IWGRP | S_IRGRP, attributes);
if (tempId != -1) {
//Successful mq_open
this->id = tempId;
return HasReturnvaluesIF::RETURN_OK;
}
}
break;
}
default:
// Failed either the first time or the second time
sif::error << "MessageQueue::MessageQueue: Creating Queue " << std::hex
<< name << std::dec << " failed with status: "
<< strerror(errno) << std::endl;
}
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, bool ignoreFault) {
return sendMessageFrom(sendTo, message, this->getId(), false);
}
ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) {
return sendToDefaultFrom(message, this->getId());
}
ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) {
if (this->lastPartner != 0) {
return sendMessageFrom(this->lastPartner, message, this->getId());
} else {
return NO_REPLY_PARTNER;
}
}
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message,
MessageQueueId_t* receivedFrom) {
ReturnValue_t status = this->receiveMessage(message);
*receivedFrom = this->lastPartner;
return status;
}
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
if(message == nullptr) {
sif::error << "MessageQueue::receiveMessage: Message is "
"nullptr!" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
if(message->getMaximumMessageSize() < maxMessageSize) {
sif::error << "MessageQueue::receiveMessage: Message size "
<< message->getMaximumMessageSize()
<< " too small to receive data!" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
unsigned int messagePriority = 0;
int status = mq_receive(id,reinterpret_cast<char*>(message->getBuffer()),
message->getMaximumMessageSize(),&messagePriority);
if (status > 0) {
this->lastPartner = message->getSender();
//Check size of incoming message.
if (message->getMessageSize() < message->getMinimumMessageSize()) {
return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_OK;
}else if(status==0){
//Success but no message received
return MessageQueueIF::EMPTY;
} else {
//No message was received. Keep lastPartner anyway, I might send
//something later. But still, delete packet content.
memset(message->getData(), 0, message->getMaximumMessageSize());
switch(errno){
case EAGAIN:
//O_NONBLOCK or MQ_NONBLOCK was set and there are no messages
//currently on the specified queue.
return MessageQueueIF::EMPTY;
case EBADF:
//mqdes doesn't represent a valid queue open for reading.
sif::error << "MessageQueue::receive: configuration error "
<< strerror(errno) << std::endl;
/*NO BREAK*/
case EINVAL:
/*
* This value indicates one of the following:
* - The pointer to the buffer for storing the received message,
* msg_ptr, is NULL.
* - The number of bytes requested, msg_len is less than zero.
* - msg_len is anything other than the mq_msgsize of the specified
* queue, and the QNX extended option MQ_READBUF_DYNAMIC hasn't
* been set in the queue's mq_flags.
*/
sif::error << "MessageQueue::receive: configuration error "
<< strerror(errno) << std::endl;
/*NO BREAK*/
case EMSGSIZE:
/*
* This value indicates one of the following:
* - the QNX extended option MQ_READBUF_DYNAMIC hasn't been set,
* and the given msg_len is shorter than the mq_msgsize for
* the given queue.
* - the extended option MQ_READBUF_DYNAMIC has been set, but the
* given msg_len is too short for the message that would have
* been received.
*/
sif::error << "MessageQueue::receive: configuration error "
<< strerror(errno) << std::endl;
/*NO BREAK*/
case EINTR:
//The operation was interrupted by a signal.
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
}
MessageQueueId_t MessageQueue::getLastPartner() const {
return this->lastPartner;
}
ReturnValue_t MessageQueue::flush(uint32_t* count) {
mq_attr attrib;
int status = mq_getattr(id,&attrib);
if(status != 0){
switch(errno){
case EBADF:
//mqdes doesn't represent a valid message queue.
sif::error << "MessageQueue::flush configuration error, "
"called flush with an invalid queue ID" << std::endl;
/*NO BREAK*/
case EINVAL:
//mq_attr is NULL
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
*count = attrib.mq_curmsgs;
attrib.mq_curmsgs = 0;
status = mq_setattr(id,&attrib,NULL);
if(status != 0){
switch(errno){
case EBADF:
//mqdes doesn't represent a valid message queue.
sif::error << "MessageQueue::flush configuration error, "
"called flush with an invalid queue ID" << std::endl;
/*NO BREAK*/
case EINVAL:
/*
* This value indicates one of the following:
* - mq_attr is NULL.
* - MQ_MULT_NOTIFY had been set for this queue, and the given
* mq_flags includes a 0 in the MQ_MULT_NOTIFY bit. Once
* MQ_MULT_NOTIFY has been turned on, it may never be turned off.
*/
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
return HasReturnvaluesIF::RETURN_OK;
}
MessageQueueId_t MessageQueue::getId() const {
return this->id;
}
void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) {
this->defaultDestination = defaultDestination;
}
ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message,
MessageQueueId_t sentFrom, bool ignoreFault) {
return sendMessageFrom(defaultDestination, message, sentFrom, ignoreFault);
}
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
bool ignoreFault) {
return sendMessageFromMessageQueue(sendTo,message, sentFrom,ignoreFault);
}
MessageQueueId_t MessageQueue::getDefaultDestination() const {
return this->defaultDestination;
}
bool MessageQueue::isDefaultDestinationSet() const {
return (defaultDestination != NO_QUEUE);
}
uint16_t MessageQueue::queueCounter = 0;
ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
MessageQueueMessageIF *message, MessageQueueId_t sentFrom,
bool ignoreFault) {
if(message == nullptr) {
sif::error << "MessageQueue::sendMessageFromMessageQueue: Message is "
"nullptr!" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
message->setSender(sentFrom);
int result = mq_send(sendTo,
reinterpret_cast<const char*>(message->getBuffer()),
message->getMessageSize(),0);
//TODO: Check if we're in ISR.
if (result != 0) {
if(!ignoreFault){
InternalErrorReporterIF* internalErrorReporter =
objectManager->get<InternalErrorReporterIF>(
objects::INTERNAL_ERROR_REPORTER);
if (internalErrorReporter != NULL) {
internalErrorReporter->queueMessageNotSent();
}
}
switch(errno){
case EAGAIN:
//The O_NONBLOCK flag was set when opening the queue, or the
//MQ_NONBLOCK flag was set in its attributes, and the
//specified queue is full.
return MessageQueueIF::FULL;
case EBADF: {
//mq_des doesn't represent a valid message queue descriptor,
//or mq_des wasn't opened for writing.
sif::error << "MessageQueue::sendMessage: Configuration error, MQ"
<< " destination invalid." << std::endl;
sif::error << strerror(errno) << " in "
<<"mq_send to: " << sendTo << " sent from "
<< sentFrom << std::endl;
return DESTINVATION_INVALID;
}
case EINTR:
//The call was interrupted by a signal.
case EINVAL:
/*
* This value indicates one of the following:
* - msg_ptr is NULL.
* - msg_len is negative.
* - msg_prio is greater than MQ_PRIO_MAX.
* - msg_prio is less than 0.
* - MQ_PRIO_RESTRICT is set in the mq_attr of mq_des, and
* msg_prio is greater than the priority of the calling process.
*/
sif::error << "MessageQueue::sendMessage: Configuration error "
<< strerror(errno) << " in mq_send" << std::endl;
/*NO BREAK*/
case EMSGSIZE:
// The msg_len is greater than the msgsize associated with
//the specified queue.
sif::error << "MessageQueue::sendMessage: Size error [" <<
strerror(errno) << "] in mq_send" << std::endl;
/*NO BREAK*/
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
return HasReturnvaluesIF::RETURN_OK;
}
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../osal/linux/MessageQueue.h"
#include <fstream>
#include <fcntl.h> /* For O_* constants */
#include <sys/stat.h> /* For mode constants */
#include <cstring>
#include <errno.h>
MessageQueue::MessageQueue(uint32_t messageDepth, size_t maxMessageSize):
id(MessageQueueIF::NO_QUEUE),lastPartner(MessageQueueIF::NO_QUEUE),
defaultDestination(MessageQueueIF::NO_QUEUE),
maxMessageSize(maxMessageSize) {
//debug << "MessageQueue::MessageQueue: Creating a queue" << std::endl;
mq_attr attributes;
this->id = 0;
//Set attributes
attributes.mq_curmsgs = 0;
attributes.mq_maxmsg = messageDepth;
attributes.mq_msgsize = maxMessageSize;
attributes.mq_flags = 0; //Flags are ignored on Linux during mq_open
//Set the name of the queue. The slash is mandatory!
sprintf(name, "/FSFW_MQ%u\n", queueCounter++);
// Create a nonblocking queue if the name is available (the queue is read
// and writable for the owner as well as the group)
int oflag = O_NONBLOCK | O_RDWR | O_CREAT | O_EXCL;
mode_t mode = S_IWUSR | S_IREAD | S_IWGRP | S_IRGRP | S_IROTH | S_IWOTH;
mqd_t tempId = mq_open(name, oflag, mode, &attributes);
if (tempId == -1) {
handleError(&attributes, messageDepth);
}
else {
//Successful mq_open call
this->id = tempId;
}
}
MessageQueue::~MessageQueue() {
int status = mq_close(this->id);
if(status != 0){
sif::error << "MessageQueue::Destructor: mq_close Failed with status: "
<< strerror(errno) <<std::endl;
}
status = mq_unlink(name);
if(status != 0){
sif::error << "MessageQueue::Destructor: mq_unlink Failed with status: "
<< strerror(errno) << std::endl;
}
}
ReturnValue_t MessageQueue::handleError(mq_attr* attributes,
uint32_t messageDepth) {
switch(errno) {
case(EINVAL): {
sif::error << "MessageQueue::MessageQueue: Invalid name or attributes"
" for message size" << std::endl;
size_t defaultMqMaxMsg = 0;
// Not POSIX conformant, but should work for all UNIX systems.
// Just an additional helpful printout :-)
if(std::ifstream("/proc/sys/fs/mqueue/msg_max",std::ios::in) >>
defaultMqMaxMsg and defaultMqMaxMsg < messageDepth) {
/*
See: https://www.man7.org/linux/man-pages/man3/mq_open.3.html
This happens if the msg_max value is not large enough
It is ignored if the executable is run in privileged mode.
Run the unlockRealtime script or grant the mode manually by using:
sudo setcap 'CAP_SYS_RESOURCE=+ep' <pathToBinary>
Persistent solution for session:
echo <newMsgMax> | sudo tee /proc/sys/fs/mqueue/msg_max
Permanent solution:
sudo nano /etc/sysctl.conf
Append at end: fs/mqueue/msg_max = <newMsgMaxLen>
Apply changes with: sudo sysctl -p
*/
sif::error << "MessageQueue::MessageQueue: Default MQ size "
<< defaultMqMaxMsg << " is too small for requested size "
<< messageDepth << std::endl;
sif::error << "This error can be fixed by setting the maximum "
"allowed message size higher!" << std::endl;
}
break;
}
case(EEXIST): {
// An error occured during open
// We need to distinguish if it is caused by an already created queue
//There's another queue with the same name
//We unlink the other queue
int status = mq_unlink(name);
if (status != 0) {
sif::error << "mq_unlink Failed with status: " << strerror(errno)
<< std::endl;
}
else {
// Successful unlinking, try to open again
mqd_t tempId = mq_open(name,
O_NONBLOCK | O_RDWR | O_CREAT | O_EXCL,
S_IWUSR | S_IREAD | S_IWGRP | S_IRGRP, attributes);
if (tempId != -1) {
//Successful mq_open
this->id = tempId;
return HasReturnvaluesIF::RETURN_OK;
}
}
break;
}
default:
// Failed either the first time or the second time
sif::error << "MessageQueue::MessageQueue: Creating Queue " << std::hex
<< name << std::dec << " failed with status: "
<< strerror(errno) << std::endl;
}
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, bool ignoreFault) {
return sendMessageFrom(sendTo, message, this->getId(), false);
}
ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) {
return sendToDefaultFrom(message, this->getId());
}
ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) {
if (this->lastPartner != 0) {
return sendMessageFrom(this->lastPartner, message, this->getId());
} else {
return NO_REPLY_PARTNER;
}
}
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message,
MessageQueueId_t* receivedFrom) {
ReturnValue_t status = this->receiveMessage(message);
*receivedFrom = this->lastPartner;
return status;
}
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
if(message == nullptr) {
sif::error << "MessageQueue::receiveMessage: Message is "
"nullptr!" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
if(message->getMaximumMessageSize() < maxMessageSize) {
sif::error << "MessageQueue::receiveMessage: Message size "
<< message->getMaximumMessageSize()
<< " too small to receive data!" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
unsigned int messagePriority = 0;
int status = mq_receive(id,reinterpret_cast<char*>(message->getBuffer()),
message->getMaximumMessageSize(),&messagePriority);
if (status > 0) {
this->lastPartner = message->getSender();
//Check size of incoming message.
if (message->getMessageSize() < message->getMinimumMessageSize()) {
return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_OK;
}else if(status==0){
//Success but no message received
return MessageQueueIF::EMPTY;
} else {
//No message was received. Keep lastPartner anyway, I might send
//something later. But still, delete packet content.
memset(message->getData(), 0, message->getMaximumMessageSize());
switch(errno){
case EAGAIN:
//O_NONBLOCK or MQ_NONBLOCK was set and there are no messages
//currently on the specified queue.
return MessageQueueIF::EMPTY;
case EBADF:
//mqdes doesn't represent a valid queue open for reading.
sif::error << "MessageQueue::receive: configuration error "
<< strerror(errno) << std::endl;
/*NO BREAK*/
case EINVAL:
/*
* This value indicates one of the following:
* - The pointer to the buffer for storing the received message,
* msg_ptr, is NULL.
* - The number of bytes requested, msg_len is less than zero.
* - msg_len is anything other than the mq_msgsize of the specified
* queue, and the QNX extended option MQ_READBUF_DYNAMIC hasn't
* been set in the queue's mq_flags.
*/
sif::error << "MessageQueue::receive: configuration error "
<< strerror(errno) << std::endl;
/*NO BREAK*/
case EMSGSIZE:
/*
* This value indicates one of the following:
* - the QNX extended option MQ_READBUF_DYNAMIC hasn't been set,
* and the given msg_len is shorter than the mq_msgsize for
* the given queue.
* - the extended option MQ_READBUF_DYNAMIC has been set, but the
* given msg_len is too short for the message that would have
* been received.
*/
sif::error << "MessageQueue::receive: configuration error "
<< strerror(errno) << std::endl;
/*NO BREAK*/
case EINTR:
//The operation was interrupted by a signal.
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
}
MessageQueueId_t MessageQueue::getLastPartner() const {
return this->lastPartner;
}
ReturnValue_t MessageQueue::flush(uint32_t* count) {
mq_attr attrib;
int status = mq_getattr(id,&attrib);
if(status != 0){
switch(errno){
case EBADF:
//mqdes doesn't represent a valid message queue.
sif::error << "MessageQueue::flush configuration error, "
"called flush with an invalid queue ID" << std::endl;
/*NO BREAK*/
case EINVAL:
//mq_attr is NULL
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
*count = attrib.mq_curmsgs;
attrib.mq_curmsgs = 0;
status = mq_setattr(id,&attrib,NULL);
if(status != 0){
switch(errno){
case EBADF:
//mqdes doesn't represent a valid message queue.
sif::error << "MessageQueue::flush configuration error, "
"called flush with an invalid queue ID" << std::endl;
/*NO BREAK*/
case EINVAL:
/*
* This value indicates one of the following:
* - mq_attr is NULL.
* - MQ_MULT_NOTIFY had been set for this queue, and the given
* mq_flags includes a 0 in the MQ_MULT_NOTIFY bit. Once
* MQ_MULT_NOTIFY has been turned on, it may never be turned off.
*/
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
return HasReturnvaluesIF::RETURN_OK;
}
MessageQueueId_t MessageQueue::getId() const {
return this->id;
}
void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) {
this->defaultDestination = defaultDestination;
}
ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message,
MessageQueueId_t sentFrom, bool ignoreFault) {
return sendMessageFrom(defaultDestination, message, sentFrom, ignoreFault);
}
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
bool ignoreFault) {
return sendMessageFromMessageQueue(sendTo,message, sentFrom,ignoreFault);
}
MessageQueueId_t MessageQueue::getDefaultDestination() const {
return this->defaultDestination;
}
bool MessageQueue::isDefaultDestinationSet() const {
return (defaultDestination != NO_QUEUE);
}
uint16_t MessageQueue::queueCounter = 0;
ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
MessageQueueMessageIF *message, MessageQueueId_t sentFrom,
bool ignoreFault) {
if(message == nullptr) {
sif::error << "MessageQueue::sendMessageFromMessageQueue: Message is "
"nullptr!" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
message->setSender(sentFrom);
int result = mq_send(sendTo,
reinterpret_cast<const char*>(message->getBuffer()),
message->getMessageSize(),0);
//TODO: Check if we're in ISR.
if (result != 0) {
if(!ignoreFault){
InternalErrorReporterIF* internalErrorReporter =
objectManager->get<InternalErrorReporterIF>(
objects::INTERNAL_ERROR_REPORTER);
if (internalErrorReporter != NULL) {
internalErrorReporter->queueMessageNotSent();
}
}
switch(errno){
case EAGAIN:
//The O_NONBLOCK flag was set when opening the queue, or the
//MQ_NONBLOCK flag was set in its attributes, and the
//specified queue is full.
return MessageQueueIF::FULL;
case EBADF: {
//mq_des doesn't represent a valid message queue descriptor,
//or mq_des wasn't opened for writing.
sif::error << "MessageQueue::sendMessage: Configuration error, MQ"
<< " destination invalid." << std::endl;
sif::error << strerror(errno) << " in "
<<"mq_send to: " << sendTo << " sent from "
<< sentFrom << std::endl;
return DESTINVATION_INVALID;
}
case EINTR:
//The call was interrupted by a signal.
case EINVAL:
/*
* This value indicates one of the following:
* - msg_ptr is NULL.
* - msg_len is negative.
* - msg_prio is greater than MQ_PRIO_MAX.
* - msg_prio is less than 0.
* - MQ_PRIO_RESTRICT is set in the mq_attr of mq_des, and
* msg_prio is greater than the priority of the calling process.
*/
sif::error << "MessageQueue::sendMessage: Configuration error "
<< strerror(errno) << " in mq_send" << std::endl;
/*NO BREAK*/
case EMSGSIZE:
// The msg_len is greater than the msgsize associated with
//the specified queue.
sif::error << "MessageQueue::sendMessage: Size error [" <<
strerror(errno) << "] in mq_send" << std::endl;
/*NO BREAK*/
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -1,187 +1,187 @@
#ifndef MESSAGEQUEUE_H_
#define MESSAGEQUEUE_H_
#include "../../internalError/InternalErrorReporterIF.h"
#include "../../ipc/MessageQueueIF.h"
#include "../../ipc/MessageQueueMessage.h"
#include <mqueue.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".
*
* The creation of message queues, as well as sending and receiving messages,
* makes use of the operating system calls provided.
* @ingroup message_queue
*/
class MessageQueue : public MessageQueueIF {
friend class MessageQueueSenderIF;
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(uint32_t messageDepth = 3,
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE );
/**
* @brief The destructor deletes the formerly created message queue.
* @details This is accomplished by using the delete call provided by the operating system.
*/
virtual ~MessageQueue();
/**
* @brief This operation sends a message to the given destination.
* @details It directly uses the sendMessage call of the MessageQueueSender parent, but passes its
* queue id as "sentFrom" parameter.
* @param sendTo This parameter specifies the message queue id of the destination message queue.
* @param message A pointer to a previously created message, which is sent.
* @param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full.
*/
virtual ReturnValue_t sendMessage(MessageQueueId_t sendTo,
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.
*/
virtual 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
* 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( MessageQueueMessageIF* 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(MessageQueueMessageIF* 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(MessageQueueMessageIF* 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.
* \param sendTo This parameter specifies the message queue id to send the message to.
* \param message This is a pointer to a previously created message, which is sent.
* \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message.
* This variable is set to zero by default.
* \param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full.
*/
virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
bool ignoreFault = false );
/**
* \brief The sendToDefault method sends a queue message to the default destination.
* \details In all other aspects, it works identical to the sendMessage method.
* \param message This is a pointer to a previously created message, which is sent.
* \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message.
* This variable is set to zero by default.
*/
virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessageIF* 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;
protected:
/**
* Implementation to be called from any send Call within MessageQueue and MessageQueueSenderIF
* \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.
*/
static ReturnValue_t sendMessageFromMessageQueue(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE,
bool ignoreFault=false);
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;
/**
* The name of the message queue, stored for unlinking
*/
char name[16];
static uint16_t queueCounter;
const size_t maxMessageSize;
ReturnValue_t handleError(mq_attr* attributes, uint32_t messageDepth);
};
#endif /* MESSAGEQUEUE_H_ */
#ifndef MESSAGEQUEUE_H_
#define MESSAGEQUEUE_H_
#include "../../internalError/InternalErrorReporterIF.h"
#include "../../ipc/MessageQueueIF.h"
#include "../../ipc/MessageQueueMessage.h"
#include <mqueue.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".
*
* The creation of message queues, as well as sending and receiving messages,
* makes use of the operating system calls provided.
* @ingroup message_queue
*/
class MessageQueue : public MessageQueueIF {
friend class MessageQueueSenderIF;
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(uint32_t messageDepth = 3,
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE );
/**
* @brief The destructor deletes the formerly created message queue.
* @details This is accomplished by using the delete call provided by the operating system.
*/
virtual ~MessageQueue();
/**
* @brief This operation sends a message to the given destination.
* @details It directly uses the sendMessage call of the MessageQueueSender parent, but passes its
* queue id as "sentFrom" parameter.
* @param sendTo This parameter specifies the message queue id of the destination message queue.
* @param message A pointer to a previously created message, which is sent.
* @param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full.
*/
virtual ReturnValue_t sendMessage(MessageQueueId_t sendTo,
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.
*/
virtual 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
* 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( MessageQueueMessageIF* 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(MessageQueueMessageIF* 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(MessageQueueMessageIF* 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.
* \param sendTo This parameter specifies the message queue id to send the message to.
* \param message This is a pointer to a previously created message, which is sent.
* \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message.
* This variable is set to zero by default.
* \param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full.
*/
virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
bool ignoreFault = false );
/**
* \brief The sendToDefault method sends a queue message to the default destination.
* \details In all other aspects, it works identical to the sendMessage method.
* \param message This is a pointer to a previously created message, which is sent.
* \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message.
* This variable is set to zero by default.
*/
virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessageIF* 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;
protected:
/**
* Implementation to be called from any send Call within MessageQueue and MessageQueueSenderIF
* \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.
*/
static ReturnValue_t sendMessageFromMessageQueue(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE,
bool ignoreFault=false);
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;
/**
* The name of the message queue, stored for unlinking
*/
char name[16];
static uint16_t queueCounter;
const size_t maxMessageSize;
ReturnValue_t handleError(mq_attr* attributes, uint32_t messageDepth);
};
#endif /* MESSAGEQUEUE_H_ */

View File

@ -1,111 +1,111 @@
#include "../../osal/linux/Mutex.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../timemanager/Clock.h"
uint8_t Mutex::count = 0;
#include <cstring>
#include <errno.h>
Mutex::Mutex() {
pthread_mutexattr_t mutexAttr;
int status = pthread_mutexattr_init(&mutexAttr);
if (status != 0) {
sif::error << "Mutex: Attribute init failed with: " << strerror(status) << std::endl;
}
status = pthread_mutexattr_setprotocol(&mutexAttr, PTHREAD_PRIO_INHERIT);
if (status != 0) {
sif::error << "Mutex: Attribute set PRIO_INHERIT failed with: " << strerror(status)
<< std::endl;
}
status = pthread_mutex_init(&mutex, &mutexAttr);
if (status != 0) {
sif::error << "Mutex: creation with name, id " << mutex.__data.__count
<< ", " << " failed with " << strerror(status) << std::endl;
}
// After a mutex attributes object has been used to initialize one or more
// mutexes, any function affecting the attributes object
// (including destruction) shall not affect any previously initialized mutexes.
status = pthread_mutexattr_destroy(&mutexAttr);
if (status != 0) {
sif::error << "Mutex: Attribute destroy failed with " << strerror(status) << std::endl;
}
}
Mutex::~Mutex() {
//No Status check yet
pthread_mutex_destroy(&mutex);
}
ReturnValue_t Mutex::lockMutex(TimeoutType timeoutType, uint32_t timeoutMs) {
int status = 0;
if(timeoutType == TimeoutType::POLLING) {
status = pthread_mutex_trylock(&mutex);
}
else if (timeoutType == TimeoutType::WAITING) {
timespec timeOut;
clock_gettime(CLOCK_REALTIME, &timeOut);
uint64_t nseconds = timeOut.tv_sec * 1000000000 + timeOut.tv_nsec;
nseconds += timeoutMs * 1000000;
timeOut.tv_sec = nseconds / 1000000000;
timeOut.tv_nsec = nseconds - timeOut.tv_sec * 1000000000;
status = pthread_mutex_timedlock(&mutex, &timeOut);
}
else if(timeoutType == TimeoutType::BLOCKING) {
status = pthread_mutex_lock(&mutex);
}
switch (status) {
case EINVAL:
// The mutex was created with the protocol attribute having the value
// PTHREAD_PRIO_PROTECT and the calling thread's priority is higher
// than the mutex's current priority ceiling.
return WRONG_ATTRIBUTE_SETTING;
// The process or thread would have blocked, and the abs_timeout
// parameter specified a nanoseconds field value less than zero or
// greater than or equal to 1000 million.
// The value specified by mutex does not refer to an initialized mutex object.
//return MUTEX_NOT_FOUND;
case EBUSY:
// The mutex could not be acquired because it was already locked.
return MUTEX_ALREADY_LOCKED;
case ETIMEDOUT:
// The mutex could not be locked before the specified timeout expired.
return MUTEX_TIMEOUT;
case EAGAIN:
// The mutex could not be acquired because the maximum number of
// recursive locks for mutex has been exceeded.
return MUTEX_MAX_LOCKS;
case EDEADLK:
// A deadlock condition was detected or the current thread
// already owns the mutex.
return CURR_THREAD_ALREADY_OWNS_MUTEX;
case 0:
//Success
return HasReturnvaluesIF::RETURN_OK;
default:
return HasReturnvaluesIF::RETURN_FAILED;
};
}
ReturnValue_t Mutex::unlockMutex() {
int status = pthread_mutex_unlock(&mutex);
switch (status) {
case EINVAL:
//The value specified by mutex does not refer to an initialized mutex object.
return MUTEX_NOT_FOUND;
case EAGAIN:
//The mutex could not be acquired because the maximum number of recursive locks for mutex has been exceeded.
return MUTEX_MAX_LOCKS;
case EPERM:
//The current thread does not own the mutex.
return CURR_THREAD_DOES_NOT_OWN_MUTEX;
case 0:
//Success
return HasReturnvaluesIF::RETURN_OK;
default:
return HasReturnvaluesIF::RETURN_FAILED;
};
}
#include "../../osal/linux/Mutex.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../timemanager/Clock.h"
uint8_t Mutex::count = 0;
#include <cstring>
#include <errno.h>
Mutex::Mutex() {
pthread_mutexattr_t mutexAttr;
int status = pthread_mutexattr_init(&mutexAttr);
if (status != 0) {
sif::error << "Mutex: Attribute init failed with: " << strerror(status) << std::endl;
}
status = pthread_mutexattr_setprotocol(&mutexAttr, PTHREAD_PRIO_INHERIT);
if (status != 0) {
sif::error << "Mutex: Attribute set PRIO_INHERIT failed with: " << strerror(status)
<< std::endl;
}
status = pthread_mutex_init(&mutex, &mutexAttr);
if (status != 0) {
sif::error << "Mutex: creation with name, id " << mutex.__data.__count
<< ", " << " failed with " << strerror(status) << std::endl;
}
// After a mutex attributes object has been used to initialize one or more
// mutexes, any function affecting the attributes object
// (including destruction) shall not affect any previously initialized mutexes.
status = pthread_mutexattr_destroy(&mutexAttr);
if (status != 0) {
sif::error << "Mutex: Attribute destroy failed with " << strerror(status) << std::endl;
}
}
Mutex::~Mutex() {
//No Status check yet
pthread_mutex_destroy(&mutex);
}
ReturnValue_t Mutex::lockMutex(TimeoutType timeoutType, uint32_t timeoutMs) {
int status = 0;
if(timeoutType == TimeoutType::POLLING) {
status = pthread_mutex_trylock(&mutex);
}
else if (timeoutType == TimeoutType::WAITING) {
timespec timeOut;
clock_gettime(CLOCK_REALTIME, &timeOut);
uint64_t nseconds = timeOut.tv_sec * 1000000000 + timeOut.tv_nsec;
nseconds += timeoutMs * 1000000;
timeOut.tv_sec = nseconds / 1000000000;
timeOut.tv_nsec = nseconds - timeOut.tv_sec * 1000000000;
status = pthread_mutex_timedlock(&mutex, &timeOut);
}
else if(timeoutType == TimeoutType::BLOCKING) {
status = pthread_mutex_lock(&mutex);
}
switch (status) {
case EINVAL:
// The mutex was created with the protocol attribute having the value
// PTHREAD_PRIO_PROTECT and the calling thread's priority is higher
// than the mutex's current priority ceiling.
return WRONG_ATTRIBUTE_SETTING;
// The process or thread would have blocked, and the abs_timeout
// parameter specified a nanoseconds field value less than zero or
// greater than or equal to 1000 million.
// The value specified by mutex does not refer to an initialized mutex object.
//return MUTEX_NOT_FOUND;
case EBUSY:
// The mutex could not be acquired because it was already locked.
return MUTEX_ALREADY_LOCKED;
case ETIMEDOUT:
// The mutex could not be locked before the specified timeout expired.
return MUTEX_TIMEOUT;
case EAGAIN:
// The mutex could not be acquired because the maximum number of
// recursive locks for mutex has been exceeded.
return MUTEX_MAX_LOCKS;
case EDEADLK:
// A deadlock condition was detected or the current thread
// already owns the mutex.
return CURR_THREAD_ALREADY_OWNS_MUTEX;
case 0:
//Success
return HasReturnvaluesIF::RETURN_OK;
default:
return HasReturnvaluesIF::RETURN_FAILED;
};
}
ReturnValue_t Mutex::unlockMutex() {
int status = pthread_mutex_unlock(&mutex);
switch (status) {
case EINVAL:
//The value specified by mutex does not refer to an initialized mutex object.
return MUTEX_NOT_FOUND;
case EAGAIN:
//The mutex could not be acquired because the maximum number of recursive locks for mutex has been exceeded.
return MUTEX_MAX_LOCKS;
case EPERM:
//The current thread does not own the mutex.
return CURR_THREAD_DOES_NOT_OWN_MUTEX;
case 0:
//Success
return HasReturnvaluesIF::RETURN_OK;
default:
return HasReturnvaluesIF::RETURN_FAILED;
};
}

View File

@ -1,22 +1,22 @@
#ifndef OS_LINUX_MUTEX_H_
#define OS_LINUX_MUTEX_H_
#include "../../ipc/MutexIF.h"
extern "C" {
#include <pthread.h>
}
class Mutex : public MutexIF {
public:
Mutex();
virtual ~Mutex();
virtual ReturnValue_t lockMutex(TimeoutType timeoutType, uint32_t timeoutMs);
virtual ReturnValue_t unlockMutex();
private:
pthread_mutex_t mutex;
static uint8_t count;
};
#endif /* OS_RTEMS_MUTEX_H_ */
#ifndef OS_LINUX_MUTEX_H_
#define OS_LINUX_MUTEX_H_
#include "../../ipc/MutexIF.h"
extern "C" {
#include <pthread.h>
}
class Mutex : public MutexIF {
public:
Mutex();
virtual ~Mutex();
virtual ReturnValue_t lockMutex(TimeoutType timeoutType, uint32_t timeoutMs);
virtual ReturnValue_t unlockMutex();
private:
pthread_mutex_t mutex;
static uint8_t count;
};
#endif /* OS_RTEMS_MUTEX_H_ */

View File

@ -1,23 +1,23 @@
#include "../../ipc/MutexFactory.h"
#include "../../osal/linux/Mutex.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;
}
#include "../../ipc/MutexFactory.h"
#include "../../osal/linux/Mutex.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;
}

View File

@ -1,83 +1,83 @@
#include "../../tasks/ExecutableObjectIF.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../osal/linux/PeriodicPosixTask.h"
#include <errno.h>
PeriodicPosixTask::PeriodicPosixTask(const char* name_, int priority_,
size_t stackSize_, uint32_t period_, void(deadlineMissedFunc_)()):
PosixThread(name_, priority_, stackSize_), objectList(), started(false),
periodMs(period_), deadlineMissedFunc(deadlineMissedFunc_) {
}
PeriodicPosixTask::~PeriodicPosixTask() {
//Not Implemented
}
void* PeriodicPosixTask::taskEntryPoint(void* arg) {
//The argument is re-interpreted as PollingTask.
PeriodicPosixTask *originalTask(reinterpret_cast<PeriodicPosixTask*>(arg));
//The task's functionality is called.
originalTask->taskFunctionality();
return NULL;
}
ReturnValue_t PeriodicPosixTask::addComponent(object_id_t object) {
ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>(
object);
if (newObject == nullptr) {
sif::error << "PeriodicTask::addComponent: Invalid object. Make sure"
"it implements ExecutableObjectIF" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
objectList.push_back(newObject);
newObject->setTaskIF(this);
return newObject->initializeAfterTaskCreation();
}
ReturnValue_t PeriodicPosixTask::sleepFor(uint32_t ms) {
return PosixThread::sleep((uint64_t)ms*1000000);
}
ReturnValue_t PeriodicPosixTask::startTask(void) {
started = true;
//sif::info << stackSize << std::endl;
PosixThread::createTask(&taskEntryPoint,this);
return HasReturnvaluesIF::RETURN_OK;
}
void PeriodicPosixTask::taskFunctionality(void) {
if(!started){
suspend();
}
uint64_t lastWakeTime = getCurrentMonotonicTimeMs();
//The task's "infinite" inner loop is entered.
while (1) {
for (ObjectList::iterator it = objectList.begin();
it != objectList.end(); ++it) {
(*it)->performOperation();
}
if(!PosixThread::delayUntil(&lastWakeTime,periodMs)){
char name[20] = {0};
int status = pthread_getname_np(pthread_self(),name,sizeof(name));
if(status == 0){
//sif::error << "PeriodicPosixTask " << name << ": Deadline "
// "missed." << std::endl;
}
else {
//sif::error << "PeriodicPosixTask X: Deadline missed. " <<
// status << std::endl;
}
if (this->deadlineMissedFunc != nullptr) {
this->deadlineMissedFunc();
}
}
}
}
uint32_t PeriodicPosixTask::getPeriodMs() const {
return periodMs;
}
#include "../../tasks/ExecutableObjectIF.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../osal/linux/PeriodicPosixTask.h"
#include <errno.h>
PeriodicPosixTask::PeriodicPosixTask(const char* name_, int priority_,
size_t stackSize_, uint32_t period_, void(deadlineMissedFunc_)()):
PosixThread(name_, priority_, stackSize_), objectList(), started(false),
periodMs(period_), deadlineMissedFunc(deadlineMissedFunc_) {
}
PeriodicPosixTask::~PeriodicPosixTask() {
//Not Implemented
}
void* PeriodicPosixTask::taskEntryPoint(void* arg) {
//The argument is re-interpreted as PollingTask.
PeriodicPosixTask *originalTask(reinterpret_cast<PeriodicPosixTask*>(arg));
//The task's functionality is called.
originalTask->taskFunctionality();
return NULL;
}
ReturnValue_t PeriodicPosixTask::addComponent(object_id_t object) {
ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>(
object);
if (newObject == nullptr) {
sif::error << "PeriodicTask::addComponent: Invalid object. Make sure"
"it implements ExecutableObjectIF" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
objectList.push_back(newObject);
newObject->setTaskIF(this);
return newObject->initializeAfterTaskCreation();
}
ReturnValue_t PeriodicPosixTask::sleepFor(uint32_t ms) {
return PosixThread::sleep((uint64_t)ms*1000000);
}
ReturnValue_t PeriodicPosixTask::startTask(void) {
started = true;
//sif::info << stackSize << std::endl;
PosixThread::createTask(&taskEntryPoint,this);
return HasReturnvaluesIF::RETURN_OK;
}
void PeriodicPosixTask::taskFunctionality(void) {
if(!started){
suspend();
}
uint64_t lastWakeTime = getCurrentMonotonicTimeMs();
//The task's "infinite" inner loop is entered.
while (1) {
for (ObjectList::iterator it = objectList.begin();
it != objectList.end(); ++it) {
(*it)->performOperation();
}
if(!PosixThread::delayUntil(&lastWakeTime,periodMs)){
char name[20] = {0};
int status = pthread_getname_np(pthread_self(),name,sizeof(name));
if(status == 0){
//sif::error << "PeriodicPosixTask " << name << ": Deadline "
// "missed." << std::endl;
}
else {
//sif::error << "PeriodicPosixTask X: Deadline missed. " <<
// status << std::endl;
}
if (this->deadlineMissedFunc != nullptr) {
this->deadlineMissedFunc();
}
}
}
}
uint32_t PeriodicPosixTask::getPeriodMs() const {
return periodMs;
}

View File

@ -1,90 +1,90 @@
#ifndef FRAMEWORK_OSAL_LINUX_PERIODICPOSIXTASK_H_
#define FRAMEWORK_OSAL_LINUX_PERIODICPOSIXTASK_H_
#include "../../tasks/PeriodicTaskIF.h"
#include "../../objectmanager/ObjectManagerIF.h"
#include "../../osal/linux/PosixThread.h"
#include "../../tasks/ExecutableObjectIF.h"
#include <vector>
class PeriodicPosixTask: public PosixThread, public PeriodicTaskIF {
public:
/**
* Create a generic periodic task.
* @param name_
* Name, maximum allowed size of linux is 16 chars, everything else will
* be truncated.
* @param priority_
* Real-time priority, ranges from 1 to 99 for Linux.
* See: https://man7.org/linux/man-pages/man7/sched.7.html
* @param stackSize_
* @param period_
* @param deadlineMissedFunc_
*/
PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_,
uint32_t period_, void(*deadlineMissedFunc_)());
virtual ~PeriodicPosixTask();
/**
* @brief The method to start the task.
* @details The method starts the task with the respective system call.
* Entry point is the taskEntryPoint method described below.
* The address of the task object is passed as an argument
* to the system call.
*/
ReturnValue_t startTask(void) override;
/**
* 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) override;
uint32_t getPeriodMs() const override;
ReturnValue_t sleepFor(uint32_t ms) override;
private:
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 Flag to indicate that the task was started and is allowed to run
*/
bool started;
/**
* @brief Period of the task in milliseconds
*/
uint32_t periodMs;
/**
* @brief The function containing the actual functionality of the task.
* @details The method sets and starts
* the task's period, then enters a loop that is repeated indefinitely. Within the loop, all performOperation methods of the added
* objects are called. Afterwards the task will be blocked until the next period.
* On missing the deadline, the deadlineMissedFunction is executed.
*/
virtual void taskFunctionality(void);
/**
* @brief This is the entry point in a new thread.
*
* @details This method, that is the entry point in the new thread and calls taskFunctionality of the child class.
* Needs a valid pointer to the derived class.
*/
static void* taskEntryPoint(void* arg);
/**
* @brief The pointer to the deadline-missed function.
* @details This pointer stores the function that is executed if the task's deadline is missed.
* So, each may react individually on a timing failure. The pointer may be NULL,
* then nothing happens on missing the deadline. The deadline is equal to the next execution
* of the periodic task.
*/
void (*deadlineMissedFunc)();
};
#endif /* FRAMEWORK_OSAL_LINUX_PERIODICPOSIXTASK_H_ */
#ifndef FRAMEWORK_OSAL_LINUX_PERIODICPOSIXTASK_H_
#define FRAMEWORK_OSAL_LINUX_PERIODICPOSIXTASK_H_
#include "../../tasks/PeriodicTaskIF.h"
#include "../../objectmanager/ObjectManagerIF.h"
#include "../../osal/linux/PosixThread.h"
#include "../../tasks/ExecutableObjectIF.h"
#include <vector>
class PeriodicPosixTask: public PosixThread, public PeriodicTaskIF {
public:
/**
* Create a generic periodic task.
* @param name_
* Name, maximum allowed size of linux is 16 chars, everything else will
* be truncated.
* @param priority_
* Real-time priority, ranges from 1 to 99 for Linux.
* See: https://man7.org/linux/man-pages/man7/sched.7.html
* @param stackSize_
* @param period_
* @param deadlineMissedFunc_
*/
PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_,
uint32_t period_, void(*deadlineMissedFunc_)());
virtual ~PeriodicPosixTask();
/**
* @brief The method to start the task.
* @details The method starts the task with the respective system call.
* Entry point is the taskEntryPoint method described below.
* The address of the task object is passed as an argument
* to the system call.
*/
ReturnValue_t startTask(void) override;
/**
* 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) override;
uint32_t getPeriodMs() const override;
ReturnValue_t sleepFor(uint32_t ms) override;
private:
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 Flag to indicate that the task was started and is allowed to run
*/
bool started;
/**
* @brief Period of the task in milliseconds
*/
uint32_t periodMs;
/**
* @brief The function containing the actual functionality of the task.
* @details The method sets and starts
* the task's period, then enters a loop that is repeated indefinitely. Within the loop, all performOperation methods of the added
* objects are called. Afterwards the task will be blocked until the next period.
* On missing the deadline, the deadlineMissedFunction is executed.
*/
virtual void taskFunctionality(void);
/**
* @brief This is the entry point in a new thread.
*
* @details This method, that is the entry point in the new thread and calls taskFunctionality of the child class.
* Needs a valid pointer to the derived class.
*/
static void* taskEntryPoint(void* arg);
/**
* @brief The pointer to the deadline-missed function.
* @details This pointer stores the function that is executed if the task's deadline is missed.
* So, each may react individually on a timing failure. The pointer may be NULL,
* then nothing happens on missing the deadline. The deadline is equal to the next execution
* of the periodic task.
*/
void (*deadlineMissedFunc)();
};
#endif /* FRAMEWORK_OSAL_LINUX_PERIODICPOSIXTASK_H_ */

View File

@ -1,217 +1,217 @@
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../osal/linux/PosixThread.h"
#include <cstring>
#include <errno.h>
PosixThread::PosixThread(const char* name_, int priority_, size_t stackSize_):
thread(0),priority(priority_),stackSize(stackSize_) {
name[0] = '\0';
std::strncat(name, name_, PTHREAD_MAX_NAMELEN - 1);
}
PosixThread::~PosixThread() {
//No deletion and no free of Stack Pointer
}
ReturnValue_t PosixThread::sleep(uint64_t ns) {
//TODO sleep might be better with timer instead of sleep()
timespec time;
time.tv_sec = ns/1000000000;
time.tv_nsec = ns - time.tv_sec*1e9;
//Remaining Time is not set here
int status = nanosleep(&time,NULL);
if(status != 0){
switch(errno){
case EINTR:
//The nanosleep() function was interrupted by a signal.
return HasReturnvaluesIF::RETURN_FAILED;
case EINVAL:
//The rqtp argument specified a nanosecond value less than zero or
// greater than or equal to 1000 million.
return HasReturnvaluesIF::RETURN_FAILED;
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
return HasReturnvaluesIF::RETURN_OK;
}
void PosixThread::suspend() {
//Wait for SIGUSR1
int caughtSig = 0;
sigset_t waitSignal;
sigemptyset(&waitSignal);
sigaddset(&waitSignal, SIGUSR1);
sigwait(&waitSignal, &caughtSig);
if (caughtSig != SIGUSR1) {
sif::error << "FixedTimeslotTask: Unknown Signal received: " <<
caughtSig << std::endl;
}
}
void PosixThread::resume(){
/* Signal the thread to start. Makes sense to call kill to start or? ;)
*
* According to Posix raise(signal) will call pthread_kill(pthread_self(), sig),
* but as the call must be done from the thread itsself this is not possible here
*/
pthread_kill(thread,SIGUSR1);
}
bool PosixThread::delayUntil(uint64_t* const prevoiusWakeTime_ms,
const uint64_t delayTime_ms) {
uint64_t nextTimeToWake_ms;
bool shouldDelay = false;
//Get current Time
const uint64_t currentTime_ms = getCurrentMonotonicTimeMs();
/* Generate the tick time at which the task wants to wake. */
nextTimeToWake_ms = (*prevoiusWakeTime_ms) + delayTime_ms;
if (currentTime_ms < *prevoiusWakeTime_ms) {
/* The tick count has overflowed since this function was
lasted called. In this case the only time we should ever
actually delay is if the wake time has also overflowed,
and the wake time is greater than the tick time. When this
is the case it is as if neither time had overflowed. */
if ((nextTimeToWake_ms < *prevoiusWakeTime_ms)
&& (nextTimeToWake_ms > currentTime_ms)) {
shouldDelay = true;
}
} else {
/* The tick time has not overflowed. In this case we will
delay if either the wake time has overflowed, and/or the
tick time is less than the wake time. */
if ((nextTimeToWake_ms < *prevoiusWakeTime_ms)
|| (nextTimeToWake_ms > currentTime_ms)) {
shouldDelay = true;
}
}
/* Update the wake time ready for the next call. */
(*prevoiusWakeTime_ms) = nextTimeToWake_ms;
if (shouldDelay) {
uint64_t sleepTime = nextTimeToWake_ms - currentTime_ms;
PosixThread::sleep(sleepTime * 1000000ull);
return true;
}
//We are shifting the time in case the deadline was missed like rtems
(*prevoiusWakeTime_ms) = currentTime_ms;
return false;
}
uint64_t PosixThread::getCurrentMonotonicTimeMs(){
timespec timeNow;
clock_gettime(CLOCK_MONOTONIC_RAW, &timeNow);
uint64_t currentTime_ms = (uint64_t) timeNow.tv_sec * 1000
+ timeNow.tv_nsec / 1000000;
return currentTime_ms;
}
void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) {
//sif::debug << "PosixThread::createTask" << std::endl;
/*
* The attr argument points to a pthread_attr_t structure whose contents
are used at thread creation time to determine attributes for the new
thread; this structure is initialized using pthread_attr_init(3) and
related functions. If attr is NULL, then the thread is created with
default attributes.
*/
pthread_attr_t attributes;
int status = pthread_attr_init(&attributes);
if(status != 0){
sif::error << "Posix Thread attribute init failed with: " <<
strerror(status) << std::endl;
}
void* stackPointer;
status = posix_memalign(&stackPointer, sysconf(_SC_PAGESIZE), stackSize);
if(status != 0){
sif::error << "PosixThread::createTask: Stack init failed with: " <<
strerror(status) << std::endl;
if(errno == ENOMEM) {
uint64_t stackMb = stackSize/10e6;
sif::error << "PosixThread::createTask: Insufficient memory for"
" the requested " << stackMb << " MB" << std::endl;
}
else if(errno == EINVAL) {
sif::error << "PosixThread::createTask: Wrong alignment argument!"
<< std::endl;
}
return;
}
status = pthread_attr_setstack(&attributes, stackPointer, stackSize);
if(status != 0){
sif::error << "PosixThread::createTask: pthread_attr_setstack "
" failed with: " << strerror(status) << std::endl;
sif::error << "Make sure the specified stack size is valid and is "
"larger than the minimum allowed stack size." << std::endl;
}
status = pthread_attr_setinheritsched(&attributes, PTHREAD_EXPLICIT_SCHED);
if(status != 0){
sif::error << "Posix Thread attribute setinheritsched failed with: " <<
strerror(status) << std::endl;
}
// TODO FIFO -> This needs root privileges for the process
status = pthread_attr_setschedpolicy(&attributes,SCHED_FIFO);
if(status != 0){
sif::error << "Posix Thread attribute schedule policy failed with: " <<
strerror(status) << std::endl;
}
sched_param scheduleParams;
scheduleParams.__sched_priority = priority;
status = pthread_attr_setschedparam(&attributes, &scheduleParams);
if(status != 0){
sif::error << "Posix Thread attribute schedule params failed with: " <<
strerror(status) << std::endl;
}
//Set Signal Mask for suspend until startTask is called
sigset_t waitSignal;
sigemptyset(&waitSignal);
sigaddset(&waitSignal, SIGUSR1);
status = pthread_sigmask(SIG_BLOCK, &waitSignal, NULL);
if(status != 0){
sif::error << "Posix Thread sigmask failed failed with: " <<
strerror(status) << " errno: " << strerror(errno) << std::endl;
}
status = pthread_create(&thread,&attributes,fnc_,arg_);
if(status != 0){
sif::error << "Posix Thread create failed with: " <<
strerror(status) << std::endl;
}
status = pthread_setname_np(thread,name);
if(status != 0){
sif::error << "PosixThread::createTask: setname failed with: " <<
strerror(status) << std::endl;
if(status == ERANGE) {
sif::error << "PosixThread::createTask: Task name length longer"
" than 16 chars. Truncating.." << std::endl;
name[15] = '\0';
status = pthread_setname_np(thread,name);
if(status != 0){
sif::error << "PosixThread::createTask: Setting name"
" did not work.." << std::endl;
}
}
}
status = pthread_attr_destroy(&attributes);
if(status!=0){
sif::error << "Posix Thread attribute destroy failed with: " <<
strerror(status) << std::endl;
}
}
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../osal/linux/PosixThread.h"
#include <cstring>
#include <errno.h>
PosixThread::PosixThread(const char* name_, int priority_, size_t stackSize_):
thread(0),priority(priority_),stackSize(stackSize_) {
name[0] = '\0';
std::strncat(name, name_, PTHREAD_MAX_NAMELEN - 1);
}
PosixThread::~PosixThread() {
//No deletion and no free of Stack Pointer
}
ReturnValue_t PosixThread::sleep(uint64_t ns) {
//TODO sleep might be better with timer instead of sleep()
timespec time;
time.tv_sec = ns/1000000000;
time.tv_nsec = ns - time.tv_sec*1e9;
//Remaining Time is not set here
int status = nanosleep(&time,NULL);
if(status != 0){
switch(errno){
case EINTR:
//The nanosleep() function was interrupted by a signal.
return HasReturnvaluesIF::RETURN_FAILED;
case EINVAL:
//The rqtp argument specified a nanosecond value less than zero or
// greater than or equal to 1000 million.
return HasReturnvaluesIF::RETURN_FAILED;
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
return HasReturnvaluesIF::RETURN_OK;
}
void PosixThread::suspend() {
//Wait for SIGUSR1
int caughtSig = 0;
sigset_t waitSignal;
sigemptyset(&waitSignal);
sigaddset(&waitSignal, SIGUSR1);
sigwait(&waitSignal, &caughtSig);
if (caughtSig != SIGUSR1) {
sif::error << "FixedTimeslotTask: Unknown Signal received: " <<
caughtSig << std::endl;
}
}
void PosixThread::resume(){
/* Signal the thread to start. Makes sense to call kill to start or? ;)
*
* According to Posix raise(signal) will call pthread_kill(pthread_self(), sig),
* but as the call must be done from the thread itsself this is not possible here
*/
pthread_kill(thread,SIGUSR1);
}
bool PosixThread::delayUntil(uint64_t* const prevoiusWakeTime_ms,
const uint64_t delayTime_ms) {
uint64_t nextTimeToWake_ms;
bool shouldDelay = false;
//Get current Time
const uint64_t currentTime_ms = getCurrentMonotonicTimeMs();
/* Generate the tick time at which the task wants to wake. */
nextTimeToWake_ms = (*prevoiusWakeTime_ms) + delayTime_ms;
if (currentTime_ms < *prevoiusWakeTime_ms) {
/* The tick count has overflowed since this function was
lasted called. In this case the only time we should ever
actually delay is if the wake time has also overflowed,
and the wake time is greater than the tick time. When this
is the case it is as if neither time had overflowed. */
if ((nextTimeToWake_ms < *prevoiusWakeTime_ms)
&& (nextTimeToWake_ms > currentTime_ms)) {
shouldDelay = true;
}
} else {
/* The tick time has not overflowed. In this case we will
delay if either the wake time has overflowed, and/or the
tick time is less than the wake time. */
if ((nextTimeToWake_ms < *prevoiusWakeTime_ms)
|| (nextTimeToWake_ms > currentTime_ms)) {
shouldDelay = true;
}
}
/* Update the wake time ready for the next call. */
(*prevoiusWakeTime_ms) = nextTimeToWake_ms;
if (shouldDelay) {
uint64_t sleepTime = nextTimeToWake_ms - currentTime_ms;
PosixThread::sleep(sleepTime * 1000000ull);
return true;
}
//We are shifting the time in case the deadline was missed like rtems
(*prevoiusWakeTime_ms) = currentTime_ms;
return false;
}
uint64_t PosixThread::getCurrentMonotonicTimeMs(){
timespec timeNow;
clock_gettime(CLOCK_MONOTONIC_RAW, &timeNow);
uint64_t currentTime_ms = (uint64_t) timeNow.tv_sec * 1000
+ timeNow.tv_nsec / 1000000;
return currentTime_ms;
}
void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) {
//sif::debug << "PosixThread::createTask" << std::endl;
/*
* The attr argument points to a pthread_attr_t structure whose contents
are used at thread creation time to determine attributes for the new
thread; this structure is initialized using pthread_attr_init(3) and
related functions. If attr is NULL, then the thread is created with
default attributes.
*/
pthread_attr_t attributes;
int status = pthread_attr_init(&attributes);
if(status != 0){
sif::error << "Posix Thread attribute init failed with: " <<
strerror(status) << std::endl;
}
void* stackPointer;
status = posix_memalign(&stackPointer, sysconf(_SC_PAGESIZE), stackSize);
if(status != 0){
sif::error << "PosixThread::createTask: Stack init failed with: " <<
strerror(status) << std::endl;
if(errno == ENOMEM) {
uint64_t stackMb = stackSize/10e6;
sif::error << "PosixThread::createTask: Insufficient memory for"
" the requested " << stackMb << " MB" << std::endl;
}
else if(errno == EINVAL) {
sif::error << "PosixThread::createTask: Wrong alignment argument!"
<< std::endl;
}
return;
}
status = pthread_attr_setstack(&attributes, stackPointer, stackSize);
if(status != 0){
sif::error << "PosixThread::createTask: pthread_attr_setstack "
" failed with: " << strerror(status) << std::endl;
sif::error << "Make sure the specified stack size is valid and is "
"larger than the minimum allowed stack size." << std::endl;
}
status = pthread_attr_setinheritsched(&attributes, PTHREAD_EXPLICIT_SCHED);
if(status != 0){
sif::error << "Posix Thread attribute setinheritsched failed with: " <<
strerror(status) << std::endl;
}
// TODO FIFO -> This needs root privileges for the process
status = pthread_attr_setschedpolicy(&attributes,SCHED_FIFO);
if(status != 0){
sif::error << "Posix Thread attribute schedule policy failed with: " <<
strerror(status) << std::endl;
}
sched_param scheduleParams;
scheduleParams.__sched_priority = priority;
status = pthread_attr_setschedparam(&attributes, &scheduleParams);
if(status != 0){
sif::error << "Posix Thread attribute schedule params failed with: " <<
strerror(status) << std::endl;
}
//Set Signal Mask for suspend until startTask is called
sigset_t waitSignal;
sigemptyset(&waitSignal);
sigaddset(&waitSignal, SIGUSR1);
status = pthread_sigmask(SIG_BLOCK, &waitSignal, NULL);
if(status != 0){
sif::error << "Posix Thread sigmask failed failed with: " <<
strerror(status) << " errno: " << strerror(errno) << std::endl;
}
status = pthread_create(&thread,&attributes,fnc_,arg_);
if(status != 0){
sif::error << "Posix Thread create failed with: " <<
strerror(status) << std::endl;
}
status = pthread_setname_np(thread,name);
if(status != 0){
sif::error << "PosixThread::createTask: setname failed with: " <<
strerror(status) << std::endl;
if(status == ERANGE) {
sif::error << "PosixThread::createTask: Task name length longer"
" than 16 chars. Truncating.." << std::endl;
name[15] = '\0';
status = pthread_setname_np(thread,name);
if(status != 0){
sif::error << "PosixThread::createTask: Setting name"
" did not work.." << std::endl;
}
}
}
status = pthread_attr_destroy(&attributes);
if(status!=0){
sif::error << "Posix Thread attribute destroy failed with: " <<
strerror(status) << std::endl;
}
}

View File

@ -1,77 +1,77 @@
#ifndef FRAMEWORK_OSAL_LINUX_POSIXTHREAD_H_
#define FRAMEWORK_OSAL_LINUX_POSIXTHREAD_H_
#include "../../returnvalues/HasReturnvaluesIF.h"
#include <pthread.h>
#include <signal.h>
#include <cstdlib>
#include <unistd.h>
class PosixThread {
public:
static constexpr uint8_t PTHREAD_MAX_NAMELEN = 16;
PosixThread(const char* name_, int priority_, size_t stackSize_);
virtual ~PosixThread();
/**
* Set the Thread to sleep state
* @param ns Nanosecond sleep time
* @return Returns Failed if sleep fails
*/
static ReturnValue_t sleep(uint64_t ns);
/**
* @brief Function to suspend the task until SIGUSR1 was received
*
* @details Will be called in the beginning to suspend execution until startTask() is called explicitly.
*/
void suspend();
/**
* @brief Function to allow a other thread to start the thread again from suspend state
*
* @details Restarts the Thread after suspend call
*/
void resume();
/**
* Delay function similar to FreeRtos delayUntil function
*
* @param prevoiusWakeTime_ms Needs the previous wake time and returns the next wakeup time
* @param delayTime_ms Time period to delay
*
* @return False If deadline was missed; True if task was delayed
*/
static bool delayUntil(uint64_t* const prevoiusWakeTime_ms, const uint64_t delayTime_ms);
/**
* Returns the current time in milliseconds from CLOCK_MONOTONIC
*
* @return current time in milliseconds from CLOCK_MONOTONIC
*/
static uint64_t getCurrentMonotonicTimeMs();
protected:
pthread_t thread;
/**
* @brief Function that has to be called by derived class because the
* derived class pointer has to be valid as argument.
* @details
* This function creates a pthread with the given parameters. As the
* function requires a pointer to the derived object it has to be called
* after the this pointer of the derived object is valid.
* Sets the taskEntryPoint as function to be called by new a thread.
* @param fnc_ Function which will be executed by the thread.
* @param arg_
* argument of the taskEntryPoint function, needs to be this pointer
* of derived class
*/
void createTask(void* (*fnc_)(void*),void* arg_);
private:
char name[PTHREAD_MAX_NAMELEN];
int priority;
size_t stackSize = 0;
};
#endif /* FRAMEWORK_OSAL_LINUX_POSIXTHREAD_H_ */
#ifndef FRAMEWORK_OSAL_LINUX_POSIXTHREAD_H_
#define FRAMEWORK_OSAL_LINUX_POSIXTHREAD_H_
#include "../../returnvalues/HasReturnvaluesIF.h"
#include <pthread.h>
#include <signal.h>
#include <cstdlib>
#include <unistd.h>
class PosixThread {
public:
static constexpr uint8_t PTHREAD_MAX_NAMELEN = 16;
PosixThread(const char* name_, int priority_, size_t stackSize_);
virtual ~PosixThread();
/**
* Set the Thread to sleep state
* @param ns Nanosecond sleep time
* @return Returns Failed if sleep fails
*/
static ReturnValue_t sleep(uint64_t ns);
/**
* @brief Function to suspend the task until SIGUSR1 was received
*
* @details Will be called in the beginning to suspend execution until startTask() is called explicitly.
*/
void suspend();
/**
* @brief Function to allow a other thread to start the thread again from suspend state
*
* @details Restarts the Thread after suspend call
*/
void resume();
/**
* Delay function similar to FreeRtos delayUntil function
*
* @param prevoiusWakeTime_ms Needs the previous wake time and returns the next wakeup time
* @param delayTime_ms Time period to delay
*
* @return False If deadline was missed; True if task was delayed
*/
static bool delayUntil(uint64_t* const prevoiusWakeTime_ms, const uint64_t delayTime_ms);
/**
* Returns the current time in milliseconds from CLOCK_MONOTONIC
*
* @return current time in milliseconds from CLOCK_MONOTONIC
*/
static uint64_t getCurrentMonotonicTimeMs();
protected:
pthread_t thread;
/**
* @brief Function that has to be called by derived class because the
* derived class pointer has to be valid as argument.
* @details
* This function creates a pthread with the given parameters. As the
* function requires a pointer to the derived object it has to be called
* after the this pointer of the derived object is valid.
* Sets the taskEntryPoint as function to be called by new a thread.
* @param fnc_ Function which will be executed by the thread.
* @param arg_
* argument of the taskEntryPoint function, needs to be this pointer
* of derived class
*/
void createTask(void* (*fnc_)(void*),void* arg_);
private:
char name[PTHREAD_MAX_NAMELEN];
int priority;
size_t stackSize = 0;
};
#endif /* FRAMEWORK_OSAL_LINUX_POSIXTHREAD_H_ */

View File

@ -1,38 +1,38 @@
#include "../../ipc/QueueFactory.h"
#include <mqueue.h>
#include <errno.h>
#include "../../osal/linux/MessageQueue.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include <cstring>
QueueFactory* QueueFactory::factoryInstance = nullptr;
ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
bool ignoreFault) {
return MessageQueue::sendMessageFromMessageQueue(sendTo,message,
sentFrom,ignoreFault);
}
QueueFactory* QueueFactory::instance() {
if (factoryInstance == nullptr) {
factoryInstance = new QueueFactory;
}
return factoryInstance;
}
QueueFactory::QueueFactory() {
}
QueueFactory::~QueueFactory() {
}
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth,
size_t maxMessageSize) {
return new MessageQueue(messageDepth, maxMessageSize);
}
void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) {
delete queue;
}
#include "../../ipc/QueueFactory.h"
#include <mqueue.h>
#include <errno.h>
#include "../../osal/linux/MessageQueue.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include <cstring>
QueueFactory* QueueFactory::factoryInstance = nullptr;
ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
bool ignoreFault) {
return MessageQueue::sendMessageFromMessageQueue(sendTo,message,
sentFrom,ignoreFault);
}
QueueFactory* QueueFactory::instance() {
if (factoryInstance == nullptr) {
factoryInstance = new QueueFactory;
}
return factoryInstance;
}
QueueFactory::QueueFactory() {
}
QueueFactory::~QueueFactory() {
}
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth,
size_t maxMessageSize) {
return new MessageQueue(messageDepth, maxMessageSize);
}
void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) {
delete queue;
}

View File

@ -1,33 +1,33 @@
#include "../../tasks/SemaphoreFactory.h"
#include "BinarySemaphore.h"
#include "CountingSemaphore.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr;
SemaphoreFactory::SemaphoreFactory() {
}
SemaphoreFactory::~SemaphoreFactory() {
delete factoryInstance;
}
SemaphoreFactory* SemaphoreFactory::instance() {
if (factoryInstance == nullptr){
factoryInstance = new SemaphoreFactory();
}
return SemaphoreFactory::factoryInstance;
}
SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t arguments) {
return new BinarySemaphore();
}
SemaphoreIF* SemaphoreFactory::createCountingSemaphore(const uint8_t maxCount,
uint8_t initCount, uint32_t arguments) {
return new CountingSemaphore(maxCount, initCount);
}
void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) {
delete semaphore;
}
#include "../../tasks/SemaphoreFactory.h"
#include "BinarySemaphore.h"
#include "CountingSemaphore.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr;
SemaphoreFactory::SemaphoreFactory() {
}
SemaphoreFactory::~SemaphoreFactory() {
delete factoryInstance;
}
SemaphoreFactory* SemaphoreFactory::instance() {
if (factoryInstance == nullptr){
factoryInstance = new SemaphoreFactory();
}
return SemaphoreFactory::factoryInstance;
}
SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t arguments) {
return new BinarySemaphore();
}
SemaphoreIF* SemaphoreFactory::createCountingSemaphore(const uint8_t maxCount,
uint8_t initCount, uint32_t arguments) {
return new CountingSemaphore(maxCount, initCount);
}
void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) {
delete semaphore;
}

View File

@ -1,42 +1,42 @@
#include "../../osal/linux/FixedTimeslotTask.h"
#include "../../osal/linux/PeriodicPosixTask.h"
#include "../../tasks/TaskFactory.h"
#include "../../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(TaskName name_,
TaskPriority taskPriority_,TaskStackSize stackSize_,
TaskPeriod periodInSeconds_,
TaskDeadlineMissedFunction deadLineMissedFunction_) {
return new PeriodicPosixTask(name_, taskPriority_,stackSize_,
periodInSeconds_ * 1000, deadLineMissedFunction_);
}
FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(TaskName name_,
TaskPriority taskPriority_,TaskStackSize stackSize_,
TaskPeriod periodInSeconds_,
TaskDeadlineMissedFunction deadLineMissedFunction_) {
return new FixedTimeslotTask(name_, taskPriority_,stackSize_,
periodInSeconds_*1000);
}
ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) {
//TODO not implemented
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t TaskFactory::delayTask(uint32_t delayMs){
return PosixThread::sleep(delayMs*1000000ull);
}
TaskFactory::TaskFactory() {
}
#include "../../osal/linux/FixedTimeslotTask.h"
#include "../../osal/linux/PeriodicPosixTask.h"
#include "../../tasks/TaskFactory.h"
#include "../../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(TaskName name_,
TaskPriority taskPriority_,TaskStackSize stackSize_,
TaskPeriod periodInSeconds_,
TaskDeadlineMissedFunction deadLineMissedFunction_) {
return new PeriodicPosixTask(name_, taskPriority_,stackSize_,
periodInSeconds_ * 1000, deadLineMissedFunction_);
}
FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(TaskName name_,
TaskPriority taskPriority_,TaskStackSize stackSize_,
TaskPeriod periodInSeconds_,
TaskDeadlineMissedFunction deadLineMissedFunction_) {
return new FixedTimeslotTask(name_, taskPriority_,stackSize_,
periodInSeconds_*1000);
}
ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) {
//TODO not implemented
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t TaskFactory::delayTask(uint32_t delayMs){
return PosixThread::sleep(delayMs*1000000ull);
}
TaskFactory::TaskFactory() {
}

View File

@ -1,137 +1,137 @@
#include "../../osal/linux/TcUnixUdpPollingTask.h"
#include "../../globalfunctions/arrayprinter.h"
TcUnixUdpPollingTask::TcUnixUdpPollingTask(object_id_t objectId,
object_id_t tmtcUnixUdpBridge, size_t frameSize,
double timeoutSeconds): SystemObject(objectId),
tmtcBridgeId(tmtcUnixUdpBridge) {
if(frameSize > 0) {
this->frameSize = frameSize;
}
else {
this->frameSize = DEFAULT_MAX_FRAME_SIZE;
}
// Set up reception buffer with specified frame size.
// For now, it is assumed that only one frame is held in the buffer!
receptionBuffer.reserve(this->frameSize);
receptionBuffer.resize(this->frameSize);
if(timeoutSeconds == -1) {
receptionTimeout = DEFAULT_TIMEOUT;
}
else {
receptionTimeout = timevalOperations::toTimeval(timeoutSeconds);
}
}
TcUnixUdpPollingTask::~TcUnixUdpPollingTask() {}
ReturnValue_t TcUnixUdpPollingTask::performOperation(uint8_t opCode) {
// Poll for new UDP datagrams in permanent loop.
while(1) {
//! Sender Address is cached here.
struct sockaddr_in senderAddress;
socklen_t senderSockLen = 0;
ssize_t bytesReceived = recvfrom(serverUdpSocket,
receptionBuffer.data(), frameSize, receptionFlags,
reinterpret_cast<sockaddr*>(&senderAddress), &senderSockLen);
if(bytesReceived < 0) {
// handle error
sif::error << "TcSocketPollingTask::performOperation: Reception"
"error." << std::endl;
handleReadError();
continue;
}
// sif::debug << "TcSocketPollingTask::performOperation: " << bytesReceived
// << " bytes received" << std::endl;
ReturnValue_t result = handleSuccessfullTcRead(bytesReceived);
if(result != HasReturnvaluesIF::RETURN_FAILED) {
}
tmtcBridge->registerCommConnect();
tmtcBridge->checkAndSetClientAddress(senderAddress);
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t TcUnixUdpPollingTask::handleSuccessfullTcRead(size_t bytesRead) {
store_address_t storeId;
ReturnValue_t result = tcStore->addData(&storeId,
receptionBuffer.data(), bytesRead);
// arrayprinter::print(receptionBuffer.data(), bytesRead);
if (result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "TcSerialPollingTask::transferPusToSoftwareBus: Data "
"storage failed" << std::endl;
sif::error << "Packet size: " << bytesRead << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
TmTcMessage message(storeId);
result = MessageQueueSenderIF::sendMessage(targetTcDestination, &message);
if (result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "Serial Polling: Sending message to queue failed"
<< std::endl;
tcStore->deleteData(storeId);
}
return result;
}
ReturnValue_t TcUnixUdpPollingTask::initialize() {
tcStore = objectManager->get<StorageManagerIF>(objects::TC_STORE);
if (tcStore == nullptr) {
sif::error << "TcSerialPollingTask::initialize: TC Store uninitialized!"
<< std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
}
tmtcBridge = objectManager->get<TmTcUnixUdpBridge>(tmtcBridgeId);
if(tmtcBridge == nullptr) {
sif::error << "TcSocketPollingTask::TcSocketPollingTask: Invalid"
" TMTC bridge object!" << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
}
serverUdpSocket = tmtcBridge->serverSocket;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t TcUnixUdpPollingTask::initializeAfterTaskCreation() {
// Initialize the destination after task creation. This ensures
// that the destination will be set in the TMTC bridge.
targetTcDestination = tmtcBridge->getRequestQueue();
return HasReturnvaluesIF::RETURN_OK;
}
void TcUnixUdpPollingTask::setTimeout(double timeoutSeconds) {
timeval tval;
tval = timevalOperations::toTimeval(timeoutSeconds);
int result = setsockopt(serverUdpSocket, SOL_SOCKET, SO_RCVTIMEO,
&tval, sizeof(receptionTimeout));
if(result == -1) {
sif::error << "TcSocketPollingTask::TcSocketPollingTask: Setting "
"receive timeout failed with " << strerror(errno) << std::endl;
}
}
void TcUnixUdpPollingTask::handleReadError() {
switch(errno) {
case(EAGAIN): {
// todo: When working in timeout mode, this will occur more often
// and is not an error.
sif::error << "TcUnixUdpPollingTask::handleReadError: Timeout."
<< std::endl;
break;
}
default: {
sif::error << "TcUnixUdpPollingTask::handleReadError: "
<< strerror(errno) << std::endl;
}
}
}
#include "../../osal/linux/TcUnixUdpPollingTask.h"
#include "../../globalfunctions/arrayprinter.h"
TcUnixUdpPollingTask::TcUnixUdpPollingTask(object_id_t objectId,
object_id_t tmtcUnixUdpBridge, size_t frameSize,
double timeoutSeconds): SystemObject(objectId),
tmtcBridgeId(tmtcUnixUdpBridge) {
if(frameSize > 0) {
this->frameSize = frameSize;
}
else {
this->frameSize = DEFAULT_MAX_FRAME_SIZE;
}
// Set up reception buffer with specified frame size.
// For now, it is assumed that only one frame is held in the buffer!
receptionBuffer.reserve(this->frameSize);
receptionBuffer.resize(this->frameSize);
if(timeoutSeconds == -1) {
receptionTimeout = DEFAULT_TIMEOUT;
}
else {
receptionTimeout = timevalOperations::toTimeval(timeoutSeconds);
}
}
TcUnixUdpPollingTask::~TcUnixUdpPollingTask() {}
ReturnValue_t TcUnixUdpPollingTask::performOperation(uint8_t opCode) {
// Poll for new UDP datagrams in permanent loop.
while(1) {
//! Sender Address is cached here.
struct sockaddr_in senderAddress;
socklen_t senderSockLen = 0;
ssize_t bytesReceived = recvfrom(serverUdpSocket,
receptionBuffer.data(), frameSize, receptionFlags,
reinterpret_cast<sockaddr*>(&senderAddress), &senderSockLen);
if(bytesReceived < 0) {
// handle error
sif::error << "TcSocketPollingTask::performOperation: Reception"
"error." << std::endl;
handleReadError();
continue;
}
// sif::debug << "TcSocketPollingTask::performOperation: " << bytesReceived
// << " bytes received" << std::endl;
ReturnValue_t result = handleSuccessfullTcRead(bytesReceived);
if(result != HasReturnvaluesIF::RETURN_FAILED) {
}
tmtcBridge->registerCommConnect();
tmtcBridge->checkAndSetClientAddress(senderAddress);
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t TcUnixUdpPollingTask::handleSuccessfullTcRead(size_t bytesRead) {
store_address_t storeId;
ReturnValue_t result = tcStore->addData(&storeId,
receptionBuffer.data(), bytesRead);
// arrayprinter::print(receptionBuffer.data(), bytesRead);
if (result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "TcSerialPollingTask::transferPusToSoftwareBus: Data "
"storage failed" << std::endl;
sif::error << "Packet size: " << bytesRead << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
TmTcMessage message(storeId);
result = MessageQueueSenderIF::sendMessage(targetTcDestination, &message);
if (result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "Serial Polling: Sending message to queue failed"
<< std::endl;
tcStore->deleteData(storeId);
}
return result;
}
ReturnValue_t TcUnixUdpPollingTask::initialize() {
tcStore = objectManager->get<StorageManagerIF>(objects::TC_STORE);
if (tcStore == nullptr) {
sif::error << "TcSerialPollingTask::initialize: TC Store uninitialized!"
<< std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
}
tmtcBridge = objectManager->get<TmTcUnixUdpBridge>(tmtcBridgeId);
if(tmtcBridge == nullptr) {
sif::error << "TcSocketPollingTask::TcSocketPollingTask: Invalid"
" TMTC bridge object!" << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
}
serverUdpSocket = tmtcBridge->serverSocket;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t TcUnixUdpPollingTask::initializeAfterTaskCreation() {
// Initialize the destination after task creation. This ensures
// that the destination will be set in the TMTC bridge.
targetTcDestination = tmtcBridge->getRequestQueue();
return HasReturnvaluesIF::RETURN_OK;
}
void TcUnixUdpPollingTask::setTimeout(double timeoutSeconds) {
timeval tval;
tval = timevalOperations::toTimeval(timeoutSeconds);
int result = setsockopt(serverUdpSocket, SOL_SOCKET, SO_RCVTIMEO,
&tval, sizeof(receptionTimeout));
if(result == -1) {
sif::error << "TcSocketPollingTask::TcSocketPollingTask: Setting "
"receive timeout failed with " << strerror(errno) << std::endl;
}
}
void TcUnixUdpPollingTask::handleReadError() {
switch(errno) {
case(EAGAIN): {
// todo: When working in timeout mode, this will occur more often
// and is not an error.
sif::error << "TcUnixUdpPollingTask::handleReadError: Timeout."
<< std::endl;
break;
}
default: {
sif::error << "TcUnixUdpPollingTask::handleReadError: "
<< strerror(errno) << std::endl;
}
}
}

View File

@ -1,67 +1,67 @@
#ifndef FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_
#define FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_
#include "../../objectmanager/SystemObject.h"
#include "../../osal/linux/TmTcUnixUdpBridge.h"
#include "../../tasks/ExecutableObjectIF.h"
#include <sys/socket.h>
#include <vector>
/**
* @brief This class can be used to implement the polling of a Unix socket,
* using UDP for now.
* @details
* The task will be blocked while the specified number of bytes has not been
* received, so TC reception is handled inside a separate task.
* This class caches the IP address of the sender. It is assumed there
* is only one sender for now.
*/
class TcUnixUdpPollingTask: public SystemObject,
public ExecutableObjectIF {
friend class TmTcUnixUdpBridge;
public:
static constexpr size_t DEFAULT_MAX_FRAME_SIZE = 2048;
//! 0.5 default milliseconds timeout for now.
static constexpr timeval DEFAULT_TIMEOUT = {.tv_sec = 0, .tv_usec = 500};
TcUnixUdpPollingTask(object_id_t objectId, object_id_t tmtcUnixUdpBridge,
size_t frameSize = 0, double timeoutSeconds = -1);
virtual~ TcUnixUdpPollingTask();
/**
* Turn on optional timeout for UDP polling. In the default mode,
* the receive function will block until a packet is received.
* @param timeoutSeconds
*/
void setTimeout(double timeoutSeconds);
virtual ReturnValue_t performOperation(uint8_t opCode) override;
virtual ReturnValue_t initialize() override;
virtual ReturnValue_t initializeAfterTaskCreation() override;
protected:
StorageManagerIF* tcStore = nullptr;
private:
//! TMTC bridge is cached.
object_id_t tmtcBridgeId = objects::NO_OBJECT;
TmTcUnixUdpBridge* tmtcBridge = nullptr;
MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE;
//! Reception flags: https://linux.die.net/man/2/recvfrom.
int receptionFlags = 0;
//! Server socket, which is member of TMTC bridge and is assigned in
//! constructor
int serverUdpSocket = 0;
std::vector<uint8_t> receptionBuffer;
size_t frameSize = 0;
timeval receptionTimeout;
ReturnValue_t handleSuccessfullTcRead(size_t bytesRead);
void handleReadError();
};
#endif /* FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_ */
#ifndef FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_
#define FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_
#include "../../objectmanager/SystemObject.h"
#include "../../osal/linux/TmTcUnixUdpBridge.h"
#include "../../tasks/ExecutableObjectIF.h"
#include <sys/socket.h>
#include <vector>
/**
* @brief This class can be used to implement the polling of a Unix socket,
* using UDP for now.
* @details
* The task will be blocked while the specified number of bytes has not been
* received, so TC reception is handled inside a separate task.
* This class caches the IP address of the sender. It is assumed there
* is only one sender for now.
*/
class TcUnixUdpPollingTask: public SystemObject,
public ExecutableObjectIF {
friend class TmTcUnixUdpBridge;
public:
static constexpr size_t DEFAULT_MAX_FRAME_SIZE = 2048;
//! 0.5 default milliseconds timeout for now.
static constexpr timeval DEFAULT_TIMEOUT = {.tv_sec = 0, .tv_usec = 500};
TcUnixUdpPollingTask(object_id_t objectId, object_id_t tmtcUnixUdpBridge,
size_t frameSize = 0, double timeoutSeconds = -1);
virtual~ TcUnixUdpPollingTask();
/**
* Turn on optional timeout for UDP polling. In the default mode,
* the receive function will block until a packet is received.
* @param timeoutSeconds
*/
void setTimeout(double timeoutSeconds);
virtual ReturnValue_t performOperation(uint8_t opCode) override;
virtual ReturnValue_t initialize() override;
virtual ReturnValue_t initializeAfterTaskCreation() override;
protected:
StorageManagerIF* tcStore = nullptr;
private:
//! TMTC bridge is cached.
object_id_t tmtcBridgeId = objects::NO_OBJECT;
TmTcUnixUdpBridge* tmtcBridge = nullptr;
MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE;
//! Reception flags: https://linux.die.net/man/2/recvfrom.
int receptionFlags = 0;
//! Server socket, which is member of TMTC bridge and is assigned in
//! constructor
int serverUdpSocket = 0;
std::vector<uint8_t> receptionBuffer;
size_t frameSize = 0;
timeval receptionTimeout;
ReturnValue_t handleSuccessfullTcRead(size_t bytesRead);
void handleReadError();
};
#endif /* FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_ */

View File

@ -1,42 +1,42 @@
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include <errno.h>
#include "../../osal/linux/Timer.h"
Timer::Timer() {
sigevent sigEvent;
sigEvent.sigev_notify = SIGEV_NONE;
sigEvent.sigev_signo = 0;
sigEvent.sigev_value.sival_ptr = &timerId;
int status = timer_create(CLOCK_MONOTONIC, &sigEvent, &timerId);
if(status!=0){
sif::error << "Timer creation failed with: " << status <<
" errno: " << errno << std::endl;
}
}
Timer::~Timer() {
timer_delete(timerId);
}
int Timer::setTimer(uint32_t intervalMs) {
itimerspec timer;
timer.it_value.tv_sec = intervalMs / 1000;
timer.it_value.tv_nsec = (intervalMs * 1000000) % (1000000000);
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_nsec = 0;
return timer_settime(timerId, 0, &timer, NULL);
}
int Timer::getTimer(uint32_t* remainingTimeMs){
itimerspec timer;
timer.it_value.tv_sec = 0;
timer.it_value.tv_nsec = 0;
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_nsec = 0;
int status = timer_gettime(timerId, &timer);
*remainingTimeMs = timer.it_value.tv_sec * 1000 + timer.it_value.tv_nsec / 1000000;
return status;
}
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include <errno.h>
#include "../../osal/linux/Timer.h"
Timer::Timer() {
sigevent sigEvent;
sigEvent.sigev_notify = SIGEV_NONE;
sigEvent.sigev_signo = 0;
sigEvent.sigev_value.sival_ptr = &timerId;
int status = timer_create(CLOCK_MONOTONIC, &sigEvent, &timerId);
if(status!=0){
sif::error << "Timer creation failed with: " << status <<
" errno: " << errno << std::endl;
}
}
Timer::~Timer() {
timer_delete(timerId);
}
int Timer::setTimer(uint32_t intervalMs) {
itimerspec timer;
timer.it_value.tv_sec = intervalMs / 1000;
timer.it_value.tv_nsec = (intervalMs * 1000000) % (1000000000);
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_nsec = 0;
return timer_settime(timerId, 0, &timer, NULL);
}
int Timer::getTimer(uint32_t* remainingTimeMs){
itimerspec timer;
timer.it_value.tv_sec = 0;
timer.it_value.tv_nsec = 0;
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_nsec = 0;
int status = timer_gettime(timerId, &timer);
*remainingTimeMs = timer.it_value.tv_sec * 1000 + timer.it_value.tv_nsec / 1000000;
return status;
}

View File

@ -1,168 +1,168 @@
#include "../../osal/linux/TmTcUnixUdpBridge.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../ipc/MutexHelper.h"
#include <errno.h>
#include <arpa/inet.h>
TmTcUnixUdpBridge::TmTcUnixUdpBridge(object_id_t objectId,
object_id_t tcDestination, object_id_t tmStoreId, object_id_t tcStoreId,
uint16_t serverPort, uint16_t clientPort):
TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) {
mutex = MutexFactory::instance()->createMutex();
uint16_t setServerPort = DEFAULT_UDP_SERVER_PORT;
if(serverPort != 0xFFFF) {
setServerPort = serverPort;
}
uint16_t setClientPort = DEFAULT_UDP_CLIENT_PORT;
if(clientPort != 0xFFFF) {
setClientPort = clientPort;
}
// Set up UDP socket: https://man7.org/linux/man-pages/man7/ip.7.html
//clientSocket = socket(AF_INET, SOCK_DGRAM, 0);
serverSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(socket < 0) {
sif::error << "TmTcUnixUdpBridge::TmTcUnixUdpBridge: Could not open"
" UDP socket!" << std::endl;
handleSocketError();
return;
}
serverAddress.sin_family = AF_INET;
// Accept packets from any interface.
//serverAddress.sin_addr.s_addr = inet_addr("127.73.73.0");
serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);
serverAddress.sin_port = htons(setServerPort);
serverAddressLen = sizeof(serverAddress);
setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &serverSocketOptions,
sizeof(serverSocketOptions));
clientAddress.sin_family = AF_INET;
clientAddress.sin_addr.s_addr = htonl(INADDR_ANY);
clientAddress.sin_port = htons(setClientPort);
clientAddressLen = sizeof(clientAddress);
int result = bind(serverSocket,
reinterpret_cast<struct sockaddr*>(&serverAddress),
serverAddressLen);
if(result == -1) {
sif::error << "TmTcUnixUdpBridge::TmTcUnixUdpBridge: Could not bind "
"local port " << setServerPort << " to server socket!"
<< std::endl;
handleBindError();
return;
}
}
TmTcUnixUdpBridge::~TmTcUnixUdpBridge() {
}
ReturnValue_t TmTcUnixUdpBridge::sendTm(const uint8_t *data, size_t dataLen) {
int flags = 0;
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,
// &clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
ssize_t bytesSent = sendto(serverSocket, data, dataLen, flags,
reinterpret_cast<sockaddr*>(&clientAddress), clientAddressLen);
if(bytesSent < 0) {
sif::error << "TmTcUnixUdpBridge::sendTm: Send operation failed."
<< std::endl;
handleSendError();
}
// sif::debug << "TmTcUnixUdpBridge::sendTm: " << bytesSent << " bytes were"
// " sent." << std::endl;
return HasReturnvaluesIF::RETURN_OK;
}
void TmTcUnixUdpBridge::checkAndSetClientAddress(sockaddr_in newAddress) {
MutexHelper lock(mutex, MutexIF::TimeoutType::WAITING, 10);
// char ipAddress [15];
// sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET,
// &newAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
// sif::debug << "IP Address Old: " << inet_ntop(AF_INET,
// &clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
// Set new IP address if it has changed.
if(clientAddress.sin_addr.s_addr != newAddress.sin_addr.s_addr) {
clientAddress.sin_addr.s_addr = newAddress.sin_addr.s_addr;
clientAddressLen = sizeof(clientAddress);
}
}
void TmTcUnixUdpBridge::handleSocketError() {
// See: https://man7.org/linux/man-pages/man2/socket.2.html
switch(errno) {
case(EACCES):
case(EINVAL):
case(EMFILE):
case(ENFILE):
case(EAFNOSUPPORT):
case(ENOBUFS):
case(ENOMEM):
case(EPROTONOSUPPORT):
sif::error << "TmTcUnixBridge::handleSocketError: Socket creation failed"
<< " with " << strerror(errno) << std::endl;
break;
default:
sif::error << "TmTcUnixBridge::handleSocketError: Unknown error"
<< std::endl;
break;
}
}
void TmTcUnixUdpBridge::handleBindError() {
// See: https://man7.org/linux/man-pages/man2/bind.2.html
switch(errno) {
case(EACCES): {
/*
Ephermeral ports can be shown with following command:
sysctl -A | grep ip_local_port_range
*/
sif::error << "TmTcUnixBridge::handleBindError: Port access issue."
"Ports 1-1024 are reserved on UNIX systems and require root "
"rights while ephermeral ports should not be used as well."
<< std::endl;
}
break;
case(EADDRINUSE):
case(EBADF):
case(EINVAL):
case(ENOTSOCK):
case(EADDRNOTAVAIL):
case(EFAULT):
case(ELOOP):
case(ENAMETOOLONG):
case(ENOENT):
case(ENOMEM):
case(ENOTDIR):
case(EROFS): {
sif::error << "TmTcUnixBridge::handleBindError: Socket creation failed"
<< " with " << strerror(errno) << std::endl;
break;
}
default:
sif::error << "TmTcUnixBridge::handleBindError: Unknown error"
<< std::endl;
break;
}
}
void TmTcUnixUdpBridge::handleSendError() {
switch(errno) {
default:
sif::error << "Error: " << strerror(errno) << std::endl;
}
}
#include "../../osal/linux/TmTcUnixUdpBridge.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../ipc/MutexHelper.h"
#include <errno.h>
#include <arpa/inet.h>
TmTcUnixUdpBridge::TmTcUnixUdpBridge(object_id_t objectId,
object_id_t tcDestination, object_id_t tmStoreId, object_id_t tcStoreId,
uint16_t serverPort, uint16_t clientPort):
TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) {
mutex = MutexFactory::instance()->createMutex();
uint16_t setServerPort = DEFAULT_UDP_SERVER_PORT;
if(serverPort != 0xFFFF) {
setServerPort = serverPort;
}
uint16_t setClientPort = DEFAULT_UDP_CLIENT_PORT;
if(clientPort != 0xFFFF) {
setClientPort = clientPort;
}
// Set up UDP socket: https://man7.org/linux/man-pages/man7/ip.7.html
//clientSocket = socket(AF_INET, SOCK_DGRAM, 0);
serverSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(socket < 0) {
sif::error << "TmTcUnixUdpBridge::TmTcUnixUdpBridge: Could not open"
" UDP socket!" << std::endl;
handleSocketError();
return;
}
serverAddress.sin_family = AF_INET;
// Accept packets from any interface.
//serverAddress.sin_addr.s_addr = inet_addr("127.73.73.0");
serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);
serverAddress.sin_port = htons(setServerPort);
serverAddressLen = sizeof(serverAddress);
setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &serverSocketOptions,
sizeof(serverSocketOptions));
clientAddress.sin_family = AF_INET;
clientAddress.sin_addr.s_addr = htonl(INADDR_ANY);
clientAddress.sin_port = htons(setClientPort);
clientAddressLen = sizeof(clientAddress);
int result = bind(serverSocket,
reinterpret_cast<struct sockaddr*>(&serverAddress),
serverAddressLen);
if(result == -1) {
sif::error << "TmTcUnixUdpBridge::TmTcUnixUdpBridge: Could not bind "
"local port " << setServerPort << " to server socket!"
<< std::endl;
handleBindError();
return;
}
}
TmTcUnixUdpBridge::~TmTcUnixUdpBridge() {
}
ReturnValue_t TmTcUnixUdpBridge::sendTm(const uint8_t *data, size_t dataLen) {
int flags = 0;
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,
// &clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
ssize_t bytesSent = sendto(serverSocket, data, dataLen, flags,
reinterpret_cast<sockaddr*>(&clientAddress), clientAddressLen);
if(bytesSent < 0) {
sif::error << "TmTcUnixUdpBridge::sendTm: Send operation failed."
<< std::endl;
handleSendError();
}
// sif::debug << "TmTcUnixUdpBridge::sendTm: " << bytesSent << " bytes were"
// " sent." << std::endl;
return HasReturnvaluesIF::RETURN_OK;
}
void TmTcUnixUdpBridge::checkAndSetClientAddress(sockaddr_in newAddress) {
MutexHelper lock(mutex, MutexIF::TimeoutType::WAITING, 10);
// char ipAddress [15];
// sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET,
// &newAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
// sif::debug << "IP Address Old: " << inet_ntop(AF_INET,
// &clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
// Set new IP address if it has changed.
if(clientAddress.sin_addr.s_addr != newAddress.sin_addr.s_addr) {
clientAddress.sin_addr.s_addr = newAddress.sin_addr.s_addr;
clientAddressLen = sizeof(clientAddress);
}
}
void TmTcUnixUdpBridge::handleSocketError() {
// See: https://man7.org/linux/man-pages/man2/socket.2.html
switch(errno) {
case(EACCES):
case(EINVAL):
case(EMFILE):
case(ENFILE):
case(EAFNOSUPPORT):
case(ENOBUFS):
case(ENOMEM):
case(EPROTONOSUPPORT):
sif::error << "TmTcUnixBridge::handleSocketError: Socket creation failed"
<< " with " << strerror(errno) << std::endl;
break;
default:
sif::error << "TmTcUnixBridge::handleSocketError: Unknown error"
<< std::endl;
break;
}
}
void TmTcUnixUdpBridge::handleBindError() {
// See: https://man7.org/linux/man-pages/man2/bind.2.html
switch(errno) {
case(EACCES): {
/*
Ephermeral ports can be shown with following command:
sysctl -A | grep ip_local_port_range
*/
sif::error << "TmTcUnixBridge::handleBindError: Port access issue."
"Ports 1-1024 are reserved on UNIX systems and require root "
"rights while ephermeral ports should not be used as well."
<< std::endl;
}
break;
case(EADDRINUSE):
case(EBADF):
case(EINVAL):
case(ENOTSOCK):
case(EADDRNOTAVAIL):
case(EFAULT):
case(ELOOP):
case(ENAMETOOLONG):
case(ENOENT):
case(ENOMEM):
case(ENOTDIR):
case(EROFS): {
sif::error << "TmTcUnixBridge::handleBindError: Socket creation failed"
<< " with " << strerror(errno) << std::endl;
break;
}
default:
sif::error << "TmTcUnixBridge::handleBindError: Unknown error"
<< std::endl;
break;
}
}
void TmTcUnixUdpBridge::handleSendError() {
switch(errno) {
default:
sif::error << "Error: " << strerror(errno) << std::endl;
}
}

View File

@ -1,48 +1,48 @@
#ifndef FRAMEWORK_OSAL_LINUX_TMTCUNIXUDPBRIDGE_H_
#define FRAMEWORK_OSAL_LINUX_TMTCUNIXUDPBRIDGE_H_
#include "../../tmtcservices/AcceptsTelecommandsIF.h"
#include "../../tmtcservices/TmTcBridge.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/udp.h>
class TmTcUnixUdpBridge: public TmTcBridge {
friend class TcUnixUdpPollingTask;
public:
// The ports chosen here should not be used by any other process.
// List of used ports on Linux: /etc/services
static constexpr uint16_t DEFAULT_UDP_SERVER_PORT = 7301;
static constexpr uint16_t DEFAULT_UDP_CLIENT_PORT = 7302;
TmTcUnixUdpBridge(object_id_t objectId, object_id_t tcDestination,
object_id_t tmStoreId, object_id_t tcStoreId,
uint16_t serverPort = 0xFFFF,uint16_t clientPort = 0xFFFF);
virtual~ TmTcUnixUdpBridge();
void checkAndSetClientAddress(sockaddr_in clientAddress);
protected:
virtual ReturnValue_t sendTm(const uint8_t * data, size_t dataLen) override;
private:
int serverSocket = 0;
const int serverSocketOptions = 0;
struct sockaddr_in clientAddress;
socklen_t clientAddressLen = 0;
struct sockaddr_in serverAddress;
socklen_t serverAddressLen = 0;
//! Access to the client address is mutex protected as it is set
//! by another task.
MutexIF* mutex;
void handleSocketError();
void handleBindError();
void handleSendError();
};
#endif /* FRAMEWORK_OSAL_LINUX_TMTCUNIXUDPBRIDGE_H_ */
#ifndef FRAMEWORK_OSAL_LINUX_TMTCUNIXUDPBRIDGE_H_
#define FRAMEWORK_OSAL_LINUX_TMTCUNIXUDPBRIDGE_H_
#include "../../tmtcservices/AcceptsTelecommandsIF.h"
#include "../../tmtcservices/TmTcBridge.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/udp.h>
class TmTcUnixUdpBridge: public TmTcBridge {
friend class TcUnixUdpPollingTask;
public:
// The ports chosen here should not be used by any other process.
// List of used ports on Linux: /etc/services
static constexpr uint16_t DEFAULT_UDP_SERVER_PORT = 7301;
static constexpr uint16_t DEFAULT_UDP_CLIENT_PORT = 7302;
TmTcUnixUdpBridge(object_id_t objectId, object_id_t tcDestination,
object_id_t tmStoreId, object_id_t tcStoreId,
uint16_t serverPort = 0xFFFF,uint16_t clientPort = 0xFFFF);
virtual~ TmTcUnixUdpBridge();
void checkAndSetClientAddress(sockaddr_in clientAddress);
protected:
virtual ReturnValue_t sendTm(const uint8_t * data, size_t dataLen) override;
private:
int serverSocket = 0;
const int serverSocketOptions = 0;
struct sockaddr_in clientAddress;
socklen_t clientAddressLen = 0;
struct sockaddr_in serverAddress;
socklen_t serverAddressLen = 0;
//! Access to the client address is mutex protected as it is set
//! by another task.
MutexIF* mutex;
void handleSocketError();
void handleBindError();
void handleSendError();
};
#endif /* FRAMEWORK_OSAL_LINUX_TMTCUNIXUDPBRIDGE_H_ */