forked from DangerousPrototypes/BusPirate5-firmware
-
Notifications
You must be signed in to change notification settings - Fork 0
/
queue.h
184 lines (162 loc) · 5.83 KB
/
queue.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _UTIL_QUEUE_H
#define _UTIL_QUEUE_H
#include "pico.h"
#include "hardware/sync.h"
/** \file queue.h
* \defgroup queue queue
* Multi-core and IRQ safe queue implementation.
*
* Note that this queue stores values of a specified size, and pushed values are copied into the queue
* \ingroup pico_util
*/
#include "pico/lock_core.h"
typedef struct {
lock_core_t core;
uint8_t *data;
uint16_t wptr;
uint16_t rptr;
uint16_t element_count;
} queue_t;
/*! \brief Initialise a queue with a specific spinlock for concurrency protection
* \ingroup queue
*
* \param q Pointer to a queue_t structure, used as a handle
* \param element_count Maximum number of entries in the queue
* \param spinlock_num The spin ID used to protect the queue
*/
void queue2_init_with_spinlock(queue_t *q, uint8_t *buf, uint element_count, uint spinlock_num);
/*! \brief Initialise a queue, allocating a (possibly shared) spinlock
* \ingroup queue
*
* \param q Pointer to a queue_t structure, used as a handle
* \param element_count Maximum number of entries in the queue
*/
static inline void queue2_init(queue_t *q, uint8_t *buf, uint element_count) {
return queue2_init_with_spinlock(q, buf, element_count, next_striped_spin_lock_num());
//return queue2_init_with_spinlock(q, buf, element_count, spin_lock_claim_unused(true));
}
void queue_available_bytes(queue_t *q, uint16_t* cnt);
void queue_update_read_pointer(queue_t *q, uint16_t* cnt);
void queue_available_bytes_unsafe(queue_t *q, uint16_t* cnt);
/*! \brief Unsafe check of level of the specified queue.
* \ingroup queue
*
* \param q Pointer to a queue_t structure, used as a handle
* \return Number of entries in the queue
*
* This does not use the spinlock, so may return incorrect results if the
* spin lock is not externally locked
*/
/*static inline uint queue2_get_level_unsafe(queue_t *q) {
int32_t rc = (int32_t)q->wptr - (int32_t)q->rptr;
if (rc < 0) {
rc += q->element_count + 1;
}
return (uint)rc;
}*/
/*! \brief Check of level of the specified queue.
* \ingroup queue
*
* \param q Pointer to a queue_t structure, used as a handle
* \return Number of entries in the queue
*/
/*static inline uint queue2_get_level(queue_t *q) {
uint32_t save = spin_lock_blocking(q->core.spin_lock);
uint level = queue2_get_level_unsafe(q);
spin_unlock(q->core.spin_lock, save);
return level;
}*/
/*! \brief Check if queue is empty
* \ingroup queue
*
* \param q Pointer to a queue_t structure, used as a handle
* \return true if queue is empty, false otherwise
*
* This function is interrupt and multicore safe.
*/
/*
static inline bool queue2_is_empty(queue_t *q) {
return queue2_get_level(q) == 0;
}
*/
/*! \brief Check if queue is full
* \ingroup queue
*
* \param q Pointer to a queue_t structure, used as a handle
* \return true if queue is full, false otherwise
*
* This function is interrupt and multicore safe.
*/
/*
static inline bool queue2_is_full(queue_t *q) {
return queue2_get_level(q) == q->element_count;
}
*/
// nonblocking queue access functions:
/*! \brief Non-blocking add value queue if not full
* \ingroup queue
*
* \param q Pointer to a queue_t structure, used as a handle
* \param data Pointer to value to be copied into the queue
* \return true if the value was added
*
* If the queue is full this function will return immediately with false, otherwise
* the data is copied into a new value added to the queue, and this function will return true.
*/
bool queue2_try_add(queue_t *q, const char *data);
/*! \brief Non-blocking removal of entry from the queue if non empty
* \ingroup queue
*
* \param q Pointer to a queue_t structure, used as a handle
* \param data Pointer to the location to receive the removed value
* \return true if a value was removed
*
* If the queue is not empty function will copy the removed value into the location provided and return
* immediately with true, otherwise the function will return immediately with false.
*/
bool queue2_try_remove(queue_t *q, char *data);
/*! \brief Non-blocking peek at the next item to be removed from the queue
* \ingroup queue
*
* \param q Pointer to a queue_t structure, used as a handle
* \param data Pointer to the location to receive the peeked value
* \return true if there was a value to peek
*
* If the queue is not empty this function will return immediately with true with the peeked entry
* copied into the location specified by the data parameter, otherwise the function will return false.
*/
bool queue2_try_peek(queue_t *q, char *data);
// blocking queue access functions:
/*! \brief Blocking add of value to queue
* \ingroup queue
*
* \param q Pointer to a queue_t structure, used as a handle
* \param data Pointer to value to be copied into the queue
*
* If the queue is full this function will block, until a removal happens on the queue
*/
void queue2_add_blocking(queue_t *q, const char *data);
/*! \brief Blocking remove entry from queue
* \ingroup queue
*
* \param q Pointer to a queue_t structure, used as a handle
* \param data Pointer to the location to receive the removed value
*
* If the queue is empty this function will block until a value is added.
*/
void queue2_remove_blocking(queue_t *q, char *data);
/*! \brief Blocking peek at next value to be removed from queue
* \ingroup queue
*
* \param q Pointer to a queue_t structure, used as a handle
* \param data Pointer to the location to receive the peeked value
*
* If the queue is empty function will block until a value is added
*/
void queue2_peek_blocking(queue_t *q, char *data);
#endif