Line |
Branch |
Exec |
Source |
1 |
|
|
/* |
2 |
|
|
* Copyright (c) 2022-2023, The Puppy RTOS Authors |
3 |
|
|
* |
4 |
|
|
* SPDX-License-Identifier: Apache-2.0 |
5 |
|
|
*/ |
6 |
|
|
#ifndef PUPPY_INC_UTIL_H__ |
7 |
|
|
#define PUPPY_INC_UTIL_H__ |
8 |
|
|
|
9 |
|
|
int p_hw_borad_init(void); |
10 |
|
|
int p_hw_cons_getc(void); |
11 |
|
|
int p_hw_cons_output(const char *str, int len); |
12 |
|
|
int printk(const char *fmt, ...); |
13 |
|
|
|
14 |
|
|
#define P_ROM_SECTION "puppy_rom_sym." |
15 |
|
|
#define P_RAM_SECTION "puppy_ram_sym." |
16 |
|
|
|
17 |
|
|
#define P_SECTION_DATA(x) p_section(x ".1") |
18 |
|
|
#define P_SECTION_START_DEFINE(x, name) p_used static p_base_t name p_section(x ".0") |
19 |
|
|
#define P_SECTION_END_DEFINE(x, name) p_used static p_base_t name p_section(x ".2") |
20 |
|
|
#define P_SECTION_START_ADDR(name) (&name + 1) |
21 |
|
|
#define P_SECTION_END_ADDR(name) (&name) |
22 |
|
|
|
23 |
|
|
#define P_TC_PASS() printk("Test Passed! at %s:%d\r\n", __FUNCTION__, __LINE__); |
24 |
|
|
#define P_TC_FAIL() printk("Test Failed! at %s:%d\r\n", __FUNCTION__, __LINE__); |
25 |
|
|
#define P_TC_LOG(...) do {printk(__VA_ARGS__); printk("\r\n");} while (0); |
26 |
|
|
|
27 |
|
|
struct p_ex_fn |
28 |
|
|
{ |
29 |
|
|
const char *name; |
30 |
|
|
void (*func)(void); |
31 |
|
|
}; |
32 |
|
|
|
33 |
|
|
#define P_TC_SECTION P_ROM_SECTION "P_TC_LIST" |
34 |
|
|
#define P_TC_FUNC(fn, name) \ |
35 |
|
|
p_used const static struct p_ex_fn _p_tc_##fn \ |
36 |
|
|
P_SECTION_DATA(P_TC_SECTION) = { #name, fn} |
37 |
|
|
|
38 |
|
|
#define P_INIT_SECTION P_ROM_SECTION "P_INIT_LIST" |
39 |
|
|
#define P_INIT_FUNC(fn) \ |
40 |
|
|
p_used const char _init_##fn##_name[] = #fn; \ |
41 |
|
|
p_used const static struct p_ex_fn _init_##fn \ |
42 |
|
|
P_SECTION_DATA(P_INIT_SECTION) = { _init_##fn##_name, fn} |
43 |
|
|
|
44 |
|
|
/** |
45 |
|
|
* p_container_of - return the start address of struct type, while ptr is the |
46 |
|
|
* member of struct type. |
47 |
|
|
*/ |
48 |
|
|
#define p_container_of(ptr, type, member) \ |
49 |
|
|
((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member))) |
50 |
|
|
|
51 |
|
|
/** |
52 |
|
|
* @brief list |
53 |
|
|
* |
54 |
|
|
*/ |
55 |
|
|
struct _list_node { |
56 |
|
|
union { |
57 |
|
|
struct _list_node *head; /* ptr to head of list (p_list_t) */ |
58 |
|
|
struct _list_node *next; /* ptr to next node (p_node_t) */ |
59 |
|
|
}; |
60 |
|
|
union { |
61 |
|
|
struct _list_node *tail; /* ptr to tail of list (p_list_t) */ |
62 |
|
|
struct _list_node *prev; /* ptr to previous node (p_node_t) */ |
63 |
|
|
}; |
64 |
|
|
}; |
65 |
|
|
typedef struct _list_node p_list_t; |
66 |
|
|
typedef struct _list_node p_node_t; |
67 |
|
|
|
68 |
|
|
|
69 |
|
|
|
70 |
|
|
/** |
71 |
|
|
* @brief get the struct for this entry |
72 |
|
|
* @param node the entry point |
73 |
|
|
* @param type the type of structure |
74 |
|
|
* @param member the name of list in structure |
75 |
|
|
*/ |
76 |
|
|
#define p_list_entry(node, type, member) \ |
77 |
|
|
p_container_of(node, type, member) |
78 |
|
|
|
79 |
|
|
/** |
80 |
|
|
* @brief Provide the primitive to iterate on a list |
81 |
|
|
* Note: the loop is unsafe and thus node should not be removed |
82 |
|
|
* @param list A pointer on a p_list_t to iterate on. |
83 |
|
|
* @param node A p_node_t pointer to peek each node of the list |
84 |
|
|
*/ |
85 |
|
|
#define p_list_for_each_node(list, node) \ |
86 |
|
|
for (node = (list)->head; node != (list); node = node->next) |
87 |
|
|
|
88 |
|
|
/** |
89 |
|
|
* @brief Provide the primitive to safely iterate on a list |
90 |
|
|
* Note: node can be removed, it will not break the loop. |
91 |
|
|
* @param list A pointer on a p_list_t to iterate on. |
92 |
|
|
* @param node A p_node_t pointer to peek each node of the list |
93 |
|
|
* @param node_s A p_node_t pointer for the loop to run safely |
94 |
|
|
*/ |
95 |
|
|
#define p_list_for_each_node_safe(list, node, node_s) \ |
96 |
|
|
for (node = (list)->head, node_s = node->next; node != (list); \ |
97 |
|
|
node = node_s, node_s = node->next) |
98 |
|
|
|
99 |
|
|
#define P_LIST_STATIC_INIT(list_ptr) { {(list_ptr)}, {(list_ptr)} } |
100 |
|
|
|
101 |
|
35 |
static inline void p_list_init(p_list_t *list) |
102 |
|
|
{ |
103 |
|
35 |
list->head = list->tail = list; |
104 |
|
35 |
} |
105 |
|
|
|
106 |
|
5343 |
static inline bool p_list_is_empty(p_list_t *list) |
107 |
|
|
{ |
108 |
|
5343 |
return list->head == list; |
109 |
|
|
} |
110 |
|
|
|
111 |
|
66 |
static inline bool p_node_is_linked(p_node_t *node) |
112 |
|
|
{ |
113 |
|
66 |
return node->next != NULL; |
114 |
|
|
} |
115 |
|
|
|
116 |
|
|
/** |
117 |
|
|
* @brief add node to tail of list |
118 |
|
|
* |
119 |
|
|
* This and other p_list_*() functions are not thread safe. |
120 |
|
|
* |
121 |
|
|
* @param list the doubly-linked list to operate on |
122 |
|
|
* @param node the element to append |
123 |
|
|
*/ |
124 |
|
|
|
125 |
|
543 |
static inline void p_list_append(p_list_t *list, p_node_t *node) |
126 |
|
|
{ |
127 |
|
543 |
p_node_t *const tail = list->tail; |
128 |
|
|
|
129 |
|
543 |
node->next = list; |
130 |
|
543 |
node->prev = tail; |
131 |
|
|
|
132 |
|
543 |
tail->next = node; |
133 |
|
543 |
list->tail = node; |
134 |
|
543 |
} |
135 |
|
|
|
136 |
|
|
/** |
137 |
|
|
* @brief add node to head of list |
138 |
|
|
* |
139 |
|
|
* This and other p_list_*() functions are not thread safe. |
140 |
|
|
* |
141 |
|
|
* @param list the doubly-linked list to operate on |
142 |
|
|
* @param node the element to append |
143 |
|
|
*/ |
144 |
|
|
|
145 |
|
|
static inline void p_list_prepend(p_list_t *list, p_node_t *node) |
146 |
|
|
{ |
147 |
|
|
p_node_t *const head = list->head; |
148 |
|
|
|
149 |
|
|
node->next = head; |
150 |
|
|
node->prev = list; |
151 |
|
|
|
152 |
|
|
head->prev = node; |
153 |
|
|
list->head = node; |
154 |
|
|
} |
155 |
|
|
|
156 |
|
|
/** |
157 |
|
|
* @brief Insert a node into a list |
158 |
|
|
* |
159 |
|
|
* Insert a node before a specified node in a dlist. |
160 |
|
|
* |
161 |
|
|
* @param successor the position before which "node" will be inserted |
162 |
|
|
* @param node the element to insert |
163 |
|
|
*/ |
164 |
|
19 |
static inline void p_list_insert(p_node_t *successor, p_node_t *node) |
165 |
|
|
{ |
166 |
|
19 |
p_node_t *const prev = successor->prev; |
167 |
|
|
|
168 |
|
19 |
node->prev = prev; |
169 |
|
19 |
node->next = successor; |
170 |
|
19 |
prev->next = node; |
171 |
|
19 |
successor->prev = node; |
172 |
|
19 |
} |
173 |
|
|
|
174 |
|
|
/** |
175 |
|
|
* @brief remove node from list. |
176 |
|
|
* @param node the node to remove from the list. |
177 |
|
|
*/ |
178 |
|
552 |
static inline void p_list_remove(p_node_t *node) |
179 |
|
|
{ |
180 |
|
552 |
node->next->prev = node->prev; |
181 |
|
552 |
node->prev->next = node->next; |
182 |
|
|
|
183 |
|
552 |
node->prev = node->next = NULL; |
184 |
|
552 |
} |
185 |
|
|
|
186 |
|
|
typedef struct { |
187 |
|
|
uint8_t *buffer; |
188 |
|
|
size_t size; |
189 |
|
|
atomic_size_t head; |
190 |
|
|
atomic_size_t tail; |
191 |
|
|
} p_rb_t; |
192 |
|
|
|
193 |
|
|
static inline bool p_rb_init(p_rb_t *rb, uint8_t *buffer, size_t size) |
194 |
|
|
{ |
195 |
|
|
if (rb == NULL || buffer == NULL || size == 0) |
196 |
|
|
{ |
197 |
|
|
return false; |
198 |
|
|
} |
199 |
|
|
rb->buffer = buffer; |
200 |
|
|
rb->size = size; |
201 |
|
|
atomic_init(&rb->head, 0); |
202 |
|
|
atomic_init(&rb->tail, 0); |
203 |
|
|
return true; |
204 |
|
|
} |
205 |
|
|
|
206 |
|
|
static inline bool p_rb_write(p_rb_t *rb, const uint8_t *data, size_t length) |
207 |
|
|
{ |
208 |
|
|
if (rb == NULL || data == NULL || length == 0) { |
209 |
|
|
return false; |
210 |
|
|
} |
211 |
|
|
|
212 |
|
|
size_t head = atomic_load_explicit(&rb->head, memory_order_relaxed); |
213 |
|
|
size_t tail = atomic_load_explicit(&rb->tail, memory_order_acquire); |
214 |
|
|
|
215 |
|
|
if (tail + rb->size - head < length) { |
216 |
|
|
return false; |
217 |
|
|
} |
218 |
|
|
|
219 |
|
|
for (size_t i = 0; i < length; ++i) { |
220 |
|
|
rb->buffer[head % rb->size] = data[i]; |
221 |
|
|
++head; |
222 |
|
|
} |
223 |
|
|
|
224 |
|
|
atomic_store_explicit(&rb->head, head, memory_order_release); |
225 |
|
|
|
226 |
|
|
return true; |
227 |
|
|
} |
228 |
|
|
|
229 |
|
|
static inline bool p_rb_read(p_rb_t *rb, uint8_t *data, size_t length) |
230 |
|
|
{ |
231 |
|
|
if (rb == NULL || data == NULL || length == 0) { |
232 |
|
|
return false; |
233 |
|
|
} |
234 |
|
|
|
235 |
|
|
size_t head = atomic_load_explicit(&rb->head, memory_order_acquire); |
236 |
|
|
size_t tail = atomic_load_explicit(&rb->tail, memory_order_relaxed); |
237 |
|
|
|
238 |
|
|
if (head - tail < length) { |
239 |
|
|
return false; |
240 |
|
|
} |
241 |
|
|
|
242 |
|
|
for (size_t i = 0; i < length; ++i) { |
243 |
|
|
data[i] = rb->buffer[tail % rb->size]; |
244 |
|
|
++tail; |
245 |
|
|
} |
246 |
|
|
|
247 |
|
|
atomic_store_explicit(&rb->tail, tail, memory_order_release); |
248 |
|
|
|
249 |
|
|
return true; |
250 |
|
|
} |
251 |
|
|
|
252 |
|
|
#endif |
253 |
|
|
|