Merge branch 'mueller_BinSempahInterface' into mueller_framework

This commit is contained in:
Robin Müller 2020-05-18 20:46:50 +02:00
commit 3c7e2c7cff
12 changed files with 358 additions and 144 deletions

View File

@ -1,8 +1,3 @@
/**
* @file BinarySemaphore.cpp
*
* @date 25.02.2020
*/
#include <framework/osal/FreeRTOS/BinarySemaphore.h>
#include <framework/osal/FreeRTOS/TaskManagement.h>
@ -10,9 +5,8 @@
BinarySemaphore::BinarySemaphore() {
handle = xSemaphoreCreateBinary();
if(handle == nullptr) {
sif::error << "Binary semaphore creation failure" << std::endl;
if(handle == nullptr) {
sif::error << "Semaphore: Binary semaph creation failure" << std::endl;
}
xSemaphoreGive(handle);
}
@ -132,7 +126,18 @@ void BinarySemaphore::resetSemaphore() {
xSemaphoreGive(handle);
}
}
ReturnValue_t BinarySemaphore::acquire(uint32_t timeoutMs) {
return takeBinarySemaphore(timeoutMs);
}
ReturnValue_t BinarySemaphore::release() {
return giveBinarySemaphore();
}
uint8_t BinarySemaphore::getSemaphoreCounter() {
return uxSemaphoreGetCount(handle);
}
// Be careful with the stack size here. This is called from an ISR!
ReturnValue_t BinarySemaphore::giveBinarySemaphoreFromISR(SemaphoreHandle_t semaphore,
@ -151,4 +156,4 @@ ReturnValue_t BinarySemaphore::giveBinarySemaphoreFromISR(SemaphoreHandle_t sema
} else {
return SEMAPHORE_NOT_OWNED;
}
}
}

View File

@ -1,30 +1,30 @@
/**
* @file BinarySempahore.h
*
* @date 25.02.2020
*/
#ifndef FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_
#define FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_
#include <framework/returnvalues/HasReturnvaluesIF.h>
#include <framework/returnvalues/HasReturnvaluesIF.h>
#include <framework/tasks/SemaphoreIF.h>
extern "C" {
#include "FreeRTOS.h"
#include "semphr.h"
#include <freertos/FreeRTOS.h>
#include <freertos/semphr.h>
}
// TODO: Counting semaphores and implement the new (better)
// task notifications. However, those use task notifications require
// the task handle. Maybe it would be better to make a separate class
// and switch between the classes with #ifdefs.
// Task Notifications require FreeRTOS V8.2 something..
/**
* @brief OS Tool to achieve synchronization of between tasks or between task and ISR
* @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
*
* SHOULDDO: check freeRTOS version and use new task notifications,
* if non-ancient freeRTOS version is used.
*
* @author R. Mueller
* @ingroup osal
*/
class BinarySemaphore: public HasReturnvaluesIF {
class BinarySemaphore: public SemaphoreIF,
public HasReturnvaluesIF {
public:
static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF;
@ -36,40 +36,25 @@ public:
//! Can be passed as tick type and ms value.
static constexpr TickType_t BLOCK_TIMEOUT_TICKS = portMAX_DELAY;
static constexpr uint32_t BLOCK_TIMEOUT = portMAX_DELAY;
//! Semaphore timeout
static constexpr ReturnValue_t SEMAPHORE_TIMEOUT = MAKE_RETURN_CODE(1);
/** The current semaphore can not be given, because it is not owned */
static constexpr ReturnValue_t SEMAPHORE_NOT_OWNED = MAKE_RETURN_CODE(2);
static constexpr ReturnValue_t SEMAPHORE_NULLPOINTER = MAKE_RETURN_CODE(3);
//! @brief Default ctor
BinarySemaphore();
/**
* @brief Copy ctor
*/
//! @brief Copy ctor
BinarySemaphore(const BinarySemaphore&);
/**
* @brief Copy assignment
*/
//! @brief Copy assignment
BinarySemaphore& operator=(const BinarySemaphore&);
/**
* @brief Move constructor
*/
//! @brief Move ctor
BinarySemaphore (BinarySemaphore &&);
/**
* Move assignment
*/
//! @brief Move assignment
BinarySemaphore & operator=(BinarySemaphore &&);
/**
* Delete the binary semaphore to prevent a memory leak
*/
//! @brief Destructor
virtual ~BinarySemaphore();
ReturnValue_t acquire(uint32_t timeoutMs =
BinarySemaphore::NO_BLOCK_TIMEOUT) override;
ReturnValue_t release() override;
uint8_t getSemaphoreCounter() override;
/**
* Take the binary semaphore.
* If the semaphore has already been taken, the task will be blocked
@ -127,7 +112,8 @@ public:
*/
static ReturnValue_t giveBinarySemaphoreFromISR(SemaphoreHandle_t semaphore,
BaseType_t * higherPriorityTaskWoken);
private:
protected:
SemaphoreHandle_t handle;
};

View File

@ -0,0 +1,26 @@
#include <framework/osal/FreeRTOS/CountingSemaphore.h>
#include <framework/serviceinterface/ServiceInterfaceStream.h>
CountingSemaphore::CountingSemaphore(uint8_t count, uint8_t initCount):
count(count), initCount(initCount) {
handle = xSemaphoreCreateCounting(count, initCount);
if(handle == nullptr) {
sif::error << "CountingSemaphore: Creation failure" << std::endl;
}
}
CountingSemaphore::CountingSemaphore(CountingSemaphore&& other) {
handle = xSemaphoreCreateCounting(other.count, other.initCount);
if(handle == nullptr) {
sif::error << "CountingSemaphore: Creation failure" << std::endl;
}
}
CountingSemaphore& CountingSemaphore::operator =(
CountingSemaphore&& other) {
handle = xSemaphoreCreateCounting(other.count, other.initCount);
if(handle == nullptr) {
sif::error << "CountingSemaphore: Creation failure" << std::endl;
}
return * this;
}

View File

@ -0,0 +1,29 @@
#ifndef FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_
#define FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_
#include <framework/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(uint8_t count, 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 &&);
private:
uint8_t count = 0;
uint8_t initCount = 0;
};
#endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ */

View File

@ -7,11 +7,10 @@
// As a first step towards this, introduces system context variable which needs
// to be switched manually
// Haven't found function to find system context.
MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize) :
defaultDestination(0),lastPartner(0), callContext(CallContext::task) {
MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize) {
handle = xQueueCreate(messageDepth, maxMessageSize);
if (handle == NULL) {
sif::error << "MessageQueue creation failed" << std::endl;
sif::error << "MessageQueue: Creation failed" << std::endl;
}
}
@ -50,16 +49,18 @@ ReturnValue_t MessageQueue::reply(MessageQueueMessage* message) {
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo,
MessageQueueMessage* message, MessageQueueId_t sentFrom,
bool ignoreFault) {
return sendMessageFromMessageQueue(sendTo,message,sentFrom,ignoreFault, callContext);
return sendMessageFromMessageQueue(sendTo, message, sentFrom,
ignoreFault, callContext);
}
ReturnValue_t MessageQueue::handleSendResult(BaseType_t result, bool ignoreFault) {
if (result != pdPASS) {
if (!ignoreFault) {
InternalErrorReporterIF* internalErrorReporter = objectManager->get<InternalErrorReporterIF>(
if (not ignoreFault) {
InternalErrorReporterIF* internalErrorReporter =
objectManager->get<InternalErrorReporterIF>(
objects::INTERNAL_ERROR_REPORTER);
if (internalErrorReporter != NULL) {
if (internalErrorReporter != nullptr) {
internalErrorReporter->queueMessageNotSent();
}
}
@ -78,7 +79,8 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message,
}
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message) {
BaseType_t result = xQueueReceive(handle,reinterpret_cast<void*>(message->getBuffer()), 0);
BaseType_t result = xQueueReceive(handle,reinterpret_cast<void*>(
message->getBuffer()), 0);
if (result == pdPASS){
this->lastPartner = message->getSender();
return HasReturnvaluesIF::RETURN_OK;
@ -103,6 +105,7 @@ MessageQueueId_t MessageQueue::getId() const {
}
void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) {
defaultDestinationSet = true;
this->defaultDestination = defaultDestination;
}
@ -111,7 +114,7 @@ MessageQueueId_t MessageQueue::getDefaultDestination() const {
}
bool MessageQueue::isDefaultDestinationSet() const {
return 0;
return defaultDestinationSet;
}
@ -126,9 +129,9 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
static_cast<const void*>(message->getBuffer()), 0);
}
else {
// If the call context is from an interrupt,
// request a context switch if a higher priority task
// was blocked by the interrupt.
/* If the call context is from an interrupt,
* request a context switch if a higher priority task
* was blocked by the interrupt. */
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
result = xQueueSendFromISR(reinterpret_cast<QueueHandle_t>(sendTo),
static_cast<const void*>(message->getBuffer()),

View File

@ -12,55 +12,71 @@ extern "C" {
}
//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
// 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.
* @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.
*
* @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.
*
* 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
* 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 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.
* @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 );
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.
* @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);
/**
@ -90,27 +106,28 @@ public:
ReturnValue_t reply( MessageQueueMessage* message );
/**
* \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
* @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.
* @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 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.
* @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 );
virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessage* message,
MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false );
/**
* @brief This function reads available messages from the message queue and returns the sender.
@ -147,27 +164,38 @@ public:
MessageQueueId_t getId() const;
/**
<<<<<<< HEAD
* \brief This method is a simple setter for the default destination.
=======
* @brief This method is a simple setter for the default destination.
>>>>>>> mueller_BinSempahInterface
*/
void setDefaultDestination(MessageQueueId_t defaultDestination);
/**
* \brief This method is a simple getter for the default destination.
* @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.
* \param context
* @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,
MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE,
@ -175,12 +203,13 @@ protected:
static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault);
private:
bool defaultDestinationSet = false;
QueueHandle_t handle;
MessageQueueId_t defaultDestination;
MessageQueueId_t lastPartner;
CallContext callContext; //!< Stores the current system context
MessageQueueId_t defaultDestination = 0;
MessageQueueId_t lastPartner = 0;
//!< Stores the current system context
CallContext callContext = CallContext::task;
};
#endif /* MESSAGEQUEUE_H_ */

View File

@ -1,9 +1,10 @@
#include <framework/ipc/MutexFactory.h>
#include <framework/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
//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 = NULL;
MutexFactory* MutexFactory::factoryInstance = nullptr;
MutexFactory::MutexFactory() {
}
@ -12,7 +13,7 @@ MutexFactory::~MutexFactory() {
}
MutexFactory* MutexFactory::instance() {
if (factoryInstance == NULL){
if (factoryInstance == nullptr){
factoryInstance = new MutexFactory();
}
return MutexFactory::factoryInstance;

View File

@ -0,0 +1,33 @@
#include <framework/osal/FreeRTOS/BinarySemaphore.h>
#include <framework/osal/FreeRTOS/CountingSemaphore.h>
#include <framework/tasks/SemaphoreFactory.h>
#include <framework/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() {
return new BinarySemaphore();
}
SemaphoreIF* SemaphoreFactory::createCountingSemaphore(uint8_t count,
uint8_t initCount) {
return new CountingSemaphore(count, initCount);
}
void SemaphoreFactory::deleteMutex(SemaphoreIF* semaphore) {
delete semaphore;
}

View File

@ -1,10 +1,11 @@
#include <framework/osal/FreeRTOS/TaskManagement.h>
void TaskManagement::requestContextSwitchFromTask() {
vTaskDelay(0);
}
void TaskManagement::requestContextSwitch(CallContext callContext = CallContext::task) {
void TaskManagement::requestContextSwitch(
CallContext callContext = CallContext::task) {
if(callContext == CallContext::isr) {
// This function depends on the partmacro.h definition for the specific device
requestContextSwitchFromISR();
@ -12,13 +13,11 @@ void TaskManagement::requestContextSwitch(CallContext callContext = CallContext:
requestContextSwitchFromTask();
}
}
TaskHandle_t TaskManagement::getCurrentTaskHandle() {
return xTaskGetCurrentTaskHandle();
}
configSTACK_DEPTH_TYPE TaskManagement::getTaskStackHighWatermark() {
return uxTaskGetStackHighWaterMark(TaskManagement::getCurrentTaskHandle());
}
}

View File

@ -8,7 +8,7 @@ extern "C" {
#include <freertos/task.h>
}
#include <cstdint>
/**
* Architecture dependant portmacro.h function call.
* Should be implemented in bsp.
@ -17,10 +17,10 @@ extern "C" void requestContextSwitchFromISR();
/*!
* 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.
* 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 CallContext {
task = 0x00,//!< task_context
isr = 0xFF //!< isr_context
@ -29,19 +29,19 @@ enum CallContext {
class TaskManagement {
public:
/**
* 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.
/**
* @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 requestContextSwitchFromTask(void);
*/
static void requestContextSwitchFromTask(void);
/**
* @return The current task handle
@ -56,8 +56,8 @@ public:
* 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 configSTACK_DEPTH_TYPE getTaskStackHighWatermark();
*/
static configSTACK_DEPTH_TYPE getTaskStackHighWatermark();
};
#endif /* FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ */

45
tasks/SemaphoreFactory.h Normal file
View File

@ -0,0 +1,45 @@
#ifndef FRAMEWORK_TASKS_SEMAPHOREFACTORY_H_
#define FRAMEWORK_TASKS_SEMAPHOREFACTORY_H_
#include <framework/tasks/SemaphoreIF.h>
/**
* Creates Semaphore.
* This class is a "singleton" interface, i.e. it provides an
* interface, but also is the base class for a singleton.
*/
class SemaphoreFactory {
public:
virtual ~SemaphoreFactory();
/**
* Returns the single instance of SemaphoreFactory.
* The implementation of #instance is found in its subclasses.
* Thus, we choose link-time variability of the instance.
*/
static SemaphoreFactory* instance();
/**
* Create a binary semaphore.
* Creator function for a binary semaphore which may only be acquired once
* @return Pointer to newly created semaphore class instance.
*/
SemaphoreIF* createBinarySemaphore();
/**
* Create a counting semaphore.
* Creator functons for a counting semaphore which may be acquired multiple
* times.
* @param count Semaphore can be taken count times.
* @param initCount Initial count value.
* @return
*/
SemaphoreIF* createCountingSemaphore(uint8_t count, uint8_t initCount);
void deleteMutex(SemaphoreIF* mutex);
private:
/**
* External instantiation is not allowed.
*/
SemaphoreFactory();
static SemaphoreFactory* factoryInstance;
};
#endif /* FRAMEWORK_TASKS_SEMAPHOREFACTORY_H_ */

58
tasks/SemaphoreIF.h Normal file
View File

@ -0,0 +1,58 @@
#ifndef FRAMEWORK_TASKS_SEMAPHOREIF_H_
#define FRAMEWORK_TASKS_SEMAPHOREIF_H_
#include <framework/returnvalues/FwClassIds.h>
#include <framework/returnvalues/HasReturnvaluesIF.h>
#include <cstdint>
/**
* @brief Generic interface for semaphores, which can be used to achieve
* task synchronization. This is a generic interface which can be
* used for both binary semaphores and counting semaphores.
* @details
* A semaphore is a synchronization primitive.
* See: https://en.wikipedia.org/wiki/Semaphore_(programming)
* A semaphore can be used to achieve task synchonization and track the
* availability of resources.
*
* If mutual exlcusion of a resource is desired, a mutex should be used,
* which is a special form of a semaphore and has an own interface.
*/
class SemaphoreIF {
public:
virtual~ SemaphoreIF() {};
//!< Needs to be defined in implementation.
static const uint32_t NO_TIMEOUT;
static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF;
//! Semaphore timeout
static constexpr ReturnValue_t SEMAPHORE_TIMEOUT = MAKE_RETURN_CODE(1);
//! The current semaphore can not be given, because it is not owned
static constexpr ReturnValue_t SEMAPHORE_NOT_OWNED = MAKE_RETURN_CODE(2);
static constexpr ReturnValue_t SEMAPHORE_NULLPOINTER = MAKE_RETURN_CODE(3);
/**
* Generic call to acquire a semaphore.
* If there are no more semaphores to be taken (for a counting semaphore,
* a semaphore may be taken more than once), the taks will block
* for a maximum of timeoutMs while trying to acquire the semaphore.
* This can be used to achieve task synchrnization.
* @param timeoutMs
* @return - c RETURN_OK for successfull acquisition
*/
virtual ReturnValue_t acquire(uint32_t timeoutMs) = 0;
/**
* Corrensponding call to release a semaphore.
* @return -@c RETURN_OK for successfull release
*/
virtual ReturnValue_t release() = 0;
/**
* If the semaphore is a counting semaphore then the semaphores current
* count value is returned. If the semaphore is a binary semaphore then 1
* is returned if the semaphore is available, and 0 is returned if the
* semaphore is not available.
*/
virtual uint8_t getSemaphoreCounter() = 0;
};
#endif /* FRAMEWORK_TASKS_SEMAPHOREIF_H_ */