/*
|
* Licensed to the Apache Software Foundation (ASF) under one
|
* or more contributor license agreements. See the NOTICE file
|
* distributed with this work for additional information
|
* regarding copyright ownership. The ASF licenses this file
|
* to you 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 "ble_hs_test.h"
|
#include "host/ble_gap.h"
|
#include "ble_hs_test_util.h"
|
|
#define BLE_OS_TEST_STACK_SIZE 256
|
#define BLE_OS_TEST_APP_STACK_SIZE 256
|
|
#define BLE_OS_TEST_APP_PRIO 9
|
#define BLE_OS_TEST_TASK_PRIO 10
|
|
static struct os_task ble_os_test_task;
|
static struct os_task ble_os_test_app_task;
|
static os_stack_t ble_os_test_stack[OS_STACK_ALIGN(BLE_OS_TEST_STACK_SIZE)];
|
|
static os_stack_t
|
ble_os_test_app_stack[OS_STACK_ALIGN(BLE_OS_TEST_APP_STACK_SIZE)];
|
|
static uint8_t ble_os_test_peer_addr[6] = { 1, 2, 3, 4, 5, 6 };
|
|
static void ble_os_test_app_task_handler(void *arg);
|
|
static int ble_os_test_gap_event_type;
|
|
static void
|
ble_os_test_init_app_task(void)
|
{
|
int rc;
|
|
rc = os_task_init(&ble_os_test_app_task,
|
"ble_gap_terminate_test_task",
|
ble_os_test_app_task_handler, NULL,
|
BLE_OS_TEST_APP_PRIO, OS_WAIT_FOREVER,
|
ble_os_test_app_stack,
|
OS_STACK_ALIGN(BLE_OS_TEST_APP_STACK_SIZE));
|
TEST_ASSERT_FATAL(rc == 0);
|
}
|
|
static void
|
ble_os_test_misc_init(void)
|
{
|
extern os_time_t g_os_time;
|
|
ble_hs_test_util_init_no_start();
|
|
/* Allow the OS to approach tick rollover. This will help ensure host
|
* timers don't break when the tick counter resets.
|
*/
|
g_os_time = UINT32_MAX - 10 * OS_TICKS_PER_SEC;
|
|
/* Receive acknowledgements for the startup sequence. We sent the
|
* corresponding requests when the host task was started.
|
*/
|
ble_hs_test_util_hci_ack_set_startup();
|
|
ble_os_test_init_app_task();
|
}
|
|
static int
|
ble_os_test_misc_conn_exists(uint16_t conn_handle)
|
{
|
struct ble_hs_conn *conn;
|
|
ble_hs_lock();
|
|
if (conn_handle == BLE_HS_CONN_HANDLE_NONE) {
|
conn = ble_hs_conn_first();
|
} else {
|
conn = ble_hs_conn_find(conn_handle);
|
}
|
|
ble_hs_unlock();
|
|
return conn != NULL;
|
}
|
|
static int
|
ble_gap_direct_connect_test_connect_cb(struct ble_gap_event *event, void *arg)
|
{
|
struct ble_gap_conn_desc desc;
|
int *cb_called;
|
int rc;
|
|
cb_called = arg;
|
*cb_called = 1;
|
|
TEST_ASSERT(event->type == BLE_GAP_EVENT_CONNECT);
|
TEST_ASSERT(event->connect.status == 0);
|
TEST_ASSERT(event->connect.conn_handle == 2);
|
|
rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
|
TEST_ASSERT_FATAL(rc == 0);
|
TEST_ASSERT(desc.peer_id_addr.type == BLE_ADDR_PUBLIC);
|
TEST_ASSERT(memcmp(desc.peer_id_addr.val, ble_os_test_peer_addr, 6) == 0);
|
|
return 0;
|
}
|
|
static void
|
ble_gap_direct_connect_test_task_handler(void *arg)
|
{
|
struct ble_gap_conn_complete evt;
|
ble_addr_t addr = { BLE_ADDR_PUBLIC, { 1, 2, 3, 4, 5, 6 }};
|
int cb_called;
|
int rc;
|
|
/* Set the connect callback so we can verify that it gets called with the
|
* proper arguments.
|
*/
|
cb_called = 0;
|
|
/* Make sure there are no created connections and no connections in
|
* progress.
|
*/
|
TEST_ASSERT(!ble_os_test_misc_conn_exists(BLE_HS_CONN_HANDLE_NONE));
|
|
/* Initiate a direct connection. */
|
ble_hs_test_util_connect(BLE_OWN_ADDR_PUBLIC, &addr, 0, NULL,
|
ble_gap_direct_connect_test_connect_cb,
|
&cb_called, 0);
|
TEST_ASSERT(!ble_os_test_misc_conn_exists(BLE_HS_CONN_HANDLE_NONE));
|
TEST_ASSERT(!cb_called);
|
|
/* ble_gap_rx_conn_complete() will send extra HCI command, need phony ack */
|
ble_hs_test_util_hci_ack_set(ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE,
|
BLE_HCI_OCF_LE_RD_REM_FEAT), 0);
|
|
/* Receive an HCI connection-complete event. */
|
memset(&evt, 0, sizeof evt);
|
evt.status = BLE_ERR_SUCCESS;
|
evt.connection_handle = 2;
|
memcpy(evt.peer_addr, addr.val, 6);
|
rc = ble_gap_rx_conn_complete(&evt, 0);
|
TEST_ASSERT(rc == 0);
|
|
/* The connection should now be created. */
|
TEST_ASSERT(ble_os_test_misc_conn_exists(2));
|
TEST_ASSERT(cb_called);
|
|
tu_restart();
|
}
|
|
TEST_CASE_SELF(ble_gap_direct_connect_test_case)
|
{
|
ble_os_test_misc_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_TASK_PRIO, OS_WAIT_FOREVER, ble_os_test_stack,
|
OS_STACK_ALIGN(BLE_OS_TEST_STACK_SIZE));
|
|
os_start();
|
|
ble_hs_test_util_assert_mbufs_freed(NULL);
|
}
|
|
static int
|
ble_os_disc_test_cb(struct ble_gap_event *event, void *arg)
|
{
|
int *cb_called;
|
|
cb_called = arg;
|
*cb_called = 1;
|
|
TEST_ASSERT(event->type == BLE_GAP_EVENT_DISC_COMPLETE);
|
|
return 0;
|
}
|
|
static void
|
ble_os_disc_test_task_handler(void *arg)
|
{
|
struct ble_gap_disc_params disc_params;
|
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_hci_ack_set_startup();
|
|
/* Set the connect callback so we can verify that it gets called with the
|
* proper arguments.
|
*/
|
cb_called = 0;
|
|
os_time_delay(10);
|
|
/* Make sure there are no created connections and no connections in
|
* progress.
|
*/
|
TEST_ASSERT(!ble_os_test_misc_conn_exists(BLE_HS_CONN_HANDLE_NONE));
|
TEST_ASSERT(!ble_gap_master_in_progress());
|
|
/* Initiate the general discovery procedure with a 300 ms timeout. */
|
memset(&disc_params, 0, sizeof disc_params);
|
rc = ble_hs_test_util_disc(BLE_OWN_ADDR_PUBLIC, 300, &disc_params,
|
ble_os_disc_test_cb,
|
&cb_called, 0, 0);
|
TEST_ASSERT(rc == 0);
|
TEST_ASSERT(!ble_os_test_misc_conn_exists(BLE_HS_CONN_HANDLE_NONE));
|
TEST_ASSERT(ble_gap_master_in_progress());
|
TEST_ASSERT(!cb_called);
|
|
/* Receive acks from the controller. */
|
TEST_ASSERT(!ble_os_test_misc_conn_exists(BLE_HS_CONN_HANDLE_NONE));
|
TEST_ASSERT(ble_gap_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_os_test_misc_conn_exists(BLE_HS_CONN_HANDLE_NONE));
|
TEST_ASSERT(ble_gap_master_in_progress());
|
TEST_ASSERT(!cb_called);
|
|
ble_hs_test_util_hci_ack_set(
|
ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE,
|
BLE_HCI_OCF_LE_SET_SCAN_ENABLE),
|
0);
|
|
/* Wait 250 more ms; verify scan completed. */
|
os_time_delay(250 * OS_TICKS_PER_SEC / 1000);
|
TEST_ASSERT(!ble_os_test_misc_conn_exists(BLE_HS_CONN_HANDLE_NONE));
|
TEST_ASSERT(!ble_gap_master_in_progress());
|
TEST_ASSERT(cb_called);
|
|
tu_restart();
|
}
|
|
TEST_CASE_SELF(ble_os_disc_test_case)
|
{
|
ble_os_test_misc_init();
|
|
os_task_init(&ble_os_test_task,
|
"ble_os_disc_test_task",
|
ble_os_disc_test_task_handler, NULL,
|
BLE_OS_TEST_TASK_PRIO, OS_WAIT_FOREVER, ble_os_test_stack,
|
OS_STACK_ALIGN(BLE_OS_TEST_STACK_SIZE));
|
|
os_start();
|
|
ble_hs_test_util_assert_mbufs_freed(NULL);
|
}
|
|
static int
|
ble_gap_terminate_cb(struct ble_gap_event *event, void *arg)
|
{
|
int *disconn_handle;
|
|
ble_os_test_gap_event_type = event->type;
|
|
if (event->type == BLE_GAP_EVENT_DISCONNECT) {
|
disconn_handle = arg;
|
*disconn_handle = event->disconnect.conn.conn_handle;
|
}
|
|
return 0;
|
}
|
|
static void
|
ble_gap_terminate_test_task_handler(void *arg)
|
{
|
struct ble_gap_conn_complete conn_evt;
|
ble_addr_t addr1 = { BLE_ADDR_PUBLIC, { 1, 2, 3, 4, 5, 6 }};
|
ble_addr_t addr2 = { BLE_ADDR_PUBLIC, { 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_hci_ack_set_startup();
|
|
/* Set the connect callback so we can verify that it gets called with the
|
* proper arguments.
|
*/
|
disconn_handle = 0;
|
|
/* Make sure there are no created connections and no connections in
|
* progress.
|
*/
|
TEST_ASSERT(!ble_os_test_misc_conn_exists(BLE_HS_CONN_HANDLE_NONE));
|
TEST_ASSERT(!ble_gap_master_in_progress());
|
|
/* Create two direct connections. */
|
ble_hs_test_util_connect(BLE_OWN_ADDR_PUBLIC,
|
&addr1, 0, NULL, ble_gap_terminate_cb,
|
&disconn_handle, 0);
|
/* ble_gap_rx_conn_complete() will send extra HCI command, need phony ack */
|
ble_hs_test_util_hci_ack_set(ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE,
|
BLE_HCI_OCF_LE_RD_REM_FEAT), 0);
|
memset(&conn_evt, 0, sizeof conn_evt);
|
conn_evt.status = BLE_ERR_SUCCESS;
|
conn_evt.connection_handle = 1;
|
memcpy(conn_evt.peer_addr, addr1.val, 6);
|
rc = ble_gap_rx_conn_complete(&conn_evt, 0);
|
TEST_ASSERT(rc == 0);
|
|
ble_hs_test_util_connect(BLE_OWN_ADDR_PUBLIC,
|
&addr2, 0, NULL, ble_gap_terminate_cb,
|
&disconn_handle, 0);
|
/* ble_gap_rx_conn_complete() will send extra HCI command, need phony ack */
|
ble_hs_test_util_hci_ack_set(ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE,
|
BLE_HCI_OCF_LE_RD_REM_FEAT), 0);
|
memset(&conn_evt, 0, sizeof conn_evt);
|
conn_evt.status = BLE_ERR_SUCCESS;
|
conn_evt.connection_handle = 2;
|
memcpy(conn_evt.peer_addr, addr2.val, 6);
|
rc = ble_gap_rx_conn_complete(&conn_evt, 0);
|
TEST_ASSERT(rc == 0);
|
|
TEST_ASSERT_FATAL(ble_os_test_misc_conn_exists(1));
|
TEST_ASSERT_FATAL(ble_os_test_misc_conn_exists(2));
|
|
/* Terminate the first one. */
|
rc = ble_hs_test_util_conn_terminate(1, 0);
|
TEST_ASSERT(rc == 0);
|
ble_hs_test_util_hci_rx_disconn_complete_event(1, 0, BLE_ERR_REM_USER_CONN_TERM);
|
TEST_ASSERT(ble_os_test_gap_event_type == BLE_GAP_EVENT_DISCONNECT);
|
TEST_ASSERT(disconn_handle == 1);
|
TEST_ASSERT_FATAL(!ble_os_test_misc_conn_exists(1));
|
TEST_ASSERT_FATAL(ble_os_test_misc_conn_exists(2));
|
|
/* Terminate the second one. */
|
rc = ble_hs_test_util_conn_terminate(2, 0);
|
TEST_ASSERT(rc == 0);
|
ble_hs_test_util_hci_rx_disconn_complete_event(2, 0, BLE_ERR_REM_USER_CONN_TERM);
|
TEST_ASSERT(ble_os_test_gap_event_type == BLE_GAP_EVENT_DISCONNECT);
|
TEST_ASSERT(disconn_handle == 2);
|
TEST_ASSERT_FATAL(!ble_os_test_misc_conn_exists(1));
|
TEST_ASSERT_FATAL(!ble_os_test_misc_conn_exists(2));
|
|
tu_restart();
|
}
|
|
static void
|
ble_os_test_app_task_handler(void *arg)
|
{
|
while (1) {
|
os_eventq_run(os_eventq_dflt_get());
|
}
|
}
|
|
TEST_CASE_SELF(ble_gap_terminate_test_case)
|
{
|
ble_os_test_misc_init();
|
|
os_task_init(&ble_os_test_task,
|
"ble_gap_terminate_test_task",
|
ble_gap_terminate_test_task_handler, NULL,
|
BLE_OS_TEST_TASK_PRIO, OS_WAIT_FOREVER, ble_os_test_stack,
|
OS_STACK_ALIGN(BLE_OS_TEST_STACK_SIZE));
|
|
os_start();
|
|
ble_hs_test_util_assert_mbufs_freed(NULL);
|
}
|
|
TEST_SUITE(ble_os_test_suite)
|
{
|
ble_os_disc_test_case();
|
ble_gap_direct_connect_test_case();
|
ble_gap_terminate_test_case();
|
}
|