-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
queue, active obect: split template to declaration and implementation…
…. Lift documentation. Add examples to docs
- Loading branch information
1 parent
d7b4557
commit aff9292
Showing
12 changed files
with
346 additions
and
235 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
#include "./active_object.h" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
/** | ||
* @file active_object.h | ||
* | ||
* @brief Active Object Design Pattern Implementation | ||
* | ||
* @details | ||
* The Active Object design pattern decouples method execution from method invocation. | ||
* This pattern provides a higher level of concurrency while keeping synchronization | ||
* simple. | ||
* | ||
* This implementation is built upon: | ||
* - An event-driven model where events are stored in a queue. | ||
* - A mechanism to dispatch and handle these events. | ||
* - State management to control the behavior and state transitions of the Active Object. | ||
* | ||
* Features: | ||
* - Uses a queue for event storage, ensuring that events are processed in a First-In-First-Out (FIFO) manner. | ||
* - Supports user-defined event types, state types, and additional fields - to store particular data. | ||
* - Provides mechanisms to dispatch events, transition between states, and process the event queue. | ||
* | ||
* This file provides the macros, data structures, and function prototypes required | ||
* to create and operate an Active Object. | ||
* | ||
* @see queue.h for the underlying queue implementation. | ||
* | ||
* @author apolisskyi | ||
*/ | ||
|
||
#ifndef ACTIVE_OBJECT_H | ||
#define ACTIVE_OBJECT_H | ||
|
||
#include <stdbool.h> | ||
#include <stdint.h> | ||
|
||
#include "../queue/queue.h" | ||
|
||
// TODO should we implement publish/subscribe? So we can have a list of subscriptions inside the object? | ||
// The main idea here is to resolve a situation when multiple objects consumes same event e.g. from ISR | ||
|
||
// TODO it seems that global superloop is kinda "scheduler" and we need there "isIdle" function to sleep on lack of events | ||
|
||
/** | ||
* @struct Struct for defining the Active Object | ||
* @param queue Queue to store events for the Active Object | ||
* @param id Base of the Active Object containing ID | ||
* @param state Current state of the Active Object | ||
* @param fields User-defined fields | ||
*/ | ||
|
||
/** | ||
* @fn void ACTIVE_OBJECT_T##_Ctor(ACTIVE_OBJECT_T *const self, uint8_t id, STATE_T initialState, FIELDS_T fields) | ||
* @brief Active Object Constructor | ||
* | ||
* @param self Pointer to the Active Object | ||
* @param initialState Initial state of the Active Object | ||
* @param fields User-defined fields | ||
* | ||
* @example Create a new active object: | ||
* MY_ACTIVE_OBJECT myObject; | ||
* MY_ACTIVE_OBJECT_Ctor(&myObject, 1, initialStateEnum, myFields); | ||
*/ | ||
|
||
/** | ||
* @fn void ACTIVE_OBJECT_T##_Dispatch(ACTIVE_OBJECT_T *const self, EVENT_T event); | ||
* @brief Dispatch an event to the Active Object | ||
* | ||
* @param self Pointer to the Active Object | ||
* @param event Event to be dispatched | ||
* | ||
* @example Dispatching an event to the active object: | ||
* MY_EVENT myEvent = { .sig=SOME_SIG }; | ||
* MY_ACTIVE_OBJECT_Dispatch(&myObject, myEvent); | ||
*/ | ||
|
||
/** | ||
* @fn bool ACTIVE_OBJECT_T##_basicTransitionToNextState(ACTIVE_OBJECT_T *const self, STATE_T nextState) | ||
* @brief Transition to the next state of the Active Object | ||
* | ||
* @param self Pointer to the Active Object | ||
* @param nextState Next state to transition to | ||
* | ||
* TODO should be improved, temporary inline, handle here exit -> enter -> traverse for states, implementing Mealy&Moore Hybrid FSM | ||
* | ||
* @example Transition to a new state: | ||
* MY_STATE newState = ...; | ||
* MY_ACTIVE_OBJECT_basicTransitionToNextState(&myObject, newState); | ||
*/ | ||
|
||
/** | ||
* @fn void ACTIVE_OBJECT_T##_ProcessQueue(ACTIVE_OBJECT_T *const self, EVENT_T##_HANDLER_F eventHandlerCb, STATE_T##_TRANSITION_F transitionToNextStateCb, ACTIVE_OBJECT_T##HAS_EMPTY_QUEUE_F hasEmptyQueueCb) | ||
* @brief Process the event queue of the Active Object | ||
* | ||
* @param self Pointer to the Active Object | ||
* @param eventHandlerCb Callback to handle queue event, returns next state | ||
* @param transitionToNextStateCb Callback to transition to the next state | ||
* @param hasEmptyQueueCb Callback to handle empty queue | ||
* | ||
* @example Processing the event queue: | ||
* MY_ACTIVE_OBJECT_ProcessQueue(&myObject, myEventHandler, myTransitionCb, myEmptyQueueHandler); \ | ||
*/ | ||
|
||
/** | ||
* @def Active object Template | ||
* | ||
* @param ACTIVE_OBJECT_T Active Object Type | ||
* @param EVENT_T Event Type | ||
* @param STATE_T State Type | ||
* @param FIELDS_T Active Object field Type | ||
* @param id ID value | ||
* @param maxQueueCapacity Queue capacity value | ||
* | ||
* @example DECLARE_ACTIVE_OBJECT(MY_ACTIVE_OBJECT, MY_EVENT, MY_STATE, MY_FIELDS, 16) | ||
*/ | ||
#define DECLARE_ACTIVE_OBJECT(ACTIVE_OBJECT_T, EVENT_T, STATE_T, FIELDS_T, maxQueueCapacity) \ | ||
DECLARE_QUEUE(EVENT_T, maxQueueCapacity); \ | ||
\ | ||
typedef struct { \ | ||
QUEUE_##EVENT_T queue; \ | ||
uint8_t id; \ | ||
STATE_T state; \ | ||
FIELDS_T fields; \ | ||
} ACTIVE_OBJECT_T; \ | ||
\ | ||
typedef STATE_T (*EVENT_T##_HANDLER_F)(ACTIVE_OBJECT_T *const self, EVENT_T event); \ | ||
typedef void (*ACTIVE_OBJECT_T##HAS_EMPTY_QUEUE_F)(ACTIVE_OBJECT_T *const self); \ | ||
typedef bool (*STATE_T##_TRANSITION_F)(ACTIVE_OBJECT_T *const self, STATE_T state); \ | ||
\ | ||
void ACTIVE_OBJECT_T##_Ctor(ACTIVE_OBJECT_T *const self, uint8_t id, STATE_T initialState, FIELDS_T fields); \ | ||
void ACTIVE_OBJECT_T##_Dispatch(ACTIVE_OBJECT_T *const self, EVENT_T event); \ | ||
bool ACTIVE_OBJECT_T##_basicTransitionToNextState(ACTIVE_OBJECT_T *const self, STATE_T nextState); \ | ||
void ACTIVE_OBJECT_T##_ProcessQueue(ACTIVE_OBJECT_T *const self, EVENT_T##_HANDLER_F eventHandlerCb, STATE_T##_TRANSITION_F transitionToNextStateCb, ACTIVE_OBJECT_T##HAS_EMPTY_QUEUE_F hasEmptyQueueCb); | ||
|
||
#endif //ACTIVE_OBJECT_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
#ifndef ACTIVE_OBJECT_IMPL_H | ||
#define ACTIVE_OBJECT_IMPL_H | ||
|
||
#include "./active_object.h" | ||
#include "../queue/queue_impl.h" | ||
|
||
#define ACTIVE_OBJECT_IMPLEMENTATION(ACTIVE_OBJECT_T, EVENT_T, STATE_T, FIELDS_T, maxQueueCapacity) \ | ||
QUEUE_IMPLEMENTATION(EVENT_T, maxQueueCapacity); \ | ||
\ | ||
void ACTIVE_OBJECT_T##_Ctor(ACTIVE_OBJECT_T *const self, uint8_t id, STATE_T initialState, FIELDS_T fields) { \ | ||
QUEUE_##EVENT_T##_Ctor(&self->queue); \ | ||
self->id = id; \ | ||
self->state = initialState; \ | ||
self->fields = fields; \ | ||
} \ | ||
\ | ||
void ACTIVE_OBJECT_T##_Dispatch(ACTIVE_OBJECT_T *const self, EVENT_T event) { \ | ||
if (QUEUE_##EVENT_T##_IsFull(&self->queue)) return; /* TODO Handle error, e.g., logging */ \ | ||
QUEUE_##EVENT_T##_Enqueue(&self->queue, event); \ | ||
} \ | ||
\ | ||
bool ACTIVE_OBJECT_T##_basicTransitionToNextState(ACTIVE_OBJECT_T *const self, STATE_T nextState) { \ | ||
self->state = nextState; \ | ||
return true; \ | ||
} \ | ||
\ | ||
void ACTIVE_OBJECT_T##_ProcessQueue(ACTIVE_OBJECT_T *const self, EVENT_T##_HANDLER_F eventHandlerCb, STATE_T##_TRANSITION_F transitionToNextStateCb, ACTIVE_OBJECT_T##HAS_EMPTY_QUEUE_F hasEmptyQueueCb) { \ | ||
bool isEmptyQueue = EMPTY_QUEUE == QUEUE_##EVENT_T##_GetSize(&self->queue); \ | ||
if (isEmptyQueue) return hasEmptyQueueCb(self); \ | ||
EVENT_T e = QUEUE_##EVENT_T##_Dequeue(&self->queue); \ | ||
STATE_T nextState = eventHandlerCb(self, e); \ | ||
transitionToNextStateCb(self, nextState); \ | ||
} | ||
|
||
#endif //ACTIVE_OBJECT_IMPL_H |
Oops, something went wrong.