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,95 +1,95 @@
#include "../../osal/FreeRTOS/BinSemaphUsingTask.h"
#include "../../osal/FreeRTOS/TaskManagement.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
BinarySemaphoreUsingTask::BinarySemaphoreUsingTask() {
handle = TaskManagement::getCurrentTaskHandle();
if(handle == nullptr) {
sif::error << "Could not retrieve task handle. Please ensure the"
"constructor was called inside a task." << std::endl;
}
xTaskNotifyGive(handle);
}
BinarySemaphoreUsingTask::~BinarySemaphoreUsingTask() {
// Clear notification value on destruction.
xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, nullptr);
}
ReturnValue_t BinarySemaphoreUsingTask::acquire(TimeoutType timeoutType,
uint32_t timeoutMs) {
TickType_t timeout = 0;
if(timeoutType == TimeoutType::POLLING) {
timeout = 0;
}
else if(timeoutType == TimeoutType::WAITING){
timeout = pdMS_TO_TICKS(timeoutMs);
}
else {
timeout = portMAX_DELAY;
}
return acquireWithTickTimeout(timeoutType, timeout);
}
ReturnValue_t BinarySemaphoreUsingTask::acquireWithTickTimeout(
TimeoutType timeoutType, TickType_t timeoutTicks) {
BaseType_t returncode = ulTaskNotifyTake(pdTRUE, timeoutTicks);
if (returncode == pdPASS) {
return HasReturnvaluesIF::RETURN_OK;
}
else {
return SemaphoreIF::SEMAPHORE_TIMEOUT;
}
}
ReturnValue_t BinarySemaphoreUsingTask::release() {
return release(this->handle);
}
ReturnValue_t BinarySemaphoreUsingTask::release(
TaskHandle_t taskHandle) {
if(getSemaphoreCounter(taskHandle) == 1) {
return SemaphoreIF::SEMAPHORE_NOT_OWNED;
}
BaseType_t returncode = xTaskNotifyGive(taskHandle);
if (returncode == pdPASS) {
return HasReturnvaluesIF::RETURN_OK;
}
else {
// This should never happen.
return HasReturnvaluesIF::RETURN_FAILED;
}
}
TaskHandle_t BinarySemaphoreUsingTask::getTaskHandle() {
return handle;
}
uint8_t BinarySemaphoreUsingTask::getSemaphoreCounter() const {
return getSemaphoreCounter(this->handle);
}
uint8_t BinarySemaphoreUsingTask::getSemaphoreCounter(
TaskHandle_t taskHandle) {
uint32_t notificationValue;
xTaskNotifyAndQuery(taskHandle, 0, eNoAction, &notificationValue);
return notificationValue;
}
// Be careful with the stack size here. This is called from an ISR!
ReturnValue_t BinarySemaphoreUsingTask::releaseFromISR(
TaskHandle_t taskHandle, BaseType_t * higherPriorityTaskWoken) {
if(getSemaphoreCounterFromISR(taskHandle, higherPriorityTaskWoken) == 1) {
return SemaphoreIF::SEMAPHORE_NOT_OWNED;
}
vTaskNotifyGiveFromISR(taskHandle, higherPriorityTaskWoken);
return HasReturnvaluesIF::RETURN_OK;
}
uint8_t BinarySemaphoreUsingTask::getSemaphoreCounterFromISR(
TaskHandle_t taskHandle, BaseType_t* higherPriorityTaskWoken) {
uint32_t notificationValue = 0;
xTaskNotifyAndQueryFromISR(taskHandle, 0, eNoAction, &notificationValue,
higherPriorityTaskWoken);
return notificationValue;
}
#include "../../osal/FreeRTOS/BinSemaphUsingTask.h"
#include "../../osal/FreeRTOS/TaskManagement.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
BinarySemaphoreUsingTask::BinarySemaphoreUsingTask() {
handle = TaskManagement::getCurrentTaskHandle();
if(handle == nullptr) {
sif::error << "Could not retrieve task handle. Please ensure the"
"constructor was called inside a task." << std::endl;
}
xTaskNotifyGive(handle);
}
BinarySemaphoreUsingTask::~BinarySemaphoreUsingTask() {
// Clear notification value on destruction.
xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, nullptr);
}
ReturnValue_t BinarySemaphoreUsingTask::acquire(TimeoutType timeoutType,
uint32_t timeoutMs) {
TickType_t timeout = 0;
if(timeoutType == TimeoutType::POLLING) {
timeout = 0;
}
else if(timeoutType == TimeoutType::WAITING){
timeout = pdMS_TO_TICKS(timeoutMs);
}
else {
timeout = portMAX_DELAY;
}
return acquireWithTickTimeout(timeoutType, timeout);
}
ReturnValue_t BinarySemaphoreUsingTask::acquireWithTickTimeout(
TimeoutType timeoutType, TickType_t timeoutTicks) {
BaseType_t returncode = ulTaskNotifyTake(pdTRUE, timeoutTicks);
if (returncode == pdPASS) {
return HasReturnvaluesIF::RETURN_OK;
}
else {
return SemaphoreIF::SEMAPHORE_TIMEOUT;
}
}
ReturnValue_t BinarySemaphoreUsingTask::release() {
return release(this->handle);
}
ReturnValue_t BinarySemaphoreUsingTask::release(
TaskHandle_t taskHandle) {
if(getSemaphoreCounter(taskHandle) == 1) {
return SemaphoreIF::SEMAPHORE_NOT_OWNED;
}
BaseType_t returncode = xTaskNotifyGive(taskHandle);
if (returncode == pdPASS) {
return HasReturnvaluesIF::RETURN_OK;
}
else {
// This should never happen.
return HasReturnvaluesIF::RETURN_FAILED;
}
}
TaskHandle_t BinarySemaphoreUsingTask::getTaskHandle() {
return handle;
}
uint8_t BinarySemaphoreUsingTask::getSemaphoreCounter() const {
return getSemaphoreCounter(this->handle);
}
uint8_t BinarySemaphoreUsingTask::getSemaphoreCounter(
TaskHandle_t taskHandle) {
uint32_t notificationValue;
xTaskNotifyAndQuery(taskHandle, 0, eNoAction, &notificationValue);
return notificationValue;
}
// Be careful with the stack size here. This is called from an ISR!
ReturnValue_t BinarySemaphoreUsingTask::releaseFromISR(
TaskHandle_t taskHandle, BaseType_t * higherPriorityTaskWoken) {
if(getSemaphoreCounterFromISR(taskHandle, higherPriorityTaskWoken) == 1) {
return SemaphoreIF::SEMAPHORE_NOT_OWNED;
}
vTaskNotifyGiveFromISR(taskHandle, higherPriorityTaskWoken);
return HasReturnvaluesIF::RETURN_OK;
}
uint8_t BinarySemaphoreUsingTask::getSemaphoreCounterFromISR(
TaskHandle_t taskHandle, BaseType_t* higherPriorityTaskWoken) {
uint32_t notificationValue = 0;
xTaskNotifyAndQueryFromISR(taskHandle, 0, eNoAction, &notificationValue,
higherPriorityTaskWoken);
return notificationValue;
}

View File

@ -1,79 +1,79 @@
#ifndef FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_
#define FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_
#include "../../returnvalues/HasReturnvaluesIF.h"
#include "../../tasks/SemaphoreIF.h"
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
/**
* @brief Binary Semaphore implementation using the task notification value.
* The notification value should therefore not be used
* for other purposes.
* @details
* Additional information: https://www.freertos.org/RTOS-task-notifications.html
* and general semaphore documentation.
* This semaphore is bound to the task it is created in!
* Take care of calling this function with the correct executing task,
* (for example in the initializeAfterTaskCreation() function).
*/
class BinarySemaphoreUsingTask: public SemaphoreIF,
public HasReturnvaluesIF {
public:
static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF;
//! @brief Default ctor
BinarySemaphoreUsingTask();
//! @brief Default dtor
virtual~ BinarySemaphoreUsingTask();
ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING,
uint32_t timeoutMs = portMAX_DELAY) override;
ReturnValue_t release() override;
uint8_t getSemaphoreCounter() const override;
static uint8_t getSemaphoreCounter(TaskHandle_t taskHandle);
static uint8_t getSemaphoreCounterFromISR(TaskHandle_t taskHandle,
BaseType_t* higherPriorityTaskWoken);
/**
* Same as acquire() with timeout in FreeRTOS ticks.
* @param timeoutTicks
* @return - @c RETURN_OK on success
* - @c RETURN_FAILED on failure
*/
ReturnValue_t acquireWithTickTimeout(
TimeoutType timeoutType = TimeoutType::BLOCKING,
TickType_t timeoutTicks = portMAX_DELAY);
/**
* Get handle to the task related to the semaphore.
* @return
*/
TaskHandle_t getTaskHandle();
/**
* Wrapper function to give back semaphore from handle
* @param semaphore
* @return - @c RETURN_OK on success
* - @c RETURN_FAILED on failure
*/
static ReturnValue_t release(TaskHandle_t taskToNotify);
/**
* Wrapper function to give back semaphore from handle when called from an ISR
* @param semaphore
* @param higherPriorityTaskWoken This will be set to pdPASS if a task with
* a higher priority was unblocked. A context switch should be requested
* from an ISR if this is the case (see TaskManagement functions)
* @return - @c RETURN_OK on success
* - @c RETURN_FAILED on failure
*/
static ReturnValue_t releaseFromISR(TaskHandle_t taskToNotify,
BaseType_t * higherPriorityTaskWoken);
protected:
TaskHandle_t handle;
};
#endif /* FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ */
#ifndef FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_
#define FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_
#include "../../returnvalues/HasReturnvaluesIF.h"
#include "../../tasks/SemaphoreIF.h"
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
/**
* @brief Binary Semaphore implementation using the task notification value.
* The notification value should therefore not be used
* for other purposes.
* @details
* Additional information: https://www.freertos.org/RTOS-task-notifications.html
* and general semaphore documentation.
* This semaphore is bound to the task it is created in!
* Take care of calling this function with the correct executing task,
* (for example in the initializeAfterTaskCreation() function).
*/
class BinarySemaphoreUsingTask: public SemaphoreIF,
public HasReturnvaluesIF {
public:
static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF;
//! @brief Default ctor
BinarySemaphoreUsingTask();
//! @brief Default dtor
virtual~ BinarySemaphoreUsingTask();
ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING,
uint32_t timeoutMs = portMAX_DELAY) override;
ReturnValue_t release() override;
uint8_t getSemaphoreCounter() const override;
static uint8_t getSemaphoreCounter(TaskHandle_t taskHandle);
static uint8_t getSemaphoreCounterFromISR(TaskHandle_t taskHandle,
BaseType_t* higherPriorityTaskWoken);
/**
* Same as acquire() with timeout in FreeRTOS ticks.
* @param timeoutTicks
* @return - @c RETURN_OK on success
* - @c RETURN_FAILED on failure
*/
ReturnValue_t acquireWithTickTimeout(
TimeoutType timeoutType = TimeoutType::BLOCKING,
TickType_t timeoutTicks = portMAX_DELAY);
/**
* Get handle to the task related to the semaphore.
* @return
*/
TaskHandle_t getTaskHandle();
/**
* Wrapper function to give back semaphore from handle
* @param semaphore
* @return - @c RETURN_OK on success
* - @c RETURN_FAILED on failure
*/
static ReturnValue_t release(TaskHandle_t taskToNotify);
/**
* Wrapper function to give back semaphore from handle when called from an ISR
* @param semaphore
* @param higherPriorityTaskWoken This will be set to pdPASS if a task with
* a higher priority was unblocked. A context switch should be requested
* from an ISR if this is the case (see TaskManagement functions)
* @return - @c RETURN_OK on success
* - @c RETURN_FAILED on failure
*/
static ReturnValue_t releaseFromISR(TaskHandle_t taskToNotify,
BaseType_t * higherPriorityTaskWoken);
protected:
TaskHandle_t handle;
};
#endif /* FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ */

View File

@ -1,108 +1,108 @@
#include "../../osal/FreeRTOS/BinarySemaphore.h"
#include "../../osal/FreeRTOS/TaskManagement.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
BinarySemaphore::BinarySemaphore() {
handle = xSemaphoreCreateBinary();
if(handle == nullptr) {
sif::error << "Semaphore: Binary semaph creation failure" << std::endl;
}
// Initiated semaphore must be given before it can be taken.
xSemaphoreGive(handle);
}
BinarySemaphore::~BinarySemaphore() {
vSemaphoreDelete(handle);
}
BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) {
handle = xSemaphoreCreateBinary();
if(handle == nullptr) {
sif::error << "Binary semaphore creation failure" << std::endl;
}
xSemaphoreGive(handle);
}
BinarySemaphore& BinarySemaphore::operator =(
BinarySemaphore&& s) {
if(&s != this) {
handle = xSemaphoreCreateBinary();
if(handle == nullptr) {
sif::error << "Binary semaphore creation failure" << std::endl;
}
xSemaphoreGive(handle);
}
return *this;
}
ReturnValue_t BinarySemaphore::acquire(TimeoutType timeoutType,
uint32_t timeoutMs) {
TickType_t timeout = 0;
if(timeoutType == TimeoutType::POLLING) {
timeout = 0;
}
else if(timeoutType == TimeoutType::WAITING){
timeout = pdMS_TO_TICKS(timeoutMs);
}
else {
timeout = portMAX_DELAY;
}
return acquireWithTickTimeout(timeoutType, timeout);
}
ReturnValue_t BinarySemaphore::acquireWithTickTimeout(TimeoutType timeoutType,
TickType_t timeoutTicks) {
if(handle == nullptr) {
return SemaphoreIF::SEMAPHORE_INVALID;
}
BaseType_t returncode = xSemaphoreTake(handle, timeoutTicks);
if (returncode == pdPASS) {
return HasReturnvaluesIF::RETURN_OK;
}
else {
return SemaphoreIF::SEMAPHORE_TIMEOUT;
}
}
ReturnValue_t BinarySemaphore::release() {
return release(handle);
}
ReturnValue_t BinarySemaphore::release(SemaphoreHandle_t semaphore) {
if (semaphore == nullptr) {
return SemaphoreIF::SEMAPHORE_INVALID;
}
BaseType_t returncode = xSemaphoreGive(semaphore);
if (returncode == pdPASS) {
return HasReturnvaluesIF::RETURN_OK;
}
else {
return SemaphoreIF::SEMAPHORE_NOT_OWNED;
}
}
uint8_t BinarySemaphore::getSemaphoreCounter() const {
return uxSemaphoreGetCount(handle);
}
SemaphoreHandle_t BinarySemaphore::getSemaphore() {
return handle;
}
// Be careful with the stack size here. This is called from an ISR!
ReturnValue_t BinarySemaphore::releaseFromISR(
SemaphoreHandle_t semaphore, BaseType_t * higherPriorityTaskWoken) {
if (semaphore == nullptr) {
return SemaphoreIF::SEMAPHORE_INVALID;
}
BaseType_t returncode = xSemaphoreGiveFromISR(semaphore,
higherPriorityTaskWoken);
if (returncode == pdPASS) {
return HasReturnvaluesIF::RETURN_OK;
}
else {
return SemaphoreIF::SEMAPHORE_NOT_OWNED;
}
}
#include "../../osal/FreeRTOS/BinarySemaphore.h"
#include "../../osal/FreeRTOS/TaskManagement.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
BinarySemaphore::BinarySemaphore() {
handle = xSemaphoreCreateBinary();
if(handle == nullptr) {
sif::error << "Semaphore: Binary semaph creation failure" << std::endl;
}
// Initiated semaphore must be given before it can be taken.
xSemaphoreGive(handle);
}
BinarySemaphore::~BinarySemaphore() {
vSemaphoreDelete(handle);
}
BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) {
handle = xSemaphoreCreateBinary();
if(handle == nullptr) {
sif::error << "Binary semaphore creation failure" << std::endl;
}
xSemaphoreGive(handle);
}
BinarySemaphore& BinarySemaphore::operator =(
BinarySemaphore&& s) {
if(&s != this) {
handle = xSemaphoreCreateBinary();
if(handle == nullptr) {
sif::error << "Binary semaphore creation failure" << std::endl;
}
xSemaphoreGive(handle);
}
return *this;
}
ReturnValue_t BinarySemaphore::acquire(TimeoutType timeoutType,
uint32_t timeoutMs) {
TickType_t timeout = 0;
if(timeoutType == TimeoutType::POLLING) {
timeout = 0;
}
else if(timeoutType == TimeoutType::WAITING){
timeout = pdMS_TO_TICKS(timeoutMs);
}
else {
timeout = portMAX_DELAY;
}
return acquireWithTickTimeout(timeoutType, timeout);
}
ReturnValue_t BinarySemaphore::acquireWithTickTimeout(TimeoutType timeoutType,
TickType_t timeoutTicks) {
if(handle == nullptr) {
return SemaphoreIF::SEMAPHORE_INVALID;
}
BaseType_t returncode = xSemaphoreTake(handle, timeoutTicks);
if (returncode == pdPASS) {
return HasReturnvaluesIF::RETURN_OK;
}
else {
return SemaphoreIF::SEMAPHORE_TIMEOUT;
}
}
ReturnValue_t BinarySemaphore::release() {
return release(handle);
}
ReturnValue_t BinarySemaphore::release(SemaphoreHandle_t semaphore) {
if (semaphore == nullptr) {
return SemaphoreIF::SEMAPHORE_INVALID;
}
BaseType_t returncode = xSemaphoreGive(semaphore);
if (returncode == pdPASS) {
return HasReturnvaluesIF::RETURN_OK;
}
else {
return SemaphoreIF::SEMAPHORE_NOT_OWNED;
}
}
uint8_t BinarySemaphore::getSemaphoreCounter() const {
return uxSemaphoreGetCount(handle);
}
SemaphoreHandle_t BinarySemaphore::getSemaphore() {
return handle;
}
// Be careful with the stack size here. This is called from an ISR!
ReturnValue_t BinarySemaphore::releaseFromISR(
SemaphoreHandle_t semaphore, BaseType_t * higherPriorityTaskWoken) {
if (semaphore == nullptr) {
return SemaphoreIF::SEMAPHORE_INVALID;
}
BaseType_t returncode = xSemaphoreGiveFromISR(semaphore,
higherPriorityTaskWoken);
if (returncode == pdPASS) {
return HasReturnvaluesIF::RETURN_OK;
}
else {
return SemaphoreIF::SEMAPHORE_NOT_OWNED;
}
}

View File

@ -1,107 +1,107 @@
#ifndef FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_
#define FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_
#include "../../returnvalues/HasReturnvaluesIF.h"
#include "../../tasks/SemaphoreIF.h"
#include <freertos/FreeRTOS.h>
#include <freertos/semphr.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
* Documentation: https://www.freertos.org/Embedded-RTOS-Binary-Semaphores.html
*
* Please note that if the semaphore implementation is only related to
* the synchronization of one task, the new task notifications can be used,
* also see the BinSemaphUsingTask and CountingSemaphUsingTask classes.
* These use the task notification value instead of a queue and are
* faster and more efficient.
*
* @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();
uint8_t getSemaphoreCounter() const override;
/**
* 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 = portMAX_DELAY) override;
/**
* Same as lockBinarySemaphore() with timeout in FreeRTOS ticks.
* @param timeoutTicks
* @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout
*/
ReturnValue_t acquireWithTickTimeout(TimeoutType timeoutType =
TimeoutType::BLOCKING, TickType_t timeoutTicks = portMAX_DELAY);
/**
* Release the binary semaphore.
* @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is
* already available.
*/
ReturnValue_t release() override;
/**
* Get Handle to the semaphore.
* @return
*/
SemaphoreHandle_t getSemaphore();
/**
* Wrapper function to give back semaphore from handle
* @param semaphore
* @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is
* already available.
*/
static ReturnValue_t release(SemaphoreHandle_t semaphore);
/**
* Wrapper function to give back semaphore from handle when called from an ISR
* @param semaphore
* @param higherPriorityTaskWoken This will be set to pdPASS if a task with
* a higher priority was unblocked. A context switch from an ISR should
* then be requested (see TaskManagement functions)
* @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is
* already available.
*/
static ReturnValue_t releaseFromISR(SemaphoreHandle_t semaphore,
BaseType_t * higherPriorityTaskWoken);
protected:
SemaphoreHandle_t handle;
};
#endif /* FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ */
#ifndef FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_
#define FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_
#include "../../returnvalues/HasReturnvaluesIF.h"
#include "../../tasks/SemaphoreIF.h"
#include <freertos/FreeRTOS.h>
#include <freertos/semphr.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
* Documentation: https://www.freertos.org/Embedded-RTOS-Binary-Semaphores.html
*
* Please note that if the semaphore implementation is only related to
* the synchronization of one task, the new task notifications can be used,
* also see the BinSemaphUsingTask and CountingSemaphUsingTask classes.
* These use the task notification value instead of a queue and are
* faster and more efficient.
*
* @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();
uint8_t getSemaphoreCounter() const override;
/**
* 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 = portMAX_DELAY) override;
/**
* Same as lockBinarySemaphore() with timeout in FreeRTOS ticks.
* @param timeoutTicks
* @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout
*/
ReturnValue_t acquireWithTickTimeout(TimeoutType timeoutType =
TimeoutType::BLOCKING, TickType_t timeoutTicks = portMAX_DELAY);
/**
* Release the binary semaphore.
* @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is
* already available.
*/
ReturnValue_t release() override;
/**
* Get Handle to the semaphore.
* @return
*/
SemaphoreHandle_t getSemaphore();
/**
* Wrapper function to give back semaphore from handle
* @param semaphore
* @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is
* already available.
*/
static ReturnValue_t release(SemaphoreHandle_t semaphore);
/**
* Wrapper function to give back semaphore from handle when called from an ISR
* @param semaphore
* @param higherPriorityTaskWoken This will be set to pdPASS if a task with
* a higher priority was unblocked. A context switch from an ISR should
* then be requested (see TaskManagement functions)
* @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is
* already available.
*/
static ReturnValue_t releaseFromISR(SemaphoreHandle_t semaphore,
BaseType_t * higherPriorityTaskWoken);
protected:
SemaphoreHandle_t handle;
};
#endif /* FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ */

View File

@ -1,196 +1,196 @@
#include "../../timemanager/Clock.h"
#include "../../globalfunctions/timevalOperations.h"
#include "../../osal/FreeRTOS/Timekeeper.h"
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <stdlib.h>
#include <time.h>
//TODO sanitize input?
//TODO much of this code can be reused for tick-only systems
uint16_t Clock::leapSeconds = 0;
MutexIF* Clock::timeMutex = nullptr;
uint32_t Clock::getTicksPerSecond(void) {
return 1000;
}
ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {
timeval time_timeval;
ReturnValue_t result = convertTimeOfDayToTimeval(time, &time_timeval);
if (result != HasReturnvaluesIF::RETURN_OK){
return result;
}
return setClock(&time_timeval);
}
ReturnValue_t Clock::setClock(const timeval* time) {
timeval uptime = getUptime();
timeval offset = *time - uptime;
Timekeeper::instance()->setOffset(offset);
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::getClock_timeval(timeval* time) {
timeval uptime = getUptime();
timeval offset = Timekeeper::instance()->getOffset();
*time = offset + uptime;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::getUptime(timeval* uptime) {
*uptime = getUptime();
return HasReturnvaluesIF::RETURN_OK;
}
timeval Clock::getUptime() {
TickType_t ticksSinceStart = xTaskGetTickCount();
return Timekeeper::ticksToTimeval(ticksSinceStart);
}
ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) {
timeval uptime = getUptime();
*uptimeMs = uptime.tv_sec * 1000 + uptime.tv_usec / 1000;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
timeval time_timeval;
ReturnValue_t result = getClock_timeval(&time_timeval);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
*time = time_timeval.tv_sec * 1000000 + time_timeval.tv_usec;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
timeval time_timeval;
ReturnValue_t result = getClock_timeval(&time_timeval);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
struct tm time_tm;
gmtime_r(&time_timeval.tv_sec,&time_tm);
time->year = time_tm.tm_year + 1900;
time->month = time_tm.tm_mon + 1;
time->day = time_tm.tm_mday;
time->hour = time_tm.tm_hour;
time->minute = time_tm.tm_min;
time->second = time_tm.tm_sec;
time->usecond = time_timeval.tv_usec;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from,
timeval* to) {
struct tm time_tm;
time_tm.tm_year = from->year - 1900;
time_tm.tm_mon = from->month - 1;
time_tm.tm_mday = from->day;
time_tm.tm_hour = from->hour;
time_tm.tm_min = from->minute;
time_tm.tm_sec = from->second;
time_t seconds = mktime(&time_tm);
to->tv_sec = seconds;
to->tv_usec = from->usecond;
//Fails in 2038..
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 == nullptr) {
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 "../../timemanager/Clock.h"
#include "../../globalfunctions/timevalOperations.h"
#include "../../osal/FreeRTOS/Timekeeper.h"
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <stdlib.h>
#include <time.h>
//TODO sanitize input?
//TODO much of this code can be reused for tick-only systems
uint16_t Clock::leapSeconds = 0;
MutexIF* Clock::timeMutex = nullptr;
uint32_t Clock::getTicksPerSecond(void) {
return 1000;
}
ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {
timeval time_timeval;
ReturnValue_t result = convertTimeOfDayToTimeval(time, &time_timeval);
if (result != HasReturnvaluesIF::RETURN_OK){
return result;
}
return setClock(&time_timeval);
}
ReturnValue_t Clock::setClock(const timeval* time) {
timeval uptime = getUptime();
timeval offset = *time - uptime;
Timekeeper::instance()->setOffset(offset);
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::getClock_timeval(timeval* time) {
timeval uptime = getUptime();
timeval offset = Timekeeper::instance()->getOffset();
*time = offset + uptime;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::getUptime(timeval* uptime) {
*uptime = getUptime();
return HasReturnvaluesIF::RETURN_OK;
}
timeval Clock::getUptime() {
TickType_t ticksSinceStart = xTaskGetTickCount();
return Timekeeper::ticksToTimeval(ticksSinceStart);
}
ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) {
timeval uptime = getUptime();
*uptimeMs = uptime.tv_sec * 1000 + uptime.tv_usec / 1000;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
timeval time_timeval;
ReturnValue_t result = getClock_timeval(&time_timeval);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
*time = time_timeval.tv_sec * 1000000 + time_timeval.tv_usec;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
timeval time_timeval;
ReturnValue_t result = getClock_timeval(&time_timeval);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
struct tm time_tm;
gmtime_r(&time_timeval.tv_sec,&time_tm);
time->year = time_tm.tm_year + 1900;
time->month = time_tm.tm_mon + 1;
time->day = time_tm.tm_mday;
time->hour = time_tm.tm_hour;
time->minute = time_tm.tm_min;
time->second = time_tm.tm_sec;
time->usecond = time_timeval.tv_usec;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from,
timeval* to) {
struct tm time_tm;
time_tm.tm_year = from->year - 1900;
time_tm.tm_mon = from->month - 1;
time_tm.tm_mday = from->day;
time_tm.tm_hour = from->hour;
time_tm.tm_min = from->minute;
time_tm.tm_sec = from->second;
time_t seconds = mktime(&time_tm);
to->tv_sec = seconds;
to->tv_usec = from->usecond;
//Fails in 2038..
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 == nullptr) {
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,114 +1,114 @@
#include "../../osal/FreeRTOS/CountingSemaphUsingTask.h"
#include "../../osal/FreeRTOS/TaskManagement.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
CountingSemaphoreUsingTask::CountingSemaphoreUsingTask(const uint8_t maxCount,
uint8_t initCount): maxCount(maxCount) {
if(initCount > maxCount) {
sif::error << "CountingSemaphoreUsingTask: Max count bigger than "
"intial cout. Setting initial count to max count." << std::endl;
initCount = maxCount;
}
handle = TaskManagement::getCurrentTaskHandle();
if(handle == nullptr) {
sif::error << "CountingSemaphoreUsingTask: Could not retrieve task "
"handle. Please ensure the constructor was called inside a "
"task." << std::endl;
}
uint32_t oldNotificationValue;
xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite,
&oldNotificationValue);
if(oldNotificationValue != 0) {
sif::warning << "CountinSemaphoreUsingTask: Semaphore initiated but "
"current notification value is not 0. Please ensure the "
"notification value is not used for other purposes!" << std::endl;
}
for(int i = 0; i < initCount; i++) {
xTaskNotifyGive(handle);
}
}
CountingSemaphoreUsingTask::~CountingSemaphoreUsingTask() {
// Clear notification value on destruction.
// If this is not desired, don't call the destructor
// (or implement a boolean which disables the reset)
xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, nullptr);
}
ReturnValue_t CountingSemaphoreUsingTask::acquire(TimeoutType timeoutType,
uint32_t timeoutMs) {
TickType_t timeout = 0;
if(timeoutType == TimeoutType::POLLING) {
timeout = 0;
}
else if(timeoutType == TimeoutType::WAITING){
timeout = pdMS_TO_TICKS(timeoutMs);
}
else {
timeout = portMAX_DELAY;
}
return acquireWithTickTimeout(timeoutType, timeout);
}
ReturnValue_t CountingSemaphoreUsingTask::acquireWithTickTimeout(
TimeoutType timeoutType, TickType_t timeoutTicks) {
// Decrement notfication value without resetting it.
BaseType_t oldCount = ulTaskNotifyTake(pdFALSE, timeoutTicks);
if (getSemaphoreCounter() == oldCount - 1) {
return HasReturnvaluesIF::RETURN_OK;
}
else {
return SemaphoreIF::SEMAPHORE_TIMEOUT;
}
}
ReturnValue_t CountingSemaphoreUsingTask::release() {
if(getSemaphoreCounter() == maxCount) {
return SemaphoreIF::SEMAPHORE_NOT_OWNED;
}
return release(handle);
}
ReturnValue_t CountingSemaphoreUsingTask::release(
TaskHandle_t taskToNotify) {
BaseType_t returncode = xTaskNotifyGive(taskToNotify);
if (returncode == pdPASS) {
return HasReturnvaluesIF::RETURN_OK;
}
else {
// This should never happen.
return HasReturnvaluesIF::RETURN_FAILED;
}
}
uint8_t CountingSemaphoreUsingTask::getSemaphoreCounter() const {
uint32_t notificationValue = 0;
xTaskNotifyAndQuery(handle, 0, eNoAction, &notificationValue);
return notificationValue;
}
TaskHandle_t CountingSemaphoreUsingTask::getTaskHandle() {
return handle;
}
ReturnValue_t CountingSemaphoreUsingTask::releaseFromISR(
TaskHandle_t taskToNotify, BaseType_t* higherPriorityTaskWoken) {
vTaskNotifyGiveFromISR(taskToNotify, higherPriorityTaskWoken);
return HasReturnvaluesIF::RETURN_OK;
}
uint8_t CountingSemaphoreUsingTask::getSemaphoreCounterFromISR(
TaskHandle_t task, BaseType_t* higherPriorityTaskWoken) {
uint32_t notificationValue;
xTaskNotifyAndQueryFromISR(task, 0, eNoAction, &notificationValue,
higherPriorityTaskWoken);
return notificationValue;
}
uint8_t CountingSemaphoreUsingTask::getMaxCount() const {
return maxCount;
}
#include "../../osal/FreeRTOS/CountingSemaphUsingTask.h"
#include "../../osal/FreeRTOS/TaskManagement.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
CountingSemaphoreUsingTask::CountingSemaphoreUsingTask(const uint8_t maxCount,
uint8_t initCount): maxCount(maxCount) {
if(initCount > maxCount) {
sif::error << "CountingSemaphoreUsingTask: Max count bigger than "
"intial cout. Setting initial count to max count." << std::endl;
initCount = maxCount;
}
handle = TaskManagement::getCurrentTaskHandle();
if(handle == nullptr) {
sif::error << "CountingSemaphoreUsingTask: Could not retrieve task "
"handle. Please ensure the constructor was called inside a "
"task." << std::endl;
}
uint32_t oldNotificationValue;
xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite,
&oldNotificationValue);
if(oldNotificationValue != 0) {
sif::warning << "CountinSemaphoreUsingTask: Semaphore initiated but "
"current notification value is not 0. Please ensure the "
"notification value is not used for other purposes!" << std::endl;
}
for(int i = 0; i < initCount; i++) {
xTaskNotifyGive(handle);
}
}
CountingSemaphoreUsingTask::~CountingSemaphoreUsingTask() {
// Clear notification value on destruction.
// If this is not desired, don't call the destructor
// (or implement a boolean which disables the reset)
xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, nullptr);
}
ReturnValue_t CountingSemaphoreUsingTask::acquire(TimeoutType timeoutType,
uint32_t timeoutMs) {
TickType_t timeout = 0;
if(timeoutType == TimeoutType::POLLING) {
timeout = 0;
}
else if(timeoutType == TimeoutType::WAITING){
timeout = pdMS_TO_TICKS(timeoutMs);
}
else {
timeout = portMAX_DELAY;
}
return acquireWithTickTimeout(timeoutType, timeout);
}
ReturnValue_t CountingSemaphoreUsingTask::acquireWithTickTimeout(
TimeoutType timeoutType, TickType_t timeoutTicks) {
// Decrement notfication value without resetting it.
BaseType_t oldCount = ulTaskNotifyTake(pdFALSE, timeoutTicks);
if (getSemaphoreCounter() == oldCount - 1) {
return HasReturnvaluesIF::RETURN_OK;
}
else {
return SemaphoreIF::SEMAPHORE_TIMEOUT;
}
}
ReturnValue_t CountingSemaphoreUsingTask::release() {
if(getSemaphoreCounter() == maxCount) {
return SemaphoreIF::SEMAPHORE_NOT_OWNED;
}
return release(handle);
}
ReturnValue_t CountingSemaphoreUsingTask::release(
TaskHandle_t taskToNotify) {
BaseType_t returncode = xTaskNotifyGive(taskToNotify);
if (returncode == pdPASS) {
return HasReturnvaluesIF::RETURN_OK;
}
else {
// This should never happen.
return HasReturnvaluesIF::RETURN_FAILED;
}
}
uint8_t CountingSemaphoreUsingTask::getSemaphoreCounter() const {
uint32_t notificationValue = 0;
xTaskNotifyAndQuery(handle, 0, eNoAction, &notificationValue);
return notificationValue;
}
TaskHandle_t CountingSemaphoreUsingTask::getTaskHandle() {
return handle;
}
ReturnValue_t CountingSemaphoreUsingTask::releaseFromISR(
TaskHandle_t taskToNotify, BaseType_t* higherPriorityTaskWoken) {
vTaskNotifyGiveFromISR(taskToNotify, higherPriorityTaskWoken);
return HasReturnvaluesIF::RETURN_OK;
}
uint8_t CountingSemaphoreUsingTask::getSemaphoreCounterFromISR(
TaskHandle_t task, BaseType_t* higherPriorityTaskWoken) {
uint32_t notificationValue;
xTaskNotifyAndQueryFromISR(task, 0, eNoAction, &notificationValue,
higherPriorityTaskWoken);
return notificationValue;
}
uint8_t CountingSemaphoreUsingTask::getMaxCount() const {
return maxCount;
}

View File

@ -1,105 +1,105 @@
#ifndef FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_
#define FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_
#include "../../osal/FreeRTOS/CountingSemaphUsingTask.h"
#include "../../tasks/SemaphoreIF.h"
extern "C" {
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
}
/**
* @brief Couting Semaphore implementation which uses the notification value
* of the task. The notification value should therefore not be used
* for other purposes.
* @details
* Additional information: https://www.freertos.org/RTOS-task-notifications.html
* and general semaphore documentation.
* This semaphore is bound to the task it is created in!
* Take care of calling this function with the correct executing task,
* (for example in the initializeAfterTaskCreation() function).
*/
class CountingSemaphoreUsingTask: public SemaphoreIF {
public:
CountingSemaphoreUsingTask(const uint8_t maxCount, uint8_t initCount);
virtual ~CountingSemaphoreUsingTask();
/**
* Acquire the counting semaphore.
* If no semaphores are available, the task will be blocked
* for a maximum of #timeoutMs or until one 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 = portMAX_DELAY) override;
/**
* Release a semaphore, increasing the number of available counting
* semaphores up to the #maxCount value.
* @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are
* already available.
*/
ReturnValue_t release() override;
uint8_t getSemaphoreCounter() const override;
/**
* Get the semaphore counter from an ISR.
* @param task
* @param higherPriorityTaskWoken This will be set to pdPASS if a task with
* a higher priority was unblocked. A context switch should be requested
* from an ISR if this is the case (see TaskManagement functions)
* @return
*/
static uint8_t getSemaphoreCounterFromISR(TaskHandle_t task,
BaseType_t* higherPriorityTaskWoken);
/**
* Acquire with a timeout value in ticks
* @param timeoutTicks
* @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout
*/
ReturnValue_t acquireWithTickTimeout(
TimeoutType timeoutType = TimeoutType::BLOCKING,
TickType_t timeoutTicks = portMAX_DELAY);
/**
* Get handle to the task related to the semaphore.
* @return
*/
TaskHandle_t getTaskHandle();
/**
* Release semaphore of task by supplying task handle
* @param taskToNotify
* @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are
* already available.
*/
static ReturnValue_t release(TaskHandle_t taskToNotify);
/**
* Release seamphore of a task from an ISR.
* @param taskToNotify
* @param higherPriorityTaskWoken This will be set to pdPASS if a task with
* a higher priority was unblocked. A context switch should be requested
* from an ISR if this is the case (see TaskManagement functions)
* @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are
* already available.
*/
static ReturnValue_t releaseFromISR(TaskHandle_t taskToNotify,
BaseType_t* higherPriorityTaskWoken);
uint8_t getMaxCount() const;
private:
TaskHandle_t handle;
const uint8_t maxCount;
};
#endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ */
#ifndef FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_
#define FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_
#include "../../osal/FreeRTOS/CountingSemaphUsingTask.h"
#include "../../tasks/SemaphoreIF.h"
extern "C" {
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
}
/**
* @brief Couting Semaphore implementation which uses the notification value
* of the task. The notification value should therefore not be used
* for other purposes.
* @details
* Additional information: https://www.freertos.org/RTOS-task-notifications.html
* and general semaphore documentation.
* This semaphore is bound to the task it is created in!
* Take care of calling this function with the correct executing task,
* (for example in the initializeAfterTaskCreation() function).
*/
class CountingSemaphoreUsingTask: public SemaphoreIF {
public:
CountingSemaphoreUsingTask(const uint8_t maxCount, uint8_t initCount);
virtual ~CountingSemaphoreUsingTask();
/**
* Acquire the counting semaphore.
* If no semaphores are available, the task will be blocked
* for a maximum of #timeoutMs or until one 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 = portMAX_DELAY) override;
/**
* Release a semaphore, increasing the number of available counting
* semaphores up to the #maxCount value.
* @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are
* already available.
*/
ReturnValue_t release() override;
uint8_t getSemaphoreCounter() const override;
/**
* Get the semaphore counter from an ISR.
* @param task
* @param higherPriorityTaskWoken This will be set to pdPASS if a task with
* a higher priority was unblocked. A context switch should be requested
* from an ISR if this is the case (see TaskManagement functions)
* @return
*/
static uint8_t getSemaphoreCounterFromISR(TaskHandle_t task,
BaseType_t* higherPriorityTaskWoken);
/**
* Acquire with a timeout value in ticks
* @param timeoutTicks
* @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout
*/
ReturnValue_t acquireWithTickTimeout(
TimeoutType timeoutType = TimeoutType::BLOCKING,
TickType_t timeoutTicks = portMAX_DELAY);
/**
* Get handle to the task related to the semaphore.
* @return
*/
TaskHandle_t getTaskHandle();
/**
* Release semaphore of task by supplying task handle
* @param taskToNotify
* @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are
* already available.
*/
static ReturnValue_t release(TaskHandle_t taskToNotify);
/**
* Release seamphore of a task from an ISR.
* @param taskToNotify
* @param higherPriorityTaskWoken This will be set to pdPASS if a task with
* a higher priority was unblocked. A context switch should be requested
* from an ISR if this is the case (see TaskManagement functions)
* @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are
* already available.
*/
static ReturnValue_t releaseFromISR(TaskHandle_t taskToNotify,
BaseType_t* higherPriorityTaskWoken);
uint8_t getMaxCount() const;
private:
TaskHandle_t handle;
const uint8_t maxCount;
};
#endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ */

View File

@ -1,43 +1,43 @@
#include "../../osal/FreeRTOS/CountingSemaphore.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../osal/FreeRTOS/TaskManagement.h"
#include <freertos/semphr.h>
// Make sure #define configUSE_COUNTING_SEMAPHORES 1 is set in
// free FreeRTOSConfig.h file.
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;
}
handle = xSemaphoreCreateCounting(maxCount, initCount);
if(handle == nullptr) {
sif::error << "CountingSemaphore: Creation failure" << std::endl;
}
}
CountingSemaphore::CountingSemaphore(CountingSemaphore&& other):
maxCount(other.maxCount), initCount(other.initCount) {
handle = xSemaphoreCreateCounting(other.maxCount, other.initCount);
if(handle == nullptr) {
sif::error << "CountingSemaphore: Creation failure" << std::endl;
}
}
CountingSemaphore& CountingSemaphore::operator =(
CountingSemaphore&& other) {
handle = xSemaphoreCreateCounting(other.maxCount, other.initCount);
if(handle == nullptr) {
sif::error << "CountingSemaphore: Creation failure" << std::endl;
}
return * this;
}
uint8_t CountingSemaphore::getMaxCount() const {
return maxCount;
}
#include "../../osal/FreeRTOS/CountingSemaphore.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../osal/FreeRTOS/TaskManagement.h"
#include <freertos/semphr.h>
// Make sure #define configUSE_COUNTING_SEMAPHORES 1 is set in
// free FreeRTOSConfig.h file.
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;
}
handle = xSemaphoreCreateCounting(maxCount, initCount);
if(handle == nullptr) {
sif::error << "CountingSemaphore: Creation failure" << std::endl;
}
}
CountingSemaphore::CountingSemaphore(CountingSemaphore&& other):
maxCount(other.maxCount), initCount(other.initCount) {
handle = xSemaphoreCreateCounting(other.maxCount, other.initCount);
if(handle == nullptr) {
sif::error << "CountingSemaphore: Creation failure" << std::endl;
}
}
CountingSemaphore& CountingSemaphore::operator =(
CountingSemaphore&& other) {
handle = xSemaphoreCreateCounting(other.maxCount, other.initCount);
if(handle == nullptr) {
sif::error << "CountingSemaphore: Creation failure" << std::endl;
}
return * this;
}
uint8_t CountingSemaphore::getMaxCount() const {
return maxCount;
}

View File

@ -1,34 +1,34 @@
#ifndef FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_
#define FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_
#include "../../osal/FreeRTOS/BinarySemaphore.h"
/**
* @brief Counting semaphores, which can be acquire 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 &&);
/* 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_FREERTOS_COUNTINGSEMAPHORE_H_
#define FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_
#include "../../osal/FreeRTOS/BinarySemaphore.h"
/**
* @brief Counting semaphores, which can be acquire 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 &&);
/* 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,166 +1,166 @@
#include "FixedTimeslotTask.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
uint32_t FixedTimeslotTask::deadlineMissedCount = 0;
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = configMINIMAL_STACK_SIZE;
FixedTimeslotTask::FixedTimeslotTask(TaskName name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod overallPeriod,
void (*setDeadlineMissedFunc)()) :
started(false), handle(nullptr), pst(overallPeriod * 1000) {
configSTACK_DEPTH_TYPE stackSize = setStack / sizeof(configSTACK_DEPTH_TYPE);
xTaskCreate(taskEntryPoint, name, stackSize, this, setPriority, &handle);
// All additional attributes are applied to the object.
this->deadlineMissedFunc = setDeadlineMissedFunc;
}
FixedTimeslotTask::~FixedTimeslotTask() {
}
void FixedTimeslotTask::taskEntryPoint(void* argument) {
// The argument is re-interpreted as FixedTimeslotTask. The Task object is
// global, so it is found from any place.
FixedTimeslotTask *originalTask(reinterpret_cast<FixedTimeslotTask*>(argument));
/* Task should not start until explicitly requested,
* but in FreeRTOS, tasks start as soon as they are created if the scheduler
* is running but not if the scheduler is not running.
* To be able to accommodate both cases we check a member which is set in
* #startTask(). If it is not set and we get here, the scheduler was started
* before #startTask() was called and we need to suspend if it is set,
* the scheduler was not running before #startTask() was called and we
* can continue */
if (not originalTask->started) {
vTaskSuspend(NULL);
}
originalTask->taskFunctionality();
sif::debug << "Polling task " << originalTask->handle
<< " returned from taskFunctionality." << std::endl;
}
void FixedTimeslotTask::missedDeadlineCounter() {
FixedTimeslotTask::deadlineMissedCount++;
if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) {
sif::error << "PST missed " << FixedTimeslotTask::deadlineMissedCount
<< " deadlines." << std::endl;
}
}
ReturnValue_t FixedTimeslotTask::startTask() {
started = true;
// We must not call resume if scheduler is not started yet
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
vTaskResume(handle);
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId,
uint32_t slotTimeMs, int8_t executionStep) {
ExecutableObjectIF* handler =
objectManager->get<ExecutableObjectIF>(componentId);
if (handler != nullptr) {
pst.addSlot(componentId, slotTimeMs, executionStep, handler, this);
return HasReturnvaluesIF::RETURN_OK;
}
sif::error << "Component " << std::hex << componentId <<
" not found, not adding it to pst" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
uint32_t FixedTimeslotTask::getPeriodMs() const {
return pst.getLengthMs();
}
ReturnValue_t FixedTimeslotTask::checkSequence() const {
return pst.checkSequence();
}
void FixedTimeslotTask::taskFunctionality() {
// A local iterator for the Polling Sequence Table is created to find the
// start time for the first entry.
auto slotListIter = pst.current;
pst.intializeSequenceAfterTaskCreation();
//The start time for the first entry is read.
uint32_t intervalMs = slotListIter->pollingTimeMs;
TickType_t interval = pdMS_TO_TICKS(intervalMs);
TickType_t xLastWakeTime;
/* The xLastWakeTime variable needs to be initialized with the current tick
count. Note that this is the only time the variable is written to
explicitly. After this assignment, xLastWakeTime is updated automatically
internally within vTaskDelayUntil(). */
xLastWakeTime = xTaskGetTickCount();
// wait for first entry's start time
if(interval > 0) {
vTaskDelayUntil(&xLastWakeTime, interval);
}
/* Enter the loop that defines the task behavior. */
for (;;) {
//The component for this slot is executed and the next one is chosen.
this->pst.executeAndAdvance();
if (not pst.slotFollowsImmediately()) {
// Get the interval till execution of the next slot.
intervalMs = this->pst.getIntervalToPreviousSlotMs();
interval = pdMS_TO_TICKS(intervalMs);
checkMissedDeadline(xLastWakeTime, interval);
// Wait for the interval. This exits immediately if a deadline was
// missed while also updating the last wake time.
vTaskDelayUntil(&xLastWakeTime, interval);
}
}
}
void FixedTimeslotTask::checkMissedDeadline(const TickType_t xLastWakeTime,
const TickType_t interval) {
/* Check whether deadline was missed while also taking overflows
* into account. Drawing this on paper with a timeline helps to understand
* it. */
TickType_t currentTickCount = xTaskGetTickCount();
TickType_t timeToWake = xLastWakeTime + interval;
// Time to wake has not overflown.
if(timeToWake > xLastWakeTime) {
/* If the current time has overflown exclusively or the current
* tick count is simply larger than the time to wake, a deadline was
* missed */
if((currentTickCount < xLastWakeTime) or (currentTickCount > timeToWake)) {
handleMissedDeadline();
}
}
/* Time to wake has overflown. A deadline was missed if the current time
* is larger than the time to wake */
else if((timeToWake < xLastWakeTime) and (currentTickCount > timeToWake)) {
handleMissedDeadline();
}
}
void FixedTimeslotTask::handleMissedDeadline() {
#ifdef DEBUG
sif::warning << "FixedTimeslotTask: " << pcTaskGetName(NULL) <<
" missed deadline!\n" << std::flush;
#endif
if(deadlineMissedFunc != nullptr) {
this->deadlineMissedFunc();
}
}
ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) {
vTaskDelay(pdMS_TO_TICKS(ms));
return HasReturnvaluesIF::RETURN_OK;
}
TaskHandle_t FixedTimeslotTask::getTaskHandle() {
return handle;
}
#include "FixedTimeslotTask.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
uint32_t FixedTimeslotTask::deadlineMissedCount = 0;
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = configMINIMAL_STACK_SIZE;
FixedTimeslotTask::FixedTimeslotTask(TaskName name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod overallPeriod,
void (*setDeadlineMissedFunc)()) :
started(false), handle(nullptr), pst(overallPeriod * 1000) {
configSTACK_DEPTH_TYPE stackSize = setStack / sizeof(configSTACK_DEPTH_TYPE);
xTaskCreate(taskEntryPoint, name, stackSize, this, setPriority, &handle);
// All additional attributes are applied to the object.
this->deadlineMissedFunc = setDeadlineMissedFunc;
}
FixedTimeslotTask::~FixedTimeslotTask() {
}
void FixedTimeslotTask::taskEntryPoint(void* argument) {
// The argument is re-interpreted as FixedTimeslotTask. The Task object is
// global, so it is found from any place.
FixedTimeslotTask *originalTask(reinterpret_cast<FixedTimeslotTask*>(argument));
/* Task should not start until explicitly requested,
* but in FreeRTOS, tasks start as soon as they are created if the scheduler
* is running but not if the scheduler is not running.
* To be able to accommodate both cases we check a member which is set in
* #startTask(). If it is not set and we get here, the scheduler was started
* before #startTask() was called and we need to suspend if it is set,
* the scheduler was not running before #startTask() was called and we
* can continue */
if (not originalTask->started) {
vTaskSuspend(NULL);
}
originalTask->taskFunctionality();
sif::debug << "Polling task " << originalTask->handle
<< " returned from taskFunctionality." << std::endl;
}
void FixedTimeslotTask::missedDeadlineCounter() {
FixedTimeslotTask::deadlineMissedCount++;
if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) {
sif::error << "PST missed " << FixedTimeslotTask::deadlineMissedCount
<< " deadlines." << std::endl;
}
}
ReturnValue_t FixedTimeslotTask::startTask() {
started = true;
// We must not call resume if scheduler is not started yet
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
vTaskResume(handle);
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId,
uint32_t slotTimeMs, int8_t executionStep) {
ExecutableObjectIF* handler =
objectManager->get<ExecutableObjectIF>(componentId);
if (handler != nullptr) {
pst.addSlot(componentId, slotTimeMs, executionStep, handler, this);
return HasReturnvaluesIF::RETURN_OK;
}
sif::error << "Component " << std::hex << componentId <<
" not found, not adding it to pst" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
uint32_t FixedTimeslotTask::getPeriodMs() const {
return pst.getLengthMs();
}
ReturnValue_t FixedTimeslotTask::checkSequence() const {
return pst.checkSequence();
}
void FixedTimeslotTask::taskFunctionality() {
// A local iterator for the Polling Sequence Table is created to find the
// start time for the first entry.
auto slotListIter = pst.current;
pst.intializeSequenceAfterTaskCreation();
//The start time for the first entry is read.
uint32_t intervalMs = slotListIter->pollingTimeMs;
TickType_t interval = pdMS_TO_TICKS(intervalMs);
TickType_t xLastWakeTime;
/* The xLastWakeTime variable needs to be initialized with the current tick
count. Note that this is the only time the variable is written to
explicitly. After this assignment, xLastWakeTime is updated automatically
internally within vTaskDelayUntil(). */
xLastWakeTime = xTaskGetTickCount();
// wait for first entry's start time
if(interval > 0) {
vTaskDelayUntil(&xLastWakeTime, interval);
}
/* Enter the loop that defines the task behavior. */
for (;;) {
//The component for this slot is executed and the next one is chosen.
this->pst.executeAndAdvance();
if (not pst.slotFollowsImmediately()) {
// Get the interval till execution of the next slot.
intervalMs = this->pst.getIntervalToPreviousSlotMs();
interval = pdMS_TO_TICKS(intervalMs);
checkMissedDeadline(xLastWakeTime, interval);
// Wait for the interval. This exits immediately if a deadline was
// missed while also updating the last wake time.
vTaskDelayUntil(&xLastWakeTime, interval);
}
}
}
void FixedTimeslotTask::checkMissedDeadline(const TickType_t xLastWakeTime,
const TickType_t interval) {
/* Check whether deadline was missed while also taking overflows
* into account. Drawing this on paper with a timeline helps to understand
* it. */
TickType_t currentTickCount = xTaskGetTickCount();
TickType_t timeToWake = xLastWakeTime + interval;
// Time to wake has not overflown.
if(timeToWake > xLastWakeTime) {
/* If the current time has overflown exclusively or the current
* tick count is simply larger than the time to wake, a deadline was
* missed */
if((currentTickCount < xLastWakeTime) or (currentTickCount > timeToWake)) {
handleMissedDeadline();
}
}
/* Time to wake has overflown. A deadline was missed if the current time
* is larger than the time to wake */
else if((timeToWake < xLastWakeTime) and (currentTickCount > timeToWake)) {
handleMissedDeadline();
}
}
void FixedTimeslotTask::handleMissedDeadline() {
#ifdef DEBUG
sif::warning << "FixedTimeslotTask: " << pcTaskGetName(NULL) <<
" missed deadline!\n" << std::flush;
#endif
if(deadlineMissedFunc != nullptr) {
this->deadlineMissedFunc();
}
}
ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) {
vTaskDelay(pdMS_TO_TICKS(ms));
return HasReturnvaluesIF::RETURN_OK;
}
TaskHandle_t FixedTimeslotTask::getTaskHandle() {
return handle;
}

View File

@ -1,101 +1,101 @@
#ifndef FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_
#define FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_
#include "../../osal/FreeRTOS/FreeRTOSTaskIF.h"
#include "../../tasks/FixedSlotSequence.h"
#include "../../tasks/FixedTimeslotTaskIF.h"
#include "../../tasks/Typedef.h"
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
class FixedTimeslotTask: public FixedTimeslotTaskIF, public FreeRTOSTaskIF {
public:
/**
* Keep in mind that you need to call before vTaskStartScheduler()!
* A lot of task parameters are set in "FreeRTOSConfig.h".
* @param name Name of the task, lenght limited by configMAX_TASK_NAME_LEN
* @param setPriority Number of priorities specified by
* configMAX_PRIORITIES. High taskPriority_ number means high priority.
* @param setStack Stack size in words (not bytes!).
* Lower limit specified by configMINIMAL_STACK_SIZE
* @param overallPeriod Period in seconds.
* @param setDeadlineMissedFunc Callback if a deadline was missed.
* @return Pointer to the newly created task.
*/
FixedTimeslotTask(TaskName name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod overallPeriod,
void (*setDeadlineMissedFunc)());
/**
* @brief The destructor of the class.
* @details
* The destructor frees all heap memory that was allocated on thread
* initialization for the PST and the device handlers. This is done by
* calling the PST's destructor.
*/
virtual ~FixedTimeslotTask(void);
ReturnValue_t startTask(void);
/**
* This static function can be used as #deadlineMissedFunc.
* It counts missedDeadlines and prints the number of missed deadlines
* every 10th time.
*/
static void missedDeadlineCounter();
/**
* A helper variable to count missed deadlines.
*/
static uint32_t deadlineMissedCount;
ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs,
int8_t executionStep) override;
uint32_t getPeriodMs() const override;
ReturnValue_t checkSequence() const override;
ReturnValue_t sleepFor(uint32_t ms) override;
TaskHandle_t getTaskHandle() override;
protected:
bool started;
TaskHandle_t handle;
FixedSlotSequence pst;
/**
* @brief This attribute holds a function pointer that is executed when
* a deadline was missed.
* @details
* Another function may be announced to determine the actions to perform
* when a deadline was missed. Currently, only one function for missing
* any deadline is allowed. If not used, it shall be declared NULL.
*/
void (*deadlineMissedFunc)(void);
/**
* @brief This is the entry point for a new task.
* @details
* This method starts the task by calling taskFunctionality(), as soon as
* all requirements (task scheduler has started and startTask()
* has been called) are met.
*/
static void taskEntryPoint(void* argument);
/**
* @brief This function holds the main functionality of the thread.
* @details
* Core function holding the main functionality of the task
* It links the functionalities provided by FixedSlotSequence with the
* OS's System Calls to keep the timing of the periods.
*/
void taskFunctionality(void);
void checkMissedDeadline(const TickType_t xLastWakeTime,
const TickType_t interval);
void handleMissedDeadline();
};
#endif /* POLLINGTASK_H_ */
#ifndef FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_
#define FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_
#include "../../osal/FreeRTOS/FreeRTOSTaskIF.h"
#include "../../tasks/FixedSlotSequence.h"
#include "../../tasks/FixedTimeslotTaskIF.h"
#include "../../tasks/Typedef.h"
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
class FixedTimeslotTask: public FixedTimeslotTaskIF, public FreeRTOSTaskIF {
public:
/**
* Keep in mind that you need to call before vTaskStartScheduler()!
* A lot of task parameters are set in "FreeRTOSConfig.h".
* @param name Name of the task, lenght limited by configMAX_TASK_NAME_LEN
* @param setPriority Number of priorities specified by
* configMAX_PRIORITIES. High taskPriority_ number means high priority.
* @param setStack Stack size in words (not bytes!).
* Lower limit specified by configMINIMAL_STACK_SIZE
* @param overallPeriod Period in seconds.
* @param setDeadlineMissedFunc Callback if a deadline was missed.
* @return Pointer to the newly created task.
*/
FixedTimeslotTask(TaskName name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod overallPeriod,
void (*setDeadlineMissedFunc)());
/**
* @brief The destructor of the class.
* @details
* The destructor frees all heap memory that was allocated on thread
* initialization for the PST and the device handlers. This is done by
* calling the PST's destructor.
*/
virtual ~FixedTimeslotTask(void);
ReturnValue_t startTask(void);
/**
* This static function can be used as #deadlineMissedFunc.
* It counts missedDeadlines and prints the number of missed deadlines
* every 10th time.
*/
static void missedDeadlineCounter();
/**
* A helper variable to count missed deadlines.
*/
static uint32_t deadlineMissedCount;
ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs,
int8_t executionStep) override;
uint32_t getPeriodMs() const override;
ReturnValue_t checkSequence() const override;
ReturnValue_t sleepFor(uint32_t ms) override;
TaskHandle_t getTaskHandle() override;
protected:
bool started;
TaskHandle_t handle;
FixedSlotSequence pst;
/**
* @brief This attribute holds a function pointer that is executed when
* a deadline was missed.
* @details
* Another function may be announced to determine the actions to perform
* when a deadline was missed. Currently, only one function for missing
* any deadline is allowed. If not used, it shall be declared NULL.
*/
void (*deadlineMissedFunc)(void);
/**
* @brief This is the entry point for a new task.
* @details
* This method starts the task by calling taskFunctionality(), as soon as
* all requirements (task scheduler has started and startTask()
* has been called) are met.
*/
static void taskEntryPoint(void* argument);
/**
* @brief This function holds the main functionality of the thread.
* @details
* Core function holding the main functionality of the task
* It links the functionalities provided by FixedSlotSequence with the
* OS's System Calls to keep the timing of the periods.
*/
void taskFunctionality(void);
void checkMissedDeadline(const TickType_t xLastWakeTime,
const TickType_t interval);
void handleMissedDeadline();
};
#endif /* POLLINGTASK_H_ */

View File

@ -1,149 +1,149 @@
#ifndef FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_
#define FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_
#include "../../internalError/InternalErrorReporterIF.h"
#include "../../ipc/MessageQueueIF.h"
#include "../../ipc/MessageQueueMessageIF.h"
#include "../../osal/FreeRTOS/TaskManagement.h"
#include <freertos/FreeRTOS.h>
#include <freertos/queue.h>
// TODO: this class assumes that MessageQueueId_t is the same size as void*
// (the FreeRTOS handle type), compiler will catch this but it might be nice
// to have something checking or even an always working solution
// https://scaryreasoner.wordpress.com/2009/02/28/checking-sizeof-at-compile-time/
/**
* @brief This class manages sending and receiving of
* message queue messages.
* @details
* Message queues are used to pass asynchronous messages between processes.
* They work like post boxes, where all incoming messages are stored in FIFO
* order. This class creates a new receiving queue and provides methods to fetch
* received messages. Being a child of MessageQueueSender, this class also
* provides methods to send a message to a user-defined or a default destination.
* In addition it also provides a reply method to answer to the queue it
* received its last message from.
*
* The MessageQueue should be used as "post box" for a single owning object.
* So all message queue communication is "n-to-one".
* For creating the queue, as well as sending and receiving messages, the class
* makes use of the operating system calls provided.
*
* Please keep in mind that FreeRTOS offers different calls for message queue
* operations if called from an ISR.
* For now, the system context needs to be switched manually.
* @ingroup osal
* @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
* in case of failure, it is set to zero.
* @param message_depth
* The number of messages to be buffered before passing an error to the
* sender. Default is three.
* @param max_message_size
* With this parameter, the maximum message size can be adjusted.
* This should be left default.
*/
MessageQueue( size_t messageDepth = 3,
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE );
/** Copying message queues forbidden */
MessageQueue(const MessageQueue&) = delete;
MessageQueue& operator=(const MessageQueue&) = delete;
/**
* @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();
/**
* This function is used to switch the call context. This has to be called
* if a message is sent or received from an ISR!
* @param callContext
*/
void switchSystemContext(CallContext callContext);
/** MessageQueueIF implementation */
ReturnValue_t sendMessage(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, bool ignoreFault = false) override;
ReturnValue_t sendToDefault(MessageQueueMessageIF* message) override;
ReturnValue_t reply(MessageQueueMessageIF* message) override;
virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo,
MessageQueueMessageIF* message,
MessageQueueId_t sentFrom = NO_QUEUE,
bool ignoreFault = false) override;
virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessageIF* message,
MessageQueueId_t sentFrom = NO_QUEUE,
bool ignoreFault = false) override;
ReturnValue_t receiveMessage(MessageQueueMessageIF* message,
MessageQueueId_t *receivedFrom) override;
ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override;
ReturnValue_t flush(uint32_t* count) override;
MessageQueueId_t getLastPartner() const override;
MessageQueueId_t getId() const override;
void setDefaultDestination(MessageQueueId_t defaultDestination) override;
MessageQueueId_t getDefaultDestination() const override;
bool isDefaultDestinationSet() const override;
protected:
/**
* @brief 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.
* @param context Specify whether call is made from task or from an ISR.
*/
static ReturnValue_t sendMessageFromMessageQueue(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE,
bool ignoreFault=false, CallContext callContext = CallContext::TASK);
static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault);
private:
bool defaultDestinationSet = false;
QueueHandle_t handle;
MessageQueueId_t defaultDestination = 0;
MessageQueueId_t lastPartner = 0;
const size_t maxMessageSize;
//! Stores the current system context
CallContext callContext = CallContext::TASK;
};
#endif /* FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_ */
#ifndef FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_
#define FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_
#include "../../internalError/InternalErrorReporterIF.h"
#include "../../ipc/MessageQueueIF.h"
#include "../../ipc/MessageQueueMessageIF.h"
#include "../../osal/FreeRTOS/TaskManagement.h"
#include <freertos/FreeRTOS.h>
#include <freertos/queue.h>
// TODO: this class assumes that MessageQueueId_t is the same size as void*
// (the FreeRTOS handle type), compiler will catch this but it might be nice
// to have something checking or even an always working solution
// https://scaryreasoner.wordpress.com/2009/02/28/checking-sizeof-at-compile-time/
/**
* @brief This class manages sending and receiving of
* message queue messages.
* @details
* Message queues are used to pass asynchronous messages between processes.
* They work like post boxes, where all incoming messages are stored in FIFO
* order. This class creates a new receiving queue and provides methods to fetch
* received messages. Being a child of MessageQueueSender, this class also
* provides methods to send a message to a user-defined or a default destination.
* In addition it also provides a reply method to answer to the queue it
* received its last message from.
*
* The MessageQueue should be used as "post box" for a single owning object.
* So all message queue communication is "n-to-one".
* For creating the queue, as well as sending and receiving messages, the class
* makes use of the operating system calls provided.
*
* Please keep in mind that FreeRTOS offers different calls for message queue
* operations if called from an ISR.
* For now, the system context needs to be switched manually.
* @ingroup osal
* @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
* in case of failure, it is set to zero.
* @param message_depth
* The number of messages to be buffered before passing an error to the
* sender. Default is three.
* @param max_message_size
* With this parameter, the maximum message size can be adjusted.
* This should be left default.
*/
MessageQueue( size_t messageDepth = 3,
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE );
/** Copying message queues forbidden */
MessageQueue(const MessageQueue&) = delete;
MessageQueue& operator=(const MessageQueue&) = delete;
/**
* @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();
/**
* This function is used to switch the call context. This has to be called
* if a message is sent or received from an ISR!
* @param callContext
*/
void switchSystemContext(CallContext callContext);
/** MessageQueueIF implementation */
ReturnValue_t sendMessage(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, bool ignoreFault = false) override;
ReturnValue_t sendToDefault(MessageQueueMessageIF* message) override;
ReturnValue_t reply(MessageQueueMessageIF* message) override;
virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo,
MessageQueueMessageIF* message,
MessageQueueId_t sentFrom = NO_QUEUE,
bool ignoreFault = false) override;
virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessageIF* message,
MessageQueueId_t sentFrom = NO_QUEUE,
bool ignoreFault = false) override;
ReturnValue_t receiveMessage(MessageQueueMessageIF* message,
MessageQueueId_t *receivedFrom) override;
ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override;
ReturnValue_t flush(uint32_t* count) override;
MessageQueueId_t getLastPartner() const override;
MessageQueueId_t getId() const override;
void setDefaultDestination(MessageQueueId_t defaultDestination) override;
MessageQueueId_t getDefaultDestination() const override;
bool isDefaultDestinationSet() const override;
protected:
/**
* @brief 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.
* @param context Specify whether call is made from task or from an ISR.
*/
static ReturnValue_t sendMessageFromMessageQueue(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE,
bool ignoreFault=false, CallContext callContext = CallContext::TASK);
static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault);
private:
bool defaultDestinationSet = false;
QueueHandle_t handle;
MessageQueueId_t defaultDestination = 0;
MessageQueueId_t lastPartner = 0;
const size_t maxMessageSize;
//! Stores the current system context
CallContext callContext = CallContext::TASK;
};
#endif /* FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_ */

View File

@ -1,51 +1,51 @@
#include "../../osal/FreeRTOS/Mutex.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
Mutex::Mutex() {
handle = xSemaphoreCreateMutex();
if(handle == nullptr) {
sif::error << "Mutex::Mutex(FreeRTOS): Creation failure" << std::endl;
}
}
Mutex::~Mutex() {
if (handle != nullptr) {
vSemaphoreDelete(handle);
}
}
ReturnValue_t Mutex::lockMutex(TimeoutType timeoutType,
uint32_t timeoutMs) {
if (handle == nullptr) {
return MutexIF::MUTEX_NOT_FOUND;
}
// If the timeout type is BLOCKING, this will be the correct value.
uint32_t timeout = portMAX_DELAY;
if(timeoutType == TimeoutType::POLLING) {
timeout = 0;
}
else if(timeoutType == TimeoutType::WAITING){
timeout = pdMS_TO_TICKS(timeoutMs);
}
BaseType_t returncode = xSemaphoreTake(handle, timeout);
if (returncode == pdPASS) {
return HasReturnvaluesIF::RETURN_OK;
} else {
return MutexIF::MUTEX_TIMEOUT;
}
}
ReturnValue_t Mutex::unlockMutex() {
if (handle == nullptr) {
return MutexIF::MUTEX_NOT_FOUND;
}
BaseType_t returncode = xSemaphoreGive(handle);
if (returncode == pdPASS) {
return HasReturnvaluesIF::RETURN_OK;
} else {
return MutexIF::CURR_THREAD_DOES_NOT_OWN_MUTEX;
}
}
#include "../../osal/FreeRTOS/Mutex.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
Mutex::Mutex() {
handle = xSemaphoreCreateMutex();
if(handle == nullptr) {
sif::error << "Mutex::Mutex(FreeRTOS): Creation failure" << std::endl;
}
}
Mutex::~Mutex() {
if (handle != nullptr) {
vSemaphoreDelete(handle);
}
}
ReturnValue_t Mutex::lockMutex(TimeoutType timeoutType,
uint32_t timeoutMs) {
if (handle == nullptr) {
return MutexIF::MUTEX_NOT_FOUND;
}
// If the timeout type is BLOCKING, this will be the correct value.
uint32_t timeout = portMAX_DELAY;
if(timeoutType == TimeoutType::POLLING) {
timeout = 0;
}
else if(timeoutType == TimeoutType::WAITING){
timeout = pdMS_TO_TICKS(timeoutMs);
}
BaseType_t returncode = xSemaphoreTake(handle, timeout);
if (returncode == pdPASS) {
return HasReturnvaluesIF::RETURN_OK;
} else {
return MutexIF::MUTEX_TIMEOUT;
}
}
ReturnValue_t Mutex::unlockMutex() {
if (handle == nullptr) {
return MutexIF::MUTEX_NOT_FOUND;
}
BaseType_t returncode = xSemaphoreGive(handle);
if (returncode == pdPASS) {
return HasReturnvaluesIF::RETURN_OK;
} else {
return MutexIF::CURR_THREAD_DOES_NOT_OWN_MUTEX;
}
}

View File

@ -1,29 +1,29 @@
#ifndef FRAMEWORK_FREERTOS_MUTEX_H_
#define FRAMEWORK_FREERTOS_MUTEX_H_
#include "../../ipc/MutexIF.h"
#include <freertos/FreeRTOS.h>
#include <freertos/semphr.h>
/**
* @brief OS component to implement MUTual EXclusion
*
* @details
* Mutexes are binary semaphores which include a priority inheritance mechanism.
* Documentation: https://www.freertos.org/Real-time-embedded-RTOS-mutexes.html
* @ingroup osal
*/
class Mutex : public MutexIF {
public:
Mutex();
~Mutex();
ReturnValue_t lockMutex(TimeoutType timeoutType,
uint32_t timeoutMs) override;
ReturnValue_t unlockMutex() override;
private:
SemaphoreHandle_t handle;
};
#endif /* FRAMEWORK_FREERTOS_MUTEX_H_ */
#ifndef FRAMEWORK_FREERTOS_MUTEX_H_
#define FRAMEWORK_FREERTOS_MUTEX_H_
#include "../../ipc/MutexIF.h"
#include <freertos/FreeRTOS.h>
#include <freertos/semphr.h>
/**
* @brief OS component to implement MUTual EXclusion
*
* @details
* Mutexes are binary semaphores which include a priority inheritance mechanism.
* Documentation: https://www.freertos.org/Real-time-embedded-RTOS-mutexes.html
* @ingroup osal
*/
class Mutex : public MutexIF {
public:
Mutex();
~Mutex();
ReturnValue_t lockMutex(TimeoutType timeoutType,
uint32_t timeoutMs) override;
ReturnValue_t unlockMutex() override;
private:
SemaphoreHandle_t handle;
};
#endif /* FRAMEWORK_FREERTOS_MUTEX_H_ */

View File

@ -1,28 +1,28 @@
#include "../../ipc/MutexFactory.h"
#include "../../osal/FreeRTOS/Mutex.h"
//TODO: Different variant than the lazy loading in QueueFactory.
//What's better and why? -> one is on heap the other on bss/data
//MutexFactory* MutexFactory::factoryInstance = new MutexFactory();
MutexFactory* MutexFactory::factoryInstance = nullptr;
MutexFactory::MutexFactory() {
}
MutexFactory::~MutexFactory() {
}
MutexFactory* MutexFactory::instance() {
if (factoryInstance == nullptr){
factoryInstance = new MutexFactory();
}
return MutexFactory::factoryInstance;
}
MutexIF* MutexFactory::createMutex() {
return new Mutex();
}
void MutexFactory::deleteMutex(MutexIF* mutex) {
delete mutex;
}
#include "../../ipc/MutexFactory.h"
#include "../../osal/FreeRTOS/Mutex.h"
//TODO: Different variant than the lazy loading in QueueFactory.
//What's better and why? -> one is on heap the other on bss/data
//MutexFactory* MutexFactory::factoryInstance = new MutexFactory();
MutexFactory* MutexFactory::factoryInstance = nullptr;
MutexFactory::MutexFactory() {
}
MutexFactory::~MutexFactory() {
}
MutexFactory* MutexFactory::instance() {
if (factoryInstance == nullptr){
factoryInstance = new MutexFactory();
}
return MutexFactory::factoryInstance;
}
MutexIF* MutexFactory::createMutex() {
return new Mutex();
}
void MutexFactory::deleteMutex(MutexIF* mutex) {
delete mutex;
}

View File

@ -1,36 +1,36 @@
#include "../../ipc/QueueFactory.h"
#include "../../osal/FreeRTOS/MessageQueue.h"
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 "../../osal/FreeRTOS/MessageQueue.h"
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,59 +1,59 @@
#include "../../osal/FreeRTOS/BinarySemaphore.h"
#include "../../osal/FreeRTOS/BinSemaphUsingTask.h"
#include "../../osal/FreeRTOS/CountingSemaphore.h"
#include "../../osal/FreeRTOS/CountingSemaphUsingTask.h"
#include "../../tasks/SemaphoreFactory.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr;
static const uint32_t USE_REGULAR_SEMAPHORES = 0;
static const uint32_t USE_TASK_NOTIFICATIONS = 1;
SemaphoreFactory::SemaphoreFactory() {
}
SemaphoreFactory::~SemaphoreFactory() {
delete factoryInstance;
}
SemaphoreFactory* SemaphoreFactory::instance() {
if (factoryInstance == nullptr){
factoryInstance = new SemaphoreFactory();
}
return SemaphoreFactory::factoryInstance;
}
SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t argument) {
if(argument == USE_REGULAR_SEMAPHORES) {
return new BinarySemaphore();
}
else if(argument == USE_TASK_NOTIFICATIONS) {
return new BinarySemaphoreUsingTask();
}
else {
sif::warning << "SemaphoreFactory: Invalid argument, return regular"
"binary semaphore" << std::endl;
return new BinarySemaphore();
}
}
SemaphoreIF* SemaphoreFactory::createCountingSemaphore(uint8_t maxCount,
uint8_t initCount, uint32_t argument) {
if(argument == USE_REGULAR_SEMAPHORES) {
return new CountingSemaphore(maxCount, initCount);
}
else if(argument == USE_TASK_NOTIFICATIONS) {
return new CountingSemaphoreUsingTask(maxCount, initCount);
}
else {
sif::warning << "SemaphoreFactory: Invalid argument, return regular"
"binary semaphore" << std::endl;
return new CountingSemaphore(maxCount, initCount);
}
}
void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) {
delete semaphore;
}
#include "../../osal/FreeRTOS/BinarySemaphore.h"
#include "../../osal/FreeRTOS/BinSemaphUsingTask.h"
#include "../../osal/FreeRTOS/CountingSemaphore.h"
#include "../../osal/FreeRTOS/CountingSemaphUsingTask.h"
#include "../../tasks/SemaphoreFactory.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr;
static const uint32_t USE_REGULAR_SEMAPHORES = 0;
static const uint32_t USE_TASK_NOTIFICATIONS = 1;
SemaphoreFactory::SemaphoreFactory() {
}
SemaphoreFactory::~SemaphoreFactory() {
delete factoryInstance;
}
SemaphoreFactory* SemaphoreFactory::instance() {
if (factoryInstance == nullptr){
factoryInstance = new SemaphoreFactory();
}
return SemaphoreFactory::factoryInstance;
}
SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t argument) {
if(argument == USE_REGULAR_SEMAPHORES) {
return new BinarySemaphore();
}
else if(argument == USE_TASK_NOTIFICATIONS) {
return new BinarySemaphoreUsingTask();
}
else {
sif::warning << "SemaphoreFactory: Invalid argument, return regular"
"binary semaphore" << std::endl;
return new BinarySemaphore();
}
}
SemaphoreIF* SemaphoreFactory::createCountingSemaphore(uint8_t maxCount,
uint8_t initCount, uint32_t argument) {
if(argument == USE_REGULAR_SEMAPHORES) {
return new CountingSemaphore(maxCount, initCount);
}
else if(argument == USE_TASK_NOTIFICATIONS) {
return new CountingSemaphoreUsingTask(maxCount, initCount);
}
else {
sif::warning << "SemaphoreFactory: Invalid argument, return regular"
"binary semaphore" << std::endl;
return new CountingSemaphore(maxCount, initCount);
}
}
void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) {
delete semaphore;
}

View File

@ -1,53 +1,53 @@
#include "../../tasks/TaskFactory.h"
#include "../../returnvalues/HasReturnvaluesIF.h"
#include "PeriodicTask.h"
#include "FixedTimeslotTask.h"
TaskFactory* TaskFactory::factoryInstance = new TaskFactory();
TaskFactory::~TaskFactory() {
}
TaskFactory* TaskFactory::instance() {
return TaskFactory::factoryInstance;
}
PeriodicTaskIF* TaskFactory::createPeriodicTask(TaskName name_,
TaskPriority taskPriority_, TaskStackSize stackSize_,
TaskPeriod period_,
TaskDeadlineMissedFunction deadLineMissedFunction_) {
return dynamic_cast<PeriodicTaskIF*>(new PeriodicTask(name_, taskPriority_,
stackSize_, period_, deadLineMissedFunction_));
}
/**
* Keep in Mind that you need to call before this vTaskStartScheduler()!
*/
FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(TaskName name_,
TaskPriority taskPriority_, TaskStackSize stackSize_,
TaskPeriod period_,
TaskDeadlineMissedFunction deadLineMissedFunction_) {
return dynamic_cast<FixedTimeslotTaskIF*>(new FixedTimeslotTask(name_,
taskPriority_,stackSize_, period_, deadLineMissedFunction_));
}
ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) {
if (task == nullptr) {
//delete self
vTaskDelete(nullptr);
return HasReturnvaluesIF::RETURN_OK;
} else {
//TODO not implemented
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t TaskFactory::delayTask(uint32_t delayMs) {
vTaskDelay(pdMS_TO_TICKS(delayMs));
return HasReturnvaluesIF::RETURN_OK;
}
TaskFactory::TaskFactory() {
}
#include "../../tasks/TaskFactory.h"
#include "../../returnvalues/HasReturnvaluesIF.h"
#include "PeriodicTask.h"
#include "FixedTimeslotTask.h"
TaskFactory* TaskFactory::factoryInstance = new TaskFactory();
TaskFactory::~TaskFactory() {
}
TaskFactory* TaskFactory::instance() {
return TaskFactory::factoryInstance;
}
PeriodicTaskIF* TaskFactory::createPeriodicTask(TaskName name_,
TaskPriority taskPriority_, TaskStackSize stackSize_,
TaskPeriod period_,
TaskDeadlineMissedFunction deadLineMissedFunction_) {
return dynamic_cast<PeriodicTaskIF*>(new PeriodicTask(name_, taskPriority_,
stackSize_, period_, deadLineMissedFunction_));
}
/**
* Keep in Mind that you need to call before this vTaskStartScheduler()!
*/
FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(TaskName name_,
TaskPriority taskPriority_, TaskStackSize stackSize_,
TaskPeriod period_,
TaskDeadlineMissedFunction deadLineMissedFunction_) {
return dynamic_cast<FixedTimeslotTaskIF*>(new FixedTimeslotTask(name_,
taskPriority_,stackSize_, period_, deadLineMissedFunction_));
}
ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) {
if (task == nullptr) {
//delete self
vTaskDelete(nullptr);
return HasReturnvaluesIF::RETURN_OK;
} else {
//TODO not implemented
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t TaskFactory::delayTask(uint32_t delayMs) {
vTaskDelay(pdMS_TO_TICKS(delayMs));
return HasReturnvaluesIF::RETURN_OK;
}
TaskFactory::TaskFactory() {
}

View File

@ -1,24 +1,24 @@
#include "../../osal/FreeRTOS/TaskManagement.h"
void TaskManagement::vRequestContextSwitchFromTask() {
vTaskDelay(0);
}
void TaskManagement::requestContextSwitch(
CallContext callContext = CallContext::TASK) {
if(callContext == CallContext::ISR) {
// This function depends on the partmacro.h definition for the specific device
vRequestContextSwitchFromISR();
} else {
vRequestContextSwitchFromTask();
}
}
TaskHandle_t TaskManagement::getCurrentTaskHandle() {
return xTaskGetCurrentTaskHandle();
}
size_t TaskManagement::getTaskStackHighWatermark(
TaskHandle_t task) {
return uxTaskGetStackHighWaterMark(task) * sizeof(StackType_t);
}
#include "../../osal/FreeRTOS/TaskManagement.h"
void TaskManagement::vRequestContextSwitchFromTask() {
vTaskDelay(0);
}
void TaskManagement::requestContextSwitch(
CallContext callContext = CallContext::TASK) {
if(callContext == CallContext::ISR) {
// This function depends on the partmacro.h definition for the specific device
vRequestContextSwitchFromISR();
} else {
vRequestContextSwitchFromTask();
}
}
TaskHandle_t TaskManagement::getCurrentTaskHandle() {
return xTaskGetCurrentTaskHandle();
}
size_t TaskManagement::getTaskStackHighWatermark(
TaskHandle_t task) {
return uxTaskGetStackHighWaterMark(task) * sizeof(StackType_t);
}

View File

@ -1,64 +1,64 @@
#ifndef FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_
#define FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_
#include "../../returnvalues/HasReturnvaluesIF.h"
extern "C" {
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
}
#include <cstdint>
/**
* Architecture dependant portmacro.h function call.
* Should be implemented in bsp.
*/
extern void vRequestContextSwitchFromISR();
/*!
* Used by functions to tell if they are being called from
* within an ISR or from a regular task. This is required because FreeRTOS
* has different functions for handling semaphores and messages from within
* an ISR and task.
*/
enum class CallContext {
TASK = 0x00,//!< task_context
ISR = 0xFF //!< isr_context
};
class TaskManagement {
public:
/**
* @brief In this function, a function dependant on the portmacro.h header
* function calls to request a context switch can be specified.
* This can be used if sending to the queue from an ISR caused a task
* to unblock and a context switch is required.
*/
static void requestContextSwitch(CallContext callContext);
/**
* If task preemption in FreeRTOS is disabled, a context switch
* can be requested manually by calling this function.
*/
static void vRequestContextSwitchFromTask(void);
/**
* @return The current task handle
*/
static TaskHandle_t getCurrentTaskHandle();
/**
* Get returns the minimum amount of remaining stack space in words
* that was a available to the task since the task started executing.
* Please note that the actual value in bytes depends
* on the stack depth type.
* E.g. on a 32 bit machine, a value of 200 means 800 bytes.
* @return Smallest value of stack remaining since the task was started in
* words.
*/
static size_t getTaskStackHighWatermark(
TaskHandle_t task = nullptr);
};
#endif /* FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ */
#ifndef FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_
#define FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_
#include "../../returnvalues/HasReturnvaluesIF.h"
extern "C" {
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
}
#include <cstdint>
/**
* Architecture dependant portmacro.h function call.
* Should be implemented in bsp.
*/
extern void vRequestContextSwitchFromISR();
/*!
* Used by functions to tell if they are being called from
* within an ISR or from a regular task. This is required because FreeRTOS
* has different functions for handling semaphores and messages from within
* an ISR and task.
*/
enum class CallContext {
TASK = 0x00,//!< task_context
ISR = 0xFF //!< isr_context
};
class TaskManagement {
public:
/**
* @brief In this function, a function dependant on the portmacro.h header
* function calls to request a context switch can be specified.
* This can be used if sending to the queue from an ISR caused a task
* to unblock and a context switch is required.
*/
static void requestContextSwitch(CallContext callContext);
/**
* If task preemption in FreeRTOS is disabled, a context switch
* can be requested manually by calling this function.
*/
static void vRequestContextSwitchFromTask(void);
/**
* @return The current task handle
*/
static TaskHandle_t getCurrentTaskHandle();
/**
* Get returns the minimum amount of remaining stack space in words
* that was a available to the task since the task started executing.
* Please note that the actual value in bytes depends
* on the stack depth type.
* E.g. on a 32 bit machine, a value of 200 means 800 bytes.
* @return Smallest value of stack remaining since the task was started in
* words.
*/
static size_t getTaskStackHighWatermark(
TaskHandle_t task = nullptr);
};
#endif /* FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ */

View File

@ -1,41 +1,41 @@
#include "../../osal/FreeRTOS/Timekeeper.h"
#include "FreeRTOSConfig.h"
Timekeeper * Timekeeper::myinstance = nullptr;
Timekeeper::Timekeeper() : offset( { 0, 0 } ) {}
Timekeeper::~Timekeeper() {}
const timeval& Timekeeper::getOffset() const {
return offset;
}
Timekeeper* Timekeeper::instance() {
if (myinstance == nullptr) {
myinstance = new Timekeeper();
}
return myinstance;
}
void Timekeeper::setOffset(const timeval& offset) {
this->offset = offset;
}
timeval Timekeeper::ticksToTimeval(TickType_t ticks) {
timeval uptime;
uptime.tv_sec = ticks / configTICK_RATE_HZ;
//TODO explain, think about overflow
uint32_t subsecondTicks = ticks % configTICK_RATE_HZ;
uint64_t usecondTicks = subsecondTicks * 1000000;
uptime.tv_usec = usecondTicks / configTICK_RATE_HZ;
return uptime;
}
TickType_t Timekeeper::getTicks() {
return xTaskGetTickCount();
}
#include "../../osal/FreeRTOS/Timekeeper.h"
#include "FreeRTOSConfig.h"
Timekeeper * Timekeeper::myinstance = nullptr;
Timekeeper::Timekeeper() : offset( { 0, 0 } ) {}
Timekeeper::~Timekeeper() {}
const timeval& Timekeeper::getOffset() const {
return offset;
}
Timekeeper* Timekeeper::instance() {
if (myinstance == nullptr) {
myinstance = new Timekeeper();
}
return myinstance;
}
void Timekeeper::setOffset(const timeval& offset) {
this->offset = offset;
}
timeval Timekeeper::ticksToTimeval(TickType_t ticks) {
timeval uptime;
uptime.tv_sec = ticks / configTICK_RATE_HZ;
//TODO explain, think about overflow
uint32_t subsecondTicks = ticks % configTICK_RATE_HZ;
uint64_t usecondTicks = subsecondTicks * 1000000;
uptime.tv_usec = usecondTicks / configTICK_RATE_HZ;
return uptime;
}
TickType_t Timekeeper::getTicks() {
return xTaskGetTickCount();
}

View File

@ -1,40 +1,40 @@
#ifndef FRAMEWORK_OSAL_FREERTOS_TIMEKEEPER_H_
#define FRAMEWORK_OSAL_FREERTOS_TIMEKEEPER_H_
#include "../../timemanager/Clock.h"
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
/**
* A Class to basically store the time difference between uptime and UTC
* so the "time-agnostic" FreeRTOS can keep an UTC Time
*
* Implemented as Singleton, so the FSFW Clock Implementation (see Clock.cpp)
* can use it without having a member.
*/
class Timekeeper {
private:
Timekeeper();
timeval offset;
static Timekeeper * myinstance;
public:
static Timekeeper * instance();
virtual ~Timekeeper();
static timeval ticksToTimeval(TickType_t ticks);
/**
* Get elapsed time in system ticks.
* @return
*/
static TickType_t getTicks();
const timeval& getOffset() const;
void setOffset(const timeval& offset);
};
#endif /* FRAMEWORK_OSAL_FREERTOS_TIMEKEEPER_H_ */
#ifndef FRAMEWORK_OSAL_FREERTOS_TIMEKEEPER_H_
#define FRAMEWORK_OSAL_FREERTOS_TIMEKEEPER_H_
#include "../../timemanager/Clock.h"
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
/**
* A Class to basically store the time difference between uptime and UTC
* so the "time-agnostic" FreeRTOS can keep an UTC Time
*
* Implemented as Singleton, so the FSFW Clock Implementation (see Clock.cpp)
* can use it without having a member.
*/
class Timekeeper {
private:
Timekeeper();
timeval offset;
static Timekeeper * myinstance;
public:
static Timekeeper * instance();
virtual ~Timekeeper();
static timeval ticksToTimeval(TickType_t ticks);
/**
* Get elapsed time in system ticks.
* @return
*/
static TickType_t getTicks();
const timeval& getOffset() const;
void setOffset(const timeval& offset);
};
#endif /* FRAMEWORK_OSAL_FREERTOS_TIMEKEEPER_H_ */

View File

@ -1,39 +1,39 @@
#ifndef INTERNALERRORCODES_H_
#define INTERNALERRORCODES_H_
#include "../returnvalues/HasReturnvaluesIF.h"
class InternalErrorCodes {
public:
static const uint8_t INTERFACE_ID = CLASS_ID::INTERNAL_ERROR_CODES;
static const ReturnValue_t NO_CONFIGURATION_TABLE = MAKE_RETURN_CODE(0x01 );
static const ReturnValue_t NO_CPU_TABLE = MAKE_RETURN_CODE(0x02 );
static const ReturnValue_t INVALID_WORKSPACE_ADDRESS = MAKE_RETURN_CODE(0x03 );
static const ReturnValue_t TOO_LITTLE_WORKSPACE = MAKE_RETURN_CODE(0x04 );
static const ReturnValue_t WORKSPACE_ALLOCATION = MAKE_RETURN_CODE(0x05 );
static const ReturnValue_t INTERRUPT_STACK_TOO_SMALL = MAKE_RETURN_CODE(0x06 );
static const ReturnValue_t THREAD_EXITTED = MAKE_RETURN_CODE(0x07 );
static const ReturnValue_t INCONSISTENT_MP_INFORMATION = MAKE_RETURN_CODE(0x08 );
static const ReturnValue_t INVALID_NODE = MAKE_RETURN_CODE(0x09 );
static const ReturnValue_t NO_MPCI = MAKE_RETURN_CODE(0x0a );
static const ReturnValue_t BAD_PACKET = MAKE_RETURN_CODE(0x0b );
static const ReturnValue_t OUT_OF_PACKETS = MAKE_RETURN_CODE(0x0c );
static const ReturnValue_t OUT_OF_GLOBAL_OBJECTS = MAKE_RETURN_CODE(0x0d );
static const ReturnValue_t OUT_OF_PROXIES = MAKE_RETURN_CODE(0x0e );
static const ReturnValue_t INVALID_GLOBAL_ID = MAKE_RETURN_CODE(0x0f );
static const ReturnValue_t BAD_STACK_HOOK = MAKE_RETURN_CODE(0x10 );
static const ReturnValue_t BAD_ATTRIBUTES = MAKE_RETURN_CODE(0x11 );
static const ReturnValue_t IMPLEMENTATION_KEY_CREATE_INCONSISTENCY = MAKE_RETURN_CODE(0x12 );
static const ReturnValue_t IMPLEMENTATION_BLOCKING_OPERATION_CANCEL = MAKE_RETURN_CODE(0x13 );
static const ReturnValue_t MUTEX_OBTAIN_FROM_BAD_STATE = MAKE_RETURN_CODE(0x14 );
static const ReturnValue_t UNLIMITED_AND_MAXIMUM_IS_0 = MAKE_RETURN_CODE(0x15 );
virtual ~InternalErrorCodes();
static ReturnValue_t translate(uint8_t code);
private:
InternalErrorCodes();
};
#endif /* INTERNALERRORCODES_H_ */
#ifndef INTERNALERRORCODES_H_
#define INTERNALERRORCODES_H_
#include "../returnvalues/HasReturnvaluesIF.h"
class InternalErrorCodes {
public:
static const uint8_t INTERFACE_ID = CLASS_ID::INTERNAL_ERROR_CODES;
static const ReturnValue_t NO_CONFIGURATION_TABLE = MAKE_RETURN_CODE(0x01 );
static const ReturnValue_t NO_CPU_TABLE = MAKE_RETURN_CODE(0x02 );
static const ReturnValue_t INVALID_WORKSPACE_ADDRESS = MAKE_RETURN_CODE(0x03 );
static const ReturnValue_t TOO_LITTLE_WORKSPACE = MAKE_RETURN_CODE(0x04 );
static const ReturnValue_t WORKSPACE_ALLOCATION = MAKE_RETURN_CODE(0x05 );
static const ReturnValue_t INTERRUPT_STACK_TOO_SMALL = MAKE_RETURN_CODE(0x06 );
static const ReturnValue_t THREAD_EXITTED = MAKE_RETURN_CODE(0x07 );
static const ReturnValue_t INCONSISTENT_MP_INFORMATION = MAKE_RETURN_CODE(0x08 );
static const ReturnValue_t INVALID_NODE = MAKE_RETURN_CODE(0x09 );
static const ReturnValue_t NO_MPCI = MAKE_RETURN_CODE(0x0a );
static const ReturnValue_t BAD_PACKET = MAKE_RETURN_CODE(0x0b );
static const ReturnValue_t OUT_OF_PACKETS = MAKE_RETURN_CODE(0x0c );
static const ReturnValue_t OUT_OF_GLOBAL_OBJECTS = MAKE_RETURN_CODE(0x0d );
static const ReturnValue_t OUT_OF_PROXIES = MAKE_RETURN_CODE(0x0e );
static const ReturnValue_t INVALID_GLOBAL_ID = MAKE_RETURN_CODE(0x0f );
static const ReturnValue_t BAD_STACK_HOOK = MAKE_RETURN_CODE(0x10 );
static const ReturnValue_t BAD_ATTRIBUTES = MAKE_RETURN_CODE(0x11 );
static const ReturnValue_t IMPLEMENTATION_KEY_CREATE_INCONSISTENCY = MAKE_RETURN_CODE(0x12 );
static const ReturnValue_t IMPLEMENTATION_BLOCKING_OPERATION_CANCEL = MAKE_RETURN_CODE(0x13 );
static const ReturnValue_t MUTEX_OBTAIN_FROM_BAD_STATE = MAKE_RETURN_CODE(0x14 );
static const ReturnValue_t UNLIMITED_AND_MAXIMUM_IS_0 = MAKE_RETURN_CODE(0x15 );
virtual ~InternalErrorCodes();
static ReturnValue_t translate(uint8_t code);
private:
InternalErrorCodes();
};
#endif /* INTERNALERRORCODES_H_ */

View File

@ -1,227 +1,227 @@
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../timemanager/Clock.h"
#include <chrono>
#if defined(WIN32)
#include <windows.h>
#elif defined(LINUX)
#include <fstream>
#endif
uint16_t Clock::leapSeconds = 0;
MutexIF* Clock::timeMutex = NULL;
using SystemClock = std::chrono::system_clock;
uint32_t Clock::getTicksPerSecond(void){
sif::warning << "Clock::getTicksPerSecond: not implemented yet" << std::endl;
return 0;
//return CLOCKS_PER_SEC;
//uint32_t ticks = sysconf(_SC_CLK_TCK);
//return ticks;
}
ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {
// do some magic with chrono
sif::warning << "Clock::setClock: not implemented yet" << std::endl;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::setClock(const timeval* time) {
// do some magic with chrono
#if defined(WIN32)
return HasReturnvaluesIF::RETURN_OK;
#elif defined(LINUX)
return HasReturnvaluesIF::RETURN_OK;
#else
#endif
sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t Clock::getClock_timeval(timeval* time) {
#if defined(WIN32)
auto now = std::chrono::system_clock::now();
auto secondsChrono = std::chrono::time_point_cast<std::chrono::seconds>(now);
auto epoch = now.time_since_epoch();
time->tv_sec = std::chrono::duration_cast<std::chrono::seconds>(epoch).count();
auto fraction = now - secondsChrono;
time->tv_usec = std::chrono::duration_cast<std::chrono::microseconds>(
fraction).count();
return HasReturnvaluesIF::RETURN_OK;
#elif defined(LINUX)
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;
#else
sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
#endif
}
ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
// do some magic with chrono
sif::warning << "Clock::gerClock_usecs: not implemented yet" << std::endl;
return HasReturnvaluesIF::RETURN_OK;
}
timeval Clock::getUptime() {
timeval timeval;
#if defined(WIN32)
auto uptime = std::chrono::milliseconds(GetTickCount64());
auto secondsChrono = std::chrono::duration_cast<std::chrono::seconds>(uptime);
timeval.tv_sec = secondsChrono.count();
auto fraction = uptime - secondsChrono;
timeval.tv_usec = std::chrono::duration_cast<std::chrono::microseconds>(
fraction).count();
#elif defined(LINUX)
double uptimeSeconds;
if (std::ifstream("/proc/uptime", std::ios::in) >> uptimeSeconds)
{
// value is rounded down automatically
timeval.tv_sec = uptimeSeconds;
timeval.tv_usec = uptimeSeconds *(double) 1e6 - (timeval.tv_sec *1e6);
}
#else
sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl;
#endif
return timeval;
}
ReturnValue_t Clock::getUptime(timeval* uptime) {
*uptime = getUptime();
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) {
timeval uptime = getUptime();
*uptimeMs = uptime.tv_sec * 1000 + uptime.tv_usec / 1000;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
// do some magic with chrono (C++20!)
// Right now, the library doesn't have the new features yet.
// so we work around that for now.
auto now = SystemClock::now();
auto seconds = std::chrono::time_point_cast<std::chrono::seconds>(now);
auto fraction = now - seconds;
time_t tt = SystemClock::to_time_t(now);
struct tm* timeInfo;
timeInfo = gmtime(&tt);
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;
auto usecond = std::chrono::duration_cast<std::chrono::microseconds>(fraction);
time->usecond = usecond.count();
//sif::warning << "Clock::getDateAndTime: not implemented yet" << std::endl;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from,
timeval* to) {
struct tm time_tm;
time_tm.tm_year = from->year - 1900;
time_tm.tm_mon = from->month - 1;
time_tm.tm_mday = from->day;
time_tm.tm_hour = from->hour;
time_tm.tm_min = from->minute;
time_tm.tm_sec = from->second;
time_t seconds = mktime(&time_tm);
to->tv_sec = seconds;
to->tv_usec = from->usecond;
//Fails in 2038..
return HasReturnvaluesIF::RETURN_OK;
sif::warning << "Clock::convertTimeBla: not implemented yet" << std::endl;
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 == nullptr){
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 == nullptr){
MutexFactory* mutexFactory = MutexFactory::instance();
if (mutexFactory == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
timeMutex = mutexFactory->createMutex();
if (timeMutex == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
return HasReturnvaluesIF::RETURN_OK;
}
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../timemanager/Clock.h"
#include <chrono>
#if defined(WIN32)
#include <windows.h>
#elif defined(LINUX)
#include <fstream>
#endif
uint16_t Clock::leapSeconds = 0;
MutexIF* Clock::timeMutex = NULL;
using SystemClock = std::chrono::system_clock;
uint32_t Clock::getTicksPerSecond(void){
sif::warning << "Clock::getTicksPerSecond: not implemented yet" << std::endl;
return 0;
//return CLOCKS_PER_SEC;
//uint32_t ticks = sysconf(_SC_CLK_TCK);
//return ticks;
}
ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {
// do some magic with chrono
sif::warning << "Clock::setClock: not implemented yet" << std::endl;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::setClock(const timeval* time) {
// do some magic with chrono
#if defined(WIN32)
return HasReturnvaluesIF::RETURN_OK;
#elif defined(LINUX)
return HasReturnvaluesIF::RETURN_OK;
#else
#endif
sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t Clock::getClock_timeval(timeval* time) {
#if defined(WIN32)
auto now = std::chrono::system_clock::now();
auto secondsChrono = std::chrono::time_point_cast<std::chrono::seconds>(now);
auto epoch = now.time_since_epoch();
time->tv_sec = std::chrono::duration_cast<std::chrono::seconds>(epoch).count();
auto fraction = now - secondsChrono;
time->tv_usec = std::chrono::duration_cast<std::chrono::microseconds>(
fraction).count();
return HasReturnvaluesIF::RETURN_OK;
#elif defined(LINUX)
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;
#else
sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
#endif
}
ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
// do some magic with chrono
sif::warning << "Clock::gerClock_usecs: not implemented yet" << std::endl;
return HasReturnvaluesIF::RETURN_OK;
}
timeval Clock::getUptime() {
timeval timeval;
#if defined(WIN32)
auto uptime = std::chrono::milliseconds(GetTickCount64());
auto secondsChrono = std::chrono::duration_cast<std::chrono::seconds>(uptime);
timeval.tv_sec = secondsChrono.count();
auto fraction = uptime - secondsChrono;
timeval.tv_usec = std::chrono::duration_cast<std::chrono::microseconds>(
fraction).count();
#elif defined(LINUX)
double uptimeSeconds;
if (std::ifstream("/proc/uptime", std::ios::in) >> uptimeSeconds)
{
// value is rounded down automatically
timeval.tv_sec = uptimeSeconds;
timeval.tv_usec = uptimeSeconds *(double) 1e6 - (timeval.tv_sec *1e6);
}
#else
sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl;
#endif
return timeval;
}
ReturnValue_t Clock::getUptime(timeval* uptime) {
*uptime = getUptime();
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) {
timeval uptime = getUptime();
*uptimeMs = uptime.tv_sec * 1000 + uptime.tv_usec / 1000;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
// do some magic with chrono (C++20!)
// Right now, the library doesn't have the new features yet.
// so we work around that for now.
auto now = SystemClock::now();
auto seconds = std::chrono::time_point_cast<std::chrono::seconds>(now);
auto fraction = now - seconds;
time_t tt = SystemClock::to_time_t(now);
struct tm* timeInfo;
timeInfo = gmtime(&tt);
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;
auto usecond = std::chrono::duration_cast<std::chrono::microseconds>(fraction);
time->usecond = usecond.count();
//sif::warning << "Clock::getDateAndTime: not implemented yet" << std::endl;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from,
timeval* to) {
struct tm time_tm;
time_tm.tm_year = from->year - 1900;
time_tm.tm_mon = from->month - 1;
time_tm.tm_mday = from->day;
time_tm.tm_hour = from->hour;
time_tm.tm_min = from->minute;
time_tm.tm_sec = from->second;
time_t seconds = mktime(&time_tm);
to->tv_sec = seconds;
to->tv_usec = from->usecond;
//Fails in 2038..
return HasReturnvaluesIF::RETURN_OK;
sif::warning << "Clock::convertTimeBla: not implemented yet" << std::endl;
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 == nullptr){
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 == nullptr){
MutexFactory* mutexFactory = MutexFactory::instance();
if (mutexFactory == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
timeMutex = mutexFactory->createMutex();
if (timeMutex == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -1,191 +1,191 @@
#include "../../osal/host/FixedTimeslotTask.h"
#include "../../ipc/MutexFactory.h"
#include "../../osal/host/Mutex.h"
#include "../../osal/host/FixedTimeslotTask.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../tasks/ExecutableObjectIF.h"
#include <thread>
#include <chrono>
#if defined(WIN32)
#include <windows.h>
#elif defined(LINUX)
#include <pthread.h>
#endif
FixedTimeslotTask::FixedTimeslotTask(const char *name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod setPeriod,
void (*setDeadlineMissedFunc)()) :
started(false), pollingSeqTable(setPeriod*1000), taskName(name),
period(setPeriod), deadlineMissedFunc(setDeadlineMissedFunc) {
// It is propably possible to set task priorities by using the native
// task handles for Windows / Linux
mainThread = std::thread(&FixedTimeslotTask::taskEntryPoint, this, this);
#if defined(WIN32)
/* List of possible priority classes:
* https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/
* nf-processthreadsapi-setpriorityclass
* And respective thread priority numbers:
* https://docs.microsoft.com/en-us/windows/
* win32/procthread/scheduling-priorities */
int result = SetPriorityClass(
reinterpret_cast<HANDLE>(mainThread.native_handle()),
ABOVE_NORMAL_PRIORITY_CLASS);
if(result != 0) {
sif::error << "FixedTimeslotTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl;
}
result = SetThreadPriority(
reinterpret_cast<HANDLE>(mainThread.native_handle()),
THREAD_PRIORITY_NORMAL);
if(result != 0) {
sif::error << "FixedTimeslotTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl;
}
#elif defined(LINUX)
// we can just copy and paste the code from linux here.
#endif
}
FixedTimeslotTask::~FixedTimeslotTask(void) {
//Do not delete objects, we were responsible for ptrs only.
terminateThread = true;
if(mainThread.joinable()) {
mainThread.join();
}
delete this;
}
void FixedTimeslotTask::taskEntryPoint(void* argument) {
FixedTimeslotTask *originalTask(reinterpret_cast<FixedTimeslotTask*>(argument));
if (not originalTask->started) {
// we have to suspend/block here until the task is started.
// if semaphores are implemented, use them here.
std::unique_lock<std::mutex> lock(initMutex);
initCondition.wait(lock);
}
this->taskFunctionality();
sif::debug << "FixedTimeslotTask::taskEntryPoint: "
"Returned from taskFunctionality." << std::endl;
}
ReturnValue_t FixedTimeslotTask::startTask() {
started = true;
// Notify task to start.
std::lock_guard<std::mutex> lock(initMutex);
initCondition.notify_one();
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) {
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
return HasReturnvaluesIF::RETURN_OK;
}
void FixedTimeslotTask::taskFunctionality() {
// A local iterator for the Polling Sequence Table is created to
// find the start time for the first entry.
FixedSlotSequence::SlotListIter slotListIter = pollingSeqTable.current;
// Get start time for first entry.
chron_ms interval(slotListIter->pollingTimeMs);
auto currentStartTime {
std::chrono::duration_cast<chron_ms>(
std::chrono::system_clock::now().time_since_epoch())
};
if(interval.count() > 0) {
delayForInterval(&currentStartTime, interval);
}
/* Enter the loop that defines the task behavior. */
for (;;) {
if(terminateThread.load()) {
break;
}
//The component for this slot is executed and the next one is chosen.
this->pollingSeqTable.executeAndAdvance();
if (not pollingSeqTable.slotFollowsImmediately()) {
// we need to wait before executing the current slot
//this gives us the time to wait:
interval = chron_ms(this->pollingSeqTable.getIntervalToPreviousSlotMs());
delayForInterval(&currentStartTime, interval);
//TODO deadline missed check
}
}
}
ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId,
uint32_t slotTimeMs, int8_t executionStep) {
if (objectManager->get<ExecutableObjectIF>(componentId) != nullptr) {
pollingSeqTable.addSlot(componentId, slotTimeMs, executionStep, this);
return HasReturnvaluesIF::RETURN_OK;
}
sif::error << "Component " << std::hex << componentId <<
" not found, not adding it to pst" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t FixedTimeslotTask::checkAndInitializeSequence() const {
return pollingSeqTable.checkSequence();
}
uint32_t FixedTimeslotTask::getPeriodMs() const {
return period * 1000;
}
bool FixedTimeslotTask::delayForInterval(chron_ms * previousWakeTimeMs,
const chron_ms interval) {
bool shouldDelay = false;
//Get current wakeup time
auto currentStartTime =
std::chrono::duration_cast<chron_ms>(
std::chrono::system_clock::now().time_since_epoch());
/* Generate the tick time at which the task wants to wake. */
auto nextTimeToWake_ms = (*previousWakeTimeMs) + interval;
if (currentStartTime < *previousWakeTimeMs) {
/* 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 < *previousWakeTimeMs)
&& (nextTimeToWake_ms > currentStartTime)) {
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 < *previousWakeTimeMs)
|| (nextTimeToWake_ms > currentStartTime)) {
shouldDelay = true;
}
}
/* Update the wake time ready for the next call. */
(*previousWakeTimeMs) = nextTimeToWake_ms;
if (shouldDelay) {
auto sleepTime = std::chrono::duration_cast<chron_ms>(
nextTimeToWake_ms - currentStartTime);
std::this_thread::sleep_for(sleepTime);
return true;
}
//We are shifting the time in case the deadline was missed like rtems
(*previousWakeTimeMs) = currentStartTime;
return false;
}
#include "../../osal/host/FixedTimeslotTask.h"
#include "../../ipc/MutexFactory.h"
#include "../../osal/host/Mutex.h"
#include "../../osal/host/FixedTimeslotTask.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../tasks/ExecutableObjectIF.h"
#include <thread>
#include <chrono>
#if defined(WIN32)
#include <windows.h>
#elif defined(LINUX)
#include <pthread.h>
#endif
FixedTimeslotTask::FixedTimeslotTask(const char *name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod setPeriod,
void (*setDeadlineMissedFunc)()) :
started(false), pollingSeqTable(setPeriod*1000), taskName(name),
period(setPeriod), deadlineMissedFunc(setDeadlineMissedFunc) {
// It is propably possible to set task priorities by using the native
// task handles for Windows / Linux
mainThread = std::thread(&FixedTimeslotTask::taskEntryPoint, this, this);
#if defined(WIN32)
/* List of possible priority classes:
* https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/
* nf-processthreadsapi-setpriorityclass
* And respective thread priority numbers:
* https://docs.microsoft.com/en-us/windows/
* win32/procthread/scheduling-priorities */
int result = SetPriorityClass(
reinterpret_cast<HANDLE>(mainThread.native_handle()),
ABOVE_NORMAL_PRIORITY_CLASS);
if(result != 0) {
sif::error << "FixedTimeslotTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl;
}
result = SetThreadPriority(
reinterpret_cast<HANDLE>(mainThread.native_handle()),
THREAD_PRIORITY_NORMAL);
if(result != 0) {
sif::error << "FixedTimeslotTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl;
}
#elif defined(LINUX)
// we can just copy and paste the code from linux here.
#endif
}
FixedTimeslotTask::~FixedTimeslotTask(void) {
//Do not delete objects, we were responsible for ptrs only.
terminateThread = true;
if(mainThread.joinable()) {
mainThread.join();
}
delete this;
}
void FixedTimeslotTask::taskEntryPoint(void* argument) {
FixedTimeslotTask *originalTask(reinterpret_cast<FixedTimeslotTask*>(argument));
if (not originalTask->started) {
// we have to suspend/block here until the task is started.
// if semaphores are implemented, use them here.
std::unique_lock<std::mutex> lock(initMutex);
initCondition.wait(lock);
}
this->taskFunctionality();
sif::debug << "FixedTimeslotTask::taskEntryPoint: "
"Returned from taskFunctionality." << std::endl;
}
ReturnValue_t FixedTimeslotTask::startTask() {
started = true;
// Notify task to start.
std::lock_guard<std::mutex> lock(initMutex);
initCondition.notify_one();
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) {
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
return HasReturnvaluesIF::RETURN_OK;
}
void FixedTimeslotTask::taskFunctionality() {
// A local iterator for the Polling Sequence Table is created to
// find the start time for the first entry.
FixedSlotSequence::SlotListIter slotListIter = pollingSeqTable.current;
// Get start time for first entry.
chron_ms interval(slotListIter->pollingTimeMs);
auto currentStartTime {
std::chrono::duration_cast<chron_ms>(
std::chrono::system_clock::now().time_since_epoch())
};
if(interval.count() > 0) {
delayForInterval(&currentStartTime, interval);
}
/* Enter the loop that defines the task behavior. */
for (;;) {
if(terminateThread.load()) {
break;
}
//The component for this slot is executed and the next one is chosen.
this->pollingSeqTable.executeAndAdvance();
if (not pollingSeqTable.slotFollowsImmediately()) {
// we need to wait before executing the current slot
//this gives us the time to wait:
interval = chron_ms(this->pollingSeqTable.getIntervalToPreviousSlotMs());
delayForInterval(&currentStartTime, interval);
//TODO deadline missed check
}
}
}
ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId,
uint32_t slotTimeMs, int8_t executionStep) {
if (objectManager->get<ExecutableObjectIF>(componentId) != nullptr) {
pollingSeqTable.addSlot(componentId, slotTimeMs, executionStep, this);
return HasReturnvaluesIF::RETURN_OK;
}
sif::error << "Component " << std::hex << componentId <<
" not found, not adding it to pst" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t FixedTimeslotTask::checkAndInitializeSequence() const {
return pollingSeqTable.checkSequence();
}
uint32_t FixedTimeslotTask::getPeriodMs() const {
return period * 1000;
}
bool FixedTimeslotTask::delayForInterval(chron_ms * previousWakeTimeMs,
const chron_ms interval) {
bool shouldDelay = false;
//Get current wakeup time
auto currentStartTime =
std::chrono::duration_cast<chron_ms>(
std::chrono::system_clock::now().time_since_epoch());
/* Generate the tick time at which the task wants to wake. */
auto nextTimeToWake_ms = (*previousWakeTimeMs) + interval;
if (currentStartTime < *previousWakeTimeMs) {
/* 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 < *previousWakeTimeMs)
&& (nextTimeToWake_ms > currentStartTime)) {
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 < *previousWakeTimeMs)
|| (nextTimeToWake_ms > currentStartTime)) {
shouldDelay = true;
}
}
/* Update the wake time ready for the next call. */
(*previousWakeTimeMs) = nextTimeToWake_ms;
if (shouldDelay) {
auto sleepTime = std::chrono::duration_cast<chron_ms>(
nextTimeToWake_ms - currentStartTime);
std::this_thread::sleep_for(sleepTime);
return true;
}
//We are shifting the time in case the deadline was missed like rtems
(*previousWakeTimeMs) = currentStartTime;
return false;
}

View File

@ -1,130 +1,130 @@
#ifndef FRAMEWORK_OSAL_HOST_FIXEDTIMESLOTTASK_H_
#define FRAMEWORK_OSAL_HOST_FIXEDTIMESLOTTASK_H_
#include "../../objectmanager/ObjectManagerIF.h"
#include "../../tasks/FixedSlotSequence.h"
#include "../../tasks/FixedTimeslotTaskIF.h"
#include "../../tasks/Typedef.h"
#include <vector>
#include <thread>
#include <condition_variable>
#include <atomic>
class ExecutableObjectIF;
/**
* @brief This class represents a task for periodic activities with multiple
* steps and strict timeslot requirements for these steps.
* @details
* @ingroup task_handling
*/
class FixedTimeslotTask: public FixedTimeslotTaskIF {
public:
/**
* @brief Standard constructor of the class.
* @details
* The class is initialized without allocated objects. These need to be
* added with #addComponent.
* @param priority
* @param stack_size
* @param setPeriod
* @param setDeadlineMissedFunc
* The function pointer to the deadline missed function that shall be
* assigned.
*/
FixedTimeslotTask(const char *name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod setPeriod,
void (*setDeadlineMissedFunc)());
/**
* @brief Currently, the executed object's lifetime is not coupled with
* the task object's lifetime, so the destructor is empty.
*/
virtual ~FixedTimeslotTask(void);
/**
* @brief The method to start the task.
* @details The method starts the task with the respective system call.
* Entry point is the taskEntryPoint method described below.
* The address of the task object is passed as an argument
* to the system call.
*/
ReturnValue_t startTask(void);
/**
* Add timeslot to the polling sequence table.
* @param componentId
* @param slotTimeMs
* @param executionStep
* @return
*/
ReturnValue_t addSlot(object_id_t componentId,
uint32_t slotTimeMs, int8_t executionStep);
ReturnValue_t checkAndInitializeSequence() const;
uint32_t getPeriodMs() const;
ReturnValue_t sleepFor(uint32_t ms);
protected:
using chron_ms = std::chrono::milliseconds;
bool started;
//!< Typedef for the List of objects.
typedef std::vector<ExecutableObjectIF*> ObjectList;
std::thread mainThread;
std::atomic<bool> terminateThread = false;
//! Polling sequence table which contains the object to execute
//! and information like the timeslots and the passed execution step.
FixedSlotSequence pollingSeqTable;
std::condition_variable initCondition;
std::mutex initMutex;
std::string taskName;
/**
* @brief The period of the task.
* @details
* The period determines the frequency of the task's execution.
* It is expressed in clock ticks.
*/
TaskPeriod period;
/**
* @brief The pointer to the deadline-missed function.
* @details
* This pointer stores the function that is executed if the task's deadline
* is missed. So, each may react individually on a timing failure.
* The pointer may be NULL, then nothing happens on missing the deadline.
* The deadline is equal to the next execution of the periodic task.
*/
void (*deadlineMissedFunc)(void);
/**
* @brief This is the function executed in the new task's context.
* @details
* It converts the argument back to the thread object type and copies the
* class instance to the task context.
* The taskFunctionality method is called afterwards.
* @param A pointer to the task object itself is passed as argument.
*/
void taskEntryPoint(void* argument);
/**
* @brief The function containing the actual functionality of the task.
* @details
* The method sets and starts the task's period, then enters a loop that is
* repeated as long as the isRunning attribute is true. Within the loop,
* all performOperation methods of the added objects are called. Afterwards
* the checkAndRestartPeriod system call blocks the task until the next
* period. On missing the deadline, the deadlineMissedFunction is executed.
*/
void taskFunctionality(void);
bool delayForInterval(chron_ms * previousWakeTimeMs,
const chron_ms interval);
};
#endif /* FRAMEWORK_OSAL_HOST_FIXEDTIMESLOTTASK_H_ */
#ifndef FRAMEWORK_OSAL_HOST_FIXEDTIMESLOTTASK_H_
#define FRAMEWORK_OSAL_HOST_FIXEDTIMESLOTTASK_H_
#include "../../objectmanager/ObjectManagerIF.h"
#include "../../tasks/FixedSlotSequence.h"
#include "../../tasks/FixedTimeslotTaskIF.h"
#include "../../tasks/Typedef.h"
#include <vector>
#include <thread>
#include <condition_variable>
#include <atomic>
class ExecutableObjectIF;
/**
* @brief This class represents a task for periodic activities with multiple
* steps and strict timeslot requirements for these steps.
* @details
* @ingroup task_handling
*/
class FixedTimeslotTask: public FixedTimeslotTaskIF {
public:
/**
* @brief Standard constructor of the class.
* @details
* The class is initialized without allocated objects. These need to be
* added with #addComponent.
* @param priority
* @param stack_size
* @param setPeriod
* @param setDeadlineMissedFunc
* The function pointer to the deadline missed function that shall be
* assigned.
*/
FixedTimeslotTask(const char *name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod setPeriod,
void (*setDeadlineMissedFunc)());
/**
* @brief Currently, the executed object's lifetime is not coupled with
* the task object's lifetime, so the destructor is empty.
*/
virtual ~FixedTimeslotTask(void);
/**
* @brief The method to start the task.
* @details The method starts the task with the respective system call.
* Entry point is the taskEntryPoint method described below.
* The address of the task object is passed as an argument
* to the system call.
*/
ReturnValue_t startTask(void);
/**
* Add timeslot to the polling sequence table.
* @param componentId
* @param slotTimeMs
* @param executionStep
* @return
*/
ReturnValue_t addSlot(object_id_t componentId,
uint32_t slotTimeMs, int8_t executionStep);
ReturnValue_t checkAndInitializeSequence() const;
uint32_t getPeriodMs() const;
ReturnValue_t sleepFor(uint32_t ms);
protected:
using chron_ms = std::chrono::milliseconds;
bool started;
//!< Typedef for the List of objects.
typedef std::vector<ExecutableObjectIF*> ObjectList;
std::thread mainThread;
std::atomic<bool> terminateThread = false;
//! Polling sequence table which contains the object to execute
//! and information like the timeslots and the passed execution step.
FixedSlotSequence pollingSeqTable;
std::condition_variable initCondition;
std::mutex initMutex;
std::string taskName;
/**
* @brief The period of the task.
* @details
* The period determines the frequency of the task's execution.
* It is expressed in clock ticks.
*/
TaskPeriod period;
/**
* @brief The pointer to the deadline-missed function.
* @details
* This pointer stores the function that is executed if the task's deadline
* is missed. So, each may react individually on a timing failure.
* The pointer may be NULL, then nothing happens on missing the deadline.
* The deadline is equal to the next execution of the periodic task.
*/
void (*deadlineMissedFunc)(void);
/**
* @brief This is the function executed in the new task's context.
* @details
* It converts the argument back to the thread object type and copies the
* class instance to the task context.
* The taskFunctionality method is called afterwards.
* @param A pointer to the task object itself is passed as argument.
*/
void taskEntryPoint(void* argument);
/**
* @brief The function containing the actual functionality of the task.
* @details
* The method sets and starts the task's period, then enters a loop that is
* repeated as long as the isRunning attribute is true. Within the loop,
* all performOperation methods of the added objects are called. Afterwards
* the checkAndRestartPeriod system call blocks the task until the next
* period. On missing the deadline, the deadlineMissedFunction is executed.
*/
void taskFunctionality(void);
bool delayForInterval(chron_ms * previousWakeTimeMs,
const chron_ms interval);
};
#endif /* FRAMEWORK_OSAL_HOST_FIXEDTIMESLOTTASK_H_ */

View File

@ -1,155 +1,155 @@
#include "../../osal/host/MessageQueue.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../osal/host/QueueMapManager.h"
#include "../../ipc/MutexFactory.h"
#include "../../ipc/MutexHelper.h"
MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize):
messageSize(maxMessageSize), messageDepth(messageDepth) {
queueLock = MutexFactory::instance()->createMutex();
auto result = QueueMapManager::instance()->addMessageQueue(this, &mqId);
if(result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "MessageQueue: Could not be created" << std::endl;
}
}
MessageQueue::~MessageQueue() {
MutexFactory::instance()->deleteMutex(queueLock);
}
ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, bool ignoreFault) {
return sendMessageFrom(sendTo, message, this->getId(), ignoreFault);
}
ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) {
return sendToDefaultFrom(message, this->getId());
}
ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message,
MessageQueueId_t sentFrom, bool ignoreFault) {
return sendMessageFrom(defaultDestination,message,sentFrom,ignoreFault);
}
ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) {
if (this->lastPartner != 0) {
return sendMessageFrom(this->lastPartner, message, this->getId());
} else {
return MessageQueueIF::NO_REPLY_PARTNER;
}
}
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
bool ignoreFault) {
return sendMessageFromMessageQueue(sendTo, message, sentFrom,
ignoreFault);
}
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message,
MessageQueueId_t* receivedFrom) {
ReturnValue_t status = this->receiveMessage(message);
if(status == HasReturnvaluesIF::RETURN_OK) {
*receivedFrom = this->lastPartner;
}
return status;
}
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
if(messageQueue.empty()) {
return MessageQueueIF::EMPTY;
}
// not sure this will work..
//*message = std::move(messageQueue.front());
MutexHelper mutexLock(queueLock, 20);
MessageQueueMessage* currentMessage = &messageQueue.front();
std::copy(currentMessage->getBuffer(),
currentMessage->getBuffer() + messageSize, message->getBuffer());
messageQueue.pop();
// The last partner is the first uint32_t field in the message
this->lastPartner = message->getSender();
return HasReturnvaluesIF::RETURN_OK;
}
MessageQueueId_t MessageQueue::getLastPartner() const {
return lastPartner;
}
ReturnValue_t MessageQueue::flush(uint32_t* count) {
*count = messageQueue.size();
// Clears the queue.
messageQueue = std::queue<MessageQueueMessage>();
return HasReturnvaluesIF::RETURN_OK;
}
MessageQueueId_t MessageQueue::getId() const {
return mqId;
}
void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) {
defaultDestinationSet = true;
this->defaultDestination = defaultDestination;
}
MessageQueueId_t MessageQueue::getDefaultDestination() const {
return defaultDestination;
}
bool MessageQueue::isDefaultDestinationSet() const {
return defaultDestinationSet;
}
// static core function to send messages.
ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
bool ignoreFault) {
if(message->getMessageSize() > message->getMaximumMessageSize()) {
// Actually, this should never happen or an error will be emitted
// in MessageQueueMessage.
// But I will still return a failure here.
return HasReturnvaluesIF::RETURN_FAILED;
}
MessageQueue* targetQueue = dynamic_cast<MessageQueue*>(
QueueMapManager::instance()->getMessageQueue(sendTo));
if(targetQueue == nullptr) {
if(not ignoreFault) {
InternalErrorReporterIF* internalErrorReporter =
objectManager->get<InternalErrorReporterIF>(
objects::INTERNAL_ERROR_REPORTER);
if (internalErrorReporter != nullptr) {
internalErrorReporter->queueMessageNotSent();
}
}
// TODO: Better returnvalue
return HasReturnvaluesIF::RETURN_FAILED;
}
if(targetQueue->messageQueue.size() < targetQueue->messageDepth) {
MutexHelper mutexLock(targetQueue->queueLock, 20);
// not ideal, works for now though.
MessageQueueMessage* mqmMessage =
dynamic_cast<MessageQueueMessage*>(message);
if(message != nullptr) {
targetQueue->messageQueue.push(*mqmMessage);
}
else {
sif::error << "MessageQueue::sendMessageFromMessageQueue: Message"
"is not MessageQueueMessage!" << std::endl;
}
}
else {
return MessageQueueIF::FULL;
}
message->setSender(sentFrom);
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t MessageQueue::lockQueue(dur_millis_t lockTimeout) {
return queueLock->lockMutex(lockTimeout);
}
ReturnValue_t MessageQueue::unlockQueue() {
return queueLock->unlockMutex();
}
#include "../../osal/host/MessageQueue.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../osal/host/QueueMapManager.h"
#include "../../ipc/MutexFactory.h"
#include "../../ipc/MutexHelper.h"
MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize):
messageSize(maxMessageSize), messageDepth(messageDepth) {
queueLock = MutexFactory::instance()->createMutex();
auto result = QueueMapManager::instance()->addMessageQueue(this, &mqId);
if(result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "MessageQueue: Could not be created" << std::endl;
}
}
MessageQueue::~MessageQueue() {
MutexFactory::instance()->deleteMutex(queueLock);
}
ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, bool ignoreFault) {
return sendMessageFrom(sendTo, message, this->getId(), ignoreFault);
}
ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) {
return sendToDefaultFrom(message, this->getId());
}
ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message,
MessageQueueId_t sentFrom, bool ignoreFault) {
return sendMessageFrom(defaultDestination,message,sentFrom,ignoreFault);
}
ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) {
if (this->lastPartner != 0) {
return sendMessageFrom(this->lastPartner, message, this->getId());
} else {
return MessageQueueIF::NO_REPLY_PARTNER;
}
}
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
bool ignoreFault) {
return sendMessageFromMessageQueue(sendTo, message, sentFrom,
ignoreFault);
}
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message,
MessageQueueId_t* receivedFrom) {
ReturnValue_t status = this->receiveMessage(message);
if(status == HasReturnvaluesIF::RETURN_OK) {
*receivedFrom = this->lastPartner;
}
return status;
}
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
if(messageQueue.empty()) {
return MessageQueueIF::EMPTY;
}
// not sure this will work..
//*message = std::move(messageQueue.front());
MutexHelper mutexLock(queueLock, 20);
MessageQueueMessage* currentMessage = &messageQueue.front();
std::copy(currentMessage->getBuffer(),
currentMessage->getBuffer() + messageSize, message->getBuffer());
messageQueue.pop();
// The last partner is the first uint32_t field in the message
this->lastPartner = message->getSender();
return HasReturnvaluesIF::RETURN_OK;
}
MessageQueueId_t MessageQueue::getLastPartner() const {
return lastPartner;
}
ReturnValue_t MessageQueue::flush(uint32_t* count) {
*count = messageQueue.size();
// Clears the queue.
messageQueue = std::queue<MessageQueueMessage>();
return HasReturnvaluesIF::RETURN_OK;
}
MessageQueueId_t MessageQueue::getId() const {
return mqId;
}
void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) {
defaultDestinationSet = true;
this->defaultDestination = defaultDestination;
}
MessageQueueId_t MessageQueue::getDefaultDestination() const {
return defaultDestination;
}
bool MessageQueue::isDefaultDestinationSet() const {
return defaultDestinationSet;
}
// static core function to send messages.
ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
bool ignoreFault) {
if(message->getMessageSize() > message->getMaximumMessageSize()) {
// Actually, this should never happen or an error will be emitted
// in MessageQueueMessage.
// But I will still return a failure here.
return HasReturnvaluesIF::RETURN_FAILED;
}
MessageQueue* targetQueue = dynamic_cast<MessageQueue*>(
QueueMapManager::instance()->getMessageQueue(sendTo));
if(targetQueue == nullptr) {
if(not ignoreFault) {
InternalErrorReporterIF* internalErrorReporter =
objectManager->get<InternalErrorReporterIF>(
objects::INTERNAL_ERROR_REPORTER);
if (internalErrorReporter != nullptr) {
internalErrorReporter->queueMessageNotSent();
}
}
// TODO: Better returnvalue
return HasReturnvaluesIF::RETURN_FAILED;
}
if(targetQueue->messageQueue.size() < targetQueue->messageDepth) {
MutexHelper mutexLock(targetQueue->queueLock, 20);
// not ideal, works for now though.
MessageQueueMessage* mqmMessage =
dynamic_cast<MessageQueueMessage*>(message);
if(message != nullptr) {
targetQueue->messageQueue.push(*mqmMessage);
}
else {
sif::error << "MessageQueue::sendMessageFromMessageQueue: Message"
"is not MessageQueueMessage!" << std::endl;
}
}
else {
return MessageQueueIF::FULL;
}
message->setSender(sentFrom);
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t MessageQueue::lockQueue(dur_millis_t lockTimeout) {
return queueLock->lockMutex(lockTimeout);
}
ReturnValue_t MessageQueue::unlockQueue() {
return queueLock->unlockMutex();
}

View File

@ -1,230 +1,230 @@
#ifndef FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_
#define FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_
#include "../../internalError/InternalErrorReporterIF.h"
#include "../../ipc/MessageQueueIF.h"
#include "../../ipc/MessageQueueMessage.h"
#include "../../ipc/MutexIF.h"
#include "../../timemanager/Clock.h"
#include <queue>
#include <memory>
/**
* @brief This class manages sending and receiving of
* message queue messages.
* @details
* Message queues are used to pass asynchronous messages between processes.
* They work like post boxes, where all incoming messages are stored in FIFO
* order. This class creates a new receiving queue and provides methods to fetch
* received messages. Being a child of MessageQueueSender, this class also
* provides methods to send a message to a user-defined or a default destination.
* In addition it also provides a reply method to answer to the queue it
* received its last message from.
*
* The MessageQueue should be used as "post box" for a single owning object.
* So all message queue communication is "n-to-one".
* For creating the queue, as well as sending and receiving messages, the class
* makes use of the operating system calls provided.
*
* Please keep in mind that FreeRTOS offers different calls for message queue
* operations if called from an ISR.
* For now, the system context needs to be switched manually.
* @ingroup osal
* @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
* in case of failure, it is set to zero.
* @param message_depth
* The number of messages to be buffered before passing an error to the
* sender. Default is three.
* @param max_message_size
* With this parameter, the maximum message size can be adjusted.
* This should be left default.
*/
MessageQueue(size_t messageDepth = 3,
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE);
/** Copying message queues forbidden */
MessageQueue(const MessageQueue&) = delete;
MessageQueue& operator=(const MessageQueue&) = delete;
/**
* @brief The destructor deletes the formerly created message queue.
* @details This is accomplished by using the delete call provided
* by the operating system.
*/
virtual ~MessageQueue();
/**
* @brief This operation sends a message to the given destination.
* @details It directly uses the sendMessage call of the MessageQueueSender
* parent, but passes its queue id as "sentFrom" parameter.
* @param sendTo This parameter specifies the message queue id of the
* destination message queue.
* @param message A pointer to a previously created message, which is sent.
* @param ignoreFault If set to true, the internal software fault counter
* is not incremented if queue is full.
*/
ReturnValue_t sendMessage(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, bool ignoreFault = false) override;
/**
* @brief This operation sends a message to the default destination.
* @details As in the sendMessage method, this function uses the
* sendToDefault call of the MessageQueueSender parent class and adds its
* queue id as "sentFrom" information.
* @param message A pointer to a previously created message, which is sent.
*/
ReturnValue_t sendToDefault(MessageQueueMessageIF* message) override;
/**
* @brief This operation sends a message to the last communication partner.
* @details This operation simplifies answering an incoming message by using
* the stored lastPartner 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) override;
/**
* @brief With the sendMessage call, a queue message is sent to a
* receiving queue.
* @details
* This method takes the message provided, adds the sentFrom information and
* passes it on to the destination provided with an operating system call.
* The OS's return value is returned.
* @param sendTo This parameter specifies the message queue id to send
* the message to.
* @param message This is a pointer to a previously created message,
* which is sent.
* @param sentFrom The sentFrom information can be set to inject the
* sender's queue id into the message. This variable is set to zero by
* default.
* @param ignoreFault If set to true, the internal software fault counter
* is not incremented if queue is full.
*/
virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE,
bool ignoreFault = false) override;
/**
* @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) override;
/**
* @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) override;
/**
* @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) override;
/**
* 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) override;
/**
* @brief This method returns the message queue id of the last
* communication partner.
*/
MessageQueueId_t getLastPartner() const override;
/**
* @brief This method returns the message queue id of this class's
* message queue.
*/
MessageQueueId_t getId() const override;
/**
* @brief This method is a simple setter for the default destination.
*/
void setDefaultDestination(MessageQueueId_t defaultDestination) override;
/**
* @brief This method is a simple getter for the default destination.
*/
MessageQueueId_t getDefaultDestination() const override;
bool isDefaultDestinationSet() const override;
ReturnValue_t lockQueue(dur_millis_t lockTimeout);
ReturnValue_t unlockQueue();
protected:
/**
* @brief 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.
* @param context Specify whether call is made from task or from an ISR.
*/
static ReturnValue_t sendMessageFromMessageQueue(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE,
bool ignoreFault=false);
//static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault);
private:
std::queue<MessageQueueMessage> messageQueue;
/**
* @brief The class stores the queue id it got assigned.
* If initialization fails, the queue id is set to zero.
*/
MessageQueueId_t mqId = 0;
size_t messageSize = 0;
size_t messageDepth = 0;
MutexIF* queueLock;
bool defaultDestinationSet = false;
MessageQueueId_t defaultDestination = 0;
MessageQueueId_t lastPartner = 0;
};
#endif /* FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_ */
#ifndef FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_
#define FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_
#include "../../internalError/InternalErrorReporterIF.h"
#include "../../ipc/MessageQueueIF.h"
#include "../../ipc/MessageQueueMessage.h"
#include "../../ipc/MutexIF.h"
#include "../../timemanager/Clock.h"
#include <queue>
#include <memory>
/**
* @brief This class manages sending and receiving of
* message queue messages.
* @details
* Message queues are used to pass asynchronous messages between processes.
* They work like post boxes, where all incoming messages are stored in FIFO
* order. This class creates a new receiving queue and provides methods to fetch
* received messages. Being a child of MessageQueueSender, this class also
* provides methods to send a message to a user-defined or a default destination.
* In addition it also provides a reply method to answer to the queue it
* received its last message from.
*
* The MessageQueue should be used as "post box" for a single owning object.
* So all message queue communication is "n-to-one".
* For creating the queue, as well as sending and receiving messages, the class
* makes use of the operating system calls provided.
*
* Please keep in mind that FreeRTOS offers different calls for message queue
* operations if called from an ISR.
* For now, the system context needs to be switched manually.
* @ingroup osal
* @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
* in case of failure, it is set to zero.
* @param message_depth
* The number of messages to be buffered before passing an error to the
* sender. Default is three.
* @param max_message_size
* With this parameter, the maximum message size can be adjusted.
* This should be left default.
*/
MessageQueue(size_t messageDepth = 3,
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE);
/** Copying message queues forbidden */
MessageQueue(const MessageQueue&) = delete;
MessageQueue& operator=(const MessageQueue&) = delete;
/**
* @brief The destructor deletes the formerly created message queue.
* @details This is accomplished by using the delete call provided
* by the operating system.
*/
virtual ~MessageQueue();
/**
* @brief This operation sends a message to the given destination.
* @details It directly uses the sendMessage call of the MessageQueueSender
* parent, but passes its queue id as "sentFrom" parameter.
* @param sendTo This parameter specifies the message queue id of the
* destination message queue.
* @param message A pointer to a previously created message, which is sent.
* @param ignoreFault If set to true, the internal software fault counter
* is not incremented if queue is full.
*/
ReturnValue_t sendMessage(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, bool ignoreFault = false) override;
/**
* @brief This operation sends a message to the default destination.
* @details As in the sendMessage method, this function uses the
* sendToDefault call of the MessageQueueSender parent class and adds its
* queue id as "sentFrom" information.
* @param message A pointer to a previously created message, which is sent.
*/
ReturnValue_t sendToDefault(MessageQueueMessageIF* message) override;
/**
* @brief This operation sends a message to the last communication partner.
* @details This operation simplifies answering an incoming message by using
* the stored lastPartner 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) override;
/**
* @brief With the sendMessage call, a queue message is sent to a
* receiving queue.
* @details
* This method takes the message provided, adds the sentFrom information and
* passes it on to the destination provided with an operating system call.
* The OS's return value is returned.
* @param sendTo This parameter specifies the message queue id to send
* the message to.
* @param message This is a pointer to a previously created message,
* which is sent.
* @param sentFrom The sentFrom information can be set to inject the
* sender's queue id into the message. This variable is set to zero by
* default.
* @param ignoreFault If set to true, the internal software fault counter
* is not incremented if queue is full.
*/
virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE,
bool ignoreFault = false) override;
/**
* @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) override;
/**
* @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) override;
/**
* @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) override;
/**
* 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) override;
/**
* @brief This method returns the message queue id of the last
* communication partner.
*/
MessageQueueId_t getLastPartner() const override;
/**
* @brief This method returns the message queue id of this class's
* message queue.
*/
MessageQueueId_t getId() const override;
/**
* @brief This method is a simple setter for the default destination.
*/
void setDefaultDestination(MessageQueueId_t defaultDestination) override;
/**
* @brief This method is a simple getter for the default destination.
*/
MessageQueueId_t getDefaultDestination() const override;
bool isDefaultDestinationSet() const override;
ReturnValue_t lockQueue(dur_millis_t lockTimeout);
ReturnValue_t unlockQueue();
protected:
/**
* @brief 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.
* @param context Specify whether call is made from task or from an ISR.
*/
static ReturnValue_t sendMessageFromMessageQueue(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE,
bool ignoreFault=false);
//static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault);
private:
std::queue<MessageQueueMessage> messageQueue;
/**
* @brief The class stores the queue id it got assigned.
* If initialization fails, the queue id is set to zero.
*/
MessageQueueId_t mqId = 0;
size_t messageSize = 0;
size_t messageDepth = 0;
MutexIF* queueLock;
bool defaultDestinationSet = false;
MessageQueueId_t defaultDestination = 0;
MessageQueueId_t lastPartner = 0;
};
#endif /* FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_ */

View File

@ -1,40 +1,40 @@
#include "../../osal/host/Mutex.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
const uint32_t MutexIF::POLLING = 0;
const uint32_t MutexIF::BLOCKING = 0xffffffff;
ReturnValue_t Mutex::lockMutex(uint32_t timeoutMs) {
if(timeoutMs == MutexIF::BLOCKING) {
mutex.lock();
locked = true;
return HasReturnvaluesIF::RETURN_OK;
}
else if(timeoutMs == MutexIF::POLLING) {
if(mutex.try_lock()) {
locked = true;
return HasReturnvaluesIF::RETURN_OK;
}
}
else if(timeoutMs > MutexIF::POLLING){
auto chronoMs = std::chrono::milliseconds(timeoutMs);
if(mutex.try_lock_for(chronoMs)) {
locked = true;
return HasReturnvaluesIF::RETURN_OK;
}
}
return MutexIF::MUTEX_TIMEOUT;
}
ReturnValue_t Mutex::unlockMutex() {
if(not locked) {
return MutexIF::CURR_THREAD_DOES_NOT_OWN_MUTEX;
}
mutex.unlock();
locked = false;
return HasReturnvaluesIF::RETURN_OK;
}
std::timed_mutex* Mutex::getMutexHandle() {
return &mutex;
}
#include "../../osal/host/Mutex.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
const uint32_t MutexIF::POLLING = 0;
const uint32_t MutexIF::BLOCKING = 0xffffffff;
ReturnValue_t Mutex::lockMutex(uint32_t timeoutMs) {
if(timeoutMs == MutexIF::BLOCKING) {
mutex.lock();
locked = true;
return HasReturnvaluesIF::RETURN_OK;
}
else if(timeoutMs == MutexIF::POLLING) {
if(mutex.try_lock()) {
locked = true;
return HasReturnvaluesIF::RETURN_OK;
}
}
else if(timeoutMs > MutexIF::POLLING){
auto chronoMs = std::chrono::milliseconds(timeoutMs);
if(mutex.try_lock_for(chronoMs)) {
locked = true;
return HasReturnvaluesIF::RETURN_OK;
}
}
return MutexIF::MUTEX_TIMEOUT;
}
ReturnValue_t Mutex::unlockMutex() {
if(not locked) {
return MutexIF::CURR_THREAD_DOES_NOT_OWN_MUTEX;
}
mutex.unlock();
locked = false;
return HasReturnvaluesIF::RETURN_OK;
}
std::timed_mutex* Mutex::getMutexHandle() {
return &mutex;
}

View File

@ -1,28 +1,28 @@
#ifndef FRAMEWORK_OSAL_FREERTOS_MUTEX_H_
#define FRAMEWORK_OSAL_FREERTOS_MUTEX_H_
#include "../../ipc/MutexIF.h"
#include <mutex>
/**
* @brief OS component to implement MUTual EXclusion
*
* @details
* Mutexes are binary semaphores which include a priority inheritance mechanism.
* Documentation: https://www.freertos.org/Real-time-embedded-RTOS-mutexes.html
* @ingroup osal
*/
class Mutex : public MutexIF {
public:
Mutex() = default;
ReturnValue_t lockMutex(uint32_t timeoutMs = MutexIF::BLOCKING) override;
ReturnValue_t unlockMutex() override;
std::timed_mutex* getMutexHandle();
private:
bool locked = false;
std::timed_mutex mutex;
};
#endif /* FRAMEWORK_FREERTOS_MUTEX_H_ */
#ifndef FRAMEWORK_OSAL_FREERTOS_MUTEX_H_
#define FRAMEWORK_OSAL_FREERTOS_MUTEX_H_
#include "../../ipc/MutexIF.h"
#include <mutex>
/**
* @brief OS component to implement MUTual EXclusion
*
* @details
* Mutexes are binary semaphores which include a priority inheritance mechanism.
* Documentation: https://www.freertos.org/Real-time-embedded-RTOS-mutexes.html
* @ingroup osal
*/
class Mutex : public MutexIF {
public:
Mutex() = default;
ReturnValue_t lockMutex(uint32_t timeoutMs = MutexIF::BLOCKING) override;
ReturnValue_t unlockMutex() override;
std::timed_mutex* getMutexHandle();
private:
bool locked = false;
std::timed_mutex mutex;
};
#endif /* FRAMEWORK_FREERTOS_MUTEX_H_ */

View File

@ -1,28 +1,28 @@
#include "../../ipc/MutexFactory.h"
#include "../../osal/host/Mutex.h"
//TODO: Different variant than the lazy loading in QueueFactory.
//What's better and why? -> one is on heap the other on bss/data
//MutexFactory* MutexFactory::factoryInstance = new MutexFactory();
MutexFactory* MutexFactory::factoryInstance = nullptr;
MutexFactory::MutexFactory() {
}
MutexFactory::~MutexFactory() {
}
MutexFactory* MutexFactory::instance() {
if (factoryInstance == nullptr){
factoryInstance = new MutexFactory();
}
return MutexFactory::factoryInstance;
}
MutexIF* MutexFactory::createMutex() {
return new Mutex();
}
void MutexFactory::deleteMutex(MutexIF* mutex) {
delete mutex;
}
#include "../../ipc/MutexFactory.h"
#include "../../osal/host/Mutex.h"
//TODO: Different variant than the lazy loading in QueueFactory.
//What's better and why? -> one is on heap the other on bss/data
//MutexFactory* MutexFactory::factoryInstance = new MutexFactory();
MutexFactory* MutexFactory::factoryInstance = nullptr;
MutexFactory::MutexFactory() {
}
MutexFactory::~MutexFactory() {
}
MutexFactory* MutexFactory::instance() {
if (factoryInstance == nullptr){
factoryInstance = new MutexFactory();
}
return MutexFactory::factoryInstance;
}
MutexIF* MutexFactory::createMutex() {
return new Mutex();
}
void MutexFactory::deleteMutex(MutexIF* mutex) {
delete mutex;
}

View File

@ -1,176 +1,176 @@
#include "../../ipc/MutexFactory.h"
#include "../../osal/host/Mutex.h"
#include "../../osal/host/PeriodicTask.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../tasks/ExecutableObjectIF.h"
#include <thread>
#include <chrono>
#if defined(WIN32)
#include <windows.h>
#elif defined(LINUX)
#include <pthread.h>
#endif
PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod setPeriod,
void (*setDeadlineMissedFunc)()) :
started(false), taskName(name), period(setPeriod),
deadlineMissedFunc(setDeadlineMissedFunc) {
// It is propably possible to set task priorities by using the native
// task handles for Windows / Linux
mainThread = std::thread(&PeriodicTask::taskEntryPoint, this, this);
#if defined(WIN32)
/* List of possible priority classes:
* https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/
* nf-processthreadsapi-setpriorityclass
* And respective thread priority numbers:
* https://docs.microsoft.com/en-us/windows/
* win32/procthread/scheduling-priorities */
int result = SetPriorityClass(
reinterpret_cast<HANDLE>(mainThread.native_handle()),
ABOVE_NORMAL_PRIORITY_CLASS);
if(result != 0) {
sif::error << "PeriodicTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl;
}
result = SetThreadPriority(
reinterpret_cast<HANDLE>(mainThread.native_handle()),
THREAD_PRIORITY_NORMAL);
if(result != 0) {
sif::error << "PeriodicTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl;
}
#elif defined(LINUX)
// we can just copy and paste the code from linux here.
#endif
}
PeriodicTask::~PeriodicTask(void) {
//Do not delete objects, we were responsible for ptrs only.
terminateThread = true;
if(mainThread.joinable()) {
mainThread.join();
}
delete this;
}
void PeriodicTask::taskEntryPoint(void* argument) {
PeriodicTask *originalTask(reinterpret_cast<PeriodicTask*>(argument));
if (not originalTask->started) {
// we have to suspend/block here until the task is started.
// if semaphores are implemented, use them here.
std::unique_lock<std::mutex> lock(initMutex);
initCondition.wait(lock);
}
this->taskFunctionality();
sif::debug << "PeriodicTask::taskEntryPoint: "
"Returned from taskFunctionality." << std::endl;
}
ReturnValue_t PeriodicTask::startTask() {
started = true;
// Notify task to start.
std::lock_guard<std::mutex> lock(initMutex);
initCondition.notify_one();
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t PeriodicTask::sleepFor(uint32_t ms) {
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
return HasReturnvaluesIF::RETURN_OK;
}
void PeriodicTask::taskFunctionality() {
std::chrono::milliseconds periodChrono(static_cast<uint32_t>(period*1000));
auto currentStartTime {
std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())
};
auto nextStartTime{ currentStartTime };
/* Enter the loop that defines the task behavior. */
for (;;) {
if(terminateThread.load()) {
break;
}
for (ObjectList::iterator it = objectList.begin();
it != objectList.end(); ++it) {
(*it)->performOperation();
}
if(not delayForInterval(&currentStartTime, periodChrono)) {
sif::warning << "PeriodicTask: " << taskName <<
" missed deadline!\n" << std::flush;
if(deadlineMissedFunc != nullptr) {
this->deadlineMissedFunc();
}
}
}
}
ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>(
object);
if (newObject == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
objectList.push_back(newObject);
return HasReturnvaluesIF::RETURN_OK;
}
uint32_t PeriodicTask::getPeriodMs() const {
return period * 1000;
}
bool PeriodicTask::delayForInterval(chron_ms* previousWakeTimeMs,
const chron_ms interval) {
bool shouldDelay = false;
//Get current wakeup time
auto currentStartTime =
std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch());
/* Generate the tick time at which the task wants to wake. */
auto nextTimeToWake_ms = (*previousWakeTimeMs) + interval;
if (currentStartTime < *previousWakeTimeMs) {
/* 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 < *previousWakeTimeMs)
&& (nextTimeToWake_ms > currentStartTime)) {
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 < *previousWakeTimeMs)
|| (nextTimeToWake_ms > currentStartTime)) {
shouldDelay = true;
}
}
/* Update the wake time ready for the next call. */
(*previousWakeTimeMs) = nextTimeToWake_ms;
if (shouldDelay) {
auto sleepTime = std::chrono::duration_cast<std::chrono::milliseconds>(
nextTimeToWake_ms - currentStartTime);
std::this_thread::sleep_for(sleepTime);
return true;
}
//We are shifting the time in case the deadline was missed like rtems
(*previousWakeTimeMs) = currentStartTime;
return false;
}
#include "../../ipc/MutexFactory.h"
#include "../../osal/host/Mutex.h"
#include "../../osal/host/PeriodicTask.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../tasks/ExecutableObjectIF.h"
#include <thread>
#include <chrono>
#if defined(WIN32)
#include <windows.h>
#elif defined(LINUX)
#include <pthread.h>
#endif
PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod setPeriod,
void (*setDeadlineMissedFunc)()) :
started(false), taskName(name), period(setPeriod),
deadlineMissedFunc(setDeadlineMissedFunc) {
// It is propably possible to set task priorities by using the native
// task handles for Windows / Linux
mainThread = std::thread(&PeriodicTask::taskEntryPoint, this, this);
#if defined(WIN32)
/* List of possible priority classes:
* https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/
* nf-processthreadsapi-setpriorityclass
* And respective thread priority numbers:
* https://docs.microsoft.com/en-us/windows/
* win32/procthread/scheduling-priorities */
int result = SetPriorityClass(
reinterpret_cast<HANDLE>(mainThread.native_handle()),
ABOVE_NORMAL_PRIORITY_CLASS);
if(result != 0) {
sif::error << "PeriodicTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl;
}
result = SetThreadPriority(
reinterpret_cast<HANDLE>(mainThread.native_handle()),
THREAD_PRIORITY_NORMAL);
if(result != 0) {
sif::error << "PeriodicTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl;
}
#elif defined(LINUX)
// we can just copy and paste the code from linux here.
#endif
}
PeriodicTask::~PeriodicTask(void) {
//Do not delete objects, we were responsible for ptrs only.
terminateThread = true;
if(mainThread.joinable()) {
mainThread.join();
}
delete this;
}
void PeriodicTask::taskEntryPoint(void* argument) {
PeriodicTask *originalTask(reinterpret_cast<PeriodicTask*>(argument));
if (not originalTask->started) {
// we have to suspend/block here until the task is started.
// if semaphores are implemented, use them here.
std::unique_lock<std::mutex> lock(initMutex);
initCondition.wait(lock);
}
this->taskFunctionality();
sif::debug << "PeriodicTask::taskEntryPoint: "
"Returned from taskFunctionality." << std::endl;
}
ReturnValue_t PeriodicTask::startTask() {
started = true;
// Notify task to start.
std::lock_guard<std::mutex> lock(initMutex);
initCondition.notify_one();
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t PeriodicTask::sleepFor(uint32_t ms) {
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
return HasReturnvaluesIF::RETURN_OK;
}
void PeriodicTask::taskFunctionality() {
std::chrono::milliseconds periodChrono(static_cast<uint32_t>(period*1000));
auto currentStartTime {
std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())
};
auto nextStartTime{ currentStartTime };
/* Enter the loop that defines the task behavior. */
for (;;) {
if(terminateThread.load()) {
break;
}
for (ObjectList::iterator it = objectList.begin();
it != objectList.end(); ++it) {
(*it)->performOperation();
}
if(not delayForInterval(&currentStartTime, periodChrono)) {
sif::warning << "PeriodicTask: " << taskName <<
" missed deadline!\n" << std::flush;
if(deadlineMissedFunc != nullptr) {
this->deadlineMissedFunc();
}
}
}
}
ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>(
object);
if (newObject == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
objectList.push_back(newObject);
return HasReturnvaluesIF::RETURN_OK;
}
uint32_t PeriodicTask::getPeriodMs() const {
return period * 1000;
}
bool PeriodicTask::delayForInterval(chron_ms* previousWakeTimeMs,
const chron_ms interval) {
bool shouldDelay = false;
//Get current wakeup time
auto currentStartTime =
std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch());
/* Generate the tick time at which the task wants to wake. */
auto nextTimeToWake_ms = (*previousWakeTimeMs) + interval;
if (currentStartTime < *previousWakeTimeMs) {
/* 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 < *previousWakeTimeMs)
&& (nextTimeToWake_ms > currentStartTime)) {
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 < *previousWakeTimeMs)
|| (nextTimeToWake_ms > currentStartTime)) {
shouldDelay = true;
}
}
/* Update the wake time ready for the next call. */
(*previousWakeTimeMs) = nextTimeToWake_ms;
if (shouldDelay) {
auto sleepTime = std::chrono::duration_cast<std::chrono::milliseconds>(
nextTimeToWake_ms - currentStartTime);
std::this_thread::sleep_for(sleepTime);
return true;
}
//We are shifting the time in case the deadline was missed like rtems
(*previousWakeTimeMs) = currentStartTime;
return false;
}

View File

@ -1,123 +1,123 @@
#ifndef FRAMEWORK_OSAL_HOST_PERIODICTASK_H_
#define FRAMEWORK_OSAL_HOST_PERIODICTASK_H_
#include "../../objectmanager/ObjectManagerIF.h"
#include "../../tasks/PeriodicTaskIF.h"
#include "../../tasks/Typedef.h"
#include <vector>
#include <thread>
#include <condition_variable>
#include <atomic>
class ExecutableObjectIF;
/**
* @brief This class represents a specialized task for
* periodic activities of multiple objects.
* @details
*
* @ingroup task_handling
*/
class PeriodicTask: public PeriodicTaskIF {
public:
/**
* @brief Standard constructor of the class.
* @details
* The class is initialized without allocated objects. These need to be
* added with #addComponent.
* @param priority
* @param stack_size
* @param setPeriod
* @param setDeadlineMissedFunc
* The function pointer to the deadline missed function that shall be
* assigned.
*/
PeriodicTask(const char *name, TaskPriority setPriority, TaskStackSize setStack,
TaskPeriod setPeriod,void (*setDeadlineMissedFunc)());
/**
* @brief Currently, the executed object's lifetime is not coupled with
* the task object's lifetime, so the destructor is empty.
*/
virtual ~PeriodicTask(void);
/**
* @brief The method to start the task.
* @details The method starts the task with the respective system call.
* Entry point is the taskEntryPoint method described below.
* The address of the task object is passed as an argument
* to the system call.
*/
ReturnValue_t startTask(void);
/**
* Adds an object to the list of objects to be executed.
* The objects are executed in the order added.
* @param object Id of the object to add.
* @return
* -@c RETURN_OK on success
* -@c RETURN_FAILED if the object could not be added.
*/
ReturnValue_t addComponent(object_id_t object);
uint32_t getPeriodMs() const;
ReturnValue_t sleepFor(uint32_t ms);
protected:
using chron_ms = std::chrono::milliseconds;
bool started;
//!< Typedef for the List of objects.
typedef std::vector<ExecutableObjectIF*> ObjectList;
std::thread mainThread;
std::atomic<bool> terminateThread = false;
/**
* @brief This attribute holds a list of objects to be executed.
*/
ObjectList objectList;
std::condition_variable initCondition;
std::mutex initMutex;
std::string taskName;
/**
* @brief The period of the task.
* @details
* The period determines the frequency of the task's execution.
* It is expressed in clock ticks.
*/
TaskPeriod period;
/**
* @brief The pointer to the deadline-missed function.
* @details
* This pointer stores the function that is executed if the task's deadline
* is missed. So, each may react individually on a timing failure.
* The pointer may be NULL, then nothing happens on missing the deadline.
* The deadline is equal to the next execution of the periodic task.
*/
void (*deadlineMissedFunc)(void);
/**
* @brief This is the function executed in the new task's context.
* @details
* It converts the argument back to the thread object type and copies the
* class instance to the task context.
* The taskFunctionality method is called afterwards.
* @param A pointer to the task object itself is passed as argument.
*/
void taskEntryPoint(void* argument);
/**
* @brief The function containing the actual functionality of the task.
* @details
* The method sets and starts the task's period, then enters a loop that is
* repeated as long as the isRunning attribute is true. Within the loop,
* all performOperation methods of the added objects are called. Afterwards
* the checkAndRestartPeriod system call blocks the task until the next
* period. On missing the deadline, the deadlineMissedFunction is executed.
*/
void taskFunctionality(void);
bool delayForInterval(chron_ms * previousWakeTimeMs,
const chron_ms interval);
};
#endif /* PERIODICTASK_H_ */
#ifndef FRAMEWORK_OSAL_HOST_PERIODICTASK_H_
#define FRAMEWORK_OSAL_HOST_PERIODICTASK_H_
#include "../../objectmanager/ObjectManagerIF.h"
#include "../../tasks/PeriodicTaskIF.h"
#include "../../tasks/Typedef.h"
#include <vector>
#include <thread>
#include <condition_variable>
#include <atomic>
class ExecutableObjectIF;
/**
* @brief This class represents a specialized task for
* periodic activities of multiple objects.
* @details
*
* @ingroup task_handling
*/
class PeriodicTask: public PeriodicTaskIF {
public:
/**
* @brief Standard constructor of the class.
* @details
* The class is initialized without allocated objects. These need to be
* added with #addComponent.
* @param priority
* @param stack_size
* @param setPeriod
* @param setDeadlineMissedFunc
* The function pointer to the deadline missed function that shall be
* assigned.
*/
PeriodicTask(const char *name, TaskPriority setPriority, TaskStackSize setStack,
TaskPeriod setPeriod,void (*setDeadlineMissedFunc)());
/**
* @brief Currently, the executed object's lifetime is not coupled with
* the task object's lifetime, so the destructor is empty.
*/
virtual ~PeriodicTask(void);
/**
* @brief The method to start the task.
* @details The method starts the task with the respective system call.
* Entry point is the taskEntryPoint method described below.
* The address of the task object is passed as an argument
* to the system call.
*/
ReturnValue_t startTask(void);
/**
* Adds an object to the list of objects to be executed.
* The objects are executed in the order added.
* @param object Id of the object to add.
* @return
* -@c RETURN_OK on success
* -@c RETURN_FAILED if the object could not be added.
*/
ReturnValue_t addComponent(object_id_t object);
uint32_t getPeriodMs() const;
ReturnValue_t sleepFor(uint32_t ms);
protected:
using chron_ms = std::chrono::milliseconds;
bool started;
//!< Typedef for the List of objects.
typedef std::vector<ExecutableObjectIF*> ObjectList;
std::thread mainThread;
std::atomic<bool> terminateThread = false;
/**
* @brief This attribute holds a list of objects to be executed.
*/
ObjectList objectList;
std::condition_variable initCondition;
std::mutex initMutex;
std::string taskName;
/**
* @brief The period of the task.
* @details
* The period determines the frequency of the task's execution.
* It is expressed in clock ticks.
*/
TaskPeriod period;
/**
* @brief The pointer to the deadline-missed function.
* @details
* This pointer stores the function that is executed if the task's deadline
* is missed. So, each may react individually on a timing failure.
* The pointer may be NULL, then nothing happens on missing the deadline.
* The deadline is equal to the next execution of the periodic task.
*/
void (*deadlineMissedFunc)(void);
/**
* @brief This is the function executed in the new task's context.
* @details
* It converts the argument back to the thread object type and copies the
* class instance to the task context.
* The taskFunctionality method is called afterwards.
* @param A pointer to the task object itself is passed as argument.
*/
void taskEntryPoint(void* argument);
/**
* @brief The function containing the actual functionality of the task.
* @details
* The method sets and starts the task's period, then enters a loop that is
* repeated as long as the isRunning attribute is true. Within the loop,
* all performOperation methods of the added objects are called. Afterwards
* the checkAndRestartPeriod system call blocks the task until the next
* period. On missing the deadline, the deadlineMissedFunction is executed.
*/
void taskFunctionality(void);
bool delayForInterval(chron_ms * previousWakeTimeMs,
const chron_ms interval);
};
#endif /* PERIODICTASK_H_ */

View File

@ -1,41 +1,41 @@
#include "../../ipc/QueueFactory.h"
#include "../../osal/host/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);
return HasReturnvaluesIF::RETURN_OK;
}
QueueFactory* QueueFactory::instance() {
if (factoryInstance == nullptr) {
factoryInstance = new QueueFactory;
}
return factoryInstance;
}
QueueFactory::QueueFactory() {
}
QueueFactory::~QueueFactory() {
}
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth,
size_t maxMessageSize) {
// A thread-safe queue can be implemented by using a combination
// of std::queue and std::mutex. This uses dynamic memory allocation
// which could be alleviated by using a custom allocator, external library
// (etl::queue) or simply using std::queue, we're on a host machine anyway.
return new MessageQueue(messageDepth, maxMessageSize);
}
void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) {
delete queue;
}
#include "../../ipc/QueueFactory.h"
#include "../../osal/host/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);
return HasReturnvaluesIF::RETURN_OK;
}
QueueFactory* QueueFactory::instance() {
if (factoryInstance == nullptr) {
factoryInstance = new QueueFactory;
}
return factoryInstance;
}
QueueFactory::QueueFactory() {
}
QueueFactory::~QueueFactory() {
}
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth,
size_t maxMessageSize) {
// A thread-safe queue can be implemented by using a combination
// of std::queue and std::mutex. This uses dynamic memory allocation
// which could be alleviated by using a custom allocator, external library
// (etl::queue) or simply using std::queue, we're on a host machine anyway.
return new MessageQueue(messageDepth, maxMessageSize);
}
void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) {
delete queue;
}

View File

@ -1,51 +1,51 @@
#include "../../ipc/MutexFactory.h"
#include "../../ipc/MutexHelper.h"
#include "../../osal/host/QueueMapManager.h"
QueueMapManager* QueueMapManager::mqManagerInstance = nullptr;
QueueMapManager::QueueMapManager() {
mapLock = MutexFactory::instance()->createMutex();
}
QueueMapManager* QueueMapManager::instance() {
if (mqManagerInstance == nullptr){
mqManagerInstance = new QueueMapManager();
}
return QueueMapManager::mqManagerInstance;
}
ReturnValue_t QueueMapManager::addMessageQueue(
MessageQueueIF* queueToInsert, MessageQueueId_t* id) {
// Not thread-safe, but it is assumed all message queues are created
// at software initialization now. If this is to be made thread-safe in
// the future, it propably would be sufficient to lock the increment
// operation here
uint32_t currentId = queueCounter++;
auto returnPair = queueMap.emplace(currentId, queueToInsert);
if(not returnPair.second) {
// this should never happen for the atomic variable.
sif::error << "QueueMapManager: This ID is already inside the map!"
<< std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
if (id != nullptr) {
*id = currentId;
}
return HasReturnvaluesIF::RETURN_OK;
}
MessageQueueIF* QueueMapManager::getMessageQueue(
MessageQueueId_t messageQueueId) const {
MutexHelper(mapLock, 50);
auto queueIter = queueMap.find(messageQueueId);
if(queueIter != queueMap.end()) {
return queueIter->second;
}
else {
sif::warning << "QueueMapManager::getQueueHandle: The ID" <<
messageQueueId << " does not exists in the map" << std::endl;
return nullptr;
}
}
#include "../../ipc/MutexFactory.h"
#include "../../ipc/MutexHelper.h"
#include "../../osal/host/QueueMapManager.h"
QueueMapManager* QueueMapManager::mqManagerInstance = nullptr;
QueueMapManager::QueueMapManager() {
mapLock = MutexFactory::instance()->createMutex();
}
QueueMapManager* QueueMapManager::instance() {
if (mqManagerInstance == nullptr){
mqManagerInstance = new QueueMapManager();
}
return QueueMapManager::mqManagerInstance;
}
ReturnValue_t QueueMapManager::addMessageQueue(
MessageQueueIF* queueToInsert, MessageQueueId_t* id) {
// Not thread-safe, but it is assumed all message queues are created
// at software initialization now. If this is to be made thread-safe in
// the future, it propably would be sufficient to lock the increment
// operation here
uint32_t currentId = queueCounter++;
auto returnPair = queueMap.emplace(currentId, queueToInsert);
if(not returnPair.second) {
// this should never happen for the atomic variable.
sif::error << "QueueMapManager: This ID is already inside the map!"
<< std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
if (id != nullptr) {
*id = currentId;
}
return HasReturnvaluesIF::RETURN_OK;
}
MessageQueueIF* QueueMapManager::getMessageQueue(
MessageQueueId_t messageQueueId) const {
MutexHelper(mapLock, 50);
auto queueIter = queueMap.find(messageQueueId);
if(queueIter != queueMap.end()) {
return queueIter->second;
}
else {
sif::warning << "QueueMapManager::getQueueHandle: The ID" <<
messageQueueId << " does not exists in the map" << std::endl;
return nullptr;
}
}

View File

@ -1,47 +1,47 @@
#ifndef FRAMEWORK_OSAL_HOST_QUEUEMAP_H_
#define FRAMEWORK_OSAL_HOST_QUEUEMAP_H_
#include "../../ipc/MessageQueueSenderIF.h"
#include "../../osal/host/MessageQueue.h"
#include <unordered_map>
#include <atomic>
using QueueMap = std::unordered_map<MessageQueueId_t, MessageQueueIF*>;
/**
* An internal map to map message queue IDs to message queues.
* This propably should be a singleton..
*/
class QueueMapManager {
public:
//! Returns the single instance of SemaphoreFactory.
static QueueMapManager* instance();
/**
* Insert a message queue into the map and returns a message queue ID
* @param queue The message queue to insert.
* @param id The passed value will be set unless a nullptr is passed
* @return
*/
ReturnValue_t addMessageQueue(MessageQueueIF* queue, MessageQueueId_t*
id = nullptr);
/**
* Get the message queue handle by providing a message queue ID.
* @param messageQueueId
* @return
*/
MessageQueueIF* getMessageQueue(MessageQueueId_t messageQueueId) const;
private:
//! External instantiation is forbidden.
QueueMapManager();
uint32_t queueCounter = 1;
MutexIF* mapLock;
QueueMap queueMap;
static QueueMapManager* mqManagerInstance;
};
#endif /* FRAMEWORK_OSAL_HOST_QUEUEMAP_H_ */
#ifndef FRAMEWORK_OSAL_HOST_QUEUEMAP_H_
#define FRAMEWORK_OSAL_HOST_QUEUEMAP_H_
#include "../../ipc/MessageQueueSenderIF.h"
#include "../../osal/host/MessageQueue.h"
#include <unordered_map>
#include <atomic>
using QueueMap = std::unordered_map<MessageQueueId_t, MessageQueueIF*>;
/**
* An internal map to map message queue IDs to message queues.
* This propably should be a singleton..
*/
class QueueMapManager {
public:
//! Returns the single instance of SemaphoreFactory.
static QueueMapManager* instance();
/**
* Insert a message queue into the map and returns a message queue ID
* @param queue The message queue to insert.
* @param id The passed value will be set unless a nullptr is passed
* @return
*/
ReturnValue_t addMessageQueue(MessageQueueIF* queue, MessageQueueId_t*
id = nullptr);
/**
* Get the message queue handle by providing a message queue ID.
* @param messageQueueId
* @return
*/
MessageQueueIF* getMessageQueue(MessageQueueId_t messageQueueId) const;
private:
//! External instantiation is forbidden.
QueueMapManager();
uint32_t queueCounter = 1;
MutexIF* mapLock;
QueueMap queueMap;
static QueueMapManager* mqManagerInstance;
};
#endif /* FRAMEWORK_OSAL_HOST_QUEUEMAP_H_ */

View File

@ -1,42 +1,42 @@
#include "../../tasks/SemaphoreFactory.h"
#include "../../osal/linux/BinarySemaphore.h"
#include "../../osal/linux/CountingSemaphore.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
const uint32_t SemaphoreIF::POLLING = 0;
const uint32_t SemaphoreIF::BLOCKING = 0xFFFFFFFF;
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) {
// Just gonna wait for full C++20 for now.
sif::error << "SemaphoreFactory: Binary Semaphore not implemented yet."
" Returning nullptr!\n" << std::flush;
return nullptr;
}
SemaphoreIF* SemaphoreFactory::createCountingSemaphore(const uint8_t maxCount,
uint8_t initCount, uint32_t arguments) {
// Just gonna wait for full C++20 for now.
sif::error << "SemaphoreFactory: Counting Semaphore not implemented yet."
" Returning nullptr!\n" << std::flush;
return nullptr;
}
void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) {
delete semaphore;
}
#include "../../tasks/SemaphoreFactory.h"
#include "../../osal/linux/BinarySemaphore.h"
#include "../../osal/linux/CountingSemaphore.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
const uint32_t SemaphoreIF::POLLING = 0;
const uint32_t SemaphoreIF::BLOCKING = 0xFFFFFFFF;
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) {
// Just gonna wait for full C++20 for now.
sif::error << "SemaphoreFactory: Binary Semaphore not implemented yet."
" Returning nullptr!\n" << std::flush;
return nullptr;
}
SemaphoreIF* SemaphoreFactory::createCountingSemaphore(const uint8_t maxCount,
uint8_t initCount, uint32_t arguments) {
// Just gonna wait for full C++20 for now.
sif::error << "SemaphoreFactory: Counting Semaphore not implemented yet."
" Returning nullptr!\n" << std::flush;
return nullptr;
}
void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) {
delete semaphore;
}

View File

@ -1,55 +1,55 @@
#include "../../osal/host/FixedTimeslotTask.h"
#include "../../osal/host/PeriodicTask.h"
#include "../../tasks/TaskFactory.h"
#include "../../returnvalues/HasReturnvaluesIF.h"
#include "../../tasks/PeriodicTaskIF.h"
#include <chrono>
TaskFactory* TaskFactory::factoryInstance = new TaskFactory();
// Will propably not be used for hosted implementation
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = 0;
TaskFactory::TaskFactory() {
}
TaskFactory::~TaskFactory() {
}
TaskFactory* TaskFactory::instance() {
return TaskFactory::factoryInstance;
}
PeriodicTaskIF* TaskFactory::createPeriodicTask(TaskName name_,
TaskPriority taskPriority_,TaskStackSize stackSize_,
TaskPeriod periodInSeconds_,
TaskDeadlineMissedFunction deadLineMissedFunction_) {
// This is going to be interesting. Time now learn the C++ threading library
// :-)
return new PeriodicTask(name_, taskPriority_, stackSize_, periodInSeconds_,
deadLineMissedFunction_);
}
FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(TaskName name_,
TaskPriority taskPriority_,TaskStackSize stackSize_,
TaskPeriod periodInSeconds_,
TaskDeadlineMissedFunction deadLineMissedFunction_) {
// This is going to be interesting. Time now learn the C++ threading library
// :-)
return new FixedTimeslotTask(name_, taskPriority_, stackSize_,
periodInSeconds_, deadLineMissedFunction_);
}
ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) {
// This might block for some time!
delete task;
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t TaskFactory::delayTask(uint32_t delayMs){
std::this_thread::sleep_for(std::chrono::milliseconds(delayMs));
return HasReturnvaluesIF::RETURN_OK;
}
#include "../../osal/host/FixedTimeslotTask.h"
#include "../../osal/host/PeriodicTask.h"
#include "../../tasks/TaskFactory.h"
#include "../../returnvalues/HasReturnvaluesIF.h"
#include "../../tasks/PeriodicTaskIF.h"
#include <chrono>
TaskFactory* TaskFactory::factoryInstance = new TaskFactory();
// Will propably not be used for hosted implementation
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = 0;
TaskFactory::TaskFactory() {
}
TaskFactory::~TaskFactory() {
}
TaskFactory* TaskFactory::instance() {
return TaskFactory::factoryInstance;
}
PeriodicTaskIF* TaskFactory::createPeriodicTask(TaskName name_,
TaskPriority taskPriority_,TaskStackSize stackSize_,
TaskPeriod periodInSeconds_,
TaskDeadlineMissedFunction deadLineMissedFunction_) {
// This is going to be interesting. Time now learn the C++ threading library
// :-)
return new PeriodicTask(name_, taskPriority_, stackSize_, periodInSeconds_,
deadLineMissedFunction_);
}
FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(TaskName name_,
TaskPriority taskPriority_,TaskStackSize stackSize_,
TaskPeriod periodInSeconds_,
TaskDeadlineMissedFunction deadLineMissedFunction_) {
// This is going to be interesting. Time now learn the C++ threading library
// :-)
return new FixedTimeslotTask(name_, taskPriority_, stackSize_,
periodInSeconds_, deadLineMissedFunction_);
}
ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) {
// This might block for some time!
delete task;
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t TaskFactory::delayTask(uint32_t delayMs){
std::this_thread::sleep_for(std::chrono::milliseconds(delayMs));
return HasReturnvaluesIF::RETURN_OK;
}

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_ */

View File

@ -1,198 +1,198 @@
#include "../../timemanager/Clock.h"
#include "RtemsBasic.h"
#include <rtems/score/todimpl.h>
uint16_t Clock::leapSeconds = 0;
MutexIF* Clock::timeMutex = NULL;
uint32_t Clock::getTicksPerSecond(void){
rtems_interval ticks_per_second = rtems_clock_get_ticks_per_second();
return static_cast<uint32_t>(ticks_per_second);
}
ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {
rtems_time_of_day timeRtems;
timeRtems.year = time->year;
timeRtems.month = time->month;
timeRtems.day = time->day;
timeRtems.hour = time->hour;
timeRtems.minute = time->minute;
timeRtems.second = time->second;
timeRtems.ticks = time->usecond * getTicksPerSecond() / 1e6;
rtems_status_code status = rtems_clock_set(&timeRtems);
switch(status){
case RTEMS_SUCCESSFUL:
return HasReturnvaluesIF::RETURN_OK;
case RTEMS_INVALID_ADDRESS:
return HasReturnvaluesIF::RETURN_FAILED;
case RTEMS_INVALID_CLOCK:
return HasReturnvaluesIF::RETURN_FAILED;
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t Clock::setClock(const timeval* time) {
//TODO This routine uses _TOD_Set which is not
timespec newTime;
newTime.tv_sec = time->tv_sec;
newTime.tv_nsec = time->tv_usec * TOD_NANOSECONDS_PER_MICROSECOND;
//SHOULDDO: Not sure if we need to protect this call somehow (by thread lock or something).
//Uli: rtems docu says you can call this from an ISR, not sure if this means no protetion needed
//TODO Second parameter is ISR_lock_Context
_TOD_Set(&newTime,NULL);
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::getClock_timeval(timeval* time) {
//Callable from ISR
rtems_status_code status = rtems_clock_get_tod_timeval(time);
switch(status){
case RTEMS_SUCCESSFUL:
return HasReturnvaluesIF::RETURN_OK;
case RTEMS_NOT_DEFINED:
return HasReturnvaluesIF::RETURN_FAILED;
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t Clock::getUptime(timeval* uptime) {
//According to docs.rtems.org for rtems 5 this method is more accurate than rtems_clock_get_ticks_since_boot
timespec time;
rtems_status_code status = rtems_clock_get_uptime(&time);
uptime->tv_sec = time.tv_sec;
time.tv_nsec = time.tv_nsec / 1000;
uptime->tv_usec = time.tv_nsec;
switch(status){
case RTEMS_SUCCESSFUL:
return HasReturnvaluesIF::RETURN_OK;
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) {
//This counter overflows after 50 days
*uptimeMs = rtems_clock_get_ticks_since_boot();
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
timeval temp_time;
rtems_status_code returnValue = rtems_clock_get_tod_timeval(&temp_time);
*time = ((uint64_t) temp_time.tv_sec * 1000000) + temp_time.tv_usec;
switch(returnValue){
case RTEMS_SUCCESSFUL:
return HasReturnvaluesIF::RETURN_OK;
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
rtems_time_of_day* timeRtems = reinterpret_cast<rtems_time_of_day*>(time);
rtems_status_code status = rtems_clock_get_tod(timeRtems);
switch (status) {
case RTEMS_SUCCESSFUL:
return HasReturnvaluesIF::RETURN_OK;
case RTEMS_NOT_DEFINED:
//system date and time is not set
return HasReturnvaluesIF::RETURN_FAILED;
case RTEMS_INVALID_ADDRESS:
//time_buffer is NULL
return HasReturnvaluesIF::RETURN_FAILED;
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from,
timeval* to) {
//Fails in 2038..
rtems_time_of_day timeRtems;
timeRtems.year = from->year;
timeRtems.month = from->month;
timeRtems.day = from->day;
timeRtems.hour = from->hour;
timeRtems.minute = from->minute;
timeRtems.second = from->second;
timeRtems.ticks = from->usecond * getTicksPerSecond() / 1e6;
to->tv_sec = _TOD_To_seconds(&timeRtems);
to->tv_usec = from->usecond;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) {
*JD2000 = (time.tv_sec - 946728000. + time.tv_usec / 1000000.) / 24.
/ 3600.;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) {
//SHOULDDO: works not for dates in the past (might have less leap seconds)
if (timeMutex == NULL) {
return HasReturnvaluesIF::RETURN_FAILED;
}
uint16_t leapSeconds;
ReturnValue_t result = getLeapSeconds(&leapSeconds);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
timeval leapSeconds_timeval = { 0, 0 };
leapSeconds_timeval.tv_sec = leapSeconds;
//initial offset between UTC and TAI
timeval UTCtoTAI1972 = { 10, 0 };
timeval TAItoTT = { 32, 184000 };
*tt = utc + leapSeconds_timeval + UTCtoTAI1972 + TAItoTT;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) {
if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t result = timeMutex->lockMutex(MutexIF::NO_TIMEOUT);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
leapSeconds = leapSeconds_;
result = timeMutex->unlockMutex();
return result;
}
ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) {
if(timeMutex==NULL){
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t result = timeMutex->lockMutex(MutexIF::NO_TIMEOUT);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
*leapSeconds_ = leapSeconds;
result = timeMutex->unlockMutex();
return result;
}
ReturnValue_t Clock::checkOrCreateClockMutex(){
if(timeMutex==NULL){
MutexFactory* mutexFactory = MutexFactory::instance();
if (mutexFactory == NULL) {
return HasReturnvaluesIF::RETURN_FAILED;
}
timeMutex = mutexFactory->createMutex();
if (timeMutex == NULL) {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
return HasReturnvaluesIF::RETURN_OK;
}
#include "../../timemanager/Clock.h"
#include "RtemsBasic.h"
#include <rtems/score/todimpl.h>
uint16_t Clock::leapSeconds = 0;
MutexIF* Clock::timeMutex = NULL;
uint32_t Clock::getTicksPerSecond(void){
rtems_interval ticks_per_second = rtems_clock_get_ticks_per_second();
return static_cast<uint32_t>(ticks_per_second);
}
ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {
rtems_time_of_day timeRtems;
timeRtems.year = time->year;
timeRtems.month = time->month;
timeRtems.day = time->day;
timeRtems.hour = time->hour;
timeRtems.minute = time->minute;
timeRtems.second = time->second;
timeRtems.ticks = time->usecond * getTicksPerSecond() / 1e6;
rtems_status_code status = rtems_clock_set(&timeRtems);
switch(status){
case RTEMS_SUCCESSFUL:
return HasReturnvaluesIF::RETURN_OK;
case RTEMS_INVALID_ADDRESS:
return HasReturnvaluesIF::RETURN_FAILED;
case RTEMS_INVALID_CLOCK:
return HasReturnvaluesIF::RETURN_FAILED;
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t Clock::setClock(const timeval* time) {
//TODO This routine uses _TOD_Set which is not
timespec newTime;
newTime.tv_sec = time->tv_sec;
newTime.tv_nsec = time->tv_usec * TOD_NANOSECONDS_PER_MICROSECOND;
//SHOULDDO: Not sure if we need to protect this call somehow (by thread lock or something).
//Uli: rtems docu says you can call this from an ISR, not sure if this means no protetion needed
//TODO Second parameter is ISR_lock_Context
_TOD_Set(&newTime,NULL);
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::getClock_timeval(timeval* time) {
//Callable from ISR
rtems_status_code status = rtems_clock_get_tod_timeval(time);
switch(status){
case RTEMS_SUCCESSFUL:
return HasReturnvaluesIF::RETURN_OK;
case RTEMS_NOT_DEFINED:
return HasReturnvaluesIF::RETURN_FAILED;
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t Clock::getUptime(timeval* uptime) {
//According to docs.rtems.org for rtems 5 this method is more accurate than rtems_clock_get_ticks_since_boot
timespec time;
rtems_status_code status = rtems_clock_get_uptime(&time);
uptime->tv_sec = time.tv_sec;
time.tv_nsec = time.tv_nsec / 1000;
uptime->tv_usec = time.tv_nsec;
switch(status){
case RTEMS_SUCCESSFUL:
return HasReturnvaluesIF::RETURN_OK;
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) {
//This counter overflows after 50 days
*uptimeMs = rtems_clock_get_ticks_since_boot();
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
timeval temp_time;
rtems_status_code returnValue = rtems_clock_get_tod_timeval(&temp_time);
*time = ((uint64_t) temp_time.tv_sec * 1000000) + temp_time.tv_usec;
switch(returnValue){
case RTEMS_SUCCESSFUL:
return HasReturnvaluesIF::RETURN_OK;
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
rtems_time_of_day* timeRtems = reinterpret_cast<rtems_time_of_day*>(time);
rtems_status_code status = rtems_clock_get_tod(timeRtems);
switch (status) {
case RTEMS_SUCCESSFUL:
return HasReturnvaluesIF::RETURN_OK;
case RTEMS_NOT_DEFINED:
//system date and time is not set
return HasReturnvaluesIF::RETURN_FAILED;
case RTEMS_INVALID_ADDRESS:
//time_buffer is NULL
return HasReturnvaluesIF::RETURN_FAILED;
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from,
timeval* to) {
//Fails in 2038..
rtems_time_of_day timeRtems;
timeRtems.year = from->year;
timeRtems.month = from->month;
timeRtems.day = from->day;
timeRtems.hour = from->hour;
timeRtems.minute = from->minute;
timeRtems.second = from->second;
timeRtems.ticks = from->usecond * getTicksPerSecond() / 1e6;
to->tv_sec = _TOD_To_seconds(&timeRtems);
to->tv_usec = from->usecond;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) {
*JD2000 = (time.tv_sec - 946728000. + time.tv_usec / 1000000.) / 24.
/ 3600.;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) {
//SHOULDDO: works not for dates in the past (might have less leap seconds)
if (timeMutex == NULL) {
return HasReturnvaluesIF::RETURN_FAILED;
}
uint16_t leapSeconds;
ReturnValue_t result = getLeapSeconds(&leapSeconds);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
timeval leapSeconds_timeval = { 0, 0 };
leapSeconds_timeval.tv_sec = leapSeconds;
//initial offset between UTC and TAI
timeval UTCtoTAI1972 = { 10, 0 };
timeval TAItoTT = { 32, 184000 };
*tt = utc + leapSeconds_timeval + UTCtoTAI1972 + TAItoTT;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) {
if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t result = timeMutex->lockMutex(MutexIF::NO_TIMEOUT);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
leapSeconds = leapSeconds_;
result = timeMutex->unlockMutex();
return result;
}
ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) {
if(timeMutex==NULL){
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t result = timeMutex->lockMutex(MutexIF::NO_TIMEOUT);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
*leapSeconds_ = leapSeconds;
result = timeMutex->unlockMutex();
return result;
}
ReturnValue_t Clock::checkOrCreateClockMutex(){
if(timeMutex==NULL){
MutexFactory* mutexFactory = MutexFactory::instance();
if (mutexFactory == NULL) {
return HasReturnvaluesIF::RETURN_FAILED;
}
timeMutex = mutexFactory->createMutex();
if (timeMutex == NULL) {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -1,183 +1,183 @@
#include "CpuUsage.h"
#include "../../serialize/SerialArrayListAdapter.h"
#include "../../serialize/SerializeAdapter.h"
#include <string.h>
extern "C" {
#include <rtems/cpuuse.h>
}
int handlePrint(void * token, const char *format, ...) {
CpuUsage *cpuUsage = (CpuUsage *) token;
if (cpuUsage->counter == 0) {
//header
cpuUsage->counter++;
return 0;
}
if (cpuUsage->counter % 2 == 1) {
{
//we can not tell when the last call is so we assume it be every uneven time
va_list vl;
va_start(vl, format);
float timeSinceLastReset = va_arg(vl,uint32_t);
uint32_t timeSinceLastResetDecimals = va_arg(vl,uint32_t);
timeSinceLastReset = timeSinceLastReset
+ (timeSinceLastResetDecimals / 1000.);
cpuUsage->timeSinceLastReset = timeSinceLastReset;
va_end(vl);
}
//task name and id
va_list vl;
va_start(vl, format);
cpuUsage->cachedValue.id = va_arg(vl,uint32_t);
const char *name = va_arg(vl,const char *);
memcpy(cpuUsage->cachedValue.name, name,
CpuUsage::ThreadData::MAX_LENGTH_OF_THREAD_NAME);
va_end(vl);
} else {
//statistics
va_list vl;
va_start(vl, format);
float run = va_arg(vl,uint32_t);
uint32_t runDecimals = va_arg(vl,uint32_t);
float percent = va_arg(vl,uint32_t);
uint32_t percent_decimals = va_arg(vl,uint32_t);
run = run + (runDecimals / 1000.);
percent = percent + (percent_decimals / 1000.);
cpuUsage->cachedValue.percentUsage = percent;
cpuUsage->cachedValue.timeRunning = run;
cpuUsage->threadData.insert(cpuUsage->cachedValue);
va_end(vl);
}
cpuUsage->counter++;
return 0;
}
CpuUsage::CpuUsage() :
counter(0), timeSinceLastReset(0) {
}
CpuUsage::~CpuUsage() {
}
void CpuUsage::resetCpuUsage() {
rtems_cpu_usage_reset();
}
void CpuUsage::read() {
//rtems_cpu_usage_report_with_plugin(this, &handlePrint);
}
void CpuUsage::clear() {
counter = 0;
timeSinceLastReset = 0;
threadData.clear();
}
ReturnValue_t CpuUsage::serialize(uint8_t** buffer, size_t* size,
size_t maxSize, Endianness streamEndianness) const {
ReturnValue_t result = SerializeAdapter::serialize(
&timeSinceLastReset, buffer, size, maxSize, streamEndianness);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
return SerialArrayListAdapter<ThreadData>::serialize(&threadData, buffer,
size, maxSize, streamEndianness);
}
uint32_t CpuUsage::getSerializedSize() const {
uint32_t size = 0;
size += sizeof(timeSinceLastReset);
size += SerialArrayListAdapter<ThreadData>::getSerializedSize(&threadData);
return size;
}
ReturnValue_t CpuUsage::deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness) {
ReturnValue_t result = SerializeAdapter::deSerialize(
&timeSinceLastReset, buffer, size, streamEndianness);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
return SerialArrayListAdapter<ThreadData>::deSerialize(&threadData, buffer,
size, streamEndianness);
}
ReturnValue_t CpuUsage::ThreadData::serialize(uint8_t** buffer, size_t* size,
size_t maxSize, Endianness streamEndianness) const {
ReturnValue_t result = SerializeAdapter::serialize(&id, buffer,
size, maxSize, streamEndianness);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
if (*size + MAX_LENGTH_OF_THREAD_NAME > maxSize) {
return BUFFER_TOO_SHORT;
}
memcpy(*buffer, name, MAX_LENGTH_OF_THREAD_NAME);
*size += MAX_LENGTH_OF_THREAD_NAME;
*buffer += MAX_LENGTH_OF_THREAD_NAME;
result = SerializeAdapter::serialize(&timeRunning,
buffer, size, maxSize, streamEndianness);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
result = SerializeAdapter::serialize(&percentUsage,
buffer, size, maxSize, streamEndianness);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
return HasReturnvaluesIF::RETURN_OK;
}
uint32_t CpuUsage::ThreadData::getSerializedSize() const {
uint32_t size = 0;
size += sizeof(id);
size += MAX_LENGTH_OF_THREAD_NAME;
size += sizeof(timeRunning);
size += sizeof(percentUsage);
return size;
}
ReturnValue_t CpuUsage::ThreadData::deSerialize(const uint8_t** buffer,
int32_t* size, Endianness streamEndianness) {
ReturnValue_t result = SerializeAdapter::deSerialize(&id, buffer,
size, streamEndianness);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
if ((*size = *size - MAX_LENGTH_OF_THREAD_NAME) < 0) {
return STREAM_TOO_SHORT;
}
memcpy(name, *buffer, MAX_LENGTH_OF_THREAD_NAME);
*buffer -= MAX_LENGTH_OF_THREAD_NAME;
result = SerializeAdapter::deSerialize(&timeRunning,
buffer, size, streamEndianness);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
result = SerializeAdapter::deSerialize(&percentUsage,
buffer, size, streamEndianness);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
return HasReturnvaluesIF::RETURN_OK;
}
#include "CpuUsage.h"
#include "../../serialize/SerialArrayListAdapter.h"
#include "../../serialize/SerializeAdapter.h"
#include <string.h>
extern "C" {
#include <rtems/cpuuse.h>
}
int handlePrint(void * token, const char *format, ...) {
CpuUsage *cpuUsage = (CpuUsage *) token;
if (cpuUsage->counter == 0) {
//header
cpuUsage->counter++;
return 0;
}
if (cpuUsage->counter % 2 == 1) {
{
//we can not tell when the last call is so we assume it be every uneven time
va_list vl;
va_start(vl, format);
float timeSinceLastReset = va_arg(vl,uint32_t);
uint32_t timeSinceLastResetDecimals = va_arg(vl,uint32_t);
timeSinceLastReset = timeSinceLastReset
+ (timeSinceLastResetDecimals / 1000.);
cpuUsage->timeSinceLastReset = timeSinceLastReset;
va_end(vl);
}
//task name and id
va_list vl;
va_start(vl, format);
cpuUsage->cachedValue.id = va_arg(vl,uint32_t);
const char *name = va_arg(vl,const char *);
memcpy(cpuUsage->cachedValue.name, name,
CpuUsage::ThreadData::MAX_LENGTH_OF_THREAD_NAME);
va_end(vl);
} else {
//statistics
va_list vl;
va_start(vl, format);
float run = va_arg(vl,uint32_t);
uint32_t runDecimals = va_arg(vl,uint32_t);
float percent = va_arg(vl,uint32_t);
uint32_t percent_decimals = va_arg(vl,uint32_t);
run = run + (runDecimals / 1000.);
percent = percent + (percent_decimals / 1000.);
cpuUsage->cachedValue.percentUsage = percent;
cpuUsage->cachedValue.timeRunning = run;
cpuUsage->threadData.insert(cpuUsage->cachedValue);
va_end(vl);
}
cpuUsage->counter++;
return 0;
}
CpuUsage::CpuUsage() :
counter(0), timeSinceLastReset(0) {
}
CpuUsage::~CpuUsage() {
}
void CpuUsage::resetCpuUsage() {
rtems_cpu_usage_reset();
}
void CpuUsage::read() {
//rtems_cpu_usage_report_with_plugin(this, &handlePrint);
}
void CpuUsage::clear() {
counter = 0;
timeSinceLastReset = 0;
threadData.clear();
}
ReturnValue_t CpuUsage::serialize(uint8_t** buffer, size_t* size,
size_t maxSize, Endianness streamEndianness) const {
ReturnValue_t result = SerializeAdapter::serialize(
&timeSinceLastReset, buffer, size, maxSize, streamEndianness);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
return SerialArrayListAdapter<ThreadData>::serialize(&threadData, buffer,
size, maxSize, streamEndianness);
}
uint32_t CpuUsage::getSerializedSize() const {
uint32_t size = 0;
size += sizeof(timeSinceLastReset);
size += SerialArrayListAdapter<ThreadData>::getSerializedSize(&threadData);
return size;
}
ReturnValue_t CpuUsage::deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness) {
ReturnValue_t result = SerializeAdapter::deSerialize(
&timeSinceLastReset, buffer, size, streamEndianness);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
return SerialArrayListAdapter<ThreadData>::deSerialize(&threadData, buffer,
size, streamEndianness);
}
ReturnValue_t CpuUsage::ThreadData::serialize(uint8_t** buffer, size_t* size,
size_t maxSize, Endianness streamEndianness) const {
ReturnValue_t result = SerializeAdapter::serialize(&id, buffer,
size, maxSize, streamEndianness);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
if (*size + MAX_LENGTH_OF_THREAD_NAME > maxSize) {
return BUFFER_TOO_SHORT;
}
memcpy(*buffer, name, MAX_LENGTH_OF_THREAD_NAME);
*size += MAX_LENGTH_OF_THREAD_NAME;
*buffer += MAX_LENGTH_OF_THREAD_NAME;
result = SerializeAdapter::serialize(&timeRunning,
buffer, size, maxSize, streamEndianness);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
result = SerializeAdapter::serialize(&percentUsage,
buffer, size, maxSize, streamEndianness);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
return HasReturnvaluesIF::RETURN_OK;
}
uint32_t CpuUsage::ThreadData::getSerializedSize() const {
uint32_t size = 0;
size += sizeof(id);
size += MAX_LENGTH_OF_THREAD_NAME;
size += sizeof(timeRunning);
size += sizeof(percentUsage);
return size;
}
ReturnValue_t CpuUsage::ThreadData::deSerialize(const uint8_t** buffer,
int32_t* size, Endianness streamEndianness) {
ReturnValue_t result = SerializeAdapter::deSerialize(&id, buffer,
size, streamEndianness);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
if ((*size = *size - MAX_LENGTH_OF_THREAD_NAME) < 0) {
return STREAM_TOO_SHORT;
}
memcpy(name, *buffer, MAX_LENGTH_OF_THREAD_NAME);
*buffer -= MAX_LENGTH_OF_THREAD_NAME;
result = SerializeAdapter::deSerialize(&timeRunning,
buffer, size, streamEndianness);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
result = SerializeAdapter::deSerialize(&percentUsage,
buffer, size, streamEndianness);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -1,53 +1,53 @@
#ifndef CPUUSAGE_H_
#define CPUUSAGE_H_
#include "../../container/FixedArrayList.h"
#include "../../serialize/SerializeIF.h"
#include <stdarg.h>
class CpuUsage : public SerializeIF {
public:
static const uint8_t MAXIMUM_NUMBER_OF_THREADS = 30;
class ThreadData: public SerializeIF {
public:
static const uint8_t MAX_LENGTH_OF_THREAD_NAME = 4;
uint32_t id;
char name[MAX_LENGTH_OF_THREAD_NAME];
float timeRunning;
float percentUsage;
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size,
size_t maxSize, Endianness streamEndianness) const override;
virtual size_t getSerializedSize() const override;
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness) override;
};
CpuUsage();
virtual ~CpuUsage();
uint8_t counter;
float timeSinceLastReset;
FixedArrayList<ThreadData, MAXIMUM_NUMBER_OF_THREADS> threadData;
ThreadData cachedValue;
static void resetCpuUsage();
void read();
void clear();
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size,
size_t maxSize, Endianness streamEndianness) const override;
virtual size_t getSerializedSize() const override;
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness) override;
};
#endif /* CPUUSAGE_H_ */
#ifndef CPUUSAGE_H_
#define CPUUSAGE_H_
#include "../../container/FixedArrayList.h"
#include "../../serialize/SerializeIF.h"
#include <stdarg.h>
class CpuUsage : public SerializeIF {
public:
static const uint8_t MAXIMUM_NUMBER_OF_THREADS = 30;
class ThreadData: public SerializeIF {
public:
static const uint8_t MAX_LENGTH_OF_THREAD_NAME = 4;
uint32_t id;
char name[MAX_LENGTH_OF_THREAD_NAME];
float timeRunning;
float percentUsage;
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size,
size_t maxSize, Endianness streamEndianness) const override;
virtual size_t getSerializedSize() const override;
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness) override;
};
CpuUsage();
virtual ~CpuUsage();
uint8_t counter;
float timeSinceLastReset;
FixedArrayList<ThreadData, MAXIMUM_NUMBER_OF_THREADS> threadData;
ThreadData cachedValue;
static void resetCpuUsage();
void read();
void clear();
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size,
size_t maxSize, Endianness streamEndianness) const override;
virtual size_t getSerializedSize() const override;
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness) override;
};
#endif /* CPUUSAGE_H_ */

View File

@ -1,60 +1,60 @@
#include "../../osal/InternalErrorCodes.h"
#include <rtems/score/interr.h>
ReturnValue_t InternalErrorCodes::translate(uint8_t code) {
switch (code) {
//TODO It looks like RTEMS-5 does not provide the same error codes
// case INTERNAL_ERROR_NO_CONFIGURATION_TABLE:
// return NO_CONFIGURATION_TABLE;
// case INTERNAL_ERROR_NO_CPU_TABLE:
// return NO_CPU_TABLE;
// case INTERNAL_ERROR_INVALID_WORKSPACE_ADDRESS:
// return INVALID_WORKSPACE_ADDRESS;
case INTERNAL_ERROR_TOO_LITTLE_WORKSPACE:
return TOO_LITTLE_WORKSPACE;
case INTERNAL_ERROR_WORKSPACE_ALLOCATION:
return WORKSPACE_ALLOCATION;
// case INTERNAL_ERROR_INTERRUPT_STACK_TOO_SMALL:
// return INTERRUPT_STACK_TOO_SMALL;
case INTERNAL_ERROR_THREAD_EXITTED:
return THREAD_EXITTED;
case INTERNAL_ERROR_INCONSISTENT_MP_INFORMATION:
return INCONSISTENT_MP_INFORMATION;
case INTERNAL_ERROR_INVALID_NODE:
return INVALID_NODE;
case INTERNAL_ERROR_NO_MPCI:
return NO_MPCI;
case INTERNAL_ERROR_BAD_PACKET:
return BAD_PACKET;
case INTERNAL_ERROR_OUT_OF_PACKETS:
return OUT_OF_PACKETS;
case INTERNAL_ERROR_OUT_OF_GLOBAL_OBJECTS:
return OUT_OF_GLOBAL_OBJECTS;
case INTERNAL_ERROR_OUT_OF_PROXIES:
return OUT_OF_PROXIES;
case INTERNAL_ERROR_INVALID_GLOBAL_ID:
return INVALID_GLOBAL_ID;
case INTERNAL_ERROR_BAD_STACK_HOOK:
return BAD_STACK_HOOK;
// case INTERNAL_ERROR_BAD_ATTRIBUTES:
// return BAD_ATTRIBUTES;
// case INTERNAL_ERROR_IMPLEMENTATION_KEY_CREATE_INCONSISTENCY:
// return IMPLEMENTATION_KEY_CREATE_INCONSISTENCY;
// case INTERNAL_ERROR_IMPLEMENTATION_BLOCKING_OPERATION_CANCEL:
// return IMPLEMENTATION_BLOCKING_OPERATION_CANCEL;
// case INTERNAL_ERROR_MUTEX_OBTAIN_FROM_BAD_STATE:
// return MUTEX_OBTAIN_FROM_BAD_STATE;
// case INTERNAL_ERROR_UNLIMITED_AND_MAXIMUM_IS_0:
// return UNLIMITED_AND_MAXIMUM_IS_0;
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
InternalErrorCodes::InternalErrorCodes() {
}
InternalErrorCodes::~InternalErrorCodes() {
}
#include "../../osal/InternalErrorCodes.h"
#include <rtems/score/interr.h>
ReturnValue_t InternalErrorCodes::translate(uint8_t code) {
switch (code) {
//TODO It looks like RTEMS-5 does not provide the same error codes
// case INTERNAL_ERROR_NO_CONFIGURATION_TABLE:
// return NO_CONFIGURATION_TABLE;
// case INTERNAL_ERROR_NO_CPU_TABLE:
// return NO_CPU_TABLE;
// case INTERNAL_ERROR_INVALID_WORKSPACE_ADDRESS:
// return INVALID_WORKSPACE_ADDRESS;
case INTERNAL_ERROR_TOO_LITTLE_WORKSPACE:
return TOO_LITTLE_WORKSPACE;
case INTERNAL_ERROR_WORKSPACE_ALLOCATION:
return WORKSPACE_ALLOCATION;
// case INTERNAL_ERROR_INTERRUPT_STACK_TOO_SMALL:
// return INTERRUPT_STACK_TOO_SMALL;
case INTERNAL_ERROR_THREAD_EXITTED:
return THREAD_EXITTED;
case INTERNAL_ERROR_INCONSISTENT_MP_INFORMATION:
return INCONSISTENT_MP_INFORMATION;
case INTERNAL_ERROR_INVALID_NODE:
return INVALID_NODE;
case INTERNAL_ERROR_NO_MPCI:
return NO_MPCI;
case INTERNAL_ERROR_BAD_PACKET:
return BAD_PACKET;
case INTERNAL_ERROR_OUT_OF_PACKETS:
return OUT_OF_PACKETS;
case INTERNAL_ERROR_OUT_OF_GLOBAL_OBJECTS:
return OUT_OF_GLOBAL_OBJECTS;
case INTERNAL_ERROR_OUT_OF_PROXIES:
return OUT_OF_PROXIES;
case INTERNAL_ERROR_INVALID_GLOBAL_ID:
return INVALID_GLOBAL_ID;
case INTERNAL_ERROR_BAD_STACK_HOOK:
return BAD_STACK_HOOK;
// case INTERNAL_ERROR_BAD_ATTRIBUTES:
// return BAD_ATTRIBUTES;
// case INTERNAL_ERROR_IMPLEMENTATION_KEY_CREATE_INCONSISTENCY:
// return IMPLEMENTATION_KEY_CREATE_INCONSISTENCY;
// case INTERNAL_ERROR_IMPLEMENTATION_BLOCKING_OPERATION_CANCEL:
// return IMPLEMENTATION_BLOCKING_OPERATION_CANCEL;
// case INTERNAL_ERROR_MUTEX_OBTAIN_FROM_BAD_STATE:
// return MUTEX_OBTAIN_FROM_BAD_STATE;
// case INTERNAL_ERROR_UNLIMITED_AND_MAXIMUM_IS_0:
// return UNLIMITED_AND_MAXIMUM_IS_0;
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
InternalErrorCodes::InternalErrorCodes() {
}
InternalErrorCodes::~InternalErrorCodes() {
}

View File

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

View File

@ -1,147 +1,147 @@
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "MessageQueue.h"
#include "RtemsBasic.h"
#include <cstring>
MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size) :
id(0), lastPartner(0), defaultDestination(NO_QUEUE), internalErrorReporter(NULL) {
rtems_name name = ('Q' << 24) + (queueCounter++ << 8);
rtems_status_code status = rtems_message_queue_create(name, message_depth,
max_message_size, 0, &(this->id));
if (status != RTEMS_SUCCESSFUL) {
error << "MessageQueue::MessageQueue: Creating Queue " << std::hex
<< name << std::dec << " failed with status:"
<< (uint32_t) status << std::endl;
this->id = 0;
}
}
MessageQueue::~MessageQueue() {
rtems_message_queue_delete(id);
}
ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo,
MessageQueueMessage* message, bool ignoreFault) {
return sendMessageFrom(sendTo, message, this->getId(), ignoreFault);
}
ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessage* message) {
return sendToDefaultFrom(message, this->getId());
}
ReturnValue_t MessageQueue::reply(MessageQueueMessage* message) {
if (this->lastPartner != 0) {
return sendMessage(this->lastPartner, message, this->getId());
} else {
return NO_REPLY_PARTNER;
}
}
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message,
MessageQueueId_t* receivedFrom) {
ReturnValue_t status = this->receiveMessage(message);
*receivedFrom = this->lastPartner;
return status;
}
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message) {
rtems_status_code status = rtems_message_queue_receive(id,
message->getBuffer(), &(message->messageSize),
RTEMS_NO_WAIT, 1);
if (status == RTEMS_SUCCESSFUL) {
this->lastPartner = message->getSender();
//Check size of incoming message.
if (message->messageSize < message->getMinimumMessageSize()) {
return HasReturnvaluesIF::RETURN_FAILED;
}
} else {
//No message was received. Keep lastPartner anyway, I might send something later.
//But still, delete packet content.
memset(message->getData(), 0, message->MAX_DATA_SIZE);
}
return convertReturnCode(status);
}
MessageQueueId_t MessageQueue::getLastPartner() const {
return this->lastPartner;
}
ReturnValue_t MessageQueue::flush(uint32_t* count) {
rtems_status_code status = rtems_message_queue_flush(id, count);
return convertReturnCode(status);
}
MessageQueueId_t MessageQueue::getId() const {
return this->id;
}
void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) {
this->defaultDestination = defaultDestination;
}
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo,
MessageQueueMessage* message, MessageQueueId_t sentFrom,
bool ignoreFault) {
message->setSender(sentFrom);
rtems_status_code result = rtems_message_queue_send(sendTo,
message->getBuffer(), message->messageSize);
//TODO: Check if we're in ISR.
if (result != RTEMS_SUCCESSFUL && !ignoreFault) {
if (internalErrorReporter == NULL) {
internalErrorReporter = objectManager->get<InternalErrorReporterIF>(
objects::INTERNAL_ERROR_REPORTER);
}
if (internalErrorReporter != NULL) {
internalErrorReporter->queueMessageNotSent();
}
}
ReturnValue_t returnCode = convertReturnCode(result);
if(result == MessageQueueIF::EMPTY){
return HasReturnvaluesIF::RETURN_FAILED;
}
return returnCode;
}
ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessage* message,
MessageQueueId_t sentFrom, bool ignoreFault) {
return sendMessageFrom(defaultDestination, message, sentFrom, ignoreFault);
}
MessageQueueId_t MessageQueue::getDefaultDestination() const {
return this->defaultDestination;
}
bool MessageQueue::isDefaultDestinationSet() const {
return (defaultDestination != NO_QUEUE);
}
ReturnValue_t MessageQueue::convertReturnCode(rtems_status_code inValue){
switch(inValue){
case RTEMS_SUCCESSFUL:
return HasReturnvaluesIF::RETURN_OK;
case RTEMS_INVALID_ID:
return HasReturnvaluesIF::RETURN_FAILED;
case RTEMS_TIMEOUT:
return HasReturnvaluesIF::RETURN_FAILED;
case RTEMS_OBJECT_WAS_DELETED:
return HasReturnvaluesIF::RETURN_FAILED;
case RTEMS_INVALID_ADDRESS:
return HasReturnvaluesIF::RETURN_FAILED;
case RTEMS_INVALID_SIZE:
return HasReturnvaluesIF::RETURN_FAILED;
case RTEMS_TOO_MANY:
return MessageQueueIF::FULL;
case RTEMS_UNSATISFIED:
return MessageQueueIF::EMPTY;
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
uint16_t MessageQueue::queueCounter = 0;
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "MessageQueue.h"
#include "RtemsBasic.h"
#include <cstring>
MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size) :
id(0), lastPartner(0), defaultDestination(NO_QUEUE), internalErrorReporter(NULL) {
rtems_name name = ('Q' << 24) + (queueCounter++ << 8);
rtems_status_code status = rtems_message_queue_create(name, message_depth,
max_message_size, 0, &(this->id));
if (status != RTEMS_SUCCESSFUL) {
error << "MessageQueue::MessageQueue: Creating Queue " << std::hex
<< name << std::dec << " failed with status:"
<< (uint32_t) status << std::endl;
this->id = 0;
}
}
MessageQueue::~MessageQueue() {
rtems_message_queue_delete(id);
}
ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo,
MessageQueueMessage* message, bool ignoreFault) {
return sendMessageFrom(sendTo, message, this->getId(), ignoreFault);
}
ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessage* message) {
return sendToDefaultFrom(message, this->getId());
}
ReturnValue_t MessageQueue::reply(MessageQueueMessage* message) {
if (this->lastPartner != 0) {
return sendMessage(this->lastPartner, message, this->getId());
} else {
return NO_REPLY_PARTNER;
}
}
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message,
MessageQueueId_t* receivedFrom) {
ReturnValue_t status = this->receiveMessage(message);
*receivedFrom = this->lastPartner;
return status;
}
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message) {
rtems_status_code status = rtems_message_queue_receive(id,
message->getBuffer(), &(message->messageSize),
RTEMS_NO_WAIT, 1);
if (status == RTEMS_SUCCESSFUL) {
this->lastPartner = message->getSender();
//Check size of incoming message.
if (message->messageSize < message->getMinimumMessageSize()) {
return HasReturnvaluesIF::RETURN_FAILED;
}
} else {
//No message was received. Keep lastPartner anyway, I might send something later.
//But still, delete packet content.
memset(message->getData(), 0, message->MAX_DATA_SIZE);
}
return convertReturnCode(status);
}
MessageQueueId_t MessageQueue::getLastPartner() const {
return this->lastPartner;
}
ReturnValue_t MessageQueue::flush(uint32_t* count) {
rtems_status_code status = rtems_message_queue_flush(id, count);
return convertReturnCode(status);
}
MessageQueueId_t MessageQueue::getId() const {
return this->id;
}
void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) {
this->defaultDestination = defaultDestination;
}
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo,
MessageQueueMessage* message, MessageQueueId_t sentFrom,
bool ignoreFault) {
message->setSender(sentFrom);
rtems_status_code result = rtems_message_queue_send(sendTo,
message->getBuffer(), message->messageSize);
//TODO: Check if we're in ISR.
if (result != RTEMS_SUCCESSFUL && !ignoreFault) {
if (internalErrorReporter == NULL) {
internalErrorReporter = objectManager->get<InternalErrorReporterIF>(
objects::INTERNAL_ERROR_REPORTER);
}
if (internalErrorReporter != NULL) {
internalErrorReporter->queueMessageNotSent();
}
}
ReturnValue_t returnCode = convertReturnCode(result);
if(result == MessageQueueIF::EMPTY){
return HasReturnvaluesIF::RETURN_FAILED;
}
return returnCode;
}
ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessage* message,
MessageQueueId_t sentFrom, bool ignoreFault) {
return sendMessageFrom(defaultDestination, message, sentFrom, ignoreFault);
}
MessageQueueId_t MessageQueue::getDefaultDestination() const {
return this->defaultDestination;
}
bool MessageQueue::isDefaultDestinationSet() const {
return (defaultDestination != NO_QUEUE);
}
ReturnValue_t MessageQueue::convertReturnCode(rtems_status_code inValue){
switch(inValue){
case RTEMS_SUCCESSFUL:
return HasReturnvaluesIF::RETURN_OK;
case RTEMS_INVALID_ID:
return HasReturnvaluesIF::RETURN_FAILED;
case RTEMS_TIMEOUT:
return HasReturnvaluesIF::RETURN_FAILED;
case RTEMS_OBJECT_WAS_DELETED:
return HasReturnvaluesIF::RETURN_FAILED;
case RTEMS_INVALID_ADDRESS:
return HasReturnvaluesIF::RETURN_FAILED;
case RTEMS_INVALID_SIZE:
return HasReturnvaluesIF::RETURN_FAILED;
case RTEMS_TOO_MANY:
return MessageQueueIF::FULL;
case RTEMS_UNSATISFIED:
return MessageQueueIF::EMPTY;
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
uint16_t MessageQueue::queueCounter = 0;

View File

@ -1,181 +1,181 @@
/**
* @file MessageQueue.h
*
* @date 10/02/2012
* @author Bastian Baetz
*
* @brief This file contains the definition of the MessageQueue class.
*/
#ifndef MESSAGEQUEUE_H_
#define MESSAGEQUEUE_H_
#include "../../internalError/InternalErrorReporterIF.h"
#include "../../ipc/MessageQueueIF.h"
#include "../../ipc/MessageQueueMessage.h"
#include "RtemsBasic.h"
/**
* @brief This class manages sending and receiving of message queue messages.
*
* @details Message queues are used to pass asynchronous messages between processes.
* They work like post boxes, where all incoming messages are stored in FIFO
* order. This class creates a new receiving queue and provides methods to fetch
* received messages. Being a child of MessageQueueSender, this class also provides
* methods to send a message to a user-defined or a default destination. In addition
* it also provides a reply method to answer to the queue it received its last message
* from.
* The MessageQueue should be used as "post box" for a single owning object. So all
* message queue communication is "n-to-one".
* For creating the queue, as well as sending and receiving messages, the class makes
* use of the operating system calls provided.
* \ingroup message_queue
*/
class MessageQueue : public MessageQueueIF {
public:
/**
* @brief The constructor initializes and configures the message queue.
* @details By making use of the according operating system call, a message queue is created
* and initialized. The message depth - the maximum number of messages to be
* buffered - may be set with the help of a parameter, whereas the message size is
* automatically set to the maximum message queue message size. The operating system
* sets the message queue id, or i case of failure, it is set to zero.
* @param message_depth The number of messages to be buffered before passing an error to the
* sender. Default is three.
* @param max_message_size With this parameter, the maximum message size can be adjusted.
* This should be left default.
*/
MessageQueue( size_t message_depth = 3, size_t max_message_size = MessageQueueMessage::MAX_MESSAGE_SIZE );
/**
* @brief The destructor deletes the formerly created message queue.
* @details This is accomplished by using the delete call provided by the operating system.
*/
virtual ~MessageQueue();
/**
* @brief This operation sends a message to the given destination.
* @details It directly uses the sendMessage call of the MessageQueueSender parent, but passes its
* queue id as "sentFrom" parameter.
* @param sendTo This parameter specifies the message queue id of the destination message queue.
* @param message A pointer to a previously created message, which is sent.
* @param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full.
*/
ReturnValue_t sendMessage(MessageQueueId_t sendTo,
MessageQueueMessage* message, bool ignoreFault = false );
/**
* @brief This operation sends a message to the default destination.
* @details As in the sendMessage method, this function uses the sendToDefault call of the
* MessageQueueSender parent class and adds its queue id as "sentFrom" information.
* @param message A pointer to a previously created message, which is sent.
*/
ReturnValue_t sendToDefault( MessageQueueMessage* message );
/**
* @brief This operation sends a message to the last communication partner.
* @details This operation simplifies answering an incoming message by using the stored
* lastParnter information as destination. If there was no message received yet
* (i.e. lastPartner is zero), an error code is returned.
* @param message A pointer to a previously created message, which is sent.
*/
ReturnValue_t reply( MessageQueueMessage* message );
/**
* @brief This function reads available messages from the message queue and returns the sender.
* @details It works identically to the other receiveMessage call, but in addition returns the
* sender's queue id.
* @param message A pointer to a message in which the received data is stored.
* @param receivedFrom A pointer to a queue id in which the sender's id is stored.
*/
ReturnValue_t receiveMessage(MessageQueueMessage* message,
MessageQueueId_t *receivedFrom);
/**
* @brief This function reads available messages from the message queue.
* @details If data is available it is stored in the passed message pointer. The message's
* original content is overwritten and the sendFrom information is stored in the
* lastPartner attribute. Else, the lastPartner information remains untouched, the
* message's content is cleared and the function returns immediately.
* @param message A pointer to a message in which the received data is stored.
*/
ReturnValue_t receiveMessage(MessageQueueMessage* message);
/**
* Deletes all pending messages in the queue.
* @param count The number of flushed messages.
* @return RETURN_OK on success.
*/
ReturnValue_t flush(uint32_t* count);
/**
* @brief This method returns the message queue id of the last communication partner.
*/
MessageQueueId_t getLastPartner() const;
/**
* @brief This method returns the message queue id of this class's message queue.
*/
MessageQueueId_t getId() const;
/**
* \brief With the sendMessage call, a queue message is sent to a receiving queue.
* \details This method takes the message provided, adds the sentFrom information and passes
* it on to the destination provided with an operating system call. The OS's return
* value is returned.
* \param sendTo This parameter specifies the message queue id to send the message to.
* \param message This is a pointer to a previously created message, which is sent.
* \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message.
* This variable is set to zero by default.
* \param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full.
*/
virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false );
/**
* \brief The sendToDefault method sends a queue message to the default destination.
* \details In all other aspects, it works identical to the sendMessage method.
* \param message This is a pointer to a previously created message, which is sent.
* \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message.
* This variable is set to zero by default.
*/
virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false );
/**
* \brief This method is a simple setter for the default destination.
*/
void setDefaultDestination(MessageQueueId_t defaultDestination);
/**
* \brief This method is a simple getter for the default destination.
*/
MessageQueueId_t getDefaultDestination() const;
bool isDefaultDestinationSet() const;
private:
/**
* @brief The class stores the queue id it got assigned from the operating system in this attribute.
* If initialization fails, the queue id is set to zero.
*/
MessageQueueId_t id;
/**
* @brief In this attribute, the queue id of the last communication partner is stored
* to allow for replying.
*/
MessageQueueId_t lastPartner;
/**
* @brief The message queue's name -a user specific information for the operating system- is
* generated automatically with the help of this static counter.
*/
/**
* \brief This attribute stores a default destination to send messages to.
* \details It is stored to simplify sending to always-the-same receiver. The attribute may
* be set in the constructor or by a setter call to setDefaultDestination.
*/
MessageQueueId_t defaultDestination;
/**
* \brief This attribute stores a reference to the internal error reporter for reporting full queues.
* \details In the event of a full destination queue, the reporter will be notified. The reference is set
* by lazy loading
*/
InternalErrorReporterIF *internalErrorReporter;
static uint16_t queueCounter;
/**
* A method to convert an OS-specific return code to the frameworks return value concept.
* @param inValue The return code coming from the OS.
* @return The converted return value.
*/
static ReturnValue_t convertReturnCode(rtems_status_code inValue);
};
#endif /* MESSAGEQUEUE_H_ */
/**
* @file MessageQueue.h
*
* @date 10/02/2012
* @author Bastian Baetz
*
* @brief This file contains the definition of the MessageQueue class.
*/
#ifndef MESSAGEQUEUE_H_
#define MESSAGEQUEUE_H_
#include "../../internalError/InternalErrorReporterIF.h"
#include "../../ipc/MessageQueueIF.h"
#include "../../ipc/MessageQueueMessage.h"
#include "RtemsBasic.h"
/**
* @brief This class manages sending and receiving of message queue messages.
*
* @details Message queues are used to pass asynchronous messages between processes.
* They work like post boxes, where all incoming messages are stored in FIFO
* order. This class creates a new receiving queue and provides methods to fetch
* received messages. Being a child of MessageQueueSender, this class also provides
* methods to send a message to a user-defined or a default destination. In addition
* it also provides a reply method to answer to the queue it received its last message
* from.
* The MessageQueue should be used as "post box" for a single owning object. So all
* message queue communication is "n-to-one".
* For creating the queue, as well as sending and receiving messages, the class makes
* use of the operating system calls provided.
* \ingroup message_queue
*/
class MessageQueue : public MessageQueueIF {
public:
/**
* @brief The constructor initializes and configures the message queue.
* @details By making use of the according operating system call, a message queue is created
* and initialized. The message depth - the maximum number of messages to be
* buffered - may be set with the help of a parameter, whereas the message size is
* automatically set to the maximum message queue message size. The operating system
* sets the message queue id, or i case of failure, it is set to zero.
* @param message_depth The number of messages to be buffered before passing an error to the
* sender. Default is three.
* @param max_message_size With this parameter, the maximum message size can be adjusted.
* This should be left default.
*/
MessageQueue( size_t message_depth = 3, size_t max_message_size = MessageQueueMessage::MAX_MESSAGE_SIZE );
/**
* @brief The destructor deletes the formerly created message queue.
* @details This is accomplished by using the delete call provided by the operating system.
*/
virtual ~MessageQueue();
/**
* @brief This operation sends a message to the given destination.
* @details It directly uses the sendMessage call of the MessageQueueSender parent, but passes its
* queue id as "sentFrom" parameter.
* @param sendTo This parameter specifies the message queue id of the destination message queue.
* @param message A pointer to a previously created message, which is sent.
* @param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full.
*/
ReturnValue_t sendMessage(MessageQueueId_t sendTo,
MessageQueueMessage* message, bool ignoreFault = false );
/**
* @brief This operation sends a message to the default destination.
* @details As in the sendMessage method, this function uses the sendToDefault call of the
* MessageQueueSender parent class and adds its queue id as "sentFrom" information.
* @param message A pointer to a previously created message, which is sent.
*/
ReturnValue_t sendToDefault( MessageQueueMessage* message );
/**
* @brief This operation sends a message to the last communication partner.
* @details This operation simplifies answering an incoming message by using the stored
* lastParnter information as destination. If there was no message received yet
* (i.e. lastPartner is zero), an error code is returned.
* @param message A pointer to a previously created message, which is sent.
*/
ReturnValue_t reply( MessageQueueMessage* message );
/**
* @brief This function reads available messages from the message queue and returns the sender.
* @details It works identically to the other receiveMessage call, but in addition returns the
* sender's queue id.
* @param message A pointer to a message in which the received data is stored.
* @param receivedFrom A pointer to a queue id in which the sender's id is stored.
*/
ReturnValue_t receiveMessage(MessageQueueMessage* message,
MessageQueueId_t *receivedFrom);
/**
* @brief This function reads available messages from the message queue.
* @details If data is available it is stored in the passed message pointer. The message's
* original content is overwritten and the sendFrom information is stored in the
* lastPartner attribute. Else, the lastPartner information remains untouched, the
* message's content is cleared and the function returns immediately.
* @param message A pointer to a message in which the received data is stored.
*/
ReturnValue_t receiveMessage(MessageQueueMessage* message);
/**
* Deletes all pending messages in the queue.
* @param count The number of flushed messages.
* @return RETURN_OK on success.
*/
ReturnValue_t flush(uint32_t* count);
/**
* @brief This method returns the message queue id of the last communication partner.
*/
MessageQueueId_t getLastPartner() const;
/**
* @brief This method returns the message queue id of this class's message queue.
*/
MessageQueueId_t getId() const;
/**
* \brief With the sendMessage call, a queue message is sent to a receiving queue.
* \details This method takes the message provided, adds the sentFrom information and passes
* it on to the destination provided with an operating system call. The OS's return
* value is returned.
* \param sendTo This parameter specifies the message queue id to send the message to.
* \param message This is a pointer to a previously created message, which is sent.
* \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message.
* This variable is set to zero by default.
* \param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full.
*/
virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false );
/**
* \brief The sendToDefault method sends a queue message to the default destination.
* \details In all other aspects, it works identical to the sendMessage method.
* \param message This is a pointer to a previously created message, which is sent.
* \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message.
* This variable is set to zero by default.
*/
virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false );
/**
* \brief This method is a simple setter for the default destination.
*/
void setDefaultDestination(MessageQueueId_t defaultDestination);
/**
* \brief This method is a simple getter for the default destination.
*/
MessageQueueId_t getDefaultDestination() const;
bool isDefaultDestinationSet() const;
private:
/**
* @brief The class stores the queue id it got assigned from the operating system in this attribute.
* If initialization fails, the queue id is set to zero.
*/
MessageQueueId_t id;
/**
* @brief In this attribute, the queue id of the last communication partner is stored
* to allow for replying.
*/
MessageQueueId_t lastPartner;
/**
* @brief The message queue's name -a user specific information for the operating system- is
* generated automatically with the help of this static counter.
*/
/**
* \brief This attribute stores a default destination to send messages to.
* \details It is stored to simplify sending to always-the-same receiver. The attribute may
* be set in the constructor or by a setter call to setDefaultDestination.
*/
MessageQueueId_t defaultDestination;
/**
* \brief This attribute stores a reference to the internal error reporter for reporting full queues.
* \details In the event of a full destination queue, the reporter will be notified. The reference is set
* by lazy loading
*/
InternalErrorReporterIF *internalErrorReporter;
static uint16_t queueCounter;
/**
* A method to convert an OS-specific return code to the frameworks return value concept.
* @param inValue The return code coming from the OS.
* @return The converted return value.
*/
static ReturnValue_t convertReturnCode(rtems_status_code inValue);
};
#endif /* MESSAGEQUEUE_H_ */

View File

@ -1,87 +1,87 @@
/**
* @file MultiObjectTask.cpp
* @brief This file defines the MultiObjectTask class.
* @date 30.01.2014
* @author baetz
*/
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../tasks/ExecutableObjectIF.h"
#include "MultiObjectTask.h"
MultiObjectTask::MultiObjectTask(const char *name, rtems_task_priority setPriority,
size_t setStack, rtems_interval setPeriod, void (*setDeadlineMissedFunc)()) :
TaskBase(setPriority, setStack, name), periodTicks(
RtemsBasic::convertMsToTicks(setPeriod)), periodId(0), deadlineMissedFunc(
setDeadlineMissedFunc) {
}
MultiObjectTask::~MultiObjectTask(void) {
//Do not delete objects, we were responsible for ptrs only.
rtems_rate_monotonic_delete(periodId);
}
rtems_task MultiObjectTask::taskEntryPoint(rtems_task_argument argument) {
//The argument is re-interpreted as MultiObjectTask. The Task object is global, so it is found from any place.
MultiObjectTask *originalTask(reinterpret_cast<MultiObjectTask*>(argument));
originalTask->taskFunctionality();
}
ReturnValue_t MultiObjectTask::startTask() {
rtems_status_code status = rtems_task_start(id, MultiObjectTask::taskEntryPoint,
rtems_task_argument((void *) this));
if (status != RTEMS_SUCCESSFUL) {
error << "ObjectTask::startTask for " << std::hex << this->getId()
<< std::dec << " failed." << std::endl;
}
switch(status){
case RTEMS_SUCCESSFUL:
//ask started successfully
return HasReturnvaluesIF::RETURN_OK;
default:
/* RTEMS_INVALID_ADDRESS - invalid task entry point
RTEMS_INVALID_ID - invalid task id
RTEMS_INCORRECT_STATE - task not in the dormant state
RTEMS_ILLEGAL_ON_REMOTE_OBJECT - cannot start remote task */
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t MultiObjectTask::sleepFor(uint32_t ms) {
return TaskBase::sleepFor(ms);
}
void MultiObjectTask::taskFunctionality() {
TaskBase::setAndStartPeriod(periodTicks,&periodId);
//The task's "infinite" inner loop is entered.
while (1) {
for (ObjectList::iterator it = objectList.begin();
it != objectList.end(); ++it) {
(*it)->performOperation();
}
rtems_status_code status = TaskBase::restartPeriod(periodTicks,periodId);
if (status == RTEMS_TIMEOUT) {
char nameSpace[8] = { 0 };
char* ptr = rtems_object_get_name(getId(), sizeof(nameSpace),
nameSpace);
error << "ObjectTask: " << ptr << " Deadline missed." << std::endl;
if (this->deadlineMissedFunc != NULL) {
this->deadlineMissedFunc();
}
}
}
}
ReturnValue_t MultiObjectTask::addComponent(object_id_t object) {
ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>(
object);
if (newObject == NULL) {
return HasReturnvaluesIF::RETURN_FAILED;
}
objectList.push_back(newObject);
ReturnValue_t result = newObject->initializeAfterTaskCreation();
return result;
}
uint32_t MultiObjectTask::getPeriodMs() const {
return RtemsBasic::convertTicksToMs(periodTicks);
}
/**
* @file MultiObjectTask.cpp
* @brief This file defines the MultiObjectTask class.
* @date 30.01.2014
* @author baetz
*/
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../tasks/ExecutableObjectIF.h"
#include "MultiObjectTask.h"
MultiObjectTask::MultiObjectTask(const char *name, rtems_task_priority setPriority,
size_t setStack, rtems_interval setPeriod, void (*setDeadlineMissedFunc)()) :
TaskBase(setPriority, setStack, name), periodTicks(
RtemsBasic::convertMsToTicks(setPeriod)), periodId(0), deadlineMissedFunc(
setDeadlineMissedFunc) {
}
MultiObjectTask::~MultiObjectTask(void) {
//Do not delete objects, we were responsible for ptrs only.
rtems_rate_monotonic_delete(periodId);
}
rtems_task MultiObjectTask::taskEntryPoint(rtems_task_argument argument) {
//The argument is re-interpreted as MultiObjectTask. The Task object is global, so it is found from any place.
MultiObjectTask *originalTask(reinterpret_cast<MultiObjectTask*>(argument));
originalTask->taskFunctionality();
}
ReturnValue_t MultiObjectTask::startTask() {
rtems_status_code status = rtems_task_start(id, MultiObjectTask::taskEntryPoint,
rtems_task_argument((void *) this));
if (status != RTEMS_SUCCESSFUL) {
error << "ObjectTask::startTask for " << std::hex << this->getId()
<< std::dec << " failed." << std::endl;
}
switch(status){
case RTEMS_SUCCESSFUL:
//ask started successfully
return HasReturnvaluesIF::RETURN_OK;
default:
/* RTEMS_INVALID_ADDRESS - invalid task entry point
RTEMS_INVALID_ID - invalid task id
RTEMS_INCORRECT_STATE - task not in the dormant state
RTEMS_ILLEGAL_ON_REMOTE_OBJECT - cannot start remote task */
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t MultiObjectTask::sleepFor(uint32_t ms) {
return TaskBase::sleepFor(ms);
}
void MultiObjectTask::taskFunctionality() {
TaskBase::setAndStartPeriod(periodTicks,&periodId);
//The task's "infinite" inner loop is entered.
while (1) {
for (ObjectList::iterator it = objectList.begin();
it != objectList.end(); ++it) {
(*it)->performOperation();
}
rtems_status_code status = TaskBase::restartPeriod(periodTicks,periodId);
if (status == RTEMS_TIMEOUT) {
char nameSpace[8] = { 0 };
char* ptr = rtems_object_get_name(getId(), sizeof(nameSpace),
nameSpace);
error << "ObjectTask: " << ptr << " Deadline missed." << std::endl;
if (this->deadlineMissedFunc != NULL) {
this->deadlineMissedFunc();
}
}
}
}
ReturnValue_t MultiObjectTask::addComponent(object_id_t object) {
ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>(
object);
if (newObject == NULL) {
return HasReturnvaluesIF::RETURN_FAILED;
}
objectList.push_back(newObject);
ReturnValue_t result = newObject->initializeAfterTaskCreation();
return result;
}
uint32_t MultiObjectTask::getPeriodMs() const {
return RtemsBasic::convertTicksToMs(periodTicks);
}

View File

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

View File

@ -1,65 +1,65 @@
#include "Mutex.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
const uint32_t MutexIF::NO_TIMEOUT = RTEMS_NO_TIMEOUT;
uint8_t Mutex::count = 0;
Mutex::Mutex() :
mutexId(0) {
rtems_name mutexName = ('M' << 24) + ('T' << 16) + ('X' << 8) + count++;
rtems_status_code status = rtems_semaphore_create(mutexName, 1,
RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY, 0,
&mutexId);
if (status != RTEMS_SUCCESSFUL) {
error << "Mutex: creation with name, id " << mutexName << ", " << mutexId
<< " failed with " << status << std::endl;
}
}
Mutex::~Mutex() {
rtems_status_code status = rtems_semaphore_delete(mutexId);
if (status != RTEMS_SUCCESSFUL) {
error << "Mutex: deletion for id " << mutexId
<< " failed with " << status << std::endl;
}
}
ReturnValue_t Mutex::lockMutex(uint32_t timeoutMs) {
rtems_status_code status = rtems_semaphore_obtain(mutexId, RTEMS_WAIT, timeoutMs);
switch(status){
case RTEMS_SUCCESSFUL:
//semaphore obtained successfully
return HasReturnvaluesIF::RETURN_OK;
case RTEMS_UNSATISFIED:
//semaphore not available
return MUTEX_NOT_FOUND;
case RTEMS_TIMEOUT:
//timed out waiting for semaphore
return MUTEX_TIMEOUT;
case RTEMS_OBJECT_WAS_DELETED:
//semaphore deleted while waiting
return MUTEX_DESTROYED_WHILE_WAITING;
case RTEMS_INVALID_ID:
//invalid semaphore id
return MUTEX_INVALID_ID;
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t Mutex::unlockMutex() {
rtems_status_code status = rtems_semaphore_release(mutexId);
switch(status){
case RTEMS_SUCCESSFUL:
//semaphore obtained successfully
return HasReturnvaluesIF::RETURN_OK;
case RTEMS_NOT_OWNER_OF_RESOURCE:
//semaphore not available
return CURR_THREAD_DOES_NOT_OWN_MUTEX;
case RTEMS_INVALID_ID:
//invalid semaphore id
return MUTEX_INVALID_ID;
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
#include "Mutex.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
const uint32_t MutexIF::NO_TIMEOUT = RTEMS_NO_TIMEOUT;
uint8_t Mutex::count = 0;
Mutex::Mutex() :
mutexId(0) {
rtems_name mutexName = ('M' << 24) + ('T' << 16) + ('X' << 8) + count++;
rtems_status_code status = rtems_semaphore_create(mutexName, 1,
RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY, 0,
&mutexId);
if (status != RTEMS_SUCCESSFUL) {
error << "Mutex: creation with name, id " << mutexName << ", " << mutexId
<< " failed with " << status << std::endl;
}
}
Mutex::~Mutex() {
rtems_status_code status = rtems_semaphore_delete(mutexId);
if (status != RTEMS_SUCCESSFUL) {
error << "Mutex: deletion for id " << mutexId
<< " failed with " << status << std::endl;
}
}
ReturnValue_t Mutex::lockMutex(uint32_t timeoutMs) {
rtems_status_code status = rtems_semaphore_obtain(mutexId, RTEMS_WAIT, timeoutMs);
switch(status){
case RTEMS_SUCCESSFUL:
//semaphore obtained successfully
return HasReturnvaluesIF::RETURN_OK;
case RTEMS_UNSATISFIED:
//semaphore not available
return MUTEX_NOT_FOUND;
case RTEMS_TIMEOUT:
//timed out waiting for semaphore
return MUTEX_TIMEOUT;
case RTEMS_OBJECT_WAS_DELETED:
//semaphore deleted while waiting
return MUTEX_DESTROYED_WHILE_WAITING;
case RTEMS_INVALID_ID:
//invalid semaphore id
return MUTEX_INVALID_ID;
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t Mutex::unlockMutex() {
rtems_status_code status = rtems_semaphore_release(mutexId);
switch(status){
case RTEMS_SUCCESSFUL:
//semaphore obtained successfully
return HasReturnvaluesIF::RETURN_OK;
case RTEMS_NOT_OWNER_OF_RESOURCE:
//semaphore not available
return CURR_THREAD_DOES_NOT_OWN_MUTEX;
case RTEMS_INVALID_ID:
//invalid semaphore id
return MUTEX_INVALID_ID;
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}

View File

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

View File

@ -1,24 +1,24 @@
#include "../../ipc/MutexFactory.h"
#include "Mutex.h"
#include "RtemsBasic.h"
//TODO: Different variant than the lazy loading in QueueFactory. What's better and why?
MutexFactory* MutexFactory::factoryInstance = new MutexFactory();
MutexFactory::MutexFactory() {
}
MutexFactory::~MutexFactory() {
}
MutexFactory* MutexFactory::instance() {
return MutexFactory::factoryInstance;
}
MutexIF* MutexFactory::createMutex() {
return new Mutex();
}
void MutexFactory::deleteMutex(MutexIF* mutex) {
delete mutex;
}
#include "../../ipc/MutexFactory.h"
#include "Mutex.h"
#include "RtemsBasic.h"
//TODO: Different variant than the lazy loading in QueueFactory. What's better and why?
MutexFactory* MutexFactory::factoryInstance = new MutexFactory();
MutexFactory::MutexFactory() {
}
MutexFactory::~MutexFactory() {
}
MutexFactory* MutexFactory::instance() {
return MutexFactory::factoryInstance;
}
MutexIF* MutexFactory::createMutex() {
return new Mutex();
}
void MutexFactory::deleteMutex(MutexIF* mutex) {
delete mutex;
}

View File

@ -1,122 +1,122 @@
#include "../../tasks/FixedSequenceSlot.h"
#include "../../objectmanager/SystemObjectIF.h"
#include "../../osal/rtems/PollingTask.h"
#include "../../osal/rtems/RtemsBasic.h"
#include "../../returnvalues/HasReturnvaluesIF.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include <rtems/bspIo.h>
#include <rtems/rtems/ratemon.h>
#include <rtems/rtems/status.h>
#include <rtems/rtems/tasks.h>
#include <rtems/rtems/types.h>
#include <stddef.h>
#include <sys/_stdint.h>
#include <iostream>
#include <list>
uint32_t PollingTask::deadlineMissedCount = 0;
PollingTask::PollingTask(const char *name, rtems_task_priority setPriority,
size_t setStack, uint32_t setOverallPeriod,
void (*setDeadlineMissedFunc)()) :
TaskBase(setPriority, setStack, name), periodId(0), pst(
setOverallPeriod) {
// All additional attributes are applied to the object.
this->deadlineMissedFunc = setDeadlineMissedFunc;
}
PollingTask::~PollingTask() {
}
rtems_task PollingTask::taskEntryPoint(rtems_task_argument argument) {
//The argument is re-interpreted as PollingTask.
PollingTask *originalTask(reinterpret_cast<PollingTask*>(argument));
//The task's functionality is called.
originalTask->taskFunctionality();
debug << "Polling task " << originalTask->getId()
<< " returned from taskFunctionality." << std::endl;
}
void PollingTask::missedDeadlineCounter() {
PollingTask::deadlineMissedCount++;
if (PollingTask::deadlineMissedCount % 10 == 0) {
error << "PST missed " << PollingTask::deadlineMissedCount
<< " deadlines." << std::endl;
}
}
ReturnValue_t PollingTask::startTask() {
rtems_status_code status = rtems_task_start(id, PollingTask::taskEntryPoint,
rtems_task_argument((void *) this));
if (status != RTEMS_SUCCESSFUL) {
error << "PollingTask::startTask for " << std::hex << this->getId()
<< std::dec << " failed." << std::endl;
}
switch(status){
case RTEMS_SUCCESSFUL:
//ask started successfully
return HasReturnvaluesIF::RETURN_OK;
default:
/* RTEMS_INVALID_ADDRESS - invalid task entry point
RTEMS_INVALID_ID - invalid task id
RTEMS_INCORRECT_STATE - task not in the dormant state
RTEMS_ILLEGAL_ON_REMOTE_OBJECT - cannot start remote task */
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t PollingTask::addSlot(object_id_t componentId,
uint32_t slotTimeMs, int8_t executionStep) {
if (objectManager->get<ExecutableObjectIF>(componentId) != nullptr) {
pst.addSlot(componentId, slotTimeMs, executionStep, this);
return HasReturnvaluesIF::RETURN_OK;
}
sif::error << "Component " << std::hex << componentId <<
" not found, not adding it to pst" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
uint32_t PollingTask::getPeriodMs() const {
return pst.getLengthMs();
}
ReturnValue_t PollingTask::checkAndInitializeSequence() const {
return pst.checkSequence();
}
#include <rtems/io.h>
void PollingTask::taskFunctionality() {
// A local iterator for the Polling Sequence Table is created to find the start time for the first entry.
std::list<FixedSequenceSlot*>::iterator it = pst.current;
//The start time for the first entry is read.
rtems_interval interval = RtemsBasic::convertMsToTicks(
(*it)->pollingTimeMs);
TaskBase::setAndStartPeriod(interval,&periodId);
//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 = RtemsBasic::convertMsToTicks(this->pst.getIntervalToNextSlotMs());
//The period is checked and restarted with the new interval.
//If the deadline was missed, the deadlineMissedFunc is called.
rtems_status_code status = TaskBase::restartPeriod(interval,periodId);
if (status == RTEMS_TIMEOUT) {
if (this->deadlineMissedFunc != NULL) {
this->deadlineMissedFunc();
}
}
}
//The device handler for this slot is executed and the next one is chosen.
this->pst.executeAndAdvance();
}
}
ReturnValue_t PollingTask::sleepFor(uint32_t ms){
return TaskBase::sleepFor(ms);
};
#include "../../tasks/FixedSequenceSlot.h"
#include "../../objectmanager/SystemObjectIF.h"
#include "../../osal/rtems/PollingTask.h"
#include "../../osal/rtems/RtemsBasic.h"
#include "../../returnvalues/HasReturnvaluesIF.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include <rtems/bspIo.h>
#include <rtems/rtems/ratemon.h>
#include <rtems/rtems/status.h>
#include <rtems/rtems/tasks.h>
#include <rtems/rtems/types.h>
#include <stddef.h>
#include <sys/_stdint.h>
#include <iostream>
#include <list>
uint32_t PollingTask::deadlineMissedCount = 0;
PollingTask::PollingTask(const char *name, rtems_task_priority setPriority,
size_t setStack, uint32_t setOverallPeriod,
void (*setDeadlineMissedFunc)()) :
TaskBase(setPriority, setStack, name), periodId(0), pst(
setOverallPeriod) {
// All additional attributes are applied to the object.
this->deadlineMissedFunc = setDeadlineMissedFunc;
}
PollingTask::~PollingTask() {
}
rtems_task PollingTask::taskEntryPoint(rtems_task_argument argument) {
//The argument is re-interpreted as PollingTask.
PollingTask *originalTask(reinterpret_cast<PollingTask*>(argument));
//The task's functionality is called.
originalTask->taskFunctionality();
debug << "Polling task " << originalTask->getId()
<< " returned from taskFunctionality." << std::endl;
}
void PollingTask::missedDeadlineCounter() {
PollingTask::deadlineMissedCount++;
if (PollingTask::deadlineMissedCount % 10 == 0) {
error << "PST missed " << PollingTask::deadlineMissedCount
<< " deadlines." << std::endl;
}
}
ReturnValue_t PollingTask::startTask() {
rtems_status_code status = rtems_task_start(id, PollingTask::taskEntryPoint,
rtems_task_argument((void *) this));
if (status != RTEMS_SUCCESSFUL) {
error << "PollingTask::startTask for " << std::hex << this->getId()
<< std::dec << " failed." << std::endl;
}
switch(status){
case RTEMS_SUCCESSFUL:
//ask started successfully
return HasReturnvaluesIF::RETURN_OK;
default:
/* RTEMS_INVALID_ADDRESS - invalid task entry point
RTEMS_INVALID_ID - invalid task id
RTEMS_INCORRECT_STATE - task not in the dormant state
RTEMS_ILLEGAL_ON_REMOTE_OBJECT - cannot start remote task */
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t PollingTask::addSlot(object_id_t componentId,
uint32_t slotTimeMs, int8_t executionStep) {
if (objectManager->get<ExecutableObjectIF>(componentId) != nullptr) {
pst.addSlot(componentId, slotTimeMs, executionStep, this);
return HasReturnvaluesIF::RETURN_OK;
}
sif::error << "Component " << std::hex << componentId <<
" not found, not adding it to pst" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
uint32_t PollingTask::getPeriodMs() const {
return pst.getLengthMs();
}
ReturnValue_t PollingTask::checkAndInitializeSequence() const {
return pst.checkSequence();
}
#include <rtems/io.h>
void PollingTask::taskFunctionality() {
// A local iterator for the Polling Sequence Table is created to find the start time for the first entry.
std::list<FixedSequenceSlot*>::iterator it = pst.current;
//The start time for the first entry is read.
rtems_interval interval = RtemsBasic::convertMsToTicks(
(*it)->pollingTimeMs);
TaskBase::setAndStartPeriod(interval,&periodId);
//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 = RtemsBasic::convertMsToTicks(this->pst.getIntervalToNextSlotMs());
//The period is checked and restarted with the new interval.
//If the deadline was missed, the deadlineMissedFunc is called.
rtems_status_code status = TaskBase::restartPeriod(interval,periodId);
if (status == RTEMS_TIMEOUT) {
if (this->deadlineMissedFunc != NULL) {
this->deadlineMissedFunc();
}
}
}
//The device handler for this slot is executed and the next one is chosen.
this->pst.executeAndAdvance();
}
}
ReturnValue_t PollingTask::sleepFor(uint32_t ms){
return TaskBase::sleepFor(ms);
};

View File

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

View File

@ -1,59 +1,59 @@
#include "../../ipc/QueueFactory.h"
#include "MessageQueue.h"
#include "RtemsBasic.h"
QueueFactory* QueueFactory::factoryInstance = NULL;
ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo,
MessageQueueMessage* message, MessageQueueId_t sentFrom,bool ignoreFault) {
//TODO add ignoreFault functionality
message->setSender(sentFrom);
rtems_status_code result = rtems_message_queue_send(sendTo, message->getBuffer(),
message->messageSize);
switch(result){
case RTEMS_SUCCESSFUL:
//message sent successfully
return HasReturnvaluesIF::RETURN_OK;
case RTEMS_INVALID_ID:
//invalid queue id
return HasReturnvaluesIF::RETURN_FAILED;
case RTEMS_INVALID_SIZE:
// invalid message size
return HasReturnvaluesIF::RETURN_FAILED;
case RTEMS_INVALID_ADDRESS:
//buffer is NULL
return HasReturnvaluesIF::RETURN_FAILED;
case RTEMS_UNSATISFIED:
//out of message buffers
return HasReturnvaluesIF::RETURN_FAILED;
case RTEMS_TOO_MANY:
//queue's limit has been reached
return MessageQueueIF::FULL;
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
QueueFactory* QueueFactory::instance() {
if (factoryInstance == NULL) {
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 "MessageQueue.h"
#include "RtemsBasic.h"
QueueFactory* QueueFactory::factoryInstance = NULL;
ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo,
MessageQueueMessage* message, MessageQueueId_t sentFrom,bool ignoreFault) {
//TODO add ignoreFault functionality
message->setSender(sentFrom);
rtems_status_code result = rtems_message_queue_send(sendTo, message->getBuffer(),
message->messageSize);
switch(result){
case RTEMS_SUCCESSFUL:
//message sent successfully
return HasReturnvaluesIF::RETURN_OK;
case RTEMS_INVALID_ID:
//invalid queue id
return HasReturnvaluesIF::RETURN_FAILED;
case RTEMS_INVALID_SIZE:
// invalid message size
return HasReturnvaluesIF::RETURN_FAILED;
case RTEMS_INVALID_ADDRESS:
//buffer is NULL
return HasReturnvaluesIF::RETURN_FAILED;
case RTEMS_UNSATISFIED:
//out of message buffers
return HasReturnvaluesIF::RETURN_FAILED;
case RTEMS_TOO_MANY:
//queue's limit has been reached
return MessageQueueIF::FULL;
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
QueueFactory* QueueFactory::instance() {
if (factoryInstance == NULL) {
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,25 +1,25 @@
#ifndef OS_RTEMS_RTEMSBASIC_H_
#define OS_RTEMS_RTEMSBASIC_H_
#include "../../returnvalues/HasReturnvaluesIF.h"
#include <rtems.h>
#include <rtems/libio.h>
#include <rtems/error.h>
#include <rtems/stackchk.h>
#include <stddef.h>
class RtemsBasic {
public:
static rtems_interval convertMsToTicks(uint32_t msIn) {
rtems_interval ticks_per_second = rtems_clock_get_ticks_per_second();
return (ticks_per_second * msIn) / 1000;
}
static rtems_interval convertTicksToMs(rtems_interval ticksIn) {
rtems_interval ticks_per_second = rtems_clock_get_ticks_per_second();
return (ticksIn * 1000) / ticks_per_second;
}
};
#endif /* OS_RTEMS_RTEMSBASIC_H_ */
#ifndef OS_RTEMS_RTEMSBASIC_H_
#define OS_RTEMS_RTEMSBASIC_H_
#include "../../returnvalues/HasReturnvaluesIF.h"
#include <rtems.h>
#include <rtems/libio.h>
#include <rtems/error.h>
#include <rtems/stackchk.h>
#include <stddef.h>
class RtemsBasic {
public:
static rtems_interval convertMsToTicks(uint32_t msIn) {
rtems_interval ticks_per_second = rtems_clock_get_ticks_per_second();
return (ticks_per_second * msIn) / 1000;
}
static rtems_interval convertTicksToMs(rtems_interval ticksIn) {
rtems_interval ticks_per_second = rtems_clock_get_ticks_per_second();
return (ticksIn * 1000) / ticks_per_second;
}
};
#endif /* OS_RTEMS_RTEMSBASIC_H_ */

View File

@ -1,82 +1,82 @@
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "TaskBase.h"
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE=RTEMS_MINIMUM_STACK_SIZE;
TaskBase::TaskBase(rtems_task_priority set_priority, size_t stack_size,
const char *name) {
rtems_name osalName = 0;
for (uint8_t i = 0; i < 4; i++) {
if (name[i] == 0) {
break;
}
osalName += name[i] << (8 * (3 - i));
}
//The task is created with the operating system's system call.
rtems_status_code status = RTEMS_UNSATISFIED;
if (set_priority >= 0 && set_priority <= 99) {
status = rtems_task_create(osalName,
(0xFF - 2 * set_priority), stack_size,
RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR,
RTEMS_FLOATING_POINT, &id);
}
ReturnValue_t result = convertReturnCode(status);
if (result != HasReturnvaluesIF::RETURN_OK) {
error << "TaskBase::TaskBase: createTask with name " << std::hex
<< osalName << std::dec << " failed with return code "
<< (uint32_t) status << std::endl;
this->id = 0;
}
}
TaskBase::~TaskBase() {
rtems_task_delete(id);
}
rtems_id TaskBase::getId() {
return this->id;
}
ReturnValue_t TaskBase::sleepFor(uint32_t ms) {
rtems_status_code status = rtems_task_wake_after(RtemsBasic::convertMsToTicks(ms));
return convertReturnCode(status);
}
ReturnValue_t TaskBase::convertReturnCode(rtems_status_code inValue) {
switch (inValue) {
case RTEMS_SUCCESSFUL:
return HasReturnvaluesIF::RETURN_OK;
case RTEMS_MP_NOT_CONFIGURED:
return HasReturnvaluesIF::RETURN_FAILED;
case RTEMS_INVALID_NAME:
return HasReturnvaluesIF::RETURN_FAILED;
case RTEMS_TOO_MANY:
return HasReturnvaluesIF::RETURN_FAILED;
case RTEMS_INVALID_ADDRESS:
return HasReturnvaluesIF::RETURN_FAILED;
case RTEMS_UNSATISFIED:
return HasReturnvaluesIF::RETURN_FAILED;
case RTEMS_INVALID_PRIORITY:
return HasReturnvaluesIF::RETURN_FAILED;
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t TaskBase::setAndStartPeriod(rtems_interval period, rtems_id *periodId) {
rtems_name periodName = (('P' << 24) + ('e' << 16) + ('r' << 8) + 'd');
rtems_status_code status = rtems_rate_monotonic_create(periodName, periodId);
if (status == RTEMS_SUCCESSFUL) {
status = restartPeriod(period,*periodId);
}
return convertReturnCode(status);
}
rtems_status_code TaskBase::restartPeriod(rtems_interval period, rtems_id periodId){
//This is necessary to avoid a call with period = 0, which does not start the period.
rtems_status_code status = rtems_rate_monotonic_period(periodId, period + 1);
return status;
}
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "TaskBase.h"
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE=RTEMS_MINIMUM_STACK_SIZE;
TaskBase::TaskBase(rtems_task_priority set_priority, size_t stack_size,
const char *name) {
rtems_name osalName = 0;
for (uint8_t i = 0; i < 4; i++) {
if (name[i] == 0) {
break;
}
osalName += name[i] << (8 * (3 - i));
}
//The task is created with the operating system's system call.
rtems_status_code status = RTEMS_UNSATISFIED;
if (set_priority >= 0 && set_priority <= 99) {
status = rtems_task_create(osalName,
(0xFF - 2 * set_priority), stack_size,
RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR,
RTEMS_FLOATING_POINT, &id);
}
ReturnValue_t result = convertReturnCode(status);
if (result != HasReturnvaluesIF::RETURN_OK) {
error << "TaskBase::TaskBase: createTask with name " << std::hex
<< osalName << std::dec << " failed with return code "
<< (uint32_t) status << std::endl;
this->id = 0;
}
}
TaskBase::~TaskBase() {
rtems_task_delete(id);
}
rtems_id TaskBase::getId() {
return this->id;
}
ReturnValue_t TaskBase::sleepFor(uint32_t ms) {
rtems_status_code status = rtems_task_wake_after(RtemsBasic::convertMsToTicks(ms));
return convertReturnCode(status);
}
ReturnValue_t TaskBase::convertReturnCode(rtems_status_code inValue) {
switch (inValue) {
case RTEMS_SUCCESSFUL:
return HasReturnvaluesIF::RETURN_OK;
case RTEMS_MP_NOT_CONFIGURED:
return HasReturnvaluesIF::RETURN_FAILED;
case RTEMS_INVALID_NAME:
return HasReturnvaluesIF::RETURN_FAILED;
case RTEMS_TOO_MANY:
return HasReturnvaluesIF::RETURN_FAILED;
case RTEMS_INVALID_ADDRESS:
return HasReturnvaluesIF::RETURN_FAILED;
case RTEMS_UNSATISFIED:
return HasReturnvaluesIF::RETURN_FAILED;
case RTEMS_INVALID_PRIORITY:
return HasReturnvaluesIF::RETURN_FAILED;
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t TaskBase::setAndStartPeriod(rtems_interval period, rtems_id *periodId) {
rtems_name periodName = (('P' << 24) + ('e' << 16) + ('r' << 8) + 'd');
rtems_status_code status = rtems_rate_monotonic_create(periodName, periodId);
if (status == RTEMS_SUCCESSFUL) {
status = restartPeriod(period,*periodId);
}
return convertReturnCode(status);
}
rtems_status_code TaskBase::restartPeriod(rtems_interval period, rtems_id periodId){
//This is necessary to avoid a call with period = 0, which does not start the period.
rtems_status_code status = rtems_rate_monotonic_period(periodId, period + 1);
return status;
}

View File

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

View File

@ -1,41 +1,41 @@
#include "../../tasks/TaskFactory.h"
#include "MultiObjectTask.h"
#include "PollingTask.h"
#include "InitTask.h"
#include "RtemsBasic.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_) {
rtems_interval taskPeriod = periodInSeconds_ * Clock::getTicksPerSecond();
return static_cast<PeriodicTaskIF*>(new MultiObjectTask(name_,taskPriority_,stackSize_,taskPeriod,deadLineMissedFunction_));
}
FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(TaskName name_,TaskPriority taskPriority_,TaskStackSize stackSize_,TaskPeriod periodInSeconds_,TaskDeadlineMissedFunction deadLineMissedFunction_) {
rtems_interval taskPeriod = periodInSeconds_ * Clock::getTicksPerSecond();
return static_cast<FixedTimeslotTaskIF*>(new PollingTask(name_,taskPriority_,stackSize_,taskPeriod,deadLineMissedFunction_));
}
ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) {
//TODO not implemented
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t TaskFactory::delayTask(uint32_t delayMs){
rtems_task_wake_after(RtemsBasic::convertMsToTicks(delayMs));
//Only return value is "RTEMS_SUCCESSFUL - always successful" so it has been neglected
return HasReturnvaluesIF::RETURN_OK;
}
TaskFactory::TaskFactory() {
}
#include "../../tasks/TaskFactory.h"
#include "MultiObjectTask.h"
#include "PollingTask.h"
#include "InitTask.h"
#include "RtemsBasic.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_) {
rtems_interval taskPeriod = periodInSeconds_ * Clock::getTicksPerSecond();
return static_cast<PeriodicTaskIF*>(new MultiObjectTask(name_,taskPriority_,stackSize_,taskPeriod,deadLineMissedFunction_));
}
FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(TaskName name_,TaskPriority taskPriority_,TaskStackSize stackSize_,TaskPeriod periodInSeconds_,TaskDeadlineMissedFunction deadLineMissedFunction_) {
rtems_interval taskPeriod = periodInSeconds_ * Clock::getTicksPerSecond();
return static_cast<FixedTimeslotTaskIF*>(new PollingTask(name_,taskPriority_,stackSize_,taskPeriod,deadLineMissedFunction_));
}
ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) {
//TODO not implemented
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t TaskFactory::delayTask(uint32_t delayMs){
rtems_task_wake_after(RtemsBasic::convertMsToTicks(delayMs));
//Only return value is "RTEMS_SUCCESSFUL - always successful" so it has been neglected
return HasReturnvaluesIF::RETURN_OK;
}
TaskFactory::TaskFactory() {
}