Skip to content

Commit

Permalink
[0.29.0][r] timers support for std, glib dispatchers
Browse files Browse the repository at this point in the history
feat: timers support for std, glib dispatchers
feat: interrupts safety for Arduino dispatcher
  • Loading branch information
igor-krechetov committed Feb 4, 2023
1 parent 1ced650 commit 3623a8b
Show file tree
Hide file tree
Showing 44 changed files with 628 additions and 217 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/auto_tag.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ jobs:
repo_dir: ${{ env.GITHUB_WORKSPACE }}
commit_sha: ${{ github.event.workflow_run.head_sha }}

deploy-platformio-arduino:
create-release-tag:
runs-on: ubuntu-latest
needs: check-hsmcpp-version

# only run for successful build after push event
# avoid running this action on forks
if: ${{ (github.repository == 'igor-krechetov/hsmcpp') && (needs.check-hsmcpp-version.outputs.commit_version != '') && (needs.check-hsmcpp-version.outputs.commit_action == '[r]') && ((github.event.workflow_run == null) || ((github.event.workflow_run.conclusion == 'success') && (github.event.workflow_run.event == 'push'))) }}
if: ${{ (github.repository == 'igor-krechetov/hsmcpp') && (needs.check-hsmcpp-version.outputs.commit_version != '') && (needs.check-hsmcpp-version.outputs.commit_action == 'r') && ((github.event.workflow_run == null) || ((github.event.workflow_run.conclusion == 'success') && (github.event.workflow_run.event == 'push'))) }}

steps:
# need to checkout current repo because workflow is not related with push event
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/deploy-platformio.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ jobs:

- name: Publish PlatformIO package
# only publish release versions
if: ${{ needs.check-hsmcpp-version.outputs.commit_action == '[r]' }}
if: ${{ needs.check-hsmcpp-version.outputs.commit_action == 'r' }}
env:
PLATFORMIO_AUTH_TOKEN: ${{ secrets.PLATFORMIO_TOKEN }}
run: |
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ jobs:
lcov -r ./coverage.info /usr/include/\* . -o ./coverage.info
lcov -r ./coverage.info \*/build/\* . -o ./coverage.info
lcov -r ./coverage.info \*/tests/\* . -o ./coverage.info
lcov -r ./coverage.info \*/gcc_64/include/QtCore/\* . -o ./coverage.info
- name: Push test coverage to Coveralls
uses: coverallsapp/github-action@master
Expand Down
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
# Changelog
All notable changes to project will be documented in this file.

## [0.29.0] - 2023-02-03
### Added
- timers support for std, glib dispatchers
- interrupts safety for Arduino dispatcher

### Fixed
- std dispatcher didn't wake up when events were emited from interrupts

### Updated
- CriticalSection was renamed into InterruptsFreeSection
- added a new CriticalSection class

## [0.28.2] - 2023-02-02
### Fixed
- applied clang format to all code
Expand Down
27 changes: 14 additions & 13 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
cmake_minimum_required(VERSION 3.16)
project(hsmcpp)

set(PROJECT_VERSION "0.28.2")
set(PROJECT_VERSION "0.29.0")
set(PROJECT_DESCRIPTION "C++ library for hierarchical state machines / finite state machines. Provides a code-free visual approach for defining state machine logic using GUI editors with automatic code and diagram generation. Check out https://hsmcpp.readthedocs.io for detailed documentation.")
set(CMAKE_VERBOSE_MAKEFILE OFF)

Expand Down Expand Up @@ -76,7 +76,8 @@ set (LIBRARY_SRC ${HSM_SRC_ROOT}/hsm.cpp
${HSM_SRC_ROOT}/logging.cpp
${HSM_SRC_ROOT}/HsmEventDispatcherBase.cpp
${HSM_SRC_ROOT}/os/common/LockGuard.cpp
${HSM_SRC_ROOT}/os/common/UniqueLock.cpp)
${HSM_SRC_ROOT}/os/common/UniqueLock.cpp
${HSM_SRC_ROOT}/os/common/CriticalSection.cpp)

set (LIBRARY_HEADERS ${HSM_INCLUDES_ROOT}/hsm.hpp
${HSM_INCLUDES_ROOT}/HsmEventDispatcherBase.hpp
Expand All @@ -85,12 +86,15 @@ set (LIBRARY_HEADERS ${HSM_INCLUDES_ROOT}/hsm.hpp
${HSM_INCLUDES_ROOT}/variant.hpp
${HSM_INCLUDES_ROOT}/os/ConditionVariable.hpp
${HSM_INCLUDES_ROOT}/os/CriticalSection.hpp
${HSM_INCLUDES_ROOT}/os/InterruptsFreeSection.hpp
${HSM_INCLUDES_ROOT}/os/LockGuard.hpp
${HSM_INCLUDES_ROOT}/os/Mutex.hpp
${HSM_INCLUDES_ROOT}/os/os.hpp
${HSM_INCLUDES_ROOT}/os/UniqueLock.hpp
${HSM_INCLUDES_ROOT}/os/common/LockGuard.hpp
${HSM_INCLUDES_ROOT}/os/common/UniqueLock.hpp)
${HSM_INCLUDES_ROOT}/os/common/UniqueLock.hpp
${HSM_INCLUDES_ROOT}/os/common/CriticalSection.hpp
${HSM_INCLUDES_ROOT}/os/common/InterruptsFreeSection.hpp)

set(FILES_SCXML2GEN ${CMAKE_CURRENT_SOURCE_DIR}/tools/scxml2gen/scxml2gen.py
${CMAKE_CURRENT_SOURCE_DIR}/tools/scxml2gen/template.cpp
Expand All @@ -102,33 +106,32 @@ set(FILES_SCXML2GEN ${CMAKE_CURRENT_SOURCE_DIR}/tools/scxml2gen/scxml2gen.py
if (HSMBUILD_PLATFORM STREQUAL "freertos")
set (LIBRARY_SRC ${LIBRARY_SRC} ${HSM_SRC_ROOT}/os/freertos/Mutex.cpp
${HSM_SRC_ROOT}/os/freertos/ConditionVariable.cpp
${HSM_SRC_ROOT}/os/freertos/CriticalSection.cpp
${HSM_SRC_ROOT}/os/freertos/InterruptsFreeSection.cpp
${HSM_SRC_ROOT}/os/freertos/FreeRtosPort.cpp
${HSM_SRC_ROOT}/HsmEventDispatcherFreeRTOS.cpp)
set (LIBRARY_HEADERS ${LIBRARY_HEADERS} ${HSM_INCLUDES_ROOT}/os/freertos/ConditionVariable.hpp
${HSM_INCLUDES_ROOT}/os/freertos/CriticalSection.hpp
${HSM_INCLUDES_ROOT}/os/freertos/InterruptsFreeSection.hpp
${HSM_INCLUDES_ROOT}/os/freertos/FreeRTOSConfig.h
${HSM_INCLUDES_ROOT}/os/freertos/FreeRtosPort.hpp
${HSM_INCLUDES_ROOT}/os/freertos/Mutex.hpp
${HSM_INCLUDES_ROOT}/HsmEventDispatcherFreeRTOS.hpp)
elseif (HSMBUILD_PLATFORM STREQUAL "arduino")
set (LIBRARY_SRC ${LIBRARY_SRC} ${HSM_SRC_ROOT}/os/arduino/ConditionVariable.cpp
${HSM_SRC_ROOT}/os/arduino/CriticalSection.cpp
${HSM_SRC_ROOT}/os/arduino/InterruptsFreeSection.cpp
${HSM_SRC_ROOT}/HsmEventDispatcherArduino.cpp)
set (LIBRARY_HEADERS ${LIBRARY_HEADERS} ${HSM_INCLUDES_ROOT}/os/arduino/ConditionVariable.hpp
${HSM_INCLUDES_ROOT}/os/arduino/Mutex.hpp
${HSM_INCLUDES_ROOT}/HsmEventDispatcherArduino.hpp)
elseif (HSMBUILD_PLATFORM STREQUAL "posix")
set (LIBRARY_SRC ${LIBRARY_SRC} ${HSM_SRC_ROOT}/os/posix/CriticalSection.cpp
set (LIBRARY_SRC ${LIBRARY_SRC} ${HSM_SRC_ROOT}/os/posix/InterruptsFreeSection.cpp
${HSM_SRC_ROOT}/os/stl/ConditionVariable.cpp)
set (LIBRARY_HEADERS ${LIBRARY_HEADERS} ${HSM_INCLUDES_ROOT}/os/posix/CriticalSection.hpp
set (LIBRARY_HEADERS ${LIBRARY_HEADERS} ${HSM_INCLUDES_ROOT}/os/posix/InterruptsFreeSection.hpp
${HSM_INCLUDES_ROOT}/os/stl/ConditionVariable.hpp
${HSM_INCLUDES_ROOT}/os/stl/Mutex.hpp)
elseif (HSMBUILD_PLATFORM STREQUAL "windows")
set (LIBRARY_SRC ${LIBRARY_SRC} ${HSM_SRC_ROOT}/os/windows/CriticalSection.cpp
set (LIBRARY_SRC ${LIBRARY_SRC} ${HSM_SRC_ROOT}/os/windows/InterruptsFreeSection.cpp
${HSM_SRC_ROOT}/os/stl/ConditionVariable.cpp)
set (LIBRARY_HEADERS ${LIBRARY_HEADERS} ${HSM_INCLUDES_ROOT}/os/common/CriticalSection.hpp
${HSM_INCLUDES_ROOT}/os/stl/ConditionVariable.hpp
set (LIBRARY_HEADERS ${LIBRARY_HEADERS} ${HSM_INCLUDES_ROOT}/os/stl/ConditionVariable.hpp
${HSM_INCLUDES_ROOT}/os/stl/Mutex.hpp)
else()
message(FATAL_ERROR "Unsupported HSMBUILD_PLATFORM=${HSMBUILD_PLATFORM}")
Expand Down Expand Up @@ -218,8 +221,6 @@ elseif (HSMBUILD_TARGET STREQUAL "library")
# Build Dispatchers
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/dispatchers.cmake)

message("------ HSMCPP_STD_LIB=${HSMCPP_STD_LIB}")

# =============================================
# Build Examples and Tests
if (HSMBUILD_EXAMPLES)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/igor-krechetov/hsmcpp/blob/main/LICENSE)
[![Changelog](https://img.shields.io/badge/changelog-v0.28.2-green.svg)](https://github.com/igor-krechetov/hsmcpp/blob/main/CHANGELOG.md)
[![Changelog](https://img.shields.io/badge/changelog-v0.29.0-green.svg)](https://github.com/igor-krechetov/hsmcpp/blob/main/CHANGELOG.md)
[![Documentation Status](https://readthedocs.org/projects/hsmcpp/badge/?version=latest)](https://hsmcpp.readthedocs.io/en/latest/?badge=latest)
[![PlatformIO Registry](https://badges.registry.platformio.org/packages/igor-krechetov/library/hsmcpp.svg)](https://registry.platformio.org/libraries/igor-krechetov/hsmcpp)

Expand Down
68 changes: 68 additions & 0 deletions doc/diagrams/dispatchers/concurrent_signals.pu
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
@startuml
mode compact
scale 1 as 120 pixels

<style>
timingDiagram {
.thread1 {
BackgroundColor LightGreen
}
.thread2 {
BackgroundColor LightSalmon
}
}
</style>

concise "Thread 1" as T1 <<thread1>>
concise "Dispatcher Thread" as DT <<thread2>>
concise "Signal" as S <<thread1>>
concise "Mutex" as M
concise OS

@0
OS is "Block signals" #LightGreen
T1 is emitEvent

@+1
T1 -> M: lock
M is Locked #LightGreen

@+1
OS -> S: signal
S is blocked #red

@+1
T1 -> M: unlock
M is {-}

@+1
OS is {-}
T1 is {-}
T1 -> DT@+1: notify
S is emitEvent
M is Locked #LightSeaGreen

@+1
DT -> M@+1: lock
DT is blocked #red
OS is "Block signals" #LightSalmon

@+1
M is Locked #LightSalmon
S is {-}
DT is "Copy events"

@+1


@+1
M is {-}

@+1
OS is {-}
DT is "Call event handlers"

@+2
DT is {-}

@enduml
51 changes: 51 additions & 0 deletions doc/diagrams/dispatchers/concurrent_threads.pu
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
@startuml
mode compact
scale 1 as 100 pixels

<style>
timingDiagram {
.thread1 {
BackgroundColor LightGreen
}
.thread2 {
BackgroundColor LightSalmon
}
}
</style>

concise "Thread 1" as T1 <<thread1>>
concise "Dispatcher Thread" as DT <<thread2>>
concise "Signal" as S
concise "Mutex" as M

@0
M is Locked #LightGreen
T1 is emitEvent

@+1
T1 -> DT@+1: notify
M is {-}
T1 is {-}

@+1
M is Locked #LightSalmon
DT is "Copy events"

@3
T1 is blocked #red
@+1
T1 is emitEvent
M is Locked #LightGreen
@+1
T1 -> DT: notify
T1 is {-}
M is {-}

@4
M is {-}
DT is "Call event handlers"

@+3
DT is {-}

@enduml
15 changes: 5 additions & 10 deletions include/hsmcpp/HsmEventDispatcherArduino.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,14 @@ namespace hsmcpp

class HsmEventDispatcherArduino: public HsmEventDispatcherBase
{
struct EnqueuedEventInfo
{
HandlerID_t handlerID;
EventID_t eventID;
};

struct RunningTimerInfo
{
unsigned long startedAt;// time when timer was started (ms)
unsigned long elapseAfter;// time when timer should elapse next time (ms)
unsigned long startedAt;// monotonic time when timer was started (ms)
unsigned long elapseAfter;// monotonic time when timer should elapse next time (ms)
};

public:
HsmEventDispatcherArduino(const size_t eventsCacheSize=32);
explicit HsmEventDispatcherArduino(const size_t eventsCacheSize = DISPATCHER_DEFAULT_EVENTS_CACHESIZE);
virtual ~HsmEventDispatcherArduino();

bool start() override;
Expand All @@ -37,6 +31,8 @@ class HsmEventDispatcherArduino: public HsmEventDispatcherBase
void dispatchEvents();

protected:
void notifyDispatcherAboutEvent() override;

void startTimerImpl(const TimerID_t timerID, const unsigned int intervalMs, const bool isSingleShot) override;
void stopTimerImpl(const TimerID_t timerID) override;

Expand All @@ -45,7 +41,6 @@ class HsmEventDispatcherArduino: public HsmEventDispatcherBase
private:
bool mStopDispatcher = false;
std::map<TimerID_t, RunningTimerInfo> mRunningTimers;
std::vector<EnqueuedEventInfo> mEnqueuedEvents;
};

} // namespace hsmcpp
Expand Down
5 changes: 5 additions & 0 deletions include/hsmcpp/HsmEventDispatcherBase.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ class HsmEventDispatcherBase: public IHsmEventDispatcher
};

public:
/**
* Constructor for FreeRTOS based event dispatcher.
* @param eventsCacheSize size of the queue preallocated for delayed events
*/
// NOTE: false positive. setting default parameter value is not parameter modification
// cppcheck-suppress misra-c2012-17.8
HsmEventDispatcherBase(const size_t eventsCacheSize = DISPATCHER_DEFAULT_EVENTS_CACHESIZE);
Expand Down Expand Up @@ -97,6 +101,7 @@ class HsmEventDispatcherBase: public IHsmEventDispatcher
std::vector<EnqueuedEventInfo> mEnqueuedEvents;
Mutex mEmitSync;
Mutex mHandlersSync;
Mutex mEnqueuedEventsSync;
};

}// namespace hsmcpp
Expand Down
3 changes: 2 additions & 1 deletion include/hsmcpp/HsmEventDispatcherFreeRTOS.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ class HsmEventDispatcherFreeRTOS: public HsmEventDispatcherBase
* @param eventsCacheSize size of the queue preallocated for delayed events
*/
HsmEventDispatcherFreeRTOS(const configSTACK_DEPTH_TYPE stackDepth = configMINIMAL_STACK_SIZE,
const UBaseType_t priority = tskIDLE_PRIORITY);
const UBaseType_t priority = tskIDLE_PRIORITY,
const size_t eventsCacheSize = DISPATCHER_DEFAULT_EVENTS_CACHESIZE);
virtual ~HsmEventDispatcherFreeRTOS();

virtual void emitEvent(const HandlerID_t handlerID) override;
Expand Down
17 changes: 15 additions & 2 deletions include/hsmcpp/HsmEventDispatcherGLib.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,34 @@
#include "HsmEventDispatcherBase.hpp"
#include <glib.h>
#include <condition_variable>
#include <map>

namespace hsmcpp
{

class HsmEventDispatcherGLib: public HsmEventDispatcherBase
{
private:
using TimerData_t = std::pair<HsmEventDispatcherGLib*, TimerID_t>;

public:
HsmEventDispatcherGLib();
explicit HsmEventDispatcherGLib(GMainContext* context);
explicit HsmEventDispatcherGLib(const size_t eventsCacheSize = DISPATCHER_DEFAULT_EVENTS_CACHESIZE);
HsmEventDispatcherGLib(GMainContext* context, const size_t eventsCacheSize = DISPATCHER_DEFAULT_EVENTS_CACHESIZE);
virtual ~HsmEventDispatcherGLib();

virtual void emitEvent(const HandlerID_t handlerID) override;

virtual bool start() override;

private:
void unregisterAllTimerHandlers();

void startTimerImpl(const TimerID_t timerID, const unsigned int intervalMs, const bool isSingleShot) override;
void stopTimerImpl(const TimerID_t timerID) override;

static gboolean onTimerEvent(const TimerData_t* timerData);
static void onFreeTimerData(void* timerData);

void notifyDispatcherAboutEvent() override;
static gboolean onPipeDataAvailable(GIOChannel* gio, GIOCondition condition, gpointer data);

Expand All @@ -36,6 +48,7 @@ class HsmEventDispatcherGLib: public HsmEventDispatcherBase
bool mDispatchingIterationRunning = false;
std::mutex mDispatchingSync;
std::condition_variable mDispatchingDoneEvent;
std::map<TimerID_t, GSource*> mNativeTimerHandlers;// <timerID, nativeTimerID>
};

} // namespace hsmcpp
Expand Down
4 changes: 2 additions & 2 deletions include/hsmcpp/HsmEventDispatcherGLibmm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ namespace hsmcpp
class HsmEventDispatcherGLibmm: public HsmEventDispatcherBase
{
public:
HsmEventDispatcherGLibmm();
explicit HsmEventDispatcherGLibmm(const Glib::RefPtr<Glib::MainContext>& context);
explicit HsmEventDispatcherGLibmm(const size_t eventsCacheSize = DISPATCHER_DEFAULT_EVENTS_CACHESIZE);
HsmEventDispatcherGLibmm(const Glib::RefPtr<Glib::MainContext>& context, const size_t eventsCacheSize = DISPATCHER_DEFAULT_EVENTS_CACHESIZE);
virtual ~HsmEventDispatcherGLibmm();

virtual bool start() override;
Expand Down

0 comments on commit 3623a8b

Please sign in to comment.