1 /*
2 * Copyright (C) 2016 YunOS Project. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include <ble_os.h>
17 #include <string.h>
18 #include <misc/util.h>
19
20 #define BT_DBG_ENABLED IS_ENABLED(CONFIG_BLUETOOTH_DEBUG_CORE)
21
22 #include <bluetooth/log.h>
23 #include "mbox.h"
24
25 struct timer *g_timer_list;
26
27 #if defined(__cplusplus)
28 extern "C"
29 {
30 #endif
31
k_mbox_new(k_mbox_t ** mb,int size)32 int k_mbox_new(k_mbox_t **mb, int size)
33 {
34 k_mbox_t *mbox;
35 UNUSED(size);
36
37 mbox = (k_mbox_t *)malloc(sizeof(k_mbox_t));
38
39 if (mbox == NULL) {
40 return ERR_MEM;
41 }
42
43 memset(mbox, 0, sizeof(k_mbox_t));
44
45 mbox->first = mbox->last = 0;
46 k_sem_init(&mbox->not_empty, 0, 1);
47 k_sem_init(&mbox->not_full, 0, 1);
48 k_sem_init(&mbox->mutex, 1, 1);
49 mbox->wait_send = 0;
50
51 *mb = mbox;
52 BT_DBG("k_mbox_new: mbox 0x%lx\n", mbox);
53 return ERR_OK;
54 }
55
56 /*-----------------------------------------------------------------------------------*/
57 /*
58 Deallocates a mailbox. If there are messages still present in the
59 mailbox when the mailbox is deallocated, it is an indication of a
60 programming error in lwIP and the developer should be notified.
61 */
k_mbox_free(k_mbox_t * mb)62 void k_mbox_free(k_mbox_t *mb)
63 {
64 if (mb != NULL) {
65 k_mbox_t *mbox = mb;
66
67 k_sem_take(&mbox->mutex, K_FOREVER);
68
69 k_sem_delete(&mbox->not_empty);
70 k_sem_delete(&mbox->not_full);
71 k_sem_delete(&mbox->mutex);
72 BT_DBG("sys_mbox_free: mbox 0x%lx\n", mbox);
73 free(mbox);
74 }
75 }
76
77 /*-----------------------------------------------------------------------------------*/
78 /*
79 void sys_mbox_post(k_mbox_t *mbox, void *msg)
80
81 Posts the "msg" to the mailbox. This function have to block until the "msg" is really posted.
82 */
k_mbox_post(k_mbox_t * mb,void * msg)83 void k_mbox_post(k_mbox_t *mb, void *msg)
84 {
85 u8_t first;
86 k_mbox_t *mbox;
87
88 if (NULL == mb) {
89 BT_ERR("invaild mbox");
90 return;
91 }
92
93 mbox = mb;
94
95 k_sem_take(&mbox->mutex, K_FOREVER);
96
97 BT_DBG("sys_mbox_post: mbox %p msg %p\n", (void *)mbox, (void *)msg);
98
99 while ((mbox->last + 1) >= (mbox->first + K_MBOX_SIZE)) {
100 mbox->wait_send++;
101 k_sem_give(&mbox->mutex);
102 k_sem_take(&mbox->not_full, K_FOREVER);
103 k_sem_take(&mbox->mutex, K_FOREVER);
104 mbox->wait_send--;
105 }
106
107 mbox->msgs[mbox->last % K_MBOX_SIZE] = msg;
108
109 if (mbox->last == mbox->first) {
110 first = 1;
111 } else {
112 first = 0;
113 }
114
115 mbox->last++;
116
117 if (first) {
118 k_sem_give(&mbox->not_empty);
119 }
120
121 k_sem_give(&mbox->mutex);
122 }
123
124 /*
125 err_t k_mbox_trypost(k_mbox_t *mbox, void *msg)
126
127 Try to post the "msg" to the mailbox. Returns ERR_MEM if this one is full, else, ERR_OK if the "msg" is posted.
128 */
k_mbox_trypost(k_mbox_t * mb,void * msg)129 int k_mbox_trypost(k_mbox_t *mb, void *msg)
130 {
131 u8_t first;
132 k_mbox_t *mbox;
133
134 if (NULL == mb) {
135 BT_ERR("invaild mbox");
136 return ERR_MEM;
137 }
138
139 mbox = mb;
140
141 k_sem_take(&mbox->mutex, K_FOREVER);
142
143 BT_DBG("k_mbox_trypost: mbox %p msg %p\n", (void *)mbox, (void *)msg);
144
145 if ((mbox->last + 1) >= (mbox->first + K_MBOX_SIZE)) {
146 k_sem_give(&mbox->mutex);
147 return ERR_MEM;
148 }
149
150 mbox->msgs[mbox->last % K_MBOX_SIZE] = msg;
151
152 if (mbox->last == mbox->first) {
153 first = 1;
154 } else {
155 first = 0;
156 }
157
158 mbox->last++;
159
160 if (first) {
161 k_sem_give(&mbox->not_empty);
162 }
163
164 k_sem_give(&mbox->mutex);
165 return ERR_OK;
166 }
167
168 /*-----------------------------------------------------------------------------------*/
169 /*
170 Blocks the thread until a message arrives in the mailbox, but does
171 not block the thread longer than "timeout" milliseconds (similar to
172 the sys_arch_sem_wait() function). The "msg" argument is a result
173 parameter that is set by the function (i.e., by doing "*msg =
174 ptr"). The "msg" parameter maybe NULL to indicate that the message
175 should be dropped.
176
177 The return values are the same as for the sys_arch_sem_wait() function:
178 Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a
179 timeout.
180
181 Note that a function with a similar name, sys_mbox_fetch(), is
182 implemented by lwIP.
183 */
k_mbox_fetch(k_mbox_t * mb,void ** msg,uint32_t timeout)184 int k_mbox_fetch(k_mbox_t *mb, void **msg, uint32_t timeout)
185 {
186 uint32_t time_needed = 0;
187 k_mbox_t *mbox;
188
189 if (NULL == mb) {
190 BT_ERR("invaild mbox");
191 return ERR_MEM;
192 }
193
194 mbox = mb;
195 BT_DBG("mbox %p\n", mbox);
196
197 /* The mutex lock is quick so we don't bother with the timeout
198 stuff here. */
199 k_sem_take(&mbox->mutex, K_FOREVER);
200
201 BT_DBG("mutex taken\n");
202
203 while (mbox->first == mbox->last) {
204 k_sem_give(&mbox->mutex);
205
206 /* We block while waiting for a mail to arrive in the mailbox. We
207 must be prepared to timeout. */
208 if (timeout != 0) {
209 time_needed = k_sem_take(&mbox->not_empty, timeout);
210
211 if (time_needed == SYS_ARCH_TIMEOUT) {
212 return SYS_ARCH_TIMEOUT;
213 }
214 } else {
215 k_sem_take(&mbox->not_empty, K_FOREVER);
216 }
217
218 k_sem_take(&mbox->mutex, K_FOREVER);
219 }
220
221 if (msg != NULL) {
222 BT_DBG("sys_mbox_fetch: mbox %p msg %p\n", (void *)mbox, *msg);
223 *msg = mbox->msgs[mbox->first % K_MBOX_SIZE];
224 } else {
225 BT_DBG("sys_mbox_fetch: mbox %p, null msg\n", (void *)mbox);
226 }
227
228 mbox->first++;
229
230 if (mbox->wait_send) {
231 k_sem_give(&mbox->not_full);
232 }
233
234 k_sem_give(&mbox->mutex);
235
236 return time_needed;
237 }
238
239 /*
240 uint32_t sys_arch_mbox_tryfetch(k_mbox_t *mbox, void **msg)
241
242 similar to sys_arch_mbox_fetch, however if a message is not present in the mailbox,
243 it immediately returns with the code SYS_MBOX_EMPTY.
244 */
k_mbox_tryfetch(k_mbox_t * mb,void ** msg)245 int k_mbox_tryfetch(k_mbox_t *mb, void **msg)
246 {
247 k_mbox_t *mbox;
248
249 if (NULL == mb) {
250 BT_ERR("invaild mbox");
251 return ERR_MEM;
252 }
253
254 mbox = mb;
255
256 k_sem_take(&mbox->mutex, K_FOREVER);
257
258 if (mbox->first == mbox->last) {
259 k_sem_give(&mbox->mutex);
260 return SYS_MBOX_EMPTY;
261 }
262
263 if (msg != NULL) {
264 BT_DBG("k_mbox_tryfetch: mbox %p msg %p\n", (void *)mbox, *msg);
265 *msg = mbox->msgs[mbox->first % K_MBOX_SIZE];
266 } else {
267 BT_DBG("k_mbox_tryfetch: mbox %p, null msg\n", (void *)mbox);
268 }
269
270 mbox->first++;
271
272 if (mbox->wait_send) {
273 k_sem_give(&mbox->not_full);
274 }
275
276 k_sem_give(&mbox->mutex);
277
278 return 0;
279 }
280
281 #if defined(__cplusplus)
282 }
283 #endif
284