mirror of
https://git.intern.spaceteamaachen.de/ALPAKA/TACOS.git
synced 2025-06-12 01:25:59 +00:00
Merge pull request 'statemachine-rework' (#10) from statemachine-rework into main
Reviewed-on: https://git.intern.spaceteamaachen.de/ALPAKA/TACOS/pulls/10 Reviewed-by: carlwachter <carlwachter@noreply.git.intern.spaceteamaachen.de>
This commit is contained in:
commit
f73cd47215
@ -25,6 +25,7 @@
|
|||||||
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.target_board.1523528544" name="Board" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.target_board" useByScannerDiscovery="false" value="genericBoard" valueType="string"/>
|
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.target_board.1523528544" name="Board" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.target_board" useByScannerDiscovery="false" value="genericBoard" valueType="string"/>
|
||||||
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.defaults.1559967274" name="Defaults" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.defaults" useByScannerDiscovery="false" value="com.st.stm32cube.ide.common.services.build.inputs.revA.1.0.6 || Debug || true || Executable || com.st.stm32cube.ide.mcu.gnu.managedbuild.option.toolchain.value.workspace || STM32F411RETx || 0 || 0 || arm-none-eabi- || ${gnu_tools_for_stm32_compiler_path} || ../Core/Inc | ../Drivers/STM32F4xx_HAL_Driver/Inc | ../Drivers/STM32F4xx_HAL_Driver/Inc/Legacy | ../Drivers/CMSIS/Device/ST/STM32F4xx/Include | ../Drivers/CMSIS/Include | ../Middlewares/Third_Party/FreeRTOS/Source/include | ../Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2 | ../Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F || || || USE_HAL_DRIVER | STM32F411xE || || Drivers | Core/Startup | Middlewares | Core || || || ${workspace_loc:/${ProjName}/STM32F411RETX_FLASH.ld} || true || NonSecure || || secure_nsclib.o || || None || || || " valueType="string"/>
|
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.defaults.1559967274" name="Defaults" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.defaults" useByScannerDiscovery="false" value="com.st.stm32cube.ide.common.services.build.inputs.revA.1.0.6 || Debug || true || Executable || com.st.stm32cube.ide.mcu.gnu.managedbuild.option.toolchain.value.workspace || STM32F411RETx || 0 || 0 || arm-none-eabi- || ${gnu_tools_for_stm32_compiler_path} || ../Core/Inc | ../Drivers/STM32F4xx_HAL_Driver/Inc | ../Drivers/STM32F4xx_HAL_Driver/Inc/Legacy | ../Drivers/CMSIS/Device/ST/STM32F4xx/Include | ../Drivers/CMSIS/Include | ../Middlewares/Third_Party/FreeRTOS/Source/include | ../Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2 | ../Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F || || || USE_HAL_DRIVER | STM32F411xE || || Drivers | Core/Startup | Middlewares | Core || || || ${workspace_loc:/${ProjName}/STM32F411RETX_FLASH.ld} || true || NonSecure || || secure_nsclib.o || || None || || || " valueType="string"/>
|
||||||
<option id="com.st.stm32cube.ide.mcu.debug.option.cpuclock.1388963198" name="Cpu clock frequence" superClass="com.st.stm32cube.ide.mcu.debug.option.cpuclock" useByScannerDiscovery="false" value="16" valueType="string"/>
|
<option id="com.st.stm32cube.ide.mcu.debug.option.cpuclock.1388963198" name="Cpu clock frequence" superClass="com.st.stm32cube.ide.mcu.debug.option.cpuclock" useByScannerDiscovery="false" value="16" valueType="string"/>
|
||||||
|
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.nanoprintffloat.2054601156" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.nanoprintffloat" value="true" valueType="boolean"/>
|
||||||
<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="com.st.stm32cube.ide.mcu.gnu.managedbuild.targetplatform.682707397" isAbstract="false" osList="all" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.targetplatform"/>
|
<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="com.st.stm32cube.ide.mcu.gnu.managedbuild.targetplatform.682707397" isAbstract="false" osList="all" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.targetplatform"/>
|
||||||
<builder buildPath="${workspace_loc:/TACOS}/Debug" id="com.st.stm32cube.ide.mcu.gnu.managedbuild.builder.1663759602" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" parallelBuildOn="true" parallelizationNumber="optimal" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.builder"/>
|
<builder buildPath="${workspace_loc:/TACOS}/Debug" id="com.st.stm32cube.ide.mcu.gnu.managedbuild.builder.1663759602" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" parallelBuildOn="true" parallelizationNumber="optimal" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.builder"/>
|
||||||
<tool id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler.1268227203" name="MCU GCC Assembler" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler">
|
<tool id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler.1268227203" name="MCU GCC Assembler" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler">
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
|
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
|
||||||
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
|
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
|
||||||
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
|
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
|
||||||
<provider class="com.st.stm32cube.ide.mcu.toolchain.armnone.setup.CrossBuiltinSpecsDetector" console="false" env-hash="1090266248531783773" id="com.st.stm32cube.ide.mcu.toolchain.armnone.setup.CrossBuiltinSpecsDetector" keep-relative-paths="false" name="MCU ARM GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true">
|
<provider class="com.st.stm32cube.ide.mcu.toolchain.armnone.setup.CrossBuiltinSpecsDetector" console="false" env-hash="1366383323889271194" id="com.st.stm32cube.ide.mcu.toolchain.armnone.setup.CrossBuiltinSpecsDetector" keep-relative-paths="false" name="MCU ARM GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true">
|
||||||
<language-scope id="org.eclipse.cdt.core.gcc"/>
|
<language-scope id="org.eclipse.cdt.core.gcc"/>
|
||||||
<language-scope id="org.eclipse.cdt.core.g++"/>
|
<language-scope id="org.eclipse.cdt.core.g++"/>
|
||||||
</provider>
|
</provider>
|
||||||
@ -16,7 +16,7 @@
|
|||||||
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
|
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
|
||||||
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
|
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
|
||||||
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
|
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
|
||||||
<provider class="com.st.stm32cube.ide.mcu.toolchain.armnone.setup.CrossBuiltinSpecsDetector" console="false" env-hash="1090266248531783773" id="com.st.stm32cube.ide.mcu.toolchain.armnone.setup.CrossBuiltinSpecsDetector" keep-relative-paths="false" name="MCU ARM GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true">
|
<provider class="com.st.stm32cube.ide.mcu.toolchain.armnone.setup.CrossBuiltinSpecsDetector" console="false" env-hash="1366383323889271194" id="com.st.stm32cube.ide.mcu.toolchain.armnone.setup.CrossBuiltinSpecsDetector" keep-relative-paths="false" name="MCU ARM GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true">
|
||||||
<language-scope id="org.eclipse.cdt.core.gcc"/>
|
<language-scope id="org.eclipse.cdt.core.gcc"/>
|
||||||
<language-scope id="org.eclipse.cdt.core.g++"/>
|
<language-scope id="org.eclipse.cdt.core.g++"/>
|
||||||
</provider>
|
</provider>
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
#define STA_TACOS_STATEMACHINE_PRIORITY osPriorityNormal
|
#define STA_TACOS_STATEMACHINE_PRIORITY osPriorityNormal
|
||||||
|
|
||||||
// Statemachine settings. Here, we only have a single state which is also the initial state.
|
// Statemachine settings. Here, we only have a single state which is also the initial state.
|
||||||
#define STA_TACOS_NUM_STATES 1
|
#define STA_TACOS_NUM_STATES 3
|
||||||
#define STA_TACOS_INITIAL_STATE 0
|
#define STA_TACOS_INITIAL_STATE 0
|
||||||
|
|
||||||
#endif /* INC_STA_CONFIG_HPP_ */
|
#endif /* INC_STA_CONFIG_HPP_ */
|
||||||
|
26
App/Inc/tasks/disturb.hpp
Normal file
26
App/Inc/tasks/disturb.hpp
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* disturb.hpp
|
||||||
|
*
|
||||||
|
* Created on: Nov 20, 2023
|
||||||
|
* Author: Dario
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INC_TASKS_DISTURB_HPP_
|
||||||
|
#define INC_TASKS_DISTURB_HPP_
|
||||||
|
|
||||||
|
#include <sta/tacos/thread.hpp>
|
||||||
|
|
||||||
|
namespace demo
|
||||||
|
{
|
||||||
|
class DisturbTask : public sta::tacos::TacosThread {
|
||||||
|
public:
|
||||||
|
DisturbTask();
|
||||||
|
|
||||||
|
void init() override;
|
||||||
|
|
||||||
|
void func() override;
|
||||||
|
};
|
||||||
|
} // namespace demo
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* INC_TASKS_DISTURB_HPP_ */
|
@ -15,7 +15,6 @@ namespace demo
|
|||||||
class DummyTask : public sta::tacos::TacosThread {
|
class DummyTask : public sta::tacos::TacosThread {
|
||||||
public:
|
public:
|
||||||
DummyTask(const char* name);
|
DummyTask(const char* name);
|
||||||
~DummyTask() override;
|
|
||||||
|
|
||||||
void init() override;
|
void init() override;
|
||||||
|
|
||||||
|
26
App/Inc/tasks/toggle.hpp
Normal file
26
App/Inc/tasks/toggle.hpp
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* toggle.hpp
|
||||||
|
*
|
||||||
|
* Created on: Nov 10, 2023
|
||||||
|
* Author: Dario
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INC_STA_TOGGLE_HPP_
|
||||||
|
#define INC_STA_TOGGLE_HPP_
|
||||||
|
|
||||||
|
#include <sta/tacos/thread.hpp>
|
||||||
|
|
||||||
|
namespace demo
|
||||||
|
{
|
||||||
|
class Toggle : public sta::tacos::TacosThread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Toggle();
|
||||||
|
|
||||||
|
void init() override;
|
||||||
|
|
||||||
|
void func() override;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* INC_STA_TOGGLE_HPP_ */
|
@ -12,8 +12,11 @@
|
|||||||
#include <sta/tacos/manager.hpp>
|
#include <sta/tacos/manager.hpp>
|
||||||
#include <sta/tacos/statemachine.hpp>
|
#include <sta/tacos/statemachine.hpp>
|
||||||
#include <tasks/dummy.hpp>
|
#include <tasks/dummy.hpp>
|
||||||
|
#include <tasks/toggle.hpp>
|
||||||
|
#include <tasks/disturb.hpp>
|
||||||
#include <gpio.h>
|
#include <gpio.h>
|
||||||
#include <sta/devices/stm32/gpio_pin.hpp>
|
#include <sta/devices/stm32/gpio_pin.hpp>
|
||||||
|
#include <sta/rtos/debug/heap_stats.hpp>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@ -24,38 +27,6 @@ namespace sta
|
|||||||
{
|
{
|
||||||
void onStatemachineInit()
|
void onStatemachineInit()
|
||||||
{
|
{
|
||||||
Statemachine::instance()->setStateFunction([](uint16_t state) -> uint16_t {
|
|
||||||
// ###### Implement your state transition function here! ######
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function should return some state within 0 and STA_TACOS_NUM_STATES (specified in the config.hpp).
|
|
||||||
* Return the same state as given as the argument for no state transition. Make sure, that this function is not
|
|
||||||
* computationally expensive.
|
|
||||||
*/
|
|
||||||
|
|
||||||
return state;
|
|
||||||
});
|
|
||||||
|
|
||||||
Statemachine::instance()->setTimerFunction([](uint16_t state, uint16_t lastState, uint32_t event) {
|
|
||||||
// ###### Set the failsafe and lockout timers here ######
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function is called after a state transition from lastState to state. Event corresponds to EventFlag enum in the Statemachine
|
|
||||||
* and encode how the state change happened.
|
|
||||||
*
|
|
||||||
* Setting a timer here is fully optional and depends on your system's specifications.
|
|
||||||
*/
|
|
||||||
|
|
||||||
uint32_t someFailsafeMillis = 42;
|
|
||||||
uint16_t someNextState = STA_TACOS_INITIAL_STATE;
|
|
||||||
uint32_t someLockoutMillis = 21;
|
|
||||||
|
|
||||||
// Start the failsafe timer to force a state transition to someNextState after someFailsafeMillis milliseconds.
|
|
||||||
Statemachine::instance()->setFailsafeTimer(someFailsafeMillis, someNextState);
|
|
||||||
|
|
||||||
// Start the lockout timer to block a state transition for the first someLockoutMillis milliseconds.
|
|
||||||
Statemachine::instance()->setLockoutTimer(someLockoutMillis);
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,7 +35,15 @@ namespace sta
|
|||||||
// ###### Register different threads for different states here. ######
|
// ###### Register different threads for different states here. ######
|
||||||
|
|
||||||
// The dummy task runs for state 0.
|
// The dummy task runs for state 0.
|
||||||
Manager::instance()->registerThread(std::make_shared<demo::DummyTask>("Dummy"), {0});
|
Manager::instance()->registerThread(std::make_shared<demo::DummyTask>("State 0"), {0});
|
||||||
|
Manager::instance()->registerThread(std::make_shared<demo::DummyTask>("State 1"), {1});
|
||||||
|
Manager::instance()->registerThread(std::make_shared<demo::DummyTask>("State 2 - FAIL"), {2});
|
||||||
|
Manager::instance()->registerThread(std::make_shared<demo::Toggle>(), {0, 1});
|
||||||
|
// Manager::instance()->registerThread(std::make_shared<demo::DisturbTask>(), {0, 1});
|
||||||
|
|
||||||
|
STA_DEBUG_PRINTF("The answer to everything is %d", 42);
|
||||||
|
|
||||||
|
STA_DEBUG_HEAP_STATS();
|
||||||
}
|
}
|
||||||
} // namespace tacos
|
} // namespace tacos
|
||||||
} // namespace sta
|
} // namespace sta
|
||||||
|
35
App/Src/tasks/disturb.cpp
Normal file
35
App/Src/tasks/disturb.cpp
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* disturb.cpp
|
||||||
|
*
|
||||||
|
* Created on: Nov 20, 2023
|
||||||
|
* Author: Dario
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <tasks/disturb.hpp>
|
||||||
|
#include <sta/tacos/statemachine.hpp>
|
||||||
|
#include <sta/debug/debug.hpp>
|
||||||
|
|
||||||
|
namespace demo
|
||||||
|
{
|
||||||
|
DisturbTask::DisturbTask()
|
||||||
|
: sta::tacos::TacosThread("Disturb", osPriorityNormal)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void DisturbTask::init()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void DisturbTask::func()
|
||||||
|
{
|
||||||
|
STA_DEBUG_PRINTLN(this->getName());
|
||||||
|
|
||||||
|
sta::tacos::Statemachine::instance()->stateChangeEvent.wait(sta::tacos::EventFlags::ALL, osWaitForever);
|
||||||
|
|
||||||
|
uint16_t currentState = sta::tacos::Statemachine::instance()->getCurrentState();
|
||||||
|
sta::tacos::Statemachine::instance()->requestTimedStateTransition(currentState, 2, 4000, 0);
|
||||||
|
}
|
||||||
|
} // namespace demo
|
||||||
|
|
@ -19,8 +19,6 @@ namespace demo
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DummyTask::~DummyTask(){}
|
|
||||||
|
|
||||||
void DummyTask::init()
|
void DummyTask::init()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
34
App/Src/tasks/toggle.cpp
Normal file
34
App/Src/tasks/toggle.cpp
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* toggle.cpp
|
||||||
|
*
|
||||||
|
* Created on: Nov 10, 2023
|
||||||
|
* Author: Dario
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <tasks/toggle.hpp>
|
||||||
|
#include <sta/tacos/statemachine.hpp>
|
||||||
|
#include <sta/debug/debug.hpp>
|
||||||
|
|
||||||
|
namespace demo
|
||||||
|
{
|
||||||
|
Toggle::Toggle()
|
||||||
|
: sta::tacos::TacosThread{ "Toggle", osPriorityNormal }
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Toggle::init()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Toggle::func()
|
||||||
|
{
|
||||||
|
uint16_t state = sta::tacos::Statemachine::instance()->getCurrentState();
|
||||||
|
uint16_t next = 1 - state;
|
||||||
|
|
||||||
|
sta::tacos::Statemachine::instance()->requestStateTransition(state, next, 5000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -1 +1 @@
|
|||||||
Subproject commit 0e96b2ec29fde1e56e12fc9f0dceb80012e0caf3
|
Subproject commit b1d6456dd88f881f68674824339483f69dd280f0
|
@ -1 +1 @@
|
|||||||
Subproject commit 4da1f0bb7dd48f89e9dd5ee0ec181638894e55e2
|
Subproject commit c4692287cf88e518d22078c1d284be343fc82fba
|
@ -20,6 +20,8 @@
|
|||||||
# define STA_TACOS_INITIAL_STATE 0
|
# define STA_TACOS_INITIAL_STATE 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define STA_TACOS_STATEMACHINE_QUEUE_LENGTH 4
|
||||||
|
|
||||||
// State transition happened because of
|
// State transition happened because of
|
||||||
#define STA_TACOS_STATE_CHANGE_NORMAL_FLAG ( 0x1U )
|
#define STA_TACOS_STATE_CHANGE_NORMAL_FLAG ( 0x1U )
|
||||||
#define STA_TACOS_STATE_CHANGE_FORCED_FLAG ( 0x1U << 1)
|
#define STA_TACOS_STATE_CHANGE_FORCED_FLAG ( 0x1U << 1)
|
||||||
@ -29,34 +31,41 @@
|
|||||||
|
|
||||||
|
|
||||||
#include <sta/tacos/thread.hpp>
|
#include <sta/tacos/thread.hpp>
|
||||||
|
#include <sta/rtos/queue.hpp>
|
||||||
#include <sta/rtos/timer.hpp>
|
#include <sta/rtos/timer.hpp>
|
||||||
#include <sta/rtos/event.hpp>
|
#include <sta/rtos/event.hpp>
|
||||||
#include <sta/event.hpp>
|
#include <sta/event.hpp>
|
||||||
#include <sta/debug/assert.hpp>
|
#include <sta/debug/assert.hpp>
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
|
||||||
namespace sta
|
namespace sta
|
||||||
{
|
{
|
||||||
namespace tacos
|
namespace tacos
|
||||||
{
|
{
|
||||||
typedef std::function<uint16_t(uint16_t)> state_fn;
|
enum EventFlags
|
||||||
typedef std::function<void(uint16_t, uint16_t, uint32_t)> timer_fn;
|
{
|
||||||
|
NORMAL = 0x1U,
|
||||||
|
FORCED = 0x1U << 1,
|
||||||
|
TIMEOUT = 0x1U << 2,
|
||||||
|
STARTUP = 0x1U << 3,
|
||||||
|
ALL = NORMAL | FORCED | TIMEOUT | STARTUP
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StateTransition
|
||||||
|
{
|
||||||
|
uint16_t from;
|
||||||
|
uint16_t to;
|
||||||
|
EventFlags event;
|
||||||
|
uint32_t lockout;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class Statemachine : public TacosThread
|
class Statemachine : public TacosThread
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum EventFlags
|
|
||||||
{
|
|
||||||
NORMAL = 0x1U,
|
|
||||||
FORCED = 0x1U << 1,
|
|
||||||
TIMEOUT = 0x1U << 2,
|
|
||||||
STARTUP = 0x1U << 3,
|
|
||||||
ALL = NORMAL | FORCED | TIMEOUT | STARTUP
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The global event signaling a state change.
|
* @brief The global event signaling a state change.
|
||||||
*/
|
*/
|
||||||
@ -84,29 +93,23 @@ namespace sta
|
|||||||
uint16_t getCurrentState() const;
|
uint16_t getCurrentState() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Registers a new state transition function. This is a function for the user to implement state transition rules.
|
* @brief Request a state transition from a state to another.
|
||||||
|
*
|
||||||
|
* @param from The state which we want to leave. This is used to filter out obsolete transitions.
|
||||||
|
* @param to The state to transition to.
|
||||||
|
* @param lockout The minimum number of milliseconds we expect to stay in this state. This is used to block premature transitions.
|
||||||
*/
|
*/
|
||||||
void setStateFunction(state_fn func);
|
void requestStateTransition(uint32_t from, uint32_t to, uint32_t lockout = 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Registers a new timer function. This is a function for the user to set the timers after a state change.
|
* @brief Request a state transition after a given time has passed.
|
||||||
|
*
|
||||||
|
* @param from The state which we want to leave. This is used to filter out obsolete transitions.
|
||||||
|
* @param to The state to transition to.
|
||||||
|
* @param millis the number of milliseconds to wait before triggering the transition.
|
||||||
|
* @param lockout The minimum number of milliseconds we expect to stay in this state. This is used to block premature transitions.
|
||||||
*/
|
*/
|
||||||
void setTimerFunction(timer_fn func);
|
void requestTimedStateTransition(uint32_t from, uint32_t to, uint32_t millis, uint32_t lockout = 0);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Starts the failsafe timer for the desired duration and the desired next state.
|
|
||||||
*/
|
|
||||||
void setFailsafeTimer(uint32_t millis, uint16_t nextState);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Starts the lockoutTimer for the desired duration.
|
|
||||||
*/
|
|
||||||
void setLockoutTimer(uint32_t millis);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief this function call allows forced state transitions from external and internal sources.
|
|
||||||
*/
|
|
||||||
void forceStateTransition(uint16_t state);
|
|
||||||
|
|
||||||
void init() override;
|
void init() override;
|
||||||
void func() override;
|
void func() override;
|
||||||
@ -133,15 +136,19 @@ namespace sta
|
|||||||
|
|
||||||
~Statemachine() {}
|
~Statemachine() {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* @brief Starts the lockoutTimer for the desired duration.
|
||||||
|
*/
|
||||||
|
void setLockoutTimer(uint32_t millis);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint16_t currentState_;
|
uint16_t currentState_;
|
||||||
uint16_t failsafeState_;
|
|
||||||
|
|
||||||
RtosTimer lockoutTimer_;
|
RtosTimer lockoutTimer_;
|
||||||
RtosTimer failsafeTimer_;
|
RtosTimer failsafeTimer_;
|
||||||
|
|
||||||
state_fn transitionFunc_;
|
RtosQueue<StateTransition> queue_;
|
||||||
timer_fn timerFunc_;
|
|
||||||
};
|
};
|
||||||
} // namespace tacos
|
} // namespace tacos
|
||||||
} // namespace sta
|
} // namespace sta
|
||||||
|
@ -80,7 +80,7 @@ namespace sta
|
|||||||
|
|
||||||
void Manager::func()
|
void Manager::func()
|
||||||
{
|
{
|
||||||
Statemachine::stateChangeEvent.wait(Statemachine::EventFlags::ALL, osWaitForever);
|
Statemachine::stateChangeEvent.wait(EventFlags::ALL, osWaitForever);
|
||||||
|
|
||||||
HeapStats_t stats;
|
HeapStats_t stats;
|
||||||
vPortGetHeapStats(&stats);
|
vPortGetHeapStats(&stats);
|
||||||
|
@ -17,47 +17,46 @@ namespace sta
|
|||||||
Statemachine::Statemachine()
|
Statemachine::Statemachine()
|
||||||
: TacosThread{"Statemachine", STA_TACOS_STATEMACHINE_PRIORITY},
|
: TacosThread{"Statemachine", STA_TACOS_STATEMACHINE_PRIORITY},
|
||||||
currentState_{STA_TACOS_INITIAL_STATE},
|
currentState_{STA_TACOS_INITIAL_STATE},
|
||||||
failsafeState_{STA_TACOS_INITIAL_STATE},
|
|
||||||
lockoutTimer_{[](void *){}, nullptr},
|
lockoutTimer_{[](void *){}, nullptr},
|
||||||
failsafeTimer_{[](void *){}, nullptr},
|
failsafeTimer_{[](void *){}, nullptr},
|
||||||
transitionFunc_{[](uint16_t) -> uint16_t { return Statemachine::instance()->getCurrentState(); }},
|
queue_{STA_TACOS_STATEMACHINE_QUEUE_LENGTH}
|
||||||
timerFunc_{[](uint16_t, uint16_t, uint16_t) {}}
|
|
||||||
{
|
{
|
||||||
STA_ASSERT(STA_TACOS_INITIAL_STATE < STA_TACOS_NUM_STATES);
|
STA_ASSERT(STA_TACOS_INITIAL_STATE < STA_TACOS_NUM_STATES);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Statemachine::init()
|
void Statemachine::init()
|
||||||
{
|
{
|
||||||
timerFunc_(0, 0, EventFlags::STARTUP);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Statemachine::func()
|
void Statemachine::func()
|
||||||
{
|
{
|
||||||
if (!lockoutTimer_.isRunning())
|
// Wait for a message to be added to the queue.
|
||||||
|
StateTransition transition;
|
||||||
|
queue_.get(&transition, osWaitForever);
|
||||||
|
|
||||||
|
// Check if the transition isn't blocked and is legal.
|
||||||
|
if (!lockoutTimer_.isRunning() && transition.from == currentState_)
|
||||||
{
|
{
|
||||||
uint16_t next = transitionFunc_(currentState_);
|
STA_ASSERT(transition.to < STA_TACOS_NUM_STATES);
|
||||||
|
|
||||||
STA_ASSERT(next < STA_TACOS_NUM_STATES);
|
// Perform the transition and notify the threads. The event flags are set
|
||||||
|
// here in order to allow threads to react immediately.
|
||||||
|
currentState_ = transition.to;
|
||||||
|
Statemachine::stateChangeEvent.set(transition.event);
|
||||||
|
Statemachine::stateChangeEvent.clear(EventFlags::ALL);
|
||||||
|
|
||||||
// Check if a state change is desired. Block if the lockoutTimer is still running.
|
if (failsafeTimer_.isRunning())
|
||||||
if (next != currentState_)
|
|
||||||
{
|
{
|
||||||
if (failsafeTimer_.isRunning())
|
failsafeTimer_.stop();
|
||||||
{
|
}
|
||||||
failsafeTimer_.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call user space code to set the timers again.
|
// Start the lockout timer if requested.
|
||||||
timerFunc_(next, currentState_, EventFlags::NORMAL);
|
if (transition.lockout != 0)
|
||||||
|
{
|
||||||
// Update the state and trigger the global state changed event.
|
setLockoutTimer(transition.lockout);
|
||||||
currentState_ = next;
|
|
||||||
Statemachine::stateChangeEvent.set(EventFlags::NORMAL);
|
|
||||||
Statemachine::stateChangeEvent.clear(EventFlags::ALL);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
osThreadYield();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t Statemachine::getCurrentState() const
|
uint16_t Statemachine::getCurrentState() const
|
||||||
@ -65,28 +64,27 @@ namespace sta
|
|||||||
return currentState_;
|
return currentState_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Statemachine::setStateFunction(state_fn func)
|
void Statemachine::requestStateTransition(uint32_t from, uint32_t to, uint32_t lockout /* = 0 */)
|
||||||
{
|
{
|
||||||
STA_ASSERT(func != nullptr);
|
StateTransition transition;
|
||||||
|
transition.from = from;
|
||||||
|
transition.to = to;
|
||||||
|
transition.event = EventFlags::NORMAL;
|
||||||
|
transition.lockout = lockout;
|
||||||
|
|
||||||
transitionFunc_ = func;
|
// Try to add a state transition request to the queue. Don't wait if another
|
||||||
|
// thread is already requesting a state change.
|
||||||
|
queue_.put(transition, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Statemachine::setTimerFunction(timer_fn func)
|
void Statemachine::requestTimedStateTransition(uint32_t from, uint32_t to, uint32_t millis, uint32_t lockout /* = 0 */)
|
||||||
{
|
{
|
||||||
STA_ASSERT(func != nullptr);
|
STA_ASSERT(to < STA_TACOS_NUM_STATES);
|
||||||
|
|
||||||
timerFunc_ = func;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Statemachine::setFailsafeTimer(uint32_t millis, uint16_t nextState)
|
|
||||||
{
|
|
||||||
STA_ASSERT(nextState < STA_TACOS_NUM_STATES);
|
|
||||||
STA_ASSERT(!failsafeTimer_.isRunning());
|
STA_ASSERT(!failsafeTimer_.isRunning());
|
||||||
|
|
||||||
failsafeTimer_.setCallback([nextState](void* arg) {
|
failsafeTimer_.setCallback([from, to, lockout](void* arg) {
|
||||||
Statemachine::instance()->forceStateTransition(nextState);
|
Statemachine::instance()->requestStateTransition(from, to, lockout);
|
||||||
}, &failsafeState_);
|
}, NULL);
|
||||||
|
|
||||||
failsafeTimer_.start(millis);
|
failsafeTimer_.start(millis);
|
||||||
}
|
}
|
||||||
@ -99,25 +97,6 @@ namespace sta
|
|||||||
lockoutTimer_.start(millis);
|
lockoutTimer_.start(millis);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Statemachine::forceStateTransition(uint16_t state)
|
|
||||||
{
|
|
||||||
if (failsafeTimer_.isRunning())
|
|
||||||
{
|
|
||||||
failsafeTimer_.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lockoutTimer_.isRunning())
|
|
||||||
{
|
|
||||||
lockoutTimer_.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
timerFunc_(state, currentState_, EventFlags::FORCED);
|
|
||||||
currentState_ = state;
|
|
||||||
|
|
||||||
Statemachine::stateChangeEvent.set(EventFlags::FORCED);
|
|
||||||
Statemachine::stateChangeEvent.clear(EventFlags::ALL);
|
|
||||||
}
|
|
||||||
|
|
||||||
Statemachine* Statemachine::_instance = nullptr;
|
Statemachine* Statemachine::_instance = nullptr;
|
||||||
|
|
||||||
RtosEvent Statemachine::stateChangeEvent;
|
RtosEvent Statemachine::stateChangeEvent;
|
||||||
|
@ -81,21 +81,26 @@ namespace sta
|
|||||||
// Infinite loop allowing quick restarts of this thread after termination.
|
// Infinite loop allowing quick restarts of this thread after termination.
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
// The thread has to wait until the startup has been completed.
|
// The thread has to wait until the system startup has been completed.
|
||||||
rtos::waitForStartupEvent();
|
rtos::waitForStartupEvent();
|
||||||
|
|
||||||
// Wait for a thread start flag.
|
// Wait for a thread start flag.
|
||||||
wait(STA_RTOS_THREAD_FLAG_START);
|
wait(STA_RTOS_THREAD_FLAG_START);
|
||||||
|
|
||||||
|
// Call user-defined initialization code.
|
||||||
running_ = true;
|
running_ = true;
|
||||||
init();
|
init();
|
||||||
|
|
||||||
// Run the thread until the termination flag is set.
|
// Run the thread until the termination flag is set. Reset this
|
||||||
while (!resetTerminationRequest())
|
while (!isTerminationRequested())
|
||||||
{
|
{
|
||||||
func();
|
func();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clear the termination request flag for this thread.
|
||||||
|
deleteTerminationRequest();
|
||||||
|
|
||||||
|
// Call user-defined cleanup code.
|
||||||
cleanup();
|
cleanup();
|
||||||
running_ = false;
|
running_ = false;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user