1
0

Initial commit

This commit is contained in:
2023-11-28 14:19:36 +01:00
commit 2b9655cdce
262 changed files with 151100 additions and 0 deletions

10
src/xf/config/xf-config.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef XF_CONFIG_DEFAULT_H
#define XF_CONFIG_DEFAULT_H
#warning "You should provide your own 'xf-config.h' file in your project!"
// If you need some inspiration on what to provide in the 'xf-config.h' file
// please have a look onto the 'xf-config.h' files provided in the
// XF test-bench tests.
#endif // XF_CONFIG_DEFAULT_H

104
src/xf/core/behavior.cpp Normal file
View File

@ -0,0 +1,104 @@
#include <cassert>
#include "xf/xf.h"
#include "xf/interface/resourcefactory.h"
#include "xf/interface/dispatcher.h"
#include "xf/timeout.h"
#include "xf/initialevent.h"
#include "xf/behavior.h"
using interface::XFResourceFactory;
XFBehavior::XFBehavior(bool ownDispatcher /* = false */) :
pDispatcher_(nullptr),
hasOwnDispatcher_(ownDispatcher),
deleteOnTerminate_(false),
pCurrentEvent_(nullptr)
{
if (ownDispatcher)
{
pDispatcher_ = XFResourceFactory::getInstance()->createDispatcher();
}
else
{
pDispatcher_ = XFResourceFactory::getInstance()->getDefaultDispatcher();
}
// Force hasOwnDispatcher attribute to false in case actual
// dispatcher is the default dispatcher. This may happen
// if in an IDF an other dispatcher is requested, but
// only the default dispatcher is present.
if (pDispatcher_ == XFResourceFactory::getInstance()->getDefaultDispatcher())
{
hasOwnDispatcher_ = false;
}
}
XFBehavior::~XFBehavior()
{
}
void XFBehavior::startBehavior()
{
// Send initial event to state machine
GEN(XFInitialEvent());
// Start dispatcher if behavior has its own dispatcher
if (hasOwnDispatcher())
{
getDispatcher()->start();
}
}
void XFBehavior::pushEvent(XFEvent * pEvent, bool fromISR)
{
// Set owner
pEvent->setBehavior(this);
// Push to dispatchers event queue
getDispatcher()->pushEvent(pEvent, fromISR);
}
bool XFBehavior::deleteOnTerminate() const
{
return deleteOnTerminate_;
}
void XFBehavior::setDeleteOnTerminate(bool deleteBehaviour)
{
deleteOnTerminate_ = deleteBehaviour;
}
XFBehavior::TerminateBehavior XFBehavior::process(const XFEvent * pEvent)
{
XFEventStatus eventStatus;
setCurrentEvent(pEvent);
eventStatus = processEvent();
setCurrentEvent(nullptr);
return (eventStatus == XFEventStatus::Terminate);
}
interface::XFDispatcher * XFBehavior::getDispatcher()
{
return pDispatcher_;
}
void XFBehavior::setCurrentEvent(const XFEvent * pEvent)
{
pCurrentEvent_ = pEvent;
}
const XFEvent * XFBehavior::getCurrentEvent() const
{
return pCurrentEvent_;
}
const XFTimeout * XFBehavior::getCurrentTimeout()
{
assert(getCurrentEvent()->getEventType() == XFEvent::Timeout);
return static_cast<const XFTimeout *>(getCurrentEvent());
}

View File

@ -0,0 +1,8 @@
#include "xf/customevent.h"
XFCustomEvent::XFCustomEvent(int id, interface::XFReactive * pBehavior)
: XFEvent(XFEvent::Event, id, pBehavior),
bDeleteAfterConsume_(true)
{
}

View File

@ -0,0 +1,11 @@
#include "xf/initialevent.h"
XFInitialEvent::XFInitialEvent()
: XFEvent(XFEvent::Initial, 0, nullptr)
{
}
bool XFInitialEvent::deleteAfterConsume() const
{
return true;
}

View File

@ -0,0 +1,11 @@
#include "xf/nulltransition.h"
XFNullTransition::XFNullTransition(interface::XFReactive * pBehavior)
: XFEvent(XFEvent::NullTransition, 0, pBehavior)
{
}
bool XFNullTransition::deleteAfterConsume() const
{
return true;
}

19
src/xf/core/timeout.cpp Normal file
View File

@ -0,0 +1,19 @@
#include "xf/timeout.h"
XFTimeout::XFTimeout(int id, int interval, interface::XFReactive * pBehavior)
: XFEvent(XFEvent::Timeout, id, pBehavior),
interval_(interval),
relTicks_(interval)
{
}
bool XFTimeout::operator ==(const XFTimeout & timeout) const
{
// Check behavior and timeout id attributes, if there are equal
return (pBehavior_ == timeout.pBehavior_ && getId() == timeout.getId()) ? true : false;
}
bool XFTimeout::deleteAfterConsume() const
{
return true;
}

2515
src/xf/doxygen/Doxyfile Normal file

File diff suppressed because it is too large Load Diff

1556
src/xf/doxygen/xf.tag Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,101 @@
#ifndef XF_BEHAVIOR_H
#define XF_BEHAVIOR_H
#include "xf/interface/reactive.h"
#include "xf/interface/dispatcher.h"
#include "xf/eventstatus.h"
#include "xf/initialevent.h"
#include "xf/nulltransition.h"
#include "xf/timeout.h"
class XFTimeout;
/** @ingroup xf_core
* @{
*/
/**
* @brief Base class for state machines, activities, process and data flows.
*
* Reactive class implementing a behavior. This class can be used to
* implement a state machine behavior or an activity behavior.
*
* Override the processEvent() operation in the inherited class to implement
* your state machine behavior. The processEvent() method gets automatically
* called every time an event or timeout arrives. The event (or timeout) can
* be accessed via the getCurrentEvent() method.
*/
class XFBehavior : public interface::XFReactive
{
public:
#define GEN(event) pushEvent(new event)
/**
* @brief Default constructor for the behavior.
*
* Per default the XFBehavior chooses the 'default dispatcher' for event processing. In
* case the ownDispatcher parameter is set to true, the XFBehavior creates internally
* a separate dispatcher.
*
* @param ownDispatcher Set to true to get dedicated dispatcher for this behavior.
*/
explicit XFBehavior(bool ownDispatcher = false);
~XFBehavior() override;
void startBehavior() override; ///< Starts the behavior, resp. the state machine.
void pushEvent(XFEvent * pEvent, bool fromISR=false) override;
bool deleteOnTerminate() const override;
void setDeleteOnTerminate(bool deleteBehaviour) override;
protected:
/**
* Executes the current event in its implemented behavior.
* This method needs to be overridden to implement the
* behavior (i.e. state machine) needed.
*/
virtual XFEventStatus processEvent() = 0;
const XFEvent * getCurrentEvent() const; ///< Returns the current event to be processed in processEvent().
interface::XFDispatcher * getDispatcher(); ///< Returns reference to #_pDispatcher.
inline bool hasOwnDispatcher() const { return hasOwnDispatcher_; } ///< True if behavior has its own dispatcher.
/** \brief Returns a reference to the actually processed timeout.
*
* Will work only if the current event is of type IXFEvent::Timeout.
*/
const XFTimeout * getCurrentTimeout();
inline void scheduleTimeout(int timeoutId, int interval) { getDispatcher()->scheduleTimeout(timeoutId, interval, this); } ///< @brief Schedules a timeout for this state machine.
inline void unscheduleTimeout(int timeoutId) { getDispatcher()->unscheduleTimeout(timeoutId, this); } ///< @brief Unschedules a timeout for this state machine.
private:
void setCurrentEvent(const XFEvent * pEvent); ///< Sets the current event to be processed in processEvent().
/**
* \brief Processes the given event.
*
* The dispatcher calls this method every time a new event
* or timeout arrives. The process method stores the actual
* event using the #_pCurrentEvent and then calls
* processEvent().
*
* In case you intend to call process() inside your state machine you
* are doing something wrong! Call GEN() or pushEvent() instead!
*
* \param pEvent The event to process.
*/
TerminateBehavior process(const XFEvent * pEvent) override;
protected:
interface::XFDispatcher * pDispatcher_; ///< Reference to dispatcher processing this behavior.
bool hasOwnDispatcher_; ///< True if behavior has its own dispatcher, False if the default dispatcher is used.
bool deleteOnTerminate_; ///< Indicates if the behavior can be deleted after reception of a 'terminate event'.
const XFEvent * pCurrentEvent_; ///< Reference to actually processed event.
};
/** @} */ // end of xf_core group
#endif // XF_BEHAVIOR_H

View File

@ -0,0 +1,51 @@
#ifndef XF_CUSTOMEVENT_H
#define XF_CUSTOMEVENT_H
#include "xf/xf.h"
#include "xf/event.h"
/** @ingroup xf_core
* @{
*/
/**
* @brief Base class for project related events.
*
* It is possible to create custom events by deriving new classes/events from
* this class.
* All custom events have `#Event` as event type. In the state machine the event
* can be uniquely identified with `getEventType() == Event` and the event id
* `getId()` given to the object at construction time.
*
* It is up to the devoper to handle the different event ids.
*/
class XFCustomEvent : public XFEvent
{
public:
/**
* Constructor for the class
*
* @param id Event identifier to identify the custom event (in the context of the behavior).
* @param pBehavior The behavior for which the event was constructed (will consume the event).
**/
XFCustomEvent(int id, interface::XFReactive * pBehavior = nullptr);
/**
* @brief Tells the XF if the event should be deleted after processing.
* @return True if the event should be deleted.
*/
bool deleteAfterConsume() const override { return bDeleteAfterConsume_; }
protected:
/**
* @brief Setter for #_bDeleteAfterConsume attribute.
* @param bDeleteAfterConsume Parameter to be assigned. Default: true.
*/
void setDeleteAfterConsume(bool bDeleteAfterConsume = true) { bDeleteAfterConsume_ = bDeleteAfterConsume; }
protected:
bool bDeleteAfterConsume_; ///< True if the XF should delete event after consumption/dispatching.
};
/** @} */ // end of xf_core group
#endif // XF_CUSTOMEVENT_H

74
src/xf/include/xf/event.h Normal file
View File

@ -0,0 +1,74 @@
#ifndef XF_EVENT_H
#define XF_EVENT_H
namespace interface {
class XFReactive;
}
/** @ingroup xf_core
* @{
*/
/**
* @brief Base class for all types of events and timeouts.
*
* Requirements:
* - Needs to hold a property which allows to distinguish between different
* types of events (#_eventType).
* - Use an enumeration to define the type for the event type property (#XFEventType).
* - The event type property needs to be set at initialization time and cannot be
* changed afterwards.
*/
class XFEvent
{
public:
/**
* Defines the types of events
*/
typedef enum
{
Unknown = 0, ///< Unknown state (not initialized).
Initial = 1, ///< Initial pseudostate.
NullTransition = 2, ///< Event generated by the state machine to define a null transition.
Event = 3, ///< Custom event.
Timeout = 4, ///< Defines a timeout event.
Terminate = -1 ///< Defines a terminate state. Will end the state machine.
} XFEventType;
public :
/**
* Default class constructor
*/
XFEvent(XFEventType eventType, int id, interface::XFReactive * pBehavior) : eventType_(eventType), id_(id), pBehavior_(pBehavior) {}
virtual ~XFEvent() {} ///< Class destructor
/** \brief Returns the type of the event.
*
* Can be used to distinguish between an event or a timeout.
*/
inline XFEventType getEventType() const { return eventType_; }
/** \brief Returns pointer to behavioral class.
*
* Returns a pointer to the behavioral class processing the event (see #_pBehavior).
*/
inline interface::XFReactive * getBehavior() const { return pBehavior_; }
/** \brief Sets pointer to behavioral class (see #_pBehavior).
* Sets the behavior in which the event should be executed.
*/
inline void setBehavior(interface::XFReactive * pBehavior) { pBehavior_ = pBehavior; }
inline int getId() const { return id_; } ///< Returns #_id identifying the event in the behaviors context.
virtual bool deleteAfterConsume() const { return false; } ///< Tells the dispatcher if the event must be deleted or not.
protected:
const XFEventType eventType_; ///< Holds the type of the event.
int id_; ///< Event id
interface::XFReactive * pBehavior_; ///< Pointer to behavioral class processing the event.
};
/** @} */ // end of xf_core group
#endif // XF_EVENT_H

View File

@ -0,0 +1,75 @@
#ifndef XF_EVENTSTATUS_H
#define XF_EVENTSTATUS_H
/** @ingroup xf_core
* @{
*/
/**
* @brief Event status returned after event processing.
*
* The XFEventStatus is used after consumption of an event. It gives an
* information on how the event was consument and how the framework should
* react.
*/
class XFEventStatus
{
public:
/**
* Status values about the event processed.
*
* \see XFBehavior::process
*/
typedef enum
{
Unknown = 0,
Consumed = 0x0001, ///< Event consumed
NotConsumed = 0x0002, ///< Event not consumed
RegionFinished = 0x0004, ///< Composite state machine finished
Terminate = 0x0008 ///< Terminate state machine
} eEventStatus;
/**
* Constructor
*
* \param eventStatus Initial value of the event status.
*/
XFEventStatus(eEventStatus eventStatus = Unknown) : status_(eventStatus) {}
/**
* Checks if both variables contain the same event status.
*/
bool operator == (const XFEventStatus::eEventStatus & eventStatus) const
{
return (this->status_ == eventStatus);
}
/**
* @brief OR assignment.
*
* OR's the right event status with the left event status.
*/
void operator |= (const XFEventStatus & eventStatus)
{
unsigned int s1 = status_, s2 = eventStatus.status_;
s1 |= s2;
status_ = (eEventStatus)s1;
}
/**
* @brief Checks if the given event status (r-value) is present in the actual (l-value).
*/
bool is(const eEventStatus eventStatus) const
{
unsigned int mask = (unsigned int)eventStatus;
return ((((unsigned int)status_) & mask) == mask);
}
public:
eEventStatus status_; ///< Attribute containing the status of the event.
};
typedef XFEventStatus::eEventStatus eEventStatus;
/** @} */ // end of xf_core group
#endif // XF_EVENTSTATUS_H

View File

@ -0,0 +1,25 @@
#ifndef INITIALEVENT_H
#define INITIALEVENT_H
#include "xf/event.h"
/** @ingroup xf_core
* @{
*/
/**
* @brief Initial event to start a behavior.
*
* Represents for example the first transition executed
* in a state machine.
*/
class XFInitialEvent : public XFEvent
{
public:
XFInitialEvent();
bool deleteAfterConsume() const override;
};
/** @} */ // end of xf_core group
#endif // INITIALEVENT_H

View File

@ -0,0 +1,98 @@
#ifndef XF_INTERFACE_DISPATCHER_H
#define XF_INTERFACE_DISPATCHER_H
#include "xf/event.h"
class XF;
namespace interface {
class XFReactive;
class XFThread;
/**
* @brief Interface for the XF dispatcher providing the event processing loop.
*
* Depending on the implementation the dispatcher is executed by
* an internal thread. It is up to the port implementation how
* the class behaves.
*
* The dispatcher should at least provide a queue to hold events
* and an algorithm (typically in execute()) that dispatches the queued
* events to the associated behavior (eq. state machine, activity).
*
* There may exist multiple dispatchers. Each behavior needs to be
* bound to a dispatcher. One dispatcher may serve different behaviors.
*
* In an IDF the attribute _pThread is usually null.
*/
class XFDispatcher
{
friend class ::XF;
public:
virtual ~XFDispatcher() = default;
virtual bool isActive() const = 0; ///< True if dispatcher has its own thread.
virtual void start() = 0; ///< Starts the thread.
virtual void stop() = 0; ///< Stops the thread.
virtual void pushEvent(XFEvent * pEvent, bool fromISR=false) = 0; ///< Adds event to the events queue.
/**
* @brief Adds a new timeout to be handled.
*
* The Thread will forward the timeout information to the timeout
* manager which is responsible to handle all timeouts.
*/
virtual void scheduleTimeout(int timeoutId, int interval, interface::XFReactive * pReactive) = 0;
/**
* @brief Removes all timeouts corresponding the given parameters.
*/
virtual void unscheduleTimeout(int timeoutId, interface::XFReactive * pReactive) = 0;
protected:
/**
* Constructor is protected because only method createInstance()
* should be called to create Dispatcher instances
*/
XFDispatcher() = default;
/**
* @brief Returns pointer to thread executing the behavior.
*
* Within an IDF no threads are present and this method returns
* always null.
*/
virtual interface::XFThread * getThread() const { return nullptr; }
/**
* @brief Main loop of the dispatcher. Implements event loop processing.
*/
virtual int execute(const void * param = nullptr) = 0;
/**
* @brief Executes once the dispatcher.
*
* Usually, this method must not be called explicitly. The
* standard way to call the dispatcher is to call execute().
*
* This method can be called by the Thread (or main function) if it
* must perform concurrent (non-XF related) tasks in addition.
*
* When using this method start() must not be called.
*/
virtual int executeOnce() = 0;
/**
* @brief Dispatches the event to the corresponding behavioral part.
*
* For example the state machine which should process the event.
*
* \param pEvent The event to dispatch
*/
virtual void dispatchEvent(const XFEvent * pEvent) const = 0;
};
} // namespace interface
#endif // XF_INTERFACE_DISPATCHER_H

View File

@ -0,0 +1,27 @@
#ifndef XF_INTERFACE_EVENT_QUEUE_H
#define XF_INTERFACE_EVENT_QUEUE_H
class XFEvent;
namespace interface {
/**
* @brief Interface to be implemented by the event queue
*/
class XFEventQueue
{
public:
virtual ~XFEventQueue() = default;
virtual bool empty() const = 0; ///< Returns true if no event is in the queue.
virtual bool push(const XFEvent * pEvent, bool fromISR = false) = 0; ///< Pushes the given event onto the queue.
virtual const XFEvent * front() = 0; ///< Returns pointer to next event to pop.
virtual void pop() = 0; ///< Pops the next event from the queue.
virtual bool pend() = 0; ///< Wait for the next event to arrive. Returns true if an event is in the queue.
public:
XFEventQueue() = default;
};
} // namespace interface
#endif // XF_INTERFACE_EVENT_QUEUE_H

View File

@ -0,0 +1,56 @@
#ifndef XF_INTERFACE_MUTEX_H
#define XF_INTERFACE_MUTEX_H
#include <stdint.h>
namespace interface {
/**
* @brief Mutex interface needed by the XF to access a mutex.
*
* This interface only needs to be implemented for an XF port using
* an underlying OS. An IDF based XF does not need to provide a
* mutex.
*
* A non-recursive mutex needs to be implemented.
*/
class XFMutex
{
public:
virtual ~XFMutex() = default;
virtual void lock() = 0; ///< Blocks until the mutex becomes available.
virtual void unlock() = 0; ///< Releases the mutex so it can be taken by other threads.
/**
* @brief Tries to get the mutex.
*
* If timeout is 0 method will leave immediately and then the return parameter indicates it the
* mutex could be taken or not. Giving a negative value will block the thread until the mutex
* becomes available.
*/
virtual bool tryLock(int32_t timeout = 0) = 0;
/**
* @brief Creates and returns a new mutex instance.
* @return Pointer to the created mutex object.
*
* The implementation of this method needs to be provided by
* every XF port realizing a Mutex with this XFMutex interface.
* Best way is to implement this method in the mutex.cpp
* (or mutex-default.cpp) file of the XF port.
*
* Attention:
* Do not forget to create an object of the class realizing
* the interface and then return this object.
*
* You cannot instanciate an object of an abstract class!
*/
static XFMutex * create();
protected:
XFMutex() = default;
};
} // namespace interface
#endif // XF_INTERFACE_MUTEX_H

View File

@ -0,0 +1,53 @@
#ifndef XF_INTERFACE_REACTIVE_H
#define XF_INTERFACE_REACTIVE_H
#include <string>
#include "xf/event.h"
#include "xf/eventstatus.h"
class XFDispatcherDefault;
class XFDispatcherActiveDefault;
class XFDispatcherPort;
class XFDispatcherActivePort;
class XFDispatcher;
namespace interface {
/**
* @brief Interface to receive and process events.
*
* Interface that needs to be implemented by every class having a
* behavior. Interface methods are needed by the other parts of the XF.
*
* This interface is used by the dispatcher to process events.
*/
class XFReactive
{
// Only XFDispatchers should get access to the 'process' method
friend class ::XFDispatcherDefault;
friend class ::XFDispatcherActiveDefault;
friend class ::XFDispatcherPort;
friend class ::XFDispatcherActivePort;
friend class ::XFDispatcher;
public:
using TerminateBehavior = bool;
public:
virtual ~XFReactive() = default;
virtual void startBehavior() = 0; ///< Starts the behavior.
virtual void pushEvent(XFEvent * pEvent, bool fromISR = false) = 0; ///< Injects an event into the class.
virtual bool deleteOnTerminate() const = 0; ///< Tells XF to delete behavior when receiving terminate event.
virtual void setDeleteOnTerminate(bool deleteBehaviour) = 0; ///< Sets/Clears the 'delete on terminate' property.
protected:
virtual TerminateBehavior process(const XFEvent * pEvent) = 0; ///< Called by the dispatcher to process an event.
protected:
XFReactive() = default;
};
} // namespace interface
#endif // XF_INTERFACE_REACTIVE_H

View File

@ -0,0 +1,76 @@
#ifndef XF_INTERFACE_RESOURCE_FACTORY_H
#define XF_INTERFACE_RESOURCE_FACTORY_H
#include "xf/interface/dispatcher.h"
#include "xf/interface/thread.h"
#include "xf/interface/mutex.h"
namespace interface {
/**
* @brief Responsible to create and return XF resources.
*
* The XF resource factory provides instances of following classes
* - Dispatcher
* - Thread
* - Mutex
*
* The XFResourceFactory::getInstance() method needs to be implemented
* in the class realizing this interface.
*
*/
class XFResourceFactory
{
public:
static XFResourceFactory * getInstance(); ///< Returns a pointer to the unique instance of the XF resource factory.
/**
* @brief Returns the default dispatcher.
*
* In case a bahavior does not have a specific dispatcher the
* default dispatcher ist used.
*
* @return A pointer to the default dispatcher.
*/
virtual interface::XFDispatcher * getDefaultDispatcher() = 0;
/**
* @brief Creates a new dispatcher.
*
* Per default this method returns a new active dispatcher. In
* case there is no OS present (IDF) the default dispatcher may
* be returned.
*
* @return The new dispatcher
*/
virtual interface::XFDispatcher * createDispatcher() = 0;
/**
* @brief Creates a new Thread.
* @param pProvider The instance providing the entry method.
* @param entryMethod The method to by called by the new thread.
* @param threadName The name of the thread.
* @param stackSize The stack size of the thread.
* @return Pointer to new thread
*
* The method may return null in case there is no OS present.
*/
virtual interface::XFThread * createThread(interface::XFThreadEntryPointProvider * pProvider,
interface::XFThread::EntryMethodBody entryMethod,
const char * threadName,
const uint32_t stackSize = 0) = 0;
/**
* @brief Returns a new mutex.
* @return Pointer to new mutex.
*/
virtual interface::XFMutex * createMutex() = 0;
virtual ~XFResourceFactory() = default;
protected:
XFResourceFactory() = default;
};
} // namespace interface
#endif // XF_INTERFACE_RESOURCE_FACTORY_H

View File

@ -0,0 +1,60 @@
#ifndef XF_INTERFACE_THREAD_H
#define XF_INTERFACE_THREAD_H
#include "stdint.h"
typedef enum
{
XF_THREAD_PRIO_UNKNOWN = 0,
XF_THREAD_PRIO_LOW = 5,
XF_THREAD_PRIO_NORMAL = 10,
XF_THREAD_PRIO_HIGH = 15,
XF_THREAD_PRIO_MAX = 20
} XFThreadPriority;
namespace interface {
/**
* @brief Interface to be implemented by the class providing the thread entry method.
*/
class XFThreadEntryPointProvider
{
public:
virtual ~XFThreadEntryPointProvider() = default;
protected:
XFThreadEntryPointProvider() = default;
};
/**
* @brief Interface for a Thread.
*
* Thread interface representing the instance executing the behavior. In an OS less XF
* (hence an IDF), usually this class is not needed. In an XF interfacing an OS,
* multiple instances can be made, each interfacing the real OS thread.
*
* Thread instances can be created using the ResourceFactory instance.
*
* The XF assumes that the Thread is in suspend state after creation. Automatically
* starting the thread after creation may lead to unwanted behavior!
*/
class XFThread
{
public:
virtual ~XFThread() = default;
typedef void (XFThreadEntryPointProvider::*EntryMethodBody)(const void *); ///< Prototype of method to be executed by the thread.
virtual void start() = 0; ///< Starts the thread.
virtual void stop() = 0; ///< Requests the thread to stop execution.
virtual void setPriority(XFThreadPriority priority) = 0; ///< Set the thread priority.
virtual XFThreadPriority getPriority() const = 0; ///< Returns the thread priority.
virtual void delay(uint32_t milliseconds) = 0; ///< Causes the thread to sleep (for the given milliseconds).
protected:
XFThread() = default;
};
} // namespace interface
#endif // XF_INTERFACE_THREAD_H

View File

@ -0,0 +1,89 @@
#ifndef XF_INTERFACE_TIMEOUTMANAGER_H
#define XF_INTERFACE_TIMEOUTMANAGER_H
#include <stdint.h>
namespace interface {
class XFReactive;
}
class XFTimeout;
namespace interface {
/**
* @brief Interface for TimerManager classes (and some few 'tick' stuff already provided).
*
* The TimeoutManager is responsible to handle timeouts used
* in state machines. It decrements them accordingly and inject
* them back to the state machine when timeouted.
*
* <b>Requirements:</b>
* - Implements the Singleton pattern
* - Handle timeouts (hold, decrement, re-inject)
*/
class XFTimeoutManager
{
public:
virtual ~XFTimeoutManager() = default;
static XFTimeoutManager * getInstance(); ///< Returns a pointer to the single instance of TimeoutManager.
/**
* Sets the time interval in milliseconds in which the timeout manager
* should handle the timeouts.
*/
virtual void initialize(int32_t tickInterval)
{
tickInterval_ = tickInterval;
}
/**
* @brief Returns tick interval in milliseconds.
*/
virtual int32_t getTickInterval() const
{
return tickInterval_;
}
/**
* Starts the timeout manager.
*/
virtual void start() = 0;
/**
* Adds a timeout to the timeout manager.
*
* \param timeoutId The timeout id known by the reactive parameter. Is needed by the reactive part to uniquely identify the timeout.
* \param interval The time in milliseconds to wait until the timeout expires.
* \param pReactive The reactive instance where to inject the timeout when it timeouts.
*/
virtual void scheduleTimeout(int32_t timeoutId, int32_t interval, interface::XFReactive * pReactive) = 0;
/**
* Removes all timeouts corresponding the given parameters.
*/
virtual void unscheduleTimeout(int32_t timeoutId, interface::XFReactive * pReactive) = 0;
/** \brief Called periodically with a delay defined by TimeoutManager::_tickInterval.
*
* On each call to this method, TimeoutManager::_tickInterval will be removed from the
* timeouts.
* When a timeout expires it is pushed back to the dispatcher. To which
* dispatcher it must be given is known by the reactive instance to which the timeout
* belongs.
*/
virtual void tick() = 0;
protected:
XFTimeoutManager() :
tickInterval_(0)
{}
virtual void addTimeout(XFTimeout * pNewTimeout) = 0; ///< Adds the timeout to the list of timeouts.
protected:
int32_t tickInterval_; ///< Interval in milliseconds the TimeoutManager is decrementing the timeouts.
};
} // namespace interface
#endif // XF_INTERFACE_TIMEOUTMANAGER_H

View File

@ -0,0 +1,33 @@
#ifndef XF_NULLTRANSITION_H
#define XF_NULLTRANSITION_H
#include "xf.h"
#include "xf/event.h"
/** @ingroup xf_core
* @{
*/
/**
* @brief State machine transition without trigger.
*
* Represents a transition in a state machine having no trigger.
*
* In case one wants to directly transition from one state to
* an other (without a trigger) a null transition must be pushed.
*/
class XFNullTransition : public XFEvent
{
public:
/**
* Constructor
*
* \param pBehavior Behavior in which the null transition will be executed.
*/
XFNullTransition(interface::XFReactive * pBehavior = nullptr);
bool deleteAfterConsume() const override;
};
/** @} */ // end of xf_core group
#endif // XF_NULLTRANSITION_H

View File

@ -0,0 +1,59 @@
#ifndef XF_TIMEOUT_H
#define XF_TIMEOUT_H
#include "xf/event.h"
namespace interface {
class XFTimeoutManager;
}
/** @ingroup xf_core
* @{
*/
/**
* @brief Used by the TimeoutManager to create and handle a timeout.
*
* Timeouts are created automatically by the TimeoutManager when
* scheduling a timeout. After expiration they are queued to the event queue
* and afterwards dispatched to the corresonding behavior.
*
* A timeout can be identified by checking against #Timeout using
* the `getEventType()` method.
*
* XFTimeout is inheriting from XFEvent, so every timeout is
* also an event.
*/
class XFTimeout : public XFEvent
{
friend class interface::XFTimeoutManager;
public:
/**
* Constructor of the class.
* \param id The id given by the behavioral class to uniquely identifying the timeout
* \param interval The interval in milliseconds the timeout expires
* \param pBehavior Pointer to behavioral class to which the timeout belongs
*/
XFTimeout(int id, int interval, interface::XFReactive * pBehavior);
/**
* Operator checks if #_pBehavior and #_id are equal and returns
* true if so. All other attributes get no attention.
*/
bool operator ==(const XFTimeout & timeout) const;
bool deleteAfterConsume() const override; ///< Tells the dispatcher if the event must be deleted or not.
inline void setRelTicks(int relTicks) { relTicks_ = relTicks; } ///< Sets remaining ticks.
inline int getRelTicks() const { return relTicks_; } ///< Returns remaining ticks.
inline void substractFromRelTicks(int ticksToSubstract) { relTicks_ -= ticksToSubstract; } ///< Substracts `ticksToSubstract` from remaining ticks.
inline void addToRelTicks(int ticksToAdd) { relTicks_ += ticksToAdd; } ///< Adds `ticksToAdd` to remaining ticks.
protected:
int interval_; ///< Timeout interval
int relTicks_; ///< Used by the TimeoutManager to calculate remaining time. Can get negative!
};
/** @} */ // end of xf_core group
#endif // XF_TIMEOUT_H

View File

@ -0,0 +1,6 @@
/** @defgroup xf_core XF Core Classes
*
* XF core classes.
*
*/

171
src/xf/include/xf/xf.h Normal file
View File

@ -0,0 +1,171 @@
#ifndef XF_XF_H
#define XF_XF_H
#include "config/xf-config.h"
//
// What is seen only by the C++ compiler
//
#ifdef __cplusplus
#include "xf/interface/dispatcher.h"
/** \mainpage PTR Execution Framework Documentation
*
* \section sec_xf_intro Introduction
*
* This library implements an e<b>X</b>ecution <b>F</b>ramework (XF) to drive finite
* state machines. Using this framework, it is possible to drive multiple state machines
* in a concurrent manner (pseudo-parallel) without having an operating system.
*
* The XF defines an interface which gives the ability to reimplement parts of the XF to
* make changes to an other target/platform. It is also possible to let the XF run with an RTOS.
* This gives the possibility to run state machines in a OS like concurrent manner with
* threads provided by the underlying RTOS.
*
* \section sec_xf_comp XF Component Diagram
* The XF is split into two parts. One part is the XF core containing classes which
* never change across platforms. The other part is the XF port containing classes
* adjusted for a specific platform:
*
* \image html comp-xf.png "Component Class Diagram"
*
* The XF core together with a port forms a complete XF which can be integrated into
* a software project.
*
* \section sec_xf_cmd XF Class Diagram
*
* Following class diagram shows the basic relations between the most important classes
* in the PTR XF. It shall give you a basic understanding about the relations between
* these classes:
*
* \image html cmd-xf.png "XF Class Diagram"
*
* \section sec_xf_start Starting Point
*
* A good point to jump into the definitions of the classes is the `#XF` class. Other classes
* of interest are `interface::XFTimeoutManager`, `interface::XFDispatcher` and `interface::XFReactive`.
*
* \section sec_xf_external_links Links to related Documentation
* \if DOC_WITH_TESTBENCH
* - <a href="../../../../../test-bench/doxygen/output/html/index.html">Test Bench Documentation</a>
* \endif
* - <a href="../../../../../src/mdw/trace/doxygen/output/html/index.html">Trace Documentation</a>
*
* \if DOC_WITH_RELEASE_HISTORY
* \section sec_xf_releases XF Releases
* \subsection xf_v_4_0_1 XF Version: 4.0.1 (2021-08)
* - crc: Added parameter 'fromISR' for push() methods
* - sth: Added XF_isRunning() function to port-functions.h
* \subsection xf_v_4_0_0 XF Version: 4.0.0 (2021-05)
* - crc: Migration from IDE-STM / CubeMX to CubeIDE
* - crc: Changed CMSIS port from `CMSIS_RTOS_V1` to `CMSIS_RTOS_V2`
* \subsection xf_v_3_3_2 XF Version: 3.3.2 (2020-09)
* - sth: Added 'override' keywords to derived methods
* - sth: Removed attribute '_mainDispatcher' from XFResourceFactoryDefault
* \subsection xf_v_3_3_1 XF Version: 3.3.1 (2020-04)
* - sth: Added XF::isRunning() method
* \subsection xf_v_3_3_0 XF Version: 3.3.0 (2020-02)
* - sth: Introduced per platform default port implementations (port/default-qt, port/default-idf, etc.)
* - sth: Moved mutex and thread classes into the platform default port folders
* - sth: Added 'interface::XFReactive::deleteOnTerminate()' method
* \subsection xf_v_3_2_1 XF Version: 3.2.1 (2019-04)
* - sth: Made several bugfixes.
* \subsection xf_v_3_2 XF Version: 3.2 (2018-09)
* - sth: Updated XF interfaces.
* - sth: Added IDF_STM32CUBE, STM32CUBE_CMSIS_FREERTOS and ACTIVE_QT ports.
* - sth: Removed old ports IDF_STM32F4 and CMSIS_RTOS_FREERTOS.
* \subsection xf_v_3_1 XF Version: 3.1 (2017-11)
* - sth: Fixed bug in removeTimeouts() method of XFTimeoutManager. Thanks to Gregory Dumoulin.
* \subsection xf_v_3_0 XF Version: 3.0 (2017-10)
* - sth: The new XF is providing interfaces to support other OS's.
* - sth: Changed XF interfaces. Porting older applications to new XF need some adjustments.
* - sth: Added 'port' folder to allow extensions to other platforms.
* - sth: Added IDF_STM32F4, CMSIS_RTOS_FREERTOS and IDF_QT ports.
* \subsection xf_v_2_1 XF Version: 2.1 (2015-03-02)
* - sth: XFTimoutManager now returns timeouts with same value correctly.
* \subsection xf_v_2_0 XF Version: 2.0 (2014-04-28)
* - sth: Changed way how XFTimeoutManager handles timeouts which timeout at the same time.
* Now new timeouts get behind the timeouts with the same (timeout) time.
* \subsection xf_v_1_0 XF Version: 1.0 (2014-04-24)
* - sth: Renamed class XFEvent to XFCustomEvent
* - sth: Renamed IXFEvent to XFEvent (because it was never a real interface)
* \subsection xf_v_0_5 XF Version: 0.5 (2013-12-09)
* - sth: Now properly stopping and terminating MainThreadExec instance
* - sth: Added new literal to XFEventStatus to handle composite states
* \subsection xf_v_0_4 XF Version: 0.4 (2013-12-05)
* - sth: Added scheduleTimeout and unscheduleTimeout to XFBehavior class (helper operations)
* \subsection xf_v_0_3 XF Version: 0.3 (2013-09-19)
* - sth: Added handling for static events (IXFEvent::deleteAfterConsume())
* \subsection xf_v_0_2 XF Version: 0.2 (2011-08-14)
* - sth: Fixed bug in XFTimeoutManager::addTimeout method
* \subsection xf_v_0_1 XF Version: 0.1 (2010-11-26)
* - sth: First release
* \endif
*/
/** @ingroup xf_core
* @{
*/
/**
* @brief Static class grouping the basic methods for the XF together.
*/
class XF
{
public:
/**
* Initializes the e<b>X</b>ecution <b>F</b>ramework (XF). Call
* this method prior to initialize the other objects of the system.
*
* @param timeInterval The interval in milliseconds with which the TimeoutManager should run.
* @param argc Optional parameter to pass application argument number to XF.
* @param argv Optional parameter to pass application arguments to XF.
*/
static void initialize(int timeInterval = 10, int argc = 0, char * argv[] = nullptr);
/**
* Starts execution of the framework. This
* results in processing the events in main loop.
*
* This method is blocking.
*/
static int exec();
/**
* Executes once the dispatcher. To be called regularly in a while loop.
*
* This method is non-blocking.
*/
static int execOnce();
/**
* @brief Returns true in case the XF is initialized and running.
*/
static bool isRunning();
protected:
static bool isInitialized_; ///< Changes from false to true after calling method initialize(int). Used to handle multiple calls to init(int).
static bool isRunning_; ///< Tells if the XF is initialized and running.
};
#endif // __cplusplus
//
// What is seen by the C and C++ compiler
//
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
void XF_initialize(int timeInterval); ///< Initializes XF within C code
void XF_exec(); ///< Calls XF execution in C code (blocking call)
void XF_execOnce(); ///< Calls XF execution in C code (non-blocking call)
#ifdef __cplusplus
}
#endif // __cplusplus
/** @} */ // end of xf_core group
#endif // XF_XF_H

62
src/xf/port/README.md Normal file
View File

@ -0,0 +1,62 @@
# XF Ports
## Introduction
An XF (execution framework) consist of a view classes which some need to be adjusted
when used on another platform.
Following you will find a list of classes which may be adjusted/reimplemented when
changing to another platform/environment:
- `XF`
- `ResourceFactory`
- `TimeoutManager`
- `Dispatcher`
- `EventQueue`
- `Thread`
- `Mutex`
These classes are also named `port classes` because they can be ported to another
platform. All port classes can be found in the _port_ folder whereas every port is
located in a separate folder.
Every port may pick some default implementation classes from the _default_ folders
also located in the _port_ folder.
In case you are going to implement an OS-less XF (hence an IDF) usually, you do not
need to implement the classes `Thread` and `Mutex`.
## Default Port Classes
There are already some default port class implementations present. You can find
them in the `default` folder and may suit your needs for a first version
of your XF. These default port classes are platform independent and can be
used by any port implementation.
## Default Platform Classes
Some classes depent on external resources like for example an OS. These
classes are located in the _default-&lt;platform&gt;_ specific folders. Currently,
the following default platfroms are available:
| Platform | Folder | Description |
|--|--|--|
| CMSIS-OS | [default-cmsis-os](./default-cmsis-os) | CMSIS-OS abstraction layer |
| IDF | [default-idf](./default-idf) | Interrupt driven framework |
| QT | [default-qt](./default-qt) | Qt library |
## Port Folder Structure
In case you want to add support for another platform to the XF, you need to add a
subfolder to the _port_ folder and put the port class files in there. Best is to
take an already present port which is most similar to what you need, rename it and
start adaption of these files.
You may also mix-up you port with classes from the _default_, _default-&lt;platform&gt;_
folder and your custom folder (or even reference classes from other ports).
## Available Ports
Here is a list of currently available ports:
| Port Name | OS | Platform | Folder Name | Description |
|--|--|--|--|--|
| PORT_IDF_QT | Qt (IDF) | Qt library based implementation | idf-qt | XF support for OS X, Linux and Windows |
| PORT_IDF_STM32CUBE | Bare-Metal (IDF) | STM32CubeMX based port | idf-stm32cube | XF for ARM Cortex based microcontrollers from STMicroelectronics |
| PORT_STM32CUBE_CMSIS_FREERTOS | CMSIS OS (FreeRTOS) | Any platform supporting CMSIS OS | stm32cube-cmsis-freertos | FreeRTOS based port |
| PORT_ACTIVE_QT | Qt multi-thread | Qt library based implementation | active-qt | XF support for OS X, Linux and Windows (multi-thread) |

View File

@ -0,0 +1,38 @@
# XF Port - Active Qt
This port folder contains specific classes for the _Active Qt_
XF port.
# Classes used by the _Active Qt_ Port
| Class name | File location | Define to set |
|--|--|--|
| XFTimeoutManagerDefault | xf/port/default/timeoutmanager-default.cpp | USE_XF_TIMEOUTMANAGER_DEFAULT_IMPLEMENTATION |
| XFDispatcherActiveDefault | xf/port/default/dispatcher-active.cpp | USE_XF_DISPATCHER_ACTIVE_DEFAULT_IMPLEMENTATION |
| XF | xf/port/idf-qt/xf.cpp | USE_XF_PORT_IDF_QT_XF_IMPLEMENTATION |
| XFMutexPort | xf/port/default-qt/mutex-default.cpp | USE_XF_MUTEX_DEFAULT_QT_IMPLEMENTATION |
| XFThreadPort | xf/port/default-qt/thread-default.cpp | USE_XF_THREAD_DEFAULT_QT_IMPLEMENTATION |
| XFEventQueuePort | xf/port/idf-qt/eventqueue.cpp | USE_XF_PORT_IDF_QT_EVENT_QUEUE_IMPLEMENTATION |
| Port Functions | xf/port/idf-qt/port-functions.cpp | USE_XF_PORT_IDF_QT_PORT_FUNCTIONS_IMPLEMENTATION |
| XFResourceFactoryPort | xf/port/active-qt/resourcefactory.cpp | USE_XF_PORT_ACTIVE_QT_RESOURCE_FACTORY_IMPLEMENTATION |
# Example _config/xf-config.h_ File
```c++
// Take all the port classes from the IDF_QT port expect...
#define USE_XF_PORT_IDF_QT_XF_IMPLEMENTATION 1
#define USE_XF_PORT_IDF_QT_EVENT_QUEUE_IMPLEMENTATION 1
#define USE_XF_PORT_IDF_QT_PORT_FUNCTIONS_IMPLEMENTATION 1
// ... the resource factory. Must provide active dispatchers!
#define USE_XF_PORT_ACTIVE_QT_RESOURCE_FACTORY_IMPLEMENTATION 1
// ... mutexes and threads from the 'default-qt' port package
#define USE_XF_MUTEX_DEFAULT_QT_IMPLEMENTATION 1
#define USE_XF_THREAD_DEFAULT_QT_IMPLEMENTATION 1
// ... and the remaining classes from the default port package.
#define USE_XF_TIMEOUTMANAGER_DEFAULT_IMPLEMENTATION 1
#define USE_XF_DISPATCHER_ACTIVE_DEFAULT_IMPLEMENTATION 1
#include "idf-qt/eventqueue.h"
```

Binary file not shown.

View File

@ -0,0 +1,51 @@
#include <config/xf-config.h>
#if (USE_XF_PORT_ACTIVE_QT_RESOURCE_FACTORY_IMPLEMENTATION != 0)
#include <QtGlobal>
#include "xf/interface/mutex.h"
#include "thread-default.h"
#include "default/dispatcher-active.h"
#include "resourcefactory.h"
using interface::XFMutex;
//static
interface::XFResourceFactory * interface::XFResourceFactory::getInstance()
{
return XFResourceFactoryPort::getInstance();
}
// static
interface::XFResourceFactory * XFResourceFactoryPort::getInstance()
{
static XFResourceFactoryPort theResourceFactory;
return &theResourceFactory;
}
interface::XFDispatcher * XFResourceFactoryPort::getDefaultDispatcher()
{
static XFDispatcherActiveDefault mainDispatcher;
return &mainDispatcher;
}
interface::XFDispatcher * XFResourceFactoryPort::createDispatcher()
{
// Create the new active dispatcher
return new XFDispatcherActiveDefault;
}
interface::XFThread * XFResourceFactoryPort::createThread(interface::XFThreadEntryPointProvider * pProvider,
interface::XFThread::EntryMethodBody entryMethod,
const char * threadName,
const uint32_t stackSize /* = 0 */)
{
return new XFThreadDefault(pProvider, entryMethod, threadName, stackSize);
}
interface::XFMutex * XFResourceFactoryPort::createMutex()
{
return XFMutex::create();
}
#endif // USE_XF_PORT_ACTIVE_QT_RESOURCE_FACTORY_IMPLEMENTATION

View File

@ -0,0 +1,31 @@
#ifndef XF_PORT_ACTIVE_QT_RESOURCE_FACTORY_H
#define XF_PORT_ACTIVE_QT_RESOURCE_FACTORY_H
#include "config/xf-config.h"
#if (USE_XF_PORT_ACTIVE_QT_RESOURCE_FACTORY_IMPLEMENTATION != 0)
#include "xf/interface/resourcefactory.h"
#include "xf/interface/dispatcher.h"
class XFResourceFactoryPort : public interface::XFResourceFactory
{
public:
~XFResourceFactoryPort() override {}
static interface::XFResourceFactory * getInstance();
interface::XFDispatcher * getDefaultDispatcher() override;
interface::XFDispatcher * createDispatcher() override;
interface::XFThread * createThread(interface::XFThreadEntryPointProvider * pProvider,
interface::XFThread::EntryMethodBody entryMethod,
const char * threadName,
const uint32_t stackSize = 0) override;
interface::XFMutex * createMutex() override;
protected:
XFResourceFactoryPort() {}
};
#endif // USE_XF_PORT_ACTIVE_QT_RESOURCE_FACTORY_IMPLEMENTATION
#endif // XF_PORT_ACTIVE_QT_RESOURCE_FACTORY_H

View File

@ -0,0 +1,8 @@
INCLUDEPATH += $$PWD/..
SOURCES += \
"$$PWD/resourcefactory.cpp"
HEADERS += \
"$$PWD/resourcefactory.h"

View File

@ -0,0 +1,24 @@
#
# This PRI file takes only the classes needed from the
# 'default' port.
#
INCLUDEPATH += $$PWD/..
# Path to default implementation of the XF port
DEFAULT_IMPL_PATH = $$PWD/../default
DEFAULT_IMPL_SOURCES += \
"$${DEFAULT_IMPL_PATH}/xf-default.cpp" \
"$${DEFAULT_IMPL_PATH}/timeoutmanager-default.cpp" \
"$${DEFAULT_IMPL_PATH}/dispatcher-active.cpp"
DEFAULT_IMPL_HEADERS += \
"$${DEFAULT_IMPL_PATH}/timeoutmanager-default.h" \
"$${DEFAULT_IMPL_PATH}/dispatcher-active.h"
SOURCES += \
$${DEFAULT_IMPL_SOURCES}$$
HEADERS += \
$${DEFAULT_IMPL_HEADERS}$$

View File

@ -0,0 +1,39 @@
# CMSIS-OS Platform Default Port
This folder provides a default implementation for CMSIS-OS platform
related XF classes. You can use these classes to construct a CMSIS-OS
based XF.
If these classes do not suit your needs, they can be reimplemented for
your platform. Create an additional folder in the 'port' folder and
implement there the classes you need for your platform.
# Available Default CMSIS-OS Port Classes
| Class name | File location | Define to set |
| -------------- | ------------------------------------- | --------------------------------------- |
| XFMutexDefault | xf/port/default-cmsis-os/mutex-default.cpp | USE_XF_MUTEX_DEFAULT_CMSIS_OS_IMPLEMENTATION |
| XFThreadDefault | xf/port/default-cmsis-os/thread-default.cpp | USE_XF_THREAD_DEFAULT_CMSIS_OS_IMPLEMENTATION |
If you need more information about the classes mentioned above, please
have a look into their header files and the doxygen comments in code.
# Example _config/xf-config.h_ File
Following you will find an example giving you a basic idea which define
to set in the application specific _config/xf-config.h_ file.
The _Stm32Cube CMSIS FreeRTOS_ port uses these classes:
```c++
// Defines to set to use the Stm32Cube CMSIS FreeRTOS port
#define USE_XF_DISPATCHER_ACTIVE_DEFAULT_IMPLEMENTATION 1
#define USE_XF_MUTEX_DEFAULT_CMSIS_OS_IMPLEMENTATION 1
#define USE_XF_THREAD_DEFAULT_CMSIS_OS_IMPLEMENTATION 1
#define USE_XF_PORT_STM32CUBE_CMSIS_FREERTOS_RESOURCE_FACTORY_IMPLEMENTATION 1
#define USE_XF_PORT_STM32CUBE_CMSIS_FREERTOS_TIMEOUTMANAGER_IMPLEMENTATION 1
#define USE_XF_PORT_STM32CUBE_CMSIS_FREERTOS_EVENT_QUEUE_IMPLEMENTATION 1
#define USE_XF_PORT_STM32CUBE_CMSIS_FREERTOS_THREAD_IMPLEMENTATION 1
#include "stm32cube-cmsis-freertos/eventqueue.h"
```

Binary file not shown.

View File

@ -0,0 +1,51 @@
#include <cassert>
#include <cstring>
#include <config/xf-config.h>
#if (USE_XF_MUTEX_DEFAULT_CMSIS_OS_IMPLEMENTATION != 0)
#include "mutex-default.h"
/**
* @brief Implementation of interface::XFMutex::create method.
*/
interface::XFMutex * interface::XFMutex::create()
{
return new XFMutexDefault;
}
XFMutexDefault::XFMutexDefault() :
_mutexId(0)
{
memset(&_mutexDefinition,0,sizeof(_mutexDefinition));
_mutexId = osMutexNew(&_mutexDefinition);
assert(_mutexId);
}
XFMutexDefault::~XFMutexDefault()
{
}
void XFMutexDefault::lock()
{
assert(_mutexId);
osStatus status = osMutexWait(_mutexId, osWaitForever);
assert(status == osOK);
}
void XFMutexDefault::unlock()
{
osStatus status = osMutexRelease(_mutexId);
assert(status == osOK);
}
bool XFMutexDefault::tryLock(int32_t timeout /* = 0 */)
{
osStatus status = osMutexWait(_mutexId, timeout);
return (status == osOK) ? true : false;
}
#endif // USE_XF_MUTEX_DEFAULT_CMSIS_OS_IMPLEMENTATION

View File

@ -0,0 +1,38 @@
#ifndef XF_MUTEX_DEFAULT_CMSIS_OS_H
#define XF_MUTEX_DEFAULT_CMSIS_OS_H
#include <config/xf-config.h>
#if (USE_XF_MUTEX_DEFAULT_CMSIS_OS_IMPLEMENTATION != 0)
#include <stdint.h>
#include <cmsis_os.h>
#include "xf/interface/mutex.h"
/** @ingroup port_default_cmsis_os
* @{
*/
/**
* @brief Default CMSIS-OS imlementation XFMutex interface.
*
*/
class XFMutexDefault : public interface::XFMutex
{
public:
XFMutexDefault();
virtual ~XFMutexDefault();
virtual void lock();
virtual void unlock();
virtual bool tryLock(int32_t timeout = 0);
protected:
osMutexDef_t _mutexDefinition;
osMutexId _mutexId;
};
/** @} */ // end of port_default_cmsis_os group
#endif // USE_XF_MUTEX_DEFAULT_CMSIS_OS_IMPLEMENTATION
#endif // XF_MUTEX_DEFAULT_CMSIS_OS_H

View File

@ -0,0 +1,6 @@
/** @defgroup port_default_cmsis_os CMSIS-OS Platform Default Port Classes
*
* CMSIS-OS platform default port classes.
*
*/

View File

@ -0,0 +1,134 @@
#include <config/xf-config.h>
#if (USE_XF_THREAD_DEFAULT_CMSIS_OS_IMPLEMENTATION != 0)
#include <cassert>
#include <string.h>
#include "thread-default.h"
#if !defined(XFTHREAD_DEFAULT_STACK_SIZE)
# define XFTHREAD_DEFAULT_STACK_SIZE 512
#endif
//extern "C" const int uxTopUsedPriority;
//const int __attribute__((used)) uxTopUsedPriority = configMAX_PRIORITIES - 1;
/**
* Always keep threads after creation in suspended state.
* Threads must be explicitly started with start()!
*/
/// Attributes structure for thread.
/*
typedef struct {
const char *name; ///< name of the thread
uint32_t attr_bits; ///< attribute bits
void *cb_mem; ///< memory for control block
uint32_t cb_size; ///< size of provided memory for control block
void *stack_mem; ///< memory for stack
uint32_t stack_size; ///< size of stack
osPriority_t priority; ///< initial thread priority (default: osPriorityNormal)
TZ_ModuleId_t tz_module; ///< TrustZone module identifier
uint32_t reserved; ///< reserved (must be 0)
} osThreadAttr_t;*/
XFThreadDefault::XFThreadDefault(interface::XFThreadEntryPointProvider * pProvider,
interface::XFThread::EntryMethodBody entryMethod,
const char * threadName,
const uint32_t stackSize /* = 0 */)
{
uint32_t threadStackSize = stackSize;
_pEntryMethodProvider = pProvider;
_entryMethod = entryMethod;
strcpy(_threadName, threadName);
if (threadStackSize == 0)
{
threadStackSize = XFTHREAD_DEFAULT_STACK_SIZE;
}
::memset(&_threadAttr, 0, sizeof(_threadAttr));
_threadAttr.name = _threadName;
_threadAttr.priority = osPriorityNormal;
_threadAttr.stack_size = threadStackSize;
_threadFunc = &threadEntryPoint;
_threadId = osThreadNew(_threadFunc, this, &_threadAttr);
assert(_threadId); // Check if thread creation was successful
// Always keep threads after creation in suspended state.
// Must be explicitly started with start();
osThreadSuspend(_threadId);
}
//static
void XFThreadDefault::threadEntryPoint(void * param)
{
XFThreadDefault * pThis = (XFThreadDefault *)param;
(pThis->_pEntryMethodProvider->*pThis->_entryMethod)(param);
}
void XFThreadDefault::start()
{
assert(_threadId != 0); // Check if thread was created
osThreadResume(_threadId);
}
void XFThreadDefault::stop()
{
osThreadTerminate(_threadId);
}
void XFThreadDefault::setPriority(XFThreadPriority priority)
{
osPriority prio = osPriorityNormal;
switch (priority)
{
case XF_THREAD_PRIO_LOW:
prio = osPriorityLow;
break;
case XF_THREAD_PRIO_HIGH:
prio = osPriorityHigh;
break;
default:
break;
}
osThreadSetPriority(_threadId, prio);
}
XFThreadPriority XFThreadDefault::getPriority() const
{
const osPriority prio = osThreadGetPriority(_threadId);
XFThreadPriority priority = XF_THREAD_PRIO_UNKNOWN;
switch (prio)
{
case osPriorityLow:
priority = XF_THREAD_PRIO_LOW;
break;
case osPriorityNormal:
priority = XF_THREAD_PRIO_NORMAL;
break;
case osPriorityHigh:
priority = XF_THREAD_PRIO_HIGH;
break;
default:
break;
}
return priority;
}
void XFThreadDefault::delay(uint32_t milliseconds)
{
osDelay(milliseconds);
}
#endif // USE_XF_THREAD_DEFAULT_CMSIS_OS_IMPLEMENTATION

View File

@ -0,0 +1,45 @@
#ifndef XF_THREAD_DEFAULT_CMSIS_OS_H
#define XF_THREAD_DEFAULT_CMSIS_OS_H
#include <config/xf-config.h>
#if (USE_XF_THREAD_DEFAULT_CMSIS_OS_IMPLEMENTATION != 0)
#include <stdint.h>
#include <cmsis_os.h>
#include "xf/interface/thread.h"
class XFThreadDefault : public interface::XFThread
{
friend class XFResourceFactoryPort;
public:
virtual void start();
virtual void stop();
virtual void setPriority(XFThreadPriority priority);
virtual XFThreadPriority getPriority() const;
virtual void delay(uint32_t milliseconds);
protected:
XFThreadDefault(interface::XFThreadEntryPointProvider * pProvider,
interface::XFThread::EntryMethodBody entryMethod,
const char * threadName,
const uint32_t stackSize = 0);
static void threadEntryPoint(void * param);
protected:
interface::XFThreadEntryPointProvider * _pEntryMethodProvider;
interface::XFThread::EntryMethodBody _entryMethod;
osThreadAttr_t _threadAttr;
osThreadFunc_t _threadFunc;
char _threadName[32];
osThreadId _threadId;
};
#endif // USE_XF_THREAD_DEFAULT_CMSIS_OS_IMPLEMENTATION
#endif // XF_THREAD_DEFAULT_CMSIS_OS_H

View File

@ -0,0 +1,42 @@
# IDF (Interrupt Driven Framework) Platform Default Port
This folder provides a default implementation for IDF related XF classes.
You can use these classes to construct an IDF based XF.
If these classes do not suit your needs, they can be reimplemented for
your platform. Create an additional folder in the 'port' folder and
implement there the classes you need for your platform.
# Available Default IDF Port Classes
| Class name | File location | Define to set |
| -------------- | ------------------------------------- | --------------------------------------- |
| XFEventQueueDefault | xf/port/default-idf/eventqueue-default.cpp | USE_XF_EVENT_QUEUE_DEFAULT_IDF_IMPLEMENTATION |
| XFMutexDefault | xf/port/default-idf/mutex-default.cpp | USE_XF_MUTEX_DEFAULT_IDF_IMPLEMENTATION |
If you need more information about the classes mentioned above, please
have a look into their header files and the doxygen comments in code.
# Example _config/xf-config.h_ File
Following you will find an example giving you a basic idea which define
to set in the application specific _config/xf-config.h_ file.
The _IDF Stm32Cube_ port uses quite all default implementations:
```c++
// Defines to set to use the IDF Stm32Cube port
#define USE_XF_DEFAULT_IMPLEMENTATION 1
#define USE_XF_DISPATCHER_DEFAULT_IMPLEMENTATION 1
#define USE_XF_TIMEOUTMANAGER_DEFAULT_IMPLEMENTATION 1
#define USE_XF_RESOURCE_FACTORY_DEFAULT_IMPLEMENTATION 1
#define USE_XF_MUTEX_DEFAULT_IDF_IMPLEMENTATION 1
#define USE_XF_EVENT_QUEUE_DEFAULT_IDF_IMPLEMENTATION 1
#define USE_XF_PORT_IDF_STM32CUBE_PORT_FUNCTIONS_IMPLEMENTATION 1
#include "default-idf/eventqueue-default.h"
#ifdef __cplusplus
using XFEventQueue = XFEventQueueDefault;
#endif // __cplusplus
```

Binary file not shown.

View File

@ -0,0 +1,61 @@
#include <config/xf-config.h>
#if (USE_XF_EVENT_QUEUE_DEFAULT_IDF_IMPLEMENTATION != 0)
#include <cassert>
#include "eventqueue-default.h"
XFEventQueueDefault::XFEventQueueDefault()
{
}
XFEventQueueDefault::~XFEventQueueDefault()
{
}
bool XFEventQueueDefault::empty() const
{
return _queue.empty();
}
bool XFEventQueueDefault::push(const XFEvent * pEvent, bool fromISR)
{
_mutex.lock();
{
_queue.push(pEvent);
}
_mutex.unlock();
return true;
}
const XFEvent * XFEventQueueDefault::front()
{
const XFEvent * event;
_mutex.lock();
{
event = _queue.front();
}
_mutex.unlock();
return event;
}
void XFEventQueueDefault::pop()
{
_mutex.lock();
{
_queue.pop();
}
_mutex.unlock();
}
bool XFEventQueueDefault::pend()
{
// Method cannot be used in an IDF! Waiting within
// this method would block the whole XF
return false;
}
#endif // USE_XF_EVENT_QUEUE_DEFAULT_IDF_IMPLEMENTATION

View File

@ -0,0 +1,51 @@
#ifndef XF_EVENT_QUEUE_DEFAULT_H
#define XF_EVENT_QUEUE_DEFAULT_H
#ifdef __cplusplus
#include "config/xf-config.h"
#if (USE_XF_EVENT_QUEUE_DEFAULT_IDF_IMPLEMENTATION != 0)
#include <stdint.h>
#include <queue>
#include "xf/interface/eventqueue.h"
#include "default-idf/mutex-default.h"
/** @ingroup port_default
* @{
*/
/**
* @brief Default implementation of the event queue using a `std::queue` as container.
*
* This class does not provide a blocking pend() method. This means that this class
* can be used in an IDF, but is not the right choice for a RTOS based XF.
*/
class XFEventQueueDefault : public interface::XFEventQueue
{
using Mutex = XFMutexDefault;
public:
XFEventQueueDefault();
virtual ~XFEventQueueDefault();
// XFEventQueue interface implementation
public:
virtual bool empty() const; ///< Returns true if no event is in the queue.
virtual bool push(const XFEvent * pEvent,
bool fromISR = false); ///< Pushes the given event onto the queue.
virtual const XFEvent * front(); ///< Returns pointer to next event to pop.
virtual void pop(); ///< Pops the next event from the queue.
///< Wait for the next event to arrive. Returns true if an event is in the queue.
virtual bool pend();
protected:
typedef std::queue<const XFEvent *> EventQueue; ///< Type of the event queue.
Mutex _mutex; ///< Mutex protecting access to _queue.
EventQueue _queue; ///< Internal queue holding the events.
};
/** @} */ // end of port_default group
#endif // USE_XF_EVENT_QUEUE_DEFAULT_IDF_IMPLEMENTATION
#endif // __cplusplus
#endif // XF_EVENT_QUEUE_DEFAULT_H

View File

@ -0,0 +1,40 @@
#include <config/xf-config.h>
#if (USE_XF_MUTEX_DEFAULT_IDF_IMPLEMENTATION != 0)
#include "critical/critical.h" // Provided by the platform used
#include "mutex-default.h"
/**
* @brief Implementation of interface::XFMutex::create method.
*/
interface::XFMutex * interface::XFMutex::create()
{
return new XFMutexDefault;
}
XFMutexDefault::XFMutexDefault()
{
}
XFMutexDefault::~XFMutexDefault()
{
}
void XFMutexDefault::lock()
{
critical_enter();
}
void XFMutexDefault::unlock()
{
critical_exit();
}
bool XFMutexDefault::tryLock(int32_t timeout /* = 0 */)
{
return true; // Always allow
}
#endif // USE_XF_MUTEX_DEFAULT_IDF_IMPLEMENTATION

View File

@ -0,0 +1,37 @@
#ifndef XF_MUTEX_DEFAULT_IDF_H
#define XF_MUTEX_DEFAULT_IDF_H
#include <config/xf-config.h>
#if (USE_XF_MUTEX_DEFAULT_IDF_IMPLEMENTATION != 0)
#include <stdint.h>
#include "xf/interface/mutex.h"
/** @ingroup port_default_idf
* @{
*/
/**
* @brief Default IDF imlementation XFMutex interface.
*
* This class uses `enterCritical()` and `exitCritical()`
* functions which must be provided by the platform.
* Therefore, this mutex implementation can be used
* in Embedded Systems without OS.
*/
class XFMutexDefault : public interface::XFMutex
{
public:
XFMutexDefault();
virtual ~XFMutexDefault();
virtual void lock();
virtual void unlock();
virtual bool tryLock(int32_t timeout = 0);
};
/** @} */ // end of port_default_idf group
#endif // USE_XF_MUTEX_DEFAULT_IDF_IMPLEMENTATION
#endif // XF_MUTEX_DEFAULT_IDF_H

View File

@ -0,0 +1,6 @@
/** @defgroup port_default_idf IDF Platform Default Port Classes
*
* IDF platform default port classes.
*
*/

View File

@ -0,0 +1,46 @@
# Qt Platform Default Port
This folder provides a default implementation for Qt platform
related XF classes. You can use these classes to construct a Qt
based XF.
If these classes do not suit your needs, they can be reimplemented for
your platform. Create an additional folder in the 'port' folder and
implement there the classes you need for your platform.
# Available Default Qt Port Classes
| Class name | File location | Define to set |
| -- | -- | -- |
| XFEventQueueDefault | xf/port/default-qt/eventqueue-default.cpp | USE_XF_EVENT_QUEUE_DEFAULT_QT_IMPLEMENTATION |
| XFMutexDefault | xf/port/default-qt/mutex-default.cpp | USE_XF_MUTEX_DEFAULT_QT_IMPLEMENTATION |
| XFThreadDefault | xf/port/default-qt/thread-default.cpp | USE_XF_THREAD_DEFAULT_QT_IMPLEMENTATION |
If you need more information about the classes mentioned above, please
have a look into their header files and the doxygen comments in code.
# Example _config/xf-config.h_ File
Following you will find an example giving you a basic idea which define
to set in the application specific _config/xf-config.h_ file.
The _IDF Qt_ port uses these classes:
```c++
// Defines to set to use the IDF Qt port
#define USE_XF_TIMEOUTMANAGER_DEFAULT_IMPLEMENTATION 1
#define USE_XF_DISPATCHER_ACTIVE_DEFAULT_IMPLEMENTATION 1
#define USE_XF_EVENT_QUEUE_DEFAULT_QT_IMPLEMENTATION 1
#define USE_XF_MUTEX_DEFAULT_QT_IMPLEMENTATION 1
#define USE_XF_THREAD_DEFAULT_QT_IMPLEMENTATION 1
#define USE_XF_CLASS_DEFAULT_QT_IMPLEMENTATION 1
#define USE_XF_PORT_FUNCTIONS_DEFAULT_QT_IMPLEMENTATION 1
#define USE_XF_PORT_IDF_QT_RESOURCE_FACTORY_IMPLEMENTATION 1
#include "default-qt/eventqueue-default.h"
#ifdef __cplusplus
// Force to take the XFEventQueueDefault implementation for the event queue
using XFEventQueue = XFEventQueueDefault;
#endif // __cplusplus
```

Binary file not shown.

View File

@ -0,0 +1,55 @@
#include <config/xf-config.h>
#if (USE_XF_EVENT_QUEUE_DEFAULT_QT_IMPLEMENTATION != 0)
#include <cassert>
#include <QtGlobal>
#include <QMutexLocker>
#include "eventqueue-default.h"
XFEventQueueDefault::XFEventQueueDefault() :
mutex_(QMutex::NonRecursive)
{
}
XFEventQueueDefault::~XFEventQueueDefault()
{
newEvents_.wakeAll();
}
bool XFEventQueueDefault::empty() const
{
return queue_.isEmpty();
}
bool XFEventQueueDefault::push(const XFEvent * pEvent)
{
QMutexLocker locker(&mutex_);
queue_.enqueue(pEvent);
// Tell waiting thread(s) there is again an event present
newEvents_.wakeAll();
return true;
}
const XFEvent * XFEventQueueDefault::front()
{
return queue_.front();
}
void XFEventQueueDefault::pop()
{
QMutexLocker locker(&mutex_);
queue_.dequeue();
}
bool XFEventQueueDefault::pend()
{
QMutexLocker locker(&mutex_);
// Wait for new events. Mutex needs to be in lock-state
// prior to call wait()!
newEvents_.wait(&mutex_);
return !queue_.isEmpty();
}
#endif // USE_XF_EVENT_QUEUE_DEFAULT_QT_IMPLEMENTATION

View File

@ -0,0 +1,45 @@
#ifndef XF_EVENT_QUEUE_DEFAULT_QT_H
#define XF_EVENT_QUEUE_DEFAULT_QT_H
#include "config/xf-config.h"
#if (USE_XF_EVENT_QUEUE_DEFAULT_QT_IMPLEMENTATION != 0)
#include <stdint.h>
#include <QMutex>
#include <QWaitCondition>
#include <QQueue>
#include "xf/interface/eventqueue.h"
/** @ingroup port_default_qt
* @{
*/
/**
* @brief Default Qt implementation for the XFEventQueue interface.
*/
class XFEventQueueDefault : public interface::XFEventQueue
{
public:
XFEventQueueDefault();
~XFEventQueueDefault() override;
// XFEventQueue interface implementation
public:
bool empty() const override; ///< Returns true if no event is in the queue.
bool push(const XFEvent * pEvent, bool fromISR = false) override; ///< Pushes the given event onto the queue. Returns false if the event could not be pushed.
const XFEvent * front() override; ///< Returns pointer to next event to pop.
void pop() override; ///< Pops the next event from the queue.
bool pend() override; ///< Wait for the next event to arrive. Returns true if an event is in the queue.
protected:
typedef QQueue<const XFEvent *> EventQueue; ///< Type of the event queue.
QMutex mutex_; ///< Mutex protecting access to _queue.
QWaitCondition newEvents_; ///< Wait condition to let thread wait until a new event arrives.
EventQueue queue_; ///< Internal queue holding the events.
};
/** @} */ // end of port_default_qt group
#endif // USE_XF_EVENT_QUEUE_DEFAULT_QT_IMPLEMENTATION
#endif // XF_EVENT_QUEUE_DEFAULT_QT_H

View File

@ -0,0 +1,31 @@
#include <cassert>
#include <config/xf-config.h>
#if (USE_XF_MUTEX_DEFAULT_QT_IMPLEMENTATION != 0)
#include "mutex-default.h"
/**
* @brief Implementation of interface::XFMutex::create method.
*/
interface::XFMutex * interface::XFMutex::create()
{
return new XFMutexDefault;
}
void XFMutexDefault::lock()
{
mutex_.lock();
}
void XFMutexDefault::unlock()
{
mutex_.unlock();
}
bool XFMutexDefault::tryLock(int32_t timeout /* = 0 */)
{
return mutex_.tryLock(timeout);
}
#endif // USE_XF_MUTEX_DEFAULT_QT_IMPLEMENTATION

View File

@ -0,0 +1,39 @@
#ifndef XF_MUTEX_DEFAULT_QT_H
#define XF_MUTEX_DEFAULT_QT_H
#include <config/xf-config.h>
#if (USE_XF_MUTEX_DEFAULT_QT_IMPLEMENTATION != 0)
#include <stdint.h>
#include <QMutex>
#include "xf/interface/mutex.h"
/** @ingroup port_default_qt
* @{
*/
/**
* @brief Default Qt implementation for the XFMutex interface.
*/
class XFMutexDefault : public interface::XFMutex
{
friend class XFResourceFactoryPort;
friend class interface::XFMutex;
public:
void lock() override;
void unlock() override;
bool tryLock(int32_t timeout = 0) override;
protected:
XFMutexDefault() = default; ///< Do not allow to directly create an object of this class. Call XFMutex::create() instead.
protected:
QMutex mutex_; ///< The real mutex.
};
/** @} */ // end of port_default_qt group
#endif // USE_XF_MUTEX_DEFAULT_QT_IMPLEMENTATION
#endif // XF_MUTEX_DEFAULT_QT_H

View File

@ -0,0 +1,6 @@
/** @defgroup port_default_qt Qt Platform Default Port Classes
*
* Qt platform default port classes.
*
*/

View File

@ -0,0 +1,41 @@
#include <config/xf-config.h>
#include "xf/interface/timeoutmanager.h"
#if (USE_XF_PORT_FUNCTIONS_DEFAULT_QT_IMPLEMENTATION != 0)
#include <QObject>
#include <QTimerEvent>
#include "port-functions.h"
static class TimeoutManagerTimer : public QObject
{
public:
TimeoutManagerTimer()
: _timerId(0)
{
}
void start(int32_t tickInterval)
{
Q_ASSERT(_timerId == 0); // Method should be called only once!
_timerId = startTimer(tickInterval, Qt::PreciseTimer);
}
void timerEvent(QTimerEvent * event) override
{
if (event->timerId() == _timerId)
{
interface::XFTimeoutManager::getInstance()->tick();
}
}
protected:
int32_t _timerId;
} timeoutManagerTimer;
void XF_startTimeoutManagerTimer(uint32_t tickInterval)
{
timeoutManagerTimer.start(int32_t(tickInterval));
}
#endif // USE_XF_PORT_FUNCTIONS_DEFAULT_QT_IMPLEMENTATION

View File

@ -0,0 +1,101 @@
#include <config/xf-config.h>
#if (USE_XF_THREAD_DEFAULT_QT_IMPLEMENTATION != 0)
#include <cassert>
#include <string.h>
#include "thread-default.h"
#if !defined(XFTHREAD_DEFAULT_STACK_SIZE)
#define XFTHREAD_DEFAULT_STACK_SIZE 256
#endif
XFThreadDefault::XFThreadDefault(interface::XFThreadEntryPointProvider * pProvider,
interface::XFThread::EntryMethodBody entryMethod,
const char * threadName,
const uint32_t stackSize /* = 0 */)
{
uint32_t threadStackSize = stackSize;
pEntryMethodProvider_ = pProvider;
entryMethod_ = entryMethod;
const QString name(threadName);
if (!name.isEmpty())
{
setObjectName(name);
}
if (threadStackSize == 0)
{
threadStackSize = XFTHREAD_DEFAULT_STACK_SIZE;
}
setStackSize(threadStackSize);
}
void XFThreadDefault::run()
{
// Call the entry point method with received provider
(this->pEntryMethodProvider_->*this->entryMethod_)(this);
}
void XFThreadDefault::start()
{
QThread::start();
}
void XFThreadDefault::stop()
{
QThread::terminate();
QThread::wait(); // Wait on thread to terminate
}
void XFThreadDefault::setPriority(XFThreadPriority priority)
{
auto prio = QThread::NormalPriority;
switch (priority)
{
case XF_THREAD_PRIO_LOW:
prio = QThread::LowPriority;
break;
case XF_THREAD_PRIO_HIGH:
prio = QThread::HighPriority;
break;
default:
break;
}
QThread::setPriority(prio);
}
XFThreadPriority XFThreadDefault::getPriority() const
{
const auto prio = QThread::priority();
XFThreadPriority priority = XF_THREAD_PRIO_UNKNOWN;
switch (prio)
{
case QThread::LowPriority:
priority = XF_THREAD_PRIO_LOW;
break;
case QThread::NormalPriority:
priority = XF_THREAD_PRIO_NORMAL;
break;
case QThread::HighPriority:
priority = XF_THREAD_PRIO_HIGH;
break;
default:
break;
}
return priority;
}
void XFThreadDefault::delay(uint32_t milliseconds)
{
QThread::msleep(milliseconds);
}
#endif // USE_XF_THREAD_DEFAULT_QT_IMPLEMENTATION

View File

@ -0,0 +1,61 @@
#ifndef XF_THREAD_DEFAULT_QT_H
#define XF_THREAD_DEFAULT_QT_H
#include <config/xf-config.h>
#if (USE_XF_THREAD_DEFAULT_QT_IMPLEMENTATION != 0)
#include <QThread>
#include <stdint.h>
#include "xf/interface/thread.h"
/** @ingroup port_default_qt
* @{
*/
/**
* @brief Default thread implementation for the IDF Qt port
*/
class XFThreadDefault : public QThread,
public interface::XFThread
{
friend class XFResourceFactoryPort;
// interface::Thread interface implementation
public:
void start() override;
void stop() override;
void setPriority(XFThreadPriority priority) override;
XFThreadPriority getPriority() const override;
void delay(uint32_t milliseconds) override;
protected:
/**
* @brief Protected XFThreadDefault constructor
* @param pProvider Instance providing the method to be executed by the thread.
* @param entryMethod Method to be executed by the Thread (usually containing a infinite loop).
* @param threadName Name of the thread.
* @param stackSize Stack size of the thread.
*
* Constructor is protected because only the XFResourceFactory interface
* based class (XFResourceFactoryPort) is allowed to created threads.
*/
XFThreadDefault(interface::XFThreadEntryPointProvider * pProvider,
interface::XFThread::EntryMethodBody entryMethod,
const char * threadName,
const uint32_t stackSize = 0);
// QThread interface implementation
protected:
void run() override; ///< Override of the QThread run method.
protected:
interface::XFThreadEntryPointProvider * pEntryMethodProvider_; ///< Pointer to object providing the entry method.
interface::XFThread::EntryMethodBody entryMethod_; ///< Entry method to be called/executed by the thread.
};
/** @} */ // end of port_default_qt group
#endif // USE_XF_THREAD_DEFAULT_QT_IMPLEMENTATION
#endif // XF_THREAD_DEFAULT_QT_H

View File

@ -0,0 +1,20 @@
INCLUDEPATH += $$PWD/..
# Path to default qt platform implementation of the XF port
DEFAULT_QT_PATH = $$PWD/../default-qt
INCLUDEPATH += \
"$${DEFAULT_QT_PATH}"
HEADERS += \
"$${DEFAULT_QT_PATH}/mutex-default.h" \
"$${DEFAULT_QT_PATH}/thread-default.h" \
"$${DEFAULT_QT_PATH}/eventqueue-default.h"
SOURCES += \
"$${DEFAULT_QT_PATH}/mutex-default.cpp" \
"$${DEFAULT_QT_PATH}/thread-default.cpp" \
"$${DEFAULT_QT_PATH}/eventqueue-default.cpp" \
"$${DEFAULT_QT_PATH}/port-functions.cpp" \
"$${DEFAULT_QT_PATH}/xf.cpp"

View File

@ -0,0 +1,70 @@
#include <config/xf-config.h>
#if (USE_XF_CLASS_DEFAULT_QT_IMPLEMENTATION != 0)
#include <QCoreApplication>
#include "xf/interface/timeoutmanager.h"
#include "xf/interface/resourcefactory.h"
#include "xf/interface/dispatcher.h"
#include "xf/xf.h"
using interface::XFResourceFactory;
/**
* In the Qt port we are going to use a QCoreApplication instance
* which gets executed by the XF::exec() method.
*
* The default dispatcher is active in this port implementation.
* This means, the default dispatcher has its own thread.
*
* The XF::execOnce() method is not applicable for this port.
*/
bool XF::isInitialized_ = false;
bool XF::isRunning_ = false;
static QCoreApplication & getApplication(int argc = 0, char * argv[] = nullptr)
{
static QCoreApplication app(argc, argv);
return app;
}
void XF::initialize(int timeInterval /* = 10 */, int argc /* = 0 */, char * argv[] /* = nullptr */)
{
if (!isInitialized_)
{
// Call getApplication() to create QT application instance
::getApplication(argc, argv);
// Create and initialize TimeoutManager
interface::XFTimeoutManager::getInstance()->initialize(timeInterval);
// Start it
interface::XFTimeoutManager::getInstance()->start();
isInitialized_ = true;
}
}
int XF::exec()
{
// Start default dispatcher
XFResourceFactory::getInstance()->getDefaultDispatcher()->start();
isRunning_ = true;
// Start Qt event loop
return ::getApplication().exec();
}
int XF::execOnce()
{
Q_ASSERT(false); // Not applicable for this port
return 0;
}
bool XF::isRunning()
{
return isRunning_;
}
#endif // USE_XF_CLASS_DEFAULT_QT_IMPLEMENTATION

View File

@ -0,0 +1,72 @@
# XF Default Port
This folder provides default implementations for some platform
indipendent XF classes.
You can use these classes to construct the XF needed.
If these classes do not suit your needs, they can be reimplemented for
your platform. Create an additional folder in the 'port' folder and
implement there the classes you need for your platform.
# Available Default Port Classes
| Class name | File location | Define to set |
|--|--|--|
| XF | xf/port/default/xf-default.cpp | USE_XF_DEFAULT_IMPLEMENTATION |
| XFResourceFactoryDefault | xf/port/default/resourcefactory-default.cpp | USE_XF_RESOURCE_FACTORY_DEFAULT_IMPLEMENTATION |
| XFTimeoutManagerDefault | xf/port/default/timeoutmanager-default.cpp | USE_XF_TIMEOUTMANAGER_DEFAULT_IMPLEMENTATION |
| XFDispatcherDefault | xf/port/default/dispatcher-default.cpp | USE_XF_DISPATCHER_DEFAULT_IMPLEMENTATION |
| XFDispatcherActiveDefault | xf/port/default/dispatcher-active.cpp | USE_XF_DISPATCHER_ACTIVE_DEFAULT_IMPLEMENTATION |
If you need more information about the classes mentioned above, please
have a look into their header files and the doxygen comments in code.
# Platform Dependend Default Port Classes
In the following folders you can pick some platform dependend
port classes:
| Platform | Folder |
|--|--|
| CMSIS-OS | [default-cmsis-os](../default-cmsis-os) |
| IDF | [default-idf](../default-idf) |
| QT | [default-qt](../default-qt) |
# Example _config/xf-config.h_ File
Following you will find some examples giving you a basic idea which define
to set in the application specific _config/xf-config.h_ file.
The _IDF Stm32Cube_ port uses quite all default implementations:
```c++
// Defines to set to use the IDF Stm32Cube port
#define USE_XF_DEFAULT_IMPLEMENTATION 1
#define USE_XF_DISPATCHER_DEFAULT_IMPLEMENTATION 1
#define USE_XF_TIMEOUTMANAGER_DEFAULT_IMPLEMENTATION 1
#define USE_XF_RESOURCE_FACTORY_DEFAULT_IMPLEMENTATION 1
#define USE_XF_MUTEX_DEFAULT_IDF_IMPLEMENTATION 1
#define USE_XF_EVENT_QUEUE_DEFAULT_IDF_IMPLEMENTATION 1
#define USE_XF_PORT_IDF_STM32CUBE_PORT_FUNCTIONS_IMPLEMENTATION 1
#include "default-idf/eventqueue-default.h"
#ifdef __cplusplus
using XFEventQueue = XFEventQueueDefault;
#endif // __cplusplus
```
If you want to build an XF on Windows, macOS or Linux use the _IDF Qt_ port.
Following defines need to be set in the application specific
_config/xf-config.h_ file:
```c++
// Defines to set to use the IDF Qt port
#define USE_XF_TIMEOUTMANAGER_DEFAULT_IMPLEMENTATION 1
#define USE_XF_DISPATCHER_ACTIVE_DEFAULT_IMPLEMENTATION 1
#define USE_XF_MUTEX_DEFAULT_QT_IMPLEMENTATION 1
#define USE_XF_THREAD_DEFAULT_QT_IMPLEMENTATION 1
#define USE_XF_PORT_IDF_QT_XF_IMPLEMENTATION 1
#define USE_XF_PORT_IDF_QT_RESOURCE_FACTORY_IMPLEMENTATION 1
#define USE_XF_PORT_IDF_QT_EVENT_QUEUE_IMPLEMENTATION 1
#define USE_XF_PORT_IDF_QT_PORT_FUNCTIONS_IMPLEMENTATION 1
#include "idf-qt/eventqueue.h"
```

Binary file not shown.

View File

@ -0,0 +1,139 @@
#include <config/xf-config.h>
#if (USE_XF_DISPATCHER_ACTIVE_DEFAULT_IMPLEMENTATION != 0)
#include <cassert>
#if defined(XF_TRACE_EVENT_PUSH_POP) && (XF_TRACE_EVENT_PUSH_POP != 0)
#include "trace/trace.h"
#endif // XF_TRACE_EVENT_PUSH_POP
#include "xf/eventstatus.h"
#include "xf/interface/timeoutmanager.h"
#include "xf/interface/reactive.h"
#include "xf/interface/thread.h"
#include "xf/interface/resourcefactory.h"
#include "dispatcher-active.h"
using interface::XFTimeoutManager;
using interface::XFResourceFactory;
using interface::XFReactive;
XFDispatcherActiveDefault::XFDispatcherActiveDefault() :
isExecuting_(false),
pThread_(nullptr)
{
// Create Thread
pThread_ = XFResourceFactory::getInstance()->createThread(this,
interface::XFThread::EntryMethodBody(&XFDispatcherActiveDefault::execute),
"dispatcherThread");
assert(pThread_);
}
XFDispatcherActiveDefault::~XFDispatcherActiveDefault()
{
isExecuting_ = false;
pThread_->stop();
if (pThread_)
{
delete pThread_;
}
}
void XFDispatcherActiveDefault::start()
{
assert(pThread_);
isExecuting_ = true;
pThread_->start();
}
void XFDispatcherActiveDefault::stop()
{
isExecuting_ = false;
pThread_->stop();
}
void XFDispatcherActiveDefault::pushEvent(XFEvent * pEvent, bool fromISR)
{
#if defined(XF_TRACE_EVENT_PUSH_POP) && (XF_TRACE_EVENT_PUSH_POP != 0)
Trace::out("Push event: 0x%x", pEvent);
#endif // XF_TRACE_EVENT_PUSH_POP
events_.push(pEvent, fromISR);
}
void XFDispatcherActiveDefault::scheduleTimeout(int timeoutId, int interval, interface::XFReactive * pReactive)
{
// Forward timeout to the timeout manager
XFTimeoutManager::getInstance()->scheduleTimeout(timeoutId, interval, pReactive);
}
void XFDispatcherActiveDefault::unscheduleTimeout(int timeoutId, interface::XFReactive * pReactive)
{
// Forward timeout to the timeout manager
XFTimeoutManager::getInstance()->unscheduleTimeout(timeoutId, pReactive);
}
int XFDispatcherActiveDefault::execute(const void * param /* = nullptr */)
{
(void)param;
while(isExecuting_)
{
while (events_.empty() && isExecuting_)
{
events_.pend(); // Wait until something to do
}
executeOnce();
}
return 0;
}
int XFDispatcherActiveDefault::executeOnce()
{
if (!events_.empty())
{
const XFEvent * pEvent;
// Deque next event from queue
pEvent = events_.front(); events_.pop();
#if defined(XF_TRACE_EVENT_PUSH_POP) && (XF_TRACE_EVENT_PUSH_POP != 0)
Trace::out("Pop event: 0x%x", pEvent);
#endif // XF_TRACE_EVENT_PUSH_POP
if (pEvent)
{
// Forward the event to the behavioral class
dispatchEvent(pEvent);
if (pEvent->getEventType() == XFEvent::Terminate)
{
// Exit the event loop
isExecuting_ = false;
}
if (pEvent->deleteAfterConsume())
{
// Remove the consumed event
delete pEvent;
}
}
}
return isExecuting_;
}
void XFDispatcherActiveDefault::dispatchEvent(const XFEvent * pEvent) const
{
XFReactive::TerminateBehavior terminateBehavior;
terminateBehavior = pEvent->getBehavior()->process(pEvent);
// Check if behavior should be deleted
if (terminateBehavior and pEvent->getBehavior()->deleteOnTerminate())
{
delete pEvent->getBehavior();
}
}
#endif // USE_XF_DISPATCHER_ACTIVE_DEFAULT_IMPLEMENTATION

View File

@ -0,0 +1,57 @@
#ifndef XF_DISPATCHER_ACTIVE_H
#define XF_DISPATCHER_ACTIVE_H
#include <config/xf-config.h>
#if (USE_XF_DISPATCHER_ACTIVE_DEFAULT_IMPLEMENTATION != 0)
#include "xf/interface/dispatcher.h"
#include "xf/interface/thread.h"
#include "xf/interface/mutex.h"
/*
* Please specify/include the XFEventQueuePort class in the xf-config file!
*/
/** @ingroup port_default
* @{
*/
/**
* @brief A dispatcher implementation which may be executed using an internal thread.
*
* The active dispatcher internally requests a Thread from the XFResourceFactory and
* starts it with the start() method. The thread itself is responsible to execute the
* protected method execute().
*/
class XFDispatcherActiveDefault : public interface::XFThreadEntryPointProvider,
public interface::XFDispatcher
{
public:
XFDispatcherActiveDefault();
~XFDispatcherActiveDefault() override;
bool isActive() const override { return (pThread_ != nullptr) ? true : false; }
void start() override;
void stop() override;
void pushEvent(XFEvent * pEvent, bool fromISR=false) override;
void scheduleTimeout(int timeoutId, int interval, interface::XFReactive * pReactive) override;
void unscheduleTimeout(int timeoutId, interface::XFReactive * pReactive) override;
int executeOnce() override;
protected:
int execute(const void * param = nullptr) override;
void dispatchEvent(const XFEvent * pEvent) const override;
protected:
bool isExecuting_; ///< True as long as the thread is executing the main loop.
interface::XFThread * pThread_; ///< Pointer to Thread executing the dispatcher.
XFEventQueue events_; ///< Thread-safe queue holding events waiting to get dispatched.
};
/** @} */ // end of port_default group
#endif // USE_XF_DISPATCHER_ACTIVE_DEFAULT_IMPLEMENTATION
#endif // XF_DISPATCHER_ACTIVE_H

View File

@ -0,0 +1,136 @@
#include <cassert>
#include <config/xf-config.h>
#if (USE_XF_DISPATCHER_DEFAULT_IMPLEMENTATION != 0)
#if (XF_TRACE_EVENT_PUSH_POP != 0)
#include "trace/trace.h"
#endif // XF_TRACE_EVENT_PUSH_POP
#include "xf/eventstatus.h"
#include "xf/interface/timeoutmanager.h"
#include "xf/interface/reactive.h"
#include "xf/interface/resourcefactory.h"
#include "dispatcher-default.h"
using interface::XFTimeoutManager;
using interface::XFResourceFactory;
using interface::XFReactive;
using interface::XFMutex;
XFDispatcherDefault::XFDispatcherDefault() :
_bExecuting(false),
_pMutex(nullptr)
{
_pMutex = XFMutex::create();
assert(_pMutex);
}
XFDispatcherDefault::~XFDispatcherDefault()
{
}
void XFDispatcherDefault::start()
{
assert(_pMutex);
_bExecuting = true;
}
void XFDispatcherDefault::stop()
{
_bExecuting = false;
}
void XFDispatcherDefault::pushEvent(XFEvent * pEvent, bool fromISR)
{
(void)fromISR;
_pMutex->lock();
{
#ifdef XF_TRACE_EVENT_PUSH_POP
Trace::out("Push event: 0x%x", pEvent);
#endif // XF_TRACE_EVENT_PUSH_POP
_events.push(pEvent);
}
_pMutex->unlock();
}
void XFDispatcherDefault::scheduleTimeout(int timeoutId, int interval, interface::XFReactive * pReactive)
{
// Forward timeout to the timeout manager
XFTimeoutManager::getInstance()->scheduleTimeout(timeoutId, interval, pReactive);
}
void XFDispatcherDefault::unscheduleTimeout(int timeoutId, interface::XFReactive * pReactive)
{
// Forward timeout to the timeout manager
XFTimeoutManager::getInstance()->unscheduleTimeout(timeoutId, pReactive);
}
int XFDispatcherDefault::execute(const void * param /* = nullptr */)
{
(void)param; // Parameter not used at the method
while(_bExecuting)
{
while (_events.empty() && _bExecuting)
{
continue; // Wait until something to do
}
executeOnce(); // Dispatch next event
}
return 0;
}
int XFDispatcherDefault::executeOnce()
{
if (!_events.empty() and _bExecuting)
{
const XFEvent * pEvent;
_pMutex->lock();
{
// Deque next event from queue
pEvent = _events.front(); _events.pop();
#ifdef XF_TRACE_EVENT_PUSH_POP
Trace::out("Pop event: 0x%x", pEvent);
#endif // XF_TRACE_EVENT_PUSH_POP
}
_pMutex->unlock();
if (pEvent)
{
// Forward the event to the behavioral class
dispatchEvent(pEvent);
if (pEvent->getEventType() == XFEvent::Terminate)
{
// Exit the event loop
_bExecuting = false;
}
if (pEvent->deleteAfterConsume())
{
// Remove the consumed event
delete pEvent;
}
}
}
return _bExecuting;
}
void XFDispatcherDefault::dispatchEvent(const XFEvent * pEvent) const
{
XFReactive::TerminateBehavior terminateBehavior;
terminateBehavior = pEvent->getBehavior()->process(pEvent);
// Check if behavior should be deleted
if (terminateBehavior and pEvent->getBehavior()->deleteOnTerminate())
{
delete pEvent->getBehavior();
}
}
#endif // USE_XF_DISPATCHER_DEFAULT_IMPLEMENTATION

View File

@ -0,0 +1,61 @@
#ifndef XF_DISPATCHER_DEFAULT_H
#define XF_DISPATCHER_DEFAULT_H
#include <config/xf-config.h>
#if (USE_XF_DISPATCHER_DEFAULT_IMPLEMENTATION != 0)
#include "xf/interface/dispatcher.h"
#include "xf/interface/mutex.h"
/*
* Please include the XFEventQueueDefault class in the xf-config file!
* Example: #include "default/eventqueue-default.h"
* and
* define the XFEventQueueDefault class as the class representing the
* XFEventQueue used by the dispatcher.
* Example: using XFEventQueue = XFEventQueueDefault;
*
* In case you want to provide you own event queue, you must implement
* your own XFEventQueue class and include the header file in the xf-config file.
*/
/** @ingroup port_default
* @{
*/
/**
* @brief A dispatcher implementation which can be used without an OS.
*
* The dispatcher can be used when an IDF on a bare-metal embedded system is needed.
*/
class XFDispatcherDefault : public interface::XFDispatcher
{
public:
XFDispatcherDefault();
virtual ~XFDispatcherDefault();
virtual bool isActive() const { return false; } ///< Default dispatcher does not have a composite thread.
virtual void start();
virtual void stop();
virtual void pushEvent(XFEvent * pEvent, bool fromISR=false);
virtual void scheduleTimeout(int timeoutId, int interval, interface::XFReactive * pReactive);
virtual void unscheduleTimeout(int timeoutId, interface::XFReactive * pReactive);
virtual int executeOnce();
virtual int execute(const void * param = nullptr);
protected:
virtual void dispatchEvent(const XFEvent * pEvent) const;
protected:
bool _bExecuting; ///< True as long as the thread is executing the main loop.
XFEventQueue _events; ///< Queue holding events waiting to get dispatched.
interface::XFMutex * _pMutex; ///< Mutex to protect event queue.
};
/** @} */ // end of port_default group
#endif // USE_XF_DISPATCHER_DEFAULT_IMPLEMENTATION
#endif // XF_DISPATCHER_DEFAULT_H

View File

@ -0,0 +1,6 @@
/** @defgroup port_default XF Default Port Classes
*
* XF default port classes.
*
*/

View File

@ -0,0 +1,51 @@
#include <config/xf-config.h>
#if (USE_XF_RESOURCE_FACTORY_DEFAULT_IMPLEMENTATION != 0)
#include "resourcefactory-default.h"
#include "mutex-default.h"
//static
interface::XFResourceFactory * interface::XFResourceFactory::getInstance()
{
return XFResourceFactoryDefault::getInstance();
}
//static
interface::XFResourceFactory * XFResourceFactoryDefault::getInstance()
{
static XFResourceFactoryDefault theResourceFactory;
return &theResourceFactory;
}
interface::XFDispatcher * XFResourceFactoryDefault::getDefaultDispatcher()
{
static XFDispatcherDefault mainDispatcher;
return &mainDispatcher;
}
interface::XFDispatcher * XFResourceFactoryDefault::createDispatcher()
{
// Default implementation cannot create new dispatcher. Return the default dispatcher
return getDefaultDispatcher();
}
interface::XFThread * XFResourceFactoryDefault::createThread(interface::XFThreadEntryPointProvider * pProvider,
interface::XFThread::EntryMethodBody entryMethod,
const char * threadName,
const uint32_t stackSize /* = 0 */)
{
// Default implementation cannot create threads (no underlying OS present)
return nullptr;
}
interface::XFMutex * XFResourceFactoryDefault::createMutex()
{
static XFMutexDefault mutex;
return &mutex;
}
#endif // USE_XF_RESOURCE_FACTORY_DEFAULT_IMPLEMENTATION

View File

@ -0,0 +1,39 @@
#ifndef XF_RESOURCE_FACTORY_DEFAULT_H
#define XF_RESOURCE_FACTORY_DEFAULT_H
#include <config/xf-config.h>
#if (USE_XF_RESOURCE_FACTORY_DEFAULT_IMPLEMENTATION != 0)
#include "xf/interface/resourcefactory.h"
#include "dispatcher-default.h"
/** @ingroup port_default
* @{
*/
/**
* @brief Default implementation of the XF resource factory.
*/
class XFResourceFactoryDefault : public interface::XFResourceFactory
{
public:
virtual ~XFResourceFactoryDefault() = default;
static interface::XFResourceFactory * getInstance(); ///< Returns a pointer to the unique instance of the XF resource factory.
virtual interface::XFDispatcher * getDefaultDispatcher(); ///< Returns the default dispatcher.
virtual interface::XFDispatcher * createDispatcher(); ///< Creates and returns a new dispatcher.
virtual interface::XFThread * createThread(interface::XFThreadEntryPointProvider * pProvider,
interface::XFThread::EntryMethodBody entryMethod,
const char * threadName,
const uint32_t stackSize = 0); ///< Creates and returns a new thread.
virtual interface::XFMutex * createMutex(); ///< Creates and returns a new mutex.
protected:
XFResourceFactoryDefault() = default;
};
/** @} */ // end of port_default group
#endif // USE_XF_RESOURCE_FACTORY_DEFAULT_IMPLEMENTATION
#endif // XF_RESOURCE_FACTORY_DEFAULT_H

View File

@ -0,0 +1,226 @@
#include <config/xf-config.h>
#if (USE_XF_TIMEOUTMANAGER_DEFAULT_IMPLEMENTATION != 0)
#include <cassert>
#include "xf/interface/reactive.h"
#include "xf/interface/mutex.h"
#include "port-functions.h"
#include "timeoutmanager-default.h"
using interface::XFMutex;
interface::XFTimeoutManager * interface::XFTimeoutManager::getInstance()
{
return XFTimeoutManagerDefault::getInstance();
}
interface::XFTimeoutManager * XFTimeoutManagerDefault::getInstance()
{
static XFTimeoutManagerDefault timeoutManager;
return &timeoutManager;
}
XFTimeoutManagerDefault::XFTimeoutManagerDefault() :
pMutex_(nullptr)
{
pMutex_ = XFMutex::create();
assert(pMutex_);
}
XFTimeoutManagerDefault::~XFTimeoutManagerDefault()
{
}
void XFTimeoutManagerDefault::start()
{
// Check tickInterval. Set default value if not set
if (tickInterval_ == 0)
{
tickInterval_ = 10;
}
XF_startTimeoutManagerTimer(uint32_t(tickInterval_));
}
void XFTimeoutManagerDefault::scheduleTimeout(int32_t timeoutId, int32_t interval, interface::XFReactive * pReactive)
{
XFTimeout * pTimeout = new XFTimeout(timeoutId, interval, pReactive);
if (pTimeout)
{
addTimeout(pTimeout);
}
}
void XFTimeoutManagerDefault::unscheduleTimeout(int32_t timeoutId, interface::XFReactive * pReactive)
{
const XFTimeout timeout(timeoutId, 0, pReactive);
XFTimeout * pTimeout;
pMutex_->lock();
{
for (TimeoutList::iterator i = timeouts_.begin();
i != timeouts_.end(); /*Do not increment here!*/)
{
pTimeout = *i;
// Check if behavior and timeout id are equal
if (*pTimeout == timeout)
{
TimeoutList::iterator next = i;
// Check if remaining ticks can be given further
if (++next != timeouts_.end())
{
// Add (remaining) ticks to next timeout in list
(*next)->addToRelTicks(pTimeout->getRelTicks());
}
i = timeouts_.erase(i);
// Iterator now points to the next element
delete pTimeout;
}
else
{
i++;
}
}
}
pMutex_->unlock();
}
void XFTimeoutManagerDefault::tick()
{
assert(tickInterval_); // Did you call start()?!
int32_t intervalToSubtract = tickInterval_;
while (!timeouts_.empty())
{
pMutex_->lock();
{
XFTimeout * pFirstTimeout = timeouts_.front();
// Subtract time elapsed
pFirstTimeout->substractFromRelTicks(intervalToSubtract);
// From now on set it to zero.
intervalToSubtract = 0;
// Check timeout timed out
if (pFirstTimeout->getRelTicks() <= 0)
{
// Check remaining ticks can be given further
if (timeouts_.size() > 1)
{
TimeoutList::iterator i = timeouts_.begin();
// Add ticks overrun to next timeout
i++;
(*i)->substractFromRelTicks(abs(pFirstTimeout->getRelTicks()));
}
// Inject the timeout back to the behavioral class
returnTimeout(pFirstTimeout);
// Remove timeout
timeouts_.pop_front();
// Check if timeouts with same timeout value are present
for (TimeoutList::iterator it = timeouts_.begin(); it != timeouts_.end(); /*Do not increment here!*/)
{
if ((*it)->getRelTicks() == 0)
{
returnTimeout(*it); // Return them true
it = timeouts_.erase(it); // Remove timeout and adjust iterator to next element
}
else
{
break;
}
}
}
else
{
pMutex_->unlock();
// Done. Exit while loop
break;
}
}
pMutex_->unlock();
}
}
void XFTimeoutManagerDefault::addTimeout(XFTimeout * pNewTimeout)
{
if (!timeouts_.empty())
{
pMutex_->lock();
{
// Insert timeout before timeout(s) triggering later
TimeoutList::iterator i = timeouts_.begin();
unsigned int index = 0;
// Find the right place to insert new timeout
while (i != timeouts_.end() &&
(*i)->getRelTicks() < pNewTimeout->getRelTicks())
{ // -> by: test4, test5
pNewTimeout->substractFromRelTicks((*i)->getRelTicks());
i++; index++;
}
if (i != timeouts_.end())
{
if ((*i)->getRelTicks() != pNewTimeout->getRelTicks())
{ // -> by: test1, test4, test5
// Timeout are going to timeout at different times
// Insert new timeout before
timeouts_.insert(i, pNewTimeout);
// Remove time from following timeout
(*i)->substractFromRelTicks(pNewTimeout->getRelTicks());
}
else
{ // -> by: test1, test5
const int32_t relTicks = (*i)->getRelTicks();
// Timeouts timeout at the same time. Put
// the new one behind the actual.
i++;
// Check if even more timeouts with the same timeout
while(i != timeouts_.end() && (*i)->getRelTicks() == 0)
{ // -> by: test5
i++;
}
// Insert new timeout behind actual
timeouts_.insert(i, pNewTimeout);
// Remove time from actual timeout
pNewTimeout->substractFromRelTicks(relTicks);
}
}
else
{ // -> by: test4, test5
// Add timeout at the end of the list
timeouts_.insert(timeouts_.end(), pNewTimeout);
}
}
pMutex_->unlock();
}
else
{ // -> by: test1, test2, test3, test4, test5
timeouts_.push_front(pNewTimeout);
}
}
void XFTimeoutManagerDefault::returnTimeout(XFTimeout * pTimeout)
{
pTimeout->getBehavior()->pushEvent(pTimeout);
}
#endif // USE_XF_TIMEOUTMANAGER_DEFAULT_IMPLEMENTATION

View File

@ -0,0 +1,53 @@
#ifndef XF_TIMEOUTMANAGER_DEFAULT_H
#define XF_TIMEOUTMANAGER_DEFAULT_H
#include <list>
#include <config/xf-config.h>
#if (USE_XF_TIMEOUTMANAGER_DEFAULT_IMPLEMENTATION != 0)
#include "xf/interface/timeoutmanager.h"
#include "xf/timeout.h"
#include "xf/interface/mutex.h"
/** @ingroup port_default
* @{
*/
/**
* @brief Default implementation of the XF TimeoutManager
*/
class XFTimeoutManagerDefault : public interface::XFTimeoutManager
{
friend interface::XFTimeoutManager * interface::XFTimeoutManager::getInstance();
public:
~XFTimeoutManagerDefault() override;
static interface::XFTimeoutManager * getInstance(); ///< Returns a pointer to the single instance of the class.
void start() override; ///< See interface::XFTimeoutManager
void scheduleTimeout(int32_t timeoutId, int32_t interval, interface::XFReactive * pReactive) override; ///< See interface::XFTimeoutManager
void unscheduleTimeout(int32_t timeoutId, interface::XFReactive * pReactive) override; ///< See interface::XFTimeoutManager
void tick() override; ///< See interface::XFTimeoutManager
protected:
XFTimeoutManagerDefault();
void addTimeout(XFTimeout * pNewTimeout) override; ///< Adds the timeout to #_timeouts.
/**
* Returns the timeout back to the queue of the thread executing
* the behavioral instance.
*/
void returnTimeout(XFTimeout * pTimeout); ///< Returns timeout back to behavioral class.
protected:
typedef std::list<XFTimeout *> TimeoutList; ///< Type used for the _timeouts property.
TimeoutList timeouts_; ///< Container holding timeouts to manage.
interface::XFMutex * pMutex_; ///< Mutex to protect access to TimeoutList.
};
/** @} */ // end of port_default group
#endif // USE_XF_TIMEOUTMANAGER_DEFAULT_IMPLEMENTATION
#endif // XF_TIMEOUTMANAGER_DEFAULT_H

View File

@ -0,0 +1,91 @@
#include <cassert>
#include <config/xf-config.h>
#if (USE_XF_DEFAULT_IMPLEMENTATION != 0)
#include "xf/interface/timeoutmanager.h"
#include "xf/interface/resourcefactory.h"
#include "xf/interface/dispatcher.h"
#include "xf/xf.h"
using interface::XFResourceFactory;
using interface::XFTimeoutManager;
bool XF::isInitialized_ = false;
bool XF::isRunning_ = false;
void XF_initialize(int timeInterval)
{
XF::initialize(timeInterval);
}
void XF_exec()
{
XF::exec();
}
void XF_execOnce()
{
XF::execOnce();
}
void XF::initialize(int timeInterval /* = 10 */, int argc /* = 0 */, char * argv[] /* = nullptr */)
{
if (!isInitialized_)
{
// Create and initialize TimeoutManager
XFTimeoutManager::getInstance()->initialize(timeInterval);
isInitialized_ = true;
}
}
int XF::exec()
{
// Start timeout manager
XFTimeoutManager::getInstance()->start();
// Start default dispatcher
XFResourceFactory::getInstance()->getDefaultDispatcher()->start();
isRunning_ = true; // From here the XF is running
// In case default dispatcher does not have a thread executing it,
// call it with this thread
if (!XFResourceFactory::getInstance()->getDefaultDispatcher()->isActive())
{
XFResourceFactory::getInstance()->getDefaultDispatcher()->execute();
}
return 0;
}
int XF::execOnce()
{
static bool usingExecOnce = false;
if (!usingExecOnce)
{
usingExecOnce = true;
// Start timeout manager
XFTimeoutManager::getInstance()->start();
// It makes no sense to call execOnce() with
// an active default dispatcher!
assert(!XFResourceFactory::getInstance()->getDefaultDispatcher()->isActive());
// Default dispatcher needs to be started explicitly
XFResourceFactory::getInstance()->getDefaultDispatcher()->start();
isRunning_ = true; // From here the XF is running
}
// Execute once the default dispatcher
return XFResourceFactory::getInstance()->getDefaultDispatcher()->executeOnce();
}
bool XF::isRunning()
{
return isRunning_;
}
#endif // USE_XF_DEFAULT_IMPLEMENTATION

View File

@ -0,0 +1,38 @@
# XF Port - IDF Qt
This port folder contains specific classes for the _IDF Qt_
XF port.
# Classes used by the _IDF Qt_ Port
| Class name | File location | Define to set |
|--|--|--|
| XFTimeoutManagerDefault | xf/port/default/timeoutmanager-default.cpp | USE_XF_TIMEOUTMANAGER_DEFAULT_IMPLEMENTATION |
| XFDispatcherActiveDefault | xf/port/default/dispatcher-active.cpp | USE_XF_DISPATCHER_ACTIVE_DEFAULT_IMPLEMENTATION |
| XFMutexDefault | xf/port/default-qt/mutex-default.cpp | USE_XF_MUTEX_DEFAULT_QT_IMPLEMENTATION |
| XFThreadDefault | xf/port/default-qt/thread-default.cpp | USE_XF_THREAD_DEFAULT_QT_IMPLEMENTATION |
| XF | xf/port/default-qt/xf.cpp | USE_XF_CLASS_DEFAULT_QT_IMPLEMENTATION |
| XFEventQueuePort | xf/port/default-qt/eventqueue.cpp | USE_XF_EVENT_QUEUE_DEFAULT_QT_IMPLEMENTATION |
| Port Functions | xf/port/default-qt/port-functions.cpp | USE_XF_PORT_FUNCTIONS_DEFAULT_QT_IMPLEMENTATION |
| XFResourceFactoryPort | xf/port/idf-qt/resourcefactory.cpp | USE_XF_PORT_IDF_QT_RESOURCE_FACTORY_IMPLEMENTATION |
# Example _config/xf-config.h_ File
```c++
// Defines to set to use the IDF Qt port
#define USE_XF_TIMEOUTMANAGER_DEFAULT_IMPLEMENTATION 1
#define USE_XF_DISPATCHER_ACTIVE_DEFAULT_IMPLEMENTATION 1
#define USE_XF_EVENT_QUEUE_DEFAULT_QT_IMPLEMENTATION 1
#define USE_XF_MUTEX_DEFAULT_QT_IMPLEMENTATION 1
#define USE_XF_THREAD_DEFAULT_QT_IMPLEMENTATION 1
#define USE_XF_CLASS_DEFAULT_QT_IMPLEMENTATION 1
#define USE_XF_PORT_FUNCTIONS_DEFAULT_QT_IMPLEMENTATION 1
#define USE_XF_PORT_IDF_QT_RESOURCE_FACTORY_IMPLEMENTATION 1
#include "default-qt/eventqueue-default.h"
#ifdef __cplusplus
// Force to take the XFEventQueueDefault implementation for the event queue
using XFEventQueue = XFEventQueueDefault;
#endif // __cplusplus
```

Binary file not shown.

View File

@ -0,0 +1,6 @@
/** @defgroup port_idf_qt IDF Qt Port Classes
*
* XF port classes for the `IDF Qt` port.
*
*/

View File

@ -0,0 +1,59 @@
#include <config/xf-config.h>
#if (USE_XF_PORT_IDF_QT_RESOURCE_FACTORY_IMPLEMENTATION != 0)
#include <QtGlobal>
#include "thread-default.h"
#include "default/dispatcher-active.h"
#include "xf/interface/mutex.h"
#include "resourcefactory.h"
using interface::XFMutex;
//static
interface::XFResourceFactory * interface::XFResourceFactory::getInstance()
{
return XFResourceFactoryPort::getInstance();
}
// static
interface::XFResourceFactory * XFResourceFactoryPort::getInstance()
{
static XFResourceFactoryPort theResourceFactory;
return &theResourceFactory;
}
interface::XFDispatcher * XFResourceFactoryPort::getDefaultDispatcher()
{
static XFDispatcherActiveDefault mainDispatcher;
return &mainDispatcher;
}
interface::XFDispatcher * XFResourceFactoryPort::createDispatcher()
{
// With an IDF implementation only one dispatcher is allowed. This
// prohibits to create new dispatchers. Return the default dispatcher.
return getDefaultDispatcher();
}
interface::XFThread * XFResourceFactoryPort::createThread(interface::XFThreadEntryPointProvider * pProvider,
interface::XFThread::EntryMethodBody entryMethod,
const char * threadName,
const uint32_t stackSize /* = 0 */)
{
// With an IDF implementation normaly only one thread is created and it handles
// all the XF related stuff. With the Qt based IDF, there is a dedicated thread needed
// which executes the XF. The primary thread (executing the main function) is
// needed to execute the QApplication instance (for timers, signals and slots).
//
// The method createThread() is only called once at XF initialization to provide
// the thread executing the XF.
return new XFThreadDefault(pProvider, entryMethod, threadName, stackSize);
}
interface::XFMutex * XFResourceFactoryPort::createMutex()
{
return XFMutex::create();
}
#endif // USE_XF_PORT_IDF_QT_RESOURCE_FACTORY_IMPLEMENTATION

View File

@ -0,0 +1,39 @@
#ifndef XF_PORT_IDF_QT_RESOURCE_FACTORY_H
#define XF_PORT_IDF_QT_RESOURCE_FACTORY_H
#include "config/xf-config.h"
#if (USE_XF_PORT_IDF_QT_RESOURCE_FACTORY_IMPLEMENTATION != 0)
/** @ingroup port_idf_qt
* @{
*/
#include "xf/interface/resourcefactory.h"
#include "xf/interface/dispatcher.h"
/**
* @brief XFResourceFactoryPort implementation for the IDF Qt port.
*/
class XFResourceFactoryPort : public interface::XFResourceFactory
{
public:
~XFResourceFactoryPort() override {}
static interface::XFResourceFactory * getInstance(); ///< Returns a pointer to the unique instance of the XF resource factory.
interface::XFDispatcher * getDefaultDispatcher() override; ///< Returns the default dispatcher.
interface::XFDispatcher * createDispatcher() override; ///< Creates and returns a new dispatcher.
interface::XFThread * createThread(interface::XFThreadEntryPointProvider * pProvider,
interface::XFThread::EntryMethodBody entryMethod,
const char * threadName,
const uint32_t stackSize = 0) override; ///< Creates and returns a new thread.
interface::XFMutex * createMutex() override; ///< Creates and returns a new mutex.
protected:
XFResourceFactoryPort() {}
};
/** @} */ // end of port_idf_qt group
#endif // USE_XF_PORT_IDF_QT_RESOURCE_FACTORY_IMPLEMENTATION
#endif // XF_PORT_IDF_QT_RESOURCE_FACTORY_H

View File

@ -0,0 +1,24 @@
#
# This PRI file takes only the classes needed from the
# 'default' port.
#
INCLUDEPATH += $$PWD/..
# Path to default implementation of the XF port
DEFAULT_IMPL_PATH = $$PWD/../default
DEFAULT_IMPL_SOURCES += \
"$${DEFAULT_IMPL_PATH}/timeoutmanager-default.cpp" \
"$${DEFAULT_IMPL_PATH}/dispatcher-active.cpp"
DEFAULT_IMPL_HEADERS += \
"$${DEFAULT_IMPL_PATH}/timeoutmanager-default.h" \
"$${DEFAULT_IMPL_PATH}/dispatcher-active.h"
SOURCES += \
$${DEFAULT_IMPL_SOURCES}$$
HEADERS += \
$${DEFAULT_IMPL_HEADERS}$$ \
"$$PWD/../port-functions.h"

View File

@ -0,0 +1,8 @@
INCLUDEPATH += $$PWD/..
SOURCES += \
"$$PWD/resourcefactory.cpp"
HEADERS += \
"$$PWD/resourcefactory.h"

View File

@ -0,0 +1,32 @@
# XF Port - IDF Stm32Cube
This port folder contains specific classes for the _IDF Stm32Cube_
XF port.
# Classes used by the _IDF Stm32Cube_ Port
| Class name | File location | Define to set |
|--|--|--|
| XF | xf/port/default/xf-default.cpp | USE_XF_DEFAULT_IMPLEMENTATION |
| XFDispatcherDefault | xf/port/default/dispatcher-default.cpp | USE_XF_DISPATCHER_DEFAULT_IMPLEMENTATION |
| XFTimeoutManagerDefault | xf/port/default/timeoutmanager-default.cpp | USE_XF_TIMEOUTMANAGER_DEFAULT_IMPLEMENTATION |
| XFResourceFactoryDefault | xf/port/default/resourcefactory-default.cpp | USE_XF_RESOURCE_FACTORY_DEFAULT_IMPLEMENTATION |
| XFMutexDefault | xf/port/default-idf/mutex-default.cpp | USE_XF_MUTEX_DEFAULT_IDF_IMPLEMENTATION |
| XFEventQueueDefault | xf/port/default-idf/eventqueue-default.cpp | USE_XF_EVENT_QUEUE_DEFAULT_IDF_IMPLEMENTATION |
| Port Functions | xf/port/idf-stm32cube/port-functions.cpp | USE_XF_PORT_IDF_STM32CUBE_PORT_FUNCTIONS_IMPLEMENTATION |
# Example _config/xf-config.h_ File
```c++
#define USE_XF_DEFAULT_IMPLEMENTATION 1
#define USE_XF_DISPATCHER_DEFAULT_IMPLEMENTATION 1
#define USE_XF_TIMEOUTMANAGER_DEFAULT_IMPLEMENTATION 1
#define USE_XF_RESOURCE_FACTORY_DEFAULT_IMPLEMENTATION 1
#define USE_XF_MUTEX_DEFAULT_IDF_IMPLEMENTATION 1
#define USE_XF_EVENT_QUEUE_DEFAULT_IDF_IMPLEMENTATION 1
#define USE_XF_PORT_IDF_STM32CUBE_PORT_FUNCTIONS_IMPLEMENTATION 1
#include "default-idf/eventqueue-default.h"
#ifdef __cplusplus
using XFEventQueue = XFEventQueueDefault;
#endif // __cplusplus
```

Binary file not shown.

View File

@ -0,0 +1,63 @@
#include <config/xf-config.h>
#if (USE_XF_PORT_IDF_STM32CUBE_PORT_FUNCTIONS_IMPLEMENTATION != 0)
#include <cassert>
#include "mcu/mcu.h"
#include "critical/critical.h"
#include "xf/xf.h"
#include "xf/interface/timeoutmanager.h"
#include "xf/port/port-functions.h"
using interface::XFTimeoutManager;
/**
* For this port the following port functions need to be implemented:
* - XF_startTimeoutManagerTimer()
* - XF_tick()
* - XF_tickIntervalInMilliseconds()
* In the XF_startTimeoutManagerTimer() function no code needs to
* be implemented because the SysTick peripheral is already initialized
* be the STM32CubeMX HAL.
* This means that changes in 'tickInterval' needs to be handled elsewhere
* using the XF_tickIntervalInMilliseconds() function.
*/
void XF_startTimeoutManagerTimer(uint32_t tickInterval)
{
(void)tickInterval;
// SysTick gets already started by the STM32CubeMX HAL.
// So nothing to do here.
}
/**
* SysTick_Handler() function is already implemented in the STM32CubeMX generated
* code (see Src/stm32fxxx_it.c file). Therefore, we must provide here a function
* which can be explicitly called in SysTick_Handler() to tick the XF.
*/
void XF_tick()
{
critical_setInIsr(true); // Tell critical section we are in an ISR
if (XF::isRunning()) // Call tick only if XF is running
{
XFTimeoutManager::getInstance()->tick(); // Call framework hook tick function
}
critical_setInIsr(false); // Tell critical section we are leaving the ISR
}
/**
* C function wrapping getTickInterval() method of XFTimeoutManager.
*/
int32_t XF_tickIntervalInMilliseconds()
{
return XFTimeoutManager::getInstance()->getTickInterval();
}
bool XF_isRunning()
{
return XF::isRunning();
}
#endif // USE_XF_PORT_IDF_STM32CUBE_PORT_FUNCTIONS_IMPLEMENTATION

View File

@ -0,0 +1,7 @@
/** @defgroup port_idf_stm32cube IDF STM32Cube Port Classes
*
* XF port classes for the `IDF STM32Cube` port.
*
* For the `IDF STM32Cube` port only default port classes are used.
*/

View File

@ -0,0 +1,44 @@
#ifndef XF_PORT_FUNCTIONS_H
#define XF_PORT_FUNCTIONS_H
#include <stdint.h>
#include <stdbool.h>
/**
* Following functions need to have "C" signature as they can be
* called in C (and C++).
*/
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief C function allowing to start the timer needed by the TimeoutManager instance.
*/
void XF_startTimeoutManagerTimer(uint32_t tickInterval);
/**
* @brief Must be called regularly in a timer ISR or software timer callback.
*
* The XF_tick() function must be called with the same interval given to the
* TimeoutManager (tickInterval).
*/
void XF_tick();
/**
* C function returning the tick interval in milliseconds with which the XF_tick()
* function should be called. This is the parameter given to the XF::init() method
* and may be different for each project.
*/
int32_t XF_tickIntervalInMilliseconds();
/**
* C function wrapping to XF::isRunning() method.
*/
bool XF_isRunning();
#ifdef __cplusplus
}
#endif
#endif // XF_PORT_FUNCTIONS_H

View File

@ -0,0 +1,27 @@
# XF Port - Stm32Cube CMSIS FreeRTOS
This port folder contains specific classes for the _Stm32Cube CMSIS FreeRTOS_
XF port.
# Classes used by the _Stm32Cube CMSIS FreeRTOS_ Port
| Class name | File location | Define to set |
|--|--|--|
| XFDispatcherActiveDefault | xf/port/default/dispatcher-active.cpp | USE_XF_DISPATCHER_ACTIVE_DEFAULT_IMPLEMENTATION |
| XFMutexDefault | xf/port/default-cmsis-os/mutex-default.cpp | USE_XF_MUTEX_DEFAULT_CMSIS_OS_IMPLEMENTATION |
| XFThreadDefault | xf/port/default-cmsis-os/thread-default.cpp | USE_XF_THREAD_DEFAULT_CMSIS_OS_IMPLEMENTATION |
| XFResourceFactoryPort | xf/port/stm32cube-cmsis-freertos/resourcefactory.cpp | USE_XF_PORT_STM32CUBE_CMSIS_FREERTOS_RESOURCE_FACTORY_IMPLEMENTATION |
| XFTimeoutManagerPort | xf/port/stm32cube-cmsis-freertos/timeoutmanager.cpp | USE_XF_PORT_STM32CUBE_CMSIS_FREERTOS_TIMEOUTMANAGER_IMPLEMENTATION |
| XFEventQueuePort | xf/port/stm32cube-cmsis-freertos/eventqueue.cpp | USE_XF_PORT_STM32CUBE_CMSIS_FREERTOS_EVENT_QUEUE_IMPLEMENTATION |
# Example _config/xf-config.h_ File
```c++
#define USE_XF_DISPATCHER_ACTIVE_DEFAULT_IMPLEMENTATION 1
#define USE_XF_MUTEX_DEFAULT_CMSIS_OS_IMPLEMENTATION 1
#define USE_XF_THREAD_DEFAULT_CMSIS_OS_IMPLEMENTATION 1
#define USE_XF_PORT_STM32CUBE_CMSIS_FREERTOS_RESOURCE_FACTORY_IMPLEMENTATION 1
#define USE_XF_PORT_STM32CUBE_CMSIS_FREERTOS_TIMEOUTMANAGER_IMPLEMENTATION 1
#define USE_XF_PORT_STM32CUBE_CMSIS_FREERTOS_EVENT_QUEUE_IMPLEMENTATION 1
#include "stm32cube-cmsis-freertos/eventqueue.h"
```

Binary file not shown.

View File

@ -0,0 +1,71 @@
#include <config/xf-config.h>
#if (USE_XF_PORT_STM32CUBE_CMSIS_FREERTOS_EVENT_QUEUE_IMPLEMENTATION != 0)
#include <cassert>
#include <croutine.h>
#include "queue.h"
#include "eventqueue.h"
XFEventQueuePort::XFEventQueuePort(const uint32_t queueSize /* = 8 */)
{
popedEvent = nullptr;
_queueId = osMessageQueueNew(queueSize, sizeof(XFEvent *), nullptr);
assert(_queueId);
}
XFEventQueuePort::~XFEventQueuePort()
{
osMessageQueueDelete(_queueId);
}
bool XFEventQueuePort::empty() const
{
return (osMessageQueueGetCount(_queueId) == 0);
}
bool XFEventQueuePort::push(const XFEvent * pEvent, bool fromISR)
{
if(fromISR){
BaseType_t pxHigherPriorityTaskWoken = false;
BaseType_t status = xQueueSendFromISR((QueueHandle_t)_queueId, &pEvent, &pxHigherPriorityTaskWoken);
return (status == pdPASS);
}
else{
const osStatus status = osMessageQueuePut(_queueId, &pEvent, 0, 100);
return (status == osOK);
}
}
XFEvent * XFEventQueuePort::front()
{
assert(!empty());
if(popedEvent==nullptr)
{
osStatus_t status = osMessageQueueGet(_queueId, &popedEvent, nullptr, 100);
assert(status == osStatus_t::osOK);
}
return popedEvent;
}
void XFEventQueuePort::pop()
{
if(popedEvent != nullptr)
{
popedEvent = nullptr;
}
else{
XFEvent * pEvent;
osMessageQueueGet(_queueId, &pEvent, nullptr, 0);
}
}
bool XFEventQueuePort::pend()
{
XFEvent * dummy;
return xQueuePeek(reinterpret_cast<QueueHandle_t>(_queueId), &dummy, 0xFFFFFFFFL);
}
#endif // USE_XF_PORT_STM32CUBE_CMSIS_FREERTOS_EVENT_QUEUE_IMPLEMENTATION

View File

@ -0,0 +1,35 @@
#ifndef XF_PORT_STM32CUBE_CMSIS_FREERTOS_EVENT_QUEUE_H
#define XF_PORT_STM32CUBE_CMSIS_FREERTOS_EVENT_QUEUE_H
#ifdef __cplusplus
#include <config/xf-config.h>
#if (USE_XF_PORT_STM32CUBE_CMSIS_FREERTOS_EVENT_QUEUE_IMPLEMENTATION != 0)
#include "xf/interface/eventqueue.h"
#include "cmsis_os.h"
class XFEventQueuePort : public interface::XFEventQueue
{
public:
XFEventQueuePort(const uint32_t queueSize = 8);
virtual ~XFEventQueuePort();
// XFEventQueue interface implementation
public:
virtual bool empty() const;
virtual bool push(const XFEvent * pEvent, bool fromISR = false);
virtual XFEvent * front();
virtual void pop();
virtual bool pend();
protected:
XFEvent * popedEvent; ///< Contain the last event after a front()
osMessageQId _queueId; ///< Unique identifier of the queue.
};
#endif // USE_XF_PORT_STM32CUBE_CMSIS_FREERTOS_EVENT_QUEUE_IMPLEMENTATION
#endif // __cplusplus
#endif // XF_PORT_STM32CUBE_CMSIS_FREERTOS_EVENT_QUEUE_H

View File

@ -0,0 +1,43 @@
#include <config/xf-config.h>
#if (USE_XF_PORT_STM32CUBE_CMSIS_FREERTOS_RESOURCE_FACTORY_IMPLEMENTATION != 0)
#include "thread-default.h"
#include "xf/interface/mutex.h"
#include "default/dispatcher-active.h"
#include "resourcefactory.h"
using interface::XFMutex;
//static
interface::XFResourceFactory * interface::XFResourceFactory::getInstance()
{
static XFResourceFactoryPort theResourceFactory;
return &theResourceFactory;
}
interface::XFDispatcher * XFResourceFactoryPort::getDefaultDispatcher()
{
static XFDispatcherActiveDefault mainDispatcher;
return &mainDispatcher;
}
interface::XFDispatcher * XFResourceFactoryPort::createDispatcher()
{
return new XFDispatcherActiveDefault;
}
interface::XFThread * XFResourceFactoryPort::createThread(interface::XFThreadEntryPointProvider * pProvider,
interface::XFThread::EntryMethodBody entryMethod,
const char * threadName,
const uint32_t stackSize /* = 0 */)
{
return new XFThreadDefault(pProvider, entryMethod, threadName, stackSize);
}
interface::XFMutex * XFResourceFactoryPort::createMutex()
{
return XFMutex::create();
}
#endif // USE_XF_PORT_STM32CUBE_CMSIS_FREERTOS_RESOURCE_FACTORY_IMPLEMENTATION

View File

@ -0,0 +1,28 @@
#ifndef XF_PORT_STM32CUBE_CMSIS_FREERTOS_RESOURCE_FACTORY_H
#define XF_PORT_STM32CUBE_CMSIS_FREERTOS_RESOURCE_FACTORY_H
#include <config/xf-config.h>
#if (USE_XF_PORT_STM32CUBE_CMSIS_FREERTOS_RESOURCE_FACTORY_IMPLEMENTATION != 0)
#include <stdint.h>
#include "xf/interface/resourcefactory.h"
#include "xf/interface/dispatcher.h"
class XFResourceFactoryPort : public interface::XFResourceFactory
{
public:
XFResourceFactoryPort() {}
virtual interface::XFDispatcher * getDefaultDispatcher();
virtual interface::XFDispatcher * createDispatcher();
virtual interface::XFThread * createThread(interface::XFThreadEntryPointProvider * pProvider,
interface::XFThread::EntryMethodBody entryMethod,
const char * threadName,
const uint32_t stackSize = 0);
virtual interface::XFMutex * createMutex();
protected:
};
#endif // USE_XF_PORT_STM32CUBE_CMSIS_FREERTOS_RESOURCE_FACTORY_IMPLEMENTATION
#endif // XF_PORT_STM32CUBE_CMSIS_FREERTOS_RESOURCE_FACTORY_H

View File

@ -0,0 +1,244 @@
#include <config/xf-config.h>
#if (USE_XF_PORT_STM32CUBE_CMSIS_FREERTOS_TIMEOUTMANAGER_IMPLEMENTATION != 0)
#include <cassert>
#include "xf/interface/reactive.h"
#include "timeoutmanager.h"
interface::XFTimeoutManager * interface::XFTimeoutManager::getInstance()
{
return XFTimeoutManagerPort::getInstance();
}
interface::XFTimeoutManager * XFTimeoutManagerPort::getInstance()
{
static XFTimeoutManagerPort timeoutManager;
return &timeoutManager;
}
XFTimeoutManagerPort::XFTimeoutManagerPort() :
_osTimerId(0)
{
_osTimerFunc = &XFTimeoutManagerPort::timerCallback;
_osTimerAttr.name="TimeoutManager";
_osTimerAttr.attr_bits=0;
_osTimerAttr.cb_mem=0;
_osTimerAttr.cb_size=0;
_osTimerId = osTimerNew(_osTimerFunc, osTimerPeriodic, this, &_osTimerAttr);
assert(_osTimerId); // You may need to enable timers in the FreeRTOS section of the STM32CubeMX project (USE_TIMERS = Enabled)
}
XFTimeoutManagerPort::~XFTimeoutManagerPort()
{
}
/*
* Gets called every #_tickInterval interval.
*/
//static
void XFTimeoutManagerPort::timerCallback(void * argument)
{
XFTimeoutManagerPort * const pThis = reinterpret_cast<XFTimeoutManagerPort * const>(argument);
pThis->tick(); // Call method handling timeouts
}
void XFTimeoutManagerPort::start()
{
// Check tickInterval. Set default value if not set
if (tickInterval_ == 0)
{
tickInterval_ = 10;
}
assert(_osTimerId); // Check existence of timer
osTimerStart(_osTimerId, tickInterval_); // Start OS timer
}
void XFTimeoutManagerPort::scheduleTimeout(int32_t timeoutId, int32_t interval, interface::XFReactive * pReactive)
{
XFTimeout * pTimeout = new XFTimeout(timeoutId, interval, pReactive);
if (pTimeout)
{
addTimeout(pTimeout);
}
}
void XFTimeoutManagerPort::unscheduleTimeout(int32_t timeoutId, interface::XFReactive * pReactive)
{
removeTimeouts(timeoutId, pReactive);
}
void XFTimeoutManagerPort::tick()
{
int32_t intervalToSubtract = tickInterval_;
while (!_timeouts.empty())
{
_mutex.lock();
{
XFTimeout * pFirstTimeout = _timeouts.front();
// Subtract time elapsed
pFirstTimeout->substractFromRelTicks(intervalToSubtract);
// From now on set it to zero.
intervalToSubtract = 0;
// Check timeout timed out
if (pFirstTimeout->getRelTicks() <= 0)
{
// Check remaining ticks can be given further
if (_timeouts.size() > 1)
{
TimeoutList::iterator i = _timeouts.begin();
// Add ticks overrun to next timeout
i++;
(*i)->substractFromRelTicks(abs(pFirstTimeout->getRelTicks()));
}
// Inject the timeout back to the behavioral class
returnTimeout(pFirstTimeout);
// Remove timeout
_timeouts.pop_front();
// Check if timeouts with same timeout value are present
for (TimeoutList::iterator it = _timeouts.begin(); it != _timeouts.end(); /*Do not increment here!*/)
{
if ((*it)->getRelTicks() == 0)
{
returnTimeout(*it); // Return them true
it = _timeouts.erase(it); // Remove timeout and adjust iterator to next element
}
else
{
break;
}
}
}
else
{
_mutex.unlock();
// Done. Exit while loop
break;
}
}
_mutex.unlock();
}
}
void XFTimeoutManagerPort::addTimeout(XFTimeout * pNewTimeout)
{
_mutex.lock();
{
if (!_timeouts.empty())
{
// Insert timeout before timeout(s) triggering later
TimeoutList::iterator i = _timeouts.begin();
unsigned int index = 0;
// Find the right place to insert new timeout
while (i != _timeouts.end() &&
(*i)->getRelTicks() < pNewTimeout->getRelTicks())
{ // -> by: test4, test5
pNewTimeout->substractFromRelTicks((*i)->getRelTicks());
i++; index++;
}
if (i != _timeouts.end())
{
if ((*i)->getRelTicks() != pNewTimeout->getRelTicks())
{ // -> by: test1, test4, test5
// Timeout are going to timeout at different times
// Insert new timeout before
_timeouts.insert(i, pNewTimeout);
// Remove time from following timeout
(*i)->substractFromRelTicks(pNewTimeout->getRelTicks());
}
else
{ // -> by: test1, test5
const int32_t relTicks = (*i)->getRelTicks();
// Timeouts timeout at the same time. Put
// the new one behind the actual.
i++;
// Check if even more timeouts with the same timeout
while(i != _timeouts.end() && (*i)->getRelTicks() == 0)
{ // -> by: test5
i++;
}
// Insert new timeout behind actual
_timeouts.insert(i, pNewTimeout);
// Remove time from actual timeout
pNewTimeout->substractFromRelTicks(relTicks);
}
}
else
{ // -> by: test4, test5
// Add timeout at the end of the list
_timeouts.insert(_timeouts.end(), pNewTimeout);
}
}
else
{ // -> by: test1, test2, test3, test4, test5
_timeouts.push_front(pNewTimeout);
}
}
_mutex.unlock();
}
void XFTimeoutManagerPort::removeTimeouts(int32_t timeoutId, interface::XFReactive * pReactive)
{
const XFTimeout timeout(timeoutId, 0, pReactive);
XFTimeout * pTimeout;
_mutex.lock();
{
for (TimeoutList::iterator i = _timeouts.begin();
i != _timeouts.end(); /*Do not increment here!*/)
{
pTimeout = *i;
// Check if behavior and timeout id are equal
if (*pTimeout == timeout)
{
TimeoutList::iterator next = i;
// Check if remaining ticks can be given further
if (++next != _timeouts.end())
{
// Add (remaining) ticks to next timeout in list
(*next)->addToRelTicks(pTimeout->getRelTicks());
}
i = _timeouts.erase(i);
// Iterator now points to the next element
delete pTimeout;
}
else
{
i++;
}
}
}
_mutex.unlock();
}
void XFTimeoutManagerPort::returnTimeout(XFTimeout * pTimeout)
{
pTimeout->getBehavior()->pushEvent(pTimeout);
}
#endif // USE_XF_PORT_STM32CUBE_CMSIS_FREERTOS_TIMEOUTMANAGER_IMPLEMENTATION

View File

@ -0,0 +1,60 @@
#ifndef XF_PORT_STM32CUBE_CMSIS_FREERTOS_TIMEOUTMANAGER_H
#define XF_PORT_STM32CUBE_CMSIS_FREERTOS_TIMEOUTMANAGER_H
#include <list>
#include <config/xf-config.h>
#if (USE_XF_PORT_STM32CUBE_CMSIS_FREERTOS_TIMEOUTMANAGER_IMPLEMENTATION != 0)
#include <cmsis_os.h>
#include "xf/interface/timeoutmanager.h"
#include "xf/timeout.h"
#include "mutex-default.h"
/**
* Default implementation of the XF TimeoutManager
*/
class XFTimeoutManagerPort : public interface::XFTimeoutManager
{
friend interface::XFTimeoutManager * interface::XFTimeoutManager::getInstance();
public:
virtual ~XFTimeoutManagerPort();
static interface::XFTimeoutManager * getInstance();
virtual void start();
virtual void scheduleTimeout(int32_t timeoutId, int32_t interval, interface::XFReactive * pReactive);
virtual void unscheduleTimeout(int32_t timeoutId, interface::XFReactive * pReactive);
virtual void tick();
protected:
XFTimeoutManagerPort();
virtual void addTimeout(XFTimeout * pNewTimeout); ///< Adds the timeout to #_timeouts.
/**
* Removes all timeouts corresponding the given parameters.
*/
virtual void removeTimeouts(int32_t timeoutId, interface::XFReactive * pReactive);
/**
* Returns the timeout back to the queue of the thread executing
* the behavioral instance.
*/
void returnTimeout(XFTimeout * pTimeout); ///< Returns timeout back to behavioral class.
static void timerCallback(void * argument); ///< Callback "function" needed by OS timer.
protected:
typedef std::list<XFTimeout *> TimeoutList; ///< Type used for the _timeouts property.
TimeoutList _timeouts; ///< Container holding timeouts to manage.
osTimerAttr_t _osTimerAttr; ///< Timer definition
osTimerFunc_t _osTimerFunc; ///< Variable containing the callback to tick()
osTimerId _osTimerId; ///< OS timer used to handle timeouts.
XFMutexDefault _mutex; ///< Mutex to protect the timeout list.
};
#endif // USE_XF_PORT_STM32CUBE_CMSIS_FREERTOS_TIMEOUTMANAGER_IMPLEMENTATION
#endif // XF_PORT_STM32CUBE_CMSIS_FREERTOS_TIMEOUTMANAGER_H

View File

@ -0,0 +1,72 @@
#include <config/xf-config.h>
#if (PORT_STM32CUBE_CMSIS_FREERTOS != 0)
#include <cassert>
#include <cmsis_os.h>
#include "xf/interface/timeoutmanager.h"
#include "xf/interface/resourcefactory.h"
#include "xf/interface/dispatcher.h"
#include "xf/xf.h"
using interface::XFTimeoutManager;
using interface::XFResourceFactory;
bool XF::isInitialized_ = false;
void XF_initialize(int timeInterval)
{
XF::initialize(timeInterval);
}
void XF_exec()
{
XF::exec();
}
void XF_execOnce()
{
XF::execOnce();
}
void XF::initialize(int timeInterval /* = 10 */, int argc /* = 0 */, char * argv[] /* = nullptr */)
{
if (!isInitialized_)
{
//osKernelInitialize();
// Create and initialize TimeoutManager
XFTimeoutManager::getInstance()->initialize(timeInterval);
isInitialized_ = true;
}
}
int XF::exec()
{
// Start timeout manager
XFTimeoutManager::getInstance()->start();
// Start default dispatcher
XFResourceFactory::getInstance()->getDefaultDispatcher()->start();
// Start RTOS if it is not already running.
// With STM32CubeMX, FreeRTOS and uGFX
// OS may already run at this stage!
if (osKernelGetState()!=osKernelRunning)
{
osKernelStart();
}
return 0;
}
int XF::execOnce()
{
assert(false); // Should not be called within the FreeRTOS based port! Call XF_exec() instead!
}
#endif // PORT_STM32CUBE_CMSIS_FREERTOS