You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by ry...@apache.org on 2019/07/19 11:55:09 UTC

[mynewt-nimble] 04/04: nimble/ble_hs_stop: Change hs stop procedure

This is an automated email from the ASF dual-hosted git repository.

rymek pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git

commit f3f06a8d6f9944fccfbad5b7c69ced2c53331738
Author: Ɓukasz Rymanowski <lu...@codecoup.pl>
AuthorDate: Fri May 31 14:18:00 2019 +0200

    nimble/ble_hs_stop: Change hs stop procedure
    
    This patch change a way of handling stop procedure. Before, host was
    disconnecting one by one all the active connections. This could result
    in long procedure time when some devices came out of range and host was
    waiting as long as supervision timout takes.
    
    Now, host is sending in the raw Disconnect Command to all the active
    connections and then start graceful disconnect timeout 2s.
    Host notifies that is stop when
    a) all the disconnection complete events arrived within 2s
    b) disconnect timeout fires
---
 nimble/host/src/ble_hs_stop.c                      | 100 ++++++++++++---------
 nimble/host/syscfg.yml                             |   6 ++
 porting/examples/linux/include/syscfg/syscfg.h     |   4 +
 .../examples/linux_blemesh/include/syscfg/syscfg.h |   4 +
 porting/nimble/include/syscfg/syscfg.h             |   4 +
 porting/npl/riot/include/syscfg/syscfg.h           |   3 +
 6 files changed, 81 insertions(+), 40 deletions(-)

diff --git a/nimble/host/src/ble_hs_stop.c b/nimble/host/src/ble_hs_stop.c
index ff540b9..5831d07 100644
--- a/nimble/host/src/ble_hs_stop.c
+++ b/nimble/host/src/ble_hs_stop.c
@@ -21,9 +21,12 @@
 #include "sysinit/sysinit.h"
 #include "syscfg/syscfg.h"
 #include "ble_hs_priv.h"
+#include "nimble/nimble_npl.h"
+#ifndef MYNEWT
+#include "nimble/nimble_port.h"
+#endif
 
-static ble_npl_event_fn ble_hs_stop_term_event_cb;
-static struct ble_npl_event ble_hs_stop_term_ev;
+#define BLE_HOST_STOP_TIMEOUT_MS MYNEWT_VAL(BLE_HS_STOP_ON_SHUTDOWN_TIMEOUT)
 
 static struct ble_gap_event_listener ble_hs_stop_gap_listener;
 
@@ -33,6 +36,11 @@ static struct ble_gap_event_listener ble_hs_stop_gap_listener;
 SLIST_HEAD(ble_hs_stop_listener_slist, ble_hs_stop_listener);
 static struct ble_hs_stop_listener_slist ble_hs_stop_listeners;
 
+/* Track number of connections */
+static uint8_t ble_hs_stop_conn_cnt;
+
+static struct ble_npl_callout ble_hs_stop_terminate_tmo;
+
 /**
  * Called when a stop procedure has completed.
  */
@@ -42,6 +50,8 @@ ble_hs_stop_done(int status)
     struct ble_hs_stop_listener_slist slist;
     struct ble_hs_stop_listener *listener;
 
+    ble_npl_callout_stop(&ble_hs_stop_terminate_tmo);
+
     ble_hs_lock();
 
     ble_gap_event_listener_unregister(&ble_hs_stop_gap_listener);
@@ -95,47 +105,41 @@ ble_hs_stop_terminate_all_periodic_sync(void)
 #endif
 
 /**
- * Terminates the first open connection.
- *
- * If there are no open connections, Check for any active periodic sync
- * handles.
+ * Terminates connection.
  */
-static void
-ble_hs_stop_terminate_next_conn(void)
+static int
+ble_hs_stop_terminate_conn(struct ble_hs_conn *conn, void *arg)
 {
-    uint16_t handle;
     int rc;
 
-    handle = ble_hs_atomic_first_conn_handle();
-    if (handle == BLE_HS_CONN_HANDLE_NONE) {
-        /* No open connections.  Signal completion of the stop procedure. */
-        ble_hs_stop_done(0);
-        return;
-    }
-
-    rc = ble_gap_terminate(handle, BLE_ERR_REM_USER_CONN_TERM);
+    rc = ble_gap_terminate_with_conn(conn, BLE_ERR_REM_USER_CONN_TERM);
     if (rc == 0) {
         /* Terminate procedure successfully initiated.  Let the GAP event
          * handler deal with the result.
          */
+        ble_hs_stop_conn_cnt++;
     } else {
-        BLE_HS_LOG(ERROR,
-            "ble_hs_stop: failed to terminate connection; rc=%d\n", rc);
-        ble_hs_stop_done(rc);
+        /* If failed, just make sure we are not going to wait for connection complete event,
+         * just count it as already disconnected
+         */
+        BLE_HS_LOG(ERROR, "ble_hs_stop: failed to terminate connection; rc=%d\n", rc);
     }
+
+    return 0;
 }
 
 /**
- * Event handler.  Attempts to terminate the first open connection if there is
- * one.  All additional connections are terminated elsewhere in the GAP event
- * handler.
- *
- * If there are no connections, signals completion of the stop procedure.
+ * This is called when host graceful disconnect timeout fires. That means some devices
+ * are out of range and disconnection completed did no happen yet.
  */
 static void
-ble_hs_stop_term_event_cb(struct ble_npl_event *ev)
+ble_hs_stop_terminate_timeout_cb(struct ble_npl_event *ev)
 {
-    ble_hs_stop_terminate_next_conn();
+    BLE_HS_LOG(ERROR, "ble_hs_stop_terminate_timeout_cb,"
+                      "%d connection(s) still up \n", ble_hs_stop_conn_cnt);
+
+    /* TODO: Shall we send error here? */
+    ble_hs_stop_done(0);
 }
 
 /**
@@ -151,7 +155,11 @@ ble_hs_stop_gap_event(struct ble_gap_event *event, void *arg)
     if (event->type == BLE_GAP_EVENT_DISCONNECT ||
         event->type == BLE_GAP_EVENT_TERM_FAILURE) {
 
-        ble_hs_stop_terminate_next_conn();
+        ble_hs_stop_conn_cnt--;
+
+        if (ble_hs_stop_conn_cnt == 0) {
+            ble_hs_stop_done(0);
+        }
     }
 
     return 0;
@@ -233,12 +241,6 @@ ble_hs_stop(struct ble_hs_stop_listener *listener,
     ble_gap_preempt();
     ble_gap_preempt_done();
 
-    rc = ble_gap_event_listener_register(&ble_hs_stop_gap_listener,
-                                         ble_hs_stop_gap_event, NULL);
-    if (rc != 0) {
-        return rc;
-    }
-
 #if MYNEWT_VAL(BLE_PERIODIC_ADV)
     /* Check for active periodic sync first and terminate it all */
     rc = ble_hs_stop_terminate_all_periodic_sync();
@@ -247,11 +249,23 @@ ble_hs_stop(struct ble_hs_stop_listener *listener,
     }
 #endif
 
-    /* Schedule termination of all open connections in the host task.  This is
-     * done even if there are no open connections so that the result of the
-     * stop procedure is signaled in a consistent manner (asynchronously).
-     */
-    ble_npl_eventq_put(ble_hs_evq_get(), &ble_hs_stop_term_ev);
+    rc = ble_gap_event_listener_register(&ble_hs_stop_gap_listener,
+                                         ble_hs_stop_gap_event, NULL);
+    if (rc != 0) {
+        return rc;
+    }
+
+    ble_hs_lock();
+    ble_hs_conn_foreach(ble_hs_stop_terminate_conn, NULL);
+    ble_hs_unlock();
+
+    if (ble_hs_stop_conn_cnt > 0) {
+        ble_npl_callout_reset(&ble_hs_stop_terminate_tmo,
+                              ble_npl_time_ms_to_ticks32(BLE_HOST_STOP_TIMEOUT_MS));
+    } else {
+        /* No connections, stop is completed */
+        ble_hs_stop_done(0);
+    }
 
     return 0;
 }
@@ -259,5 +273,11 @@ ble_hs_stop(struct ble_hs_stop_listener *listener,
 void
 ble_hs_stop_init(void)
 {
-    ble_npl_event_init(&ble_hs_stop_term_ev, ble_hs_stop_term_event_cb, NULL);
+#ifdef MYNEWT
+    ble_npl_callout_init(&ble_hs_stop_terminate_tmo, ble_npl_eventq_dflt_get(),
+                         ble_hs_stop_terminate_timeout_cb, NULL);
+#else
+    ble_npl_callout_init(&ble_hs_stop_terminate_tmo, nimble_port_get_dflt_eventq(),
+                         ble_hs_stop_terminate_timeout_cb, NULL);
+#endif
 }
diff --git a/nimble/host/syscfg.yml b/nimble/host/syscfg.yml
index 0b97661..3c3c21d 100644
--- a/nimble/host/syscfg.yml
+++ b/nimble/host/syscfg.yml
@@ -435,6 +435,12 @@ syscfg.defs:
             entails aborting all GAP procedures and terminating open
             connections.
         value: 1
+
+    BLE_HS_STOP_ON_SHUTDOWN_TIMEOUT:
+        description: >
+            Timeout used in NimBLE's host stop procedure in ms.
+        value: 2000
+
     BLE_HS_SYSINIT_STAGE:
         description: >
             Sysinit stage for the NimBLE host.
diff --git a/porting/examples/linux/include/syscfg/syscfg.h b/porting/examples/linux/include/syscfg/syscfg.h
index d4d4aee..507a580 100644
--- a/porting/examples/linux/include/syscfg/syscfg.h
+++ b/porting/examples/linux/include/syscfg/syscfg.h
@@ -723,6 +723,10 @@
 #define MYNEWT_VAL_BLE_STORE_MAX_CCCDS (8)
 #endif
 
+#ifndef MYNEWT_VAL_BLE_HS_STOP_ON_SHUTDOWN_TIMEOUT
+#define MYNEWT_VAL_BLE_HS_STOP_ON_SHUTDOWN_TIMEOUT (2000)
+#endif
+
 /*** nimble/host/services/ans */
 #ifndef MYNEWT_VAL_BLE_SVC_ANS_NEW_ALERT_CAT
 #define MYNEWT_VAL_BLE_SVC_ANS_NEW_ALERT_CAT (0)
diff --git a/porting/examples/linux_blemesh/include/syscfg/syscfg.h b/porting/examples/linux_blemesh/include/syscfg/syscfg.h
index 522345e..12d969b 100644
--- a/porting/examples/linux_blemesh/include/syscfg/syscfg.h
+++ b/porting/examples/linux_blemesh/include/syscfg/syscfg.h
@@ -723,6 +723,10 @@
 #define MYNEWT_VAL_BLE_STORE_MAX_CCCDS (8)
 #endif
 
+#ifndef MYNEWT_VAL_BLE_HS_STOP_ON_SHUTDOWN_TIMEOUT
+#define MYNEWT_VAL_BLE_HS_STOP_ON_SHUTDOWN_TIMEOUT (2000)
+#endif
+
 /*** nimble/host/services/ans */
 #ifndef MYNEWT_VAL_BLE_SVC_ANS_NEW_ALERT_CAT
 #define MYNEWT_VAL_BLE_SVC_ANS_NEW_ALERT_CAT (0)
diff --git a/porting/nimble/include/syscfg/syscfg.h b/porting/nimble/include/syscfg/syscfg.h
index 6ebfc63..bbfed57 100644
--- a/porting/nimble/include/syscfg/syscfg.h
+++ b/porting/nimble/include/syscfg/syscfg.h
@@ -723,6 +723,10 @@
 #define MYNEWT_VAL_BLE_STORE_MAX_CCCDS (8)
 #endif
 
+#ifndef MYNEWT_VAL_BLE_HS_STOP_ON_SHUTDOWN_TIMEOUT
+#define MYNEWT_VAL_BLE_HS_STOP_ON_SHUTDOWN_TIMEOUT (2000)
+#endif
+
 /*** nimble/host/services/ans */
 #ifndef MYNEWT_VAL_BLE_SVC_ANS_NEW_ALERT_CAT
 #define MYNEWT_VAL_BLE_SVC_ANS_NEW_ALERT_CAT (0)
diff --git a/porting/npl/riot/include/syscfg/syscfg.h b/porting/npl/riot/include/syscfg/syscfg.h
index 84321db..b0b9c5a 100644
--- a/porting/npl/riot/include/syscfg/syscfg.h
+++ b/porting/npl/riot/include/syscfg/syscfg.h
@@ -933,6 +933,9 @@
 #define MYNEWT_VAL_BLE_STORE_MAX_CCCDS (8)
 #endif
 
+#ifndef MYNEWT_VAL_BLE_HS_STOP_ON_SHUTDOWN_TIMEOUT
+#define MYNEWT_VAL_BLE_HS_STOP_ON_SHUTDOWN_TIMEOUT (2000)
+#endif
 
 /*** net/nimble/host/mesh */
 #ifndef MYNEWT_VAL_BLE_MESH_ADV_BUF_COUNT