# Jobs Many names are given to digital procedures that occur on a system in the context of multitasking. FreeRTOS calls them "tasks", POSIX calls them "threads" and so on. To not confuse a FreeRTOS task with the processes that happen in `jescore`, they are called **"jobs"**. These jobs are connected to one or more FreeRTOS tasks, but they are more than just wrappers. A job exists as a `struct`, holding descriptions of what to do in case of invocation. Below is such a job `struct`: ```c typedef struct job_struct_t{ char name[__MAX_JOB_NAME_LEN_BYTE]; TaskHandle_t handle; uint32_t mem_size; uint8_t priority; void (*function) (void* p); char args[__MAX_JOB_ARGS_LEN_BYTE]; uint8_t is_loop; uint8_t is_singleton; uint8_t instances; e_role_t role; origin_t caller; void* param; jes_err_t error; QueueHandle_t notif_queue; SemaphoreHandle_t lock; uint32_t timing_begin; uint32_t timing_end; struct job_struct_t* pn; }job_struct_t; ``` #### Parameters ##### `name` Notice the emphasis on a dedicated string buffer. Not only does FreeRTOS require each task to have a name for debugging and tracing, but `jescore` gives it a second purpose. If desired, the job can be launched via the mentioned CLI by this exact name, making CLI integration **native**. ##### `handle` This is the same handle you would expect from FreeRTOS. It has exactly that same usage. ##### `mem_size` Allocated dynamic memory for the job in bytes. Is used by FreeRTOS. ##### `priority` Priority of the task. Be careful to give tasks that are always active the same priority, otherwise they won't be executed in parallel! This is also used by FreeRTOS. ##### `function` This is the user job you define, see [`your_function()`](https://github.com/jesdev-io/jescore/wiki/API-Documentation#void-your_functionvoid-p). ##### `args` Arguments in string format. This field can be set in 3 different ways: 1. Evoking the CLI with the name of a job with additional strings behind the job name will store these additional strings here. 2. Launching a job with [`jes_launch_job_args()`](https://github.com/jesdev-io/jescore/wiki/API-Documentation#jes_err_t-jes_launch_job_argsconst-char-name-const-char-args). This mimics the CLI behavior, but stays purely in memory. 3. Calling [`jes_job_set_args()`](https://github.com/jesdev-io/jescore/wiki/API-Documentation#jes_err_t-jes_job_set_argschar-s). However, this can only be done by the calling job to the calling job. These args can then be retrieved with [`jes_job_get_args()`](https://github.com/jesdev-io/jescore/wiki/API-Documentation#char-jes_job_get_argsvoid) from inside a job and be parsed accordingly. ##### `is_loop` This is a boolean variable that the user has to set truthfully. The reason for this is CLI interaction. If a job is finite, its optional output (such as a processing message) can be printed, before the header of the CLI is reprinted, ending the transaction. If a job is infinite, ergo contains `while(1)`, the CLI would never return if this job were to be evoked. For this reason, the header is reprinted **before** the infinite job is evoked. ##### `is_singleton` This is a boolean variable that controls whether only one instance of this job can run at a time. If set to 1 (true), launching the job while it's already running will fail with `e_err_duplicate`. If set to 0 (false), multiple instances of the same job can run concurrently. ##### `instances` A job can be started multiple times concurrently, as long as they don't create resource sharing conflicts and `is_singleton` is set to 0. This variable counts how many instances of the same registered job exist at any given point in time. ##### `role` This is an internal variable that describes what kind of role the job fulfills in a hierarchical context. Core jobs are listed as core-role, base jobs have their own role and finally, user jobs as well. This is important for access rights. ##### `caller` The caller describes the origin of the job invocation. It can take on these values: ```c typedef enum origin_t{ e_origin_undefined, e_origin_interrupt, e_origin_cli, e_origin_core, e_origin_api, }origin_t; ``` Anything called by the API functions will have the `e_origin_api` role, anything called by the CLI `e_origin_cli` and so on. ##### `param` This is the content of the optional `param`, see [`jes_job_set_param()`](https://github.com/jesdev-io/jescore/wiki/API-Documentation#jes_err_t-jes_job_set_paramvoid-p). ##### `error` If a system error occurs in the job that can be caught by `jescore`, the job will be cancelled and the error will be stored here. This is helpful for tracing issues. ##### `notif_queue` Notification queue handle for inter-job communication. ##### `lock` Task semaphore handle for locking the job in multitasking context. ##### `timing_begin` Timestamp for the beginning of a job execution. This can be used for benchmarking. Use [`__job_set_timing_begin()`](https://github.com/jesdev-io/jescore/wiki/API-Documentation) to set this manually in your job code. ##### `timing_end` Timestamp for the end of a job execution. This can be used for benchmarking. Use [`__job_set_timing_end()`](https://github.com/jesdev-io/jescore/wiki/API-Documentation) to set this manually in your job code. ##### `pn` Now for the coolest thing: Job-structs themselves are arranged in a **linked list**. As soon as you register them, they become a member of the list, which gives `jescore` the ability to create a **journal** of the specified jobs. You can search through this journal and get every job, status, resource... Whatever you wish to get. If this reminds you somewhat of system-daemons on Linux, then I have reached my goal! # UART unified `jescore` runs in C, that was my requirement. This means, no existing Arduino FW unifications. For this reason, I wrote my own small abstraction package for UART peripherals of the ESP32 and STM32 MCUs. The driver code for that can be found in `lib/unified/uart_unif.c`. This file abstracts the differences in UART peripheral config from all mentioned MCUs. It compiles differently according to the macros `BUILD_FOR_STM32` and `BUILD_FOR_ESP32`, which are set by the detection of the automatically selected platform. **Support for "generic" Arduino and AVR is planned.** ## Board support For a complete and up-to-date list of all supported boards and platforms, see the dedicated [Board Support](Board-Support.md) page. How a board is supported depends on its macro implementation in `include/board_parser.h`. Here, the hardware specific interfaces are hooked up to generic macros that then enable `jescore` and CLI support on the MCU. If the CLI is disabled, `jescore` just needs FreeRTOS. If the CLI is enabled, it needs access to the UART stream that is in some way connected to a client PC. This is different for various boards. You can add your own UART board support for these platforms. See [Adding Board Support](Board-Support.md#adding-board-support) for more verbose details on how to add a new board. ### For ESP32 For the ESP32, this is straight forward, as the platform's UART peripheral shares ESP-IDF-framework code among the ESP32 families. If you want to use a custom UART on the ESP32, you only need to set the UART number, which is set in `BASE_UART`. Here's an example: ```bash # in compile command or platformio.ini -DJES_UART_CUSTOM -DBASE_UART=UART_NUM_ ``` where `` is the UART peripheral index (often index 0) and `JES_UART_CUSTOM` is a macro that tells the linker to not use the default UART for that board. ### For STM32 For the STM MCUs, this is more complicated. The following macros need to be set: ```c #define BUILD_PLATFORM_NAME "" #define USART_RCC_PERIPH RCC_PERIPHCLK_USART #define USART_CLK_SRC_DEFAULT(PeriphClkInit_struct) PeriphClkInit_struct.UsartClockSelection = __HAL_RCC_GET_USART_SOURCE() #define USART_CLK_ENABLE() __HAL_RCC_USART_CLK_ENABLE() #define USART_CLK_GPIO_ENABLE() __HAL_RCC_GPIO_CLK_ENABLE() #define USART_CLK_GPIO_DISABLE() __USART_CLK_DISABLE(); #define USART_NUM USART #define USART_GPIO_TX_PORT GPIO #define USART_GPIO_RX_PORT GPIO #define USART_GPIO_TX_NUM GPIO_PIN_ #define USART_GPIO_RX_NUM GPIO_PIN_ #define USART_GPIO_TX_ALT GPIO_AF_USART #define USART_GPIO_RX_ALT GPIO_AF_USART #define USART_IRQn_NUM USART_IRQn ``` where `` is the UART peripheral index (often index 2), `` is the GPIO bank of the UART TX and RX ``s. `` denotes the alternate function index and is specific to the MCU. If BUILD_PLATFORM_NAME is not set, it defaults to "STM32" without the specific family number. > **Note**: `uart_cfg.h` is only required for STM32 boards. For ESP32, the `JES_UART_CUSTOM` flag only requires defining `BASE_UART` (e.g., `-DBASE_UART=UART_NUM_1`), and no `uart_cfg.h` file is needed. You can define these macros in a file called `uart_cfg.h`, which you include in one of your source files and build process. If you then build with the flag `-DJES_UART_CUSTOM` or you define that macro in your main code, the file `uart_cfg.h` will be included. Here is an example: ```c #ifndef _UART_CFG_H_ #define _UART_CFG_H_ #define USART_RCC_PERIPH RCC_PERIPHCLK_USART2 #define USART_CLK_SRC_DEFAULT(PeriphClkInit_struct) PeriphClkInit_struct.Usart2ClockSelection = __HAL_RCC_GET_USART2_SOURCE() #define USART_CLK_ENABLE() __HAL_RCC_USART2_CLK_ENABLE() #define USART_CLK_GPIO_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() #define USART_CLK_GPIO_DISABLE() __USART2_CLK_DISABLE(); #define USART_NUM USART2 #define USART_GPIO_TX_PORT GPIOA #define USART_GPIO_RX_PORT GPIOA #define USART_GPIO_TX_NUM GPIO_PIN_2 #define USART_GPIO_RX_NUM GPIO_PIN_15 #define USART_GPIO_TX_ALT GPIO_AF7_USART2 #define USART_GPIO_RX_ALT GPIO_AF3_USART2 #define USART_IRQn_NUM USART2_IRQn #endif // _UART_CFG_H_ ```