You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by cc...@apache.org on 2015/12/17 21:04:54 UTC

[1/3] incubator-mynewt-larva git commit: Host HCI tx timeouts.

Repository: incubator-mynewt-larva
Updated Branches:
  refs/heads/master 66bf96edc -> 9d9616046


Host HCI tx timeouts.


Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/commit/fcc40659
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/tree/fcc40659
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/diff/fcc40659

Branch: refs/heads/master
Commit: fcc40659b20407545de52b1fd4526bc6844956c0
Parents: 66bf96e
Author: Christopher Collins <cc...@gmail.com>
Authored: Wed Dec 16 16:58:42 2015 -0800
Committer: Christopher Collins <cc...@gmail.com>
Committed: Thu Dec 17 12:03:56 2015 -0800

----------------------------------------------------------------------
 net/nimble/host/include/host/host_hci.h |  1 +
 net/nimble/host/src/ble_gap_conn.c      |  3 +-
 net/nimble/host/src/host_hci.c          | 44 ++++++++++++++++++++++++++--
 3 files changed, 44 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/fcc40659/net/nimble/host/include/host/host_hci.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/include/host/host_hci.h b/net/nimble/host/include/host/host_hci.h
index c37de90..094f3c1 100644
--- a/net/nimble/host/include/host/host_hci.h
+++ b/net/nimble/host/include/host/host_hci.h
@@ -50,6 +50,7 @@ uint16_t host_hci_handle_pb_bc_join(uint16_t handle, uint8_t pb, uint8_t bc);
 int host_hci_data_rx(struct os_mbuf *om);
 int host_hci_data_tx(struct ble_hs_conn *connection, struct os_mbuf *om);
 
+void host_hci_timer_set(void);
 void host_hci_init(void);
 
 extern uint16_t host_hci_outstanding_opcode;

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/fcc40659/net/nimble/host/src/ble_gap_conn.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_gap_conn.c b/net/nimble/host/src/ble_gap_conn.c
index 748ad00..61224b5 100644
--- a/net/nimble/host/src/ble_gap_conn.c
+++ b/net/nimble/host/src/ble_gap_conn.c
@@ -176,8 +176,7 @@ ble_gap_conn_master_failed(uint8_t status)
 
 /**
  * Called when an error is encountered while the slave-connection-fsm is
- * active.  Resets the state machine, clears the HCI ack callback, and notifies
- * the host task that the next hci_batch item can be processed.
+ * active.
  */
 static void
 ble_gap_conn_slave_failed(uint8_t status)

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/fcc40659/net/nimble/host/src/host_hci.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/host_hci.c b/net/nimble/host/src/host_hci.c
index c8c4290..2ac44f1 100644
--- a/net/nimble/host/src/host_hci.c
+++ b/net/nimble/host/src/host_hci.c
@@ -59,6 +59,10 @@ struct host_hci_stats g_host_hci_stats;
 /** The opcode of the current unacked HCI command; 0 if none. */
 uint16_t host_hci_outstanding_opcode;
 
+#define HOST_HCI_TIMEOUT        50      /* Milliseconds. */
+
+static struct os_callout_func host_hci_timer;
+
 /** Dispatch table for incoming HCI events.  Sorted by event code field. */
 typedef int host_hci_event_fn(uint8_t event_code, uint8_t *data, int len);
 struct host_hci_event_dispatch_entry {
@@ -124,6 +128,39 @@ host_hci_le_dispatch_entry_find(uint8_t event_code)
     return NULL;
 }
 
+void
+host_hci_timer_set(void)
+{
+    int rc;
+
+    rc = os_callout_reset(&host_hci_timer.cf_c,
+                          HOST_HCI_TIMEOUT * OS_TICKS_PER_SEC / 1000);
+    assert(rc == 0);
+}
+
+static void
+host_hci_timer_stop(void)
+{
+    os_callout_stop(&host_hci_timer.cf_c);
+}
+
+static void
+host_hci_timer_exp(void *arg)
+{
+    struct ble_hci_ack ack;
+
+    assert(host_hci_outstanding_opcode != 0);
+
+    ack.bha_opcode = host_hci_outstanding_opcode;
+    ack.bha_status = 0xff; /* XXX */
+    ack.bha_params = NULL;
+    ack.bha_params_len = 0;
+
+    host_hci_outstanding_opcode = 0;
+    ble_hci_ack_rx(&ack);
+}
+
+
 static int
 host_hci_rx_disconn_complete(uint8_t event_code, uint8_t *data, int len)
 {
@@ -172,7 +209,7 @@ host_hci_rx_cmd_complete(uint8_t event_code, uint8_t *data, int len)
     if (opcode == host_hci_outstanding_opcode) {
         /* Mark the outstanding command as acked. */
         host_hci_outstanding_opcode = 0;
-        /* XXX: Stop timer. */
+        host_hci_timer_stop();
     }
 
     ack.bha_opcode = opcode;
@@ -220,7 +257,7 @@ host_hci_rx_cmd_status(uint8_t event_code, uint8_t *data, int len)
     if (opcode == host_hci_outstanding_opcode) {
         /* Mark the outstanding command as acked. */
         host_hci_outstanding_opcode = 0;
-        /* XXX: Stop timer. */
+        host_hci_timer_stop();
     }
 
     ack.bha_opcode = opcode;
@@ -612,4 +649,7 @@ void
 host_hci_init(void)
 {
     host_hci_outstanding_opcode = 0;
+
+    os_callout_func_init(&host_hci_timer, &ble_hs_evq,
+                         host_hci_timer_exp, NULL);
 }


[2/3] incubator-mynewt-larva git commit: Rename ble_gap_test to ble_os_test.

Posted by cc...@apache.org.
Rename ble_gap_test to ble_os_test.


Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/commit/abed8b72
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/tree/abed8b72
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/diff/abed8b72

Branch: refs/heads/master
Commit: abed8b723cf7c28231c693bca7b7695ce6dbff13
Parents: fcc4065
Author: Christopher Collins <cc...@gmail.com>
Authored: Wed Dec 16 17:02:23 2015 -0800
Committer: Christopher Collins <cc...@gmail.com>
Committed: Thu Dec 17 12:04:07 2015 -0800

----------------------------------------------------------------------
 net/nimble/host/include/host/ble_hs_test.h |   2 +-
 net/nimble/host/src/test/ble_gap_test.c    | 348 ------------------------
 net/nimble/host/src/test/ble_hs_test.c     |   2 +-
 net/nimble/host/src/test/ble_os_test.c     | 348 ++++++++++++++++++++++++
 4 files changed, 350 insertions(+), 350 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/abed8b72/net/nimble/host/include/host/ble_hs_test.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/include/host/ble_hs_test.h b/net/nimble/host/include/host/ble_hs_test.h
index 60d80d3..12014ff 100644
--- a/net/nimble/host/include/host/ble_hs_test.h
+++ b/net/nimble/host/include/host/ble_hs_test.h
@@ -26,7 +26,7 @@ int ble_att_svr_test_all(void);
 int ble_att_clt_test_all(void);
 int ble_host_hci_test_all(void);
 int ble_hs_conn_test_all(void);
-int ble_gap_test_all(void);
+int ble_os_test_all(void);
 int ble_hs_uuid_test_all(void);
 int ble_gatt_disc_s_test_all(void);
 int ble_gatt_disc_c_test_all(void);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/abed8b72/net/nimble/host/src/test/ble_gap_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_gap_test.c b/net/nimble/host/src/test/ble_gap_test.c
deleted file mode 100644
index 4728046..0000000
--- a/net/nimble/host/src/test/ble_gap_test.c
+++ /dev/null
@@ -1,348 +0,0 @@
-/**
- * Copyright (c) 2015 Runtime Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <string.h>
-#include "os/os.h"
-#include "testutil/testutil.h"
-#include "nimble/hci_common.h"
-#include "nimble/hci_transport.h"
-#include "ble_hs_priv.h"
-#include "host/ble_hs_test.h"
-#include "host/ble_gap.h"
-#include "ble_hs_test_util.h"
-#include "ble_hs_conn.h"
-#include "ble_gap_conn.h"
-
-#ifdef ARCH_sim
-#define BLE_GAP_TEST_STACK_SIZE     1024
-#else
-#define BLE_GAP_TEST_STACK_SIZE     256
-#endif
-
-#define BLE_GAP_TEST_HS_PRIO        10
-
-static struct os_task ble_gap_test_task;
-static os_stack_t ble_gap_test_stack[OS_STACK_ALIGN(BLE_GAP_TEST_STACK_SIZE)];
-
-static uint8_t ble_gap_test_peer_addr[6] = { 1, 2, 3, 4, 5, 6 };
-
-static void
-ble_gap_test_misc_rx_ack(uint8_t ogf, uint8_t ocf, uint8_t status)
-{
-    uint16_t opcode;
-    uint8_t *cmd;
-    int rc;
-
-    cmd = os_memblock_get(&g_hci_cmd_pool);
-    TEST_ASSERT_FATAL(cmd != NULL);
-
-    opcode = (ogf << 10) | ocf;
-    ble_hs_test_util_build_cmd_status(cmd, BLE_HCI_EVENT_CMD_STATUS_LEN,
-                                      status, 1, opcode);
-
-    rc = ble_hci_transport_ctlr_event_send(cmd);
-    TEST_ASSERT(rc == 0);
-}
-
-static void
-ble_gap_test_misc_rx_le_ack(uint16_t ocf, uint8_t status)
-{
-    ble_gap_test_misc_rx_ack(BLE_HCI_OGF_LE, ocf, status);
-}
-
-static void
-ble_gap_direct_connect_test_connect_cb(struct ble_gap_conn_event *event,
-                                       void *arg)
-{
-    int *cb_called;
-
-    cb_called = arg;
-    *cb_called = 1;
-
-    TEST_ASSERT(event->type == BLE_GAP_CONN_EVENT_TYPE_CONNECT);
-    TEST_ASSERT(event->conn.status == BLE_ERR_SUCCESS);
-    TEST_ASSERT(event->conn.handle == 2);
-    TEST_ASSERT(memcmp(event->conn.peer_addr, ble_gap_test_peer_addr, 6) ==
-                0);
-}
-
-static void
-ble_gap_direct_connect_test_task_handler(void *arg)
-{
-    struct hci_le_conn_complete evt;
-    uint8_t addr[6] = { 1, 2, 3, 4, 5, 6 };
-    int cb_called;
-    int rc;
-
-    /* Receive acknowledgements for the startup sequence.  We sent the
-     * corresponding requests when the host task was started.
-     */
-    ble_hs_test_util_rx_startup_acks();
-
-    /* Set the connect callback so we can verify that it gets called with the
-     * proper arguments.
-     */
-    cb_called = 0;
-    ble_gap_conn_set_cb(ble_gap_direct_connect_test_connect_cb, &cb_called);
-
-    /* Make sure there are no created connections and no connections in
-     * progress.
-     */
-    TEST_ASSERT(ble_hs_conn_first() == NULL);
-
-    /* Initiate a direct connection. */
-    ble_gap_conn_direct_connect(0, addr);
-    TEST_ASSERT(ble_hs_conn_first() == NULL);
-    TEST_ASSERT(!cb_called);
-
-    /* Receive an ack for the HCI create-connection command. */
-    ble_gap_test_misc_rx_le_ack(BLE_HCI_OCF_LE_CREATE_CONN, 0);
-    TEST_ASSERT(ble_hs_conn_first() == NULL);
-    TEST_ASSERT(!cb_called);
-
-    /* Receive an HCI connection-complete event. */
-    memset(&evt, 0, sizeof evt);
-    evt.subevent_code = BLE_HCI_LE_SUBEV_CONN_COMPLETE;
-    evt.status = BLE_ERR_SUCCESS;
-    evt.connection_handle = 2;
-    memcpy(evt.peer_addr, addr, 6);
-    rc = ble_gap_conn_rx_conn_complete(&evt);
-    TEST_ASSERT(rc == 0);
-
-    /* The connection should now be created. */
-    TEST_ASSERT(ble_hs_conn_find(2) != NULL);
-    TEST_ASSERT(cb_called);
-
-    tu_restart();
-}
-
-TEST_CASE(ble_gap_direct_connect_test_case)
-{
-    os_init();
-
-    ble_hs_test_util_init();
-
-    os_task_init(&ble_gap_test_task,
-                 "ble_gap_direct_connect_test_task",
-                 ble_gap_direct_connect_test_task_handler, NULL,
-                 BLE_GAP_TEST_HS_PRIO + 1, OS_WAIT_FOREVER, ble_gap_test_stack,
-                 OS_STACK_ALIGN(BLE_GAP_TEST_STACK_SIZE));
-
-    os_start();
-}
-
-static void
-ble_gap_gen_disc_test_connect_cb(struct ble_gap_conn_event *event, void *arg)
-{
-    int *cb_called;
-
-    cb_called = arg;
-    *cb_called = 1;
-
-    TEST_ASSERT(event->type == BLE_GAP_CONN_EVENT_TYPE_SCAN_DONE);
-}
-
-static void
-ble_gap_gen_disc_test_task_handler(void *arg)
-{
-    int cb_called;
-
-    /* Receive acknowledgements for the startup sequence.  We sent the
-     * corresponding requests when the host task was started.
-     */
-    ble_hs_test_util_rx_startup_acks();
-
-    /* Set the connect callback so we can verify that it gets called with the
-     * proper arguments.
-     */
-    cb_called = 0;
-    ble_gap_conn_set_cb(ble_gap_gen_disc_test_connect_cb, &cb_called);
-
-    /* Make sure there are no created connections and no connections in
-     * progress.
-     */
-    TEST_ASSERT(ble_hs_conn_first() == NULL);
-    TEST_ASSERT(!ble_gap_conn_master_in_progress());
-
-    /* Initiate the general discovery procedure with a 200 ms timeout. */
-    ble_gap_conn_gen_disc(200);
-    TEST_ASSERT(ble_hs_conn_first() == NULL);
-    TEST_ASSERT(ble_gap_conn_master_in_progress());
-    TEST_ASSERT(!cb_called);
-
-    /* Receive acks from the controller. */
-    ble_gap_test_misc_rx_le_ack(BLE_HCI_OCF_LE_SET_SCAN_PARAMS, 0);
-    ble_gap_test_misc_rx_le_ack(BLE_HCI_OCF_LE_SET_SCAN_ENABLE, 0);
-    TEST_ASSERT(ble_hs_conn_first() == NULL);
-    TEST_ASSERT(ble_gap_conn_master_in_progress());
-    TEST_ASSERT(!cb_called);
-
-    /* Wait 100 ms; verify scan still in progress. */
-    os_time_delay(100 * OS_TICKS_PER_SEC / 1000);
-    TEST_ASSERT(ble_hs_conn_first() == NULL);
-    TEST_ASSERT(ble_gap_conn_master_in_progress());
-    TEST_ASSERT(!cb_called);
-
-    /* Wait 150 more ms; verify scan completed. */
-    os_time_delay(150 * OS_TICKS_PER_SEC / 1000);
-    TEST_ASSERT(ble_hs_conn_first() == NULL);
-    TEST_ASSERT(!ble_gap_conn_master_in_progress());
-    TEST_ASSERT(cb_called);
-
-    tu_restart();
-}
-
-TEST_CASE(ble_gap_gen_disc_test_case)
-{
-    os_init();
-
-    ble_hs_test_util_init();
-
-    os_task_init(&ble_gap_test_task,
-                 "ble_gap_gen_disc_test_task",
-                 ble_gap_gen_disc_test_task_handler, NULL,
-                 BLE_GAP_TEST_HS_PRIO + 1, OS_WAIT_FOREVER, ble_gap_test_stack,
-                 OS_STACK_ALIGN(BLE_GAP_TEST_STACK_SIZE));
-
-    os_start();
-}
-
-static void
-ble_gap_terminate_cb(struct ble_gap_conn_event *event, void *arg)
-{
-    int *disconn_handle;
-
-    if (event->type != BLE_GAP_CONN_EVENT_TYPE_TERMINATE) {
-        return;
-    }
-
-    disconn_handle = arg;
-
-    TEST_ASSERT(event->term.status == 0);
-    TEST_ASSERT(event->term.reason == BLE_ERR_REM_USER_CONN_TERM);
-
-    *disconn_handle = event->term.handle;
-}
-
-
-static void
-ble_gap_terminate_test_task_handler(void *arg)
-{
-    struct hci_disconn_complete disconn_evt;
-    struct hci_le_conn_complete conn_evt;
-    uint8_t addr1[6] = { 1, 2, 3, 4, 5, 6 };
-    uint8_t addr2[6] = { 2, 3, 4, 5, 6, 7 };
-    int disconn_handle;;
-    int rc;
-
-    /* Receive acknowledgements for the startup sequence.  We sent the
-     * corresponding requests when the host task was started.
-     */
-    ble_hs_test_util_rx_startup_acks();
-
-    /* Set the connect callback so we can verify that it gets called with the
-     * proper arguments.
-     */
-    disconn_handle = 0;
-    ble_gap_conn_set_cb(ble_gap_terminate_cb, &disconn_handle);
-
-    /* Make sure there are no created connections and no connections in
-     * progress.
-     */
-    TEST_ASSERT(ble_hs_conn_first() == NULL);
-    TEST_ASSERT(!ble_gap_conn_master_in_progress());
-
-    /* Create two direct connections. */
-    ble_gap_conn_direct_connect(0, addr1);
-    ble_gap_test_misc_rx_le_ack(BLE_HCI_OCF_LE_CREATE_CONN, 0);
-    memset(&conn_evt, 0, sizeof conn_evt);
-    conn_evt.subevent_code = BLE_HCI_LE_SUBEV_CONN_COMPLETE;
-    conn_evt.status = BLE_ERR_SUCCESS;
-    conn_evt.connection_handle = 1;
-    memcpy(conn_evt.peer_addr, addr1, 6);
-    rc = ble_gap_conn_rx_conn_complete(&conn_evt);
-    TEST_ASSERT(rc == 0);
-
-    ble_gap_conn_direct_connect(0, addr2);
-    ble_gap_test_misc_rx_le_ack(BLE_HCI_OCF_LE_CREATE_CONN, 0);
-    memset(&conn_evt, 0, sizeof conn_evt);
-    conn_evt.subevent_code = BLE_HCI_LE_SUBEV_CONN_COMPLETE;
-    conn_evt.status = BLE_ERR_SUCCESS;
-    conn_evt.connection_handle = 2;
-    memcpy(conn_evt.peer_addr, addr2, 6);
-    rc = ble_gap_conn_rx_conn_complete(&conn_evt);
-    TEST_ASSERT(rc == 0);
-
-    TEST_ASSERT_FATAL(ble_hs_conn_find(1) != NULL);
-    TEST_ASSERT_FATAL(ble_hs_conn_find(2) != NULL);
-
-    /* Terminate the first one. */
-    rc = ble_gap_conn_terminate(1);
-    TEST_ASSERT(rc == 0);
-    ble_gap_test_misc_rx_ack(BLE_HCI_OGF_LINK_CTRL, BLE_HCI_OCF_DISCONNECT_CMD,
-                             0);
-    disconn_evt.connection_handle = 1;
-    disconn_evt.status = 0;
-    disconn_evt.reason = BLE_ERR_REM_USER_CONN_TERM;
-    ble_gap_conn_rx_disconn_complete(&disconn_evt);
-    TEST_ASSERT(disconn_handle == 1);
-    TEST_ASSERT(ble_hs_conn_find(1) == NULL);
-    TEST_ASSERT(ble_hs_conn_find(2) != NULL);
-
-    /* Terminate the second one. */
-    rc = ble_gap_conn_terminate(2);
-    TEST_ASSERT(rc == 0);
-    ble_gap_test_misc_rx_ack(BLE_HCI_OGF_LINK_CTRL, BLE_HCI_OCF_DISCONNECT_CMD,
-                             0);
-    disconn_evt.connection_handle = 2;
-    disconn_evt.status = 0;
-    disconn_evt.reason = BLE_ERR_REM_USER_CONN_TERM;
-    ble_gap_conn_rx_disconn_complete(&disconn_evt);
-    TEST_ASSERT(disconn_handle == 2);
-    TEST_ASSERT(ble_hs_conn_find(1) == NULL);
-    TEST_ASSERT(ble_hs_conn_find(2) == NULL);
-
-    tu_restart();
-}
-
-TEST_CASE(ble_gap_terminate_test_case)
-{
-    os_init();
-
-    ble_hs_test_util_init();
-
-    os_task_init(&ble_gap_test_task,
-                 "ble_gap_terminate_test_task",
-                 ble_gap_terminate_test_task_handler, NULL,
-                 BLE_GAP_TEST_HS_PRIO + 1, OS_WAIT_FOREVER, ble_gap_test_stack,
-                 OS_STACK_ALIGN(BLE_GAP_TEST_STACK_SIZE));
-
-    os_start();
-}
-
-TEST_SUITE(ble_gap_test_suite)
-{
-    ble_gap_gen_disc_test_case();
-    ble_gap_direct_connect_test_case();
-    ble_gap_terminate_test_case();
-}
-
-int
-ble_gap_test_all(void)
-{
-    ble_gap_test_suite();
-    return tu_any_failed;
-}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/abed8b72/net/nimble/host/src/test/ble_hs_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_hs_test.c b/net/nimble/host/src/test/ble_hs_test.c
index dfcf0f8..464c4cd 100644
--- a/net/nimble/host/src/test/ble_hs_test.c
+++ b/net/nimble/host/src/test/ble_hs_test.c
@@ -45,7 +45,7 @@ main(void)
     ble_att_clt_test_all();
     ble_host_hci_test_all();
     ble_hs_conn_test_all();
-    ble_gap_test_all();
+    ble_os_test_all();
     ble_hs_uuid_test_all();
     ble_gatt_disc_s_test_all();
     ble_gatt_disc_c_test_all();

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/abed8b72/net/nimble/host/src/test/ble_os_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_os_test.c b/net/nimble/host/src/test/ble_os_test.c
new file mode 100644
index 0000000..18e8ada
--- /dev/null
+++ b/net/nimble/host/src/test/ble_os_test.c
@@ -0,0 +1,348 @@
+/**
+ * Copyright (c) 2015 Runtime Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string.h>
+#include "os/os.h"
+#include "testutil/testutil.h"
+#include "nimble/hci_common.h"
+#include "nimble/hci_transport.h"
+#include "ble_hs_priv.h"
+#include "host/ble_hs_test.h"
+#include "host/ble_gap.h"
+#include "ble_hs_test_util.h"
+#include "ble_hs_conn.h"
+#include "ble_gap_conn.h"
+
+#ifdef ARCH_sim
+#define BLE_OS_TEST_STACK_SIZE      1024
+#else
+#define BLE_OS_TEST_STACK_SIZE      256
+#endif
+
+#define BLE_OS_TEST_HS_PRIO         10
+
+static struct os_task ble_os_test_task;
+static os_stack_t ble_os_test_stack[OS_STACK_ALIGN(BLE_OS_TEST_STACK_SIZE)];
+
+static uint8_t ble_os_test_peer_addr[6] = { 1, 2, 3, 4, 5, 6 };
+
+static void
+ble_os_test_misc_rx_ack(uint8_t ogf, uint8_t ocf, uint8_t status)
+{
+    uint16_t opcode;
+    uint8_t *cmd;
+    int rc;
+
+    cmd = os_memblock_get(&g_hci_cmd_pool);
+    TEST_ASSERT_FATAL(cmd != NULL);
+
+    opcode = (ogf << 10) | ocf;
+    ble_hs_test_util_build_cmd_status(cmd, BLE_HCI_EVENT_CMD_STATUS_LEN,
+                                      status, 1, opcode);
+
+    rc = ble_hci_transport_ctlr_event_send(cmd);
+    TEST_ASSERT(rc == 0);
+}
+
+static void
+ble_os_test_misc_rx_le_ack(uint16_t ocf, uint8_t status)
+{
+    ble_os_test_misc_rx_ack(BLE_HCI_OGF_LE, ocf, status);
+}
+
+static void
+ble_gap_direct_connect_test_connect_cb(struct ble_gap_conn_event *event,
+                                       void *arg)
+{
+    int *cb_called;
+
+    cb_called = arg;
+    *cb_called = 1;
+
+    TEST_ASSERT(event->type == BLE_GAP_CONN_EVENT_TYPE_CONNECT);
+    TEST_ASSERT(event->conn.status == BLE_ERR_SUCCESS);
+    TEST_ASSERT(event->conn.handle == 2);
+    TEST_ASSERT(memcmp(event->conn.peer_addr, ble_os_test_peer_addr, 6) ==
+                0);
+}
+
+static void
+ble_gap_direct_connect_test_task_handler(void *arg)
+{
+    struct hci_le_conn_complete evt;
+    uint8_t addr[6] = { 1, 2, 3, 4, 5, 6 };
+    int cb_called;
+    int rc;
+
+    /* Receive acknowledgements for the startup sequence.  We sent the
+     * corresponding requests when the host task was started.
+     */
+    ble_hs_test_util_rx_startup_acks();
+
+    /* Set the connect callback so we can verify that it gets called with the
+     * proper arguments.
+     */
+    cb_called = 0;
+    ble_gap_conn_set_cb(ble_gap_direct_connect_test_connect_cb, &cb_called);
+
+    /* Make sure there are no created connections and no connections in
+     * progress.
+     */
+    TEST_ASSERT(ble_hs_conn_first() == NULL);
+
+    /* Initiate a direct connection. */
+    ble_gap_conn_direct_connect(0, addr);
+    TEST_ASSERT(ble_hs_conn_first() == NULL);
+    TEST_ASSERT(!cb_called);
+
+    /* Receive an ack for the HCI create-connection command. */
+    ble_os_test_misc_rx_le_ack(BLE_HCI_OCF_LE_CREATE_CONN, 0);
+    TEST_ASSERT(ble_hs_conn_first() == NULL);
+    TEST_ASSERT(!cb_called);
+
+    /* Receive an HCI connection-complete event. */
+    memset(&evt, 0, sizeof evt);
+    evt.subevent_code = BLE_HCI_LE_SUBEV_CONN_COMPLETE;
+    evt.status = BLE_ERR_SUCCESS;
+    evt.connection_handle = 2;
+    memcpy(evt.peer_addr, addr, 6);
+    rc = ble_gap_conn_rx_conn_complete(&evt);
+    TEST_ASSERT(rc == 0);
+
+    /* The connection should now be created. */
+    TEST_ASSERT(ble_hs_conn_find(2) != NULL);
+    TEST_ASSERT(cb_called);
+
+    tu_restart();
+}
+
+TEST_CASE(ble_gap_direct_connect_test_case)
+{
+    os_init();
+
+    ble_hs_test_util_init();
+
+    os_task_init(&ble_os_test_task,
+                 "ble_gap_direct_connect_test_task",
+                 ble_gap_direct_connect_test_task_handler, NULL,
+                 BLE_OS_TEST_HS_PRIO + 1, OS_WAIT_FOREVER, ble_os_test_stack,
+                 OS_STACK_ALIGN(BLE_OS_TEST_STACK_SIZE));
+
+    os_start();
+}
+
+static void
+ble_gap_gen_disc_test_connect_cb(struct ble_gap_conn_event *event, void *arg)
+{
+    int *cb_called;
+
+    cb_called = arg;
+    *cb_called = 1;
+
+    TEST_ASSERT(event->type == BLE_GAP_CONN_EVENT_TYPE_SCAN_DONE);
+}
+
+static void
+ble_gap_gen_disc_test_task_handler(void *arg)
+{
+    int cb_called;
+
+    /* Receive acknowledgements for the startup sequence.  We sent the
+     * corresponding requests when the host task was started.
+     */
+    ble_hs_test_util_rx_startup_acks();
+
+    /* Set the connect callback so we can verify that it gets called with the
+     * proper arguments.
+     */
+    cb_called = 0;
+    ble_gap_conn_set_cb(ble_gap_gen_disc_test_connect_cb, &cb_called);
+
+    /* Make sure there are no created connections and no connections in
+     * progress.
+     */
+    TEST_ASSERT(ble_hs_conn_first() == NULL);
+    TEST_ASSERT(!ble_gap_conn_master_in_progress());
+
+    /* Initiate the general discovery procedure with a 200 ms timeout. */
+    ble_gap_conn_gen_disc(200);
+    TEST_ASSERT(ble_hs_conn_first() == NULL);
+    TEST_ASSERT(ble_gap_conn_master_in_progress());
+    TEST_ASSERT(!cb_called);
+
+    /* Receive acks from the controller. */
+    ble_os_test_misc_rx_le_ack(BLE_HCI_OCF_LE_SET_SCAN_PARAMS, 0);
+    ble_os_test_misc_rx_le_ack(BLE_HCI_OCF_LE_SET_SCAN_ENABLE, 0);
+    TEST_ASSERT(ble_hs_conn_first() == NULL);
+    TEST_ASSERT(ble_gap_conn_master_in_progress());
+    TEST_ASSERT(!cb_called);
+
+    /* Wait 100 ms; verify scan still in progress. */
+    os_time_delay(100 * OS_TICKS_PER_SEC / 1000);
+    TEST_ASSERT(ble_hs_conn_first() == NULL);
+    TEST_ASSERT(ble_gap_conn_master_in_progress());
+    TEST_ASSERT(!cb_called);
+
+    /* Wait 150 more ms; verify scan completed. */
+    os_time_delay(150 * OS_TICKS_PER_SEC / 1000);
+    TEST_ASSERT(ble_hs_conn_first() == NULL);
+    TEST_ASSERT(!ble_gap_conn_master_in_progress());
+    TEST_ASSERT(cb_called);
+
+    tu_restart();
+}
+
+TEST_CASE(ble_gap_gen_disc_test_case)
+{
+    os_init();
+
+    ble_hs_test_util_init();
+
+    os_task_init(&ble_os_test_task,
+                 "ble_gap_gen_disc_test_task",
+                 ble_gap_gen_disc_test_task_handler, NULL,
+                 BLE_OS_TEST_HS_PRIO + 1, OS_WAIT_FOREVER, ble_os_test_stack,
+                 OS_STACK_ALIGN(BLE_OS_TEST_STACK_SIZE));
+
+    os_start();
+}
+
+static void
+ble_gap_terminate_cb(struct ble_gap_conn_event *event, void *arg)
+{
+    int *disconn_handle;
+
+    if (event->type != BLE_GAP_CONN_EVENT_TYPE_TERMINATE) {
+        return;
+    }
+
+    disconn_handle = arg;
+
+    TEST_ASSERT(event->term.status == 0);
+    TEST_ASSERT(event->term.reason == BLE_ERR_REM_USER_CONN_TERM);
+
+    *disconn_handle = event->term.handle;
+}
+
+
+static void
+ble_gap_terminate_test_task_handler(void *arg)
+{
+    struct hci_disconn_complete disconn_evt;
+    struct hci_le_conn_complete conn_evt;
+    uint8_t addr1[6] = { 1, 2, 3, 4, 5, 6 };
+    uint8_t addr2[6] = { 2, 3, 4, 5, 6, 7 };
+    int disconn_handle;;
+    int rc;
+
+    /* Receive acknowledgements for the startup sequence.  We sent the
+     * corresponding requests when the host task was started.
+     */
+    ble_hs_test_util_rx_startup_acks();
+
+    /* Set the connect callback so we can verify that it gets called with the
+     * proper arguments.
+     */
+    disconn_handle = 0;
+    ble_gap_conn_set_cb(ble_gap_terminate_cb, &disconn_handle);
+
+    /* Make sure there are no created connections and no connections in
+     * progress.
+     */
+    TEST_ASSERT(ble_hs_conn_first() == NULL);
+    TEST_ASSERT(!ble_gap_conn_master_in_progress());
+
+    /* Create two direct connections. */
+    ble_gap_conn_direct_connect(0, addr1);
+    ble_os_test_misc_rx_le_ack(BLE_HCI_OCF_LE_CREATE_CONN, 0);
+    memset(&conn_evt, 0, sizeof conn_evt);
+    conn_evt.subevent_code = BLE_HCI_LE_SUBEV_CONN_COMPLETE;
+    conn_evt.status = BLE_ERR_SUCCESS;
+    conn_evt.connection_handle = 1;
+    memcpy(conn_evt.peer_addr, addr1, 6);
+    rc = ble_gap_conn_rx_conn_complete(&conn_evt);
+    TEST_ASSERT(rc == 0);
+
+    ble_gap_conn_direct_connect(0, addr2);
+    ble_os_test_misc_rx_le_ack(BLE_HCI_OCF_LE_CREATE_CONN, 0);
+    memset(&conn_evt, 0, sizeof conn_evt);
+    conn_evt.subevent_code = BLE_HCI_LE_SUBEV_CONN_COMPLETE;
+    conn_evt.status = BLE_ERR_SUCCESS;
+    conn_evt.connection_handle = 2;
+    memcpy(conn_evt.peer_addr, addr2, 6);
+    rc = ble_gap_conn_rx_conn_complete(&conn_evt);
+    TEST_ASSERT(rc == 0);
+
+    TEST_ASSERT_FATAL(ble_hs_conn_find(1) != NULL);
+    TEST_ASSERT_FATAL(ble_hs_conn_find(2) != NULL);
+
+    /* Terminate the first one. */
+    rc = ble_gap_conn_terminate(1);
+    TEST_ASSERT(rc == 0);
+    ble_os_test_misc_rx_ack(BLE_HCI_OGF_LINK_CTRL, BLE_HCI_OCF_DISCONNECT_CMD,
+                             0);
+    disconn_evt.connection_handle = 1;
+    disconn_evt.status = 0;
+    disconn_evt.reason = BLE_ERR_REM_USER_CONN_TERM;
+    ble_gap_conn_rx_disconn_complete(&disconn_evt);
+    TEST_ASSERT(disconn_handle == 1);
+    TEST_ASSERT(ble_hs_conn_find(1) == NULL);
+    TEST_ASSERT(ble_hs_conn_find(2) != NULL);
+
+    /* Terminate the second one. */
+    rc = ble_gap_conn_terminate(2);
+    TEST_ASSERT(rc == 0);
+    ble_os_test_misc_rx_ack(BLE_HCI_OGF_LINK_CTRL, BLE_HCI_OCF_DISCONNECT_CMD,
+                             0);
+    disconn_evt.connection_handle = 2;
+    disconn_evt.status = 0;
+    disconn_evt.reason = BLE_ERR_REM_USER_CONN_TERM;
+    ble_gap_conn_rx_disconn_complete(&disconn_evt);
+    TEST_ASSERT(disconn_handle == 2);
+    TEST_ASSERT(ble_hs_conn_find(1) == NULL);
+    TEST_ASSERT(ble_hs_conn_find(2) == NULL);
+
+    tu_restart();
+}
+
+TEST_CASE(ble_gap_terminate_test_case)
+{
+    os_init();
+
+    ble_hs_test_util_init();
+
+    os_task_init(&ble_os_test_task,
+                 "ble_gap_terminate_test_task",
+                 ble_gap_terminate_test_task_handler, NULL,
+                 BLE_OS_TEST_HS_PRIO + 1, OS_WAIT_FOREVER, ble_os_test_stack,
+                 OS_STACK_ALIGN(BLE_OS_TEST_STACK_SIZE));
+
+    os_start();
+}
+
+TEST_SUITE(ble_os_test_suite)
+{
+    ble_gap_gen_disc_test_case();
+    ble_gap_direct_connect_test_case();
+    ble_gap_terminate_test_case();
+}
+
+int
+ble_os_test_all(void)
+{
+    ble_os_test_suite();
+    return tu_any_failed;
+}


[3/3] incubator-mynewt-larva git commit: Number of Completed Packets event.

Posted by cc...@apache.org.
Number of Completed Packets event.


Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/commit/9d961604
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/tree/9d961604
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/diff/9d961604

Branch: refs/heads/master
Commit: 9d96160469db4b22120332a6d196b62367723f5e
Parents: abed8b7
Author: Christopher Collins <cc...@gmail.com>
Authored: Thu Dec 17 11:25:12 2015 -0800
Committer: Christopher Collins <cc...@gmail.com>
Committed: Thu Dec 17 12:04:38 2015 -0800

----------------------------------------------------------------------
 net/nimble/host/src/ble_hs_conn.c            | 17 ++++++
 net/nimble/host/src/ble_hs_conn.h            |  2 +
 net/nimble/host/src/host_hci.c               | 38 ++++++++++++-
 net/nimble/host/src/test/ble_host_hci_test.c |  2 +-
 net/nimble/host/src/test/ble_hs_conn_test.c  | 66 +++++++++++++++++++++++
 net/nimble/host/src/test/ble_hs_test_util.c  | 40 +++++++++++++-
 net/nimble/host/src/test/ble_hs_test_util.h  |  7 +++
 net/nimble/include/nimble/hci_common.h       |  4 ++
 8 files changed, 173 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/9d961604/net/nimble/host/src/ble_hs_conn.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_hs_conn.c b/net/nimble/host/src/ble_hs_conn.c
index 99c919c..1dddb3a 100644
--- a/net/nimble/host/src/ble_hs_conn.c
+++ b/net/nimble/host/src/ble_hs_conn.c
@@ -42,6 +42,7 @@ ble_hs_conn_alloc(void)
     if (conn == NULL) {
         goto err;
     }
+    memset(conn, 0, sizeof *conn);
 
     SLIST_INIT(&conn->bhc_channels);
 
@@ -136,6 +137,22 @@ ble_hs_conn_chan_find(struct ble_hs_conn *conn, uint16_t cid)
     return NULL;
 }
 
+void
+ble_hs_conn_rx_num_completed_pkts(uint16_t handle, uint16_t num_pkts)
+{
+    struct ble_hs_conn *conn;
+
+    conn = ble_hs_conn_find(handle);
+    if (conn == NULL) {
+        return;
+    }
+
+    if (num_pkts > conn->bhc_outstanding_pkts) {
+        num_pkts = conn->bhc_outstanding_pkts;
+    }
+    conn->bhc_outstanding_pkts -= num_pkts;
+}
+
 static void
 ble_hs_conn_free_mem(void)
 {

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/9d961604/net/nimble/host/src/ble_hs_conn.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_hs_conn.h b/net/nimble/host/src/ble_hs_conn.h
index 0951376..a8b2dfb 100644
--- a/net/nimble/host/src/ble_hs_conn.h
+++ b/net/nimble/host/src/ble_hs_conn.h
@@ -30,6 +30,7 @@ struct ble_hs_conn {
     uint8_t bhc_addr[6];
 
     struct ble_l2cap_chan_list bhc_channels;
+    uint16_t bhc_outstanding_pkts;
 
     struct ble_att_svr_conn bhc_att_svr;
 };
@@ -42,6 +43,7 @@ struct ble_hs_conn *ble_hs_conn_find(uint16_t con_handle);
 struct ble_hs_conn *ble_hs_conn_first(void);
 struct ble_l2cap_chan *ble_hs_conn_chan_find(struct ble_hs_conn *conn,
                                              uint16_t cid);
+void ble_hs_conn_rx_num_completed_pkts(uint16_t handle, uint16_t num_pkts);
 int ble_hs_conn_init(void);
 
 #endif

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/9d961604/net/nimble/host/src/host_hci.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/host_hci.c b/net/nimble/host/src/host_hci.c
index 2ac44f1..c901f6d 100644
--- a/net/nimble/host/src/host_hci.c
+++ b/net/nimble/host/src/host_hci.c
@@ -38,6 +38,8 @@ static int host_hci_rx_disconn_complete(uint8_t event_code, uint8_t *data,
 static int host_hci_rx_cmd_complete(uint8_t event_code, uint8_t *data,
                                     int len);
 static int host_hci_rx_cmd_status(uint8_t event_code, uint8_t *data, int len);
+static int host_hci_rx_num_completed_pkts(uint8_t event_code, uint8_t *data,
+                                          int len);
 static int host_hci_rx_le_meta(uint8_t event_code, uint8_t *data, int len);
 static int host_hci_rx_le_conn_complete(uint8_t subevent, uint8_t *data,
                                         int len);
@@ -71,9 +73,10 @@ struct host_hci_event_dispatch_entry {
 };
 
 static const struct host_hci_event_dispatch_entry host_hci_event_dispatch[] = {
+    { BLE_HCI_EVCODE_DISCONN_CMP, host_hci_rx_disconn_complete },
     { BLE_HCI_EVCODE_COMMAND_COMPLETE, host_hci_rx_cmd_complete },
     { BLE_HCI_EVCODE_COMMAND_STATUS, host_hci_rx_cmd_status },
-    { BLE_HCI_EVCODE_DISCONN_CMP, host_hci_rx_disconn_complete },
+    { BLE_HCI_EVCODE_NUM_COMP_PKTS, host_hci_rx_num_completed_pkts },
     { BLE_HCI_EVCODE_LE_META, host_hci_rx_le_meta },
 };
 
@@ -271,6 +274,37 @@ host_hci_rx_cmd_status(uint8_t event_code, uint8_t *data, int len)
 }
 
 static int
+host_hci_rx_num_completed_pkts(uint8_t event_code, uint8_t *data, int len)
+{
+    uint16_t num_pkts;
+    uint16_t handle;
+    uint8_t num_handles;
+    int off;
+    int i;
+
+    if (len < BLE_HCI_EVENT_HDR_LEN + BLE_HCI_EVENT_NUM_COMP_PKTS_HDR_LEN) {
+        return BLE_HS_EMSGSIZE;
+    }
+
+    off = BLE_HCI_EVENT_HDR_LEN;
+    num_handles = data[off];
+    if (len < BLE_HCI_EVENT_NUM_COMP_PKTS_HDR_LEN +
+              num_handles * BLE_HCI_EVENT_NUM_COMP_PKTS_ENT_LEN) {
+        return BLE_HS_EMSGSIZE;
+    }
+    off++;
+
+    for (i = 0; i < num_handles; i++) {
+        handle = le16toh(data + off + 2 * i);
+        num_pkts = le16toh(data + off + 2 * num_handles + 2 * i);
+
+        ble_hs_conn_rx_num_completed_pkts(handle, num_pkts);
+    }
+
+    return 0;
+}
+
+static int
 host_hci_rx_le_meta(uint8_t event_code, uint8_t *data, int len)
 {
     const struct host_hci_le_event_dispatch_entry *entry;
@@ -642,6 +676,8 @@ host_hci_data_tx(struct ble_hs_conn *connection, struct os_mbuf *om)
         return rc;
     }
 
+    connection->bhc_outstanding_pkts++;
+
     return 0;
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/9d961604/net/nimble/host/src/test/ble_host_hci_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_host_hci_test.c b/net/nimble/host/src/test/ble_host_hci_test.c
index 271104f..284f149 100644
--- a/net/nimble/host/src/test/ble_host_hci_test.c
+++ b/net/nimble/host/src/test/ble_host_hci_test.c
@@ -86,7 +86,7 @@ TEST_CASE(ble_host_hci_test_event_cmd_status)
 
     /*** No error on NOP. */
     ble_hs_test_util_build_cmd_complete(buf, sizeof buf, 0, 1,
-                                              BLE_HCI_OPCODE_NOP);
+                                        BLE_HCI_OPCODE_NOP);
     rc = host_hci_event_rx(buf);
     TEST_ASSERT(rc == 0);
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/9d961604/net/nimble/host/src/test/ble_hs_conn_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_hs_conn_test.c b/net/nimble/host/src/test/ble_hs_conn_test.c
index db966a1..6c5d9a6 100644
--- a/net/nimble/host/src/test/ble_hs_conn_test.c
+++ b/net/nimble/host/src/test/ble_hs_conn_test.c
@@ -223,12 +223,78 @@ TEST_CASE(ble_hs_conn_test_direct_connectable_hci_errors)
     TEST_ASSERT(ble_hs_conn_first() == NULL);
 }
 
+TEST_CASE(ble_hs_conn_test_completed_pkts)
+{
+    struct ble_hs_conn *conn1;
+    struct ble_hs_conn *conn2;
+
+    ble_hs_test_util_init();
+
+    conn1 = ble_hs_test_util_create_conn(1, ((uint8_t[]){2,3,4,5,6,7,8,9}));
+    conn2 = ble_hs_test_util_create_conn(2, ((uint8_t[]){3,4,5,6,7,8,9,10}));
+
+    conn1->bhc_outstanding_pkts = 5;
+    conn2->bhc_outstanding_pkts = 5;
+
+    /*** Event specifies nonexistent connection; no effect. */
+    ble_hs_test_util_rx_num_completed_pkts_event(
+        (struct ble_hs_test_util_num_completed_pkts_entry []) {
+            { 5, 5 },
+            { 0 }});
+    TEST_ASSERT(conn1->bhc_outstanding_pkts == 5);
+    TEST_ASSERT(conn2->bhc_outstanding_pkts == 5);
+
+    /*** Event specifies connection 1. */
+    ble_hs_test_util_rx_num_completed_pkts_event(
+        (struct ble_hs_test_util_num_completed_pkts_entry []) {
+            { 1, 1 },
+            { 0 }});
+    TEST_ASSERT(conn1->bhc_outstanding_pkts == 4);
+    TEST_ASSERT(conn2->bhc_outstanding_pkts == 5);
+
+    /*** Event specifies connection 2. */
+    ble_hs_test_util_rx_num_completed_pkts_event(
+        (struct ble_hs_test_util_num_completed_pkts_entry []) {
+            { 2, 1 },
+            { 0 }});
+    TEST_ASSERT(conn1->bhc_outstanding_pkts == 4);
+    TEST_ASSERT(conn2->bhc_outstanding_pkts == 4);
+
+    /*** Event specifies connections 1 and 2. */
+    ble_hs_test_util_rx_num_completed_pkts_event(
+        (struct ble_hs_test_util_num_completed_pkts_entry []) {
+            { 1, 2 },
+            { 2, 2 },
+            { 0 }});
+    TEST_ASSERT(conn1->bhc_outstanding_pkts == 2);
+    TEST_ASSERT(conn2->bhc_outstanding_pkts == 2);
+
+    /*** Event specifies connections 1, 2, and nonexistent. */
+    ble_hs_test_util_rx_num_completed_pkts_event(
+        (struct ble_hs_test_util_num_completed_pkts_entry []) {
+            { 1, 1 },
+            { 2, 1 },
+            { 10, 50 },
+            { 0 }});
+    TEST_ASSERT(conn1->bhc_outstanding_pkts == 1);
+    TEST_ASSERT(conn2->bhc_outstanding_pkts == 1);
+
+    /*** Don't wrap when count gets out of sync. */
+    ble_hs_test_util_rx_num_completed_pkts_event(
+        (struct ble_hs_test_util_num_completed_pkts_entry []) {
+            { 1, 10 },
+            { 0 }});
+    TEST_ASSERT(conn1->bhc_outstanding_pkts == 0);
+    TEST_ASSERT(conn2->bhc_outstanding_pkts == 1);
+}
+
 TEST_SUITE(conn_suite)
 {
     ble_hs_conn_test_direct_connect_success();
     ble_hs_conn_test_direct_connect_hci_errors();
     ble_hs_conn_test_direct_connectable_success();
     ble_hs_conn_test_direct_connectable_hci_errors();
+    ble_hs_conn_test_completed_pkts();
 }
 
 int

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/9d961604/net/nimble/host/src/test/ble_hs_test_util.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_hs_test_util.c b/net/nimble/host/src/test/ble_hs_test_util.c
index dcf1f5c..9481f70 100644
--- a/net/nimble/host/src/test/ble_hs_test_util.c
+++ b/net/nimble/host/src/test/ble_hs_test_util.c
@@ -16,6 +16,7 @@
 
 #include <string.h>
 #include <errno.h>
+#include <assert.h>
 #include "nimble/ble.h"
 #include "nimble/hci_common.h"
 #include "testutil/testutil.h"
@@ -75,7 +76,7 @@ ble_hs_test_util_create_conn(uint16_t handle, uint8_t *addr)
     memset(&evt, 0, sizeof evt);
     evt.subevent_code = BLE_HCI_LE_SUBEV_CONN_COMPLETE;
     evt.status = BLE_ERR_SUCCESS;
-    evt.connection_handle = 2;
+    evt.connection_handle = handle;
     memcpy(evt.peer_addr, addr, 6);
     rc = ble_gap_conn_rx_conn_complete(&evt);
 
@@ -188,6 +189,43 @@ ble_hs_test_util_rx_startup_acks(void)
 }
 
 void
+ble_hs_test_util_rx_num_completed_pkts_event(
+    struct ble_hs_test_util_num_completed_pkts_entry *entries)
+{
+    struct ble_hs_test_util_num_completed_pkts_entry *entry;
+    uint8_t buf[1024];
+    int num_entries;
+    int off;
+    int rc;
+    int i;
+
+    /* Count number of entries. */
+    num_entries = 0;
+    for (entry = entries; entry->handle_id != 0; entry++) {
+        num_entries++;
+    }
+    assert(num_entries <= UINT8_MAX);
+
+    buf[0] = BLE_HCI_EVCODE_NUM_COMP_PKTS;
+    buf[2] = num_entries;
+
+    off = 3;
+    for (i = 0; i < num_entries; i++) {
+        htole16(buf + off, entries[i].handle_id);
+        off += 2;
+    }
+    for (i = 0; i < num_entries; i++) {
+        htole16(buf + off, entries[i].num_pkts);
+        off += 2;
+    }
+
+    buf[1] = off - 2;
+
+    rc = host_hci_event_rx(buf);
+    TEST_ASSERT(rc == 0);
+}
+
+void
 ble_hs_test_util_init(void)
 {
     int rc;

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/9d961604/net/nimble/host/src/test/ble_hs_test_util.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_hs_test_util.h b/net/nimble/host/src/test/ble_hs_test_util.h
index 9c71560..feae544 100644
--- a/net/nimble/host/src/test/ble_hs_test_util.h
+++ b/net/nimble/host/src/test/ble_hs_test_util.h
@@ -23,6 +23,11 @@ struct ble_l2cap_chan;
 
 extern struct os_mbuf *ble_hs_test_util_prev_tx;
 
+struct ble_hs_test_util_num_completed_pkts_entry {
+    uint16_t handle_id; /* 0 for terminating entry in array. */
+    uint16_t num_pkts;
+};
+
 void ble_hs_test_util_build_cmd_complete(uint8_t *dst, int len,
                                          uint8_t param_len, uint8_t num_pkts,
                                          uint16_t opcode);
@@ -40,6 +45,8 @@ void ble_hs_test_util_rx_hci_buf_size_ack(uint16_t buf_size);
 void ble_hs_test_util_rx_att_err_rsp(struct ble_hs_conn *conn, uint8_t req_op,
                                      uint8_t error_code);
 void ble_hs_test_util_rx_startup_acks(void);
+void ble_hs_test_util_rx_num_completed_pkts_event(
+    struct ble_hs_test_util_num_completed_pkts_entry *entries);
 void ble_hs_test_util_init(void);
 
 #endif

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/9d961604/net/nimble/include/nimble/hci_common.h
----------------------------------------------------------------------
diff --git a/net/nimble/include/nimble/hci_common.h b/net/nimble/include/nimble/hci_common.h
index 50c07a7..f456f9c 100644
--- a/net/nimble/include/nimble/hci_common.h
+++ b/net/nimble/include/nimble/hci_common.h
@@ -358,6 +358,10 @@
 /* Event command status */
 #define BLE_HCI_EVENT_CMD_STATUS_LEN        (6)
 
+/* Number of completed packets */
+#define BLE_HCI_EVENT_NUM_COMP_PKTS_HDR_LEN (1)
+#define BLE_HCI_EVENT_NUM_COMP_PKTS_ENT_LEN (4)
+
 /* Advertising report */
 #define BLE_HCI_ADV_RPT_EVTYPE_ADV_IND      (0)
 #define BLE_HCI_ADV_RPT_EVTYPE_DIR_IND      (1)