diff --git a/README.md b/README.md index 0a16532..d28f2d1 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,63 @@ # 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: -``` -Properties -> C/C++ General -> Paths and Symbols -> Includes -> GNU C -> Add... -Properties -> C/C++ General -> Paths and Symbols -> Includes -> GNU C++ -> Add... -Properties -> C/C++ General -> Paths and Symbols -> Source Location -> Add Folder... +## Setting up a TACOS project + +### Setting up the project + +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) { /* 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: -``` +```cpp #ifndef 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_WATCHDOG_ENABLE // #define STA_RTOS_WATCHDOG_ENABLE +// #define STA_TACOS_WATCHDOG_FREQUENCY 10000 #define STA_CAN_BUS_ENABLE // 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_ */ ``` PS: For not officially supported chips use this as the include: -``` +```cpp #include #define STA_MCU_LITTLE_ENDIAN #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 + +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 + +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 +#include + +#include + +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(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: 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} ``` -After this messages will automatically be forwarded to the task with it's ID. To send messages use the interface defined in `tacos.hpp`. \ No newline at end of file +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. \ No newline at end of file diff --git a/include/sta/README.md b/include/sta/README.md new file mode 100644 index 0000000..b39d0bc --- /dev/null +++ b/include/sta/README.md @@ -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 std::shared_ptr addThread(std::set 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. \ No newline at end of file diff --git a/include/sta/tacos/README.md b/include/sta/tacos/README.md new file mode 100644 index 0000000..cf4aafa --- /dev/null +++ b/include/sta/tacos/README.md @@ -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. \ No newline at end of file diff --git a/include/sta/tacos/c_api/README.md b/include/sta/tacos/c_api/README.md new file mode 100644 index 0000000..a842e64 --- /dev/null +++ b/include/sta/tacos/c_api/README.md @@ -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. \ No newline at end of file