1 /*
2  * Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #ifndef _PICO_ASYNC_CONTEXT_THREADSAFE_BACKGROUND_H
8 #define _PICO_ASYNC_CONTEXT_THREADSAFE_BACKGROUND_H
9 
10 /** \file pico/async_context.h
11  *  \defgroup async_context_threadsafe_background async_context_threadsafe_background
12  *  \ingroup pico_async_context
13  *
14  * \brief async_context_threadsafe_background provides an implementation of \ref async_context that handles asynchronous
15  * work in a low priority IRQ, and there is no need for the user to poll for work
16  *
17  * \note The workers used with this async_context MUST be safe to call from an IRQ.
18  */
19 
20 #include "pico/async_context.h"
21 #include "pico/sem.h"
22 #include "pico/mutex.h"
23 #include "hardware/irq.h"
24 
25 #ifdef __cplusplus
26 extern "C" {
27 #endif
28 
29 #ifndef ASYNC_CONTEXT_THREADSAFE_BACKGROUND_MULTI_CORE
30 #define ASYNC_CONTEXT_THREADSAFE_BACKGROUND_MULTI_CORE LIB_PICO_MULTICORE
31 #endif
32 
33 typedef struct async_context_threadsafe_background async_context_threadsafe_background_t;
34 
35 /**
36  * \brief Configuration object for async_context_threadsafe_background instances.
37  */
38 typedef struct async_context_threadsafe_background_config {
39 /**
40  * \brief the priority of the low priority IRQ
41  */
42     uint8_t low_priority_irq_handler_priority;
43     /**
44      * \brief a specific alarm pool to use (or NULL to use ta default)
45      *
46      * \note this alarm pool MUST be on the same core as the async_context
47      *
48      * The default alarm pool used is the "default alarm pool" (see
49      * \ref alarm_pool_get_default()) if available, and if that is on the same
50      * core, otherwise a private alarm_pool instance created during
51      * initialization.
52      */
53     alarm_pool_t *custom_alarm_pool;
54 } async_context_threadsafe_background_config_t;
55 
56 struct async_context_threadsafe_background {
57     async_context_t core;
58     alarm_pool_t *alarm_pool; // this must be on the same core as core_num
59     absolute_time_t last_set_alarm_time;
60     recursive_mutex_t lock_mutex;
61     semaphore_t work_needed_sem;
62     volatile alarm_id_t alarm_id;
63 #if ASYNC_CONTEXT_THREADSAFE_BACKGROUND_MULTI_CORE
64     volatile alarm_id_t force_alarm_id;
65     bool alarm_pool_owned;
66 #endif
67     uint8_t low_priority_irq_num;
68     volatile bool alarm_pending;
69 };
70 
71 /*!
72  * \brief Initialize an async_context_threadsafe_background instance using the specified configuration
73  * \ingroup async_context_threadsafe_background
74  *
75  * If this method succeeds (returns true), then the async_context is available for use
76  * and can be de-initialized by calling async_context_deinit().
77  *
78  * \param self a pointer to async_context_threadsafe_background structure to initialize
79  * \param config the configuration object specifying characteristics for the async_context
80  * \return true if initialization is successful, false otherwise
81  */
82 bool async_context_threadsafe_background_init(async_context_threadsafe_background_t *self, async_context_threadsafe_background_config_t *config);
83 
84 /*!
85  * \brief Return a copy of the default configuration object used by \ref async_context_threadsafe_background_init_with_defaults()
86  * \ingroup async_context_threadsafe_background
87  *
88  * The caller can then modify just the settings it cares about, and call \ref async_context_threadsafe_background_init()
89  * \return the default configuration object
90  */
91 async_context_threadsafe_background_config_t async_context_threadsafe_background_default_config(void);
92 
93 /*!
94  * \brief Initialize an async_context_threadsafe_background instance with default values
95  * \ingroup async_context_threadsafe_background
96  *
97  * If this method succeeds (returns true), then the async_context is available for use
98  * and can be de-initialized by calling async_context_deinit().
99  *
100  * \param self a pointer to async_context_threadsafe_background structure to initialize
101  * \return true if initialization is successful, false otherwise
102  */
async_context_threadsafe_background_init_with_defaults(async_context_threadsafe_background_t * self)103 static inline bool async_context_threadsafe_background_init_with_defaults(async_context_threadsafe_background_t *self) {
104     async_context_threadsafe_background_config_t config = async_context_threadsafe_background_default_config();
105     return async_context_threadsafe_background_init(self, &config);
106 }
107 
108 #ifdef __cplusplus
109 }
110 #endif
111 
112 #endif
113