1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 #include <assert.h>
21 #include <errno.h>
22 #include <string.h>
23 #include "sysinit/sysinit.h"
24 #include "syscfg/syscfg.h"
25 #include "stats/stats.h"
26 #include "nimble/ble_hci_trans.h"
27 #include "ble_hs_priv.h"
28 #include "ble_monitor_priv.h"
29 #include "nimble/nimble_npl.h"
30 #ifndef MYNEWT
31 #include "nimble/nimble_port.h"
32 #endif
33
34 #define BLE_HS_HCI_EVT_COUNT \
35 (MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT) + \
36 MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT))
37
38 static void ble_hs_event_rx_hci_ev(struct ble_npl_event *ev);
39 static void ble_hs_event_tx_notify(struct ble_npl_event *ev);
40 static void ble_hs_event_reset(struct ble_npl_event *ev);
41 static void ble_hs_event_start_stage1(struct ble_npl_event *ev);
42 static void ble_hs_event_start_stage2(struct ble_npl_event *ev);
43 static void ble_hs_timer_sched(int32_t ticks_from_now);
44
45 struct os_mempool ble_hs_hci_ev_pool;
46 static os_membuf_t ble_hs_hci_os_event_buf[
47 OS_MEMPOOL_SIZE(BLE_HS_HCI_EVT_COUNT, sizeof(struct ble_npl_event))
48 ];
49
50 /** OS event - triggers tx of pending notifications and indications. */
51 static struct ble_npl_event ble_hs_ev_tx_notifications;
52
53 /** OS event - triggers a full reset. */
54 static struct ble_npl_event ble_hs_ev_reset;
55
56 static struct ble_npl_event ble_hs_ev_start_stage1;
57 static struct ble_npl_event ble_hs_ev_start_stage2;
58
59 uint8_t ble_hs_sync_state;
60 uint8_t ble_hs_enabled_state;
61 static int ble_hs_reset_reason;
62
63 #define BLE_HS_SYNC_RETRY_TIMEOUT_MS 100 /* ms */
64
65 static void *ble_hs_parent_task;
66
67 /**
68 * Handles unresponsive timeouts and periodic retries in case of resource
69 * shortage.
70 */
71 static struct ble_npl_callout ble_hs_timer;
72
73 /* Shared queue that the host uses for work items. */
74 static struct ble_npl_eventq *ble_hs_evq;
75
76 static struct ble_mqueue ble_hs_rx_q;
77
78 static struct ble_npl_mutex ble_hs_mutex;
79
80 /** These values keep track of required ATT and GATT resources counts. They
81 * increase as services are added, and are read when the ATT server and GATT
82 * server are started.
83 */
84 uint16_t ble_hs_max_attrs;
85 uint16_t ble_hs_max_services;
86 uint16_t ble_hs_max_client_configs;
87
88 #if MYNEWT_VAL(BLE_HS_DEBUG)
89 static uint8_t ble_hs_dbg_mutex_locked;
90 #endif
91
92 STATS_SECT_DECL(ble_hs_stats) ble_hs_stats;
93 STATS_NAME_START(ble_hs_stats)
STATS_NAME(ble_hs_stats,conn_create)94 STATS_NAME(ble_hs_stats, conn_create)
95 STATS_NAME(ble_hs_stats, conn_delete)
96 STATS_NAME(ble_hs_stats, hci_cmd)
97 STATS_NAME(ble_hs_stats, hci_event)
98 STATS_NAME(ble_hs_stats, hci_invalid_ack)
99 STATS_NAME(ble_hs_stats, hci_unknown_event)
100 STATS_NAME(ble_hs_stats, hci_timeout)
101 STATS_NAME(ble_hs_stats, reset)
102 STATS_NAME(ble_hs_stats, sync)
103 STATS_NAME(ble_hs_stats, pvcy_add_entry)
104 STATS_NAME(ble_hs_stats, pvcy_add_entry_fail)
105 STATS_NAME_END(ble_hs_stats)
106
107 struct ble_npl_eventq *ble_hs_evq_get(void)
108 {
109 return ble_hs_evq;
110 }
111
ble_hs_evq_set(struct ble_npl_eventq * evq)112 void ble_hs_evq_set(struct ble_npl_eventq *evq)
113 {
114 ble_hs_evq = evq;
115 }
116
117 #if MYNEWT_VAL(BLE_HS_DEBUG)
ble_hs_locked_by_cur_task(void)118 int ble_hs_locked_by_cur_task(void)
119 {
120 #if MYNEWT
121 struct os_task *owner;
122
123 if (!ble_npl_os_started()) {
124 return ble_hs_dbg_mutex_locked;
125 }
126
127 owner = ble_hs_mutex.mu.mu_owner;
128 return owner != NULL && owner == os_sched_get_current_task();
129 #else
130 return 1;
131 #endif
132 }
133 #endif
134
135 /**
136 * Indicates whether the host's parent task is currently running.
137 */
ble_hs_is_parent_task(void)138 int ble_hs_is_parent_task(void)
139 {
140 return !ble_npl_os_started() ||
141 ble_npl_get_current_task_id() == ble_hs_parent_task;
142 }
143
144 /**
145 * Locks the BLE host mutex. Nested locks allowed.
146 */
ble_hs_lock_nested(void)147 void ble_hs_lock_nested(void)
148 {
149 int rc;
150 #if MYNEWT_VAL(BLE_HS_DEBUG)
151
152 if (!ble_npl_os_started()) {
153 ble_hs_dbg_mutex_locked = 1;
154 return;
155 }
156
157 #endif
158 rc = ble_npl_mutex_pend(&ble_hs_mutex, 0xffffffff);
159 BLE_HS_DBG_ASSERT_EVAL(rc == 0 || rc == OS_NOT_STARTED);
160 }
161
162 /**
163 * Unlocks the BLE host mutex. Nested locks allowed.
164 */
ble_hs_unlock_nested(void)165 void ble_hs_unlock_nested(void)
166 {
167 int rc;
168 #if MYNEWT_VAL(BLE_HS_DEBUG)
169
170 if (!ble_npl_os_started()) {
171 ble_hs_dbg_mutex_locked = 0;
172 return;
173 }
174
175 #endif
176 rc = ble_npl_mutex_release(&ble_hs_mutex);
177 BLE_HS_DBG_ASSERT_EVAL(rc == 0 || rc == OS_NOT_STARTED);
178 }
179
180 /**
181 * Locks the BLE host mutex. Nested locks not allowed.
182 */
ble_hs_lock(void)183 void ble_hs_lock(void)
184 {
185 BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task());
186 #if MYNEWT_VAL(BLE_HS_DEBUG)
187
188 if (!ble_npl_os_started()) {
189 BLE_HS_DBG_ASSERT(!ble_hs_dbg_mutex_locked);
190 }
191
192 #endif
193 ble_hs_lock_nested();
194 }
195
196 /**
197 * Unlocks the BLE host mutex. Nested locks not allowed.
198 */
ble_hs_unlock(void)199 void ble_hs_unlock(void)
200 {
201 #if MYNEWT_VAL(BLE_HS_DEBUG)
202
203 if (!ble_npl_os_started()) {
204 BLE_HS_DBG_ASSERT(ble_hs_dbg_mutex_locked);
205 }
206
207 #endif
208 ble_hs_unlock_nested();
209 }
210
ble_hs_process_rx_data_queue(void)211 void ble_hs_process_rx_data_queue(void)
212 {
213 struct os_mbuf *om;
214 while ((om = ble_mqueue_get(&ble_hs_rx_q)) != NULL) {
215 #if BLE_MONITOR
216 ble_monitor_send_om(BLE_MONITOR_OPCODE_ACL_RX_PKT, om);
217 #endif
218 ble_hs_hci_evt_acl_process(om);
219 }
220 }
221
ble_hs_wakeup_tx_conn(struct ble_hs_conn * conn)222 static int ble_hs_wakeup_tx_conn(struct ble_hs_conn *conn)
223 {
224 struct os_mbuf_pkthdr *omp;
225 struct os_mbuf *om;
226
227 while ((omp = STAILQ_FIRST(&conn->bhc_tx_q)) != NULL) {
228 STAILQ_REMOVE_HEAD(&conn->bhc_tx_q, omp_next);
229 om = OS_MBUF_PKTHDR_TO_MBUF(omp);
230 int rc = ble_hs_hci_acl_tx_now(conn, &om);
231 if (rc == BLE_HS_EAGAIN) {
232 /* Controller is at capacity. This packet will be the first to
233 * get transmitted next time around.
234 */
235 STAILQ_INSERT_HEAD(&conn->bhc_tx_q, OS_MBUF_PKTHDR(om), omp_next);
236 return BLE_HS_EAGAIN;
237 }
238 }
239
240 return 0;
241 }
242
243 /**
244 * Schedules the transmission of all queued ACL data packets to the controller.
245 */
ble_hs_wakeup_tx(void)246 void ble_hs_wakeup_tx(void)
247 {
248 struct ble_hs_conn *conn;
249 int rc;
250 ble_hs_lock();
251
252 /* If there is a connection with a partially transmitted packet, it has to
253 * be serviced first. The controller is waiting for the remainder so it
254 * can reassemble it.
255 */
256 for (conn = ble_hs_conn_first();
257 conn != NULL;
258 conn = SLIST_NEXT(conn, bhc_next)) {
259 if (conn->bhc_flags & BLE_HS_CONN_F_TX_FRAG) {
260 rc = ble_hs_wakeup_tx_conn(conn);
261 if (rc != 0) {
262 goto done;
263 }
264
265 break;
266 }
267 }
268
269 /* For each connection, transmit queued packets until there are no more
270 * packets to send or the controller's buffers are exhausted.
271 */
272 for (conn = ble_hs_conn_first();
273 conn != NULL;
274 conn = SLIST_NEXT(conn, bhc_next)) {
275 rc = ble_hs_wakeup_tx_conn(conn);
276 if (rc != 0) {
277 goto done;
278 }
279 }
280
281 done:
282 ble_hs_unlock();
283 }
284
ble_hs_clear_rx_queue(void)285 static void ble_hs_clear_rx_queue(void)
286 {
287 struct os_mbuf *om;
288 while ((om = ble_mqueue_get(&ble_hs_rx_q)) != NULL) {
289 os_mbuf_free_chain(om);
290 }
291 }
292
ble_hs_is_enabled(void)293 int ble_hs_is_enabled(void)
294 {
295 return ble_hs_enabled_state == BLE_HS_ENABLED_STATE_ON;
296 }
297
ble_hs_synced(void)298 int ble_hs_synced(void)
299 {
300 return ble_hs_sync_state == BLE_HS_SYNC_STATE_GOOD;
301 }
302
ble_hs_sync(void)303 static int ble_hs_sync(void)
304 {
305 ble_npl_time_t retry_tmo_ticks;
306 int rc;
307 /* Set the sync state to "bringup." This allows the parent task to send
308 * the startup sequence to the controller. No other tasks are allowed to
309 * send any commands.
310 */
311 ble_hs_sync_state = BLE_HS_SYNC_STATE_BRINGUP;
312 rc = ble_hs_startup_go();
313 if (rc == 0) {
314 ble_hs_sync_state = BLE_HS_SYNC_STATE_GOOD;
315 } else {
316 ble_hs_sync_state = BLE_HS_SYNC_STATE_BAD;
317 }
318
319 retry_tmo_ticks = ble_npl_time_ms_to_ticks32(BLE_HS_SYNC_RETRY_TIMEOUT_MS);
320 ble_hs_timer_sched(retry_tmo_ticks);
321
322 if (rc == 0) {
323 rc = ble_hs_misc_restore_irks();
324 if (rc != 0) {
325 BLE_HS_LOG(INFO, "Failed to restore IRKs from store; status=%d\n",
326 rc);
327 }
328
329 if (ble_hs_cfg.sync_cb != NULL) {
330 ble_hs_cfg.sync_cb();
331 }
332
333 STATS_INC(ble_hs_stats, sync);
334 }
335
336 return rc;
337 }
338
ble_hs_reset(void)339 static int ble_hs_reset(void)
340 {
341 int rc;
342 STATS_INC(ble_hs_stats, reset);
343 ble_hs_sync_state = 0;
344 /* Reset transport. Assume success; there is nothing we can do in case of
345 * failure. If the transport failed to reset, the host will reset itself
346 * again when it fails to sync with the controller.
347 */
348 (void)ble_hci_trans_reset();
349 ble_hs_clear_rx_queue();
350
351 while (1) {
352 uint16_t conn_handle = ble_hs_atomic_first_conn_handle();
353 if (conn_handle == BLE_HS_CONN_HANDLE_NONE) {
354 break;
355 }
356
357 ble_gap_conn_broken(conn_handle, ble_hs_reset_reason);
358 }
359
360 /* Clear configured addresses. */
361 ble_hs_id_reset();
362
363 if (ble_hs_cfg.reset_cb != NULL && ble_hs_reset_reason != 0) {
364 ble_hs_cfg.reset_cb(ble_hs_reset_reason);
365 }
366
367 ble_hs_reset_reason = 0;
368 rc = ble_hs_sync();
369 return rc;
370 }
371
372 /**
373 * Called when the host timer expires. Handles unresponsive timeouts and
374 * periodic retries in case of resource shortage.
375 */
ble_hs_timer_exp(struct ble_npl_event * ev)376 static void ble_hs_timer_exp(struct ble_npl_event *ev)
377 {
378 int32_t ticks_until_next;
379
380 switch (ble_hs_sync_state) {
381 case BLE_HS_SYNC_STATE_GOOD:
382 ticks_until_next = ble_gattc_timer();
383 ble_hs_timer_sched(ticks_until_next);
384 ticks_until_next = ble_gap_timer();
385 ble_hs_timer_sched(ticks_until_next);
386 ticks_until_next = ble_l2cap_sig_timer();
387 ble_hs_timer_sched(ticks_until_next);
388 ticks_until_next = ble_sm_timer();
389 ble_hs_timer_sched(ticks_until_next);
390 ticks_until_next = ble_hs_conn_timer();
391 ble_hs_timer_sched(ticks_until_next);
392 break;
393
394 case BLE_HS_SYNC_STATE_BAD:
395 ble_hs_reset();
396 break;
397
398 case BLE_HS_SYNC_STATE_BRINGUP:
399 default:
400 /* The timer should not be set in this state. */
401 assert(0);
402 break;
403 }
404 }
405
ble_hs_timer_reset(uint32_t ticks)406 static void ble_hs_timer_reset(uint32_t ticks)
407 {
408 if (!ble_hs_is_enabled()) {
409 ble_npl_callout_stop(&ble_hs_timer);
410 } else {
411 int rc = ble_npl_callout_reset(&ble_hs_timer, ticks);
412 BLE_HS_DBG_ASSERT_EVAL(rc == 0);
413 }
414 }
415
ble_hs_timer_sched(int32_t ticks_from_now)416 static void ble_hs_timer_sched(int32_t ticks_from_now)
417 {
418 ble_npl_time_t abs_time;
419
420 if (ticks_from_now == BLE_HS_FOREVER) {
421 return;
422 }
423
424 /* Reset timer if it is not currently scheduled or if the specified time is
425 * sooner than the previous expiration time.
426 */
427 abs_time = ble_npl_time_get() + ticks_from_now;
428 if (!ble_npl_callout_is_active(&ble_hs_timer) ||
429 ((ble_npl_stime_t)(abs_time -
430 ble_npl_callout_get_ticks(&ble_hs_timer))) < 0) {
431 ble_hs_timer_reset(ticks_from_now);
432 }
433 }
434
ble_hs_timer_resched(void)435 void ble_hs_timer_resched(void)
436 {
437 /* Reschedule the timer to run immediately. The timer callback will query
438 * each module for an up-to-date expiration time.
439 */
440 ble_hs_timer_reset(0);
441 }
442
ble_hs_sched_start_stage2(void)443 static void ble_hs_sched_start_stage2(void)
444 {
445 ble_npl_eventq_put((struct ble_npl_eventq *)ble_hs_evq_get(),
446 &ble_hs_ev_start_stage2);
447 }
448
ble_hs_sched_start(void)449 void ble_hs_sched_start(void)
450 {
451 #ifdef MYNEWT
452 ble_npl_eventq_put((struct ble_npl_eventq *)os_eventq_dflt_get(),
453 &ble_hs_ev_start_stage1);
454 #else
455 ble_npl_eventq_put(nimble_port_get_dflt_eventq(), &ble_hs_ev_start_stage1);
456 #endif
457 }
458
ble_hs_event_rx_hci_ev(struct ble_npl_event * ev)459 static void ble_hs_event_rx_hci_ev(struct ble_npl_event *ev)
460 {
461 const struct ble_hci_ev *hci_ev;
462 int rc;
463 hci_ev = ble_npl_event_get_arg(ev);
464 rc = os_memblock_put(&ble_hs_hci_ev_pool, ev);
465 BLE_HS_DBG_ASSERT_EVAL(rc == 0);
466 #if BLE_MONITOR
467 ble_monitor_send(BLE_MONITOR_OPCODE_EVENT_PKT, hci_ev,
468 hci_ev->length + sizeof(*hci_ev));
469 #endif
470 ble_hs_hci_evt_process(hci_ev);
471 }
472
ble_hs_event_tx_notify(struct ble_npl_event * ev)473 static void ble_hs_event_tx_notify(struct ble_npl_event *ev)
474 {
475 ble_gatts_tx_notifications();
476 }
477
ble_hs_event_rx_data(struct ble_npl_event * ev)478 static void ble_hs_event_rx_data(struct ble_npl_event *ev)
479 {
480 ble_hs_process_rx_data_queue();
481 }
482
ble_hs_event_reset(struct ble_npl_event * ev)483 static void ble_hs_event_reset(struct ble_npl_event *ev)
484 {
485 ble_hs_reset();
486 }
487
488 /**
489 * Implements the first half of the start process. This just enqueues another
490 * event on the host parent task's event queue.
491 *
492 * Starting is done in two stages to allow the application time to configure
493 * the event queue to use after system initialization but before the host
494 * starts.
495 */
ble_hs_event_start_stage1(struct ble_npl_event * ev)496 static void ble_hs_event_start_stage1(struct ble_npl_event *ev)
497 {
498 ble_hs_sched_start_stage2();
499 }
500
501 /**
502 * Implements the second half of the start process. This actually starts the
503 * host.
504 *
505 * Starting is done in two stages to allow the application time to configure
506 * the event queue to use after system initialization but before the host
507 * starts.
508 */
ble_hs_event_start_stage2(struct ble_npl_event * ev)509 static void ble_hs_event_start_stage2(struct ble_npl_event *ev)
510 {
511 int rc;
512 rc = ble_hs_start();
513 assert(rc == 0);
514 }
515
ble_hs_enqueue_hci_event(uint8_t * hci_evt)516 void ble_hs_enqueue_hci_event(uint8_t *hci_evt)
517 {
518 struct ble_npl_event *ev;
519 ev = os_memblock_get(&ble_hs_hci_ev_pool);
520 if (ev == NULL) {
521 ble_hci_trans_buf_free(hci_evt);
522 } else {
523 ble_npl_event_init(ev, ble_hs_event_rx_hci_ev, hci_evt);
524 ble_npl_eventq_put(ble_hs_evq, ev);
525 }
526 }
527
528 /**
529 * Schedules for all pending notifications and indications to be sent in the
530 * host parent task.
531 */
ble_hs_notifications_sched(void)532 void ble_hs_notifications_sched(void)
533 {
534 #if !MYNEWT_VAL(BLE_HS_REQUIRE_OS)
535
536 if (!ble_npl_os_started()) {
537 ble_gatts_tx_notifications();
538 return;
539 }
540
541 #endif
542 ble_npl_eventq_put(ble_hs_evq, &ble_hs_ev_tx_notifications);
543 }
544
ble_hs_sched_reset(int reason)545 void ble_hs_sched_reset(int reason)
546 {
547 BLE_HS_DBG_ASSERT(ble_hs_reset_reason == 0);
548 ble_hs_reset_reason = reason;
549 ble_npl_eventq_put(ble_hs_evq, &ble_hs_ev_reset);
550 }
551
ble_hs_hw_error(uint8_t hw_code)552 void ble_hs_hw_error(uint8_t hw_code)
553 {
554 ble_hs_sched_reset(BLE_HS_HW_ERR(hw_code));
555 }
556
ble_hs_start(void)557 int ble_hs_start(void)
558 {
559 int rc;
560 ble_hs_lock();
561
562 switch (ble_hs_enabled_state) {
563 case BLE_HS_ENABLED_STATE_ON:
564 rc = BLE_HS_EALREADY;
565 break;
566
567 case BLE_HS_ENABLED_STATE_STOPPING:
568 rc = BLE_HS_EBUSY;
569 break;
570
571 case BLE_HS_ENABLED_STATE_OFF:
572 ble_hs_enabled_state = BLE_HS_ENABLED_STATE_ON;
573 rc = 0;
574 break;
575
576 default:
577 assert(0);
578 rc = BLE_HS_EUNKNOWN;
579 break;
580 }
581
582 ble_hs_unlock();
583
584 if (rc != 0) {
585 return rc;
586 }
587
588 ble_hs_parent_task = ble_npl_get_current_task_id();
589 #if MYNEWT_VAL(SELFTEST)
590 /* Stop the timer just in case the host was already running (e.g., unit
591 * tests).
592 */
593 ble_npl_callout_stop(&ble_hs_timer);
594 #endif
595 ble_npl_callout_init(&ble_hs_timer, ble_hs_evq, ble_hs_timer_exp, NULL);
596 ble_hs_sync();
597 return 0;
598 }
599
600 /**
601 * Called when a data packet is received from the controller. This function
602 * consumes the supplied mbuf, regardless of the outcome.
603 *
604 * @param om The incoming data packet, beginning with the
605 * HCI ACL data header.
606 *
607 * @return 0 on success; nonzero on failure.
608 */
ble_hs_rx_data(struct os_mbuf * om,void * arg)609 static int ble_hs_rx_data(struct os_mbuf *om, void *arg)
610 {
611 int rc;
612 /* If flow control is enabled, mark this packet with its corresponding
613 * connection handle.
614 */
615 ble_hs_flow_fill_acl_usrhdr(om);
616 rc = ble_mqueue_put(&ble_hs_rx_q, ble_hs_evq, om);
617 if (rc != 0) {
618 os_mbuf_free_chain(om);
619 return BLE_HS_EOS;
620 }
621
622 return 0;
623 }
624
625 /**
626 * Enqueues an ACL data packet for transmission. This function consumes the
627 * supplied mbuf, regardless of the outcome.
628 *
629 * @param om The outgoing data packet, beginning with the
630 * HCI ACL data header.
631 *
632 * @return 0 on success; nonzero on failure.
633 */
ble_hs_tx_data(struct os_mbuf * om)634 int ble_hs_tx_data(struct os_mbuf *om)
635 {
636 #if BLE_MONITOR
637 ble_monitor_send_om(BLE_MONITOR_OPCODE_ACL_TX_PKT, om);
638 #endif
639 return ble_hci_trans_hs_acl_tx(om);
640 }
641
ble_hs_init(void)642 void ble_hs_init(void)
643 {
644 int rc;
645 /* Ensure this function only gets called by sysinit. */
646 SYSINIT_ASSERT_ACTIVE();
647 /* Create memory pool of OS events */
648 rc = os_mempool_init(&ble_hs_hci_ev_pool, BLE_HS_HCI_EVT_COUNT,
649 sizeof(struct ble_npl_event), ble_hs_hci_os_event_buf,
650 "ble_hs_hci_ev_pool");
651 SYSINIT_PANIC_ASSERT(rc == 0);
652 /* These get initialized here to allow unit tests to run without a zeroed
653 * bss.
654 */
655 ble_hs_reset_reason = 0;
656 ble_hs_enabled_state = BLE_HS_ENABLED_STATE_OFF;
657 ble_npl_event_init(&ble_hs_ev_tx_notifications, ble_hs_event_tx_notify,
658 NULL);
659 ble_npl_event_init(&ble_hs_ev_reset, ble_hs_event_reset, NULL);
660 ble_npl_event_init(&ble_hs_ev_start_stage1, ble_hs_event_start_stage1,
661 NULL);
662 ble_npl_event_init(&ble_hs_ev_start_stage2, ble_hs_event_start_stage2,
663 NULL);
664 ble_hs_hci_init();
665 rc = ble_hs_conn_init();
666 SYSINIT_PANIC_ASSERT(rc == 0);
667 #if MYNEWT_VAL(BLE_PERIODIC_ADV)
668 rc = ble_hs_periodic_sync_init();
669 SYSINIT_PANIC_ASSERT(rc == 0);
670 #endif
671 rc = ble_l2cap_init();
672 SYSINIT_PANIC_ASSERT(rc == 0);
673 rc = ble_att_init();
674 SYSINIT_PANIC_ASSERT(rc == 0);
675 rc = ble_att_svr_init();
676 SYSINIT_PANIC_ASSERT(rc == 0);
677 rc = ble_gap_init();
678 SYSINIT_PANIC_ASSERT(rc == 0);
679 rc = ble_gattc_init();
680 SYSINIT_PANIC_ASSERT(rc == 0);
681 rc = ble_gatts_init();
682 SYSINIT_PANIC_ASSERT(rc == 0);
683 ble_hs_stop_init();
684 ble_mqueue_init(&ble_hs_rx_q, ble_hs_event_rx_data, NULL);
685 rc = stats_init_and_reg(STATS_HDR(ble_hs_stats), STATS_SIZE_INIT_PARMS(ble_hs_stats,
686 STATS_SIZE_32), STATS_NAME_INIT_PARMS(ble_hs_stats), "ble_hs");
687 SYSINIT_PANIC_ASSERT(rc == 0);
688 rc = ble_npl_mutex_init(&ble_hs_mutex);
689 SYSINIT_PANIC_ASSERT(rc == 0);
690 #if MYNEWT_VAL(BLE_HS_DEBUG)
691 ble_hs_dbg_mutex_locked = 0;
692 #endif
693 #ifdef MYNEWT
694 ble_hs_evq_set((struct ble_npl_eventq *)os_eventq_dflt_get());
695 #else
696 ble_hs_evq_set(nimble_port_get_dflt_eventq());
697 #endif
698 /* Configure the HCI transport to communicate with a host. */
699 ble_hci_trans_cfg_hs(ble_hs_hci_rx_evt, NULL, ble_hs_rx_data, NULL);
700 #if BLE_MONITOR
701 rc = ble_monitor_init();
702 SYSINIT_PANIC_ASSERT(rc == 0);
703 #endif
704 /* Enqueue the start event to the default event queue. Using the default
705 * queue ensures the event won't run until the end of main(). This allows
706 * the application to configure this package in the meantime.
707 */
708 #if MYNEWT_VAL(BLE_HS_AUTO_START)
709 #ifdef MYNEWT
710 ble_npl_eventq_put((struct ble_npl_eventq *)os_eventq_dflt_get(),
711 &ble_hs_ev_start_stage1);
712 #else
713 ble_npl_eventq_put(nimble_port_get_dflt_eventq(), &ble_hs_ev_start_stage1);
714 #endif
715 #endif
716 #if BLE_MONITOR
717 ble_monitor_new_index(0, (uint8_t[6]) { }, "nimble0");
718 #endif
719 }
720
ble_hs_deinit(void)721 void ble_hs_deinit(void)
722 {
723 ble_gatts_stop();
724 ble_npl_callout_deinit(&ble_hs_timer);
725 ble_npl_mutex_deinit(&ble_hs_mutex);
726 ble_gap_deinit();
727 ble_hs_stop_deinit();
728 ble_hs_hci_deinit();
729 }