mirror of
https://git.intern.spaceteamaachen.de/ALPAKA/TACOS.git
synced 2025-06-10 16:45:59 +00:00
Merge pull request 'Merge manager task into statemachine task' (#41) from refactor/statemachine into main
Reviewed-on: https://git.intern.spaceteamaachen.de/ALPAKA/TACOS/pulls/41 Reviewed-by: dario <dario@noreply.git.intern.spaceteamaachen.de>
This commit is contained in:
commit
235dd0a6d7
190
README.md
190
README.md
@ -1,18 +1,63 @@
|
|||||||
# TACOS
|
# TACOS
|
||||||
|
|
||||||
This is the Trajectory Analysis Control OS (TACOS) that serves as a starting point for developing TACOS-based projects, by implementing threads in the App directory. TACOS is a subset of the features provided by ALPAKA. In particular, TACOS consists of the STM32-specific components of sta-core, rtos-2 and rtos2-utils.
|
This is the Trajectory Analysis Control OS (TACOS) that serves as a framework for flight computer development. TACOS offers a state machine, a CAN bus interface, a watchdog and other HAL features through it's submodules. It runs on cmsis-rtos2 FreeRTOS on STM32 microcontrollers with C++ (maybe future versions will offer external C interfaces to support a wide array of languages...).
|
||||||
|
|
||||||
## Setting Up TACOS
|
To use TACOS one should implement threads, which fulfill the various roles of the module in the App directory. TACOS utilizes [ALPAKA](https://git.intern.spaceteamaachen.de/ALPAKA) features, in particular requiring [sta-core](https://git.intern.spaceteamaachen.de/ALPAKA/sta-core) and [rtos2-utils](https://git.intern.spaceteamaachen.de/ALPAKA/rtos2-utils), as such it requires these to be in it's include path.
|
||||||
|
|
||||||
Add this as a library an existing CubeIDE project using FreeRTOS. Generally, we advise you to add it as a submodule. Make sure that you add the include paths for Tacos, i.e. sta-core and rtos2-utils, to the project with the following steps:
|
## Setting up a TACOS project
|
||||||
```
|
|
||||||
Properties -> C/C++ General -> Paths and Symbols -> Includes -> GNU C -> Add...
|
### Setting up the project
|
||||||
Properties -> C/C++ General -> Paths and Symbols -> Includes -> GNU C++ -> Add...
|
|
||||||
Properties -> C/C++ General -> Paths and Symbols -> Source Location -> Add Folder...
|
First one must create a new CubeIDE project with FreeRTOS. To avoid doing that however we recommend using the [ioc-collection](https://git.intern.spaceteamaachen.de/ALPAKA/ioc-collection) to get a preconfigured IOC for the STM microcontroller you are using. From here follow the following steps:
|
||||||
|
|
||||||
|
1. ```Import -> General -> Import an Existing STM32CubeMX Configuration File (.ioc)```
|
||||||
|
2. Select the .ioc file from the ioc-collection
|
||||||
|
3. Enter the project name and location you want to save the project to
|
||||||
|
4. Select C++ as the target language
|
||||||
|
5. Click "Finish"
|
||||||
|
|
||||||
|
|
||||||
|
### Setting up the folder structure
|
||||||
|
|
||||||
|
Now it is necessary to setup the dependencies and include paths for TACOS. For this first create a new folder in the project directory called `Libs`. Then create another folder in the project directory called `App` with the subfolders `Inc` and `Src`. Now also create a folder called `sta` in the `Inc` folder. Finally add the empty files `App/Inc/sta/config.hpp` and `App/Src/startup.cpp`.
|
||||||
|
|
||||||
|
Now your project should look like this:
|
||||||
|
```
|
||||||
|
...
|
||||||
|
App/
|
||||||
|
├── Inc/
|
||||||
|
│ ├── sta/
|
||||||
|
│ │ └── config.hpp
|
||||||
|
├── Src/
|
||||||
|
│ └── startup.cpp
|
||||||
|
Libs/
|
||||||
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
Create a new thread via the project's IOC and call `startTACOS()` from this thread. If your thread is called `defaultTask`, the corresponding function `StartDefaultTask` generated in `Core/Src/freertos.c` should look like this:
|
### Setting up the dependencies
|
||||||
|
|
||||||
|
First it is recommended to initialize a git repository in the project folder with `git init`. Then add the TACOS, sta-core and rtos2-utils repositories as submodules in the `Libs` folder with the following commands:
|
||||||
|
```bash
|
||||||
|
cd Libs
|
||||||
|
git submodule add https://git.intern.spaceteamaachen.de/ALPAKA/TACOS.git
|
||||||
|
git submodule add https://git.intern.spaceteamaachen.de/ALPAKA/sta-core.git
|
||||||
|
git submodule add https://git.intern.spaceteamaachen.de/ALPAKA/rtos2-utils.git
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Make sure that you add the include paths for TACOS, sta-core and rtos2-utils to the project with the following steps:
|
||||||
|
1. `Properties -> C/C++ General -> Paths and Symbols -> Includes -> GNU C -> Add...`
|
||||||
|
2. Select `Add to all languages` and `Is a workspace path`
|
||||||
|
3. Click on `Workspace` and select a folder from the `YOUR_PROJECT_FOLDER/(Libs|App)` directory
|
||||||
|
- Always select the `include` or `Inc` folder for the include paths
|
||||||
|
- If the path you want to add is not in the list, refresh the project with `F5` in the `Project Explorer` and try again
|
||||||
|
4. Repeat for TACOS, sta-core, rtos2-utils and the App folder
|
||||||
|
5. `Properties -> C/C++ General -> Paths and Symbols -> Source Location -> Add Folder...`
|
||||||
|
- Add the `App` and `Libs` folders
|
||||||
|
|
||||||
|
### Starting TACOS
|
||||||
|
|
||||||
|
Navigate to the `Core/Src/freertos.c` file and add the following code to the `StartDefaultTask` function:
|
||||||
|
```cpp
|
||||||
void StartDefaultTask(void *argument)
|
void StartDefaultTask(void *argument)
|
||||||
{
|
{
|
||||||
/* USER CODE BEGIN StartDefaultTask */
|
/* USER CODE BEGIN StartDefaultTask */
|
||||||
@ -28,9 +73,11 @@ void StartDefaultTask(void *argument)
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Configuring TACOS
|
This will start the TACOS startup and initialize all TACOS threads (which will then initialize yours).
|
||||||
|
|
||||||
|
### Configuring TACOS
|
||||||
In order to use TACOS, you need to provide a configuration file in the path `sta/config.hpp`. The following code is an example for a TACOS-project using default configuration:
|
In order to use TACOS, you need to provide a configuration file in the path `sta/config.hpp`. The following code is an example for a TACOS-project using default configuration:
|
||||||
```
|
```cpp
|
||||||
#ifndef INC_STA_CONFIG_HPP_
|
#ifndef INC_STA_CONFIG_HPP_
|
||||||
#define INC_STA_CONFIG_HPP_
|
#define INC_STA_CONFIG_HPP_
|
||||||
|
|
||||||
@ -50,6 +97,7 @@ In order to use TACOS, you need to provide a configuration file in the path `sta
|
|||||||
#define STA_RTOS_SYSTEM_EVENTS_ENABLE
|
#define STA_RTOS_SYSTEM_EVENTS_ENABLE
|
||||||
// #define STA_RTOS_SYSTEM_WATCHDOG_ENABLE
|
// #define STA_RTOS_SYSTEM_WATCHDOG_ENABLE
|
||||||
// #define STA_RTOS_WATCHDOG_ENABLE
|
// #define STA_RTOS_WATCHDOG_ENABLE
|
||||||
|
// #define STA_TACOS_WATCHDOG_FREQUENCY 10000
|
||||||
#define STA_CAN_BUS_ENABLE
|
#define STA_CAN_BUS_ENABLE
|
||||||
|
|
||||||
// Statemachine settings.
|
// Statemachine settings.
|
||||||
@ -61,12 +109,85 @@ In order to use TACOS, you need to provide a configuration file in the path `sta
|
|||||||
#endif /* INC_STA_CONFIG_HPP_ */
|
#endif /* INC_STA_CONFIG_HPP_ */
|
||||||
```
|
```
|
||||||
PS: For not officially supported chips use this as the include:
|
PS: For not officially supported chips use this as the include:
|
||||||
```
|
```cpp
|
||||||
#include <sta/devices/stm32/mcu/common.hpp>
|
#include <sta/devices/stm32/mcu/common.hpp>
|
||||||
#define STA_MCU_LITTLE_ENDIAN
|
#define STA_MCU_LITTLE_ENDIAN
|
||||||
#define STA_PLATFORM_STM32
|
#define STA_PLATFORM_STM32
|
||||||
```
|
```
|
||||||
## Setting up the CAN Bus
|
|
||||||
|
### Implementing your own threads
|
||||||
|
|
||||||
|
Let's create a simple thread that prints "Hello World" every second. First create a new file in the `App/Inc/tasks` folder called `spam_task.hpp`. Then add the following code:
|
||||||
|
```cpp
|
||||||
|
#ifndef INC_TASKS_SPAM_TASK_HPP_
|
||||||
|
#define INC_TASKS_SPAM_TASK_HPP_
|
||||||
|
|
||||||
|
#include <sta/tacos.hpp>
|
||||||
|
|
||||||
|
namespace tasks
|
||||||
|
{
|
||||||
|
class SpamTask : public sta::tacos::TacosThread {
|
||||||
|
public:
|
||||||
|
SpamTask();
|
||||||
|
|
||||||
|
// One time function that is called when the thread is created.
|
||||||
|
void init() override;
|
||||||
|
|
||||||
|
// Repeatable function that is called every time the thread is executed.
|
||||||
|
void func() override;
|
||||||
|
};
|
||||||
|
} // namespace tasks
|
||||||
|
|
||||||
|
#endif /* INC_TASKS_SPAM_TASK_HPP_ */
|
||||||
|
```
|
||||||
|
This code defines a new thread that inherits from `TacosThread` and implements the `init` and `func` functions. The `init` function is called once when the thread is created and the `func` function is called every time the thread is executed.
|
||||||
|
|
||||||
|
Now create a new file in the `App/Src/tasks` folder called `spam_task.cpp` and add the following code:
|
||||||
|
```cpp
|
||||||
|
#include <tasks/spam_task.hpp>
|
||||||
|
|
||||||
|
namespace tasks {
|
||||||
|
SpamTask::SpamTask() :
|
||||||
|
TacosThread("SPAM", osPriorityNormal){}
|
||||||
|
|
||||||
|
void SpamTask::init() {
|
||||||
|
// Nothing to init...
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpamTask::func() {
|
||||||
|
// Print "Hello World" every second.
|
||||||
|
STA_DEBUG_PRINTLN("Hello World");
|
||||||
|
this->periodicDelay(1); // Execute this function with 1 Hz.
|
||||||
|
}
|
||||||
|
} // namespace tasks
|
||||||
|
```
|
||||||
|
|
||||||
|
To start this thread, we first need to fill out the `startup.cpp` file. This file may look like this:
|
||||||
|
```cpp
|
||||||
|
#include <sta/tacos.hpp>
|
||||||
|
#include <tasks/spam_task.hpp>
|
||||||
|
|
||||||
|
#include <sta/debug/debug.hpp>
|
||||||
|
|
||||||
|
namespace sta
|
||||||
|
{
|
||||||
|
namespace tacos
|
||||||
|
{
|
||||||
|
void onStatemachineInit()
|
||||||
|
{
|
||||||
|
// ###### Register different threads for different states here. ######
|
||||||
|
// Register a "Spam Task" thread for all states except 1 and 2.
|
||||||
|
sta::tacos::addThread<tasks::SpamTask>(ALL_STATES - state_set{1,2});
|
||||||
|
|
||||||
|
STA_DEBUG_PRINTF("The answer to everything is %d", 42);
|
||||||
|
}
|
||||||
|
} // namespace tacos
|
||||||
|
} // namespace sta
|
||||||
|
```
|
||||||
|
|
||||||
|
And that's it! Now you have a thread that prints "Hello World" every second. Simply build the project and flash it to your microcontroller and be amazed by the Spam!
|
||||||
|
|
||||||
|
### Setting up the CAN Bus
|
||||||
|
|
||||||
To enable the CAN Bus two things need to be done:
|
To enable the CAN Bus two things need to be done:
|
||||||
1. Enable CAN in the IOC with the RX0 and RX1 Interrupts enabled.
|
1. Enable CAN in the IOC with the RX0 and RX1 Interrupts enabled.
|
||||||
@ -79,4 +200,47 @@ PS: For not officially supported chips add this:
|
|||||||
#define STA_STM32_CAN_HANDLE {YOUR_HCAN_HANDLE}
|
#define STA_STM32_CAN_HANDLE {YOUR_HCAN_HANDLE}
|
||||||
```
|
```
|
||||||
|
|
||||||
After this messages will automatically be forwarded to the task with it's ID. To send messages use the interface defined in `tacos.hpp`.
|
There are two options for handling incoming CAN messages:
|
||||||
|
1. If `#define STA_CAN_BUS_FWD_ENABLE` is set, the messages will be forwarded to the task with the ID of the message.
|
||||||
|
- Tasks set their ID with `setID(uint32_t id)` in their constructor.
|
||||||
|
- From here they can handle the message by going through their `CAN_queue_` with `CanSysMsg msg; CAN_queue_.get(&msg);`
|
||||||
|
2. All messages will trigger the weakly defined handleSysMessage callback.
|
||||||
|
- This could be implemented like this:
|
||||||
|
```cpp
|
||||||
|
namespace sta
|
||||||
|
{
|
||||||
|
namespace tacos
|
||||||
|
{
|
||||||
|
bool handleSysMessage(CanMsgHeader &header, uint8_t *payload)
|
||||||
|
{
|
||||||
|
// Print the message ID and the first byte of the payload.
|
||||||
|
//(please don't do this in production, it will crash the system sooner or later)
|
||||||
|
STA_DEBUG_PRINTF("> ID: %d", header.sid);
|
||||||
|
|
||||||
|
switch (header.sid)
|
||||||
|
{
|
||||||
|
// State transition message
|
||||||
|
case STA_TACOS_CAN_BUS_SYS_MSG_ID:
|
||||||
|
// First byte of payload is the origin state, second byte is the destination state
|
||||||
|
tacos::setState(payload[0], payload[1], 0, true);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case MODULE_SW_RESET_CAN_ID:
|
||||||
|
HAL_NVIC_SystemReset();
|
||||||
|
|
||||||
|
return true; // :)
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false; // I know, i know, this is not necessary, but it's good practice. And you know what they say about good practice: Do it!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Further information
|
||||||
|
To look into other function of TACOS please consult the READMEs in the include folder or the doxygen documentation. Also consult the sta-core and rtos2-utils READMEs for further information on the features that TACOS uses.
|
93
include/sta/README.md
Normal file
93
include/sta/README.md
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
# TACOS.hpp
|
||||||
|
|
||||||
|
The TACOS API is defined in the tacos.hpp, in normal use cases you should only need to include this file.
|
||||||
|
|
||||||
|
## Functions
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
uint16_t getState()
|
||||||
|
```
|
||||||
|
|
||||||
|
Retrieves the current state of the TACOS state machine.
|
||||||
|
|
||||||
|
---
|
||||||
|
```cpp
|
||||||
|
void requestState(uint32_t from, uint32_t to, uint32_t lockout = 0, bool publish = true)
|
||||||
|
```
|
||||||
|
|
||||||
|
Requests a state transition. Invalid state transitions will be dismissed. First come, first serve.
|
||||||
|
|
||||||
|
- **Parameters**:
|
||||||
|
- `from`: The starting state for the transition.
|
||||||
|
- `to`: The target state to transition to.
|
||||||
|
- `lockout`: (Optional) A timer to block further transitions.
|
||||||
|
- `publish`: (Optional) Whether to publish the state transition to the CAN bus.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void forceState(uint32_t from, uint32_t to, uint32_t lockout = 0, bool publish = true)
|
||||||
|
```
|
||||||
|
|
||||||
|
Forces a state transition. Will be ignored if already in the given state. Triggers instantly.
|
||||||
|
|
||||||
|
- **Parameters**:
|
||||||
|
- `from`: The starting state for the transition.
|
||||||
|
- `to`: The target state to transition to.
|
||||||
|
- `lockout`: (Optional) A timer to block further transitions.
|
||||||
|
- `publish`: (Optional) Whether to publish the state transition to the CAN bus.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void setStateTimed(uint32_t from, uint32_t to, uint32_t millis, uint32_t lockout = 0, bool publish = false)
|
||||||
|
```
|
||||||
|
|
||||||
|
Requests a state transition after a specified time.
|
||||||
|
|
||||||
|
- **Parameters**:
|
||||||
|
- `from`: The starting state.
|
||||||
|
- `to`: The target state.
|
||||||
|
- `millis`: The wait time in milliseconds before requesting the transition.
|
||||||
|
- `lockout`: (Optional) A timer for blocking subsequent transitions.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
template<typename T, typename ... Args> std::shared_ptr<T> addThread(std::set<uint16_t> states, Args ... args)
|
||||||
|
```
|
||||||
|
|
||||||
|
Registers a new thread to be run by TACOS.
|
||||||
|
|
||||||
|
- **Template Parameters**:
|
||||||
|
- `T`: The class type of the thread, which should inherit from `TacosThread`.
|
||||||
|
- **Parameters**:
|
||||||
|
- `states`: A set of states in which the thread should be active.
|
||||||
|
- `args`: The constructor arguments for the thread class.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### CAN Bus Functions (Conditional)
|
||||||
|
|
||||||
|
The following functions are available only if `STA_TACOS_CAN_BUS_ENABLED` is defined:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
bool queueCanBusMsg(CanSysMsg & msg, uint32_t timeout)
|
||||||
|
```
|
||||||
|
|
||||||
|
Queues a message to be sent over the CAN bus.
|
||||||
|
|
||||||
|
- **Parameters**:
|
||||||
|
- `msg`: The message to be sent.
|
||||||
|
- `timeout`: The maximum time to wait for sending the message.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
bool publishState(uint32_t from, uint32_t to, uint32_t timeout = 0)
|
||||||
|
```
|
||||||
|
|
||||||
|
Publishes a state transition message to the CAN bus.
|
||||||
|
|
||||||
|
- **Parameters**:
|
||||||
|
- `from`: The starting state for the transition.
|
||||||
|
- `to`: The target state.
|
||||||
|
- `timeout`: (Optional) A timeout for CAN communication.
|
@ -9,7 +9,6 @@
|
|||||||
#define STA_TACOS_HPP
|
#define STA_TACOS_HPP
|
||||||
|
|
||||||
#include <sta/tacos/thread.hpp>
|
#include <sta/tacos/thread.hpp>
|
||||||
#include <sta/tacos/manager.hpp>
|
|
||||||
#include <sta/tacos/statemachine.hpp>
|
#include <sta/tacos/statemachine.hpp>
|
||||||
#include <sta/tacos/can_bus.hpp>
|
#include <sta/tacos/can_bus.hpp>
|
||||||
|
|
||||||
@ -42,11 +41,23 @@ namespace sta
|
|||||||
* @param from The start we want to transition from.
|
* @param from The start we want to transition from.
|
||||||
* @param to The state we want to transition to.
|
* @param to The state we want to transition to.
|
||||||
* @param lockout An optional timer blocking state transition for a given time.
|
* @param lockout An optional timer blocking state transition for a given time.
|
||||||
* @param force If true, the state transition will be executed regardless of the current state.
|
* @param publish If true, the state transition will be published via CAN.
|
||||||
*
|
*
|
||||||
* @ingroup tacos_api
|
* @ingroup tacos_api
|
||||||
*/
|
*/
|
||||||
void setState(uint32_t from, uint32_t to, uint32_t lockout = 0, bool force = false, bool publish = false);
|
void requestState(uint32_t from, uint32_t to, uint32_t lockout = 0, bool publish = true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Request a state transition. Invalid state transitions will be dismissed.
|
||||||
|
*
|
||||||
|
* @param from The start we want to transition from.
|
||||||
|
* @param to The state we want to transition to.
|
||||||
|
* @param lockout An optional timer blocking state transition for a given time.
|
||||||
|
* @param publish If true, the state transition will be published via CAN.
|
||||||
|
*
|
||||||
|
* @ingroup tacos_api
|
||||||
|
*/
|
||||||
|
void forceState(uint32_t from, uint32_t to, uint32_t lockout = 0, bool publish = true);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Request a state transition after a given time has passed. Invalid state transitions will be dismissed.
|
* @brief Request a state transition after a given time has passed. Invalid state transitions will be dismissed.
|
||||||
@ -74,7 +85,7 @@ namespace sta
|
|||||||
{
|
{
|
||||||
std::shared_ptr<T> thread_ptr = std::make_shared<T>(args...);
|
std::shared_ptr<T> thread_ptr = std::make_shared<T>(args...);
|
||||||
|
|
||||||
Manager::instance()->registerThread(thread_ptr, states);
|
Statemachine::instance()->registerThread(thread_ptr, states);
|
||||||
|
|
||||||
return thread_ptr;
|
return thread_ptr;
|
||||||
}
|
}
|
||||||
|
23
include/sta/tacos/README.md
Normal file
23
include/sta/tacos/README.md
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# TACOS tasks and prototypes
|
||||||
|
|
||||||
|
## Statemachine
|
||||||
|
The statemachine is the core of TACOS. It is responsible for managing the state of the system and executing the threads that are registered to it. The statemachine is a singleton and can be accessed via `sta::tacos::Statemachine::instance()`.
|
||||||
|
|
||||||
|
For further info check the file or the doxygen documentation.
|
||||||
|
|
||||||
|
## Watchdog
|
||||||
|
The watchdog checks if all threads are setting a flag after every func call. If a thread does not set the flag in the given interval the thread is restarted.
|
||||||
|
|
||||||
|
The watchdog is enabled and configured with the following defines:
|
||||||
|
```cpp
|
||||||
|
#define STA_RTOS_WATCHDOG_ENABLE
|
||||||
|
#define STA_TACOS_WATCHDOG_FREQUENCY 10000
|
||||||
|
```
|
||||||
|
|
||||||
|
## CAN Bus
|
||||||
|
The CAN bus is used to communicate between different devices. The CAN bus task is triggered by IRQ from the transceiver or if something is inserted into it's output queue.
|
||||||
|
|
||||||
|
This thing is a huge steaming (but functioning) pile of shit. Further documentation is on hold until rework.
|
||||||
|
|
||||||
|
## Thread.hpp
|
||||||
|
Here the TacosThread is defined. Very straight forward. Just take a look inside.
|
3
include/sta/tacos/c_api/README.md
Normal file
3
include/sta/tacos/c_api/README.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# TACOS C API
|
||||||
|
|
||||||
|
Currently the only C API is the entry point for starting up TACOS. This will be extended to provide full functionality via C calling conventions.
|
@ -2,13 +2,11 @@
|
|||||||
#define STA_TACOS_CONFIGS_DEFAULT_HPP
|
#define STA_TACOS_CONFIGS_DEFAULT_HPP
|
||||||
|
|
||||||
// Generally, we assume the TACOS threads to have the highest priorties.
|
// Generally, we assume the TACOS threads to have the highest priorties.
|
||||||
#define STA_TACOS_MANAGER_PRIORITY osPriorityHigh
|
|
||||||
#define STA_TACOS_STATEMACHINE_PRIORITY osPriorityHigh
|
#define STA_TACOS_STATEMACHINE_PRIORITY osPriorityHigh
|
||||||
#define STA_TACOS_WATCHDOG_PRIORITY osPriorityHigh
|
#define STA_TACOS_WATCHDOG_PRIORITY osPriorityHigh
|
||||||
#define STA_TACOS_CAN_BUS_PRIORITY osPriorityHigh
|
#define STA_TACOS_CAN_BUS_PRIORITY osPriorityHigh
|
||||||
|
|
||||||
// Set the Stack size for the TACOS threads, to 0 to use the default stack size, set in the ioc
|
// Set the Stack size for the TACOS threads, to 0 to use the default stack size, set in the ioc
|
||||||
#define STA_TACOS_MANAGER_STACK_SIZE 0
|
|
||||||
#define STA_TACOS_STATEMACHINE_STACK_SIZE 0
|
#define STA_TACOS_STATEMACHINE_STACK_SIZE 0
|
||||||
|
|
||||||
// Per default, we assume state 0 to be the initial state.
|
// Per default, we assume state 0 to be the initial state.
|
||||||
@ -22,7 +20,4 @@
|
|||||||
// State transition message define with highest CAN priority
|
// State transition message define with highest CAN priority
|
||||||
#define STA_TACOS_CAN_BUS_SYS_MSG_ID 0x0
|
#define STA_TACOS_CAN_BUS_SYS_MSG_ID 0x0
|
||||||
|
|
||||||
// TACOS requires system events to start threads
|
|
||||||
#define STA_RTOS_SYSTEM_EVENTS_ENABLE
|
|
||||||
|
|
||||||
#endif // STA_TACOS_CONFIGS_DEFAULT_HPP
|
#endif // STA_TACOS_CONFIGS_DEFAULT_HPP
|
||||||
|
@ -1,124 +0,0 @@
|
|||||||
/*
|
|
||||||
* manager.hpp
|
|
||||||
*
|
|
||||||
* Created on: Sep 19, 2023
|
|
||||||
* Author: Dario
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef INCLUDE_STA_TACOS_MANAGER_HPP_
|
|
||||||
#define INCLUDE_STA_TACOS_MANAGER_HPP_
|
|
||||||
|
|
||||||
|
|
||||||
#include <sta/config.hpp>
|
|
||||||
|
|
||||||
#if !defined(STA_TACOS_MANAGER_PRIORITY) && !defined(DOXYGEN)
|
|
||||||
# error "Manger task priority not specified in config.hpp"
|
|
||||||
#else
|
|
||||||
|
|
||||||
#include <set>
|
|
||||||
#include <list>
|
|
||||||
#include <vector>
|
|
||||||
#include <memory>
|
|
||||||
#include <sta/tacos/thread.hpp>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @defgroup tacos_manager Manager Task
|
|
||||||
* @ingroup tacos
|
|
||||||
* @brief Manager task for TACOS.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace sta
|
|
||||||
{
|
|
||||||
namespace tacos
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @brief Manager class for Tacos.
|
|
||||||
*
|
|
||||||
* @ingroup tacos_manager
|
|
||||||
*/
|
|
||||||
class Manager : public TacosThread
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* @brief Get the singleton instance of the manager.
|
|
||||||
*
|
|
||||||
* @ingroup tacos_manager
|
|
||||||
*/
|
|
||||||
static Manager* instance()
|
|
||||||
{
|
|
||||||
static CGuard g;
|
|
||||||
|
|
||||||
if (!_instance)
|
|
||||||
{
|
|
||||||
// Create a the manager singleton instance.
|
|
||||||
Manager::_instance = new Manager();
|
|
||||||
}
|
|
||||||
|
|
||||||
return _instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Register a thread to be managed by the manager.
|
|
||||||
*/
|
|
||||||
void registerThread(std::shared_ptr<TacosThread> thread, std::set<uint16_t> states);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the Active Threads object
|
|
||||||
*
|
|
||||||
* @return std::vector<std::shared_ptr<TacosThread>>
|
|
||||||
*/
|
|
||||||
std::vector<std::shared_ptr<TacosThread>> getActiveThreads();
|
|
||||||
|
|
||||||
void init() override;
|
|
||||||
|
|
||||||
void func() override;
|
|
||||||
private:
|
|
||||||
static Manager* _instance;
|
|
||||||
|
|
||||||
class CGuard
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
~CGuard()
|
|
||||||
{
|
|
||||||
if( NULL != Manager::_instance )
|
|
||||||
{
|
|
||||||
delete Manager::_instance;
|
|
||||||
Manager::_instance = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Manager();
|
|
||||||
|
|
||||||
Manager(const Manager&);
|
|
||||||
|
|
||||||
//~Manager();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Forces only threads of current state to run.
|
|
||||||
*/
|
|
||||||
void updateThreads();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Starts all threads which should be running in the given state. Does nothing if the state is already running.
|
|
||||||
*/
|
|
||||||
void startThreads(uint16_t state);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Stops all threads which should not be running in the given state.
|
|
||||||
*/
|
|
||||||
void stopThreads(uint16_t state);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Pointers to all threads which are managed by the manager.
|
|
||||||
*
|
|
||||||
* @ingroup tacos_manager
|
|
||||||
*/
|
|
||||||
std::vector<std::shared_ptr<TacosThread>> threads_[STA_TACOS_NUM_STATES];
|
|
||||||
};
|
|
||||||
} // namespace tacos
|
|
||||||
} // namespace sta
|
|
||||||
|
|
||||||
#endif // STA_TACOS_MANAGER_PRIORITY
|
|
||||||
|
|
||||||
#endif /* INCLUDE_STA_TACOS_MANAGER_HPP_ */
|
|
@ -66,9 +66,13 @@
|
|||||||
#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 <sta/lang.hpp>
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
#include <list>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
@ -134,11 +138,15 @@ namespace sta
|
|||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief The global event signaling a state change.
|
* @brief The global event signaling a state change.
|
||||||
|
*
|
||||||
|
* @ingroup tacos_statemachine
|
||||||
*/
|
*/
|
||||||
static RtosEvent stateChangeEvent;
|
static RtosEvent stateChangeEvent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Getter function for the singleton instance.
|
* @brief Getter function for the singleton instance.
|
||||||
|
*
|
||||||
|
* @ingroup tacos_statemachine
|
||||||
*/
|
*/
|
||||||
static Statemachine* instance()
|
static Statemachine* instance()
|
||||||
{
|
{
|
||||||
@ -146,7 +154,7 @@ namespace sta
|
|||||||
|
|
||||||
if (!_instance)
|
if (!_instance)
|
||||||
{
|
{
|
||||||
// Create the manager singleton instance.
|
// Create the statemachine singleton instance.
|
||||||
Statemachine::_instance = new Statemachine();
|
Statemachine::_instance = new Statemachine();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,6 +163,8 @@ namespace sta
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the statemachine's current state.
|
* @brief Returns the statemachine's current state.
|
||||||
|
*
|
||||||
|
* @ingroup tacos_statemachine
|
||||||
*/
|
*/
|
||||||
uint16_t getCurrentState() const;
|
uint16_t getCurrentState() const;
|
||||||
|
|
||||||
@ -164,9 +174,23 @@ namespace sta
|
|||||||
* @param from The state which we want to leave. This is used to filter out obsolete transitions.
|
* @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 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.
|
* @param lockout The minimum number of milliseconds we expect to stay in this state. This is used to block premature transitions.
|
||||||
* @param force If true, the state transition will be executed regardless of the current state.
|
* @param publish If true, the state transition will be published via CAN.
|
||||||
|
*
|
||||||
|
* @ingroup tacos_statemachine
|
||||||
*/
|
*/
|
||||||
void requestStateTransition(uint32_t from, uint32_t to, uint32_t lockout = 0, bool force = false, bool publish = true);
|
void requestStateTransition(uint32_t from, uint32_t to, uint32_t lockout = 0, bool publish = true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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.
|
||||||
|
* @param publish If true, the state transition will be published via CAN.
|
||||||
|
*
|
||||||
|
* @ingroup tacos_statemachine
|
||||||
|
*/
|
||||||
|
void forceStateTransition(uint32_t from, uint32_t to, uint32_t lockout = 0, bool publish = true);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Request a state transition after a given time has passed.
|
* @brief Request a state transition after a given time has passed.
|
||||||
@ -175,9 +199,28 @@ namespace sta
|
|||||||
* @param to The state to transition to.
|
* @param to The state to transition to.
|
||||||
* @param millis the number of milliseconds to wait before triggering the transition.
|
* @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.
|
* @param lockout The minimum number of milliseconds we expect to stay in this state. This is used to block premature transitions.
|
||||||
|
* @param publish If true, the state transition will be published via CAN.
|
||||||
|
*
|
||||||
|
* @ingroup tacos_statemachine
|
||||||
*/
|
*/
|
||||||
void requestTimedStateTransition(uint32_t from, uint32_t to, uint32_t millis, uint32_t lockout = 0, bool publish = true);
|
void requestTimedStateTransition(uint32_t from, uint32_t to, uint32_t millis, uint32_t lockout = 0, bool publish = true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Register a thread to be managed by the statemachine.
|
||||||
|
*
|
||||||
|
* @ingroup tacos_statemachine
|
||||||
|
*/
|
||||||
|
void registerThread(std::shared_ptr<TacosThread> thread, std::set<uint16_t> states);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the Active Threads object
|
||||||
|
*
|
||||||
|
* @return std::vector<std::shared_ptr<TacosThread>>
|
||||||
|
*
|
||||||
|
* @ingroup tacos_statemachine
|
||||||
|
*/
|
||||||
|
std::vector<std::shared_ptr<TacosThread>> getActiveThreads();
|
||||||
|
|
||||||
void init() override;
|
void init() override;
|
||||||
void func() override;
|
void func() override;
|
||||||
|
|
||||||
@ -208,9 +251,32 @@ namespace sta
|
|||||||
* @brief Starts the lockoutTimer for the desired duration.
|
* @brief Starts the lockoutTimer for the desired duration.
|
||||||
*
|
*
|
||||||
* @param millis The duration of the timer in milliseconds.
|
* @param millis The duration of the timer in milliseconds.
|
||||||
|
*
|
||||||
|
* @ingroup tacos_statemachine
|
||||||
*/
|
*/
|
||||||
void setLockoutTimer(uint32_t millis);
|
void setLockoutTimer(uint32_t millis);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Forces only threads of current state to run.
|
||||||
|
*
|
||||||
|
* @ingroup tacos_statemachine
|
||||||
|
*/
|
||||||
|
void updateThreads();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Starts all threads which should be running in the given state. Does nothing if the state is already running.
|
||||||
|
*
|
||||||
|
* @ingroup tacos_statemachine
|
||||||
|
*/
|
||||||
|
void startThreads(uint16_t state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stops all threads which should not be running in the given state.
|
||||||
|
*
|
||||||
|
* @ingroup tacos_statemachine
|
||||||
|
*/
|
||||||
|
void stopThreads(uint16_t state);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint16_t currentState_;
|
uint16_t currentState_;
|
||||||
|
|
||||||
@ -218,7 +284,26 @@ namespace sta
|
|||||||
RtosTimer failsafeTimer_;
|
RtosTimer failsafeTimer_;
|
||||||
|
|
||||||
RtosQueue<StateTransition> queue_;
|
RtosQueue<StateTransition> queue_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pointers to all threads which are managed by the statemachine.
|
||||||
|
*
|
||||||
|
* @ingroup tacos_statemachine
|
||||||
|
*/
|
||||||
|
std::vector<std::shared_ptr<TacosThread>> threads_[STA_TACOS_NUM_STATES];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback that is called when a state transition occurs.
|
||||||
|
*
|
||||||
|
* @param from The state we transitioned from.
|
||||||
|
* @param to The state we transitioned to.
|
||||||
|
* @param lockout The lockout time after the transition.
|
||||||
|
*
|
||||||
|
* @ingroup tacos_statemachine
|
||||||
|
*/
|
||||||
|
STA_WEAK
|
||||||
|
void onStateTransition(uint16_t from, uint16_t to, uint32_t lockout) {}
|
||||||
} // namespace tacos
|
} // namespace tacos
|
||||||
} // namespace sta
|
} // namespace sta
|
||||||
|
|
||||||
|
82
include/sta/tacos/system/events.hpp
Normal file
82
include/sta/tacos/system/events.hpp
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief Implementation of system events.
|
||||||
|
*/
|
||||||
|
#ifndef STA_TACOS_SYSTEM_EVENTS_HPP
|
||||||
|
#define STA_TACOS_SYSTEM_EVENTS_HPP
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup STA_RTOS_SysEvent System Events
|
||||||
|
* @ingroup STA_RTOS_API
|
||||||
|
* @brief System events.
|
||||||
|
*
|
||||||
|
* Check @ref STA_RTOS_BuildConfig for configuration options.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
|
||||||
|
// System event flags
|
||||||
|
//
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Startup system event flag.
|
||||||
|
*
|
||||||
|
* @ingroup STA_RTOS_SysEvent
|
||||||
|
*/
|
||||||
|
#define STA_TACOS_SYSTEM_EVENTS_STARTUP 0x100000U
|
||||||
|
|
||||||
|
|
||||||
|
namespace sta
|
||||||
|
{
|
||||||
|
namespace tacos
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @brief Initialize system events.
|
||||||
|
*/
|
||||||
|
void initSystemEvents();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Signal system events.
|
||||||
|
*
|
||||||
|
* @param flags System event flags
|
||||||
|
*
|
||||||
|
* @ingroup STA_RTOS_SysEvent
|
||||||
|
*/
|
||||||
|
void signalSystemEvents(uint32_t flags);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Wait for system events.
|
||||||
|
*
|
||||||
|
* @param flags System event flags
|
||||||
|
* @param options osFlagsWaitAll or osFlagsWaitAny (osFlagsNoClear always set)
|
||||||
|
* @param timeout Wait timeout (0 = instant, osWaitForever = infinite)
|
||||||
|
*
|
||||||
|
* @ingroup STA_RTOS_SysEvent
|
||||||
|
*/
|
||||||
|
void waitForSystemEvents(uint32_t flags, uint32_t options, uint32_t timeout);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Signal startup system event.
|
||||||
|
*
|
||||||
|
* @ingroup STA_RTOS_SysEvent
|
||||||
|
*/
|
||||||
|
void signalStartupEvent();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Wait for startup system event.
|
||||||
|
*
|
||||||
|
* Blocking while waiting
|
||||||
|
*
|
||||||
|
* @ingroup STA_RTOS_SysEvent
|
||||||
|
*/
|
||||||
|
void waitForStartupEvent();
|
||||||
|
} // namespace tacos
|
||||||
|
} // namespace sta
|
||||||
|
|
||||||
|
|
||||||
|
#endif // STA_RTOS_SYSTEM_EVENTS_HPP
|
@ -79,7 +79,7 @@ namespace sta
|
|||||||
* @brief Create a new thread with the given name and priority.
|
* @brief Create a new thread with the given name and priority.
|
||||||
*
|
*
|
||||||
* @param name The thread's name. This is used for debugging.
|
* @param name The thread's name. This is used for debugging.
|
||||||
* @param prio The thread's priority. Generally, this should be lower than the manager and statemachine priority.
|
* @param prio The thread's priority. Generally, this should be lower than the statemachine priority.
|
||||||
* @param stack_size The stack size for the task. The default is 0, i.e. the stack size specified in the FreeRTOS settings.
|
* @param stack_size The stack size for the task. The default is 0, i.e. the stack size specified in the FreeRTOS settings.
|
||||||
* @param cb_size The control block size for the task. The default is 0, i.e. the size specified in the FreeRTOS settings.
|
* @param cb_size The control block size for the task. The default is 0, i.e. the size specified in the FreeRTOS settings.
|
||||||
*/
|
*/
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include <sta/tacos/can_bus.hpp>
|
#include <sta/tacos/can_bus.hpp>
|
||||||
#include <sta/debug/assert.hpp>
|
#include <sta/debug/assert.hpp>
|
||||||
#include <sta/tacos/manager.hpp>
|
#include <sta/tacos/statemachine.hpp>
|
||||||
#include <sta/tacos.hpp>
|
#include <sta/tacos.hpp>
|
||||||
|
|
||||||
extern CAN_HandleTypeDef STA_STM32_CAN_HANDLE;
|
extern CAN_HandleTypeDef STA_STM32_CAN_HANDLE;
|
||||||
@ -64,7 +64,7 @@ namespace sta
|
|||||||
{
|
{
|
||||||
|
|
||||||
// Append to the correct thread's queue
|
// Append to the correct thread's queue
|
||||||
for (std::shared_ptr<TacosThread> thread : Manager::instance()->getActiveThreads())
|
for (std::shared_ptr<TacosThread> thread : Statemachine::instance()->getActiveThreads())
|
||||||
{
|
{
|
||||||
if (thread->getCanID() == sysMsg.header.sid)
|
if (thread->getCanID() == sysMsg.header.sid)
|
||||||
{
|
{
|
||||||
@ -160,7 +160,7 @@ namespace sta
|
|||||||
STA_ASSERT(header.payloadLength == 2);
|
STA_ASSERT(header.payloadLength == 2);
|
||||||
|
|
||||||
// First byte of payload is the origin state, second byte is the destination state. Transition is forced
|
// First byte of payload is the origin state, second byte is the destination state. Transition is forced
|
||||||
tacos::setState(payload[0], payload[1], 0, true);
|
tacos::forceState(payload[0], payload[1], 0, true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
51
src/events.cpp
Normal file
51
src/events.cpp
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#include <sta/tacos/system/events.hpp>
|
||||||
|
#include <sta/rtos/event.hpp>
|
||||||
|
|
||||||
|
#include <sta/debug/assert.hpp>
|
||||||
|
|
||||||
|
#include <cmsis_os2.h>
|
||||||
|
#include <FreeRTOS.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// Event handle
|
||||||
|
sta::RtosEvent * systemEvents = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
namespace sta
|
||||||
|
{
|
||||||
|
namespace tacos
|
||||||
|
{
|
||||||
|
void initSystemEvents()
|
||||||
|
{
|
||||||
|
if (systemEvents == nullptr)
|
||||||
|
{
|
||||||
|
systemEvents = new sta::RtosEvent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void signalSystemEvents(uint32_t flags)
|
||||||
|
{
|
||||||
|
STA_ASSERT_MSG(systemEvents != nullptr, "System events not initialized");
|
||||||
|
systemEvents->set(flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
void waitForSystemEvents(uint32_t flags, uint32_t options, uint32_t timeout)
|
||||||
|
{
|
||||||
|
STA_ASSERT_MSG(systemEvents != nullptr, "System events not initialized");
|
||||||
|
systemEvents->peek(flags, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void signalStartupEvent()
|
||||||
|
{
|
||||||
|
signalSystemEvents(STA_TACOS_SYSTEM_EVENTS_STARTUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void waitForStartupEvent()
|
||||||
|
{
|
||||||
|
waitForSystemEvents(STA_TACOS_SYSTEM_EVENTS_STARTUP, osFlagsWaitAll, osWaitForever);
|
||||||
|
}
|
||||||
|
} // namespace tacos
|
||||||
|
} // namespace sta
|
110
src/manager.cpp
110
src/manager.cpp
@ -1,110 +0,0 @@
|
|||||||
/*
|
|
||||||
* manager.cpp
|
|
||||||
*
|
|
||||||
* Created on: Sep 19, 2023
|
|
||||||
* Author: Dario
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <sta/tacos/manager.hpp>
|
|
||||||
#include <sta/tacos/statemachine.hpp>
|
|
||||||
#include <sta/debug/debug.hpp>
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
#include <FreeRTOS.h>
|
|
||||||
#include <sta/tacos.hpp>
|
|
||||||
|
|
||||||
|
|
||||||
namespace sta
|
|
||||||
{
|
|
||||||
namespace tacos
|
|
||||||
{
|
|
||||||
void Manager::registerThread(std::shared_ptr<TacosThread> thread, std::set<uint16_t> states)
|
|
||||||
{
|
|
||||||
for (uint16_t state : states)
|
|
||||||
{
|
|
||||||
STA_ASSERT(state < STA_TACOS_NUM_STATES);
|
|
||||||
|
|
||||||
threads_[state].push_back(thread);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::shared_ptr<TacosThread>> Manager::getActiveThreads()
|
|
||||||
{
|
|
||||||
return threads_[tacos::getState()];
|
|
||||||
}
|
|
||||||
|
|
||||||
void Manager::startThreads(uint16_t state)
|
|
||||||
{
|
|
||||||
STA_ASSERT(state < STA_TACOS_NUM_STATES);
|
|
||||||
|
|
||||||
for (std::shared_ptr<TacosThread> thread : threads_[state])
|
|
||||||
{
|
|
||||||
if (!thread->isRunning())
|
|
||||||
{
|
|
||||||
thread->start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Manager::stopThreads(uint16_t state)
|
|
||||||
{
|
|
||||||
std::set<std::shared_ptr<TacosThread>> terminated;
|
|
||||||
|
|
||||||
for (uint16_t other = 0; other < STA_TACOS_NUM_STATES; ++other)
|
|
||||||
{
|
|
||||||
if (other == state)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (std::shared_ptr<TacosThread> thread : threads_[other])
|
|
||||||
{
|
|
||||||
// If the thread is currently running but not part of the set of threads that should be running...
|
|
||||||
if (thread->isRunning() && terminated.count(thread) == 0 && std::count(threads_[state].begin(), threads_[state].end(), thread) == 0)
|
|
||||||
{
|
|
||||||
// ...politely request termination.
|
|
||||||
thread->requestTermination();
|
|
||||||
terminated.emplace(thread);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Manager::updateThreads()
|
|
||||||
{
|
|
||||||
uint16_t state = Statemachine::instance()->getCurrentState();
|
|
||||||
|
|
||||||
stopThreads(state);
|
|
||||||
startThreads(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Manager::init()
|
|
||||||
{
|
|
||||||
startThreads(Statemachine::instance()->getCurrentState());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Manager::func()
|
|
||||||
{
|
|
||||||
Statemachine::stateChangeEvent.wait(EventFlags::ALL, osWaitForever);
|
|
||||||
|
|
||||||
HeapStats_t stats;
|
|
||||||
vPortGetHeapStats(&stats);
|
|
||||||
|
|
||||||
// Start all new tasks and stop all the tasks that aren't supposed to be running.
|
|
||||||
updateThreads();
|
|
||||||
}
|
|
||||||
|
|
||||||
Manager::Manager()
|
|
||||||
: TacosThread{"Manager", STA_TACOS_MANAGER_PRIORITY, STA_TACOS_MANAGER_STACK_SIZE},
|
|
||||||
threads_{}
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Manager* Manager::_instance = nullptr;
|
|
||||||
|
|
||||||
} // namespace tacos
|
|
||||||
} // namespace sta
|
|
||||||
|
|
||||||
|
|
@ -28,12 +28,10 @@
|
|||||||
#include <sta/lang.hpp>
|
#include <sta/lang.hpp>
|
||||||
|
|
||||||
// rtos2-utils-specific includes.
|
// rtos2-utils-specific includes.
|
||||||
#include <sta/rtos/system/startup.hpp>
|
#include <sta/tacos/system/events.hpp>
|
||||||
#include <sta/rtos/system/events.hpp>
|
|
||||||
|
|
||||||
// Tacos-specific includes.
|
// Tacos-specific includes.
|
||||||
#include <sta/tacos/c_api/startup.h>
|
#include <sta/tacos/c_api/startup.h>
|
||||||
#include <sta/tacos/manager.hpp>
|
|
||||||
#include <sta/tacos/statemachine.hpp>
|
#include <sta/tacos/statemachine.hpp>
|
||||||
#include <sta/tacos/watchdog.hpp>
|
#include <sta/tacos/watchdog.hpp>
|
||||||
#include <sta/tacos/can_bus.hpp>
|
#include <sta/tacos/can_bus.hpp>
|
||||||
@ -85,39 +83,22 @@ namespace sta
|
|||||||
namespace tacos
|
namespace tacos
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @brief Function that is called before the statemachine task is started. Override it to
|
* @brief Function that is called before the statemachine task is started. It serves as an entry point for the user to
|
||||||
* adjust the statemachine to your specifications.
|
* define the threads the statemachine should run.
|
||||||
*
|
*
|
||||||
* @ingroup tacos_startup
|
* @ingroup tacos_startup
|
||||||
*/
|
*/
|
||||||
STA_WEAK
|
STA_WEAK
|
||||||
void onStatemachineInit()
|
void startup()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void initStatemachine()
|
void initStatemachine()
|
||||||
{
|
{
|
||||||
onStatemachineInit();
|
startup();
|
||||||
|
|
||||||
Statemachine::instance()->start();
|
Statemachine::instance()->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Function that is called before the manager task is started. Override it to adjust
|
|
||||||
* the manager to your specifications.
|
|
||||||
*
|
|
||||||
* @ingroup tacos_startup
|
|
||||||
*/
|
|
||||||
STA_WEAK
|
|
||||||
void onManagerInit()
|
|
||||||
{}
|
|
||||||
|
|
||||||
void initManager()
|
|
||||||
{
|
|
||||||
onManagerInit();
|
|
||||||
|
|
||||||
Manager::instance()->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef STA_TACOS_WATCHDOG_ENABLED
|
#ifdef STA_TACOS_WATCHDOG_ENABLED
|
||||||
STA_WEAK
|
STA_WEAK
|
||||||
void onWatchdogInit()
|
void onWatchdogInit()
|
||||||
@ -158,8 +139,6 @@ namespace sta
|
|||||||
|
|
||||||
tacos::initStatemachine();
|
tacos::initStatemachine();
|
||||||
|
|
||||||
tacos::initManager();
|
|
||||||
|
|
||||||
#ifdef STA_TACOS_WATCHDOG_ENABLED
|
#ifdef STA_TACOS_WATCHDOG_ENABLED
|
||||||
tacos::initWatchdog();
|
tacos::initWatchdog();
|
||||||
#endif // STA_TACOS_WATCHDOG_ENABLED
|
#endif // STA_TACOS_WATCHDOG_ENABLED
|
||||||
@ -178,16 +157,14 @@ void startTACOS(void * arg)
|
|||||||
// Initialize HAL
|
// Initialize HAL
|
||||||
sta::initHAL();
|
sta::initHAL();
|
||||||
|
|
||||||
// Initialize RTOS system resources
|
// Initialize RTOS system events
|
||||||
sta::rtos::initSystem();
|
sta::tacos::initSystemEvents();
|
||||||
|
|
||||||
// Call further initialization code
|
// Call further initialization code
|
||||||
sta::tacos::startupExtras(arg);
|
sta::tacos::startupExtras(arg);
|
||||||
|
|
||||||
// Wake threads
|
// Wake threads
|
||||||
#ifdef STA_RTOS_SYSTEM_EVENTS_ENABLE
|
sta::tacos::signalStartupEvent();
|
||||||
sta::rtos::signalStartupEvent();
|
|
||||||
#endif // STA_RTOS_SYSTEM_EVENTS_ENABLE
|
|
||||||
|
|
||||||
// Check if called from thread
|
// Check if called from thread
|
||||||
if (osThreadGetId() != nullptr)
|
if (osThreadGetId() != nullptr)
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include <sta/tacos/statemachine.hpp>
|
#include <sta/tacos/statemachine.hpp>
|
||||||
|
|
||||||
#include <sta/debug/debug.hpp>
|
#include <sta/debug/debug.hpp>
|
||||||
|
#include <FreeRTOS.h>
|
||||||
|
|
||||||
|
|
||||||
namespace sta
|
namespace sta
|
||||||
@ -20,14 +21,15 @@ namespace sta
|
|||||||
currentState_{STA_TACOS_INITIAL_STATE},
|
currentState_{STA_TACOS_INITIAL_STATE},
|
||||||
lockoutTimer_{[](void *){}, nullptr},
|
lockoutTimer_{[](void *){}, nullptr},
|
||||||
failsafeTimer_{[](void *){}, nullptr},
|
failsafeTimer_{[](void *){}, nullptr},
|
||||||
queue_{STA_TACOS_STATEMACHINE_QUEUE_LENGTH}
|
queue_{STA_TACOS_STATEMACHINE_QUEUE_LENGTH},
|
||||||
|
threads_{}
|
||||||
{
|
{
|
||||||
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()
|
||||||
{
|
{
|
||||||
|
startThreads(getCurrentState());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Statemachine::func()
|
void Statemachine::func()
|
||||||
@ -42,8 +44,11 @@ namespace sta
|
|||||||
STA_ASSERT(transition.to < STA_TACOS_NUM_STATES);
|
STA_ASSERT(transition.to < STA_TACOS_NUM_STATES);
|
||||||
|
|
||||||
#ifdef STA_TACOS_CAN_BUS_ENABLED
|
#ifdef STA_TACOS_CAN_BUS_ENABLED
|
||||||
// Publish the state via CAN bus.
|
if (transition.publish)
|
||||||
tacos::publishState(transition.from, transition.to, 0);
|
{
|
||||||
|
// Publish the state via CAN bus.
|
||||||
|
tacos::publishState(transition.from, transition.to, 0);
|
||||||
|
}
|
||||||
#endif // STA_TACOS_CAN_BUS_ENABLED
|
#endif // STA_TACOS_CAN_BUS_ENABLED
|
||||||
|
|
||||||
// Perform the transition and notify the threads. The event flags are set
|
// Perform the transition and notify the threads. The event flags are set
|
||||||
@ -64,6 +69,16 @@ namespace sta
|
|||||||
{
|
{
|
||||||
setLockoutTimer(transition.lockout);
|
setLockoutTimer(transition.lockout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get heap stats at the end of the state transition
|
||||||
|
HeapStats_t stats;
|
||||||
|
vPortGetHeapStats(&stats);
|
||||||
|
|
||||||
|
// Execute the user-defined callback.
|
||||||
|
sta::tacos::onStateTransition(transition.from, transition.to, transition.lockout);
|
||||||
|
|
||||||
|
// Start all new tasks and stop all the tasks that aren't supposed to be running.
|
||||||
|
updateThreads();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,7 +87,7 @@ namespace sta
|
|||||||
return currentState_;
|
return currentState_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Statemachine::requestStateTransition(uint32_t from, uint32_t to, uint32_t lockout /* = 0 */, bool force /* = 0 */, bool publish /* = true */)
|
void Statemachine::requestStateTransition(uint32_t from, uint32_t to, uint32_t lockout /* = 0 */, bool publish /* = true */)
|
||||||
{
|
{
|
||||||
StateTransition transition;
|
StateTransition transition;
|
||||||
transition.from = from;
|
transition.from = from;
|
||||||
@ -81,17 +96,28 @@ namespace sta
|
|||||||
transition.lockout = lockout;
|
transition.lockout = lockout;
|
||||||
transition.publish = publish;
|
transition.publish = publish;
|
||||||
|
|
||||||
// Force the transition if requested, but only if the requested state is different from the current one.
|
// Try to add a state transition request to the queue. Don't wait if another
|
||||||
if (force && transition.to != currentState_){
|
// thread is already requesting a state change.
|
||||||
|
queue_.put(transition, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Statemachine::forceStateTransition(uint32_t from, uint32_t to, uint32_t lockout /* = 0 */, bool publish /* = true */)
|
||||||
|
{
|
||||||
|
// Force the transition, but only if the requested state is different from the current one.
|
||||||
|
if (to != currentState_){
|
||||||
// Perform the transition and notify the threads. The event flags are set
|
// Perform the transition and notify the threads. The event flags are set
|
||||||
// here in order to allow threads to react immediately.
|
// here in order to allow threads to react immediately.
|
||||||
currentState_ = transition.to;
|
currentState_ = to;
|
||||||
|
|
||||||
#ifdef STA_TACOS_CAN_BUS_ENABLED
|
#ifdef STA_TACOS_CAN_BUS_ENABLED
|
||||||
tacos::publishState(transition.from, transition.to, transition.lockout);
|
if (publish)
|
||||||
|
{
|
||||||
|
// Publish the state via CAN bus.
|
||||||
|
tacos::publishState(from, to, 0);
|
||||||
|
}
|
||||||
#endif // STA_TACOS_CAN_BUS_ENABLED
|
#endif // STA_TACOS_CAN_BUS_ENABLED
|
||||||
|
|
||||||
Statemachine::stateChangeEvent.set(transition.event);
|
Statemachine::stateChangeEvent.set(EventFlags::NORMAL);
|
||||||
Statemachine::stateChangeEvent.clear(EventFlags::ALL);
|
Statemachine::stateChangeEvent.clear(EventFlags::ALL);
|
||||||
|
|
||||||
if (failsafeTimer_.isRunning())
|
if (failsafeTimer_.isRunning())
|
||||||
@ -100,14 +126,16 @@ namespace sta
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start the lockout timer if requested.
|
// Start the lockout timer if requested.
|
||||||
if (transition.lockout != 0)
|
if (lockout != 0)
|
||||||
{
|
{
|
||||||
setLockoutTimer(transition.lockout);
|
setLockoutTimer(lockout);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// Try to add a state transition request to the queue. Don't wait if another
|
// Execute the user-defined callback.
|
||||||
// thread is already requesting a state change.
|
sta::tacos::onStateTransition(from, to, lockout);
|
||||||
queue_.put(transition, 0);
|
|
||||||
|
// Start all new tasks and stop all the tasks that aren't supposed to be running.
|
||||||
|
updateThreads();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,7 +144,7 @@ namespace sta
|
|||||||
STA_ASSERT(to < STA_TACOS_NUM_STATES);
|
STA_ASSERT(to < STA_TACOS_NUM_STATES);
|
||||||
|
|
||||||
failsafeTimer_.setCallback([from, to, lockout, publish](void* arg) {
|
failsafeTimer_.setCallback([from, to, lockout, publish](void* arg) {
|
||||||
Statemachine::instance()->requestStateTransition(from, to, lockout, false, publish);
|
Statemachine::instance()->requestStateTransition(from, to, lockout, publish);
|
||||||
}, NULL);
|
}, NULL);
|
||||||
|
|
||||||
failsafeTimer_.start(millis);
|
failsafeTimer_.start(millis);
|
||||||
@ -130,6 +158,66 @@ namespace sta
|
|||||||
lockoutTimer_.start(millis);
|
lockoutTimer_.start(millis);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Statemachine::registerThread(std::shared_ptr<TacosThread> thread, std::set<uint16_t> states)
|
||||||
|
{
|
||||||
|
for (uint16_t state : states)
|
||||||
|
{
|
||||||
|
STA_ASSERT(state < STA_TACOS_NUM_STATES);
|
||||||
|
|
||||||
|
threads_[state].push_back(thread);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<TacosThread>> Statemachine::getActiveThreads()
|
||||||
|
{
|
||||||
|
return threads_[tacos::getState()];
|
||||||
|
}
|
||||||
|
|
||||||
|
void Statemachine::startThreads(uint16_t state)
|
||||||
|
{
|
||||||
|
STA_ASSERT(state < STA_TACOS_NUM_STATES);
|
||||||
|
|
||||||
|
for (std::shared_ptr<TacosThread> thread : threads_[state])
|
||||||
|
{
|
||||||
|
if (!thread->isRunning())
|
||||||
|
{
|
||||||
|
thread->start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Statemachine::stopThreads(uint16_t state)
|
||||||
|
{
|
||||||
|
std::set<std::shared_ptr<TacosThread>> terminated;
|
||||||
|
|
||||||
|
for (uint16_t other = 0; other < STA_TACOS_NUM_STATES; ++other)
|
||||||
|
{
|
||||||
|
if (other == state)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::shared_ptr<TacosThread> thread : threads_[other])
|
||||||
|
{
|
||||||
|
// If the thread is currently running but not part of the set of threads that should be running...
|
||||||
|
if (thread->isRunning() && terminated.count(thread) == 0 && std::count(threads_[state].begin(), threads_[state].end(), thread) == 0)
|
||||||
|
{
|
||||||
|
// ...politely request termination.
|
||||||
|
thread->requestTermination();
|
||||||
|
terminated.emplace(thread);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Statemachine::updateThreads()
|
||||||
|
{
|
||||||
|
uint16_t state = getCurrentState();
|
||||||
|
|
||||||
|
stopThreads(state);
|
||||||
|
startThreads(state);
|
||||||
|
}
|
||||||
|
|
||||||
Statemachine* Statemachine::_instance = nullptr;
|
Statemachine* Statemachine::_instance = nullptr;
|
||||||
|
|
||||||
RtosEvent Statemachine::stateChangeEvent;
|
RtosEvent Statemachine::stateChangeEvent;
|
||||||
|
@ -16,9 +16,14 @@ namespace sta
|
|||||||
return Statemachine::instance()->getCurrentState();
|
return Statemachine::instance()->getCurrentState();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setState(uint32_t from, uint32_t to, uint32_t lockout /* = 0 */, bool force /* = false */, bool publish /* = false */)
|
void requestState(uint32_t from, uint32_t to, uint32_t lockout /* = 0 */, bool publish /* = true */)
|
||||||
{
|
{
|
||||||
Statemachine::instance()->requestStateTransition(from, to, lockout, force, publish);
|
Statemachine::instance()->requestStateTransition(from, to, lockout, publish);
|
||||||
|
}
|
||||||
|
|
||||||
|
void forceState(uint32_t from, uint32_t to, uint32_t lockout /* = 0 */, bool publish /* = true */)
|
||||||
|
{
|
||||||
|
Statemachine::instance()->forceStateTransition(from, to, lockout, publish);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setStateTimed(uint32_t from, uint32_t to, uint32_t millis, uint32_t lockout /* = 0 */, bool publish /* = false */)
|
void setStateTimed(uint32_t from, uint32_t to, uint32_t millis, uint32_t lockout /* = 0 */, bool publish /* = false */)
|
||||||
|
@ -7,9 +7,10 @@
|
|||||||
|
|
||||||
|
|
||||||
#include <sta/tacos/thread.hpp>
|
#include <sta/tacos/thread.hpp>
|
||||||
|
#include <sta/tacos/system/events.hpp>
|
||||||
|
|
||||||
#include <sta/debug/assert.hpp>
|
#include <sta/debug/assert.hpp>
|
||||||
#include <sta/debug/debug.hpp>
|
#include <sta/debug/debug.hpp>
|
||||||
#include <sta/rtos/system/events.hpp>
|
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@ -63,7 +64,7 @@ namespace sta
|
|||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
// The thread has to wait until the system startup has been completed.
|
// The thread has to wait until the system startup has been completed.
|
||||||
rtos::waitForStartupEvent();
|
sta::tacos::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);
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#ifdef STA_TACOS_WATCHDOG_ENABLED
|
#ifdef STA_TACOS_WATCHDOG_ENABLED
|
||||||
|
|
||||||
#include <sta/tacos/manager.hpp>
|
#include <sta/tacos/statemachine.hpp>
|
||||||
|
|
||||||
namespace sta
|
namespace sta
|
||||||
{
|
{
|
||||||
@ -10,7 +10,7 @@ namespace sta
|
|||||||
{
|
{
|
||||||
void Watchdog::func()
|
void Watchdog::func()
|
||||||
{
|
{
|
||||||
for (std::shared_ptr<TacosThread> thread : Manager::instance()->getActiveThreads())
|
for (std::shared_ptr<TacosThread> thread : Statemachine::instance()->getActiveThreads())
|
||||||
{
|
{
|
||||||
switch (thread->getStatus())
|
switch (thread->getStatus())
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user