/* * 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" static struct os_callout stress_timer_callout; 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[0], STRESS_PAT_LEN); if (rc) { os_mbuf_free_chain(om); assert(0); } } rc = os_mbuf_append(om, &test_6_pattern[0], 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); }