1 /*
2  * Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #ifndef _PICO_ASYNC_CONTEXT_FREERTOS_H
8 #define _PICO_ASYNC_CONTEXT_FREERTOS_H
9 
10 /** \file pico/async_context.h
11  *  \defgroup async_context_freertos async_context_freertos
12  *  \ingroup pico_async_context
13  *
14  * async_context_freertos provides an implementation of \ref async_context that handles asynchronous
15  * work in a separate FreeRTOS task.
16  */
17 #include "pico/async_context.h"
18 
19 // FreeRTOS includes
20 #include "FreeRTOS.h"
21 #include "semphr.h"
22 #include "timers.h"
23 
24 #ifdef __cplusplus
25 extern "C" {
26 #endif
27 
28 #ifndef ASYNC_CONTEXT_DEFAULT_FREERTOS_TASK_PRIORITY
29 #define ASYNC_CONTEXT_DEFAULT_FREERTOS_TASK_PRIORITY ( tskIDLE_PRIORITY + 4)
30 #endif
31 
32 #ifndef ASYNC_CONTEXT_DEFAULT_FREERTOS_TASK_STACK_SIZE
33 #define ASYNC_CONTEXT_DEFAULT_FREERTOS_TASK_STACK_SIZE configMINIMAL_STACK_SIZE
34 #endif
35 
36 typedef struct async_context_freertos async_context_freertos_t;
37 
38 /**
39  * \brief Configuration object for async_context_freertos instances.
40  */
41 typedef struct async_context_freertos_config {
42     /**
43      * Task priority for the async_context task
44      */
45     UBaseType_t task_priority;
46     /**
47      * Stack size for the async_context task
48      */
49     configSTACK_DEPTH_TYPE task_stack_size;
50     /**
51      * the core ID (see \ref portGET_CORE_ID()) to pin the task to.
52      * This is only relevant in SMP mode.
53      */
54 #if configUSE_CORE_AFFINITY && configNUM_CORES > 1
55     UBaseType_t task_core_id;
56 #endif
57 } async_context_freertos_config_t;
58 
59 struct async_context_freertos {
60     async_context_t core;
61     SemaphoreHandle_t lock_mutex;
62     SemaphoreHandle_t work_needed_sem;
63     TimerHandle_t timer_handle;
64     TaskHandle_t task_handle;
65     uint8_t nesting;
66     volatile bool task_should_exit;
67 };
68 
69 /*!
70  * \brief Initialize an async_context_freertos instance using the specified configuration
71  * \ingroup async_context_freertos
72  *
73  * If this method succeeds (returns true), then the async_context is available for use
74  * and can be de-initialized by calling async_context_deinit().
75  *
76  * \param self a pointer to async_context_freertos structure to initialize
77  * \param config the configuration object specifying characteristics for the async_context
78  * \return true if initialization is successful, false otherwise
79  */
80 bool async_context_freertos_init(async_context_freertos_t *self, async_context_freertos_config_t *config);
81 
82 /*!
83  * \brief Return a copy of the default configuration object used by \ref async_context_freertos_init_with_defaults()
84  * \ingroup async_context_freertos
85  *
86  * The caller can then modify just the settings it cares about, and call \ref async_context_freertos_init()
87  * \return the default configuration object
88  */
async_context_freertos_default_config(void)89  static inline async_context_freertos_config_t async_context_freertos_default_config(void) {
90     async_context_freertos_config_t config = {
91             .task_priority = ASYNC_CONTEXT_DEFAULT_FREERTOS_TASK_PRIORITY,
92             .task_stack_size = ASYNC_CONTEXT_DEFAULT_FREERTOS_TASK_STACK_SIZE,
93 #if configUSE_CORE_AFFINITY && configNUM_CORES > 1
94             .task_core_id = (UBaseType_t)-1, // none
95 #endif
96     };
97     return config;
98 
99 }
100 
101 /*!
102  * \brief Initialize an async_context_freertos instance with default values
103  * \ingroup async_context_freertos
104  *
105  * If this method succeeds (returns true), then the async_context is available for use
106  * and can be de-initialized by calling async_context_deinit().
107  *
108  * \param self a pointer to async_context_freertos structure to initialize
109  * \return true if initialization is successful, false otherwise
110  */
async_context_freertos_init_with_defaults(async_context_freertos_t * self)111  static inline bool async_context_freertos_init_with_defaults(async_context_freertos_t *self) {
112     async_context_freertos_config_t config = async_context_freertos_default_config();
113     return async_context_freertos_init(self, &config);
114 }
115 
116 #ifdef __cplusplus
117 }
118 #endif
119 
120 #endif
121