Преглед изворни кода

ble_mesh: add ble mesh coex test example

wangcheng пре 6 година
родитељ
комит
a8035d21ef
25 измењених фајлова са 2564 додато и 0 уклоњено
  1. 8 0
      examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/CMakeLists.txt
  2. 8 0
      examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/Makefile
  3. 107 0
      examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/README.md
  4. 12 0
      examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/components/case/CMakeLists.txt
  5. 253 0
      examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/components/case/ble_unit.c
  6. 57 0
      examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/components/case/ble_unit.h
  7. 7 0
      examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/components/case/component.mk
  8. 291 0
      examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/components/case/run_tc.c
  9. 56 0
      examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/components/case/run_tc.h
  10. 542 0
      examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/components/case/sync.c
  11. 122 0
      examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/components/case/sync.h
  12. 128 0
      examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/components/case/test_env.c
  13. 43 0
      examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/components/case/test_env.h
  14. 158 0
      examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/components/case/wifi_connect.c
  15. 22 0
      examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/components/case/wifi_connect.h
  16. 187 0
      examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/components/case/wifi_unit.c
  17. 38 0
      examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/components/case/wifi_unit.h
  18. 6 0
      examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/main/CMakeLists.txt
  19. 70 0
      examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/main/Kconfig.projbuild
  20. 168 0
      examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/main/coex_cmd.c
  21. 16 0
      examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/main/coex_cmd.h
  22. 5 0
      examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/main/component.mk
  23. 145 0
      examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/main/main.c
  24. 5 0
      examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/partitions.csv
  25. 110 0
      examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/sdkconfig.defaults

+ 8 - 0
examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/CMakeLists.txt

@@ -0,0 +1,8 @@
+# The following lines of boilerplate have to be in your project's CMakeLists
+# in this exact order for cmake to work correctly
+cmake_minimum_required(VERSION 3.5)
+
+
+include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+set(SUPPORTED_TARGETS esp32)
+project(ble_mesh_coex_test)

+ 8 - 0
examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/Makefile

@@ -0,0 +1,8 @@
+#
+# This is a project Makefile. It is assumed the directory this Makefile resides in is a
+# project subdirectory.
+#
+
+PROJECT_NAME := ble_mesh_coex_test
+
+include $(IDF_PATH)/make/project.mk

+ 107 - 0
examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/README.md

@@ -0,0 +1,107 @@
+# Example of BLE Mesh and TCP Server/Client Coexistence
+
+This example introduces how to test the basic functions of `BLE Mesh data interface` and `TCP Server/Client Coexistence`. `BLE Mesh data interface` is GAP scanning and advertising.
+
+There are two working modes here:
+
+ * In automatic mode, the program coordinates three development boards working through a synchronization mechanism.
+
+ * In manual mode, you will work with three development boards via commands
+
+
+## Test Preparation
+
+* Before running the test, you need to prepare a router and three ESP32 development boards. This Example of BLE Mesh and TCP Server/Client Coexistence has the following three items, and any of the three development boards is for running one specific item.
+
+  * ble_dev : Run only the BLE  program.
+  * coex_dev: Run BLE  and Wi-Fi program.
+  * wifi_dev: Run only the Wi-Fi program.
+
+``Note: If you want better performance in BLE and WiFi coexistence, you should use a development board with PSRAM that could run a coexistence program. Such as ESP32_LyraT, ESP32-WROVER-B and etc.`` 
+
+* The following structure shows the parameters you need to configure. And usually, there are two methods for configuration, i.e. configuring during initialization or configuring with the command `env`.
+
+```c
+coex_test_env_t test_env = {
+#if defined(CONFIG_EXAMPLE_MANAUL)
+    .ap_ssid = CONFIG_EXAMPLE_WIFI_SSID,
+    .ap_password = CONFIG_EXAMPLE_WIFI_PASSWORD,
+#endif
+#if defined(CONFIG_EXAMPLE_COEX_ROLE)
+    .ap_ssid = CONFIG_EXAMPLE_WIFI_SSID,
+    .ap_password = CONFIG_EXAMPLE_WIFI_PASSWORD,
+#endif
+    .test_port = "8080",
+    .server_ip = "192.168.3.32",
+    .duration = "120000",
+    .is_start = false,
+};
+```
+
+
+## Run Test Case Manually
+Configure to Manual Mode via `Example Configuration  --->run mode (manual) `
+
+The meaning of the numeric argument of the command `run_tc` is as follows:
+
+| id | case name | description |
+|:-:|:-|:-|
+| 0 | wifi_tcp_tx_throughput| Test the case of Wi-Fi tcp tx, which will create a tcp client that will continuously send data to the tcp server. |
+| 1 |wifi_tcp_rx_throughput| Test the case of Wi-Fi tcp rx, which will create a tcp server that will continuously receive data from the tcp client.  |
+| 2 | ble_adv  | Test the case of BLE advertising. |
+| 3 | ble_scan| Test the case of BLE Scan.|
+
+
+###  Case 1: tcp tx + scan  
+1. wifi_dev: run_tc -w 1
+2. coex_dev: env -s -k server_ip -v 192.168.3.34       run_tc -w 0 -b 3
+3. ble_dev : run_tc -b 2	
+
+
+### Case 2: tcp rx + scan
+1.  coex_dev:  run_tc -w 1 -b 3 
+2.  wifi_dev:  env -s -k server_ip -v 192.168.3.34     run_tc -w 0
+3.  ble_dev :  run_tc -b 2
+
+### Case 3: tcp tx + adv
+1.  wifi_dev:  run_tc -w 1
+2.  coex_dev:  env -s -k server_ip -v 192.168.3.13     run_tc -w 0 -b 2 
+3.  ble_dev :  run_tc -b 3
+
+
+### Case 4: tcp rx + adv
+1. coex_dev:  run_tc -w 1 -b 2
+2. wifi_dev:  env -s -k server_ip -v 192.168.3.34       run_tc -w 0
+3. ble_dev :  run_tc -b 3
+
+## Run Test Case By Automation
+Configure to Automatic Mode via `Example Configuration  --->run mode (auto) `
+
+### Coexistence device configuration
+1. Select a development board as coexistence role by `Example Configuration  --->select role (run device as coex role) `
+2. Select a test case by `Example Configuration  --->select case `. 
+* There are four types of cases:
+    * TCP TX and BLE ADV:  The TCP client will be created on the coexistence device, and bluetooth will start advertising when the Wi-Fi is running tx throughput program.
+    * TCP RX and BLE ADV:  The TCP server will be created on the coexistence device, and bluetooth will start advertising when the Wi-Fi is running rx throughput program.
+    * TCP TX and BLE SCAN: The TCP client will be created on the coexistence device, and bluetooth will start scanning when the Wi-Fi is running tx throughput program.
+    * TCP RX and BLE SCAN: The TCP server will be created on the coexistence device, and bluetooth will start scanning when the Wi-Fi is running rx throughput program.
+
+### Bluetooth device configuration
+1. Select a development board as bluetooth role by `select role (run device as bluetooth role) `
+
+### Wi-Fi device configuration
+1. Select a development board as bluetooth role by `select role (run device as wifi role) `
+
+
+## Coexistence Configuration
+In theory, the performance of BLE and Wi-Fi coexistence will drop to half of the performance in BLE Only mode or Wi-Fi Only mode.
+
+* ESP32 working frequency:
+    * Component config  --->  ESP32-specific  --->  CPU frequency (240 MHz) 
+
+* ESP32 external PSRAM
+    * Component config  --->  ESP32-specific  --->  Support for external, SPI-connected RAM
+    * Devices that do not support PSRAM cannot open this option!
+
+* ESP32 coexistence mode
+    * Component config  --->  Wi-Fi  --->   WiFi/Bluetooth coexistence performance preference (Balance)

+ 12 - 0
examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/components/case/CMakeLists.txt

@@ -0,0 +1,12 @@
+set(COMPONENT_SRCS  "ble_unit.c"
+    "run_tc.c"
+    "sync.c"
+    "test_env.c"
+    "wifi_connect.c"
+    "wifi_unit.c")
+
+set(COMPONENT_ADD_INCLUDEDIRS .)
+
+set(COMPONENT_REQUIRES  console nvs_flash bt)
+set(SUPPORTED_TARGETS esp32)
+register_component()

+ 253 - 0
examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/components/case/ble_unit.c

@@ -0,0 +1,253 @@
+/* ESP BLE Mesh Example
+
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#include "ble_unit.h"
+#include "sync.h"
+#define TAG "BLE_UINT"
+
+#define GAP_TRANS_DEFAULT_SHORT_TO      50  // 50ms for events expected to reported as soon as API called
+
+static uint8_t default_adv_data[] = {
+    0x02, 0x01, 0x06,
+    0x02, 0x0a, 0xeb, 0x03, 0x03, 0xab, 0xcd
+};
+static uint8_t default_scan_rsp_data[] = {
+    0x0f, 0x09, 0x45, 0x53, 0x50, 0x5f, 0x47, 0x41, 0x54, 0x54, 0x53, 0x5f, 0x43,
+    0x4f, 0x45, 0x58
+};
+
+esp_ble_scan_params_t default_scan_param = {
+    .scan_type              = BLE_SCAN_TYPE_ACTIVE,
+    .own_addr_type          = BLE_ADDR_TYPE_PUBLIC,
+    .scan_filter_policy     = BLE_SCAN_FILTER_ALLOW_ALL,
+    .scan_interval          = 0x100,
+    .scan_window            = 0x100
+};
+
+esp_ble_adv_params_t default_adv_param = {
+    .adv_int_min        = 0x40,
+    .adv_int_max        = 0x40,
+    .adv_type           = ADV_TYPE_IND,
+    .own_addr_type      = BLE_ADDR_TYPE_PUBLIC,
+    .channel_map        = ADV_CHNL_ALL,
+    .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
+};
+
+ble_util_scan_count_t scan_count;
+
+static void ble_gap_event_default_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
+{
+    switch (event) {
+    case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: {
+        if (param->scan_param_cmpl.status != ESP_BT_STATUS_SUCCESS) {
+            ESP_LOGE(TAG, "set scan parameter failed, error status = %x", param->scan_param_cmpl.status);
+        }
+        break;
+    }
+    case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT: {
+        if (param->adv_data_raw_cmpl.status != ESP_BT_STATUS_SUCCESS) {
+            ESP_LOGE(TAG, "set row data failed, error status = %x", param->adv_data_raw_cmpl.status);
+        }
+        break;
+    }
+    case ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT: {
+        if (param->scan_rsp_data_raw_cmpl.status != ESP_BT_STATUS_SUCCESS) {
+            ESP_LOGE(TAG, "set scan response data failed, error status = %x", param->scan_rsp_data_raw_cmpl.status);
+        }
+        break;
+    }
+    case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: {
+        if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) {
+            ESP_LOGE(TAG, "Advertising start failed\n");
+        }
+        break;
+    }
+    case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT:
+        if (param->adv_stop_cmpl.status != ESP_BT_STATUS_SUCCESS) {
+            ESP_LOGE(TAG, "Advertising stop failed\n");
+        }
+        break;
+    case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT: {
+        if (param->scan_start_cmpl.status != ESP_BT_STATUS_SUCCESS) {
+            ESP_LOGE(TAG, "scan start failed, error status = %x", param->scan_start_cmpl.status);
+        }
+        break;
+    }
+    case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT:
+        if (param->scan_stop_cmpl.status != ESP_BT_STATUS_SUCCESS) {
+            ESP_LOGE(TAG, "scan stop failed, error status = %x", param->scan_stop_cmpl.status);
+        }
+        break;
+    default:
+        break;
+    }
+}
+
+static void ble_gap_util_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
+{
+    if (sync_obj.cmd_recv != NULL) {
+        sync_obj.cmd_recv(param->scan_rst.ble_adv, param->scan_rst.adv_data_len);
+    }
+
+    switch (event) {
+    case ESP_GAP_BLE_SCAN_RESULT_EVT:
+        switch (param->scan_rst.search_evt) {
+        case ESP_GAP_SEARCH_INQ_RES_EVT:
+            if (param->scan_rst.adv_data_len > 0 \
+                    &&  (memcmp(default_adv_data, param->scan_rst.ble_adv, sizeof(default_adv_data)) == 0)) {
+                scan_count.adv_count += 1;
+                if (scan_count.adv_count % 10 == 0) {
+                    ESP_LOGI(TAG, "adv count:%d scan_res count %d\n", scan_count.adv_count, scan_count.scan_res_count);
+                }
+            }
+
+            if (param->scan_rst.scan_rsp_len > 0 \
+                    && (memcmp(default_scan_rsp_data, (param->scan_rst.ble_adv + param->scan_rst.adv_data_len), sizeof(default_scan_rsp_data)) == 0)) {
+                scan_count.scan_res_count += 1;
+            }
+            break;
+        default:
+            break;
+        }
+        break;
+    default:
+        ble_gap_event_default_handler(event, param);
+        break;
+    }
+}
+
+
+esp_err_t ble_gap_util_set_adv_data(uint8_t *adv_data, uint32_t adv_data_len, uint8_t *scan_rsp_data, uint32_t scan_rsp_data_len)
+{
+    esp_err_t ret;
+
+    ret = esp_ble_gap_config_adv_data_raw(adv_data, adv_data_len);
+    if (ret != ESP_OK) {
+        ESP_LOGE(TAG, "esp_ble_gap_config_adv_data_raw error, %d", ret);
+        return ret;
+    }
+    ret = esp_ble_gap_config_scan_rsp_data_raw(scan_rsp_data, scan_rsp_data_len);
+    if (ret != ESP_OK) {
+        ESP_LOGE(TAG, "esp_ble_gap_config_scan_rsp_data_raw error, %d", ret);
+        return ret;
+    }
+    return 0;
+}
+
+esp_err_t ble_gap_util_set_default_adv_data(void)
+{
+    return ble_gap_util_set_adv_data(default_adv_data, sizeof(default_adv_data), default_scan_rsp_data, sizeof(default_scan_rsp_data));
+}
+
+esp_err_t ble_gap_util_start_adv(esp_ble_adv_params_t *adv_param)
+{
+    esp_err_t ret;
+    ret = esp_ble_gap_start_advertising(adv_param);
+    if (ret != ESP_OK) {
+        ESP_LOGE(TAG, "esp_ble_gap_start_advertising error, %d", ret);
+        return ret;
+    }
+    return 0;
+}
+
+esp_err_t ble_gap_util_start_adv_default(void)
+{
+    esp_err_t ret;
+
+    ret = esp_ble_gap_start_advertising(&default_adv_param);
+    if (ret != ESP_OK) {
+        ESP_LOGE(TAG, "esp_ble_gap_start_advertising error, %d", ret);
+        return ret;
+    }
+    return 0;
+}
+
+esp_err_t ble_gap_util_stop_adv(void)
+{
+    esp_err_t ret;
+    ret = esp_ble_gap_stop_advertising();
+    if (ret != ESP_OK) {
+        ESP_LOGE(TAG, "esp_ble_gap_stop_advertising error, %d", ret);
+        return ret;
+    }
+    return 0;
+}
+
+esp_err_t ble_gap_util_set_scan_param(esp_ble_scan_params_t *scan_param)
+{
+    esp_err_t ret;
+    ret = esp_ble_gap_set_scan_params(scan_param);
+    if (ret != ESP_OK) {
+        ESP_LOGE(TAG, "esp_ble_gap_set_scan_params error, %d", ret);
+        return ret;
+    }
+    return 0;
+}
+
+esp_err_t ble_gap_util_set_default_scan_param(void)
+{
+    return ble_gap_util_set_scan_param(&default_scan_param);
+}
+
+esp_err_t ble_gap_util_start_scan(uint32_t duration)
+{
+    esp_err_t ret;
+    ret = esp_ble_gap_start_scanning(duration);
+    if (ret != ESP_OK) {
+        ESP_LOGE(TAG, "esp_ble_gap_start_scanning error, %d", ret);
+        return ret;
+    }
+    return 0;
+}
+
+esp_err_t ble_gap_util_stop_scan(void)
+{
+    esp_err_t ret;
+    ret = esp_ble_gap_stop_scanning();
+    if (ret != ESP_OK) {
+        ESP_LOGE(TAG, "esp_ble_gap_stop_scanning error, %d", ret);
+        return ret;
+    }
+    return 0;
+}
+
+
+void ble_gap_util_stop(void)
+{
+    ble_gap_util_stop_adv();
+    ble_gap_util_stop_scan();
+}
+
+esp_err_t init_ble_gap_test_util(void)
+{
+    esp_err_t ret;
+    ret = esp_ble_gap_register_callback(ble_gap_util_handler);
+    if (ret) {
+        ESP_LOGE(TAG, "gap register error, error code = %x", ret);
+    }
+    return ret;
+}
+
+void bt_test_init(void)
+{
+    ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
+    esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
+    ESP_ERROR_CHECK(esp_bt_controller_init(&bt_cfg));
+    ESP_ERROR_CHECK(esp_bt_controller_enable(ESP_BT_MODE_BLE));
+    ESP_ERROR_CHECK(esp_bluedroid_init());
+    ESP_ERROR_CHECK(esp_bluedroid_enable());
+}
+
+void bt_test_deinit(void)
+{
+    esp_bluedroid_disable();
+    esp_bluedroid_deinit();
+    esp_bt_controller_disable();
+    esp_bt_controller_deinit();
+}

+ 57 - 0
examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/components/case/ble_unit.h

@@ -0,0 +1,57 @@
+/* ESP BLE Mesh Example
+
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#ifndef _BLE_UNIT_H_
+#define _BLE_UNIT_H_
+#include <stdio.h>
+#include <string.h>
+#include "esp_system.h"
+#include "esp_timer.h"
+#include "esp_log.h"
+#include "nvs_flash.h"
+#include "esp_bt.h"
+
+#include "esp_gap_ble_api.h"
+#include "esp_gatts_api.h"
+#include "esp_gattc_api.h"
+#include "esp_bt_defs.h"
+#include "esp_bt_main.h"
+#include "esp_gatt_common_api.h"
+
+#define BLE_TC_SCAN_REPORT_PERIOD           10000
+
+typedef struct {
+    uint32_t adv_count;
+    uint32_t scan_res_count;
+} ble_util_scan_count_t;
+
+
+extern esp_bd_addr_t bt_addr;
+extern ble_util_scan_count_t scan_count;
+extern esp_ble_adv_params_t default_adv_param;
+extern esp_ble_scan_params_t default_scan_param;
+
+void bt_test_init(void);
+void bt_test_deinit(void);
+void ble_gap_util_stop(void);
+
+esp_err_t ble_gap_util_set_adv_data(uint8_t *adv_data, uint32_t adv_data_len, uint8_t *scan_rsp_data, uint32_t scan_rsp_data_len);
+esp_err_t ble_gap_util_set_default_adv_data(void);
+esp_err_t ble_gap_util_start_adv(esp_ble_adv_params_t *adv_param);
+esp_err_t ble_gap_util_start_adv_default(void);
+esp_err_t ble_gap_util_stop_adv(void);
+
+esp_err_t ble_gap_util_set_scan_param(esp_ble_scan_params_t *scan_param);
+esp_err_t ble_gap_util_set_default_scan_param(void);
+esp_err_t ble_gap_util_start_scan(uint32_t duration);
+esp_err_t ble_gap_util_stop_scan(void);
+
+esp_err_t init_ble_gap_test_util(void);
+
+#endif /* _BLE_UNIT_H_ */

+ 7 - 0
examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/components/case/component.mk

@@ -0,0 +1,7 @@
+#
+# Component Makefile
+#
+
+COMPONENT_SRCDIRS := .
+
+COMPONENT_ADD_INCLUDEDIRS = .

+ 291 - 0
examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/components/case/run_tc.c

@@ -0,0 +1,291 @@
+/* ESP BLE Mesh Example
+
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#include "run_tc.h"
+#include "test_env.h"
+#include "wifi_unit.h"
+#include "ble_unit.h"
+#include "sync.h"
+#include "wifi_connect.h"
+
+#define TAG "CASE"
+
+xQueueHandle xTaskQueue = 0;
+
+static const char *coex_get_case_env(coex_test_env_t *test_env, const char *keyword)
+{
+    const char *ret = NULL;
+    if (!strcmp(keyword, "ap_ssid")) {
+        ret = test_env->ap_ssid;
+    } else if (!strcmp(keyword, "ap_password")) {
+        ret = test_env->ap_password;
+    } else if (!strcmp(keyword, "test_port")) {
+        ret = test_env->test_port;
+    } else if (!strcmp(keyword, "server_ip")) {
+        ret = test_env->server_ip;
+    } else if (!strcmp(keyword, "duration")) {
+        ret = test_env->duration;
+    }
+
+    return ret;
+}
+
+static void wifi_tc_sta_throughput_timeout(void *arg)
+{
+    static uint32_t statistic_count  = 0;
+    static uint64_t accumulate_speed = 0;
+
+    uint32_t now = utils_get_system_ts();
+    uint32_t *report = (uint32_t *) arg;
+    uint32_t last_timestamp = report[0];
+
+    if (now > last_timestamp) {
+        uint32_t speed = report[1] * 8 / (now - last_timestamp);
+        accumulate_speed += speed;
+        statistic_count += 1;
+        printf("speed: %d kbps average speed: %lld kbps\n", speed, accumulate_speed / statistic_count );
+        report[1] = 0;
+        report[0] = now;
+    }
+}
+
+static esp_err_t create_statistic_timer(esp_timer_handle_t *timer_hdl , uint32_t statistic_date[])
+{
+    esp_err_t ret;
+    esp_timer_create_args_t tca = {
+        .callback = (esp_timer_cb_t)wifi_tc_sta_throughput_timeout,
+        .dispatch_method = ESP_TIMER_TASK,
+        .name = "TCP_STATISTIC",
+    };
+    tca.arg = statistic_date;
+    ret = esp_timer_create(&tca, timer_hdl);
+    if (ret != ESP_OK) {
+        ESP_LOGE(TAG, "statistic_timer create failed");
+        return ret;
+    }
+    esp_timer_start_periodic(*timer_hdl, 1000000); //1000ms
+    return ret;
+}
+
+
+void wifi_tcp_tx_throught_start(void *param)
+{
+    esp_timer_handle_t timer_hdl = NULL;
+    esp_err_t ret;
+    int sock = -1;
+    uint32_t statistic_date[2] = {0};
+
+    const char *ssid   = coex_get_case_env(param, "ap_ssid");
+    const char *passwd = coex_get_case_env(param, "ap_password");
+
+
+    wifi_util_init();
+    // wifi_unit_connect_ap(ssid, passwd);
+    example_connect(ssid, passwd);
+
+#if defined(CONFIG_EXAMPLE_AUTO)
+    if (((coex_test_env_t *)param)->run_mutex != NULL) {
+        //This will be blocked by the sync timer.
+        xSemaphoreTake(((coex_test_env_t *)param)->run_mutex, portMAX_DELAY);
+        xSemaphoreGive(((coex_test_env_t *)param)->run_mutex);
+    }
+#endif
+    const char *ip = coex_get_case_env(param, "server_ip");
+    const char *port = coex_get_case_env(param, "test_port");
+    const char *duration = coex_get_case_env(param, "duration");
+    wifi_unit_client_establish(&sock, ip, port);
+
+    ret = create_statistic_timer(&timer_hdl, statistic_date);
+    if (ret != ESP_OK) {
+        ESP_LOGE(TAG, "statistic_timer create failed");
+        goto _stop;
+    }
+
+    ret = wifi_util_tcp_send(sock, 1460, 0, &statistic_date[1], atoi(duration));
+    if (ret != ESP_OK) {
+        ESP_LOGE(TAG, "send failed, %x", ret);
+    }
+
+_stop:
+    if (timer_hdl) {
+        esp_timer_stop(timer_hdl);
+        esp_timer_delete(timer_hdl);
+    }
+
+    if (sock > 0) {
+        close(sock);
+    }
+}
+
+void wifi_tcp_tx_throught_end(void)
+{
+    esp_wifi_disconnect();
+}
+
+void wifi_tcp_rx_throught_start(void *param)
+{
+    esp_timer_handle_t timer_hdl = NULL;
+    esp_err_t ret;
+    int sock = -1;
+    uint32_t statistic_date[2] = {0};
+
+    const char *ssid   = coex_get_case_env(param, "ap_ssid");
+    const char *passwd = coex_get_case_env(param, "ap_password");
+    const char *port = coex_get_case_env(param, "test_port");
+    const char *duration = coex_get_case_env(param, "duration");
+
+    wifi_util_init();
+    // wifi_unit_connect_ap(ssid, passwd);
+    example_connect(ssid, passwd);
+    wifi_unit_server_establish( &sock, port);
+
+    ret = create_statistic_timer(&timer_hdl, statistic_date);
+    if (ret != ESP_OK) {
+        ESP_LOGE(TAG, "statistic_timer create failed");
+        goto _stop;
+    }
+    ret = wifi_unit_tcp_recv(sock, duration, statistic_date);
+    if (ret != ESP_OK) {
+        ESP_LOGE(TAG, "tcp receive failed");
+        goto _stop;
+    }
+_stop:
+    if (timer_hdl) {
+        esp_timer_stop(timer_hdl);
+        esp_timer_delete(timer_hdl);
+    }
+
+    if (sock > 0) {
+        close(sock);
+    }
+}
+
+void wifi_tcp_rx_throught_end(void)
+{
+    esp_wifi_disconnect();
+}
+
+void ble_adv_start(void *param)
+{
+    esp_err_t ret;
+    const char *duration = coex_get_case_env(param, "duration");
+#if defined(CONFIG_EXAMPLE_MANAUL)
+    bt_test_init();
+#endif
+    ret = ble_gap_util_set_default_adv_data();
+
+    if (ret != ESP_OK) {
+        ESP_LOGE(TAG, "failed to set adv data");
+        return;
+    }
+
+    ret = ble_gap_util_start_adv(&default_adv_param);
+
+    if (ret != ESP_OK) {
+        ESP_LOGE(TAG, "failed to start adv");
+        return;
+    }
+
+    vTaskDelay(atoi(duration) / portTICK_PERIOD_MS);
+
+}
+
+void ble_adv_end(void)
+{
+    ble_gap_util_stop();
+}
+
+
+void ble_scan_start(void *param)
+{
+    esp_err_t ret;
+#if defined(CONFIG_EXAMPLE_MANAUL)
+    bt_test_init();
+    vTaskDelay(10 / portTICK_PERIOD_MS);
+    init_ble_gap_test_util();
+#endif
+
+
+    ret = ble_gap_util_set_scan_param(&default_scan_param);
+    if (ret != ESP_OK) {
+        ESP_LOGE(TAG, "set scan param fail");
+        return;
+    }
+    vTaskDelay(10 / portTICK_PERIOD_MS);
+
+    scan_count.adv_count = 0;
+    scan_count.scan_res_count = 0;
+
+    ret = esp_ble_gap_start_scanning(BLE_TC_SCAN_REPORT_PERIOD);
+    if (ret != ESP_OK) {
+        ESP_LOGE(TAG, "esp_ble_gap_start_scanning error, %d", ret);
+        return;
+    }
+}
+
+void ble_scan_end(void)
+{
+    ESP_LOGI(TAG, "%s \n", __func__);
+}
+
+tc_t tc_case[] = {
+    DECLARE_TC(TC_WIFI_COEX_TCP_TX_THROUGHPUT, 0, wifi_tcp_tx_throught_start, wifi_tcp_tx_throught_end, (void *)&test_env),
+    DECLARE_TC(TC_WIFI_COEX_TCP_RX_THROUGHPUT, 1, wifi_tcp_rx_throught_start, wifi_tcp_rx_throught_end, (void *)&test_env),
+    DECLARE_TC(TC_BLE_COEX_ADV,                2, ble_adv_start,              ble_adv_end,              (void *)&test_env),
+    DECLARE_TC(TC_BLE_COEX_SCAN,               3, ble_scan_start,             ble_scan_end,             (void *)&test_env),
+};
+
+static void excute_case(void *arg)
+{
+    tc_t *run_case = (tc_t *) arg;
+    if (run_case && run_case->func_start != NULL) {
+        run_case->func_start(run_case->param_list);
+    }
+
+    if (run_case && run_case->func_stop != NULL ) {
+        vTaskDelay(100 / portTICK_RATE_MS);
+        run_case->func_stop();
+    }
+    vTaskDelete(NULL);
+}
+
+static void run_task(void *arg)
+{
+    tc_t *tc_case_table = (tc_t *) arg;
+    run_task_msg_t msg;
+
+    for (;;) {
+        if (pdTRUE == xQueueReceive(xTaskQueue, &msg, (portTickType)portMAX_DELAY)) {
+            if ( msg.case_id < sizeof(tc_case) / sizeof(tc_case[0]) ) {
+                xTaskCreatePinnedToCore(excute_case, tc_case_table->name, 4096, &tc_case_table[msg.case_id], RUN_TASK_PRIORITY, NULL, 0);
+            } else {
+                ESP_LOGW(TAG, "msg.case_id  %d\n", msg.case_id);
+            }
+
+        }
+    }
+    vTaskDelete(NULL);
+}
+
+
+void run_tc_init(void)
+{
+    xTaskQueue = xQueueCreate(RUN_TASK_QUEUE_LEN, sizeof(run_task_msg_t));
+    if (!xTaskQueue) {
+        ESP_LOGE(TAG, "xTaskQueue create failed");
+        return;
+    }
+    xTaskCreatePinnedToCore(run_task, "run_task", 4096, tc_case, RUN_TASK_PRIORITY, NULL, 0);
+}
+
+
+
+
+
+

+ 56 - 0
examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/components/case/run_tc.h

@@ -0,0 +1,56 @@
+/* ESP BLE Mesh Example
+
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#ifndef __RUN_TC_H__
+#define __RUN_TC_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/queue.h"
+
+#define TC_NAME_LEN     63
+typedef void (*tc_func_start_t)(void *param);
+typedef void (*tc_func_end_t)(void);
+
+
+typedef struct tc {
+    char name[TC_NAME_LEN + 1];
+    uint8_t case_id;
+    tc_func_start_t func_start;
+    tc_func_end_t func_stop;
+    void *param_list;
+} tc_t;
+
+
+#define TC_WIFI_COEX_TCP_TX_THROUGHPUT       "TCP_COEX_TX_THROUGHPUT"
+#define TC_WIFI_COEX_TCP_RX_THROUGHPUT       "TCP_COEX_RX_THROUGHPUT"
+#define TC_BLE_COEX_ADV                      "BLE_COEX_ADVERTISING"
+#define TC_BLE_COEX_SCAN                     "BLE_COEX_SCAN"
+
+// run_task queue size
+#define RUN_TASK_QUEUE_LEN   6
+#define RUN_TASK_PRIORITY    18
+
+#define DECLARE_TC(name, id, start_func, stop_func, param_list) \
+    {name, id, start_func, stop_func, param_list}
+
+typedef struct run_task_msg {
+    uint8_t case_id;
+} run_task_msg_t;
+
+extern xQueueHandle xTaskQueue ;
+
+void run_tc_init(void);
+
+#endif /* __RUN_TC_H__ */

+ 542 - 0
examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/components/case/sync.c

@@ -0,0 +1,542 @@
+/* ESP BLE Mesh Example
+
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#include "sync.h"
+#include "run_tc.h"
+#include "wifi_unit.h"
+#define TAG "SYNC"
+
+SemaphoreHandle_t client_mutex;
+
+struct sync_t sync_obj = {
+    .except_recv_wifi_id = false,
+    .except_recv_bt_id   = false,
+    .recv_param_bit = 0x0,
+    .start_time     = 0x0,
+
+#if defined(CONFIG_EXAMPLE_COEX_ROLE)
+    .state = ASSIGN_CASE,
+#else
+    .state = WAIT_CASE,
+#endif
+#if defined(CONFIG_EXAMPLE_COEX_TX_ADV)
+    .own_wifi_case = WIFI_TCP_TX_CASE,
+    .own_ble_case  = BLE_ADV_CASE,
+#elif defined(CONFIG_EXAMPLE_COEX_RX_ADV)
+    .own_wifi_case = WIFI_TCP_RX_CASE,
+    .own_ble_case  = BLE_ADV_CASE,
+#elif defined(CONFIG_EXAMPLE_COEX_TX_SCAN)
+    .own_wifi_case = WIFI_TCP_TX_CASE,
+    .own_ble_case  = BLE_SCAN_CASE,
+#elif defined(CONFIG_EXAMPLE_COEX_RX_SCAN)
+    .own_wifi_case = WIFI_TCP_RX_CASE,
+    .own_ble_case  = BLE_SCAN_CASE,
+#else
+    .own_wifi_case = NOT_CASE,
+    .own_ble_case  = NOT_CASE,
+#endif
+};
+
+
+auto_tc auto_tb[6] = {
+    {WIFI_TCP_TX_CASE,  PARAMTER(0b011011)},     //need paramter: wifi_case_id ssid password server ip
+    {WIFI_TCP_RX_CASE,  PARAMTER(0b010011)},     //need paramter: wifi_case_id ssid password
+    {BLE_ADV_CASE,      PARAMTER(0b100000)},     //need paramter: ble_case_id
+    {BLE_SCAN_CASE,     PARAMTER(0b100000)},     //need paramter: ble_case_id
+};
+
+
+esp_err_t send_adv(uint8_t *raw_data, uint32_t raw_data_len)
+{
+    esp_err_t ret;
+
+    esp_ble_adv_params_t adv_param = {
+        .adv_int_min        = 0x40,
+        .adv_int_max        = 0x40,
+        .adv_type           = ADV_TYPE_NONCONN_IND,
+        .own_addr_type      = BLE_ADDR_TYPE_PUBLIC,
+        .channel_map        = ADV_CHNL_ALL,
+        .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
+    };
+    ret = esp_ble_gap_config_adv_data_raw(raw_data, raw_data_len);
+    if (ret != ESP_OK) {
+        ESP_LOGE(TAG, "esp_ble_gap_config_adv_data_raw error, %d", ret);
+        return ret;
+    }
+
+    ret = esp_ble_gap_start_advertising(&adv_param);
+    if (ret != ESP_OK) {
+        ESP_LOGE(TAG, "esp_ble_gap_start_advertising error, %d", ret);
+        return ret;
+    }
+    vTaskDelay(30 / portTICK_PERIOD_MS);  //every 30ms send one packet
+
+    ret = esp_ble_gap_stop_advertising();
+    if (ret != ESP_OK) {
+        ESP_LOGE(TAG, "esp_ble_gap_stop_advertising error, %d", ret);
+        return ret;
+    }
+    return 0;
+}
+
+esp_err_t send_adv_data(sync_msg *msg)
+{
+    send_adv((uint8_t *)msg, sizeof(sync_msg));
+    return 0;
+}
+
+void send_start_msg(uint8_t start_time)
+{
+    sync_msg msg = {
+        .length = 30,
+        .type   = MSG_TYPE,
+        .head   = MSG_HEAD,
+        .msg_id = 0x4,
+        .ctl  = MSG_CONTINUE,
+        .param_bit = 0b000100 << PARAM_MAX,
+        .reserve   = 0xff,
+        .data = {start_time},
+    };
+    send_adv_data(&msg);
+}
+void send_start_countdown(void)
+{
+    if (sync_obj.except_recv_bt_id == true && sync_obj.except_recv_wifi_id == true) {
+        esp_timer_stop(sync_obj.sync_timer);
+        esp_timer_start_once(sync_obj.sync_timer,  1000000);
+        sync_obj.state = START_CASE;
+    }
+}
+void send_tcp_rx_inited_msg(void)
+{
+    uint8_t hex_ip[4];
+    uint32_t ip = wifi_util_get_ip();
+    memcpy(hex_ip, &ip, sizeof(hex_ip));
+    if (hex_ip[0] == 0x0) {
+        return;
+    }
+    sync_msg msg = {
+        .length = 30,
+        .type   = MSG_TYPE,
+        .head   = MSG_HEAD,
+        .msg_id = MSG_ID_WIFI_DEV_INIT_FINISH,
+        .ctl    = MSG_CONTINUE,
+        .param_bit = 0b001000 << PARAM_MAX,
+        .reserve   = 0xff,
+        .data = {hex_ip[0], hex_ip[1], hex_ip[2], hex_ip[3]},
+    };
+    send_adv_data(&msg);
+}
+void send_case_inited_msg(uint8_t msg_id)
+{
+    sync_msg msg = {
+        .length = 30,
+        .type   = MSG_TYPE,
+        .head = MSG_HEAD,
+        .msg_id = msg_id,
+        .ctl  = MSG_CONTINUE,
+        .param_bit = 0b000000 << PARAM_MAX,
+        .reserve   = 0xff,
+        .data = {0},
+    };
+    send_adv_data(&msg);
+}
+
+void assign_case_to_dev(uint8_t ble_id, uint8_t wifi_id)
+{
+    if ( sync_obj.own_wifi_case == WIFI_TCP_RX_CASE ) {
+        uint8_t hex_ip[4];
+        uint32_t ip = wifi_util_get_ip();
+        ESP_LOGI(TAG, "ip:%s", inet_ntoa(ip));
+        memcpy(hex_ip, &ip, sizeof(hex_ip));
+        if (hex_ip[0] == 0x0) {
+            return;
+        }
+        sync_msg msg = {
+            .length = 30,
+            .type   = MSG_TYPE,
+            .head = MSG_HEAD,
+            .msg_id = 0x1,
+            .ctl  = MSG_CONTINUE,
+            .param_bit = 0b111000 << PARAM_MAX,
+            .reserve   = 0xff,
+            .data = {ble_id, wifi_id, hex_ip[0], hex_ip[1], hex_ip[2], hex_ip[3]},
+        };
+        send_adv_data(&msg);
+    } else if ( sync_obj.own_wifi_case == WIFI_TCP_TX_CASE ) {
+        sync_msg msg1 = {
+            .length = 30,
+            .type   = MSG_TYPE,
+            .head = MSG_HEAD,
+            .msg_id = 0x1,
+            .ctl  = MSG_CONTINUE,
+            .param_bit = 0b110000 << PARAM_MAX,
+            .reserve   = 0xff,
+            .data = {ble_id, wifi_id},
+        };
+        send_adv_data(&msg1);
+    }
+#if defined(CONFIG_EXAMPLE_COEX_ROLE)
+    if (strlen(CONFIG_EXAMPLE_WIFI_SSID) < 20) {
+        sync_msg msg = {
+            .length = 30,
+            .type   = MSG_TYPE,
+            .head = MSG_HEAD,
+            .msg_id = 0x1,
+            .ctl  = MSG_CONTINUE,
+            .param_bit = 0b000010 << PARAM_MAX,
+            .reserve   = 0xff,
+            .data[0] = strlen(CONFIG_EXAMPLE_WIFI_SSID),
+        };
+        for (uint8_t i = 0 ; i < strlen(CONFIG_EXAMPLE_WIFI_SSID); i++) {
+            msg.data[i + 1] = CONFIG_EXAMPLE_WIFI_SSID[i] - '0';
+        }
+        send_adv_data(&msg);
+    }
+
+    if (strlen(CONFIG_EXAMPLE_WIFI_PASSWORD) < 20) {
+        sync_msg msg = {
+            .length = 30,
+            .type   = MSG_TYPE,
+            .head = MSG_HEAD,
+            .msg_id = 0x1,
+            .ctl  = MSG_END,
+            .param_bit = 0b000001 << PARAM_MAX,
+            .reserve   = 0xff,
+            .data[0] = strlen(CONFIG_EXAMPLE_WIFI_PASSWORD),
+        };
+        for (int i = 0 ; i < strlen(CONFIG_EXAMPLE_WIFI_PASSWORD); i++) {
+            msg.data[i + 1] = CONFIG_EXAMPLE_WIFI_PASSWORD[i] - '0';
+        }
+        send_adv_data(&msg);
+    }
+#endif
+}
+
+
+void excute_case(uint8_t run_case)
+{
+    run_task_msg_t msg;
+    msg.case_id = run_case;
+    if (xQueueSend(xTaskQueue, &msg, portMAX_DELAY) != pdTRUE) {
+        ESP_LOGE(TAG, "xTaskQueue Post failed\n");
+    }
+}
+
+
+void assign_test_case(void)
+{
+#if defined(CONFIG_EXAMPLE_COEX_TX_ADV)
+    assign_case_to_dev(BLE_SCAN_CASE, WIFI_TCP_RX_CASE);
+#elif defined(CONFIG_EXAMPLE_COEX_RX_ADV)
+    assign_case_to_dev(BLE_SCAN_CASE, WIFI_TCP_TX_CASE);
+#elif defined(CONFIG_EXAMPLE_COEX_TX_SCAN)
+    assign_case_to_dev(BLE_ADV_CASE, WIFI_TCP_RX_CASE);
+#elif defined(CONFIG_EXAMPLE_COEX_RX_SCAN)
+    assign_case_to_dev(BLE_ADV_CASE, WIFI_TCP_TX_CASE);
+#endif
+}
+
+
+void analys_param(uint16_t param_bit, uint8_t data[], uint16_t *recv_param_bit)
+{
+
+    uint8_t data_ptr = 0;
+
+    for (int i = 0 ; i < PARAM_MAX; i++ ) {
+        switch (GET_PARAM(param_bit, 0x1000 >> i)) {
+        case BLE_CASE_ID:
+            ESP_LOGD(TAG, "BLE_CASE_ID\n");
+#if defined(CONFIG_EXAMPLE_BT_ROLE)
+            sync_obj.own_ble_case = data[data_ptr];
+            (*recv_param_bit) |= BLE_CASE_ID;
+#endif
+            data_ptr += 1;
+            break;
+        case WIFI_CASE_ID:
+            ESP_LOGD(TAG, "WIFI_CASE_ID\n");
+#if defined(CONFIG_EXAMPLE_WIFI_ROLE)
+            sync_obj.own_wifi_case = data[data_ptr];
+            (*recv_param_bit) |= WIFI_CASE_ID;
+#endif
+            data_ptr += 1;
+            break;
+        case START_TIME:
+            ESP_LOGD(TAG, "START_TIME\n");
+            sync_obj.start_time   = data[data_ptr];
+            data_ptr += 1;
+            break;
+        case SERVER_IP: {
+            ESP_LOGD(TAG, "SERVER_IP\n");
+            char server_ip[16];
+            memset(server_ip, '0', sizeof(server_ip));
+            sprintf(server_ip, "%d.%d.%d.%d", data[data_ptr], data[data_ptr + 1], data[data_ptr + 2], data[data_ptr + 3]); // size conversion
+            coex_set_test_env("server_ip", server_ip, sizeof(server_ip));
+            coex_print_test_env();
+            data_ptr += 4;
+            (*recv_param_bit) |= SERVER_IP;
+            break;
+        }
+        case WIFI_SSID: {
+            ESP_LOGD(TAG, "WIFI_SSID\n");
+            uint8_t length = data[data_ptr];
+            data_ptr += 1;
+            if ( length > 20) {
+                ESP_LOGE(TAG, "ssid length error");
+                break;
+            }
+            char *ssid = malloc(length + 1);
+            if (ssid == NULL) {
+                ESP_LOGE(TAG, "%s malloc fail\n", __func__);
+                return ;
+            }
+            memset(ssid, '0', sizeof(length + 1));
+
+            for (int i = length - 1 ; i >= 0 ; i--) {
+                ssid[i] = data[data_ptr + i] + '0';
+            }
+            ssid[length] = '\n';
+            coex_set_test_env("ap_ssid", ssid, length);
+            coex_print_test_env();
+            (*recv_param_bit) |= WIFI_SSID;
+            free(ssid);
+            break;
+        }
+        case WIFI_PASSWIRD: {
+            ESP_LOGD(TAG, "WIFI_PASSWIRD\n");
+            uint8_t length = data[data_ptr];
+            data_ptr += 1;
+            if ( length > 20) {
+                ESP_LOGE(TAG, "password length error");
+                break;
+            }
+            char *password = malloc(length + 1);
+            if (password == NULL) {
+                ESP_LOGE(TAG, "%s malloc fail\n", __func__);
+                return ;
+            }
+            memset(password, '0', sizeof(length + 1));
+            for (int i = length - 1 ; i >= 0 ; i--) {
+                password[i] = data[data_ptr + i] + '0';
+            }
+            password[length] = '\n';
+            coex_set_test_env("ap_password", password, length);
+            coex_print_test_env();
+            (*recv_param_bit) |= WIFI_PASSWIRD;
+            free(password);
+            break;
+        }
+        default:
+            break;
+        }
+    }
+
+}
+
+void sync_cmd_recv(uint8_t *raw_data, uint32_t raw_data_len)
+{
+    if (raw_data_len < MSG_MIN_LEN) {
+        ESP_LOGD(TAG, "msg length is low");
+    }
+    sync_msg_head msg_head = {0};
+    memcpy(&msg_head, raw_data, sizeof(sync_msg_head));
+
+    if (msg_head.type != MSG_TYPE || msg_head.head != MSG_HEAD) {
+        ESP_LOGD(TAG, "msg is unknown");
+        return;
+    }
+    ESP_LOGD(TAG, "msg_id: %x\n", msg_head.msg_id);
+    // ESP_LOG_BUFFER_HEX("sync recv:", raw_data, raw_data_len);
+    switch (sync_obj.state) {
+#if defined(CONFIG_EXAMPLE_WIFI_ROLE) || defined(CONFIG_EXAMPLE_BT_ROLE)
+    case WAIT_CASE: {
+        ESP_LOGD(TAG, "WAIT_CASE\n");
+        if (msg_head.msg_id == MSG_ID_ASSIGN_CASE) {
+            analys_param(msg_head.param_bit, raw_data + MSG_DATA_BASE, &sync_obj.recv_param_bit );
+#if defined(CONFIG_EXAMPLE_WIFI_ROLE)
+            if (sync_obj.own_wifi_case != NOT_CASE) {
+                if ((sync_obj.recv_param_bit & auto_tb[sync_obj.own_wifi_case].excpet_param_bit) == auto_tb[sync_obj.own_wifi_case].excpet_param_bit) {
+                    excute_case(sync_obj.own_wifi_case);
+                    sync_obj.state = WAIT_START;
+                    esp_timer_start_periodic(sync_obj.sync_timer, SYNC_TIMEOUT );
+                }
+            }
+#endif
+#if defined(CONFIG_EXAMPLE_BT_ROLE)
+            if (sync_obj.own_ble_case != NOT_CASE) {
+                if ((sync_obj.recv_param_bit & auto_tb[sync_obj.own_ble_case].excpet_param_bit) == auto_tb[sync_obj.own_ble_case].excpet_param_bit) {
+                    sync_obj.state = WAIT_START;
+                    esp_timer_start_periodic(sync_obj.sync_timer, SYNC_TIMEOUT );
+                }
+            }
+#endif
+        }
+        break;
+    }
+    case WAIT_START:
+        ESP_LOGD(TAG, "WAIT_START\n");
+        ESP_LOGD(TAG, "WAIT_START %x\n", msg_head.msg_id);
+        if (msg_head.msg_id == MSG_ID_START_CASE) {
+            analys_param(msg_head.param_bit, raw_data + MSG_DATA_BASE, &sync_obj.recv_param_bit );
+            sync_obj.state = START_CASE;
+            ble_gap_util_stop();
+#if defined(CONFIG_EXAMPLE_WIFI_ROLE)
+            bt_test_deinit();
+#endif
+            esp_timer_stop(sync_obj.sync_timer);
+            esp_timer_start_once(sync_obj.sync_timer, sync_obj.start_time * 1000000);
+        }
+        break;
+#endif
+#if defined(CONFIG_EXAMPLE_COEX_ROLE)
+    case ASSIGN_CASE:
+        ESP_LOGD(TAG, "ASSIGN_CASE\n");
+        switch (msg_head.msg_id) {
+        case MSG_ID_WIFI_DEV_INIT_FINISH:
+            if (msg_head.param_bit != 0x0) {
+                analys_param(msg_head.param_bit, raw_data + MSG_DATA_BASE, &sync_obj.recv_param_bit );
+            }
+            sync_obj.except_recv_wifi_id = true;
+            break;
+        case MSG_ID_BT_DEV_INIT_FINISH:
+            sync_obj.except_recv_bt_id = true;
+            break;
+        default:
+            break;
+        }
+        send_start_countdown();
+        break;
+#endif
+    default:
+        ESP_LOGD(TAG, "state is unknown %s", __func__);
+        break;
+    }
+}
+
+static void handle_sync_timeout(void *arg)
+{
+    static bool run_first = true;
+    if (run_first == true) {
+        xSemaphoreTake((SemaphoreHandle_t)arg, (portTickType)portMAX_DELAY);
+        esp_timer_start_periodic( (SemaphoreHandle_t)arg, 1000000);
+        run_first = false;
+    }
+    switch (sync_obj.state) {
+#if defined(CONFIG_EXAMPLE_COEX_ROLE)
+    case ASSIGN_CASE:
+        ESP_LOGD(TAG, "ASSIGN_CASE\n");
+        assign_test_case();
+        esp_timer_start_periodic(sync_obj.sync_timer, SYNC_TIMEOUT);
+        break;
+#endif
+
+#if defined(CONFIG_EXAMPLE_WIFI_ROLE) || defined(CONFIG_EXAMPLE_BT_ROLE)
+    case WAIT_START: {
+        ESP_LOGD(TAG, "WAIT_START\n");
+#if defined(CONFIG_EXAMPLE_WIFI_ROLE)
+        if ( WIFI_TCP_RX_CASE == sync_obj.own_wifi_case ) {
+            send_tcp_rx_inited_msg();
+        } else {
+            send_case_inited_msg(MSG_ID_WIFI_DEV_INIT_FINISH);
+        }
+#elif defined(CONFIG_EXAMPLE_BT_ROLE)
+        send_case_inited_msg(MSG_ID_BT_DEV_INIT_FINISH);
+#endif
+        esp_timer_start_periodic(sync_obj.sync_timer, SYNC_TIMEOUT);
+        break;
+    }
+#endif
+
+
+    case START_CASE: {
+        ESP_LOGD(TAG, "START_CASE\n");
+#if defined(CONFIG_EXAMPLE_BT_ROLE)
+        excute_case(sync_obj.own_ble_case);
+
+#elif defined(CONFIG_EXAMPLE_WIFI_ROLE)
+        ESP_LOGD(TAG, "START_CASE\n");
+        if (arg != NULL) {
+            xSemaphoreGive((SemaphoreHandle_t)arg);
+            run_first = true;
+            esp_timer_stop(sync_obj.sync_timer);
+
+        }
+#else
+        static uint8_t send_start_count = 10;
+        if (send_start_count == 0) {
+            excute_case(sync_obj.own_ble_case);
+            xSemaphoreGive((SemaphoreHandle_t)arg);
+            run_first = true;
+            esp_timer_stop(sync_obj.sync_timer);
+            break;
+        }
+
+        send_start_msg(send_start_count);
+        send_start_count -= 1;
+        esp_timer_start_once(sync_obj.sync_timer,  1000000);
+#endif
+        break;
+    }
+    default:
+        ESP_LOGD(TAG, "state is unknown%s", __func__);
+        break;
+    }
+}
+
+esp_err_t create_sync_timer(esp_timer_handle_t *timer_hdl)
+{
+    esp_err_t ret;
+    esp_timer_create_args_t tca = {
+        .callback = (esp_timer_cb_t)handle_sync_timeout,
+        .dispatch_method = ESP_TIMER_TASK,
+        .name = "SYNC_TIMER",
+    };
+    tca.arg = client_mutex;
+
+    ret = esp_timer_create(&tca, timer_hdl);
+    if (ret != ESP_OK) {
+        ESP_LOGE(TAG, "timer create failed %d %x\n", __LINE__, ret);
+        return ret;
+    }
+    esp_timer_start_once( *timer_hdl, 10);
+
+    return ret;
+}
+
+
+void sync_init(void)
+{
+    esp_err_t ret;
+    sync_obj.cmd_recv = &sync_cmd_recv;
+    client_mutex = xSemaphoreCreateMutex();
+    if (!client_mutex) {
+        ESP_LOGE(TAG, "client_mutex Create failed ");
+        return;
+    }
+    coex_set_test_env("mutex", NULL, 0);
+
+    bt_test_init();
+    init_ble_gap_test_util();
+    ret = esp_ble_gap_start_scanning(BLE_TC_SCAN_REPORT_PERIOD);
+    if (ret != ESP_OK) {
+        ESP_LOGE(TAG, "esp_ble_gap_start_scanning error, %d", ret);
+        return ;
+    }
+    ret = create_sync_timer(&sync_obj.sync_timer);
+    if (ret != ESP_OK) {
+        ESP_LOGE(TAG, "sync timer create failed");
+        return ;
+    }
+
+#if defined(CONFIG_EXAMPLE_COEX_ROLE)
+    excute_case(sync_obj.own_wifi_case);
+    vTaskDelay(3000 / portTICK_PERIOD_MS);
+#endif
+
+}

+ 122 - 0
examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/components/case/sync.h

@@ -0,0 +1,122 @@
+/* ESP BLE Mesh Example
+
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#ifndef __SYNC_H__
+#define __SYNC_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include "esp_log.h"
+#include "esp_timer.h"
+#include "ble_unit.h"
+#include "test_env.h"
+
+#include "esp_bt.h"
+#include "esp_bt_main.h"
+#include "esp_bt_device.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/semphr.h"
+#include "freertos/task.h"
+#include "freertos/queue.h"
+
+#include "mesh_util.h"
+#define PARAM_MAX           7
+
+#define SYNC_TIMEOUT   500000 //500ms
+#define PARAMTER(value) (((uint32_t)value) << 7)
+
+#define WIFI_TCP_TX_CASE    0x0
+#define WIFI_TCP_RX_CASE    0x1
+#define BLE_ADV_CASE        0x2
+#define BLE_SCAN_CASE       0x3
+#define NOT_CASE            0xff
+
+#define MSG_HEAD                     0xcbb3
+#define MSG_TYPE                     0xff
+#define MSG_CONTINUE                 0x0
+#define MSG_END                      0x1
+#define MSG_DATA_BASE                0x8
+#define MSG_ID_ASSIGN_CASE           0x1
+#define MSG_ID_WIFI_DEV_INIT_FINISH  0x2
+#define MSG_ID_BT_DEV_INIT_FINISH    0x3
+#define MSG_ID_START_CASE            0x4
+
+#define BLE_CASE_ID         0b100000 << PARAM_MAX
+#define WIFI_CASE_ID        0b010000 << PARAM_MAX
+#define SERVER_IP           0b001000 << PARAM_MAX
+#define START_TIME          0b000100 << PARAM_MAX
+#define WIFI_SSID           0b000010 << PARAM_MAX
+#define WIFI_PASSWIRD       0b000001 << PARAM_MAX
+
+
+#define GET_PARAM(value,bit)    (((value) & (bit)) ? bit:0x0)
+
+#define MSG_MIN_LEN         8
+
+typedef void (*sync_recv)(uint8_t *raw_data, uint32_t raw_data_len);
+
+typedef struct  {
+    uint8_t length;
+    uint8_t  type;
+    uint16_t head;
+    uint8_t  msg_id;
+    uint16_t ctl: 3,
+             param_bit: 13;
+} __attribute__((packed)) sync_msg_head;
+
+typedef struct  {
+    uint8_t length;
+    uint8_t  type;
+    uint16_t head;
+    uint8_t  msg_id;
+    uint16_t ctl: 3,
+             param_bit: 13;
+    uint8_t  reserve;       //reserved for extend param_bit
+    uint8_t  data[23];
+} __attribute__((packed)) sync_msg;
+
+typedef struct {
+    uint8_t  case_id;
+    const uint16_t excpet_param_bit;
+} auto_tc;
+auto_tc auto_tb[6];
+
+
+typedef enum {
+#if defined(CONFIG_EXAMPLE_COEX_ROLE)
+    ASSIGN_CASE,
+#else
+    WAIT_CASE,
+    WAIT_START,
+#endif
+    START_CASE,
+} sync_state;
+
+struct sync_t {
+    sync_state    state;
+    uint8_t       own_wifi_case;
+    uint8_t       own_ble_case;
+    uint8_t       start_time;
+
+    uint16_t      recv_param_bit;
+
+    bool          except_recv_wifi_id;
+    bool          except_recv_bt_id;
+
+    esp_timer_handle_t sync_timer;
+    sync_recv     cmd_recv;
+};
+struct sync_t sync_obj;
+
+extern SemaphoreHandle_t client_mutex;
+void sync_init(void);
+
+#endif

+ 128 - 0
examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/components/case/test_env.c

@@ -0,0 +1,128 @@
+/* ESP BLE Mesh Example
+
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#include <stdio.h>
+#include <string.h>
+
+#include "esp_err.h"
+#include "esp_log.h"
+#include "test_env.h"
+#include "sync.h"
+
+#define TAG         "ENV"
+
+coex_test_env_t test_env = {
+#if defined(CONFIG_EXAMPLE_MANAUL)
+    .ap_ssid = CONFIG_EXAMPLE_WIFI_SSID,
+    .ap_password = CONFIG_EXAMPLE_WIFI_PASSWORD,
+#endif
+#if defined(CONFIG_EXAMPLE_COEX_ROLE)
+    .ap_ssid = CONFIG_EXAMPLE_WIFI_SSID,
+    .ap_password = CONFIG_EXAMPLE_WIFI_PASSWORD,
+#endif
+    .test_port = "8080",
+    .server_ip = "192.168.3.32",
+    .duration = "120000",
+    .is_start = false,
+};
+
+esp_err_t coex_set_test_env(const char *keyword, const char *value, uint8_t length)
+{
+    esp_err_t ret = ESP_OK;
+    if (!strcmp(keyword, "ap_ssid")) {
+        memset(test_env.ap_ssid, '\0', sizeof(test_env.ap_ssid));
+        strncpy(test_env.ap_ssid, value, length);
+    } else if (!strcmp(keyword, "ap_password")) {
+        memset(test_env.ap_password, '\0', sizeof(test_env.ap_password));
+        strncpy(test_env.ap_password, value, length);
+    } else if (!strcmp( keyword, "test_port")) {
+        memset(test_env.test_port, '\0', sizeof(test_env.test_port));
+        strncpy(test_env.test_port, value, length);
+    } else if (!strcmp(keyword, "server_ip")) {
+        memset(test_env.server_ip, '\0', sizeof(test_env.server_ip));
+        strncpy(test_env.server_ip, value, length);
+    } else if (!strcmp(keyword, "duration")) {
+        strncpy(test_env.duration, value, length);
+    } else if (!strcmp(keyword, "mutex")) {
+        test_env.run_mutex = client_mutex;
+
+    } else {
+        ret = ESP_ERR_NOT_SUPPORTED;
+    }
+    return ret;
+}
+
+const char *coex_get_test_env(const char *keyword)
+{
+    const char *ret = NULL;
+    if (!strcmp(keyword, "ap_ssid")) {
+        ret = test_env.ap_ssid;
+    } else if (!strcmp(keyword, "ap_password")) {
+        ret = test_env.ap_password;
+    } else if (!strcmp(keyword, "test_port")) {
+        ret = test_env.test_port;
+    } else if (!strcmp(keyword, "server_ip")) {
+        ret = test_env.server_ip;
+    } else if (!strcmp(keyword, "duration")) {
+        ret = test_env.duration;
+    }
+    return ret;
+}
+
+void coex_print_test_env(void)
+{
+    ESP_LOGI(TAG, "current test env:");
+    ESP_LOGI(TAG, "\tap_ssid: %s", test_env.ap_ssid);
+    ESP_LOGI(TAG, "\tap_password: %s", test_env.ap_password);
+    ESP_LOGI(TAG, "\ttest_port: %s", test_env.test_port);
+    ESP_LOGI(TAG, "\tserver_ip: %s", test_env.server_ip);
+    ESP_LOGI(TAG, "\tduration: %s", test_env.duration);
+}
+
+bool coex_env_str_to_mac(uint8_t *str, uint8_t *dest)
+{
+    uint8_t loop = 0;
+    uint8_t tmp = 0;
+    uint8_t *src_p = str;
+
+    if (strlen((char *)src_p) != 17) { // must be like 12:34:56:78:90:AB
+        ESP_LOGE(TAG, "wrong format");
+        return false;
+    }
+
+    for (loop = 0; loop < 17 ; loop++) {
+        if (loop % 3 == 2) {
+            if (src_p[loop] != ':') {
+                ESP_LOGE(TAG, "wrong format");
+                return false;
+            }
+
+            continue;
+        }
+
+        if ((src_p[loop] >= '0') && (src_p[loop] <= '9')) {
+            tmp = tmp * 16 + src_p[loop] - '0';
+        } else if ((src_p[loop] >= 'A') && (src_p[loop] <= 'F')) {
+            tmp = tmp * 16 + src_p[loop] - 'A' + 10;
+        } else if ((src_p[loop] >= 'a') && (src_p[loop] <= 'f')) {
+            tmp = tmp * 16 + src_p[loop] - 'a' + 10;
+        } else {
+            ESP_LOGE(TAG, "wrong format");
+            return false;
+        }
+
+        if (loop % 3 == 1) {
+            *dest++ = tmp;
+            tmp = 0;
+        }
+    }
+
+    return true;
+}
+

+ 43 - 0
examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/components/case/test_env.h

@@ -0,0 +1,43 @@
+/* ESP BLE Mesh Example
+
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#ifndef __TEST_ENV_H__
+#define __TEST_ENV_H__
+
+#include <stdint.h>
+#include "esp_err.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/semphr.h"
+
+#define MAX_SSID_LEN                        32
+#define MAX_PASSWORD_LEN                    64
+#define MAX_IP_STR_LEN                      15
+#define MAX_PORT_STR_LEN                    5
+#define MAX_MAC_ADDR_LEN                    17
+#define INVALID_REMOTE_BT_MAC               "ff:ff:ff:ff:ff:ff"
+#define DURATION_MAX_LEN                    10
+
+typedef struct {
+    char ap_ssid[MAX_SSID_LEN + 1];
+    char ap_password[MAX_PASSWORD_LEN + 1];
+    char test_port[MAX_PORT_STR_LEN + 1];
+    char server_ip[MAX_IP_STR_LEN + 1];
+    char duration[DURATION_MAX_LEN + 1];
+    bool is_start;
+    SemaphoreHandle_t run_mutex;
+} coex_test_env_t;
+
+extern coex_test_env_t test_env;
+
+esp_err_t coex_set_test_env(const char *keyword, const char *value, uint8_t length);
+const char *coex_get_test_env(const char *keyword);
+void coex_print_test_env(void);
+bool coex_env_str_to_mac(uint8_t *str, uint8_t *dest);
+
+#endif /* __TEST_ENV_H__ */

+ 158 - 0
examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/components/case/wifi_connect.c

@@ -0,0 +1,158 @@
+/* ESP BLE Mesh Example
+
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#include <stdio.h>
+#include <string.h>
+
+#include "esp_err.h"
+#include "esp_log.h"
+
+#include "wifi_connect.h"
+
+
+#include <string.h>
+#include "sdkconfig.h"
+#include "esp_event.h"
+#include "esp_wifi.h"
+#include "esp_wifi_default.h"
+
+#include "esp_log.h"
+#include "esp_netif.h"
+#include "driver/gpio.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/event_groups.h"
+#include "lwip/err.h"
+#include "lwip/sys.h"
+
+#define GOT_IPV4_BIT BIT(0)
+
+#define CONNECTED_BITS (GOT_IPV4_BIT)
+
+
+static EventGroupHandle_t s_connect_event_group;
+static esp_ip4_addr_t s_ip_addr;
+static const char *s_connection_name;
+static esp_netif_t *s_example_esp_netif = NULL;
+
+
+
+static const char *TAG = "example_connect";
+
+/* set up connection, Wi-Fi or Ethernet */
+static void start(const char *ssid, const char *passwd);
+
+/* tear down connection, release resources */
+static void stop(void);
+
+static void on_got_ip(void *arg, esp_event_base_t event_base,
+                      int32_t event_id, void *event_data)
+{
+    ESP_LOGI(TAG, "Got IP event!");
+    ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
+    memcpy(&s_ip_addr, &event->ip_info.ip, sizeof(s_ip_addr));
+    xEventGroupSetBits(s_connect_event_group, GOT_IPV4_BIT);
+}
+
+esp_err_t example_connect(const char *ssid, const char *passwd)
+{
+    if (s_connect_event_group != NULL) {
+        return ESP_ERR_INVALID_STATE;
+    }
+    s_connect_event_group = xEventGroupCreate();
+    start(ssid, passwd);
+    ESP_ERROR_CHECK(esp_register_shutdown_handler(&stop));
+    ESP_LOGI(TAG, "Waiting for IP");
+    xEventGroupWaitBits(s_connect_event_group, CONNECTED_BITS, true, true, portMAX_DELAY);
+    ESP_LOGI(TAG, "Connected to %s", s_connection_name);
+    ESP_LOGI(TAG, "IPv4 address: " IPSTR, IP2STR(&s_ip_addr));
+    return ESP_OK;
+}
+
+esp_err_t example_disconnect(void)
+{
+    if (s_connect_event_group == NULL) {
+        return ESP_ERR_INVALID_STATE;
+    }
+    vEventGroupDelete(s_connect_event_group);
+    s_connect_event_group = NULL;
+    stop();
+    ESP_LOGI(TAG, "Disconnected from %s", s_connection_name);
+    s_connection_name = NULL;
+    return ESP_OK;
+}
+
+
+static void on_wifi_disconnect(void *arg, esp_event_base_t event_base,
+                               int32_t event_id, void *event_data)
+{
+    ESP_LOGI(TAG, "Wi-Fi disconnected, trying to reconnect...");
+    esp_err_t err = esp_wifi_connect();
+    if (err == ESP_ERR_WIFI_NOT_STARTED) {
+        return;
+    }
+    ESP_ERROR_CHECK(err);
+}
+
+static void start(const char *ssid, const char *passwd)
+{
+    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
+    ESP_ERROR_CHECK(esp_wifi_init(&cfg));
+
+    esp_netif_config_t netif_config = ESP_NETIF_DEFAULT_WIFI_STA();
+
+    esp_netif_t *netif = esp_netif_new(&netif_config);
+
+    assert(netif);
+
+    esp_netif_attach_wifi_station(netif);
+    esp_wifi_set_default_wifi_sta_handlers();
+
+    s_example_esp_netif = netif;
+
+    ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &on_wifi_disconnect, NULL));
+    ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &on_got_ip, NULL));
+    ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
+
+    wifi_config_t wifi_config;
+    memset(&wifi_config, 0, sizeof(wifi_config));
+    if (ssid) {
+        strncpy((char *)wifi_config.sta.ssid, ssid, strlen(ssid));
+    }
+    if (passwd) {
+        strncpy((char *)wifi_config.sta.password, passwd, strlen(passwd));
+    }
+
+    ESP_LOGI(TAG, "Connecting to %s...", wifi_config.sta.ssid);
+    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
+    ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
+    ESP_ERROR_CHECK(esp_wifi_start());
+    ESP_ERROR_CHECK(esp_wifi_connect());
+    s_connection_name = ssid;
+}
+
+static void stop(void)
+{
+    ESP_ERROR_CHECK(esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &on_wifi_disconnect));
+    ESP_ERROR_CHECK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, &on_got_ip));
+    esp_err_t err = esp_wifi_stop();
+    if (err == ESP_ERR_WIFI_NOT_INIT) {
+        return;
+    }
+    ESP_ERROR_CHECK(err);
+    ESP_ERROR_CHECK(esp_wifi_deinit());
+    ESP_ERROR_CHECK(esp_wifi_clear_default_wifi_driver_and_handlers(s_example_esp_netif));
+    esp_netif_destroy(s_example_esp_netif);
+    s_example_esp_netif = NULL;
+}
+
+esp_netif_t *get_example_netif(void)
+{
+    return s_example_esp_netif;
+}

+ 22 - 0
examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/components/case/wifi_connect.h

@@ -0,0 +1,22 @@
+/* ESP BLE Mesh Example
+
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#ifndef __WIFI_CONNECT_H__
+#define __WIFI_CONNECT_H__
+
+#include "esp_err.h"
+#include "esp_netif.h"
+#include "esp_event.h"
+
+esp_err_t example_connect(const char *ssid, const char *passwd);
+esp_err_t example_disconnect(void);
+esp_err_t example_configure_stdin_stdout(void);
+esp_netif_t *get_example_netif(void);
+
+#endif  /* __WIFI_CONNECT_H__ */

+ 187 - 0
examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/components/case/wifi_unit.c

@@ -0,0 +1,187 @@
+/* ESP BLE Mesh Example
+
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "wifi_unit.h"
+#include "wifi_connect.h"
+#define TAG "WIFI_UINT"
+
+uint32_t utils_get_system_ts(void)
+{
+    return esp_log_timestamp();
+}
+
+esp_err_t wifi_unit_client_establish(int *sock, const char *ip, const char *port)
+{
+    esp_err_t ret = 0;
+    uint32_t start_ts;
+    uint32_t timeout = 10000;
+    struct sockaddr_in sock_addr;
+    int s;
+
+    memset(&sock_addr, 0, sizeof(sock_addr));
+    sock_addr.sin_family = AF_INET;
+    sock_addr.sin_addr.s_addr = ipaddr_addr(ip);
+    sock_addr.sin_port = htons(atoi(port));
+
+    start_ts = utils_get_system_ts();
+    do {
+        s = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
+        if (s < 0) {
+            ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
+        }
+        ret = connect(s, (struct sockaddr *)&sock_addr, sizeof(sock_addr));
+        if (ret == 0) {
+            *sock = s;
+            break;
+        } else if (s > 0) {
+            close(s);
+        }
+    } while (utils_get_system_ts() - start_ts < timeout);
+    return ret;
+}
+
+esp_err_t wifi_unit_server_establish(int *socket_id, const char *port)
+{
+    esp_err_t ret = -1;
+    struct sockaddr_in local_addr;
+    uint32_t local_ip;
+
+    static int ls_sock = -1;
+
+    local_ip = wifi_util_get_ip();
+
+    if (ls_sock < 0) {
+        ls_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
+        if (ls_sock < 0) {
+            ESP_LOGE(TAG, "create socket failed");
+            return ls_sock;
+        }
+
+        local_addr.sin_family = AF_INET;
+        local_addr.sin_port = htons(atoi(port));
+        local_addr.sin_addr.s_addr = local_ip;
+        ret = bind(ls_sock, (struct sockaddr *)&local_addr, sizeof(local_addr));
+        if (ret != 0) {
+            ESP_LOGE(TAG, "socket bind failed");
+            return ret;
+        }
+
+        ret = listen(ls_sock, 1);
+        if (ret < 0) {
+            ESP_LOGE(TAG, "socket listen failed");
+            return ret;
+        }
+    }
+
+    struct sockaddr_in6 sourceAddr; // Large enough for both IPv4 or IPv6
+    socklen_t addrLen = sizeof(sourceAddr);
+    *socket_id = accept(ls_sock, (struct sockaddr *)&sourceAddr, &addrLen);
+    if (*socket_id < 0) {
+        ESP_LOGE(TAG, "Unable to accept connection: errno %d", errno);
+        return -1;
+    }
+    ESP_LOGI(TAG, "Socket accepted");
+    return ret;
+}
+
+esp_err_t wifi_unit_tcp_recv(int socket_id, const char *duration, uint32_t user_date[])
+{
+    esp_err_t ret = -1;
+    uint32_t start_ts;
+    uint8_t *buffer;
+    struct timeval tv_t;
+    uint32_t *recv_len = &user_date[1];
+    tv_t.tv_sec = 1;
+    tv_t.tv_usec = 0;
+    ret = setsockopt(socket_id, SOL_SOCKET, SO_RCVTIMEO, &tv_t, sizeof(tv_t));
+
+    buffer = malloc(2920);
+
+    if (buffer == NULL) {
+        ESP_LOGE(TAG, "%s malloc fail\n", __func__);
+        return ESP_ERR_NO_MEM;
+    }
+
+    start_ts = utils_get_system_ts();
+
+    while (utils_get_system_ts() - start_ts < atoi(duration)) {
+        ret = recv(socket_id, buffer, 2920, 0);
+        if (ret > 0) {
+            *recv_len = *recv_len + ret;
+        } else if (ret == 0) {
+            break;
+        }
+    }
+    free(buffer);
+    if (ret > 0 ) {
+        ret = ESP_OK;
+    }
+    return ret;
+}
+
+esp_err_t wifi_util_tcp_send(int socket_id, uint32_t len, uint32_t delay, uint32_t *sent_len, uint32_t timeout)
+{
+    esp_err_t ret = ESP_OK;
+    uint32_t start_ts;
+    uint8_t *buffer;
+
+    if ( len == 0) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    buffer = malloc(len);
+    if (buffer == NULL) {
+        ESP_LOGE(TAG, "%s malloc fail\n", __func__);
+        return ESP_ERR_NO_MEM;
+    }
+
+    start_ts = utils_get_system_ts();
+
+    while (utils_get_system_ts() - start_ts < timeout) {
+        ret = send(socket_id, buffer, len, 0);
+        if (ret < 0) {
+            ESP_LOGE(TAG, "recv failed: errno %d", errno);
+            break;
+        }
+        *sent_len = *sent_len + ret;
+
+        if (delay) {
+            vTaskDelay(delay / portTICK_PERIOD_MS);
+        }
+    }
+    if (ret == len) {
+        ret = ESP_OK;
+    } else {
+        ESP_LOGE(TAG, "tcp send error, %d", ret);
+        ret = -2;
+    }
+
+    free(buffer);
+
+    return ret;
+}
+
+uint32_t wifi_util_get_ip(void)
+{
+    esp_netif_ip_info_t ip_info;
+    esp_netif_t *netif = get_example_netif();
+    esp_netif_get_ip_info(netif, &ip_info);
+    return ip_info.ip.addr;
+}
+
+void wifi_util_init(void)
+{
+    ESP_ERROR_CHECK(nvs_flash_init());
+    ESP_ERROR_CHECK(esp_netif_init());
+    ESP_ERROR_CHECK(esp_event_loop_create_default());
+}

+ 38 - 0
examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/components/case/wifi_unit.h

@@ -0,0 +1,38 @@
+/* ESP BLE Mesh Example
+
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#ifndef _WIFI_UNIT_H
+#define _WIFI_UNIT_H
+
+#include "esp_wifi_types.h"
+#include "esp_wifi.h"
+#include "esp_event.h"
+#include "esp_log.h"
+#include "esp_timer.h"
+#include "nvs_flash.h"
+
+#include "esp_netif.h"
+
+#include "lwip/err.h"
+#include "lwip/sockets.h"
+#include "lwip/sys.h"
+#include "lwip/netdb.h"
+#include "lwip/dns.h"
+
+uint32_t utils_get_system_ts(void);
+
+void wifi_util_init(void);
+
+uint32_t wifi_util_get_ip(void);
+esp_err_t wifi_unit_client_establish(int *sock, const char *ip, const char *port);
+esp_err_t wifi_unit_server_establish(int *socket_id, const char *port);
+
+esp_err_t wifi_unit_tcp_recv(int socket_id, const char *duration, uint32_t user_date[]);
+esp_err_t wifi_util_tcp_send(int socket_id, uint32_t len, uint32_t delay, uint32_t *sent_len, uint32_t timeout);
+#endif /* _WIFI_UNIT_H */

+ 6 - 0
examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/main/CMakeLists.txt

@@ -0,0 +1,6 @@
+set(COMPONENT_SRCS "main.c"
+                   "coex_cmd.c")
+
+set(COMPONENT_ADD_INCLUDEDIRS ".")
+set(SUPPORTED_TARGETS esp32)
+register_component()

+ 70 - 0
examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/main/Kconfig.projbuild

@@ -0,0 +1,70 @@
+menu "Example Configuration"
+
+    choice EXAMPLE_RUN_MODE
+        prompt "select run mode"
+        help
+            select run mode
+
+        config EXAMPLE_AUTO
+            bool "auto"
+            help
+                In automatic mode, the program coordinates three development board work
+                through a synchronization mechanism.
+
+        config EXAMPLE_MANAUL
+            bool "manual"
+            help
+                In manual mode, you will work with three development boards via commands.
+    endchoice
+
+    config EXAMPLE_WIFI_SSID
+        depends on EXAMPLE_MANAUL
+        string "WiFi SSID"
+        help
+            SSID (network name) for the example to connect to. The length cannot exceed 20 bytes.
+    config EXAMPLE_WIFI_PASSWORD
+        depends on EXAMPLE_MANAUL
+        string "WiFi Password"
+        help
+            WiFi password (WPA or WPA2) for the example to use.
+            Can be left blank if the network has no security set.
+            The length cannot exceed 20 bytes.
+
+    choice EXAMPLE_SELECT_ROLE
+        prompt "select role"
+        depends on EXAMPLE_AUTO
+        config EXAMPLE_COEX_ROLE
+            bool "run device as coex role"
+        config EXAMPLE_WIFI_ROLE
+            bool "run device as wifi role"
+        config EXAMPLE_BT_ROLE
+            bool "run device as bluetooth role"
+    endchoice
+
+    choice EXAMPLE_SELECT_CASE
+        prompt "select case"
+        depends on EXAMPLE_COEX_ROLE
+        config EXAMPLE_COEX_TX_ADV
+            bool "TCP TX and BLE ADV"
+        config EXAMPLE_COEX_RX_ADV
+            bool "TCP RX and BLE ADV"
+        config EXAMPLE_COEX_TX_SCAN
+            bool "TCP TX and BLE SCAN"
+        config EXAMPLE_COEX_RX_SCAN
+            bool "TCP RX and BLE SCAN"
+    endchoice
+
+    config EXAMPLE_WIFI_SSID
+        depends on EXAMPLE_COEX_ROLE
+        string "WiFi SSID"
+        help
+            SSID (network name) for the example to connect to. The length cannot exceed 20 bytes.
+    config EXAMPLE_WIFI_PASSWORD
+        depends on EXAMPLE_COEX_ROLE
+        string "WiFi Password"
+        help
+            WiFi password (WPA or WPA2) for the example to use.
+            Can be left blank if the network has no security set.
+            The length cannot exceed 20 bytes.
+
+endmenu #"Example Configuration End"

+ 168 - 0
examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/main/coex_cmd.c

@@ -0,0 +1,168 @@
+/* ESP BLE Mesh Example
+
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include "esp_log.h"
+#include "esp_console.h"
+#include "argtable3/argtable3.h"
+
+#include "esp_bt.h"
+#include "esp_bt_main.h"
+#include "esp_bt_device.h"
+
+#include "run_tc.h"
+#include "test_env.h"
+
+
+#define TAG_CNSL "CNSL"
+
+typedef struct {
+    struct arg_str *wifi_tc_idx;
+    struct arg_str *bt_tc_idx;
+    struct arg_end *end;
+} tc_run_args_t;
+
+typedef struct {
+    struct arg_lit *set;
+    struct arg_lit *get;
+    struct arg_str *key;
+    struct arg_str *value;
+    struct arg_end *end;
+} env_param_cmd_args_t;
+
+static tc_run_args_t tc_run_args;
+static env_param_cmd_args_t env_param_cmd_args;
+
+static int process_env_parameter_cmd(int argc, char **argv)
+{
+    int nerrors = arg_parse(argc, argv, (void **) &env_param_cmd_args);
+    int ret;
+    const char *env_value = "";
+
+    if (nerrors != 0) {
+        arg_print_errors(stderr, env_param_cmd_args.end, argv[0]);
+        return 1;
+    }
+    if (env_param_cmd_args.set->count == 1) {
+        if (env_param_cmd_args.key->count == 1) {
+            if (env_param_cmd_args.value->count == 1) {
+                env_value = env_param_cmd_args.value->sval[0];
+            }
+            ret = coex_set_test_env(env_param_cmd_args.key->sval[0], env_value, strlen(env_param_cmd_args.value->sval[0]));
+            if (ret == ESP_ERR_NOT_SUPPORTED) {
+                ESP_LOGE(TAG_CNSL, "Not supported env key");
+            } else if (ret == ESP_ERR_INVALID_ARG) {
+                ESP_LOGE(TAG_CNSL, "Invalid value");
+            }
+            ESP_LOGI(TAG_CNSL, "env set done");
+        } else {
+            ESP_LOGE(TAG_CNSL, "env key not set correctly");
+        }
+    } else if (env_param_cmd_args.get->count == 1) {
+        coex_print_test_env();
+    }
+    return 0;
+}
+
+static int process_restart_cmd(int argc, char **argv)
+{
+    ESP_LOGI(TAG_CNSL, "restarting...");
+    esp_restart();
+    return 0;
+}
+
+
+static int process_run_tc_cmd(int argc, char **argv)
+{
+    run_task_msg_t msg;
+    int nerrors = arg_parse(argc, argv, (void **) &tc_run_args);
+    if (nerrors != 0) {
+        arg_print_errors(stderr, tc_run_args.end, argv[0]);
+        return 1;
+    }
+
+    if (tc_run_args.wifi_tc_idx->count == 1) {
+        msg.case_id = atoi(tc_run_args.wifi_tc_idx->sval[0]);
+        if (xQueueSend(xTaskQueue, &msg, portMAX_DELAY) != pdTRUE) {
+            ESP_LOGE(TAG_CNSL, "xTaskQueue Post failed\n");
+        }
+    }
+
+    if (tc_run_args.bt_tc_idx->count == 1) {
+        msg.case_id = atoi(tc_run_args.bt_tc_idx->sval[0]);
+        if (xQueueSend(xTaskQueue, &msg, portMAX_DELAY) != pdTRUE) {
+            ESP_LOGE(TAG_CNSL, "xTaskQueue Post failed\n");
+        }
+    }
+
+    return 0;
+}
+
+static int process_get_mac_addr_cmd(int argc, char **argv)
+{
+    const uint8_t *mac = esp_bt_dev_get_address();
+
+    if (mac != NULL) {
+        ESP_LOGI(TAG_CNSL, "+BTMAC:"MACSTR"\n", MAC2STR(mac));
+    } 
+    return 0;
+}
+void register_coex_cmd(void)
+{
+    const esp_console_cmd_t restart_cmd = {
+        .command = "restart",
+        .help = "restart cmd",
+        .hint = NULL,
+        .func = &process_restart_cmd,
+        .argtable = NULL
+    };
+
+    ESP_ERROR_CHECK( esp_console_cmd_register(&restart_cmd) );
+
+    const esp_console_cmd_t get_mac_cmd = {
+        .command = "mac",
+        .help = "Get DUT mac address",
+        .hint = NULL,
+        .func = &process_get_mac_addr_cmd,
+        .argtable = NULL
+    };
+
+    ESP_ERROR_CHECK( esp_console_cmd_register(&get_mac_cmd) );
+
+    tc_run_args.wifi_tc_idx = arg_str0("w", "wifi", "<str>", "0 : wifi_tcp_tx_throught 1 : wifi_tcp_rx_throught\n");
+    tc_run_args.bt_tc_idx   = arg_str0("b", "bluetooth", "<str>", "2  :ble_adv  3 : ble_scan\n");
+    tc_run_args.end = arg_end(2);
+
+    const esp_console_cmd_t run_tc_cmd = {
+        .command = "run_tc",
+        .help = "run wifi bt test case command",
+        .hint = NULL,
+        .func = &process_run_tc_cmd,
+        .argtable = &tc_run_args
+    };
+
+    ESP_ERROR_CHECK( esp_console_cmd_register(&run_tc_cmd) );
+
+    env_param_cmd_args.set = arg_lit0("s", "set", "set env parameter");
+    env_param_cmd_args.get = arg_lit0("g", "get", "get env parameter");
+    env_param_cmd_args.key = arg_str0("k", "key", "<str>", "env parameter key");
+    env_param_cmd_args.value = arg_str0("v", "value", "<str>", "env parameter value (only used with set)");
+    env_param_cmd_args.end = arg_end(4);
+
+    const esp_console_cmd_t env_cmd = {
+        .command = "env",
+        .help = "Set or get test environment parameters",
+        .hint = NULL,
+        .func = &process_env_parameter_cmd,
+        .argtable = &env_param_cmd_args,
+    };
+
+    ESP_ERROR_CHECK( esp_console_cmd_register(&env_cmd) );
+}

+ 16 - 0
examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/main/coex_cmd.h

@@ -0,0 +1,16 @@
+/* ESP BLE Mesh Example
+
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#ifndef MAIN_COEX_CMD_H_
+#define MAIN_COEX_CMD_H_
+
+#define CNSL_CMD_OUTPUT_PREFIX      "COEX_CNSL_OUTPUT"
+void register_coex_cmd(void);
+
+#endif /* MAIN_COEX_CMD_H_ */

+ 5 - 0
examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/main/component.mk

@@ -0,0 +1,5 @@
+#
+# "main" pseudo-component makefile.
+#
+# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
+#

+ 145 - 0
examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/main/main.c

@@ -0,0 +1,145 @@
+/* ESP BLE Mesh Example
+
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include "esp_system.h"
+#include "esp_log.h"
+#include "esp_console.h"
+#include "esp_vfs_dev.h"
+#include "driver/uart.h"
+#include "linenoise/linenoise.h"
+#include "argtable3/argtable3.h"
+#include "esp_vfs_fat.h"
+#include "nvs.h"
+#include "nvs_flash.h"
+
+#include "esp_coexist.h"
+#include "coex_cmd.h"
+#include "run_tc.h"
+#include "sync.h"
+
+static void initialize_nvs(void)
+{
+    esp_err_t err = nvs_flash_init();
+    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
+        ESP_ERROR_CHECK( nvs_flash_erase() );
+        err = nvs_flash_init();
+    }
+    ESP_ERROR_CHECK(err);
+}
+
+static void initialize_console(void)
+{
+    /* Disable buffering on stdin and stdout */
+    setvbuf(stdin, NULL, _IONBF, 0);
+
+    /* Minicom, screen, idf_monitor send CR when ENTER key is pressed */
+    esp_vfs_dev_uart_set_rx_line_endings(ESP_LINE_ENDINGS_CR);
+    /* Move the caret to the beginning of the next line on '\n' */
+    esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);
+
+    /* Configure UART. Note that REF_TICK is used so that the baud rate remains
+     * correct while APB frequency is changing in light sleep mode.
+     */
+    const uart_config_t uart_config = {
+        .baud_rate = CONFIG_CONSOLE_UART_BAUDRATE,
+        .data_bits = UART_DATA_8_BITS,
+        .parity = UART_PARITY_DISABLE,
+        .stop_bits = UART_STOP_BITS_1,
+        .use_ref_tick = true
+    };
+    ESP_ERROR_CHECK( uart_param_config(CONFIG_ESP_CONSOLE_UART_NUM, &uart_config) );
+
+    /* Install UART driver for interrupt-driven reads and writes */
+    ESP_ERROR_CHECK( uart_driver_install(CONFIG_ESP_CONSOLE_UART_NUM,
+                                         256, 0, 0, NULL, 0) );
+
+    /* Tell VFS to use UART driver */
+    esp_vfs_dev_uart_use_driver(CONFIG_ESP_CONSOLE_UART_NUM);
+
+    /* Initialize the console */
+    esp_console_config_t console_config = {
+        .max_cmdline_args = 8,
+        .max_cmdline_length = 256,
+#if CONFIG_LOG_COLORS
+        .hint_color = atoi(LOG_COLOR_CYAN)
+#endif
+    };
+    ESP_ERROR_CHECK( esp_console_init(&console_config) );
+
+    /* Configure linenoise line completion library */
+    /* Enable multiline editing. If not set, long commands will scroll within
+     * single line.
+     */
+    linenoiseSetMultiLine(1);
+
+    /* Tell linenoise where to get command completions and hints */
+    linenoiseSetCompletionCallback(&esp_console_get_completion);
+    linenoiseSetHintsCallback((linenoiseHintsCallback *) &esp_console_get_hint);
+
+    /* Set command history size */
+    linenoiseHistorySetMaxLen(100);
+
+}
+
+
+
+void app_main(void)
+{
+    initialize_nvs();
+
+    initialize_console();
+    run_tc_init();
+
+    /* Register commands */
+    esp_console_register_help_command();
+    register_coex_cmd();
+
+#if defined(CONFIG_EXAMPLE_AUTO)
+    sync_init();
+#endif
+
+    /* Prompt to be printed before each line.
+     * This can be customized, made dynamic, etc.
+     */
+    printf("esp-idf version: %s\n\n", esp_get_idf_version());
+    printf("coexist version: %s\n\n", esp_coex_version_get());
+    const char *prompt = "esp32> ";
+    linenoiseSetDumbMode(1);
+
+
+    /* Main loop */
+    while (true) {
+        /* Get a line using linenoise.
+         * The line is returned when ENTER is pressed.
+         */
+        char *line = linenoise(prompt);
+        if (line == NULL) { /* Ignore empty lines */
+            continue;
+        }
+        /* Add the command to the history */
+        linenoiseHistoryAdd(line);
+
+        /* Try to run the command */
+        int ret;
+        esp_err_t err = esp_console_run(line, &ret);
+        if (err == ESP_ERR_NOT_FOUND) {
+            printf("Unrecognized command\n");
+        } else if (err == ESP_ERR_INVALID_ARG) {
+            // command was empty
+        } else if (err == ESP_OK && ret != ESP_OK) {
+            printf("Command returned non-zero error code: 0x%x (%s)\n", ret, esp_err_to_name(err));
+        } else if (err != ESP_OK) {
+            printf("Internal error: %s\n", esp_err_to_name(err));
+        }
+        /* linenoise allocates line buffer on the heap, so need to free it */
+        linenoiseFree(line);
+    }
+}

+ 5 - 0
examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/partitions.csv

@@ -0,0 +1,5 @@
+# Name,   Type, SubType, Offset,  Size, Flags
+# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
+nvs,      data, nvs,     0x9000,  0x6000,
+phy_init, data, phy,     0xf000,  0x1000,
+factory,  app,  factory, 0x10000, 0x1F0000,

+ 110 - 0
examples/bluetooth/esp_ble_mesh/ble_mesh_coex_test/sdkconfig.defaults

@@ -0,0 +1,110 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Espressif IoT Development Framework Configuration
+#
+
+#
+# SDK tool configuration
+#
+CONFIG_SDK_MAKE_WARN_UNDEFINED_VARIABLES=y
+#
+# Partition Table
+#
+# CONFIG_PARTITION_TABLE_SINGLE_APP is not set
+# CONFIG_PARTITION_TABLE_TWO_OTA is not set
+CONFIG_PARTITION_TABLE_CUSTOM=y
+CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
+CONFIG_PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET=0x10000
+CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
+CONFIG_APP_OFFSET=0x10000
+
+
+#
+# Serial flasher config
+#
+CONFIG_ESPTOOLPY_BAUD_921600B=y
+CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
+CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
+
+#
+# Component config
+#
+#
+# Bluetooth
+#
+CONFIG_BT_ENABLED=y
+CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
+CONFIG_BTDM_CTRL_PINNED_TO_CORE=1
+CONFIG_BTDM_MODEM_SLEEP=n
+CONFIG_BTDM_BLE_SCAN_DUPL=y
+CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y
+CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y
+CONFIG_BT_BLUEDROID_ENABLED=y
+CONFIG_BT_BLUEDROID_PINNED_TO_CORE_1=y
+CONFIG_BT_BTU_TASK_STACK_SIZE=4512
+CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y
+CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST=y
+CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY=y
+CONFIG_BT_SMP_ENABLE=y
+CONFIG_BT_RESERVE_DRAM=0x10000
+
+#
+# ESP32-specific
+#
+CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y
+CONFIG_MEMMAP_SMP=y
+CONFIG_ESP32_SPIRAM_SUPPORT=y
+CONFIG_SPIRAM_SPEED_80M=y
+CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=4096
+CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y
+CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=6
+CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200
+CONFIG_SPIRAM_IGNORE_NOTFOUND=y
+
+#
+# Wi-Fi
+#
+CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE=y
+CONFIG_ESP32_WIFI_SW_COEXIST_PREFERENCE_BALANCE=y
+CONFIG_ESP32_WIFI_SW_COEXIST_PREFERENCE_VALUE=2
+CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=16
+CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=64
+CONFIG_ESP32_WIFI_STATIC_TX_BUFFER=y
+CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=0
+CONFIG_ESP32_WIFI_STATIC_TX_BUFFER_NUM=16
+CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y
+CONFIG_ESP32_WIFI_TX_BA_WIN=16
+CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y
+CONFIG_ESP32_WIFI_RX_BA_WIN=16
+CONFIG_ESP32_WIFI_NVS_ENABLED=y
+CONFIG_ESP32_WIFI_MGMT_SBUF_NUM=6
+
+#
+# FreeRTOS
+#
+CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=1536
+CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=5
+CONFIG_FREERTOS_HZ=1000
+
+#
+# LWIP
+#
+CONFIG_LWIP_IP_FRAG=y
+CONFIG_LWIP_IP_REASSEMBLY=y
+CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=64
+CONFIG_LWIP_TCP_SND_BUF_DEFAULT=65534
+CONFIG_LWIP_TCP_WND_DEFAULT=65534
+CONFIG_LWIP_TCP_RECVMBOX_SIZE=64
+CONFIG_LWIP_UDP_RECVMBOX_SIZE=64
+CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU0=y
+CONFIG_LWIP_TCPIP_TASK_AFFINITY=0x0
+
+#
+# ble mesh
+#
+CONFIG_BLE_MESH=y
+CONFIG_BLE_MESH_NODE=y
+CONFIG_BLE_MESH_PB_GATT=y
+CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=10
+CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10
+CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y