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/BinarySemaphore.h>
#include <framework/osal/FreeRTOS/TaskManagement.h> #include <framework/osal/FreeRTOS/TaskManagement.h>
@ -11,8 +6,7 @@
BinarySemaphore::BinarySemaphore() { BinarySemaphore::BinarySemaphore() {
handle = xSemaphoreCreateBinary(); handle = xSemaphoreCreateBinary();
if(handle == nullptr) { if(handle == nullptr) {
sif::error << "Semaphore: Binary semaph creation failure" << std::endl;
sif::error << "Binary semaphore creation failure" << std::endl;
} }
xSemaphoreGive(handle); xSemaphoreGive(handle);
} }
@ -133,6 +127,17 @@ void BinarySemaphore::resetSemaphore() {
} }
} }
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! // Be careful with the stack size here. This is called from an ISR!
ReturnValue_t BinarySemaphore::giveBinarySemaphoreFromISR(SemaphoreHandle_t semaphore, ReturnValue_t BinarySemaphore::giveBinarySemaphoreFromISR(SemaphoreHandle_t semaphore,

View File

@ -1,30 +1,30 @@
/**
* @file BinarySempahore.h
*
* @date 25.02.2020
*/
#ifndef FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ #ifndef FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_
#define 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" { extern "C" {
#include "FreeRTOS.h" #include <freertos/FreeRTOS.h>
#include "semphr.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 * @details
* Documentation: https://www.freertos.org/Embedded-RTOS-Binary-Semaphores.html * Documentation: https://www.freertos.org/Embedded-RTOS-Binary-Semaphores.html
* *
* SHOULDDO: check freeRTOS version and use new task notifications, * @author R. Mueller
* if non-ancient freeRTOS version is used.
*
* @ingroup osal * @ingroup osal
*/ */
class BinarySemaphore: public HasReturnvaluesIF { class BinarySemaphore: public SemaphoreIF,
public HasReturnvaluesIF {
public: public:
static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF;
@ -37,39 +37,24 @@ public:
static constexpr TickType_t BLOCK_TIMEOUT_TICKS = portMAX_DELAY; static constexpr TickType_t BLOCK_TIMEOUT_TICKS = portMAX_DELAY;
static constexpr uint32_t BLOCK_TIMEOUT = portMAX_DELAY; static constexpr uint32_t BLOCK_TIMEOUT = portMAX_DELAY;
//! Semaphore timeout //! @brief Default ctor
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);
BinarySemaphore(); BinarySemaphore();
//! @brief Copy ctor
/**
* @brief Copy ctor
*/
BinarySemaphore(const BinarySemaphore&); BinarySemaphore(const BinarySemaphore&);
//! @brief Copy assignment
/**
* @brief Copy assignment
*/
BinarySemaphore& operator=(const BinarySemaphore&); BinarySemaphore& operator=(const BinarySemaphore&);
//! @brief Move ctor
/**
* @brief Move constructor
*/
BinarySemaphore (BinarySemaphore &&); BinarySemaphore (BinarySemaphore &&);
//! @brief Move assignment
/**
* Move assignment
*/
BinarySemaphore & operator=(BinarySemaphore &&); BinarySemaphore & operator=(BinarySemaphore &&);
//! @brief Destructor
/**
* Delete the binary semaphore to prevent a memory leak
*/
virtual ~BinarySemaphore(); 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. * Take the binary semaphore.
* If the semaphore has already been taken, the task will be blocked * If the semaphore has already been taken, the task will be blocked
@ -127,7 +112,8 @@ public:
*/ */
static ReturnValue_t giveBinarySemaphoreFromISR(SemaphoreHandle_t semaphore, static ReturnValue_t giveBinarySemaphoreFromISR(SemaphoreHandle_t semaphore,
BaseType_t * higherPriorityTaskWoken); BaseType_t * higherPriorityTaskWoken);
private:
protected:
SemaphoreHandle_t handle; 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 // As a first step towards this, introduces system context variable which needs
// to be switched manually // to be switched manually
// Haven't found function to find system context. // Haven't found function to find system context.
MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize) : MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize) {
defaultDestination(0),lastPartner(0), callContext(CallContext::task) {
handle = xQueueCreate(messageDepth, maxMessageSize); handle = xQueueCreate(messageDepth, maxMessageSize);
if (handle == NULL) { 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, ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo,
MessageQueueMessage* message, MessageQueueId_t sentFrom, MessageQueueMessage* message, MessageQueueId_t sentFrom,
bool ignoreFault) { 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) { ReturnValue_t MessageQueue::handleSendResult(BaseType_t result, bool ignoreFault) {
if (result != pdPASS) { if (result != pdPASS) {
if (!ignoreFault) { if (not ignoreFault) {
InternalErrorReporterIF* internalErrorReporter = objectManager->get<InternalErrorReporterIF>( InternalErrorReporterIF* internalErrorReporter =
objectManager->get<InternalErrorReporterIF>(
objects::INTERNAL_ERROR_REPORTER); objects::INTERNAL_ERROR_REPORTER);
if (internalErrorReporter != NULL) { if (internalErrorReporter != nullptr) {
internalErrorReporter->queueMessageNotSent(); internalErrorReporter->queueMessageNotSent();
} }
} }
@ -78,7 +79,8 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message,
} }
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){ if (result == pdPASS){
this->lastPartner = message->getSender(); this->lastPartner = message->getSender();
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
@ -103,6 +105,7 @@ MessageQueueId_t MessageQueue::getId() const {
} }
void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) { void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) {
defaultDestinationSet = true;
this->defaultDestination = defaultDestination; this->defaultDestination = defaultDestination;
} }
@ -111,7 +114,7 @@ MessageQueueId_t MessageQueue::getDefaultDestination() const {
} }
bool MessageQueue::isDefaultDestinationSet() 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); static_cast<const void*>(message->getBuffer()), 0);
} }
else { else {
// If the call context is from an interrupt, /* If the call context is from an interrupt,
// request a context switch if a higher priority task * request a context switch if a higher priority task
// was blocked by the interrupt. * was blocked by the interrupt. */
BaseType_t xHigherPriorityTaskWoken = pdFALSE; BaseType_t xHigherPriorityTaskWoken = pdFALSE;
result = xQueueSendFromISR(reinterpret_cast<QueueHandle_t>(sendTo), result = xQueueSendFromISR(reinterpret_cast<QueueHandle_t>(sendTo),
static_cast<const void*>(message->getBuffer()), static_cast<const void*>(message->getBuffer()),

View File

@ -12,28 +12,30 @@ extern "C" {
} }
// TODO: this class assumes that MessageQueueId_t is the same size as void*
//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 // (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/ // 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. * @details
* Message queues are used to pass asynchronous messages between processes.
* They work like post boxes, where all incoming messages are stored in FIFO * 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 * order. This class creates a new receiving queue and provides methods to fetch
* received messages. Being a child of MessageQueueSender, this class also provides * received messages. Being a child of MessageQueueSender, this class also
* methods to send a message to a user-defined or a default destination. In addition * provides methods to send a message to a user-defined or a default destination.
* it also provides a reply method to answer to the queue it received its last message * In addition it also provides a reply method to answer to the queue it
* from. * received its last message from.
* *
* The MessageQueue should be used as "post box" for a single owning object. So all * The MessageQueue should be used as "post box" for a single owning object.
* message queue communication is "n-to-one". * So all message queue communication is "n-to-one".
* For creating the queue, as well as sending and receiving messages, the class makes * For creating the queue, as well as sending and receiving messages, the class
* use of the operating system calls provided. * makes use of the operating system calls provided.
* *
* Please keep in mind that FreeRTOS offers * Please keep in mind that FreeRTOS offers different calls for message queue
* different calls for message queue operations if called from an ISR. * operations if called from an ISR.
* For now, the system context needs to be switched manually. * For now, the system context needs to be switched manually.
* @ingroup osal * @ingroup osal
* @ingroup message_queue * @ingroup message_queue
@ -43,24 +45,38 @@ class MessageQueue : public MessageQueueIF {
public: public:
/** /**
* @brief The constructor initializes and configures the message queue. * @brief The constructor initializes and configures the message queue.
* @details By making use of the according operating system call, a message queue is created * @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 * 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 * 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 * 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. * 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 * @param message_depth
* The number of messages to be buffered before passing an error to the
* sender. Default is three. * sender. Default is three.
* @param max_message_size With this parameter, the maximum message size can be adjusted. * @param max_message_size
* With this parameter, the maximum message size can be adjusted.
* This should be left default. * 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. * @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(); 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); void switchSystemContext(CallContext callContext);
/** /**
@ -90,27 +106,28 @@ public:
ReturnValue_t reply( MessageQueueMessage* message ); ReturnValue_t reply( MessageQueueMessage* message );
/** /**
* \brief With the sendMessage call, a queue message is sent to a receiving queue. * @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 * @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 * it on to the destination provided with an operating system call. The OS's return
* value is returned. * value is returned.
* \param sendTo This parameter specifies the message queue id to send the message to. * @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 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 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. * 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, virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, MessageQueueMessage* message,
MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false );
/** /**
* \brief The sendToDefault method sends a queue message to the default destination. * @brief The sendToDefault method sends a queue message to the default destination.
* \details In all other aspects, it works identical to the sendMessage method. * @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 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 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. * 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. * @brief This function reads available messages from the message queue and returns the sender.
@ -147,27 +164,38 @@ public:
MessageQueueId_t getId() const; 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.
=======
* @brief This method is a simple setter for the default destination.
>>>>>>> mueller_BinSempahInterface
*/ */
void setDefaultDestination(MessageQueueId_t defaultDestination); 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; MessageQueueId_t getDefaultDestination() const;
bool isDefaultDestinationSet() const; bool isDefaultDestinationSet() const;
protected: protected:
/** /**
* Implementation to be called from any send Call within MessageQueue and MessageQueueSenderIF * @brief Implementation to be called from any send Call within
* \details This method takes the message provided, adds the sentFrom information and passes * MessageQueue and MessageQueueSenderIF.
* it on to the destination provided with an operating system call. The OS's return * @details
* value is returned. * This method takes the message provided, adds the sentFrom information and
* \param sendTo This parameter specifies the message queue id to send the message to. * passes it on to the destination provided with an operating system call.
* \param message This is a pointer to a previously created message, which is sent. * The OS's return value is returned.
* \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. * @param sendTo
* This variable is set to zero by default. * This parameter specifies the message queue id to send the message to.
* \param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. * @param message
* \param context * 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, static ReturnValue_t sendMessageFromMessageQueue(MessageQueueId_t sendTo,
MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE,
@ -175,12 +203,13 @@ protected:
static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault); static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault);
private: private:
bool defaultDestinationSet = false;
QueueHandle_t handle; QueueHandle_t handle;
MessageQueueId_t defaultDestination; MessageQueueId_t defaultDestination = 0;
MessageQueueId_t lastPartner; MessageQueueId_t lastPartner = 0;
CallContext callContext; //!< Stores the current system context //!< Stores the current system context
CallContext callContext = CallContext::task;
}; };
#endif /* MESSAGEQUEUE_H_ */ #endif /* MESSAGEQUEUE_H_ */

View File

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

@ -4,7 +4,8 @@ void TaskManagement::requestContextSwitchFromTask() {
vTaskDelay(0); vTaskDelay(0);
} }
void TaskManagement::requestContextSwitch(CallContext callContext = CallContext::task) { void TaskManagement::requestContextSwitch(
CallContext callContext = CallContext::task) {
if(callContext == CallContext::isr) { if(callContext == CallContext::isr) {
// This function depends on the partmacro.h definition for the specific device // This function depends on the partmacro.h definition for the specific device
requestContextSwitchFromISR(); requestContextSwitchFromISR();
@ -20,5 +21,3 @@ TaskHandle_t TaskManagement::getCurrentTaskHandle() {
configSTACK_DEPTH_TYPE TaskManagement::getTaskStackHighWatermark() { configSTACK_DEPTH_TYPE TaskManagement::getTaskStackHighWatermark() {
return uxTaskGetStackHighWaterMark(TaskManagement::getCurrentTaskHandle()); return uxTaskGetStackHighWaterMark(TaskManagement::getCurrentTaskHandle());
} }

View File

@ -18,9 +18,9 @@ extern "C" void requestContextSwitchFromISR();
/*! /*!
* Used by functions to tell if they are being called from * Used by functions to tell if they are being called from
* within an ISR or from a regular task. This is required because FreeRTOS * 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. * has different functions for handling semaphores and messages from within
* an ISR and task.
*/ */
enum CallContext { enum CallContext {
task = 0x00,//!< task_context task = 0x00,//!< task_context
isr = 0xFF //!< isr_context isr = 0xFF //!< isr_context
@ -30,10 +30,10 @@ enum CallContext {
class TaskManagement { class TaskManagement {
public: public:
/** /**
* In this function, a function dependant on the portmacro.h header function calls * @brief In this function, a function dependant on the portmacro.h header
* to request a context switch can be specified. * 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 * This can be used if sending to the queue from an ISR caused a task
* and a context switch is required. * to unblock and a context switch is required.
*/ */
static void requestContextSwitch(CallContext callContext); static void requestContextSwitch(CallContext callContext);

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