diff options
author | JF <jf@codingfield.com> | 2020-04-26 10:25:59 +0200 |
---|---|---|
committer | JF <jf@codingfield.com> | 2020-04-26 10:25:59 +0200 |
commit | bdc10744fb338ae197692713a0b48a7ccc36f566 (patch) | |
tree | af7a8f2f16ddd2e5483758effec15c7683f6c453 /src/libs/mynewt-nimble/apps/blestress/src | |
parent | 032fad094c6411ad3ff4321ad61ceed95d7dc4ff (diff) |
Add Nimble in libs directory
Diffstat (limited to 'src/libs/mynewt-nimble/apps/blestress/src')
-rw-r--r-- | src/libs/mynewt-nimble/apps/blestress/src/main.c | 99 | ||||
-rw-r--r-- | src/libs/mynewt-nimble/apps/blestress/src/misc.c | 224 | ||||
-rw-r--r-- | src/libs/mynewt-nimble/apps/blestress/src/misc.h | 54 | ||||
-rw-r--r-- | src/libs/mynewt-nimble/apps/blestress/src/rx_stress.c | 1471 | ||||
-rw-r--r-- | src/libs/mynewt-nimble/apps/blestress/src/rx_stress.h | 53 | ||||
-rw-r--r-- | src/libs/mynewt-nimble/apps/blestress/src/stress.c | 389 | ||||
-rw-r--r-- | src/libs/mynewt-nimble/apps/blestress/src/stress.h | 375 | ||||
-rw-r--r-- | src/libs/mynewt-nimble/apps/blestress/src/stress_gatt.c | 155 | ||||
-rw-r--r-- | src/libs/mynewt-nimble/apps/blestress/src/stress_gatt.h | 54 | ||||
-rw-r--r-- | src/libs/mynewt-nimble/apps/blestress/src/tx_stress.c | 1671 | ||||
-rw-r--r-- | src/libs/mynewt-nimble/apps/blestress/src/tx_stress.h | 49 |
11 files changed, 4594 insertions, 0 deletions
diff --git a/src/libs/mynewt-nimble/apps/blestress/src/main.c b/src/libs/mynewt-nimble/apps/blestress/src/main.c new file mode 100644 index 00000000..ec28ed8a --- /dev/null +++ b/src/libs/mynewt-nimble/apps/blestress/src/main.c @@ -0,0 +1,99 @@ +/* + * 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 <assert.h> +#include <stdio.h> +#include "os/mynewt.h" +#include "config/config.h" +#include "bsp.h" +#include "hal/hal_gpio.h" + +/* BLE */ +#include "nimble/ble.h" +#include "host/ble_hs.h" +#include "host/util/util.h" +#include "services/gap/ble_svc_gap.h" + +/* Application-specified header. */ +#include "rx_stress.h" +#include "tx_stress.h" +#include "stress_gatt.h" + +static void +stress_test_on_reset(int reason) +{ + MODLOG_DFLT(ERROR, "Resetting state; reason=%d\n", reason); +} + +static void +stress_test_on_sync(void) +{ + int rc; + + /* Make sure we have proper identity address set (public preferred) */ + rc = ble_hs_util_ensure_addr(1); + assert(rc == 0); + +#if MYNEWT_VAL(BLE_STRESS_TEST_ROLE) + rx_stress_start_auto(); +#else + tx_stress_start_auto(); +#endif +} + +/** + * main + * + * The main task for the project. This function initializes the packages, + * then starts serving events from default event queue. + * + * @return int NOTE: this function should never return! + */ +int +main(void) +{ + int rc; + + sysinit(); + + ble_hs_cfg.reset_cb = stress_test_on_reset; + ble_hs_cfg.sync_cb = stress_test_on_sync; + ble_hs_cfg.store_status_cb = ble_store_util_status_rr; + + /* Please do not change name. Otherwise some tests could fail. */ + rc = ble_svc_gap_device_name_set("STRESS"); + assert(rc == 0); + + conf_load(); + + rc = gatt_svr_init(); + assert(rc == 0); + +#if MYNEWT_VAL(BLE_STRESS_TEST_ROLE) + /* RX device */ + ble_hs_cfg.gatts_register_cb = gatt_svr_register_cb; + hal_gpio_init_out(LED_2, 1); + hal_gpio_toggle(LED_2); +#endif + + while (1) { + os_eventq_run(os_eventq_dflt_get()); + } + return 0; +} diff --git a/src/libs/mynewt-nimble/apps/blestress/src/misc.c b/src/libs/mynewt-nimble/apps/blestress/src/misc.c new file mode 100644 index 00000000..bd71a871 --- /dev/null +++ b/src/libs/mynewt-nimble/apps/blestress/src/misc.c @@ -0,0 +1,224 @@ +/* + * 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 "misc.h" + +void +rand_bytes(uint8_t *data, int len) { + int i; + + for (i = 0; i < len; ++i) { + data[i] = (uint8_t) rand() % UINT8_MAX; + } +} + +/** + * Utility function to log an array of bytes. + */ +void +print_bytes(const uint8_t *bytes, int len) +{ + int i; + + for (i = 0; i < len; i++) { + MODLOG_DFLT(DEBUG, "%s0x%02x", i != 0 ? ":" : "", bytes[i]); + } +} + +void +print_addr(const void *addr) +{ + const uint8_t *u8p; + + u8p = addr; + MODLOG_DFLT(DEBUG, "%02x:%02x:%02x:%02x:%02x:%02x", + u8p[5], u8p[4], u8p[3], u8p[2], u8p[1], u8p[0]); +} + +void +print_mbuf(const struct os_mbuf *om) +{ + while (om != NULL) { + print_bytes(om->om_data, om->om_len); + om = SLIST_NEXT(om, om_next); + + if(om == NULL) { + return; + } + + /* Separate buf fields with colon to maintain continuity */ + MODLOG_DFLT(DEBUG, ":"); + } +} + +char * +addr_str(const void *addr) +{ + /* 6 bytes of MAC address * 2 signs for each byte in string + 5 colons to + * separate bytes + 1 byte for null-character appended by sprintf + */ + static char buf[6 * 2 + 5 + 1]; + const uint8_t *u8p; + + u8p = addr; + sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", + u8p[5], u8p[4], u8p[3], u8p[2], u8p[1], u8p[0]); + + return buf; +} + +void +print_uuid(const ble_uuid_t *uuid) +{ + char buf[BLE_UUID_STR_LEN]; + + MODLOG_DFLT(DEBUG, "%s", ble_uuid_to_str(uuid, buf)); +} + +/** + * Logs information about a connection to the console. + */ +void +print_conn_desc(const struct ble_gap_conn_desc *desc) +{ + MODLOG_DFLT(DEBUG, "handle=%d our_ota_addr_type=%d our_ota_addr=%s ", + desc->conn_handle, desc->our_ota_addr.type, + addr_str(desc->our_ota_addr.val)); + MODLOG_DFLT(DEBUG, "our_id_addr_type=%d our_id_addr=%s ", + desc->our_id_addr.type, addr_str(desc->our_id_addr.val)); + MODLOG_DFLT(DEBUG, "peer_ota_addr_type=%d peer_ota_addr=%s ", + desc->peer_ota_addr.type, addr_str(desc->peer_ota_addr.val)); + MODLOG_DFLT(DEBUG, "peer_id_addr_type=%d peer_id_addr=%s ", + desc->peer_id_addr.type, addr_str(desc->peer_id_addr.val)); + MODLOG_DFLT(DEBUG, "conn_itvl=%d conn_latency=%d supervision_timeout=%d " + "encrypted=%d authenticated=%d bonded=%d", + desc->conn_itvl, desc->conn_latency, + desc->supervision_timeout, + desc->sec_state.encrypted, + desc->sec_state.authenticated, + desc->sec_state.bonded); +} + +void +print_adv_fields(const struct ble_hs_adv_fields *fields) +{ + char s[BLE_HS_ADV_MAX_SZ]; + const uint8_t *u8p; + int i; + + if (fields->flags != 0) { + MODLOG_DFLT(DEBUG, " flags=0x%02x\n", fields->flags); + } + + if (fields->uuids16 != NULL) { + MODLOG_DFLT(DEBUG, " uuids16(%scomplete)=", + fields->uuids16_is_complete ? "" : "in"); + for (i = 0; i < fields->num_uuids16; i++) { + print_uuid(&fields->uuids16[i].u); + MODLOG_DFLT(DEBUG, " "); + } + MODLOG_DFLT(DEBUG, "\n"); + } + + if (fields->uuids32 != NULL) { + MODLOG_DFLT(DEBUG, " uuids32(%scomplete)=", + fields->uuids32_is_complete ? "" : "in"); + for (i = 0; i < fields->num_uuids32; i++) { + print_uuid(&fields->uuids32[i].u); + MODLOG_DFLT(DEBUG, " "); + } + MODLOG_DFLT(DEBUG, "\n"); + } + + if (fields->uuids128 != NULL) { + MODLOG_DFLT(DEBUG, " uuids128(%scomplete)=", + fields->uuids128_is_complete ? "" : "in"); + for (i = 0; i < fields->num_uuids128; i++) { + print_uuid(&fields->uuids128[i].u); + MODLOG_DFLT(DEBUG, " "); + } + MODLOG_DFLT(DEBUG, "\n"); + } + + if (fields->name != NULL) { + assert(fields->name_len < sizeof s - 1); + memcpy(s, fields->name, fields->name_len); + s[fields->name_len] = '\0'; + MODLOG_DFLT(DEBUG, " name(%scomplete)=%s\n", + fields->name_is_complete ? "" : "in", s); + } + + if (fields->tx_pwr_lvl_is_present) { + MODLOG_DFLT(DEBUG, " tx_pwr_lvl=%d\n", fields->tx_pwr_lvl); + } + + if (fields->slave_itvl_range != NULL) { + MODLOG_DFLT(DEBUG, " slave_itvl_range="); + print_bytes(fields->slave_itvl_range, BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN); + MODLOG_DFLT(DEBUG, "\n"); + } + + if (fields->svc_data_uuid16 != NULL) { + MODLOG_DFLT(DEBUG, " svc_data_uuid16="); + print_bytes(fields->svc_data_uuid16, fields->svc_data_uuid16_len); + MODLOG_DFLT(DEBUG, "\n"); + } + + if (fields->public_tgt_addr != NULL) { + MODLOG_DFLT(DEBUG, " public_tgt_addr="); + u8p = fields->public_tgt_addr; + for (i = 0; i < fields->num_public_tgt_addrs; i++) { + MODLOG_DFLT(DEBUG, "public_tgt_addr=%s ", addr_str(u8p)); + u8p += BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN; + } + MODLOG_DFLT(DEBUG, "\n"); + } + + if (fields->appearance_is_present) { + MODLOG_DFLT(DEBUG, " appearance=0x%04x\n", fields->appearance); + } + + if (fields->adv_itvl_is_present) { + MODLOG_DFLT(DEBUG, " adv_itvl=0x%04x\n", fields->adv_itvl); + } + + if (fields->svc_data_uuid32 != NULL) { + MODLOG_DFLT(DEBUG, " svc_data_uuid32="); + print_bytes(fields->svc_data_uuid32, fields->svc_data_uuid32_len); + MODLOG_DFLT(DEBUG, "\n"); + } + + if (fields->svc_data_uuid128 != NULL) { + MODLOG_DFLT(DEBUG, " svc_data_uuid128="); + print_bytes(fields->svc_data_uuid128, fields->svc_data_uuid128_len); + MODLOG_DFLT(DEBUG, "\n"); + } + + if (fields->uri != NULL) { + MODLOG_DFLT(DEBUG, " uri="); + print_bytes(fields->uri, fields->uri_len); + MODLOG_DFLT(DEBUG, "\n"); + } + + if (fields->mfg_data != NULL) { + MODLOG_DFLT(DEBUG, " mfg_data="); + print_bytes(fields->mfg_data, fields->mfg_data_len); + MODLOG_DFLT(DEBUG, "\n"); + } +} diff --git a/src/libs/mynewt-nimble/apps/blestress/src/misc.h b/src/libs/mynewt-nimble/apps/blestress/src/misc.h new file mode 100644 index 00000000..39e5e737 --- /dev/null +++ b/src/libs/mynewt-nimble/apps/blestress/src/misc.h @@ -0,0 +1,54 @@ +/* + * 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. + */ + +#ifndef BLE_TGT_MISC_H +#define BLE_TGT_MISC_H + +#include <assert.h> +#include <stdio.h> +#include <string.h> +#include "host/ble_hs.h" +#include "host/ble_uuid.h" +#include "host/ble_hs_adv.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void rand_bytes(uint8_t *data, int len); + +void print_bytes(const uint8_t *bytes, int len); + +void print_addr(const void *addr); + +void print_mbuf(const struct os_mbuf *om); + +char *addr_str(const void *addr); + +void print_uuid(const ble_uuid_t *uuid); + +void print_conn_desc(const struct ble_gap_conn_desc *desc); + +void print_adv_fields(const struct ble_hs_adv_fields *fields); + +#ifdef __cplusplus +} +#endif + +#endif //BLE_TGT_MISC_H diff --git a/src/libs/mynewt-nimble/apps/blestress/src/rx_stress.c b/src/libs/mynewt-nimble/apps/blestress/src/rx_stress.c new file mode 100644 index 00000000..a4253ce6 --- /dev/null +++ b/src/libs/mynewt-nimble/apps/blestress/src/rx_stress.c @@ -0,0 +1,1471 @@ +/* + * 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 <host/ble_gap.h> +#include "rx_stress.h" + +/* UUID128 of stress test use cases*/ +static uint8_t rx_stress_uuid128[STRESS_UUIDS_NUM][16]; + +static struct com_stress_test_ctx rx_stress_ctxD = { + .conn_handle = 0xffff, + .cur_test_id = 0, + .s6_rcv_adv_first = 0, + .s6_rcv_adv_suc = 0, +}; + +static struct com_stress_test_ctx *rx_stress_ctx = &rx_stress_ctxD; + +#define EXTENDED_ADVERT 0 +#define LEGACY_ADVERT 1 +/* Advertising instances ids */ +#define SWITCHER_INSTANCE 0 +#define TEST_INSTANCE 1 +/* Main test task priority. Set a high value so that the task does not + * interfere with event handling */ +#define RX_STRESS_MAIN_TASK_PRIO 0xf0 + +/* Advertising settings */ +struct rx_stress_adv_set { + uint8_t instance; + uint8_t *instance_uuid128; + uint8_t legacy_pdu; + ble_gap_event_fn *cb; + const uint8_t *pattern_data; + int pattern_len; +}; + +/* Define task stack and task object */ +#define RX_STRESS_MAIN_TASK_STACK_SIZE (2000) +static struct os_task rx_stress_main_task; +static os_stack_t rx_stress_main_task_stack[RX_STRESS_MAIN_TASK_STACK_SIZE]; +static struct os_sem rx_stress_main_sem; + +static void +rx_stress_on_test_finish(int test_num) +{ + console_printf("\033[0;32m\nStress test %d completed\033[0m\n", test_num); + os_sem_release(&rx_stress_main_sem); +} + +static int +rx_stress_adv_start(uint8_t instance) +{ + int rc; + + /* Resume advertising earlier configured instance */ + rc = ble_gap_ext_adv_start(instance, 0, 0); + assert (rc == 0 || rc == 2); + MODLOG_DFLT(INFO, "Instance %d started; rc: %d\n", instance, rc); + return rc; +} + +static int +rx_stress_adv_start_with_rand_addr(uint8_t instance) +{ + int rc; + ble_addr_t addr; + + ble_gap_ext_adv_stop(instance); + + rc = ble_hs_id_gen_rnd(1, &addr); + assert (rc == 0); + + /* Set random address for advertising instance */ + rc = ble_gap_ext_adv_set_addr(instance, &addr); + assert (rc == 0); + + return rx_stress_adv_start(instance); +} + +static void +rx_stress_simple_adv(struct rx_stress_adv_set *adv_set) +{ + uint8_t own_addr_type; + struct ble_gap_ext_adv_params params; + struct ble_hs_adv_fields fields; + struct os_mbuf *adv_data; + ble_addr_t addr; + const char *name; + int rc; + int pattern_len; + + /* Determine own address type */ + rc = ble_hs_id_infer_auto(0, &own_addr_type); + if (rc != 0) { + MODLOG_DFLT(ERROR, "\033[0;31mError determining own address type; " + "rc=%d\033[0m\n", rc); + return; + } + + /* Use defaults for non-set fields */ + memset(&fields, 0, sizeof fields); + /* General Discoverable and BrEdrNotSupported */ + fields.flags = BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP; + /* Set device name as instance name */ + name = ble_svc_gap_device_name(); + fields.name = (uint8_t *) name; + fields.name_len = strlen(name); + fields.name_is_complete = 1; + /* Set UUID 128 data service */ + fields.svc_data_uuid128 = adv_set->instance_uuid128; + fields.svc_data_uuid128_len = 16; + + /* Use defaults for non-set params */ + memset(¶ms, 0, sizeof(params)); + /* Set adv mode */ + if (adv_set->legacy_pdu == 1) { + params.connectable = 1; + params.scannable = 1; + } else if (adv_set->pattern_len < 255) { + params.connectable = 1; + } + + params.own_addr_type = own_addr_type; + params.primary_phy = BLE_HCI_LE_PHY_1M; + /* If legacy, this param will be lowered by API */ + params.secondary_phy = BLE_HCI_LE_PHY_2M; + params.sid = adv_set->instance; + params.legacy_pdu = adv_set->legacy_pdu; + + ble_gap_set_prefered_default_le_phy(TX_PHY_MASK, RX_PHY_MASK); + + rc = ble_gap_ext_adv_remove(adv_set->instance); + assert(rc == 0 || rc == BLE_HS_EALREADY); + + /* Configure instance with the params set */ + rc = ble_gap_ext_adv_configure(adv_set->instance, ¶ms, + NULL, adv_set->cb, NULL); + assert (rc == 0); + + if (own_addr_type == 0) { + memcpy(addr.val, MYNEWT_VAL(BLE_PUBLIC_DEV_ADDR), 6); + } else { + rc = ble_hs_id_gen_rnd(1, &addr); + assert (rc == 0); + + /* Set random address for advertising instance */ + rc = ble_gap_ext_adv_set_addr(adv_set->instance, &addr); + assert (rc == 0); + } + + /* Get mbuf for adv data */ + adv_data = os_msys_get_pkthdr(16, 0); + assert(adv_data != NULL); + + /* Fill mbuf with adv fields - structured data */ + rc = ble_hs_adv_set_fields_mbuf(&fields, adv_data); + + if (rc) { + os_mbuf_free_chain(adv_data); + assert(0); + } + + pattern_len = min(adv_set->pattern_len, + MYNEWT_VAL(BLE_EXT_ADV_MAX_SIZE) - adv_data->om_len); + + /* Append to mbuf pattern data - raw data */ + rc = os_mbuf_append(adv_data, adv_set->pattern_data, pattern_len); + + if (rc) { + os_mbuf_free_chain(adv_data); + assert(0); + } + + /* Include mbuf data in advertisement */ + rc = ble_gap_ext_adv_set_data(adv_set->instance, adv_data); + assert (rc == 0); + + /* Start advertising */ + rc = ble_gap_ext_adv_start(adv_set->instance, 0, 0); + assert (rc == 0); + + MODLOG_DFLT(INFO, "instance %u started\n", adv_set->instance); +} + +static int +rx_stress_0_gap_event(struct ble_gap_event *event, void *arg) +{ + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + /* A new connection was established or a connection attempt failed */ + if (event->connect.status == 0) { + MODLOG_DFLT(INFO, "\nConnection established; status=%d; num=%d\n", + event->connect.status, + ++rx_stress_ctx->con_stat[0].num); + + /* Stop test advert */ + ble_gap_ext_adv_stop(TEST_INSTANCE); + ble_gap_terminate(event->connect.conn_handle, + BLE_ERR_REM_USER_CONN_TERM); + } else { + /* Connection failed; resume advertising */ + MODLOG_DFLT(INFO, "Connection failed; status=%d ", + event->connect.status); + } + return 0; + case BLE_GAP_EVENT_DISCONNECT: + MODLOG_DFLT(INFO, "Disconnect; reason=%d \n", + event->disconnect.reason); + console_printf("\033[0;32mReceived signal to switch test\033[0m\n"); + /* Add token to semaphore. Main task will start next test. */ + os_sem_release(&rx_stress_main_sem); + + return 0; + default: + MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + return 0; + } +} + +static int +rx_stress_2_gap_event(struct ble_gap_event *event, void *arg) +{ + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + ++rx_stress_ctx->con_stat[2].attempts_num; + /* A new connection was established or a connection attempt failed. */ + if (event->connect.status == 0) { + MODLOG_DFLT(INFO, "\nConnection established; status=%d; num=%d\n", + event->connect.status, + ++rx_stress_ctx->con_stat[2].num); + } else { + /* Connection failed; resume advertising. */ + MODLOG_DFLT(INFO, "Connection failed; status=%d ", + event->connect.status); + + rx_stress_adv_start(TEST_INSTANCE); + } + return 0; + + case BLE_GAP_EVENT_DISCONNECT: + MODLOG_DFLT(INFO, "Disconnect; reason=%d \n", + event->disconnect.reason); + console_printf("\033[0;32m>\033[0m"); + if (rx_stress_ctx->con_stat[2].num >= MYNEWT_VAL(BLE_STRESS_REPEAT)) { + rx_stress_on_test_finish(2); + } else { + /* Connection terminated; resume advertising. */ + rx_stress_adv_start(TEST_INSTANCE); + } + return 0; + + default: + MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + return 0; + } +} + +static int +rx_stress_3_gap_event(struct ble_gap_event *event, void *arg) +{ + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + ++rx_stress_ctx->con_stat[3].attempts_num; + /* A new connection was established or a connection attempt failed. */ + if (event->connect.status == 0) { + MODLOG_DFLT(INFO, "\nConnection established; status=%d; num=%d\n", + event->connect.status, + ++rx_stress_ctx->con_stat[3].num); + } else { + /* Connection failed; resume advertising. */ + rx_stress_adv_start(TEST_INSTANCE); + } + return 0; + + case BLE_GAP_EVENT_DISCONNECT: + MODLOG_DFLT(INFO, "Disconnect; reason=%d \n", + event->disconnect.reason); + console_printf("\033[0;32m>\033[0m"); + if (rx_stress_ctx->con_stat[3].num >= MYNEWT_VAL(BLE_STRESS_REPEAT)) { + rx_stress_on_test_finish(3); + } else { + /* Connection terminated; resume advertising. */ + rx_stress_adv_start(TEST_INSTANCE); + } + return 0; + + default: + MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + return 0; + } +} + +static int +rx_stress_4_gap_event(struct ble_gap_event *event, void *arg) +{ + struct ble_gap_conn_desc desc; + int rc; + + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + ++rx_stress_ctx->con_stat[4].attempts_num; + /* A new connection was established or a connection attempt failed. */ + if (event->connect.status == 0) { + MODLOG_DFLT(INFO, "Connection established; status=%d; num=%d", + event->connect.status, + ++rx_stress_ctx->con_stat[4].num); + + /* Remember connection handler */ + rc = ble_gap_conn_find(event->connect.conn_handle, &desc); + assert(rc == 0); + rx_stress_ctx->conn_handle = event->connect.conn_handle; + } else { + /* Connection failed; resume advertising. */ + MODLOG_DFLT(INFO, "Connection failed; status=%d ", + event->connect.status); + rx_stress_adv_start(TEST_INSTANCE); + } + return 0; + + case BLE_GAP_EVENT_DISCONNECT: + MODLOG_DFLT(INFO, "Disconnect; reason=%d ", event->disconnect.reason); + if (rx_stress_ctx->con_stat[4].prms_upd_num >= + MYNEWT_VAL(BLE_STRESS_REPEAT)) { + rx_stress_on_test_finish(4); + } else { + /* Connection terminated; resume advertising. */ + rx_stress_adv_start(TEST_INSTANCE); + } + return 0; + + case BLE_GAP_EVENT_CONN_UPDATE: + if (event->conn_update.status != 0) { + MODLOG_DFLT(INFO, "Connection update failed\n"); + } else { + MODLOG_DFLT(INFO, "Connection updated; num=%d\n", + ++rx_stress_ctx->con_stat[4].prms_upd_num); + console_printf("\033[0;32m>\033[0m"); + } + + if (rx_stress_ctx->con_stat[4].prms_upd_num >= + MYNEWT_VAL(BLE_STRESS_REPEAT)) { + /* Test completed. */ + ble_gap_terminate(rx_stress_ctx->conn_handle, + BLE_ERR_REM_USER_CONN_TERM); + } + return 0; + + default: + MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + return 0; + } +} + +static int +rx_stress_5_con_update(void) +{ + int rc; + + /* With every next update at least one param must change. Otherwise no + * event occurs and test will not be continued */ + struct ble_gap_upd_params params = { + .itvl_min = BLE_GAP_INITIAL_CONN_ITVL_MIN, + .itvl_max = BLE_GAP_INITIAL_CONN_ITVL_MAX, + .latency = BLE_GAP_INITIAL_CONN_LATENCY, + /* So let's change e.g. timeout value. Put ...% 2 ? 1 : 2 to make sure + * that value won't grow significantly and will be different with every + * iteration. */ + .supervision_timeout = BLE_GAP_INITIAL_SUPERVISION_TIMEOUT + + (rx_stress_ctx->con_stat[5].prms_upd_num % 2 ? + 1 : 2), + .min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN, + .max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN, + }; + + rc = ble_gap_update_params(rx_stress_ctx->conn_handle, ¶ms); + + if (rc == BLE_HS_ENOTCONN) { + MODLOG_DFLT(INFO, "Device disconnected. Connection update failed\n"); + assert(0); + } + + if (rc != 0) { + MODLOG_DFLT(ERROR, "\033[0;31mError during connection update; " + "rc=%d\033[0m\n", rc); + assert(0); + } + + return rc; +} + +static int +rx_stress_5_gap_event(struct ble_gap_event *event, void *arg) +{ + struct ble_gap_conn_desc desc; + int rc; + + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + ++rx_stress_ctx->con_stat[5].attempts_num; + + /* A new connection was established or a connection attempt failed. */ + if (event->connect.status == 0) { + MODLOG_DFLT(INFO, "Connection established; status=%d; num=%d", + event->connect.status, + ++rx_stress_ctx->con_stat[5].num); + + /* Remember connection handler */ + rc = ble_gap_conn_find(event->connect.conn_handle, &desc); + assert(rc == 0); + rx_stress_ctx->conn_handle = event->connect.conn_handle; + + /* Update connection. */ + rc = rx_stress_5_con_update(); + assert(rc == 0); + } else { + /* Connection failed; resume advertising. */ + MODLOG_DFLT(INFO, "Connection failed; status=%d ", + event->connect.status); + rx_stress_adv_start(TEST_INSTANCE); + } + return 0; + + case BLE_GAP_EVENT_DISCONNECT: + MODLOG_DFLT(INFO, "Disconnect; reason=%d ", event->disconnect.reason); + if (rx_stress_ctx->con_stat[5].prms_upd_num >= + MYNEWT_VAL(BLE_STRESS_REPEAT)) { + rx_stress_on_test_finish(5); + } else { + /* Connection terminated; resume advertising. */ + rx_stress_adv_start(TEST_INSTANCE); + } + return 0; + + case BLE_GAP_EVENT_CONN_UPDATE: + if (event->conn_update.status != 0) { + MODLOG_DFLT(INFO, "Connection update failed\n"); + } else { + MODLOG_DFLT(INFO, "Connection updated; num=%d\n", + ++rx_stress_ctx->con_stat[5].prms_upd_num); + console_printf("\033[0;32m>\033[0m"); + } + + if (rx_stress_ctx->con_stat[5].prms_upd_num >= + MYNEWT_VAL(BLE_STRESS_REPEAT)) { + /* Test completed. */ + ble_gap_terminate(rx_stress_ctx->conn_handle, + BLE_ERR_REM_USER_CONN_TERM); + } else { + /* Update connection. */ + rc = rx_stress_5_con_update(); + assert(rc == 0); + } + return 0; + + default: + MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + return 0; + } +} + +static int +rx_stress_6_gap_event(struct ble_gap_event *event, void *arg) +{ + MODLOG_DFLT(INFO, "Event occurs=%d\n", event->type); + return 0; +} + +static int +rx_stress_7_gap_event(struct ble_gap_event *event, void *arg) +{ + struct ble_gap_conn_desc desc; + int rc; + + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + ++rx_stress_ctx->con_stat[7].attempts_num; + + /* A new connection was established or a connection attempt failed. */ + if (event->connect.status == 0) { + MODLOG_DFLT(INFO, "Connection established; status=%d; num=%d", + event->connect.status, + ++rx_stress_ctx->con_stat[7].num); + + /* Remember connection handler */ + rc = ble_gap_conn_find(event->connect.conn_handle, &desc); + assert(rc == 0); + rx_stress_ctx->conn_handle = event->connect.conn_handle; + } else { + /* Connection failed; resume advertising. */ + MODLOG_DFLT(INFO, "Connection failed; status=%d ", + event->connect.status); + rx_stress_adv_start(TEST_INSTANCE); + } + return 0; + + case BLE_GAP_EVENT_DISCONNECT: + MODLOG_DFLT(INFO, "Disconnect; reason=%d ", event->disconnect.reason); + if (rx_stress_ctx->con_stat[7].phy_upd_num >= + MYNEWT_VAL(BLE_STRESS_REPEAT)) { + rx_stress_on_test_finish(7); + } else { + /* Connection terminated; resume advertising. */ + rx_stress_adv_start(TEST_INSTANCE); + } + return 0; + + case BLE_GAP_EVENT_PHY_UPDATE_COMPLETE: + if (event->phy_updated.status != 0) { + MODLOG_DFLT(INFO, "PHY update failed\n"); + } else { + MODLOG_DFLT(INFO, "PHY updated; num=%d\n", + ++rx_stress_ctx->con_stat[7].phy_upd_num); + console_printf("\033[0;32m>\033[0m"); + } + + if (rx_stress_ctx->con_stat[7].phy_upd_num >= + MYNEWT_VAL(BLE_STRESS_REPEAT)) { + /* Test completed. */ + ble_gap_terminate(rx_stress_ctx->conn_handle, + BLE_ERR_REM_USER_CONN_TERM); + } + return 0; + + default: + MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + return 0; + } +} + +static int +rx_stress_8_con_update(void) +{ + int rc; + uint8_t tx_phys_mask; + uint8_t rx_phys_mask; + + ble_gap_read_le_phy(rx_stress_ctx->conn_handle, &tx_phys_mask, + &rx_phys_mask); + + /* With every next update at least one param must change */ + switch (rx_phys_mask) { + case BLE_GAP_LE_PHY_1M_MASK: + rx_phys_mask = BLE_GAP_LE_PHY_2M_MASK; + break; + case BLE_GAP_LE_PHY_2M_MASK: +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) + rx_phys_mask = BLE_GAP_LE_PHY_CODED_MASK; + break; + case BLE_GAP_LE_PHY_CODED_MASK: +#endif + rx_phys_mask = BLE_GAP_LE_PHY_1M_MASK; + break; + default: + rx_phys_mask = BLE_GAP_LE_PHY_1M_MASK; + break; + } + + switch (tx_phys_mask) { + case BLE_GAP_LE_PHY_1M_MASK: + tx_phys_mask = BLE_GAP_LE_PHY_2M_MASK; + break; + case BLE_GAP_LE_PHY_2M_MASK: +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) + tx_phys_mask = BLE_GAP_LE_PHY_CODED_MASK; + break; + case BLE_GAP_LE_PHY_CODED_MASK: +#endif + tx_phys_mask = BLE_GAP_LE_PHY_1M_MASK; + break; + default: + tx_phys_mask = BLE_GAP_LE_PHY_1M_MASK; + break; + } + + rc = ble_gap_set_prefered_le_phy(rx_stress_ctx->conn_handle, + tx_phys_mask, rx_phys_mask, 0); + + if (rc == BLE_HS_ENOTCONN) { + MODLOG_DFLT(INFO, "Device disconnected. Connection update failed\n"); + return rc; + } + + if (rc != 0) { + MODLOG_DFLT(ERROR, "\033[0;31mError during PHY update; " + "rc=%d\033[0m\n", rc); + } + + return rc; +} + +static int +rx_stress_8_gap_event(struct ble_gap_event *event, void *arg) +{ + struct ble_gap_conn_desc desc; + int rc; + + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + ++rx_stress_ctx->con_stat[8].attempts_num; + + /* A new connection was established or a connection attempt failed. */ + if (event->connect.status == 0) { + MODLOG_DFLT(INFO, "Connection established; status=%d; num=%d", + event->connect.status, + ++rx_stress_ctx->con_stat[8].num); + + /* Remember connection handler */ + rc = ble_gap_conn_find(event->connect.conn_handle, &desc); + assert(rc == 0); + rx_stress_ctx->conn_handle = event->connect.conn_handle; + + /* Update connection. */ + rc = rx_stress_8_con_update(); + assert(rc == 0); + } else { + /* Connection failed; resume advertising. */ + MODLOG_DFLT(INFO, "Connection failed; status=%d ", + event->connect.status); + rx_stress_adv_start(TEST_INSTANCE); + } + return 0; + + case BLE_GAP_EVENT_DISCONNECT: + MODLOG_DFLT(INFO, "Disconnect; reason=%d ", event->disconnect.reason); + if (rx_stress_ctx->con_stat[8].phy_upd_num >= + MYNEWT_VAL(BLE_STRESS_REPEAT)) { + rx_stress_on_test_finish(8); + } else { + /* Connection terminated; resume advertising. */ + rx_stress_adv_start(TEST_INSTANCE); + } + return 0; + + case BLE_GAP_EVENT_PHY_UPDATE_COMPLETE: + if (event->phy_updated.status != 0) { + MODLOG_DFLT(INFO, "PHY update failed\n"); + } else { + MODLOG_DFLT(INFO, "PHY updated; num=%d; rx:%d, tx:%d\n", + ++rx_stress_ctx->con_stat[8].phy_upd_num, + event->phy_updated.rx_phy, event->phy_updated.tx_phy); + console_printf("\033[0;32m>\033[0m"); + } + + if (rx_stress_ctx->con_stat[8].phy_upd_num >= + MYNEWT_VAL(BLE_STRESS_REPEAT)) { + /* Test completed. */ + ble_gap_terminate(rx_stress_ctx->conn_handle, + BLE_ERR_REM_USER_CONN_TERM); + } else { + /* Update connection. */ + rc = rx_stress_8_con_update(); + assert(rc == 0); + } + return 0; + + default: + MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + return 0; + } +} + +static int +rx_stress_9_gap_event(struct ble_gap_event *event, void *arg) +{ + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + ++rx_stress_ctx->con_stat[9].attempts_num; + + /* A new connection was established or a connection attempt failed. */ + if (event->connect.status == 0) { + MODLOG_DFLT(INFO, "Connection established; status=%d; num=%d", + event->connect.status, + ++rx_stress_ctx->con_stat[9].num); + console_printf("\033[0;32m>\033[0m"); + + /* Remember max number of established connections */ + if (rx_stress_ctx->con_stat[9].num > + rx_stress_ctx->con_stat[9].max_num) { + rx_stress_ctx->con_stat[9].max_num = rx_stress_ctx->con_stat[9].num; + } + } else { + /* Connection failed; resume advertising. */ + MODLOG_DFLT(INFO, "Connection failed; status=%d ", + event->connect.status); + } + return 0; + + case BLE_GAP_EVENT_DISCONNECT: + MODLOG_DFLT(INFO, "Disconnect; reason=%d ", event->disconnect.reason); + console_printf("\033[0;31mX\033[0m"); + MODLOG_DFLT(INFO, "Connections num: %d\n", + --rx_stress_ctx->con_stat[9].num); + + if (rx_stress_ctx->con_stat[9].num != 0 && + rx_stress_ctx->con_stat[9].num < + MYNEWT_VAL(BLE_MAX_CONNECTIONS) + 1) { + rx_stress_adv_start_with_rand_addr(TEST_INSTANCE); + } else { + /* When TX device has terminated all connections, stop advertising. */ + ble_gap_ext_adv_stop(TEST_INSTANCE); + rx_stress_on_test_finish(9); + } + return 0; + + case BLE_GAP_EVENT_ADV_COMPLETE: + /* Stop test when TX device has terminated all connections or + * number of connections has reached the max possible value. */ + if (rx_stress_ctx->con_stat[9].num != 0 && + rx_stress_ctx->con_stat[9].num < + MYNEWT_VAL(BLE_MAX_CONNECTIONS) + 1) { + rx_stress_adv_start_with_rand_addr(TEST_INSTANCE); + } + return 0; + + default: + MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + } + return 0; +} + +static void +tx_stress_10_l2cap_update_event(uint16_t conn_handle, int status, void *arg) +{ + if (status == 0) { + MODLOG_DFLT(INFO, "L2CAP params updated\n"); + } else { + MODLOG_DFLT(INFO, "L2CAP params update failed; rc=%d\n", status); + assert(0); + } +} + +static int +rx_stress_10_l2cap_event(struct ble_l2cap_event *event, void *arg) +{ + int rc; + struct os_mbuf *data_buf; + static int data_len = 1000; + static int send_cnt = 0; + static bool stalled = false; + struct ble_l2cap_chan_info chan_info; + + switch (event->type) { + case BLE_L2CAP_EVENT_COC_CONNECTED: + if (event->connect.status) { + MODLOG_DFLT(INFO, "LE COC error: %d\n", event->connect.status); + return 0; + } + + ble_l2cap_get_chan_info(event->connect.chan, &chan_info); + + MODLOG_DFLT(INFO, + "LE COC connected, conn: %d, chan: 0x%08lx, scid: 0x%04x, " + "dcid: 0x%04x, our_mtu: 0x%04x, peer_mtu: 0x%04x\n", + event->connect.conn_handle, + (uint32_t) event->connect.chan, + chan_info.scid, + chan_info.dcid, + chan_info.our_l2cap_mtu, + chan_info.peer_l2cap_mtu); + + struct ble_l2cap_sig_update_params params = { + .itvl_min = 0x0006,//BLE_GAP_INITIAL_CONN_ITVL_MIN + .itvl_max = 0x0006,//BLE_GAP_INITIAL_CONN_ITVL_MIN + .slave_latency = 0x0000, + .timeout_multiplier = 0x0100, + }; + + rc = ble_l2cap_sig_update(event->connect.conn_handle, ¶ms, + &tx_stress_10_l2cap_update_event, NULL); + assert(rc == 0); + return 0; + + case BLE_L2CAP_EVENT_COC_DISCONNECTED: + MODLOG_DFLT(INFO, "LE CoC disconnected, chan: 0x%08lx\n", + (uint32_t) event->disconnect.chan); + return 0; + + case BLE_L2CAP_EVENT_COC_ACCEPT: + stress_l2cap_coc_accept(event->accept.peer_sdu_size, + event->accept.chan); + return 0; + + case BLE_L2CAP_EVENT_COC_DATA_RECEIVED: + stress_l2cap_coc_recv(event->receive.chan, event->receive.sdu_rx); + + MODLOG_DFLT(INFO, "L2CAP server received data; num=%d\n", + ++rx_stress_ctx->rcv_num); + rx_stress_ctx->chan = event->receive.chan; + + /* In this use case, receiving any data by RX device L2CAP server means + * request from TX device to send data. */ + + /* Do not send if stalled on the last sending. */ + if (stalled) { + return 0; + } + break; + + case BLE_L2CAP_EVENT_COC_TX_UNSTALLED: + MODLOG_DFLT(INFO, "L2CAP unstalled event\n"); + + stalled = false; + + /* Send if was stalled on the last request to send. */ + if (rx_stress_ctx->rcv_num > send_cnt) { + break; + } + return 0; + + default: + MODLOG_DFLT(INFO, "Other L2CAP event occurs: %d\n", event->type); + return 0; + } + + /* Send pattern data */ + + /* Get mbuf for adv data */ + data_buf = os_msys_get_pkthdr(data_len, 0); + + MODLOG_DFLT(INFO, "Data buf %s\n", data_buf ? "OK" : "NOK"); + assert(data_buf != NULL); + + /* The first 2 bytes of data is the size of appended pattern data. */ + rc = os_mbuf_append(data_buf, (uint8_t[]) {data_len >> 8, data_len}, + 2); + if (rc) { + os_mbuf_free_chain(data_buf); + assert(0); + } + + /* Fill mbuf with the pattern */ + stress_fill_mbuf_with_pattern(data_buf, data_len); + + /* Send data */ + rc = ble_l2cap_send(rx_stress_ctx->chan, data_buf); + MODLOG_DFLT(INFO, "Return code=%d\n", rc); + if (rc) { + MODLOG_DFLT(INFO, "L2CAP stalled - waiting\n"); + stalled = true; + } + + MODLOG_DFLT(INFO, " %d, %d\n", ++send_cnt, data_len); + data_len += 500; + + return 0; +} + +static int +rx_stress_10_gap_event(struct ble_gap_event *event, void *arg) +{ + struct ble_gap_conn_desc out_desc; + + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + ++rx_stress_ctx->con_stat[10].attempts_num; + + /* A new connection was established or a connection attempt failed. */ + if (event->connect.status == 0) { + MODLOG_DFLT(INFO, "Connection established; status=%d; num=%d", + event->connect.status, + ++rx_stress_ctx->con_stat[10].num); + + ble_gap_conn_find(event->connect.conn_handle, &out_desc); + MODLOG_DFLT(INFO, "Address %s", + addr_str(out_desc.peer_id_addr.val)); + } else { + /* Connection failed; resume advertising. */ + MODLOG_DFLT(INFO, "Connection failed; status=%d ", + event->connect.status); + } + return 0; + + case BLE_GAP_EVENT_DISCONNECT: + MODLOG_DFLT(INFO, "Disconnect; reason=%d ", event->disconnect.reason); + rx_stress_ctx->completed[10] = true; + rx_stress_on_test_finish(10); + return 0; + + default: + MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + return 0; + } +} + +static int +rx_stress_11_gap_event(struct ble_gap_event *event, void *arg) +{ + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + ++rx_stress_ctx->con_stat[11].attempts_num; + /* A new connection was established or a connection attempt failed. */ + if (event->connect.status == 0) { + MODLOG_DFLT(INFO, "\nConnection established; status=%d; num=%d\n", + event->connect.status, + ++rx_stress_ctx->con_stat[11].num); + } else { + MODLOG_DFLT(INFO, "\033[0;31mError: connection attempt failed; " + "status=%d\033[0m\n", event->connect.status); + } + + ble_gap_terminate(event->connect.conn_handle, + BLE_ERR_REM_USER_CONN_TERM); + return 0; + + case BLE_GAP_EVENT_DISCONNECT: + MODLOG_DFLT(INFO, "Disconnect; reason=%d \n", + event->disconnect.reason); + console_printf("\033[0;32m>\033[0m"); + if (rx_stress_ctx->con_stat[11].num >= MYNEWT_VAL(BLE_STRESS_REPEAT)) { + rx_stress_on_test_finish(11); + } else { + /* Connection terminated; resume advertising. */ + rx_stress_adv_start(TEST_INSTANCE); + } + return 0; + + default: + MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + return 0; + } +} + +static int +rx_stress_12_gap_event(struct ble_gap_event *event, void *arg) +{ + int om_len = 10000; + struct os_mbuf *om; + int64_t us = 0; + int rc; + + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + /* A new connection was established or a connection attempt failed */ + if (event->connect.status == 0) { + MODLOG_DFLT(INFO, "\nConnection established; status=%d; num=%d\n", + event->connect.status, + ++rx_stress_ctx->con_stat[12].num); + rx_stress_ctx->conn_handle = event->connect.conn_handle; + + break; + } else { + /* Connection failed; resume advertising */ + MODLOG_DFLT(INFO, "Connection failed; status=%d ", + event->connect.status); + } + return 0; + + case BLE_GAP_EVENT_DISCONNECT: + MODLOG_DFLT(INFO, "Disconnect; reason=%d \n", + event->disconnect.reason); + + rx_stress_ctx->s12_notif_time = rx_stress_ctx->time_sum / + rx_stress_ctx->send_num; + + MODLOG_DFLT(INFO, "Average time: %d us\n", + rx_stress_ctx->s12_notif_time); + + rx_stress_on_test_finish(12); + return 0; + + case BLE_GAP_EVENT_NOTIFY_TX: + rx_stress_ctx->end_us = os_get_uptime_usec(); + MODLOG_DFLT(INFO, "Notify TX event\n"); + + if (!event->notify_tx.status) { + /* Send next only after previous indication is done */ + return 0; + } + assert(event->notify_tx.status == BLE_HS_EDONE); + + if (rx_stress_ctx->send_num++ >= MYNEWT_VAL(BLE_STRESS_REPEAT)) { + ble_gap_terminate(event->notify_tx.conn_handle, + BLE_ERR_REM_USER_CONN_TERM); + return 0; + } + + /* Time of data sending */ + us = rx_stress_ctx->end_us - rx_stress_ctx->begin_us; + console_printf("Indication time: %lld\n", us); + rx_stress_ctx->time_sum += us; + console_printf("\033[0;32m>\033[0m"); + break; + + default: + MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + return 0; + } + + /* Indicate data pattern */ + rx_stress_ctx->begin_us = os_get_uptime_usec(); + om = os_msys_get_pkthdr(om_len, 0); + stress_fill_mbuf_with_pattern(om, om_len); + rc = ble_gattc_indicate_custom(rx_stress_ctx->conn_handle, hrs_hrm_handle, + om); + assert(rc == 0); + return 0; +} + +static int +rx_stress_13_gap_event(struct ble_gap_event *event, void *arg) +{ + int rc; + struct os_mbuf *om = NULL; + + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + /* A new connection was established or a connection attempt failed */ + if (event->connect.status == 0) { + MODLOG_DFLT(INFO, "\nConnection established; status=%d; num=%d\n", + event->connect.status, + ++rx_stress_ctx->con_stat[13].num); + rx_stress_ctx->conn_handle = event->connect.conn_handle; + + rx_stress_ctx->begin_us = os_get_uptime_usec(); + break; + } else { + /* Connection failed; resume advertising */ + MODLOG_DFLT(INFO, "Connection failed; status=%d ", + event->connect.status); + assert(0); + } + return 0; + + case BLE_GAP_EVENT_DISCONNECT: + MODLOG_DFLT(INFO, "Disconnect; reason=%d \n", + event->disconnect.reason); + + rx_stress_ctx->time_sum = rx_stress_ctx->end_us - + rx_stress_ctx->begin_us; + + rx_stress_ctx->s13_notif_time = rx_stress_ctx->time_sum / + rx_stress_ctx->send_num; + + MODLOG_DFLT(INFO, "Average time: %lld us\n", + rx_stress_ctx->s13_notif_time); + rx_stress_on_test_finish(13); + return 0; + + case BLE_GAP_EVENT_NOTIFY_TX: + MODLOG_DFLT(INFO, "Notify TX event; num=%d\n", + ++rx_stress_ctx->send_num); + assert(event->notify_tx.status == 0); + + if (rx_stress_ctx->send_num >= MYNEWT_VAL(BLE_STRESS_REPEAT)) { + rx_stress_ctx->end_us = os_get_uptime_usec(); + ble_gap_terminate(event->connect.conn_handle, + BLE_ERR_REM_USER_CONN_TERM); + return 0; + } + break; + + default: + MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + return 0; + } + + om = ble_hs_mbuf_from_flat(test_6_pattern, 10); + rc = ble_gattc_notify_custom(rx_stress_ctx->conn_handle, + hrs_hrm_handle, om); + assert(rc == 0); + return 0; +} + +static int +rx_stress_14_gap_event(struct ble_gap_event *event, void *arg) +{ + int bytes_num = 10000; + static struct os_mbuf *om = NULL; + int rc; + + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + /* A new connection was established or a connection attempt failed */ + if (event->connect.status == 0) { + MODLOG_DFLT(INFO, "\nConnection established; status=%d; num=%d\n", + event->connect.status, + ++rx_stress_ctx->con_stat[14].num); + rx_stress_ctx->conn_handle = event->connect.conn_handle; + } else { + /* Connection failed; resume advertising */ + MODLOG_DFLT(INFO, "Connection failed; status=%d ", + event->connect.status); + assert(0); + } + return 0; + + case BLE_GAP_EVENT_DISCONNECT: + MODLOG_DFLT(INFO, "Disconnect; reason=%d \n", + event->disconnect.reason); + + rx_stress_ctx->s14_notif_time = rx_stress_ctx->time_sum / + rx_stress_ctx->send_num; + + MODLOG_DFLT(INFO, "Average time: %d us\n", + rx_stress_ctx->s14_notif_time); + + rx_stress_on_test_finish(14); + return 0; + + case BLE_GAP_EVENT_NOTIFY_TX: + MODLOG_DFLT(INFO, "Notify TX event\n"); + assert(event->notify_tx.status == 0); + return 0; + + case BLE_GAP_EVENT_SUBSCRIBE: + MODLOG_DFLT(INFO, "Subscribe event\n"); + + if (event->subscribe.cur_notify) { + MODLOG_DFLT(INFO, "Notification subscribed\n"); + + ++rx_stress_ctx->send_num; + + /* Notify data pattern */ + om = ble_hs_mbuf_from_flat(test_6_pattern, bytes_num); + + rc = ble_gattc_notify_custom(rx_stress_ctx->conn_handle, + hrs_hrm_handle, om); + assert(rc == 0); + + console_printf("\033[0;32m>\033[0m"); + } else if (event->subscribe.prev_notify) { + MODLOG_DFLT(INFO, "Notification unsubscribed\n"); + } else { + MODLOG_DFLT(INFO, "Other subscription\n"); + } + return 0; + + default: + MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + return 0; + } +} + +static int +rx_stress_15_gap_event(struct ble_gap_event *event, void *arg) +{ + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + ++rx_stress_ctx->con_stat[15].attempts_num; + /* A new connection was established or a connection attempt failed. */ + if (event->connect.status == 0) { + MODLOG_DFLT(INFO, "\nConnection established; status=%d; num=%d\n", + event->connect.status, + ++rx_stress_ctx->con_stat[15].num); + } else { + MODLOG_DFLT(INFO, "\033[0;31mError: connection attempt failed; " + "status=%d\033[0m\n", event->connect.status); + assert(0); + } + return 0; + + case BLE_GAP_EVENT_DISCONNECT: + MODLOG_DFLT(INFO, "Disconnect; reason=%d \n", + event->disconnect.reason); + console_printf("\033[0;32m>\033[0m"); + if (rx_stress_ctx->con_stat[15].num >= MYNEWT_VAL(BLE_STRESS_REPEAT)) { + rx_stress_on_test_finish(15); + } else { + /* Connection terminated; resume advertising. */ + rx_stress_adv_start(TEST_INSTANCE); + } + return 0; + + default: + MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + return 0; + } +} + +/* Advert settings for each test. */ +static struct rx_stress_adv_set rx_stress_adv_sets[] = { + { + .instance = SWITCHER_INSTANCE, + .instance_uuid128 = rx_stress_uuid128[0], + .legacy_pdu = LEGACY_ADVERT, + .cb = rx_stress_0_gap_event, + .pattern_data = NULL, + .pattern_len = 0, + }, + { + .instance = SWITCHER_INSTANCE, + .instance_uuid128 = rx_stress_uuid128[0], + .legacy_pdu = LEGACY_ADVERT, + .cb = rx_stress_0_gap_event, + .pattern_data = NULL, + .pattern_len = 0, + }, + { + .instance = TEST_INSTANCE, + .instance_uuid128 = rx_stress_uuid128[2], + .legacy_pdu = LEGACY_ADVERT, + .cb = rx_stress_2_gap_event, + .pattern_data = NULL, + .pattern_len = 0, + }, + { + .instance = TEST_INSTANCE, + .instance_uuid128 = rx_stress_uuid128[3], + .legacy_pdu = EXTENDED_ADVERT, + .cb = rx_stress_3_gap_event, + .pattern_data = NULL, + .pattern_len = 0, + }, + { + .instance = TEST_INSTANCE, + .instance_uuid128 = rx_stress_uuid128[4], + .legacy_pdu = LEGACY_ADVERT, + .cb = rx_stress_4_gap_event, + .pattern_data = NULL, + .pattern_len = 0, + }, + { + .instance = TEST_INSTANCE, + .instance_uuid128 = rx_stress_uuid128[5], + .legacy_pdu = LEGACY_ADVERT, + .cb = rx_stress_5_gap_event, + .pattern_data = NULL, + .pattern_len = 0, + }, + { + .instance = TEST_INSTANCE, + .instance_uuid128 = rx_stress_uuid128[6], + .legacy_pdu = EXTENDED_ADVERT, + .cb = rx_stress_6_gap_event, + .pattern_data = test_6_pattern, + .pattern_len = 1640, + }, + { + .instance = TEST_INSTANCE, + .instance_uuid128 = rx_stress_uuid128[7], + .legacy_pdu = EXTENDED_ADVERT, + .cb = rx_stress_7_gap_event, + .pattern_data = NULL, + .pattern_len = 0, + }, + { + .instance = TEST_INSTANCE, + .instance_uuid128 = rx_stress_uuid128[8], + .legacy_pdu = EXTENDED_ADVERT, + .cb = rx_stress_8_gap_event, + .pattern_data = NULL, + .pattern_len = 0, + }, + { + .instance = TEST_INSTANCE, + .instance_uuid128 = rx_stress_uuid128[9], + .legacy_pdu = EXTENDED_ADVERT, + .cb = rx_stress_9_gap_event, + .pattern_data = NULL, + .pattern_len = 0, + }, + { + .instance = TEST_INSTANCE, + .instance_uuid128 = rx_stress_uuid128[10], + .legacy_pdu = EXTENDED_ADVERT, + .cb = rx_stress_10_gap_event, + .pattern_data = NULL, + .pattern_len = 0, + }, + { + .instance = TEST_INSTANCE, + .instance_uuid128 = rx_stress_uuid128[11], + .legacy_pdu = EXTENDED_ADVERT, + .cb = rx_stress_11_gap_event, + .pattern_data = NULL, + .pattern_len = 0, + }, + { + .instance = TEST_INSTANCE, + .instance_uuid128 = rx_stress_uuid128[12], + .legacy_pdu = EXTENDED_ADVERT, + .cb = rx_stress_12_gap_event, + .pattern_data = NULL, + .pattern_len = 0, + }, + { + .instance = TEST_INSTANCE, + .instance_uuid128 = rx_stress_uuid128[13], + .legacy_pdu = EXTENDED_ADVERT, + .cb = rx_stress_13_gap_event, + .pattern_data = NULL, + .pattern_len = 0, + }, + { + .instance = TEST_INSTANCE, + .instance_uuid128 = rx_stress_uuid128[14], + .legacy_pdu = EXTENDED_ADVERT, + .cb = rx_stress_14_gap_event, + .pattern_data = NULL, + .pattern_len = 0, + }, + { + .instance = TEST_INSTANCE, + .instance_uuid128 = rx_stress_uuid128[15], + .legacy_pdu = EXTENDED_ADVERT, + .cb = rx_stress_15_gap_event, + .pattern_data = NULL, + .pattern_len = 0, + }, +}; + +static void +rx_stress_start(int test_num) +{ + int rc; + + /* Init semaphore with 0 tokens. */ + os_sem_init(&rx_stress_main_sem, 0); + + console_printf("\033[1;36mStart test num %d - ", test_num); + + /* Start test. */ + switch (test_num) { + case 2: + console_printf("Stress Connect/Disconnect legacy\033[0m\n"); + rx_stress_simple_adv(&rx_stress_adv_sets[2]); + break; + case 3: + console_printf("Stress Connect/Disconnect ext adv\033[0m\n"); + rx_stress_simple_adv(&rx_stress_adv_sets[3]); + break; + case 4: + console_printf("Stress connection params update (TX)\033[0m\n"); + rx_stress_simple_adv(&rx_stress_adv_sets[4]); + break; + case 5: + console_printf("Stress connection params update (RX)\033[0m\n"); + rx_stress_simple_adv(&rx_stress_adv_sets[5]); + break; + case 6: + /* Start SWITCHER advert that gives possibility to remotely start + * next test advert */ + console_printf("Stress Scan\033[0m\n"); + rx_stress_simple_adv(&rx_stress_adv_sets[0]); + rx_stress_simple_adv(&rx_stress_adv_sets[6]); + break; + case 7: + console_printf("Stress PHY Update (TX)\033[0m\n"); + rx_stress_simple_adv(&rx_stress_adv_sets[7]); + break; + case 8: + console_printf("Stress PHY Update (RX)\033[0m\n"); + rx_stress_simple_adv(&rx_stress_adv_sets[8]); + break; + case 9: + console_printf("Stress multi connection\033[0m\n"); + rx_stress_simple_adv(&rx_stress_adv_sets[9]); + break; + case 10: + console_printf("Stress L2CAP send\033[0m\n"); + rc = ble_l2cap_create_server(1, STRESS_COC_MTU, + rx_stress_10_l2cap_event, NULL); + assert(rc == 0); + rx_stress_simple_adv(&rx_stress_adv_sets[10]); + break; + case 11: + console_printf("Stress Advertise/Connect/Disconnect\033[0m\n"); + rx_stress_simple_adv(&rx_stress_adv_sets[11]); + break; + case 12: + console_printf("Stress GATT indication\033[0m\n"); + rx_stress_simple_adv(&rx_stress_adv_sets[12]); + break; + case 13: + console_printf("Stress GATT notification\033[0m\n"); + rx_stress_simple_adv(&rx_stress_adv_sets[13]); + break; + case 14: + console_printf("Stress GATT Subscribe/Notify/Unsubscribe\033[0m\n"); + rx_stress_simple_adv(&rx_stress_adv_sets[14]); + break; + case 15: + console_printf("Stress Connect/Send/Disconnect\033[0m\n"); + rx_stress_simple_adv(&rx_stress_adv_sets[15]); + break; + default: + console_printf("\033[0;31mFound test, but do not know how to perform." + "\033[0m\n"); + assert(0); + } + + /* Wait for the test to finish. Then 1 token will be released + * allowing to pass through semaphore. */ + os_sem_pend(&rx_stress_main_sem, OS_TIMEOUT_NEVER); + + ble_gap_ext_adv_stop(SWITCHER_INSTANCE); + + stress_clear_ctx_reusable_var(rx_stress_ctx); +} + +static void +stress_uuid_init() +{ + uint8_t i; + + for (i = 0; i < STRESS_UUIDS_NUM; ++i) { + /* Fill all 16 bytes of UUID128 */ + rx_stress_uuid128[i][0] = 0xC0; + rx_stress_uuid128[i][1] = 0xDE; + rx_stress_uuid128[i][2] = i; + memcpy(&rx_stress_uuid128[i][3], MYNEWT_VAL(BLE_STRESS_UUID_BASE), 13); + } +} + +static void +rx_stress_read_command_cb(void) +{ + console_printf("Start testing\n"); + os_sem_release(&rx_stress_main_sem); +} + +static void +rx_stress_main_task_fn(void *arg) +{ + int i; + + stress_uuid_init(); + + console_printf("\033[1;36mRX device\033[0m\n"); + console_printf("Press ENTER to start: \n"); + console_init(&rx_stress_read_command_cb); + + /* Waite for pressing ENTER in console */ + os_sem_pend(&rx_stress_main_sem, OS_TIMEOUT_NEVER); + + /* Standard tests perform */ + for (i = 11; i < STRESS_UUIDS_NUM; ++i) { + if (i == 7 || i == 8 || i == 13) { + /* 7,8: PHY update tests cause that the device during the next test + * will stuck somewhere and will reset. Skip them for now. + * 13: Should work after fixing ble_gattc_notify_custom (nimble issue on GitHub)*/ + continue; + } + /* Start test. */ + rx_stress_start(i); + } + + /* Print tests results */ + com_stress_print_report(rx_stress_ctx); + + /* Task should never return */ + while (1) { + } +} + +void +rx_stress_start_auto() +{ + /* Start task that will run all stress tests one by one. */ + os_task_init(&rx_stress_main_task, "rx_stress_main_task", + rx_stress_main_task_fn, NULL, RX_STRESS_MAIN_TASK_PRIO, + OS_WAIT_FOREVER, rx_stress_main_task_stack, + RX_STRESS_MAIN_TASK_STACK_SIZE); +} diff --git a/src/libs/mynewt-nimble/apps/blestress/src/rx_stress.h b/src/libs/mynewt-nimble/apps/blestress/src/rx_stress.h new file mode 100644 index 00000000..62f84117 --- /dev/null +++ b/src/libs/mynewt-nimble/apps/blestress/src/rx_stress.h @@ -0,0 +1,53 @@ +/* + * 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. + */ + +#ifndef _BLE_STRESS_RX_H +#define _BLE_STRESS_RX_H + +#include <assert.h> +#include <string.h> +#include <console/console.h> +#include <errno.h> +#include <nrfx/hal/nrf_aar.h> + +/* BLE */ +#include "nimble/ble.h" +#include "host/ble_hs.h" +#include "services/gap/ble_svc_gap.h" +#include "host/ble_gap.h" +#include <host/ble_l2cap.h> + +#include "misc.h" +#include "stress.h" +#include "stress_gatt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Executes stress tests one by one. + */ +void rx_stress_start_auto(); + +#ifdef __cplusplus +} +#endif + +#endif //_BLE_STRESS_RX_H diff --git a/src/libs/mynewt-nimble/apps/blestress/src/stress.c b/src/libs/mynewt-nimble/apps/blestress/src/stress.c new file mode 100644 index 00000000..6f5badf0 --- /dev/null +++ b/src/libs/mynewt-nimble/apps/blestress/src/stress.c @@ -0,0 +1,389 @@ +/* + * 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 "stress.h" + +void +com_stress_print_report(const struct com_stress_test_ctx *test_ctxs) +{ + console_printf("\033[0;32mAll tests completed\033[0m\n"); + console_printf("Tests results:\n"); + + console_printf( + "\033[0;33mUse case 1 - Stress Connect -> Connect Cancel: \n\033[0m"); + console_printf("Con attempts = %d\n", test_ctxs->con_stat[1].attempts_num); + console_printf("Con success = %d\n", test_ctxs->con_stat[1].num); + + console_printf( + "\033[0;33mUse case 2 - Stress Connect/Disconnect legacy: \n\033[0m"); + console_printf("Con attempts = %d\n", test_ctxs->con_stat[2].attempts_num); + console_printf("Con success = %d\n", test_ctxs->con_stat[2].num); + + console_printf( + "\033[0;33mUse case 3 - Stress Connect/Disconnect ext adv: \n\033[0m"); + console_printf("Con attempts = %d\n", test_ctxs->con_stat[3].attempts_num); + console_printf("Con success = %d\n", test_ctxs->con_stat[3].num); + + console_printf( + "\033[0;33mUse case 4 - Stress connection params update (TX): \n\033[0m"); + console_printf("Params updates = %d\n", + test_ctxs->con_stat[4].prms_upd_num); + + console_printf( + "\033[0;33mUse case 5 - Stress connection params update (RX): \n\033[0m"); + console_printf("Params updates = %d\n", + test_ctxs->con_stat[5].prms_upd_num); + + console_printf("\033[0;33mUse case 6 - Stress Scan: \n\033[0m"); + console_printf("Received first packets = %d\n", + test_ctxs->s6_rcv_adv_first); + console_printf("Received all packets = %d\n", test_ctxs->s6_rcv_adv_suc); + + console_printf("\033[0;33mUse case 7 - Stress PHY Update (TX): \n\033[0m"); + console_printf("PHY updates = %d\n", test_ctxs->con_stat[7].phy_upd_num); + + console_printf("\033[0;33mUse case 8 - Stress PHY Update (RX): \n\033[0m"); + console_printf("PHY updates = %d\n", test_ctxs->con_stat[8].phy_upd_num); + + console_printf( + "\033[0;33mUse case 9 - Stress multi connection: \n\033[0m"); + console_printf("Max reached num of connections = %d\n", + test_ctxs->con_stat[9].max_num); + + console_printf("\033[0;33mUse case 10 - Stress L2CAP send: \n\033[0m"); + console_printf("Average bit rate = %d\n", test_ctxs->s10_bit_rate); + console_printf("Max received MTU = %lld\n", test_ctxs->s10_max_mtu); + + console_printf("\033[0;33mUse case 11 - " + "Stress Advertise/Connect/Continue adv \n\033[0m"); +// console_printf(" = %d\n",); + + console_printf("\033[0;33mUse case 12 - " + "Stress GATT indication: \n\033[0m"); + console_printf("Average bit rate = %d\n", test_ctxs->s12_notif_time); + + console_printf("\033[0;33mUse case 13 - " + "Stress GATT notification: \n\033[0m"); + console_printf("Average time = %d\n", test_ctxs->s13_notif_time); + + console_printf("\033[0;33mUse case 14 - " + "Stress GATT Subscribe/Notify/Unsubscribe: \n\033[0m"); + console_printf("Average time = %d\n", test_ctxs->s14_notif_time); + + console_printf("\033[0;33mUse case 15 - " + "Stress Connect/Send/Disconnect: \n\033[0m"); + console_printf("Con num = %d\n", test_ctxs->con_stat[15].num); +} + +void +stress_clear_ctx_reusable_var(struct com_stress_test_ctx *ctx) +{ + ctx->cur_test_id = 0; + ctx->dev_addr.type = 0; + ctx->dev_addr.type = 0; + ctx->conn_handle = 0; + ctx->chan = 0; + ctx->rcv_data_bytes = 0; + ctx->rcv_num = 0; + ctx->send_num = 0; + ctx->begin_us = 0; + ctx->end_us = 0; + ctx->time_sum = 0; + ctx->bytes_sum = 0; + ctx->timeout_flag = 0; + ctx->rcv_data_flag = 0; +} + +int +stress_fill_mbuf_with_pattern(struct os_mbuf *om, uint16_t len) +{ + int rc, i, mul, rest; + + mul = len / STRESS_PAT_LEN; + rest = len % STRESS_PAT_LEN; + + for (i = 0; i < mul; ++i) { + rc = os_mbuf_append(om, &test_6_pattern[29], STRESS_PAT_LEN); + + if (rc) { + os_mbuf_free_chain(om); + assert(0); + } + } + + rc = os_mbuf_append(om, &test_6_pattern[29], rest); + + if (rc) { + os_mbuf_free_chain(om); + assert(0); + } + + return rc; +} + +void +stress_l2cap_coc_recv(struct ble_l2cap_chan *chan, struct os_mbuf *sdu) +{ + int rc; + console_printf("LE CoC SDU received, chan: 0x%08lx, data len %d\n", + (uint32_t) chan, OS_MBUF_PKTLEN(sdu)); + + rc = os_mbuf_free_chain(sdu); + assert(rc == 0); + + /* Get buffer for data chain */ + sdu = os_msys_get_pkthdr(STRESS_COC_MTU, 0); + assert(sdu != NULL); + + /* Receive data chain */ + rc = ble_l2cap_recv_ready(chan, sdu); + assert(rc == 0); +} + +void +stress_l2cap_coc_accept(uint16_t peer_mtu, struct ble_l2cap_chan *chan) +{ + struct os_mbuf *sdu_rx; + int rc; + + console_printf("LE CoC accepting, chan: 0x%08lx, peer_mtu %d\n", + (uint32_t) chan, peer_mtu); + + sdu_rx = os_msys_get_pkthdr(STRESS_COC_MTU, 0); + assert(sdu_rx != NULL); + + rc = ble_l2cap_recv_ready(chan, sdu_rx); + assert(rc == 0); +} + +void +stress_start_timer(uint32_t timeout_ms, os_event_fn *ev_cb) +{ + int rc; + os_callout_stop(&stress_timer_callout); + + os_callout_init(&stress_timer_callout, os_eventq_dflt_get(), ev_cb, NULL); + + rc = os_callout_reset(&stress_timer_callout, + os_time_ms_to_ticks32(timeout_ms)); + + assert(rc == 0); +} + +int64_t +stress_calc_bit_rate(int64_t us, int64_t bytes_num) +{ + int bit_rate; + + /* Multiply by 1000000 so you don't lose accuracy */ + bit_rate = 1000000 * bytes_num / us; + + return bit_rate; +} + +static int +stress_disc_dsc_fn(uint16_t conn_handle, + const struct ble_gatt_error *error, + uint16_t chr_val_handle, + const struct ble_gatt_dsc *dsc, + void *arg) +{ + struct stress_gatt_search_ctx *search_ctx; + static bool found = false; + + search_ctx = (struct stress_gatt_search_ctx *) arg; + + if (error->status == 0) { + if (!ble_uuid_cmp(&dsc->uuid.u, &search_ctx->dsc_uuid.u) && !found) { + MODLOG_DFLT(INFO, "Found chr descriptor\n"); + search_ctx->dsc_handle = dsc->handle; + MODLOG_DFLT(INFO, "uuid=%#06x; handle=%#06x", dsc->uuid.u16.value, + dsc->handle); + found = true; + } + return 0; + } + + if (error->status == BLE_HS_EDONE) { + MODLOG_DFLT(INFO, "Done descriptor discovery\n"); + + if (found) { + found = false; + search_ctx->disc_end_fn(search_ctx); + return 0; + } + + MODLOG_DFLT(ERROR, "\033[0;31mDid not find particular descriptor" + "\033[0m\n"); + return 0; + } + + MODLOG_DFLT(ERROR, "\033[0;31mError during descriptor discovery" + "\033[0m\n"); + assert(0); + return 0; +} + +static int +stress_disc_chr_fn(uint16_t conn_handle, + const struct ble_gatt_error *error, + const struct ble_gatt_chr *chr, void *arg) +{ + int rc; + struct stress_gatt_search_ctx *search_ctx; + static bool found = false; + + search_ctx = (struct stress_gatt_search_ctx *) arg; + + if (error->status == 0) { + MODLOG_DFLT(INFO, "Found characteristic\n"); + search_ctx->chr_start_handle = chr->val_handle; + found = true; + return 0; + } + + if (error->status == BLE_HS_EDONE) { + MODLOG_DFLT(INFO, "Done characteristic discovery\n"); + + if (found) { + found = false; + + if (search_ctx->search_goal == STRESS_FIND_CHR) { + search_ctx->disc_end_fn(search_ctx); + return 0; + } + + rc = ble_gattc_disc_all_dscs(conn_handle, + search_ctx->chr_start_handle, + search_ctx->srv_end_handle, + &stress_disc_dsc_fn, search_ctx); + assert(rc == 0); + return 0; + } + + MODLOG_DFLT(ERROR, "\033[0;31mDid not find particular " + "characteristic\033[0m\n"); + return 0; + } + + MODLOG_DFLT(ERROR, + "\033[0;31mError during characteristic discovery\033[0m\n"); + assert(0); + return 0; +} + +static int +stress_disc_svc_fn(uint16_t conn_handle, const struct ble_gatt_error *error, + const struct ble_gatt_svc *service, void *arg) +{ + int rc; + struct stress_gatt_search_ctx *search_ctx = NULL; + static bool found = false; + + search_ctx = (struct stress_gatt_search_ctx *) arg; + + if (error->status == 0) { + MODLOG_DFLT(INFO, "Found service\n"); + search_ctx->srv_start_handle = service->start_handle; + search_ctx->srv_end_handle = service->end_handle; + found = true; + return 0; + } + + if (error->status == BLE_HS_EDONE) { + MODLOG_DFLT(INFO, "Done service discovery\n"); + + if (found) { + found = false; + if (search_ctx->search_goal == STRESS_FIND_SRV) { + search_ctx->disc_end_fn(search_ctx); + return 0; + } + + rc = ble_gattc_disc_chrs_by_uuid(conn_handle, + search_ctx->srv_start_handle, + search_ctx->srv_end_handle, + &search_ctx->chr_uuid.u, + &stress_disc_chr_fn, + search_ctx); + MODLOG_DFLT(INFO, "rc=%d\n", rc); + assert(rc == 0); + return 0; + } + + MODLOG_DFLT(ERROR, + "\033[0;31mDid not find particular service\033[0m\n"); + return 0; + } + + MODLOG_DFLT(ERROR, "\033[0;31mError during service discovery\033[0m\n"); + assert(0); + return 0; +} + +static void +stress_gatt_find_handle(uint16_t conn_handle, const ble_uuid_t *srv_uuid, + const ble_uuid_t *chr_uuid, const ble_uuid_t *dsc_uuid, + stress_gatt_disc_end_fn *disc_end_fn, + uint8_t search_goal) +{ + static struct stress_gatt_search_ctx search_ctx; + int rc; + + search_ctx.conn_handle = conn_handle; + ble_uuid_copy((ble_uuid_any_t *) &search_ctx.srv_uuid, srv_uuid); + ble_uuid_copy((ble_uuid_any_t *) &search_ctx.chr_uuid, chr_uuid); + ble_uuid_copy((ble_uuid_any_t *) &search_ctx.dsc_uuid, dsc_uuid); + search_ctx.disc_end_fn = disc_end_fn; + search_ctx.search_goal = search_goal; + search_ctx.srv_start_handle = 0; + search_ctx.srv_end_handle = 0; + search_ctx.chr_start_handle = 0; + search_ctx.dsc_handle = 0; + + rc = ble_gattc_disc_svc_by_uuid(conn_handle, srv_uuid, &stress_disc_svc_fn, + &search_ctx); + assert(rc == 0); +} + +void +stress_find_svc_handle(uint16_t conn_handle, const ble_uuid_t *srv_uuid, + stress_gatt_disc_end_fn *disc_end_fn) +{ + stress_gatt_find_handle(conn_handle, srv_uuid, NULL, NULL, disc_end_fn, + STRESS_FIND_SRV); +} + +void +stress_find_chr_handle(uint16_t conn_handle, const ble_uuid_t *srv_uuid, + const ble_uuid_t *chr_uuid, + stress_gatt_disc_end_fn *disc_end_fn) +{ + stress_gatt_find_handle(conn_handle, srv_uuid, chr_uuid, NULL, disc_end_fn, + STRESS_FIND_CHR); +} + +void +stress_find_dsc_handle(uint16_t conn_handle, const ble_uuid_t *srv_uuid, + const ble_uuid_t *chr_uuid, const ble_uuid_t *dsc_uuid, + stress_gatt_disc_end_fn *disc_end_fn) +{ + stress_gatt_find_handle(conn_handle, srv_uuid, chr_uuid, dsc_uuid, + disc_end_fn, STRESS_FIND_DSC); +} diff --git a/src/libs/mynewt-nimble/apps/blestress/src/stress.h b/src/libs/mynewt-nimble/apps/blestress/src/stress.h new file mode 100644 index 00000000..91ab4f47 --- /dev/null +++ b/src/libs/mynewt-nimble/apps/blestress/src/stress.h @@ -0,0 +1,375 @@ +/* + * 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. + */ + +#ifndef BLE_TGT_STRESS_H +#define BLE_TGT_STRESS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <nimble/ble.h> +#include <modlog/modlog.h> +#include <os/mynewt.h> +#include <console/console.h> +#include <host/ble_l2cap.h> +#include <host/ble_gatt.h> +#include <host/ble_gap.h> +#include <assert.h> + +#define STRESS_UUIDS_NUM (16) + +/* No preferred PHY */ +#define TX_PHY_MASK 0 +#define RX_PHY_MASK 0 +/* L2CAP SDU */ +#define STRESS_COC_MTU (64000) + +#define STRESS_FIND_SRV 1 +#define STRESS_FIND_CHR 2 +#define STRESS_FIND_DSC 3 + +struct os_callout stress_timer_callout; +struct stress_gatt_search_ctx; +typedef void stress_gatt_disc_end_fn(struct stress_gatt_search_ctx *search_ctx); + +struct stress_gatt_search_ctx { + /* Connection handle */ + uint16_t conn_handle; + + /* Wanted service uuid */ + ble_uuid16_t srv_uuid; + + /* Wanted characteristic uuid */ + ble_uuid16_t chr_uuid; + + /* Wanted descriptor uuid */ + ble_uuid16_t dsc_uuid; + + /* Search goal: 1 - service, 2 - characteristic, 3 - descriptor */ + uint8_t search_goal; + + /* Callback after reaching the goal */ + stress_gatt_disc_end_fn *disc_end_fn; + + /* Service start handle */ + uint16_t srv_start_handle; + + /* Service end handle */ + uint16_t srv_end_handle; + + /* Characteristic start handle */ + uint16_t chr_start_handle; + + /* Descriptor handle */ + uint16_t dsc_handle; +}; + +struct stress_con_stat { + /* Number of successful connection attempts */ + int num; + + /* Max number of established connections */ + int max_num; + + /* Number connection attempts */ + int attempts_num; + + /* Number of params updates */ + int prms_upd_num; + + /* Number of PHY updates */ + int phy_upd_num; +}; + +/* Common stress test context. + * (Reusable) - auxiliary variable + * (Stress x) - variable contains result of x stress test */ +struct com_stress_test_ctx { + /* Which of tests are completed already. Each element for different + * stress test. */ + bool completed[STRESS_UUIDS_NUM]; + + /* Connection stats. Each element for different stress test. */ + struct stress_con_stat con_stat[STRESS_UUIDS_NUM]; + +/* Reusable variables */ + + /* Stress test number */ + int cur_test_id; + + /* Instance address */ + ble_addr_t dev_addr; + + /* Connection handler */ + uint16_t conn_handle; + + /* L2CAP channel (Reusable) */ + struct ble_l2cap_chan * chan; + + /* Size of received data */ + int64_t rcv_data_bytes; + + /* Number of received packages */ + int rcv_num; + + /* Number of send actions */ + int send_num; + + /* Variables for bit rate measurement */ + int64_t begin_us; + int64_t end_us; + int64_t time_sum; + int64_t bytes_sum; + + /* Timeout flag */ + bool timeout_flag; + + /* Data received flag */ + bool rcv_data_flag; + + uint16_t start_handle; + uint16_t end_handle; + uint16_t dsc_handle; + +/* Variables for test results */ + /* Reached timeout of scanning for test */ + bool scan_timeout; + + /* Number of received first packets of adverts */ + int s6_rcv_adv_first; + + /* Number of full received adverts */ + int s6_rcv_adv_suc; + + /* L2CAP Send Bit Rate */ + int s10_bit_rate; + + /* Average indication time */ + int s12_notif_time; + + /* Average notification time */ + int s13_notif_time; + + /* Average notification time */ + int s14_notif_time; + + /* Max size of received MTU */ + int64_t s10_max_mtu; +}; + +#define STRESS_PAT_LEN 1650 + +static const uint8_t test_6_pattern[STRESS_PAT_LEN] = { + /* Random data */ + 0x00, 0x02, 0x00, 0x04, 0x00, 0x06, 0x00, 0x08, 0x00, 0x0a, + 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x10, 0x00, 0x12, 0x00, 0x14, + 0x00, 0x16, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1c, 0x00, 0x1e, + 0x00, 0x20, 0x00, 0x22, 0x00, 0x24, 0x00, 0x26, 0x00, 0x28, + 0x00, 0x2a, 0x00, 0x2c, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x32, + 0x00, 0x34, 0x00, 0x36, 0x00, 0x38, 0x00, 0x3a, 0x00, 0x3c, + 0x00, 0x3e, 0x00, 0x40, 0x00, 0x42, 0x00, 0x44, 0x00, 0x46, + 0x00, 0x48, 0x00, 0x4a, 0x00, 0x4c, 0x00, 0x4e, 0x00, 0x50, + 0x00, 0x52, 0x00, 0x54, 0x00, 0x56, 0x00, 0x58, 0x00, 0x5a, + 0x00, 0x5c, 0x00, 0x5e, 0x00, 0x60, 0x00, 0x62, 0x00, 0x64, + 0x00, 0x66, 0x00, 0x68, 0x00, 0x6a, 0x00, 0x6c, 0x00, 0x6e, + 0x00, 0x70, 0x00, 0x72, 0x00, 0x74, 0x00, 0x76, 0x00, 0x78, + 0x00, 0x7a, 0x00, 0x7c, 0x00, 0x7e, 0x00, 0x80, 0x00, 0x82, + 0x00, 0x84, 0x00, 0x86, 0x00, 0x88, 0x00, 0x8a, 0x00, 0x8c, + 0x00, 0x8e, 0x00, 0x90, 0x00, 0x92, 0x00, 0x94, 0x00, 0x96, + 0x00, 0x98, 0x00, 0x9a, 0x00, 0x9c, 0x00, 0x9e, 0x00, 0xa0, + 0x00, 0xa2, 0x00, 0xa4, 0x00, 0xa6, 0x00, 0xa8, 0x00, 0xaa, + 0x00, 0xac, 0x00, 0xae, 0x00, 0xb0, 0x00, 0xb2, 0x00, 0xb4, + 0x00, 0xb6, 0x00, 0xb8, 0x00, 0xba, 0x00, 0xbc, 0x00, 0xbe, + 0x00, 0xc0, 0x00, 0xc2, 0x00, 0xc4, 0x00, 0xc6, 0x00, 0xc8, + 0x00, 0xca, 0x00, 0xcc, 0x00, 0xce, 0x00, 0xd0, 0x00, 0xd2, + 0x00, 0xd4, 0x00, 0xd6, 0x00, 0xd8, 0x00, 0xda, 0x00, 0xdc, + 0x00, 0xde, 0x00, 0xe0, 0x00, 0xe2, 0x00, 0xe4, 0x00, 0xe6, + 0x00, 0xe8, 0x00, 0xea, 0x00, 0xec, 0x00, 0xee, 0x00, 0xf0, + 0x00, 0xf2, 0x00, 0xf4, 0x00, 0xf6, 0x00, 0xf8, 0x00, 0xfa, + 0x00, 0xfc, 0x00, 0xfe, 0x01, 0x01, 0x01, 0x03, 0x01, 0x05, + 0x01, 0x07, 0x01, 0x09, 0x01, 0x0b, 0x01, 0x0d, 0x01, 0x0f, + 0x01, 0x11, 0x01, 0x13, 0x01, 0x15, 0x01, 0x17, 0x01, 0x19, + 0x01, 0x1b, 0x01, 0x1d, 0x01, 0x1f, 0x01, 0x21, 0x01, 0x23, + 0x01, 0x25, 0x01, 0x27, 0x01, 0x29, 0x01, 0x2b, 0x01, 0x2d, + 0x01, 0x2f, 0x01, 0x31, 0x01, 0x33, 0x01, 0x35, 0x01, 0x37, + 0x01, 0x39, 0x01, 0x3b, 0x01, 0x3d, 0x01, 0x3f, 0x01, 0x41, + 0x01, 0x43, 0x01, 0x45, 0x01, 0x47, 0x01, 0x49, 0x01, 0x4b, + 0x01, 0x4d, 0x01, 0x4f, 0x01, 0x51, 0x01, 0x53, 0x01, 0x55, + 0x01, 0x57, 0x01, 0x59, 0x01, 0x5b, 0x01, 0x5d, 0x01, 0x5f, + 0x01, 0x61, 0x01, 0x63, 0x01, 0x65, 0x01, 0x67, 0x01, 0x69, + 0x01, 0x6b, 0x01, 0x6d, 0x01, 0x6f, 0x01, 0x71, 0x01, 0x73, + 0x01, 0x75, 0x01, 0x77, 0x01, 0x79, 0x01, 0x7b, 0x01, 0x7d, + 0x01, 0x7f, 0x01, 0x81, 0x01, 0x83, 0x01, 0x85, 0x01, 0x87, + 0x01, 0x89, 0x01, 0x8b, 0x01, 0x8d, 0x01, 0x8f, 0x01, 0x91, + 0x01, 0x93, 0x01, 0x95, 0x01, 0x97, 0x01, 0x99, 0x01, 0x9b, + 0x01, 0x9d, 0x01, 0x9f, 0x01, 0xa1, 0x01, 0xa3, 0x01, 0xa5, + 0x01, 0xa7, 0x01, 0xa9, 0x01, 0xab, 0x01, 0xad, 0x01, 0xaf, + 0x01, 0xb1, 0x01, 0xb3, 0x01, 0xb5, 0x01, 0xb7, 0x01, 0xb9, + 0x01, 0xbb, 0x01, 0xbd, 0x01, 0xbf, 0x01, 0xc1, 0x01, 0xc3, + 0x01, 0xc5, 0x01, 0xc7, 0x01, 0xc9, 0x01, 0xcb, 0x01, 0xcd, + 0x01, 0xcf, 0x01, 0xd1, 0x01, 0xd3, 0x01, 0xd5, 0x01, 0xd7, + 0x01, 0xd9, 0x01, 0xdb, 0x01, 0xdd, 0x01, 0xdf, 0x01, 0xe1, + 0x01, 0xe3, 0x01, 0xe5, 0x01, 0xe7, 0x01, 0xe9, 0x01, 0xeb, + 0x01, 0xed, 0x01, 0xef, 0x01, 0xf1, 0x01, 0xf3, 0x01, 0xf5, + 0x01, 0xf7, 0x01, 0xf9, 0x01, 0xfb, 0x01, 0xfd, 0x02, 0x00, + 0x02, 0x02, 0x02, 0x04, 0x02, 0x06, 0x02, 0x08, 0x02, 0x0a, + 0x02, 0x0c, 0x02, 0x0e, 0x02, 0x10, 0x02, 0x12, 0x02, 0x14, + 0x02, 0x16, 0x02, 0x18, 0x02, 0x1a, 0x02, 0x1c, 0x02, 0x1e, + 0x02, 0x20, 0x02, 0x22, 0x02, 0x24, 0x02, 0x26, 0x02, 0x28, + 0x02, 0x2a, 0x02, 0x2c, 0x02, 0x2e, 0x02, 0x30, 0x02, 0x32, + 0x02, 0x34, 0x02, 0x36, 0x02, 0x38, 0x02, 0x3a, 0x02, 0x3c, + 0x02, 0x3e, 0x02, 0x40, 0x02, 0x42, 0x02, 0x44, 0x02, 0x46, + 0x02, 0x48, 0x02, 0x4a, 0x02, 0x4c, 0x02, 0x4e, 0x02, 0x50, + 0x02, 0x52, 0x02, 0x54, 0x02, 0x56, 0x02, 0x58, 0x02, 0x5a, + 0x02, 0x5c, 0x02, 0x5e, 0x02, 0x60, 0x02, 0x62, 0x02, 0x64, + 0x02, 0x66, 0x02, 0x68, 0x02, 0x6a, 0x02, 0x6c, 0x02, 0x6e, + 0x02, 0x70, 0x02, 0x72, 0x02, 0x74, 0x02, 0x76, 0x02, 0x78, + 0x02, 0x7a, 0x02, 0x7c, 0x02, 0x7e, 0x02, 0x80, 0x02, 0x82, + 0x02, 0x84, 0x02, 0x86, 0x02, 0x88, 0x02, 0x8a, 0x02, 0x8c, + 0x02, 0x8e, 0x02, 0x90, 0x02, 0x92, 0x02, 0x94, 0x02, 0x96, + 0x02, 0x98, 0x02, 0x9a, 0x02, 0x9c, 0x02, 0x9e, 0x02, 0xa0, + 0x02, 0xa2, 0x02, 0xa4, 0x02, 0xa6, 0x02, 0xa8, 0x02, 0xaa, + 0x02, 0xac, 0x02, 0xae, 0x02, 0xb0, 0x02, 0xb2, 0x02, 0xb4, + 0x02, 0xb6, 0x02, 0xb8, 0x02, 0xba, 0x02, 0xbc, 0x02, 0xbe, + 0x02, 0xc0, 0x02, 0xc2, 0x02, 0xc4, 0x02, 0xc6, 0x02, 0xc8, + 0x02, 0xca, 0x02, 0xcc, 0x02, 0xce, 0x02, 0xd0, 0x02, 0xd2, + 0x02, 0xd4, 0x02, 0xd6, 0x02, 0xd8, 0x02, 0xda, 0x02, 0xdc, + 0x02, 0xde, 0x02, 0xe0, 0x02, 0xe2, 0x02, 0xe4, 0x02, 0xe6, + 0x02, 0xe8, 0x02, 0xea, 0x02, 0xec, 0x02, 0xee, 0x02, 0xf0, + 0x02, 0xf2, 0x02, 0xf4, 0x02, 0xf6, 0x02, 0xf8, 0x02, 0xfa, + 0x02, 0xfc, 0x02, 0xfe, 0x03, 0x01, 0x03, 0x03, 0x03, 0x05, + 0x03, 0x07, 0x03, 0x09, 0x03, 0x0b, 0x03, 0x0d, 0x03, 0x0f, + 0x03, 0x11, 0x03, 0x13, 0x03, 0x15, 0x03, 0x17, 0x03, 0x19, + 0x03, 0x1b, 0x03, 0x1d, 0x03, 0x1f, 0x03, 0x21, 0x03, 0x23, + 0x03, 0x25, 0x03, 0x27, 0x03, 0x29, 0x03, 0x2b, 0x03, 0x2d, + 0x03, 0x2f, 0x03, 0x31, 0x03, 0x33, 0x03, 0x35, 0x03, 0x37, + 0x03, 0x39, 0x03, 0x3b, 0x03, 0x3d, 0x03, 0x3f, 0x03, 0x41, + 0x03, 0x43, 0x03, 0x45, 0x03, 0x47, 0x03, 0x49, 0x03, 0x4b, + 0x03, 0x4d, 0x03, 0x4f, 0x03, 0x51, 0x03, 0x53, 0x03, 0x55, + 0x03, 0x57, 0x03, 0x59, 0x03, 0x5b, 0x03, 0x5d, 0x03, 0x5f, + 0x03, 0x61, 0x03, 0x63, 0x03, 0x65, 0x03, 0x67, 0x03, 0x69, + 0x03, 0x6b, 0x03, 0x6d, 0x03, 0x6f, 0x03, 0x71, 0x03, 0x73, + 0x03, 0x75, 0x03, 0x77, 0x03, 0x79, 0x03, 0x7b, 0x03, 0x7d, + 0x03, 0x7f, 0x03, 0x81, 0x03, 0x83, 0x03, 0x85, 0x03, 0x87, + 0x03, 0x89, 0x03, 0x8b, 0x03, 0x8d, 0x03, 0x8f, 0x03, 0x91, + 0x03, 0x93, 0x03, 0x95, 0x03, 0x97, 0x03, 0x99, 0x03, 0x9b, + 0x03, 0x9d, 0x03, 0x9f, 0x03, 0xa1, 0x03, 0xa3, 0x03, 0xa5, + 0x03, 0xa7, 0x03, 0xa9, 0x03, 0xab, 0x03, 0xad, 0x03, 0xaf, + 0x03, 0xb1, 0x03, 0xb3, 0x03, 0xb5, 0x03, 0xb7, 0x03, 0xb9, + 0x03, 0xbb, 0x03, 0xbd, 0x03, 0xbf, 0x03, 0xc1, 0x03, 0xc3, + 0x03, 0xc5, 0x03, 0xc7, 0x03, 0xc9, 0x03, 0xcb, 0x03, 0xcd, + 0x03, 0xcf, 0x03, 0xd1, 0x03, 0xd3, 0x03, 0xd5, 0x03, 0xd7, + 0x03, 0xd9, 0x03, 0xdb, 0x03, 0xdd, 0x03, 0xdf, 0x03, 0xe1, + 0x03, 0xe3, 0x03, 0xe5, 0x03, 0xe7, 0x03, 0xe9, 0x03, 0xeb, + 0x03, 0xed, 0x03, 0xef, 0x03, 0xf1, 0x03, 0xf3, 0x03, 0xf5, + 0x03, 0xf7, 0x03, 0xf9, 0x03, 0xfb, 0x03, 0xfd, 0x04, 0x00, + 0x04, 0x02, 0x04, 0x04, 0x04, 0x06, 0x04, 0x08, 0x04, 0x0a, + 0x04, 0x0c, 0x04, 0x0e, 0x04, 0x10, 0x04, 0x12, 0x04, 0x14, + 0x04, 0x16, 0x04, 0x18, 0x04, 0x1a, 0x04, 0x1c, 0x04, 0x1e, + 0x04, 0x20, 0x04, 0x22, 0x04, 0x24, 0x04, 0x26, 0x04, 0x28, + 0x04, 0x2a, 0x04, 0x2c, 0x04, 0x2e, 0x04, 0x30, 0x04, 0x32, + 0x04, 0x34, 0x04, 0x36, 0x04, 0x38, 0x04, 0x3a, 0x04, 0x3c, + 0x04, 0x3e, 0x04, 0x40, 0x04, 0x42, 0x04, 0x44, 0x04, 0x46, + 0x04, 0x48, 0x04, 0x4a, 0x04, 0x4c, 0x04, 0x4e, 0x04, 0x50, + 0x04, 0x52, 0x04, 0x54, 0x04, 0x56, 0x04, 0x58, 0x04, 0x5a, + 0x04, 0x5c, 0x04, 0x5e, 0x04, 0x60, 0x04, 0x62, 0x04, 0x64, + 0x04, 0x66, 0x04, 0x68, 0x04, 0x6a, 0x04, 0x6c, 0x04, 0x6e, + 0x04, 0x70, 0x04, 0x72, 0x04, 0x74, 0x04, 0x76, 0x04, 0x78, + 0x04, 0x7a, 0x04, 0x7c, 0x04, 0x7e, 0x04, 0x80, 0x04, 0x82, + 0x04, 0x84, 0x04, 0x86, 0x04, 0x88, 0x04, 0x8a, 0x04, 0x8c, + 0x04, 0x8e, 0x04, 0x90, 0x04, 0x92, 0x04, 0x94, 0x04, 0x96, + 0x04, 0x98, 0x04, 0x9a, 0x04, 0x9c, 0x04, 0x9e, 0x04, 0xa0, + 0x04, 0xa2, 0x04, 0xa4, 0x04, 0xa6, 0x04, 0xa8, 0x04, 0xaa, + 0x04, 0xac, 0x04, 0xae, 0x04, 0xb0, 0x04, 0xb2, 0x04, 0xb4, + 0x04, 0xb6, 0x04, 0xb8, 0x04, 0xba, 0x04, 0xbc, 0x04, 0xbe, + 0x04, 0xc0, 0x04, 0xc2, 0x04, 0xc4, 0x04, 0xc6, 0x04, 0xc8, + 0x04, 0xca, 0x04, 0xcc, 0x04, 0xce, 0x04, 0xd0, 0x04, 0xd2, + 0x04, 0xd4, 0x04, 0xd6, 0x04, 0xd8, 0x04, 0xda, 0x04, 0xdc, + 0x04, 0xde, 0x04, 0xe0, 0x04, 0xe2, 0x04, 0xe4, 0x04, 0xe6, + 0x04, 0xe8, 0x04, 0xea, 0x04, 0xec, 0x04, 0xee, 0x04, 0xf0, + 0x04, 0xf2, 0x04, 0xf4, 0x04, 0xf6, 0x04, 0xf8, 0x04, 0xfa, + 0x04, 0xfc, 0x04, 0xfe, 0x05, 0x01, 0x05, 0x03, 0x05, 0x05, + 0x05, 0x07, 0x05, 0x09, 0x05, 0x0b, 0x05, 0x0d, 0x05, 0x0f, + 0x05, 0x11, 0x05, 0x13, 0x05, 0x15, 0x05, 0x17, 0x05, 0x19, + 0x05, 0x1b, 0x05, 0x1d, 0x05, 0x1f, 0x05, 0x21, 0x05, 0x23, + 0x05, 0x25, 0x05, 0x27, 0x05, 0x29, 0x05, 0x2b, 0x05, 0x2d, + 0x05, 0x2f, 0x05, 0x31, 0x05, 0x33, 0x05, 0x35, 0x05, 0x37, + 0x05, 0x39, 0x05, 0x3b, 0x05, 0x3d, 0x05, 0x3f, 0x05, 0x41, + 0x05, 0x43, 0x05, 0x45, 0x05, 0x47, 0x05, 0x49, 0x05, 0x4b, + 0x05, 0x4d, 0x05, 0x4f, 0x05, 0x51, 0x05, 0x53, 0x05, 0x55, + 0x05, 0x57, 0x05, 0x59, 0x05, 0x5b, 0x05, 0x5d, 0x05, 0x5f, + 0x05, 0x61, 0x05, 0x63, 0x05, 0x65, 0x05, 0x67, 0x05, 0x69, + 0x05, 0x6b, 0x05, 0x6d, 0x05, 0x6f, 0x05, 0x71, 0x05, 0x73, + 0x05, 0x75, 0x05, 0x77, 0x05, 0x79, 0x05, 0x7b, 0x05, 0x7d, + 0x05, 0x7f, 0x05, 0x81, 0x05, 0x83, 0x05, 0x85, 0x05, 0x87, + 0x05, 0x89, 0x05, 0x8b, 0x05, 0x8d, 0x05, 0x8f, 0x05, 0x91, + 0x05, 0x93, 0x05, 0x95, 0x05, 0x97, 0x05, 0x99, 0x05, 0x9b, + 0x05, 0x9d, 0x05, 0x9f, 0x05, 0xa1, 0x05, 0xa3, 0x05, 0xa5, + 0x05, 0xa7, 0x05, 0xa9, 0x05, 0xab, 0x05, 0xad, 0x05, 0xaf, + 0x05, 0xb1, 0x05, 0xb3, 0x05, 0xb5, 0x05, 0xb7, 0x05, 0xb9, + 0x05, 0xbb, 0x05, 0xbd, 0x05, 0xbf, 0x05, 0xc1, 0x05, 0xc3, + 0x05, 0xc5, 0x05, 0xc7, 0x05, 0xc9, 0x05, 0xcb, 0x05, 0xcd, + 0x05, 0xcf, 0x05, 0xd1, 0x05, 0xd3, 0x05, 0xd5, 0x05, 0xd7, + 0x05, 0xd9, 0x05, 0xdb, 0x05, 0xdd, 0x05, 0xdf, 0x05, 0xe1, + 0x05, 0xe3, 0x05, 0xe5, 0x05, 0xe7, 0x05, 0xe9, 0x05, 0xeb, + 0x05, 0xed, 0x05, 0xef, 0x05, 0xf1, 0x05, 0xf3, 0x05, 0xf5, + 0x05, 0xf7, 0x05, 0xf9, 0x05, 0xfb, 0x05, 0xfd, 0x06, 0x00, + 0x06, 0x02, 0x06, 0x04, 0x06, 0x06, 0x06, 0x08, 0x06, 0x0a, + 0x06, 0x0c, 0x06, 0x0e, 0x06, 0x10, 0x06, 0x12, 0x06, 0x14, + 0x06, 0x16, 0x06, 0x18, 0x06, 0x1a, 0x06, 0x1c, 0x06, 0x1e, + 0x06, 0x20, 0x06, 0x22, 0x06, 0x24, 0x06, 0x26, 0x06, 0x28, + 0x06, 0x2a, 0x06, 0x2c, 0x06, 0x2e, 0x06, 0x30, 0x06, 0x32, + 0x06, 0x34, 0x06, 0x36, 0x06, 0x38, 0x06, 0x3a, 0x06, 0x3c, + 0x06, 0x3e, 0x06, 0x40, 0x06, 0x42, 0x06, 0x44, 0x06, 0x46, + 0x06, 0x48, 0x06, 0x4a, 0x06, 0x4c, 0x06, 0x4e, 0x06, 0x50, + 0x06, 0x52, 0x06, 0x54, 0x06, 0x56, 0x06, 0x58, 0x06, 0x5a, + 0x06, 0x5c, 0x06, 0x5e, 0x06, 0x60, 0x06, 0x62, 0x06, 0x64, + 0x06, 0x66, 0x06, 0x68, 0x06, 0x6a, 0x06, 0x6c, 0x06, 0x6e, + 0x06, 0x70, 0x06, 0x72, 0x06, 0x74, 0x06, 0x76, 0x06, 0x78, +}; + +void stress_clear_ctx_reusable_var(struct com_stress_test_ctx *ctx); + +void com_stress_print_report(const struct com_stress_test_ctx test_ctxs[]); + +int stress_fill_mbuf_with_pattern(struct os_mbuf *om, uint16_t len); + +void stress_l2cap_coc_recv(struct ble_l2cap_chan *chan, struct os_mbuf *sdu); + +void stress_l2cap_coc_accept(uint16_t peer_mtu, struct ble_l2cap_chan *chan); + +void stress_start_timer(uint32_t timeout_ms, os_event_fn *ev_cb); + +int64_t stress_calc_bit_rate(int64_t us, int64_t bytes_num); + +void stress_find_svc_handle(uint16_t conn_handle, const ble_uuid_t *srv_uuid, + stress_gatt_disc_end_fn *disc_end_fn); +void stress_find_chr_handle(uint16_t conn_handle, const ble_uuid_t *srv_uuid, + const ble_uuid_t *chr_uuid, + stress_gatt_disc_end_fn *disc_end_fn); + +void stress_find_dsc_handle(uint16_t conn_handle, const ble_uuid_t *srv_uuid, + const ble_uuid_t *chr_uuid, const ble_uuid_t *dsc_uuid, + stress_gatt_disc_end_fn *disc_end_fn); +#ifdef __cplusplus +} +#endif + +#endif //BLE_TGT_STRESS_H diff --git a/src/libs/mynewt-nimble/apps/blestress/src/stress_gatt.c b/src/libs/mynewt-nimble/apps/blestress/src/stress_gatt.c new file mode 100644 index 00000000..a6d845c5 --- /dev/null +++ b/src/libs/mynewt-nimble/apps/blestress/src/stress_gatt.c @@ -0,0 +1,155 @@ +/* + * 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 "stress_gatt.h" + +uint16_t hrs_hrm_handle = 0xffff; + +static int +stress_gatt_access_cb(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg); + +static const struct ble_gatt_svc_def gatt_svr_svcs[] = { + { + /* Service: Heart-rate */ + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(STRESS_GATT_UUID), + .characteristics = (struct ble_gatt_chr_def[]) { + { + /* Characteristic: read test */ + .uuid = BLE_UUID16_DECLARE(STRESS_GATT_READ_UUID), + .access_cb = stress_gatt_access_cb, + .val_handle = &hrs_hrm_handle, + .flags = BLE_GATT_CHR_F_READ, + }, + { + /* Characteristic: write test */ + .uuid = BLE_UUID16_DECLARE(STRESS_GATT_WRITE_UUID), + .access_cb = stress_gatt_access_cb, + .val_handle = &hrs_hrm_handle, + .flags = BLE_GATT_CHR_F_WRITE, + }, + { + /* Characteristic: notify test */ + .uuid = BLE_UUID16_DECLARE(STRESS_GATT_NOTIFY_UUID), + .access_cb = stress_gatt_access_cb, + .val_handle = &hrs_hrm_handle, + .flags = BLE_GATT_CHR_F_NOTIFY, + }, + { + /* Characteristic: indicate test */ + .uuid = BLE_UUID16_DECLARE(STRESS_GATT_INDICATE_UUID), + .access_cb = stress_gatt_access_cb, + .val_handle = &hrs_hrm_handle, + .flags = BLE_GATT_CHR_F_INDICATE, + }, + { + 0, /* No more characteristics in this service */ + },} + }, + { + 0, /* No more services */ + }, +}; + +static int +stress_gatt_access_cb(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg) +{ + /* Sensor location, set to "Chest" */ + static uint8_t chr_value[] = "Hello"; + uint16_t uuid; + int rc; + + //chr_value = (uint8_t)rand() % 256; + uuid = ble_uuid_u16(ctxt->chr->uuid); + + switch(uuid){ + case STRESS_GATT_READ_UUID: + MODLOG_DFLT(INFO, "GATT Read event\n"); + rc = os_mbuf_append(ctxt->om, &chr_value, sizeof(chr_value)); + assert(rc == 0); + //return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + return 0; + case STRESS_GATT_WRITE_UUID: + MODLOG_DFLT(INFO, "GATT Write event\n"); + print_mbuf(ctxt->om); + return 0; + case STRESS_GATT_NOTIFY_UUID: + MODLOG_DFLT(INFO, "GATT Notify event\n"); + return 0; + case STRESS_GATT_INDICATE_UUID: + MODLOG_DFLT(INFO, "GATT Indicate event\n"); + return 0; + default: + MODLOG_DFLT(ERROR, "GATT UUID does not exist\n"); + assert(0); + return BLE_ATT_ERR_UNLIKELY; + } +} + +void +gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg) +{ + char buf[BLE_UUID_STR_LEN]; + + switch (ctxt->op) { + case BLE_GATT_REGISTER_OP_SVC: + MODLOG_DFLT(DEBUG, "registered service %s with handle=%d\n", + ble_uuid_to_str(ctxt->svc.svc_def->uuid, buf), + ctxt->svc.handle); + break; + + case BLE_GATT_REGISTER_OP_CHR: + MODLOG_DFLT(DEBUG, "registering characteristic %s with " + "def_handle=%d val_handle=%d\n", + ble_uuid_to_str(ctxt->chr.chr_def->uuid, buf), + ctxt->chr.def_handle, + ctxt->chr.val_handle); + break; + + case BLE_GATT_REGISTER_OP_DSC: + MODLOG_DFLT(DEBUG, "registering descriptor %s with handle=%d\n", + ble_uuid_to_str(ctxt->dsc.dsc_def->uuid, buf), + ctxt->dsc.handle); + break; + + default: + assert(0); + break; + } +} + +int +gatt_svr_init(void) +{ + int rc; + + rc = ble_gatts_count_cfg(gatt_svr_svcs); + if (rc != 0) { + return rc; + } + + rc = ble_gatts_add_svcs(gatt_svr_svcs); + if (rc != 0) { + return rc; + } + + return 0; +} diff --git a/src/libs/mynewt-nimble/apps/blestress/src/stress_gatt.h b/src/libs/mynewt-nimble/apps/blestress/src/stress_gatt.h new file mode 100644 index 00000000..3344fe2d --- /dev/null +++ b/src/libs/mynewt-nimble/apps/blestress/src/stress_gatt.h @@ -0,0 +1,54 @@ +/* + * 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. + */ + +#ifndef BLE_TGT_STRESS_GATT_H +#define BLE_TGT_STRESS_GATT_H + +#include <assert.h> +#include <stdio.h> +#include <string.h> +#include "host/ble_hs.h" +#include "host/ble_uuid.h" +#include "nimble/ble.h" +#include "modlog/modlog.h" +#include "misc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint16_t hrs_hrm_handle; + +/* Heart-rate configuration */ +#define STRESS_GATT_UUID 0xC0DE +#define STRESS_GATT_READ_UUID 0xC1DE +#define STRESS_GATT_WRITE_UUID 0xC2DE +#define STRESS_GATT_INDICATE_UUID 0xC3DE +#define STRESS_GATT_NOTIFY_UUID 0xC4DE + +int gatt_svr_init(void); + +void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg); + +#ifdef __cplusplus +} +#endif + + +#endif //BLE_TGT_STRESS_GATT_H diff --git a/src/libs/mynewt-nimble/apps/blestress/src/tx_stress.c b/src/libs/mynewt-nimble/apps/blestress/src/tx_stress.c new file mode 100644 index 00000000..b73adc8a --- /dev/null +++ b/src/libs/mynewt-nimble/apps/blestress/src/tx_stress.c @@ -0,0 +1,1671 @@ +/* + * 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 <host/ble_gap.h> +#include <console/console.h> +#include <host/util/util.h> +#include <host/ble_l2cap.h> +#include "tx_stress.h" + +/* Main test task priority. Set a high value so that the task does not + * interfere with event handling */ +#define TX_STRESS_MAIN_TASK_PRIO 0xf0 +#define BASE_UUID_LEN 13 + +/* Contexts for stress tests. */ +static struct com_stress_test_ctx tx_stress_ctxD = { + .conn_handle = 0xffff, + .cur_test_id = 0, +}; + +static struct com_stress_test_ctx *tx_stress_ctx; + +/* Define stack, object and semaphore for test main task. */ +#define TX_STRESS_MAIN_TASK_STACK_SIZE (500) +static struct os_task tx_stress_main_task; +static os_stack_t tx_stress_main_task_stack[TX_STRESS_MAIN_TASK_STACK_SIZE]; +static struct os_sem tx_stress_main_sem; +/* Test use case and address of test advertiser. */ +static int tx_stress_use_case; +static int completed_tests = 0; + +static void +tx_stress_on_test_finish(int test_num) +{ + console_printf("\033[0;32m\nStress test %d completed\033[0m\n", test_num); + ++completed_tests; + tx_stress_ctx->completed[test_num] = true; + os_sem_release(&tx_stress_main_sem); +} + +static void +tx_stress_simple_scan(ble_gap_event_fn *cb, uint16_t duration) +{ + uint8_t own_addr_type; + struct ble_gap_ext_disc_params params = {0}; + int rc; + + /* Figure out address to use while scanning. */ + rc = ble_hs_id_infer_auto(0, &own_addr_type); + if (rc != 0) { + console_printf("\033[0;31mError determining own address type; " + "rc=%d\033[0m\n", rc); + assert(0); + } + + params.itvl = BLE_GAP_SCAN_FAST_INTERVAL_MAX; + params.passive = 1; + params.window = BLE_GAP_SCAN_FAST_WINDOW; + + rc = ble_gap_ext_disc(own_addr_type, duration, 0, 1, 0, 0, ¶ms, NULL, + cb, NULL); + + if (rc != 0) { + console_printf("\033[0;31mError initiating GAP discovery procedure" + "; rc=%d\033[0m\n", rc); + } +} + +static int +tx_stress_simple_connect(ble_gap_event_fn *cb, int test_num) +{ + uint8_t own_addr_type; + int rc; + + /* Set so any PHY mask allowed. */ + ble_gap_set_prefered_default_le_phy(TX_PHY_MASK, RX_PHY_MASK); + + /* Figure out address to use while connecting. */ + rc = ble_hs_id_infer_auto(0, &own_addr_type); + if (rc != 0) { + MODLOG_DFLT(INFO, "\033[0;31mError determining own address type; " + "rc=%d\033[0m\n", rc); + return rc; + } + + MODLOG_DFLT(INFO, "Connection attempt: %d\n", + ++tx_stress_ctx->con_stat[test_num].attempts_num); + + rc = ble_gap_ext_connect(own_addr_type, &tx_stress_ctx->dev_addr, + 10000, + BLE_GAP_LE_PHY_1M_MASK | BLE_GAP_LE_PHY_2M_MASK, + NULL, NULL, NULL, cb, NULL); + + if (rc != 0) { + MODLOG_DFLT(INFO, "\033[0;31mError during connection; rc=%d\033[0m\n", + rc); + } + + return rc; +} + +static int +tx_stress_find_test(struct ble_gap_ext_disc_desc *ext_disc) +{ + struct ble_hs_adv_fields fields; + int data_len; + int rc; + + /* Parser refuses greater length data than 31. But known UUID128 will be + * in first 31 bytes of adv data first packet. */ + if (ext_disc->length_data > 31) { + data_len = 31; + } else { + data_len = ext_disc->length_data; + } + + /* Parse part of adv data. */ + ble_hs_adv_parse_fields(&fields, ext_disc->data, data_len); + print_adv_fields(&fields); + + /* UUID128 service data of stress test advert includes only UUID128. */ + if (fields.svc_data_uuid128_len != 16) { + return -1; + } + + /* Check if service data include known UUID128. */ + rc = memcmp(fields.svc_data_uuid128, (uint8_t[]) {0xC0, 0xDE}, 2); + if (rc) { + return -1; + } + + rc = memcmp(fields.svc_data_uuid128 + 3, MYNEWT_VAL(BLE_STRESS_UUID_BASE), + BASE_UUID_LEN); + + if (rc != 0) { + return -1; + } + + /* This UUID 128 byte indicates the stress test ID to be executed. */ + return fields.svc_data_uuid128[2]; +} + +static int +tx_stress_switcher_gap_event(struct ble_gap_event *event, void *arg) +{ + int rc; + + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + /* A new connection was established or a connection attempt failed. */ + if (event->connect.status == 0) { + MODLOG_DFLT(INFO, "Success to connect to device\n"); + return 0; + } else if (event->connect.status == BLE_HS_ETIMEOUT_HCI) { + MODLOG_DFLT(INFO, "Connection timeout\n"); + } else { + MODLOG_DFLT(INFO, "Error: connection attempt failed; status=%d\n", + event->connect.status); + } + /* Connect to rx device just to give it a signal to switch test. */ + tx_stress_simple_connect(tx_stress_switcher_gap_event, + tx_stress_ctx->cur_test_id); + return 0; + + case BLE_GAP_EVENT_DISCONNECT: + os_sem_release(&tx_stress_main_sem); + return 0; + + case BLE_GAP_EVENT_EXT_DISC: + /* Check if caught advert contains known UUID128. The UUID128 + * contains the ID of test use case to be executed. */ + rc = tx_stress_find_test(&event->ext_disc); + if (rc == 0) { + tx_stress_ctx->dev_addr = event->ext_disc.addr; + /* Stop scanning. */ + ble_gap_disc_cancel(); + /* Add token to semaphore. Main task will start the test. */ + os_sem_release(&tx_stress_main_sem); + } + return 0; + + case BLE_GAP_EVENT_DISC_COMPLETE: + MODLOG_DFLT(INFO, "Discovery complete; reason=%d\n", + event->disc_complete.reason); + return 0; + + default: + MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + return 0; + } +} + +static void +tx_stress_switch_test() +{ + tx_stress_simple_scan(tx_stress_switcher_gap_event, 0); + os_sem_pend(&tx_stress_main_sem, OS_TIMEOUT_NEVER); + + tx_stress_simple_connect(tx_stress_switcher_gap_event, 0); +} + +static int +tx_stress_1_gap_event(struct ble_gap_event *event, void *arg) +{ + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + /* A new connection was established or a connection attempt failed. */ + MODLOG_DFLT(INFO, "Connection %s; status=%d ", + event->connect.status == 0 ? "established" : "failed", + event->connect.status); + + if (event->connect.status == 0) { + /* Connection successfully established. In this use case + * it is error of 'Connect cancel'. Stress test failed. */ + MODLOG_DFLT(INFO, "Success to connect to device\n"); + ++tx_stress_ctx->con_stat[1].num; + + ble_gap_terminate(event->connect.conn_handle, BLE_ERR_NO_PAIRING); + } + return 0; + + case BLE_GAP_EVENT_DISCONNECT: + MODLOG_DFLT(INFO, "Disconnect; reason=%d ", event->disconnect.reason); + return 0; + + default: + MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + return 0; + } +} + +static void +tx_stress_1_test() +{ + int rc; + uint8_t own_addr_type; + ble_addr_t rnd_rx_addr; + int delay_time; + + rc = ble_gap_disc_active(); + assert(rc == 0); + + /* Figure out address to use while advertising. */ + rc = ble_hs_id_infer_auto(0, &own_addr_type); + if (rc != 0) { + MODLOG_DFLT(INFO, "\033[0;31mError determining own address type; " + "rc=%d\033[0m\n", rc); + os_sem_release(&tx_stress_main_sem); + return; + } + + while (tx_stress_ctx->con_stat[1].attempts_num < + MYNEWT_VAL(BLE_STRESS_REPEAT)) { + /* Rand ble address to connect*/ + rc = ble_hs_id_gen_rnd(1, &rnd_rx_addr); + assert (rc == 0); + + MODLOG_DFLT(INFO, "Connection attempt; num=%d\n", + ++tx_stress_ctx->con_stat[1].attempts_num); + + rc = ble_gap_connect(own_addr_type, &rnd_rx_addr, 10000, NULL, + tx_stress_1_gap_event, NULL); + + if (rc != 0) { + MODLOG_DFLT(INFO, "\033[0;31mConnection error; rc=%d\033[0m\n", + rc); + os_sem_release(&tx_stress_main_sem); + return; + } + + MODLOG_DFLT(INFO, "Connect cancel\n"); + ble_gap_conn_cancel(); + console_printf("\033[0;32m>\033[0m"); + } + + console_printf( + "\033[0;32m\nFirst part of test completed\nStart second part: " + "Connect->random delay->cancel\n\033[0m"); + + while (tx_stress_ctx->con_stat[1].attempts_num < + 2 * MYNEWT_VAL(BLE_STRESS_REPEAT)) { + /* Rand ble address to connect*/ + rc = ble_hs_id_gen_rnd(1, &rnd_rx_addr); + assert (rc == 0); + + MODLOG_DFLT(INFO, "Connection attempt; num=%d\n", + ++tx_stress_ctx->con_stat[1].attempts_num); + + delay_time = rand() % 1000; + + MODLOG_DFLT(INFO, "Time to delay=%d\n", delay_time); + + rc = ble_gap_connect(own_addr_type, &rnd_rx_addr, 10000, NULL, + tx_stress_1_gap_event, NULL); + + if (rc != 0) { + MODLOG_DFLT(INFO, "\033[0;31mConnection error; rc=%d\033[0m\n", + rc); + os_sem_release(&tx_stress_main_sem); + return; + } + + os_time_delay(os_time_ms_to_ticks32(delay_time)); + + MODLOG_DFLT(INFO, "Connect cancel\n"); + ble_gap_conn_cancel(); + console_printf("\033[0;32m>\033[0m"); + } + + tx_stress_on_test_finish(1); +} + +static int +tx_stress_2_gap_event(struct ble_gap_event *event, void *arg) +{ + struct ble_gap_conn_desc desc; + int rc; + + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + /* A new connection was established or a connection attempt failed. */ + if (event->connect.status == 0) { + MODLOG_DFLT(INFO, "Success to connect to device\n"); + + ++tx_stress_ctx->con_stat[2].num; + rc = ble_gap_conn_find(event->connect.conn_handle, &desc); + assert(rc == 0); + + tx_stress_ctx->conn_handle = desc.conn_handle; + + ble_gap_terminate(event->connect.conn_handle, + BLE_ERR_REM_USER_CONN_TERM); + } else { + MODLOG_DFLT(INFO, "\033[0;31mError: connection attempt failed; " + "status=%d\033[0m\n", event->connect.status); + os_sem_release(&tx_stress_main_sem); + } + return 0; + + case BLE_GAP_EVENT_DISCONNECT: + MODLOG_DFLT(INFO, "Disconnect; reason=%d \n", + event->disconnect.reason); + console_printf("\033[0;32m>\033[0m"); + + if (tx_stress_ctx->con_stat[2].num >= MYNEWT_VAL(BLE_STRESS_REPEAT)) { + tx_stress_on_test_finish(2); + return 0; + } + tx_stress_simple_connect(tx_stress_2_gap_event, + tx_stress_ctx->cur_test_id); + return 0; + + default: + MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + return 0; + } +} + +static int +tx_stress_3_gap_event(struct ble_gap_event *event, void *arg) +{ + int rc; + + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + /* A new connection was established or a connection attempt failed. */ + if (event->connect.status == 0) { + ++tx_stress_ctx->con_stat[3].num; + MODLOG_DFLT(INFO, "Success to connect to device\n"); + + rc = ble_gap_terminate(event->connect.conn_handle, + BLE_ERR_REM_USER_CONN_TERM); + + MODLOG_DFLT(INFO, "rc=%d\n", rc); + } else { + MODLOG_DFLT(INFO, "\033[0;31mError: connection attempt failed; " + "status=%d\033[0m\n", event->connect.status); + os_sem_release(&tx_stress_main_sem); + } + return 0; + + case BLE_GAP_EVENT_DISCONNECT: + MODLOG_DFLT(INFO, "Disconnect; reason=%d \n", + event->disconnect.reason); + console_printf("\033[0;32m>\033[0m"); + + if (tx_stress_ctx->con_stat[3].num >= MYNEWT_VAL(BLE_STRESS_REPEAT)) { + tx_stress_on_test_finish(3); + return 0; + } + tx_stress_simple_connect(tx_stress_3_gap_event, + tx_stress_ctx->cur_test_id); + return 0; + + default: + MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + return 0; + } +} + +static int +tx_stress_4_con_update(void) +{ + int rc; + + /* With every next update at least one param must change. Otherwise no + * event occurs and test will not be continued */ + struct ble_gap_upd_params params = { + .itvl_min = BLE_GAP_INITIAL_CONN_ITVL_MIN, + .itvl_max = BLE_GAP_INITIAL_CONN_ITVL_MAX, + .latency = BLE_GAP_INITIAL_CONN_LATENCY, + /* So let's change e.g. timeout value. Put ...% 2 ? 1 : 2 to make sure + * that value won't grow significantly and will be different with every + * iteration. */ + .supervision_timeout = BLE_GAP_INITIAL_SUPERVISION_TIMEOUT + + (tx_stress_ctx->con_stat[4].prms_upd_num % 2 ? + 1 : 2), + .min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN, + .max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN, + }; + + rc = ble_gap_update_params(tx_stress_ctx->conn_handle, ¶ms); + + if (rc == BLE_HS_ENOTCONN) { + MODLOG_DFLT(INFO, "Device disconnected. Connection update failed\n"); + assert(0); + } + + if (rc != 0) { + MODLOG_DFLT(ERROR, "\033[0;31mError during connection update; " + "rc=%d\033[0m\n", rc); + assert(0); + } + + return rc; +} + +static int +tx_stress_4_gap_event(struct ble_gap_event *event, void *arg) +{ + int rc; + + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + ++tx_stress_ctx->con_stat[4].attempts_num; + /* A new connection was established or a connection attempt failed. */ + if (event->connect.status == 0) { + MODLOG_DFLT(INFO, "Success to connect to device\n"); + + ++tx_stress_ctx->con_stat[4].num; + tx_stress_ctx->conn_handle = event->connect.conn_handle; + + tx_stress_4_con_update(); + } else { + MODLOG_DFLT(INFO, "\033[0;31mError: connection attempt failed; " + "status=%d\033[0m\n", event->connect.status); + os_sem_release(&tx_stress_main_sem); + } + return 0; + + case BLE_GAP_EVENT_DISCONNECT: + MODLOG_DFLT(INFO, "Disconnect; reason=%d \n", + event->disconnect.reason); + tx_stress_on_test_finish(4); + return 0; + + case BLE_GAP_EVENT_CONN_UPDATE: + if (event->conn_update.status != 0) { + MODLOG_DFLT(INFO, "Connection update failed\n"); + } else { + MODLOG_DFLT(INFO, "Connection updated; num=%d\n", + ++tx_stress_ctx->con_stat[4].prms_upd_num); + console_printf("\033[0;32m>\033[0m"); + } + + if (tx_stress_ctx->con_stat[4].prms_upd_num >= + MYNEWT_VAL(BLE_STRESS_REPEAT)) { + ble_gap_terminate(tx_stress_ctx->conn_handle, + BLE_ERR_REM_USER_CONN_TERM); + } else { + /* Update connection. */ + rc = tx_stress_4_con_update(); + + if (rc != 0) { + MODLOG_DFLT(INFO, "\033[0;31mError: update fail; " + "rc=%d\033[0m\n", rc); + os_sem_release(&tx_stress_main_sem); + } + } + return 0; + + case BLE_GAP_EVENT_CONN_UPDATE_REQ: + MODLOG_DFLT(INFO, "Connection update request\n"); + return 0; + + default: + MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + return 0; + } +} + +static int +tx_stress_5_gap_event(struct ble_gap_event *event, void *arg) +{ + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + /* A new connection was established or a connection attempt failed. */ + if (event->connect.status == 0) { + MODLOG_DFLT(INFO, "Success to connect to device\n"); + + ++tx_stress_ctx->con_stat[5].num; + tx_stress_ctx->conn_handle = event->connect.conn_handle; + } else { + console_printf("\033[0;31mError: Update fail; " + "status=%d\033[0m\n", event->connect.status); + os_sem_release(&tx_stress_main_sem); + } + return 0; + + case BLE_GAP_EVENT_DISCONNECT: + MODLOG_DFLT(INFO, "Disconnect; reason=%d \n", + event->disconnect.reason); + tx_stress_on_test_finish(5); + return 0; + + case BLE_GAP_EVENT_CONN_UPDATE: + if (event->conn_update.status != 0) { + MODLOG_DFLT(INFO, "Connection update failed\n"); + } else { + MODLOG_DFLT(INFO, "Connection updated; num=%d\n", + ++tx_stress_ctx->con_stat[5].prms_upd_num); + console_printf("\033[0;32m>\033[0m"); + } + + if (tx_stress_ctx->con_stat[5].prms_upd_num >= + MYNEWT_VAL(BLE_STRESS_REPEAT)) { + ble_gap_terminate(tx_stress_ctx->conn_handle, + BLE_ERR_REM_USER_CONN_TERM); + } + return 0; + + case BLE_GAP_EVENT_CONN_UPDATE_REQ: + MODLOG_DFLT(INFO, "Connection update request\n"); + return 0; + + default: + MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + return 0; + } +} + +static int +tx_stress_6_gap_event(struct ble_gap_event *event, void *arg) +{ + static int start_id = 0; + int use_case = 0; + int adv_pattern_len; + const uint8_t *adv_pattern; + + switch (event->type) { + case BLE_GAP_EVENT_EXT_DISC: + + /* Instance 0 reserved for SWITCH advert. */ + if (event->ext_disc.sid == 0) { + return 0; + } + + /* Check if advertiser is known rx device. */ + if (memcmp(tx_stress_ctx->dev_addr.val, + event->ext_disc.addr.val, 6) != 0) { + return 0; + } + + /* Return -1 if not first package of advert. */ + use_case = tx_stress_find_test(&event->ext_disc); + + if (use_case > 0) { + /* If first package of advert */ + ++tx_stress_ctx->s6_rcv_adv_first; + start_id = 0; + adv_pattern = &event->ext_disc.data[29]; + adv_pattern_len = event->ext_disc.length_data - 29; + } else { + if (start_id == 0) { + return 0; + } + /* If not first package of advert */ + adv_pattern = event->ext_disc.data; + adv_pattern_len = event->ext_disc.length_data; + } + + /* Check data pattern */ + if (memcmp(adv_pattern, test_6_pattern + start_id, + adv_pattern_len) != 0) { + /* Pattern does not match. May lost some data or package. + * Reset data pattern index. */ + start_id = 0; + return 0; + } + + /* At the next adv data package, start comparing from this index.*/ + start_id += adv_pattern_len; + + /* Check if last packet of advert. */ + if (event->ext_disc.data_status == + BLE_GAP_EXT_ADV_DATA_STATUS_COMPLETE) { + /* Got all packets of advert. */ + ++tx_stress_ctx->s6_rcv_adv_suc; + MODLOG_DFLT(INFO, "Got all packets of advert. num=%d\n", + tx_stress_ctx->s6_rcv_adv_suc); + console_printf("\033[0;32m>\033[0m"); + start_id = 0; + + if (tx_stress_ctx->s6_rcv_adv_suc >= + MYNEWT_VAL(BLE_STRESS_REPEAT)) { + /* Stop scanning. */ + ble_gap_disc_cancel(); + tx_stress_on_test_finish(6); + } + } + return 0; + + case BLE_GAP_EVENT_DISC_COMPLETE: + MODLOG_DFLT(INFO, "Discovery complete; reason=%d\n", + event->disc_complete.reason); + return 0; + + default: + MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + return 0; + } +} + +static void +tx_stress_6_perform(void) +{ + tx_stress_simple_scan(tx_stress_6_gap_event, 0); + os_sem_pend(&tx_stress_main_sem, OS_TIMEOUT_NEVER); + tx_stress_switch_test(); +} + +static int +tx_stress_7_phy_update(void) +{ + int rc; + uint8_t tx_phys_mask; + uint8_t rx_phys_mask; + + ble_gap_read_le_phy(tx_stress_ctx->conn_handle, &tx_phys_mask, + &rx_phys_mask); + + + /* With every next update at least one param must change */ + switch (rx_phys_mask) { + case BLE_GAP_LE_PHY_1M_MASK: + rx_phys_mask = BLE_GAP_LE_PHY_2M_MASK; + break; + case BLE_GAP_LE_PHY_2M_MASK: +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) + rx_phys_mask = BLE_GAP_LE_PHY_CODED_MASK; + break; + case BLE_GAP_LE_PHY_CODED_MASK: +#endif + rx_phys_mask = BLE_GAP_LE_PHY_1M_MASK; + break; + default: + rx_phys_mask = BLE_GAP_LE_PHY_1M_MASK; + break; + } + + switch (tx_phys_mask) { + case BLE_GAP_LE_PHY_1M_MASK: + tx_phys_mask = BLE_GAP_LE_PHY_2M_MASK; + break; + case BLE_GAP_LE_PHY_2M_MASK: +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) + tx_phys_mask = BLE_GAP_LE_PHY_CODED_MASK; + break; + case BLE_GAP_LE_PHY_CODED_MASK: +#endif + tx_phys_mask = BLE_GAP_LE_PHY_1M_MASK; + break; + default: + tx_phys_mask = BLE_GAP_LE_PHY_1M_MASK; + break; + } + + rc = ble_gap_set_prefered_le_phy(tx_stress_ctx->conn_handle, + tx_phys_mask, rx_phys_mask, 0); + + if (rc == BLE_HS_ENOTCONN) { + MODLOG_DFLT(INFO, "Device disconnected. Connection update failed\n"); + return rc; + } + + if (rc != 0) { + MODLOG_DFLT(ERROR, "\033[0;31mError during PHY update; " + "rc=%d\033[0m\n", rc); + } + + return rc; +} + +static int +tx_stress_7_gap_event(struct ble_gap_event *event, void *arg) +{ + int rc; + + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + /* A new connection was established or a connection attempt failed. */ + if (event->connect.status == 0) { + MODLOG_DFLT(INFO, "Success to connect to device\n"); + + ++tx_stress_ctx->con_stat[7].num; + tx_stress_ctx->conn_handle = event->connect.conn_handle; + + tx_stress_7_phy_update(); + } else { + console_printf("\033[0;31mError: Update fail; " + "status=%d\033[0m\n", event->connect.status); + os_sem_release(&tx_stress_main_sem); + } + return 0; + + case BLE_GAP_EVENT_DISCONNECT: + MODLOG_DFLT(INFO, "Disconnect; reason=%d \n", + event->disconnect.reason); + tx_stress_on_test_finish(7); + return 0; + + case BLE_GAP_EVENT_CONN_UPDATE: + MODLOG_DFLT(INFO, "Connection updated\n"); + return 0; + + case BLE_GAP_EVENT_CONN_UPDATE_REQ: + MODLOG_DFLT(INFO, "Connection update request\n"); + return 0; + + case BLE_GAP_EVENT_PHY_UPDATE_COMPLETE: + if (event->phy_updated.status != 0) { + MODLOG_DFLT(INFO, "PHY update failed\n"); + } else { + MODLOG_DFLT(INFO, "PHY updated; num=%d; rx:%d, tx:%d\n", + ++tx_stress_ctx->con_stat[7].phy_upd_num, + event->phy_updated.rx_phy, event->phy_updated.tx_phy); + console_printf("\033[0;32m>\033[0m"); + } + + if (tx_stress_ctx->con_stat[7].phy_upd_num >= + MYNEWT_VAL(BLE_STRESS_REPEAT)) { + ble_gap_terminate(tx_stress_ctx->conn_handle, + BLE_ERR_REM_USER_CONN_TERM); + } else { + /* Update connection. */ + rc = tx_stress_7_phy_update(); + if (rc != 0) { + console_printf("\033[0;31mError: PHPY update fail; " + "rc=%d\033[0m\n", event->phy_updated.status); + assert(0); + } + } + return 0; + + default: + MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + return 0; + } +} + +static int +tx_stress_8_gap_event(struct ble_gap_event *event, void *arg) +{ + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + /* A new connection was established or a connection attempt failed. */ + if (event->connect.status == 0) { + MODLOG_DFLT(INFO, "Success to connect to device\n"); + + ++tx_stress_ctx->con_stat[8].num; + tx_stress_ctx->conn_handle = event->connect.conn_handle; + } else { + MODLOG_DFLT(INFO, "\033[0;31mError: connection attempt failed; " + "status=%d\033[0m\n", event->connect.status); + os_sem_release(&tx_stress_main_sem); + } + return 0; + + case BLE_GAP_EVENT_DISCONNECT: + MODLOG_DFLT(INFO, "Disconnect; reason=%d \n", + event->disconnect.reason); + tx_stress_on_test_finish(8); + return 0; + + case BLE_GAP_EVENT_CONN_UPDATE: + if (event->conn_update.status != 0) { + MODLOG_DFLT(INFO, "Connection update failed\n"); + } else { + MODLOG_DFLT(INFO, "Connection updated; num=%d\n", + ++tx_stress_ctx->con_stat[8].prms_upd_num); + } + return 0; + + case BLE_GAP_EVENT_CONN_UPDATE_REQ: + MODLOG_DFLT(INFO, "Connection update request\n"); + return 0; + + case BLE_GAP_EVENT_PHY_UPDATE_COMPLETE: + if (event->phy_updated.status != 0) { + MODLOG_DFLT(INFO, "PHY update failed\n"); + } else { + MODLOG_DFLT(INFO, "PHY updated; num=%d\n", + ++tx_stress_ctx->con_stat[8].phy_upd_num); + console_printf("\033[0;32m>\033[0m"); + } + + if (tx_stress_ctx->con_stat[8].phy_upd_num >= + MYNEWT_VAL(BLE_STRESS_REPEAT)) { + ble_gap_terminate(tx_stress_ctx->conn_handle, + BLE_ERR_REM_USER_CONN_TERM); + } + return 0; + + default: + MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + return 0; + } +} + +static int +tx_stress_9_gap_event(struct ble_gap_event *event, void *arg) +{ + ble_addr_t addr; + int test; + + switch (event->type) { + case BLE_GAP_EVENT_EXT_DISC: + /* Looking for next instance of test 9 advert. */ + test = tx_stress_find_test(&event->ext_disc); + /* To avoid messing by rest of test 9 events in queue, check if handle + * filled */ + if (test == 9 && tx_stress_ctx->conn_handle == 0xffff) { + tx_stress_ctx->conn_handle = 0; + ble_gap_disc_cancel(); + tx_stress_ctx->dev_addr = event->ext_disc.addr; + tx_stress_simple_connect(tx_stress_9_gap_event, + tx_stress_ctx->cur_test_id); + } + return 0; + + case BLE_GAP_EVENT_DISC_COMPLETE: + if (event->disc_complete.reason == 0 && !tx_stress_ctx->completed[9]) { + console_printf("\033[0;31mScanning timeout\033[0m"); + tx_stress_ctx->completed[9] = true; + os_sem_release(&tx_stress_main_sem); + return 0; + } + break; + + case BLE_GAP_EVENT_CONNECT: + /* A new connection was established or a connection attempt failed. */ + if (event->connect.status == 0) { + MODLOG_DFLT(INFO, "Success to connect to device\n"); + MODLOG_DFLT(INFO, "Connections num: %d\n", + ++tx_stress_ctx->con_stat[9].num); + console_printf("\033[0;32m>\033[0m"); + /* Remember max number of handled connections */ + if (tx_stress_ctx->con_stat[9].num > + tx_stress_ctx->con_stat[9].max_num) { + tx_stress_ctx->con_stat[9].max_num = tx_stress_ctx->con_stat[9].num; + } + } else { + MODLOG_DFLT(INFO, "\033[0;31mError: connection attempt failed; " + "status=%d\033[0m\n", event->connect.status); + } + break; + + case BLE_GAP_EVENT_DISCONNECT: + MODLOG_DFLT(INFO, "Disconnect; reason=%d ", event->disconnect.reason); + console_printf("\033[0;31mX\033[0m"); + MODLOG_DFLT(INFO, "Connections num: %d\n", + --tx_stress_ctx->con_stat[9].num); + + if (tx_stress_ctx->con_stat[9].num == 0) { + os_sem_release(&tx_stress_main_sem); + return 0; + } + break; + + default: + MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + return 0; + } + + if (tx_stress_ctx->completed[9]) { + return 0; + } + + /* End use case after specified number of scan times or max config number + * of connections */ + if (tx_stress_ctx->con_stat[9].attempts_num < + MYNEWT_VAL(BLE_STRESS_REPEAT) && + tx_stress_ctx->con_stat[9].max_num < MYNEWT_VAL(BLE_MAX_CONNECTIONS)) { + if (ble_gap_disc_active() == 0) { + /* Generate and set new random address */ + ble_hs_id_gen_rnd(0, &addr); + ble_hs_id_set_rnd(addr.val); + tx_stress_ctx->conn_handle = 0xffff; + /* Scan for next instance of the test. */ + tx_stress_simple_scan(tx_stress_9_gap_event, 2000); + } + } else { + tx_stress_ctx->completed[9] = true; + os_sem_release(&tx_stress_main_sem); + } + return 0; +} + +static void +tx_stress_9_perform() +{ + int i, rc; + + /* Scan for next instance of the test. */ + tx_stress_simple_scan(tx_stress_9_gap_event, 2000); + + os_sem_pend(&tx_stress_main_sem, OS_TIMEOUT_NEVER); + + /* On use case finishing terminate all handled connections */ + for (i = 0; i <= MYNEWT_VAL(BLE_MAX_CONNECTIONS); ++i) { + rc = ble_gap_conn_find(i, NULL); + if (rc == 0) { + MODLOG_DFLT(INFO, "Terminating...\n"); + ble_gap_terminate(i, BLE_ERR_REM_USER_CONN_TERM); + } + } + + os_sem_pend(&tx_stress_main_sem, OS_TIMEOUT_NEVER); + tx_stress_on_test_finish(9); +} + +static int +tx_stress_10_l2cap_send(struct ble_l2cap_chan *chan, uint8_t *data, + int data_len) +{ + struct os_mbuf *data_buf; + int rc; + + /* Get mbuf for adv data */ + data_buf = os_msys_get_pkthdr(data_len, 0); + assert(data != NULL); + + /* Fill mbuf with pattern data */ + rc = os_mbuf_append(data_buf, data, data_len); + + if (rc) { + os_mbuf_free_chain(data_buf); + assert(0); + } + + /* Send data with L2CAP */ + rc = ble_l2cap_send(chan, data_buf); + + return rc; +} + +void tx_stress_10_timer_ev_cb(struct os_event *ev) +{ + assert(ev != NULL); + + if (tx_stress_ctx->rcv_data_flag) { + return; + } + + tx_stress_ctx->timeout_flag = true; + MODLOG_DFLT(INFO, "L2CAP receiving timeout\n"); + ble_gap_terminate(tx_stress_ctx->conn_handle, + BLE_ERR_REM_USER_CONN_TERM); +} + +static void +tx_stress_10_l2cap_send_req() +{ + int rc; + /* Send a request to the RX device */ + + MODLOG_DFLT(INFO, "L2CAP sending request\n"); + tx_stress_ctx->timeout_flag = false; + tx_stress_ctx->rcv_data_flag = false; + stress_start_timer(7000, tx_stress_10_timer_ev_cb); + + /* Get the sending begin time */ + tx_stress_ctx->begin_us = os_get_uptime_usec(); + + /* Send anything just to give a signal to start sending data + * by RX device */ + rc = tx_stress_10_l2cap_send(tx_stress_ctx->chan, (uint8_t *) "S", + sizeof("S")); + assert(rc == 0); +} + +static int +tx_stress_10_l2cap_event(struct ble_l2cap_event *event, void *arg) +{ + static int i = 0; + int64_t us = 0; + struct ble_l2cap_chan_info chan_info; + + switch (event->type) { + case BLE_L2CAP_EVENT_COC_CONNECTED: + /* A new L2CAP connection was established. */ + if (event->connect.status == 0) { + MODLOG_DFLT(INFO, "Established L2CAP connection\n"); + tx_stress_ctx->chan = event->connect.chan; + + ble_l2cap_get_chan_info(event->connect.chan, &chan_info); + + MODLOG_DFLT(INFO, + "LE COC connected, conn: %d, chan: 0x%08lx, scid: 0x%04x, " + "dcid: 0x%04x, our_mtu: 0x%04x, peer_mtu: 0x%04x\n", + event->connect.conn_handle, + (uint32_t) event->connect.chan, + chan_info.scid, + chan_info.dcid, + chan_info.our_l2cap_mtu, + chan_info.peer_l2cap_mtu); + + tx_stress_10_l2cap_send_req(); + } + return 0; + + case BLE_L2CAP_EVENT_COC_DISCONNECTED: + MODLOG_DFLT(INFO, "Remote device disconnected from L2CAP server\n"); + return 0; + + case BLE_L2CAP_EVENT_COC_ACCEPT: + stress_l2cap_coc_accept(event->accept.peer_sdu_size, + event->accept.chan); + return 0; + + case BLE_L2CAP_EVENT_COC_DATA_RECEIVED: + /* Get the time of data receive */ + tx_stress_ctx->end_us = os_get_uptime_usec(); + + /* And test after timeout */ + if (tx_stress_ctx->timeout_flag) { + ble_gap_terminate(tx_stress_ctx->conn_handle, + BLE_ERR_REM_USER_CONN_TERM); + return 0; + } + + tx_stress_ctx->rcv_data_flag = true; + + stress_l2cap_coc_recv(event->receive.chan, event->receive.sdu_rx); + + /* Time of data sending */ + us = tx_stress_ctx->end_us - tx_stress_ctx->begin_us; + MODLOG_DFLT(INFO, "Time of receiving L2CAP data: %ld \n", + tx_stress_ctx->end_us); + + /* Remember size of entire mbuf chain */ + tx_stress_ctx->rcv_data_bytes = OS_MBUF_PKTLEN( + event->receive.sdu_rx); + MODLOG_DFLT(INFO, "Num of received bytes: %lld\n", + tx_stress_ctx->rcv_data_bytes); + + /* Calculate the bit rate of this send */ + tx_stress_ctx->s10_bit_rate = + stress_calc_bit_rate(us, tx_stress_ctx->rcv_data_bytes); + MODLOG_DFLT(INFO, "Bit rate: %d B/s\n", tx_stress_ctx->s10_bit_rate); + + /* Remember the sum of bytes and the time to calculate the average + * bit rate. */ + tx_stress_ctx->bytes_sum += tx_stress_ctx->rcv_data_bytes; + tx_stress_ctx->time_sum += us; + + /* Remember max received MTU */ + if (tx_stress_ctx->s10_max_mtu < tx_stress_ctx->rcv_data_bytes) { + tx_stress_ctx->s10_max_mtu = tx_stress_ctx->rcv_data_bytes; + } + console_printf("\033[0;32m>\033[0m"); + MODLOG_DFLT(INFO, "Loop nr: %d\n", ++i); + + tx_stress_10_l2cap_send_req(); + return 0; + + case BLE_L2CAP_EVENT_COC_TX_UNSTALLED: + MODLOG_DFLT(INFO, "L2CAP event unstalled\n"); + return 0; + + default: + MODLOG_DFLT(INFO, "Other L2CAP event occurs; rc=%d\n", event->type); + return 0; + } +} + +static int +tx_stress_10_gap_event(struct ble_gap_event *event, void *arg) +{ + int rc; + struct os_mbuf *sdu_rx; + + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + /* A new connection was established or a connection attempt failed. */ + if (event->connect.status == 0) { + MODLOG_DFLT(INFO, "Success to connect to device; num: %d\n", + ++tx_stress_ctx->con_stat[10].num); + + sdu_rx = os_msys_get_pkthdr(STRESS_COC_MTU, 0); + assert(sdu_rx != NULL); + + tx_stress_ctx->conn_handle = event->connect.conn_handle; + rc = ble_l2cap_connect(event->connect.conn_handle, 1, + STRESS_COC_MTU, sdu_rx, + tx_stress_10_l2cap_event, NULL); + assert(rc == 0); + } else { + MODLOG_DFLT(INFO, "\033[0;31mError: connection attempt failed; " + "status=%d\033[0m\n", event->connect.status); + } + return 0; + + case BLE_GAP_EVENT_DISCONNECT: + tx_stress_ctx->s10_bit_rate = 1000000 * tx_stress_ctx->bytes_sum / + tx_stress_ctx->time_sum; + + MODLOG_DFLT(INFO, "Average bit rate: %d B/s\n", + tx_stress_ctx->s10_bit_rate); + tx_stress_on_test_finish(10); + return 0; + + default: + MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + return 0; + } +} + +static int +tx_stress_11_gap_event(struct ble_gap_event *event, void *arg) +{ + int test; + + switch (event->type) { + case BLE_GAP_EVENT_EXT_DISC: + /* Looking for next instance of test 9 advert. */ + test = tx_stress_find_test(&event->ext_disc); + + /* To avoid messing by rest of test 9 events in queue, check if handle + * filled */ + if (test == 11 && tx_stress_ctx->conn_handle == 0xffff) { + tx_stress_ctx->conn_handle = 0; + ble_gap_disc_cancel(); + tx_stress_ctx->dev_addr = event->ext_disc.addr; + tx_stress_simple_connect(tx_stress_11_gap_event, + tx_stress_ctx->cur_test_id); + } + return 0; + + case BLE_GAP_EVENT_CONNECT: + /* A new connection was established or a connection attempt failed. */ + if (event->connect.status == 0) { + ++tx_stress_ctx->con_stat[11].num; + MODLOG_DFLT(INFO, "Success to connect to device\n"); + } else { + MODLOG_DFLT(INFO, "\033[0;31mError: connection attempt failed; " + "status=%d\033[0m\n", event->connect.status); + break; + } + return 0; + + case BLE_GAP_EVENT_DISCONNECT: + MODLOG_DFLT(INFO, "Disconnect; reason=%d \n", + event->disconnect.reason); + console_printf("\033[0;32m>\033[0m"); + + if (tx_stress_ctx->con_stat[11].num >= MYNEWT_VAL(BLE_STRESS_REPEAT)) { + tx_stress_on_test_finish(11); + return 0; + } + break; + + default: + MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + return 0; + } + + tx_stress_ctx->conn_handle = 0xffff; + + /* Scan for next instance of the test. */ + tx_stress_simple_scan(tx_stress_11_gap_event, 750); + + return 0; +} + +static int +tx_stress_12_gap_event(struct ble_gap_event *event, void *arg) +{ + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + /* A new connection was established or a connection attempt failed. */ + if (event->connect.status == 0) { + ++tx_stress_ctx->con_stat[12].num; + MODLOG_DFLT(INFO, "Success to connect to device\n"); + tx_stress_ctx->conn_handle = event->connect.conn_handle; + } else { + MODLOG_DFLT(INFO, "\033[0;31mError: connection attempt failed; " + "status=%d\033[0m\n", event->connect.status); + } + return 0; + + case BLE_GAP_EVENT_DISCONNECT: + MODLOG_DFLT(INFO, "Disconnect; reason=%d \n", + event->disconnect.reason); + /* Finish test after first disconnection */ + tx_stress_on_test_finish(12); + return 0; + + case BLE_GAP_EVENT_NOTIFY_RX: + /* Received indication */ + MODLOG_DFLT(INFO, "Notify RX event\n"); + console_printf("\033[0;32m>\033[0m"); + return 0; + + default: + MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + return 0; + } +} + +static int +tx_stress_13_gap_event(struct ble_gap_event *event, void *arg) +{ + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + /* A new connection was established or a connection attempt failed. */ + if (event->connect.status == 0) { + ++tx_stress_ctx->con_stat[13].num; + MODLOG_DFLT(INFO, "Success to connect to device\n"); + tx_stress_ctx->conn_handle = event->connect.conn_handle; + } else { + MODLOG_DFLT(INFO, "\033[0;31mError: connection attempt failed; " + "status=%d\033[0m\n", event->connect.status); + assert(0); + } + return 0; + + case BLE_GAP_EVENT_DISCONNECT: + MODLOG_DFLT(INFO, "Disconnect; reason=%d \n", + event->disconnect.reason); + /* Finish test after disconnection */ + tx_stress_on_test_finish(13); + return 0; + + case BLE_GAP_EVENT_NOTIFY_RX: + MODLOG_DFLT(INFO, "Notify RX event\n"); + console_printf("\033[0;32m>\033[0m"); + os_mbuf_free_chain(event->notify_rx.om); + ++tx_stress_ctx->rcv_num; + return 0; + + default: + MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + return 0; + } +} + +static int +tx_stress_14_subs_cb(uint16_t conn_handle, const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, void *arg) +{ + struct os_mbuf *om; + bool *sub; + int rc; + + assert(error->status == 0); + + /* If the first subscription after finding cccd */ + if(arg == NULL) { + return 0; + } + + sub = (bool*)arg; + + /* Enable notifications */ + if(*sub == 0) { + *sub = true; + om = ble_hs_mbuf_from_flat( + (uint8_t[]) {0x01, 0x00}, 2); + + tx_stress_ctx->begin_us = tx_stress_ctx->end_us; + + rc = ble_gattc_write(tx_stress_ctx->conn_handle, + tx_stress_ctx->dsc_handle, om, + tx_stress_14_subs_cb, arg); + assert(rc == 0); + } + + return 0; +} + +static void +tx_stress_14_disc_cccd_fn(struct stress_gatt_search_ctx *search_ctx) +{ + int rc; + struct os_mbuf *om; + MODLOG_DFLT(INFO, "CCCD found\n"); + + /* Enable notifications */ + om = ble_hs_mbuf_from_flat((uint8_t[]) {0x01, 0x00}, 2); + tx_stress_ctx->begin_us = os_get_uptime_usec(); + tx_stress_ctx->dsc_handle = search_ctx->dsc_handle; + + rc = ble_gattc_write(tx_stress_ctx->conn_handle, + tx_stress_ctx->dsc_handle, om, + tx_stress_14_subs_cb, NULL); + assert(rc == 0); +} + +static int +tx_stress_14_gap_event(struct ble_gap_event *event, void *arg) +{ + int64_t us = 0; + struct os_mbuf *om; + int rc; + static bool subscribed = true; + + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + /* A new connection was established or a connection attempt failed. */ + if (event->connect.status == 0) { + ++tx_stress_ctx->con_stat[14].num; + MODLOG_DFLT(INFO, "Success to connect to device\n"); + tx_stress_ctx->conn_handle = event->connect.conn_handle; + + /* Find CCCD handle (with default UUID16 = 0x2902) */ + stress_find_dsc_handle(event->connect.conn_handle, + BLE_UUID16_DECLARE(STRESS_GATT_UUID), + BLE_UUID16_DECLARE(STRESS_GATT_NOTIFY_UUID), + BLE_UUID16_DECLARE(0x2902), + &tx_stress_14_disc_cccd_fn); + } else { + MODLOG_DFLT(INFO, "\033[0;31mError: connection attempt failed; " + "status=%d\033[0m\n", event->connect.status); + assert(0); + } + return 0; + + case BLE_GAP_EVENT_DISCONNECT: + MODLOG_DFLT(INFO, "Disconnect; reason=%d \n", + event->disconnect.reason); + /* Calc average notifying time */ + if (tx_stress_ctx->rcv_num > 0) { + tx_stress_ctx->s14_notif_time = tx_stress_ctx->time_sum / + tx_stress_ctx->rcv_num; + } + MODLOG_DFLT(INFO, "Average notification time: %d\n", + tx_stress_ctx->s14_notif_time); + /* Finish test after first disconnection */ + tx_stress_on_test_finish(14); + return 0; + + case BLE_GAP_EVENT_NOTIFY_RX: + tx_stress_ctx->end_us = os_get_uptime_usec(); + MODLOG_DFLT(INFO, "Notify RX event\n"); + + /* Time of data sending */ + us = tx_stress_ctx->end_us - tx_stress_ctx->begin_us; + MODLOG_DFLT(INFO, "Notification time: %lld\n us", us); + + tx_stress_ctx->time_sum += us; + console_printf("\033[0;32m>\033[0m"); + + /* Perform use case specified number of times */ + if (++tx_stress_ctx->rcv_num >= MYNEWT_VAL(BLE_STRESS_REPEAT)) { + rc = ble_gap_terminate(event->notify_rx.conn_handle, + BLE_ERR_REM_USER_CONN_TERM); + MODLOG_DFLT(INFO, "rc=%d\n"); + assert(rc == 0); + return 0; + } + + /* Disable notifications */ + subscribed = false; + om = ble_hs_mbuf_from_flat( + (uint8_t[]) {0x00, 0x00}, 2); + + rc = ble_gattc_write(tx_stress_ctx->conn_handle, + tx_stress_ctx->dsc_handle, om, + tx_stress_14_subs_cb, &subscribed); + assert(rc == 0); + return 0; + + default: + MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + return 0; + } +} + +static int +tx_stress_15_write_cb(uint16_t conn_handle, const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, void *arg) +{ + /* Disconnect */ + ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM); + console_printf("\033[0;32m>\033[0m"); + return 0; +} + +static void +tx_stress_15_disc_chr_fn(struct stress_gatt_search_ctx *search_ctx) +{ + int rc; + struct os_mbuf *om; + + /* Send some data */ + MODLOG_DFLT(INFO, "Write to chr\n"); + om = ble_hs_mbuf_from_flat(test_6_pattern, 20); + + rc = ble_gattc_write(tx_stress_ctx->conn_handle, + search_ctx->chr_start_handle, om, + tx_stress_15_write_cb, NULL); + assert(rc == 0); +} + +static int +tx_stress_15_gap_event(struct ble_gap_event *event, void *arg) +{ + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + /* A new connection was established or a connection attempt failed. */ + if (event->connect.status == 0) { + MODLOG_DFLT(INFO, "Success to connect to device; num: %d\n", + ++tx_stress_ctx->con_stat[15].num); + tx_stress_ctx->conn_handle = event->connect.conn_handle; + + /* Find characteristic handle */ + stress_find_chr_handle(event->connect.conn_handle, + BLE_UUID16_DECLARE(STRESS_GATT_UUID), + BLE_UUID16_DECLARE(STRESS_GATT_WRITE_UUID), + &tx_stress_15_disc_chr_fn); + } else { + MODLOG_DFLT(INFO, "\033[0;31mError: connection attempt failed; " + "status=%d\033[0m\n", event->connect.status); + assert(0); + } + return 0; + + case BLE_GAP_EVENT_DISCONNECT: + /* Perform use case specified number of times */ + if(tx_stress_ctx->con_stat[15].num >= MYNEWT_VAL(BLE_STRESS_REPEAT)) { + tx_stress_on_test_finish(15); + return 0; + } + /* Reconnect */ + tx_stress_simple_connect(tx_stress_15_gap_event, 15); + return 0; + + default: + MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + return 0; + } +} + +static int +scan_for_test_gap_event(struct ble_gap_event *event, void *arg) +{ + int use_case; + int rc; + + switch (event->type) { + case BLE_GAP_EVENT_EXT_DISC: + /* Check if caught advert contains known UUID128. The UUID128 + * contains the ID of test use case to be executed. */ + use_case = tx_stress_find_test(&event->ext_disc); + if (use_case > 0) { + rc = ble_gap_disc_cancel(); + tx_stress_ctx->dev_addr = event->ext_disc.addr; + + /* After discovery cancel there are still some events in queue. */ + if (rc == 0) { + tx_stress_use_case = use_case; + /* Add token to semaphore. Main task will start the test. */ + os_sem_release(&tx_stress_main_sem); + } + } + return 0; + + case BLE_GAP_EVENT_DISC_COMPLETE: + /* On timeout */ + tx_stress_ctx->scan_timeout = true; + console_printf("\033[1;36mDiscover complete\033[0m\n"); + os_sem_release(&tx_stress_main_sem); + return 0; + + default: + MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + return 0; + } +} + +static void +tx_stress_test_perform(int test_num) +{ + /* Perform every test only once */ +// if (test_num <= 0 || tx_stress_ctx->completed[test_num] == true) { +// return; +// } + + tx_stress_ctx->cur_test_id = test_num; + tx_stress_ctx->completed[test_num] = false; + tx_stress_ctx->conn_handle = 0xffff; + + console_printf("\033[1;36mStart test num %d - ", test_num); + + /* Start test */ + switch (test_num) { + case 0: + return; + case 1: + console_printf("Stress Connect -> Connect Cancel\033[0m\n"); + tx_stress_1_test(); + break; + case 2: + console_printf("Stress Connect/Disconnect legacy\033[0m\n"); + tx_stress_simple_connect(&tx_stress_2_gap_event, 2); + break; + case 3: + console_printf("Stress Connect/Disconnect ext adv\033[0m\n"); + tx_stress_simple_connect(&tx_stress_3_gap_event, 3); + break; + case 4: + console_printf("Stress connection params update (TX)\033[0m\n"); + tx_stress_simple_connect(&tx_stress_4_gap_event, 4); + break; + case 5: + console_printf("Stress connection params update (RX)\033[0m\n"); + tx_stress_simple_connect(&tx_stress_5_gap_event, 5); + break; + case 6: + console_printf("Stress Scan\033[0m\n"); + tx_stress_6_perform(); + break; + case 7: + console_printf("Stress PHY Update (TX)\033[0m\n"); + tx_stress_simple_connect(&tx_stress_7_gap_event, 7); + break; + case 8: + console_printf("Stress PHY Update (RX)\033[0m\n"); + tx_stress_simple_connect(&tx_stress_8_gap_event, 8); + break; + case 9: + console_printf("Stress multi connection\033[0m\n"); + tx_stress_9_perform(); + break; + case 10: + console_printf("Stress L2CAP send\033[0m\n"); + tx_stress_simple_connect(&tx_stress_10_gap_event, 10); + break; + case 11: + console_printf("Stress Advertise/Connect/Disconnect\033[0m\n"); + tx_stress_simple_connect(&tx_stress_11_gap_event, 11); + break; + case 12: + console_printf("Stress GATT indication\033[0m\n"); + tx_stress_simple_connect(&tx_stress_12_gap_event, 12); + break; + case 13: + console_printf("Stress GATT notification\033[0m\n"); + tx_stress_simple_connect(&tx_stress_13_gap_event, 13); + break; + case 14: + console_printf("Stress GATT Subscribe/Notify/Unsubscribe\033[0m\n"); + tx_stress_simple_connect(&tx_stress_14_gap_event, 14); + break; + case 15: + console_printf("Stress Connect/Send/Disconnect\033[0m\n"); + tx_stress_simple_connect(&tx_stress_15_gap_event, 15); + break; + default: + console_printf("\033[0;31mFound test, but do not know how to perform." + "\033[0m\n"); + assert(0); + } + + /* Wait for the test to finish. Then 1 token will be released + * allowing to pass through semaphore. */ + os_sem_pend(&tx_stress_main_sem, OS_TIMEOUT_NEVER); + + stress_clear_ctx_reusable_var(tx_stress_ctx); +} + +static void +tx_stress_read_command_cb(void) { + console_printf("Start testing\n"); + os_sem_release(&tx_stress_main_sem); +} + +static void +tx_stress_main_task_fn(void *arg) +{ + int rc; + + tx_stress_ctx = &tx_stress_ctxD; + + console_printf("\033[1;36mTX device\033[0m\n"); + console_printf("Press ENTER to start: \n"); + console_init(&tx_stress_read_command_cb); + + /* Waite for pressing ENTER in console */ + os_sem_pend(&tx_stress_main_sem, OS_TIMEOUT_NEVER); + + /* Init semaphore with 0 tokens. */ + rc = os_sem_init(&tx_stress_main_sem, 0); + assert(rc == 0); + + /* Start test 1 - Connect/Connect cancel */ + //tx_stress_test_perform(1); + + while (1) { + console_printf("\033[0;36mStart scan for test\033[0m\n"); + + /* Scan for known UUID128 of one of the stress tests. */ + tx_stress_simple_scan(scan_for_test_gap_event, 2000); + + /* Wait for the scan to find the test. Then 1 token will be + * released allowing to pass through semaphore. */ + os_sem_pend(&tx_stress_main_sem, OS_TIMEOUT_NEVER); + if(tx_stress_ctx->scan_timeout) { + break; + } + + /* Start test. */ + tx_stress_test_perform(tx_stress_use_case); + tx_stress_use_case = -1; + } + + /* Print tests results */ + com_stress_print_report(tx_stress_ctx); + + /* Task should never return */ + while (1) { + /* Delay used only to prevent watchdog to reset the device. */ + os_time_delay(os_time_ms_to_ticks32(2000)); + } +} + +void tx_stress_start_auto() +{ + /* Start task that will run all stress tests one by one. */ + os_task_init(&tx_stress_main_task, "tx_stress_main_task", + tx_stress_main_task_fn, NULL, TX_STRESS_MAIN_TASK_PRIO, + OS_WAIT_FOREVER, tx_stress_main_task_stack, + TX_STRESS_MAIN_TASK_STACK_SIZE); +} diff --git a/src/libs/mynewt-nimble/apps/blestress/src/tx_stress.h b/src/libs/mynewt-nimble/apps/blestress/src/tx_stress.h new file mode 100644 index 00000000..83ed3020 --- /dev/null +++ b/src/libs/mynewt-nimble/apps/blestress/src/tx_stress.h @@ -0,0 +1,49 @@ +/* + * 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. + */ + +#ifndef _BLE_STRESS_TX_H +#define _BLE_STRESS_TX_H + +#include <assert.h> +#include <string.h> +#include <host/ble_gap.h> +#include <stdlib.h> + +/* BLE */ +#include "nimble/ble.h" +#include "host/ble_hs.h" + +#include "misc.h" +#include "stress.h" +#include "stress_gatt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Scan and execute tests one by one. + */ +void tx_stress_start_auto(); + +#ifdef __cplusplus +} +#endif + +#endif //_BLE_STRESS_TX_H |