tusb_os_custom.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2022 Gunar Schorcht
3  *
4  * This file is subject to the terms and conditions of the GNU Lesser
5  * General Public License v2.1. See the file LICENSE in the top level
6  * directory for more details.
7  */
8 
9 #pragma once
10 
21 #include "mutex.h"
22 #include "sema.h"
23 #include "ztimer.h"
24 
25 #ifdef __cplusplus
26 extern "C" {
27 #endif
28 
29 #if !DOXYGEN
30 
31 /* set to 1 to use cancelable mutex in osal_mutex and osal_queue */
32 #ifndef TINYUSB_OSAL_MUTEX_CANCELABLE
33 #define TINYUSB_OSAL_MUTEX_CANCELABLE 0
34 #endif
35 
40 TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec)
41 {
43 }
44 
51 typedef sema_t osal_semaphore_def_t; /* semaphore */
52 typedef sema_t *osal_semaphore_t; /* semaphore handle */
53 
54 TU_ATTR_ALWAYS_INLINE
55 static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef)
56 {
57  sema_create(semdef, 0);
58  return (osal_semaphore_t)semdef;
59 }
60 
61 TU_ATTR_ALWAYS_INLINE
62 static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr)
63 {
64  (void)in_isr; /* hasn't to be considered since RIOT doesn't block in sema_post */
65  return sema_post(sem_hdl) == 0;
66 }
67 
68 TU_ATTR_ALWAYS_INLINE
69 static inline bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec)
70 {
71  assert(0);
72  return sema_wait_timed_ztimer(sem_hdl, ZTIMER_MSEC, msec) == 0;
73 }
74 
75 TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t const sem_hdl)
76 {
77  (void)sem_hdl;
78  /* TODO, function seems to be removed anyway */
79 }
80 
82 typedef mutex_t osal_mutex_def_t; /* RIOT mutex */
83 typedef mutex_t *osal_mutex_t; /* RIOT mutex handle */
84 
85 TU_ATTR_ALWAYS_INLINE
86 static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef)
87 {
88  assert(mdef != NULL);
89  mutex_init((mutex_t *)mdef);
90  return (osal_mutex_t)mdef;
91 }
92 
93 #if TINYUSB_OSAL_MUTEX_CANCELABLE
94 static void _osal_mutex_lock_timeout(void *arg)
95 {
96  mutex_cancel(arg);
97 }
98 #endif
99 
100 TU_ATTR_ALWAYS_INLINE
101 static inline bool osal_mutex_lock(osal_mutex_t mutex_hdl, uint32_t msec)
102 {
103  assert(mutex_hdl);
104 #if TINYUSB_OSAL_MUTEX_CANCELABLE
105  mutex_cancel_t _mc = mutex_cancel_init(mutex_hdl);
106 
107  ztimer_t _timer = { .callback = _osal_mutex_lock_timeout, .arg = &_mc };
108  ztimer_set(ZTIMER_MSEC, &_timer, msec);
109 
110  return mutex_lock_cancelable(&_mc) == 0;
111 #else
112  (void)msec;
113  assert(msec == OSAL_TIMEOUT_WAIT_FOREVER);
114  mutex_lock(mutex_hdl);
115  return true;
116 #endif
117 }
118 
119 TU_ATTR_ALWAYS_INLINE
120 static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl)
121 {
122  assert(mutex_hdl);
123  mutex_unlock(mutex_hdl);
124  return true;
125 }
126 
131 #define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \
132  /* _int_set is not used in RTOS */ \
133  static _type _name##_##q_items[_depth]; /* queue item data storage */ \
134  osal_queue_def_t _name = { \
135  .buffer = _name##_##q_items, \
136  .size = sizeof(_type), \
137  .depth = _depth, \
138  };
139 
140 typedef struct {
141  list_node_t node;
142  void *data;
143 } osal_queue_entry;
144 
145 typedef struct {
146  void *buffer; /* buffer used for queue item data */
147  uint16_t size; /* queue item size */
148  uint16_t depth; /* maximum number of queue items */
149  uint16_t front;
150  uint16_t tail;
151  sema_t smphr; /* semaphore value represents the queue fill level */
152 } osal_queue_def_t;
153 
154 typedef osal_queue_def_t *osal_queue_t;
155 
156 TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef)
157 {
158  assert(qdef != NULL);
159 
160  qdef->front = 0;
161  qdef->tail = 0;
162 
163  sema_create(&qdef->smphr, 0);
164 
165  return (osal_queue_t)qdef;
166 }
167 
168 TU_ATTR_ALWAYS_INLINE
169 static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr)
170 {
171  assert(qhdl != NULL);
172  assert(data != NULL);
173 
174  if (sema_get_value(&qhdl->smphr) == qhdl->depth) {
175  /* queue is full */
176  if (in_isr) {
177  /* return in case of ISR */
178  return false;
179  }
180  /* We do not block the sending thread when `osal_queue_send` is called
181  * from a thread context and the queue is full. The call of function
182  * `osal_queue_send` is usually interrupt-driven and must not block
183  * anyway. There is only one exception in `src/class/msc/msc_device.c`
184  * where it is called in thread context. However, since the call of
185  * `osal_queue_send` would then be made in the same thread context as
186  * the call of the unlocking function `osal_queue_receive`, using a
187  * mutex to block the sending thread would not work here anyway.
188  * Therefore, we return with false in all cases when `NDEBUG` is
189  * defined, as most other implementations of `osal_queue_send` do,
190  * or point out the problem with assertion. */
191 #ifdef NDEBUG
192  return false;
193 #else
194  assert(0);
195 #endif
196  }
197 
198  /* copy the data to the queue item data */
199  memcpy(qhdl->buffer + (qhdl->tail * (qhdl->size)), data, qhdl->size);
200  /* update write pointer */
201  qhdl->tail = (qhdl->tail + 1) % qhdl->depth;
202 
203  /* unlock a possibly waiting receiving thread */
204  sema_post(&qhdl->smphr);
205 
206  return true;
207 }
208 
209 #if TINYUSB_OSAL_MUTEX_CANCELABLE
210 static void _osal_queue_lock_timeout(void *arg)
211 {
212  mutex_cancel(arg);
213 }
214 #endif
215 
216 TU_ATTR_ALWAYS_INLINE
217 static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec)
218 {
219  assert(qhdl != NULL);
220  assert(data != NULL);
221 
222  (void)msec;
223  /* In RIOT we use only `tusd_task` and `tush_task` functions which call
224  * `osal_queue_receive` with `OSAL_TIMEOUT_WAIT_FOREVER` (`UINT32_MAX`).
225  * Therefore we do not use `msec` and just call `sema_wait` without timeout
226  * handling here. */
227  if (sema_wait(&qhdl->smphr) != 0) {
228  /* timeout error or any other semaphore error on receiving */
229  return false;
230  }
231 
232  /* at least one item should be in the queue now */
233  assert(qhdl->front != qhdl->tail);
234 
235  /* copy data from queue item data */
236  memcpy(data, qhdl->buffer + (qhdl->front * (qhdl->size)), qhdl->size);
237  /* update read pointer */
238  qhdl->front = (qhdl->front + 1) % qhdl->depth;
239 
240  return true;
241 }
242 
243 TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl)
244 {
245  assert(qhdl != NULL);
246  return sema_get_value(&qhdl->smphr) == 0;
247 }
248 
249 #ifdef __cplusplus
250 }
251 #endif
252 
253 #endif /* !DOXYGEN */
#define assert(cond)
abort the program if assertion is false
Definition: assert.h:146
void mutex_unlock(mutex_t *mutex)
Unlocks the mutex.
void mutex_cancel(mutex_cancel_t *mc)
Cancels a call to mutex_lock_cancelable.
static mutex_cancel_t mutex_cancel_init(mutex_t *mutex)
Initialize a mutex cancellation structure.
Definition: mutex.h:170
int mutex_lock_cancelable(mutex_cancel_t *mc)
Locks a mutex, blocking.
static void mutex_init(mutex_t *mutex)
Initializes a mutex object.
Definition: mutex.h:144
static void mutex_lock(mutex_t *mutex)
Locks a mutex, blocking.
Definition: mutex.h:205
void sema_create(sema_t *sema, unsigned int value)
Creates semaphore dynamically.
static int sema_wait(sema_t *sema)
Wait for a semaphore being posted (without timeout).
Definition: sema.h:172
static int sema_wait_timed_ztimer(sema_t *sema, ztimer_clock_t *clock, uint32_t timeout)
Wait for a semaphore being posted, using ztimer as backend.
Definition: sema.h:232
static unsigned sema_get_value(const sema_t *sema)
Get a semaphore's current value.
Definition: sema.h:111
int sema_post(sema_t *sema)
Signal semaphore.
uint32_t ztimer_set(ztimer_clock_t *clock, ztimer_t *timer, uint32_t val)
Set a timer on a clock.
void ztimer_sleep(ztimer_clock_t *clock, uint32_t duration)
Put the calling thread to sleep for the specified number of ticks.
ztimer_clock_t *const ZTIMER_MSEC
Default ztimer millisecond clock.
Mutex for thread synchronization.
Semaphore definitions.
List node structure.
Definition: list.h:39
A cancellation structure for use with mutex_lock_cancelable and mutex_cancel.
Definition: mutex.h:106
Mutex structure.
Definition: mutex.h:39
A Semaphore.
Definition: sema.h:67
ztimer structure
Definition: ztimer.h:319
ztimer_callback_t callback
timer callback function pointer
Definition: ztimer.h:321
ztimer API