Merge branch 'Doc/optimize_spp_doc_v4.4' into 'release/v4.4'

Doc/Optimize SPP Document[backport 4.4]

See merge request espressif/esp-idf!16603
This commit is contained in:
Jiang Jiang Jian 2022-01-27 05:41:33 +00:00
commit 80a395e319
12 changed files with 452 additions and 139 deletions

View File

@ -1,24 +1,39 @@
| Supported Targets | ESP32 |
| ----------------- | ----- |
## ESP-IDF BT-SPP-ACCEPTOR demo
## ESP-IDF BT-SPP-ACCEPTOR Example
This is the demo for user to use ESP_APIs to create a **Serial Port Protocol** (**SPP**) acceptor and we aggregate **Secure Simple Pair** (**SSP**) into this demo to show how to use SPP when creating your own APPs.
This example is to show how to use the APIs of **Serial Port Protocol** (**SPP**) to create an SPP acceptor which performs as a server. We aggregate **Secure Simple Pair** (**SSP**) into this example to show how to use SPP when creating your own APPs. We also provide the example `bt_spp_initiator` or the example `bt_spp_vfs_initiator` to create an SPP initiator which performs as a client. In fact, you can create SPP acceptors and SPP initiators on a single device at the same time.
## How to use example
### Hardware Required
This example is designed to run on commonly available ESP32 development board, e.g. ESP32-DevKitC.
To operate it should be connected to an SPP Initiator running on a smartphone or on another ESP32 development board.
This example is designed to run on commonly available ESP32 development board, e.g. ESP32-DevKitC. To operate the example, it should be connected to an SPP Initiator running on a smartphone, a computer or on another ESP32 development board.
### Configure the project
1. Open the project configuration menu:
```
idf.py menuconfig
```
2. Enable the SPP functionality by choosing the path as following:
`Component config --> Bluetooth --> Bluedroid Options --> SPP`
3. If you want to limit the number of connected devices, please make sure set the `BT/BLE MAX ACL CONNECTIONS` and `BR/EDR ACL Max Connections` with same value you want.
`Component config --> Bluetooth --> Bluedroid Options --> BT/BLE MAX ACL CONNECTIONS(1~7)`
and
`Component config --> Bluetooth --> Bluetooth --> Bluetooth controller --> BR/EDR ACL Max Connections`
4. SSP is enabled as default in this example. If you prefer the legacy pairing, you can disable it in the following path.
`Component config --> Bluetooth--> Bluedroid Options --> Secure Simple Pair`.
### Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output:
@ -35,16 +50,19 @@ See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/l
## Example Description
After the program started, `bt_spp_initator` will connect it and send data.
After the program starts, the example will start an SPP acceptor. The example will calculate the data rate or just print the received data after the SPP connection is established. You can connect to the server and send data with another ESP32 development board, Andriod phone or computer which performs as the SPP initiator.
## Trouble shooting
- Acceptor is expected to start before `bt_spp_initator` start.
- To see the information of data, users shall set `SPP_SHOW_MODE` as `SPP_SHOW_DATA` or `SPP_SHOW_SPEED` in code(should be same with `bt_spp_initator`).
- We also show the Security Simple Pair in this SPP demo. Users can set the IO Capability and Security Mode for their device (security level is fixed level 4). The default security mode of this demo is `ESP_SPP_SEC_AUTHENTICATE` which support MITM (Man In The Middle) protection. For more information about Security Simple Pair on ESP32, please refer to [ESP32_SSP](./ESP32_SSP.md).
- To see the information of data, users shall set `SPP_SHOW_MODE` as `SPP_SHOW_DATA` or `SPP_SHOW_SPEED` in code(should be same with `bt_spp_initiator`, if the peer device runs it). When setting `SPP_SHOW_MODE` as `SPP_SHOW_DATA`, if the data rate is too high or the data length is too long, it is strongly recommended to process them in other lower priority application task rather than in this callback directly. Since the printing takes too much time, and it may stuck the Bluetooth stack.
## FAQ
Q: How to change the process of SSP?
A: Users can set the IO Capability and Security Mask for their device (fixed Security Mode, Security Mode 4). In short, the Security Mask sets the security level for authentication stage and the IO Capability determines the way of user interaction during pairing. The default Security Mask of this example is `ESP_SPP_SEC_AUTHENTICATE` which support MITM (Man In The Middle) protection. For more information about Security Simple Pair on ESP32, please refer to [ESP32_SSP](./ESP32_SSP.md).
Q: How many SPP servers does ESP32 support?
A: For now, the maximum number of SPP servers is 6, which is limited by the maximum number of SDP records. When the SPP server is successfully started, the unique SCN (Server Channel Number) will be mapped to the SPP server.
Q: Is SPP absolutely reliable?
A: For now, most Bluetooth stacks implement the SPP based on the L2CAP Basic Mode, and the reliability only depends on the controller. If errors(e.g. CRC) are missed by controller, the L2CAP packet will not be retransmitted, so it is recommended that you should implement the retransmission at the application layer. For more information about L2CAP operation modes, please refer to Bluetooth Core Specification, Version 4.2 or later, Volume 3, Part A: Logical Link Control and Adaptation Protocol Specification.

View File

@ -1,2 +1,2 @@
idf_component_register(SRCS "example_spp_acceptor_demo.c"
idf_component_register(SRCS "main.c"
INCLUDE_DIRS ".")

View File

@ -39,6 +39,18 @@ static long data_num = 0;
static const esp_spp_sec_t sec_mask = ESP_SPP_SEC_AUTHENTICATE;
static const esp_spp_role_t role_slave = ESP_SPP_ROLE_SLAVE;
static char *bda2str(uint8_t *bda, char *str, size_t size)
{
if (bda == NULL || str == NULL || size < 18) {
return NULL;
}
uint8_t *p = bda;
sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
p[0], p[1], p[2], p[3], p[4], p[5]);
return str;
}
static void print_speed(void)
{
float time_old_s = time_old.tv_sec + time_old.tv_usec / 1000000.0;
@ -53,10 +65,16 @@ static void print_speed(void)
static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
{
char bda_str[18] = {0};
switch (event) {
case ESP_SPP_INIT_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_INIT_EVT");
esp_spp_start_srv(sec_mask,role_slave, 0, SPP_SERVER_NAME);
if (param->init.status == ESP_SPP_SUCCESS) {
ESP_LOGI(SPP_TAG, "ESP_SPP_INIT_EVT");
esp_spp_start_srv(sec_mask, role_slave, 0, SPP_SERVER_NAME);
} else {
ESP_LOGE(SPP_TAG, "ESP_SPP_INIT_EVT status:%d", param->init.status);
}
break;
case ESP_SPP_DISCOVERY_COMP_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_DISCOVERY_COMP_EVT");
@ -65,21 +83,35 @@ static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
ESP_LOGI(SPP_TAG, "ESP_SPP_OPEN_EVT");
break;
case ESP_SPP_CLOSE_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_CLOSE_EVT");
ESP_LOGI(SPP_TAG, "ESP_SPP_CLOSE_EVT status:%d handle:%d close_by_remote:%d", param->close.status,
param->close.handle, param->close.async);
break;
case ESP_SPP_START_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_START_EVT");
esp_bt_dev_set_device_name(EXAMPLE_DEVICE_NAME);
esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
if (param->start.status == ESP_SPP_SUCCESS) {
ESP_LOGI(SPP_TAG, "ESP_SPP_START_EVT handle:%d sec_id:%d scn:%d", param->start.handle, param->start.sec_id,
param->start.scn);
esp_bt_dev_set_device_name(EXAMPLE_DEVICE_NAME);
esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
} else {
ESP_LOGE(SPP_TAG, "ESP_SPP_START_EVT status:%d", param->start.status);
}
break;
case ESP_SPP_CL_INIT_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_CL_INIT_EVT");
break;
case ESP_SPP_DATA_IND_EVT:
#if (SPP_SHOW_MODE == SPP_SHOW_DATA)
ESP_LOGI(SPP_TAG, "ESP_SPP_DATA_IND_EVT len=%d handle=%d",
/*
* We only show the data in which the data length is less than 128 here. If you want to print the data and
* the data rate is high, it is strongly recommended to process them in other lower priority application task
* rather than in this callback directly. Since the printing takes too much time, it may stuck the Bluetooth
* stack and also have a effect on the throughput!
*/
ESP_LOGI(SPP_TAG, "ESP_SPP_DATA_IND_EVT len:%d handle:%d",
param->data_ind.len, param->data_ind.handle);
esp_log_buffer_hex("",param->data_ind.data,param->data_ind.len);
if (param->data_ind.len < 128) {
esp_log_buffer_hex("", param->data_ind.data, param->data_ind.len);
}
#else
gettimeofday(&time_new, NULL);
data_num += param->data_ind.len;
@ -95,7 +127,8 @@ static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
ESP_LOGI(SPP_TAG, "ESP_SPP_WRITE_EVT");
break;
case ESP_SPP_SRV_OPEN_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_SRV_OPEN_EVT");
ESP_LOGI(SPP_TAG, "ESP_SPP_SRV_OPEN_EVT status:%d handle:%d, rem_bda:[%s]", param->srv_open.status,
param->srv_open.handle, bda2str(param->srv_open.rem_bda, bda_str, sizeof(bda_str)));
gettimeofday(&time_old, NULL);
break;
case ESP_SPP_SRV_STOP_EVT:
@ -111,11 +144,13 @@ static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
{
char bda_str[18] = {0};
switch (event) {
case ESP_BT_GAP_AUTH_CMPL_EVT:{
if (param->auth_cmpl.stat == ESP_BT_STATUS_SUCCESS) {
ESP_LOGI(SPP_TAG, "authentication success: %s", param->auth_cmpl.device_name);
esp_log_buffer_hex(SPP_TAG, param->auth_cmpl.bda, ESP_BD_ADDR_LEN);
ESP_LOGI(SPP_TAG, "authentication success: %s bda:[%s]", param->auth_cmpl.device_name,
bda2str(param->auth_cmpl.bda, bda_str, sizeof(bda_str)));
} else {
ESP_LOGE(SPP_TAG, "authentication failed, status:%d", param->auth_cmpl.stat);
}
@ -153,7 +188,8 @@ void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
#endif
case ESP_BT_GAP_MODE_CHG_EVT:
ESP_LOGI(SPP_TAG, "ESP_BT_GAP_MODE_CHG_EVT mode:%d", param->mode_chg.mode);
ESP_LOGI(SPP_TAG, "ESP_BT_GAP_MODE_CHG_EVT mode:%d bda:[%s]", param->mode_chg.mode,
bda2str(param->mode_chg.bda, bda_str, sizeof(bda_str)));
break;
default: {
@ -166,6 +202,7 @@ void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
void app_main(void)
{
char bda_str[18] = {0};
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
@ -225,4 +262,6 @@ void app_main(void)
esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_VARIABLE;
esp_bt_pin_code_t pin_code;
esp_bt_gap_set_pin(pin_type, 0, pin_code);
ESP_LOGI(SPP_TAG, "Own address:[%s]", bda2str((uint8_t *)esp_bt_dev_get_address(), bda_str, sizeof(bda_str)));
}

View File

@ -1,23 +1,30 @@
| Supported Targets | ESP32 |
| ----------------- | ----- |
# ESP-IDF BT-SPP-INITATOR demo
# ESP-IDF BT-SPP-INITATOR Example
This is the demo for user to use ESP_APIs to create a **Serial Port Protocol** (**SPP**) initiator and we aggregate **Secure Simple Pair** (**SSP**) into this demo to show how to use SPP when creating your own APPs.
This example is to show how to use the APIs of **Serial Port Protocol** (**SPP**) to create an SPP initiator which performs as a client. we aggregate **Secure Simple Pair** (**SSP**) into this example to show how to use SPP when creating your own APPs. We also provide the example `bt_spp_acceptor` or the example `bt_spp_vfs_acceptor` to create an SPP acceptor which performs as a server. In fact, you can create SPP acceptors and SPP initiators on a single device at the same time.
## How to use example
### Hardware Required
This example is designed to run on commonly available ESP32 development board, e.g. ESP32-DevKitC. To operate it should be connected to an SPP Acceptor running on another device.
This example is designed to run on commonly available ESP32 development board, e.g. ESP32-DevKitC. To operate the example, you should be connect to an SPP acceptor running on a smartphone, a computer or on another ESP32 development board.
### Configure the project
1. Open the project configuration menu:
```
idf.py menuconfig
```
In `menuconfig` path: `Coponent config --> Bluetooth--> Bluedroid Options -->SPP` and `Coponent config --> Bluetooth--> Bluedroid Options -->Secure Simple Pair`.
2. Enable the SPP functionality by choosing the path as following:
`Component config --> Bluetooth --> Bluedroid Options --> SPP`.
3. SSP is enabled as default in this example. If you prefer the legacy pairing, you can disable it in the following path.
`Component config --> Bluetooth--> Bluedroid Options --> Secure Simple Pair`.
### Build and Flash
@ -33,6 +40,9 @@ idf.py -p PORT flash monitor
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
## Example Description
After the program starts, the example will initiate a Bluetooth discovery procedure and filter out the peer device by the name in the EIR(Extended Inquiry Response). After discovering the SPP service, it will connect to the SPP acceptor and send data. The example will calculate the data rate or print the sent data after the SPP connection is established.
### Example Output
When you run this example and the IO capability is `ESP_IO_CAP_IO` or `ESP_IO_CAP_IN` , the commands help table prints the following at the very beginning:
@ -98,13 +108,9 @@ Whether you should passkey or confirm the number also depends on the IO capabili
## Troubleshouting
- Set `SPP_SHOW_MODE` as `SPP_SHOW_DATA` or `SPP_SHOW_SPEED` in code (should be same with bt_spp_acceptor).
- Set `SPP_SHOW_MODE` as `SPP_SHOW_DATA` or `SPP_SHOW_SPEED` in code (should be same with `bt_spp_acceptor`, if the peer device runs it). When setting `SPP_SHOW_MODE` as `SPP_SHOW_DATA`, if the data rate is too high or the data length is too long, it is strongly recommended to process them in other lower priority application task rather than in this callback directly. Since the printing takes too much time, and it may stuck the Bluetooth stack.
- After the program started, It will connect to bt_spp_acceptor and send data.
- We haven't do the same update to `bt_acceptor_demo` for the sake of reducing the size of ESP_IDF, but transplanting of input module is supported.
- We also show the Security Simple Pair in this SPP demo. Users can set the IO Capability and Security Mode for their device (security level is fixed level 4). The default security mode of this demo is `ESP_SPP_SEC_AUTHENTICATE` which support MITM (Man In The Middle) protection. For more information about Security Simple Pair on ESP32, please refer to [ESP32_SSP](../bt_spp_acceptor/ESP32_SSP.md).
- We haven't do the same update to the example `bt_spp_acceptor` for the sake of reducing the size of ESP_IDF, but transplanting of input module is supported.
## Example Breakdown
@ -116,11 +122,10 @@ To clearly show how the SSP aggregate with the SPP , we use the Commands and Eff
- If you want to update the command parse rules, please refer to `app_spp_msg_prs.c`.
- If you want to update the responses of HF Unit or want to update the log, please refer to `bt_app_spp.c`.
- Task configuration part is in `example_spp_initiator_demo.c`.
## FAQ
Q: How to change the process of SSP?
A: Users can set the IO Capability and Security Mask for their device (fixed Security Mode, Security Mode 4). In short, the Security Mask sets the security level for authentication stage and the IO Capability determines the way of user interaction during pairing. The default Security Mask of this example is `ESP_SPP_SEC_AUTHENTICATE` which support MITM (Man In The Middle) protection. For more information about Security Simple Pair on ESP32, please refer to [ESP32_SSP](../bt_spp_acceptor/ESP32_SSP.md).
Q: How can we reach the maximum throughput when using SPP?
A: The default MTU size of classic Bluetooth SPP on ESP32 is 990 bytes, and higher throughput can be achieved in the case that data chunck size is close to the MTU size or multiple of MTU size. For example, sending 100 bytes data per second is much better than sending 10 bytes every 100 milliseconds.

View File

@ -1,4 +1,4 @@
idf_component_register(SRCS "example_spp_initiator_demo.c"
idf_component_register(SRCS "main.c"
SRCS "app_spp_msg_prs.c"
SRCS "app_spp_msg_set.c"
SRCS "console_uart.c"

View File

@ -54,6 +54,19 @@ static const uint8_t inq_num_rsps = 0;
#define SPP_DATA_LEN ESP_SPP_MAX_MTU
#endif
static uint8_t spp_data[SPP_DATA_LEN];
static uint8_t *s_p_data = NULL; /* data pointer of spp_data */
static char *bda2str(uint8_t *bda, char *str, size_t size)
{
if (bda == NULL || str == NULL || size < 18) {
return NULL;
}
uint8_t *p = bda;
sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
p[0], p[1], p[2], p[3], p[4], p[5]);
return str;
}
static void print_speed(void)
{
@ -101,58 +114,123 @@ static bool get_name_from_eir(uint8_t *eir, char *bdname, uint8_t *bdname_len)
static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
{
uint8_t i = 0;
char bda_str[18] = {0};
switch (event) {
case ESP_SPP_INIT_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_INIT_EVT");
esp_bt_dev_set_device_name(EXAMPLE_DEVICE_NAME);
esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
esp_bt_gap_start_discovery(inq_mode, inq_len, inq_num_rsps);
if (param->init.status == ESP_SPP_SUCCESS) {
ESP_LOGI(SPP_TAG, "ESP_SPP_INIT_EVT");
esp_bt_dev_set_device_name(EXAMPLE_DEVICE_NAME);
esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
esp_bt_gap_start_discovery(inq_mode, inq_len, inq_num_rsps);
} else {
ESP_LOGE(SPP_TAG, "ESP_SPP_INIT_EVT status:%d", param->init.status);
}
break;
case ESP_SPP_DISCOVERY_COMP_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_DISCOVERY_COMP_EVT status=%d scn_num=%d",param->disc_comp.status, param->disc_comp.scn_num);
if (param->disc_comp.status == ESP_SPP_SUCCESS) {
ESP_LOGI(SPP_TAG, "ESP_SPP_DISCOVERY_COMP_EVT scn_num:%d", param->disc_comp.scn_num);
for (i = 0; i < param->disc_comp.scn_num; i++) {
ESP_LOGI(SPP_TAG, "-- [%d] scn:%d service_name:%s", i, param->disc_comp.scn[i],
param->disc_comp.service_name[i]);
}
/* We only connect to the first found server on the remote SPP acceptor here */
esp_spp_connect(sec_mask, role_master, param->disc_comp.scn[0], peer_bd_addr);
} else {
ESP_LOGE(SPP_TAG, "ESP_SPP_DISCOVERY_COMP_EVT status=%d", param->disc_comp.status);
}
break;
case ESP_SPP_OPEN_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_OPEN_EVT");
esp_spp_write(param->open.handle, SPP_DATA_LEN, spp_data);
gettimeofday(&time_old, NULL);
if (param->open.status == ESP_SPP_SUCCESS) {
ESP_LOGI(SPP_TAG, "ESP_SPP_OPEN_EVT handle:%d rem_bda:[%s]", param->open.handle,
bda2str(param->open.rem_bda, bda_str, sizeof(bda_str)));
/* Start to write the first data packet */
esp_spp_write(param->open.handle, SPP_DATA_LEN, spp_data);
s_p_data = spp_data;
gettimeofday(&time_old, NULL);
} else {
ESP_LOGE(SPP_TAG, "ESP_SPP_OPEN_EVT status:%d", param->open.status);
}
break;
case ESP_SPP_CLOSE_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_CLOSE_EVT");
ESP_LOGI(SPP_TAG, "ESP_SPP_CLOSE_EVT status:%d handle:%d close_by_remote:%d", param->close.status,
param->close.handle, param->close.async);
break;
case ESP_SPP_START_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_START_EVT");
break;
case ESP_SPP_CL_INIT_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_CL_INIT_EVT");
if (param->cl_init.status == ESP_SPP_SUCCESS) {
ESP_LOGI(SPP_TAG, "ESP_SPP_CL_INIT_EVT handle:%d sec_id:%d", param->cl_init.handle, param->cl_init.sec_id);
} else {
ESP_LOGE(SPP_TAG, "ESP_SPP_CL_INIT_EVT status:%d", param->cl_init.status);
}
break;
case ESP_SPP_DATA_IND_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_DATA_IND_EVT");
break;
case ESP_SPP_WRITE_EVT:
if (param->write.status == ESP_SPP_SUCCESS) {
if (s_p_data + param->write.len == spp_data + SPP_DATA_LEN) {
/* Means the previous data packet be sent completely, send a new data packet */
s_p_data = spp_data;
} else {
/*
* Means the previous data packet only be sent partially due to the lower layer congestion, resend the
* remainning data.
*/
s_p_data += param->write.len;
}
#if (SPP_SHOW_MODE == SPP_SHOW_DATA)
/*
* We only show the data in which the data length is less than 128 here. If you want to print the data and
* the data rate is high, it is strongly recommended to process them in other lower priority application task
* rather than in this callback directly. Since the printing takes too much time, it may stuck the Bluetooth
* stack and also have a effect on the throughput!
*/
ESP_LOGI(SPP_TAG, "ESP_SPP_WRITE_EVT len:%d handle:%d cong:%d", param->write.len, param->write.handle,
param->write.cong);
if (param->write.len < 128) {
esp_log_buffer_hex("", spp_data, param->write.len);
/* Delay a little to avoid the task watch dog */
vTaskDelay(pdMS_TO_TICKS(10));
}
#else
gettimeofday(&time_new, NULL);
data_num += param->write.len;
if (time_new.tv_sec - time_old.tv_sec >= 3) {
print_speed();
}
#endif
} else {
/* Means the prevous data packet is not sent at all, need to send the whole data packet again. */
ESP_LOGE(SPP_TAG, "ESP_SPP_WRITE_EVT status:%d", param->write.status);
}
if (!param->write.cong) {
/* The lower layer is not congested, you can send the next data packet now. */
esp_spp_write(param->write.handle, spp_data + SPP_DATA_LEN - s_p_data, s_p_data);
} else {
/*
* The lower layer is congested now, don't send the next data packet until receiving the
* ESP_SPP_CONG_EVT with param->cong.cong == 0.
*/
;
}
/*
* If you don't want to manage this complicated process, we also provide the SPP VFS mode that hides the
* implementation details. However, it is less efficient and will block the caller until all data has been sent.
*/
break;
case ESP_SPP_CONG_EVT:
#if (SPP_SHOW_MODE == SPP_SHOW_DATA)
ESP_LOGI(SPP_TAG, "ESP_SPP_CONG_EVT cong=%d", param->cong.cong);
ESP_LOGI(SPP_TAG, "ESP_SPP_CONG_EVT cong:%d", param->cong.cong);
#endif
if (param->cong.cong == 0) {
esp_spp_write(param->cong.handle, SPP_DATA_LEN, spp_data);
}
break;
case ESP_SPP_WRITE_EVT:
#if (SPP_SHOW_MODE == SPP_SHOW_DATA)
ESP_LOGI(SPP_TAG, "ESP_SPP_WRITE_EVT len=%d cong=%d", param->write.len , param->write.cong);
esp_log_buffer_hex("",spp_data,SPP_DATA_LEN);
#else
gettimeofday(&time_new, NULL);
data_num += param->write.len;
if (time_new.tv_sec - time_old.tv_sec >= 3) {
print_speed();
}
#endif
if (param->write.cong == 0) {
esp_spp_write(param->write.handle, SPP_DATA_LEN, spp_data);
/* Send the privous (partial) data packet or the next data packet. */
esp_spp_write(param->write.handle, spp_data + SPP_DATA_LEN - s_p_data, s_p_data);
}
break;
case ESP_SPP_SRV_OPEN_EVT:
@ -172,6 +250,7 @@ static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa
case ESP_BT_GAP_DISC_RES_EVT:
ESP_LOGI(SPP_TAG, "ESP_BT_GAP_DISC_RES_EVT");
esp_log_buffer_hex(SPP_TAG, param->disc_res.bda, ESP_BD_ADDR_LEN);
/* Find the target peer device name in the EIR data */
for (int i = 0; i < param->disc_res.num_prop; i++){
if (param->disc_res.prop[i].type == ESP_BT_GAP_DEV_PROP_EIR
&& get_name_from_eir(param->disc_res.prop[i].val, peer_bdname, &peer_bdname_len)){
@ -179,8 +258,10 @@ static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa
if (strlen(remote_device_name) == peer_bdname_len
&& strncmp(peer_bdname, remote_device_name, peer_bdname_len) == 0) {
memcpy(peer_bd_addr, param->disc_res.bda, ESP_BD_ADDR_LEN);
esp_spp_start_discovery(peer_bd_addr);
/* Have found the target peer device, cancel the previous GAP discover procedure. And go on
* dsicovering the SPP service on the peer device */
esp_bt_gap_cancel_discovery();
esp_spp_start_discovery(peer_bd_addr);
}
}
}
@ -247,11 +328,14 @@ static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa
void app_main(void)
{
esp_err_t ret = ESP_OK;
char bda_str[18] = {0};
for (int i = 0; i < SPP_DATA_LEN; ++i) {
spp_data[i] = i;
}
esp_err_t ret = nvs_flash_init();
ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
@ -286,6 +370,17 @@ void app_main(void)
return;
}
#if (CONFIG_BT_SSP_ENABLED == true)
/* Set default parameters for Secure Simple Pairing */
esp_bt_sp_param_t param_type = ESP_BT_SP_IOCAP_MODE;
esp_bt_io_cap_t iocap = ESP_BT_IO_CAP_IN;
esp_bt_gap_set_security_param(param_type, &iocap, sizeof(uint8_t));
if (iocap == ESP_BT_IO_CAP_IN || iocap == ESP_BT_IO_CAP_IO) {
console_uart_init();
vTaskDelay(pdMS_TO_TICKS(500));
}
#endif
if ((ret = esp_spp_register_callback(esp_spp_cb)) != ESP_OK) {
ESP_LOGE(SPP_TAG, "%s spp register failed: %s\n", __func__, esp_err_to_name(ret));
return;
@ -296,16 +391,6 @@ void app_main(void)
return;
}
#if (CONFIG_BT_SSP_ENABLED == true)
/* Set default parameters for Secure Simple Pairing */
esp_bt_sp_param_t param_type = ESP_BT_SP_IOCAP_MODE;
esp_bt_io_cap_t iocap = ESP_BT_IO_CAP_IN;
esp_bt_gap_set_security_param(param_type, &iocap, sizeof(uint8_t));
if (iocap == ESP_BT_IO_CAP_IN || iocap == ESP_BT_IO_CAP_IO) {
console_uart_init();
}
#endif
/*
* Set default parameters for Legacy Pairing
* Use variable pin, input pin code when pairing
@ -313,4 +398,6 @@ void app_main(void)
esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_VARIABLE;
esp_bt_pin_code_t pin_code;
esp_bt_gap_set_pin(pin_type, 0, pin_code);
ESP_LOGI(SPP_TAG, "Own address:[%s]", bda2str((uint8_t *)esp_bt_dev_get_address(), bda_str, sizeof(bda_str)));
}

View File

@ -1,17 +1,56 @@
| Supported Targets | ESP32 |
| ----------------- | ----- |
ESP-IDF BT-SPP-VFS-ACCEPTOR demo
======================
## ESP-IDF BT-SPP-VFS-ACCEPTOR Example
Demo of SPP acceptor role
This example is to show how to use the APIs of **Serial Port Protocol** (**SPP**) to create an SPP acceptor which performs as a server, and it will register into the VFS. We aggregate **Secure Simple Pair** (**SSP**) into this example to show how to use SPP when creating your own APPs. We also provide the example `bt_spp_initiator` or the example `bt_spp_vfs_initiator` to create an SPP initiator which performs as a client. In fact, you can create SPP acceptors and SPP initiators on a single device at the same time.
This is the demo for user to use ESP_APIs to create a SPP acceptor.
## How to use example
Options choose step:
1. `idf.py menuconfig`
2. enter menuconfig `Component config`, choose `Bluetooth`
3. enter menu Bluetooth, choose `Classic Bluetooth` and `SPP Profile`
4. choose your options.
### Hardware Required
After the program started, bt_spp_vfs_initator will connect it and send data.
This example is designed to run on commonly available ESP32 development board, e.g. ESP32-DevKitC. To operate the example, it should be connected to an SPP Initiator running on a smartphone, a computer or on another ESP32 development board.
### Configure the project
1. Open the project configuration menu:
```
idf.py menuconfig
```
2. Enable the SPP functionality by choosing the path as following:
`Component config --> Bluetooth --> Bluedroid Options --> SPP`
3. If you want to limit the number of connected devices, please make sure set the `BT/BLE MAX ACL CONNECTIONS` and `BR/EDR ACL Max Connections` with same value you want.
`Component config --> Bluetooth --> Bluedroid Options --> BT/BLE MAX ACL CONNECTIONS(1~7)`
and
`Component config --> Bluetooth --> Bluetooth --> Bluetooth controller --> BR/EDR ACL Max Connections`
4. SSP is enabled as default in this example. If you prefer the legacy pairing, you can disable it in the following path.
`Component config --> Bluetooth--> Bluedroid Options --> Secure Simple Pair`.
### Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output:
```
idf.py -p PORT flash monitor
```
(Replace PORT with the name of the serial port to use.)
(To exit the serial monitor, type ``Ctrl-]``.)
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
## Example Description
After the program starts, the example will start an SPP acceptor. The example will print the received data after the SPP connection is established. You can connect to the server and send data with another ESP32 development board, Andriod phone or computer which performs as the SPP initiator.
## FAQ
Please refer the FAQ part in the [README.md](../bt_spp_acceptor/README.md)

View File

@ -1,3 +1,3 @@
idf_component_register(SRCS "example_spp_vfs_acceptor_demo.c"
idf_component_register(SRCS "main.c"
"spp_task.c"
INCLUDE_DIRS ".")

View File

@ -46,27 +46,51 @@ static const esp_spp_sec_t sec_mask = ESP_SPP_SEC_AUTHENTICATE;
static const esp_spp_role_t role_slave = ESP_SPP_ROLE_SLAVE;
#define SPP_DATA_LEN 100
static uint8_t spp_data[SPP_DATA_LEN];
static char *bda2str(uint8_t *bda, char *str, size_t size)
{
if (bda == NULL || str == NULL || size < 18) {
return NULL;
}
uint8_t *p = bda;
sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
p[0], p[1], p[2], p[3], p[4], p[5]);
return str;
}
static void spp_read_handle(void * param)
{
int size = 0;
int fd = (int)param;
do {
/* controll the log frequency, retry after 1s */
vTaskDelay(1000 / portTICK_PERIOD_MS);
uint8_t *spp_data = NULL;
size = read (fd, spp_data, SPP_DATA_LEN);
ESP_LOGI(SPP_TAG, "fd = %d data_len = %d", fd, size);
if (size == -1) {
spp_data = malloc(SPP_DATA_LEN);
if (!spp_data) {
ESP_LOGE(SPP_TAG, "malloc spp_data failed, fd:%d", fd);
goto done;
}
do {
/* The frequency of calling this function also limits the speed at which the peer device can send data. */
size = read(fd, spp_data, SPP_DATA_LEN);
if (size < 0) {
break;
}
esp_log_buffer_hex(SPP_TAG, spp_data, size);
if (size == 0) {
/*read fail due to there is no data, retry after 1s*/
vTaskDelay(1000 / portTICK_PERIOD_MS);
} else if (size == 0) {
/* There is no data, retry after 500 ms */
vTaskDelay(500 / portTICK_PERIOD_MS);
} else {
ESP_LOGI(SPP_TAG, "fd = %d data_len = %d", fd, size);
esp_log_buffer_hex(SPP_TAG, spp_data, size);
/* To avoid task watchdog */
vTaskDelay(10 / portTICK_PERIOD_MS);
}
} while (1);
done:
if (spp_data) {
free(spp_data);
}
spp_wr_task_shut_down();
}
@ -74,13 +98,17 @@ static void esp_spp_cb(uint16_t e, void *p)
{
esp_spp_cb_event_t event = e;
esp_spp_cb_param_t *param = p;
char bda_str[18] = {0};
switch (event) {
case ESP_SPP_INIT_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_INIT_EVT status=%d", param->init.status);
if (param->init.status == ESP_SPP_SUCCESS) {
ESP_LOGI(SPP_TAG, "ESP_SPP_INIT_EVT");
/* Enable SPP VFS mode */
esp_spp_vfs_register();
esp_spp_start_srv(sec_mask, role_slave, 0, SPP_SERVER_NAME);
} else {
ESP_LOGE(SPP_TAG, "ESP_SPP_INIT_EVT status:%d", param->init.status);
}
break;
case ESP_SPP_DISCOVERY_COMP_EVT:
@ -90,18 +118,25 @@ static void esp_spp_cb(uint16_t e, void *p)
ESP_LOGI(SPP_TAG, "ESP_SPP_OPEN_EVT");
break;
case ESP_SPP_CLOSE_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_CLOSE_EVT");
ESP_LOGI(SPP_TAG, "ESP_SPP_CLOSE_EVT status:%d handle:%d close_by_remote:%d", param->close.status,
param->close.handle, param->close.async);
break;
case ESP_SPP_START_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_START_EVT");
esp_bt_dev_set_device_name(EXAMPLE_DEVICE_NAME);
esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
if (param->start.status == ESP_SPP_SUCCESS) {
ESP_LOGI(SPP_TAG, "ESP_SPP_START_EVT handle:%d sec_id:%d scn:%d", param->start.handle, param->start.sec_id,
param->start.scn);
esp_bt_dev_set_device_name(EXAMPLE_DEVICE_NAME);
esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
} else {
ESP_LOGE(SPP_TAG, "ESP_SPP_START_EVT status:%d", param->start.status);
}
break;
case ESP_SPP_CL_INIT_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_CL_INIT_EVT");
break;
case ESP_SPP_SRV_OPEN_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_SRV_OPEN_EVT status=%d", param->srv_open.status);
ESP_LOGI(SPP_TAG, "ESP_SPP_SRV_OPEN_EVT status:%d handle:%d, rem_bda:[%s]", param->srv_open.status,
param->srv_open.handle, bda2str(param->srv_open.rem_bda, bda_str, sizeof(bda_str)));
if (param->srv_open.status == ESP_SPP_SUCCESS) {
spp_wr_task_start_up(spp_read_handle, param->srv_open.fd);
}
@ -113,6 +148,7 @@ static void esp_spp_cb(uint16_t e, void *p)
static void esp_spp_stack_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
{
/* To avoid stucking Bluetooth stack, we dispatch the SPP callback event to the other lower priority task */
spp_task_work_dispatch(esp_spp_cb, event, param, sizeof(esp_spp_cb_param_t), NULL);
}
@ -173,6 +209,7 @@ void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
void app_main(void)
{
char bda_str[18] = {0};
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
@ -234,4 +271,6 @@ void app_main(void)
esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_VARIABLE;
esp_bt_pin_code_t pin_code;
esp_bt_gap_set_pin(pin_type, 0, pin_code);
ESP_LOGI(SPP_TAG, "Own address:[%s]", bda2str((uint8_t *)esp_bt_dev_get_address(), bda_str, sizeof(bda_str)));
}

View File

@ -1,17 +1,48 @@
| Supported Targets | ESP32 |
| ----------------- | ----- |
ESP-IDF BT-SPP-VFS-INITATOR demo
======================
# ESP-IDF BT-SPP-INITATOR Example
Demo of SPP initator role
This example is to show how to use the APIs of **Serial Port Protocol** (**SPP**) to create an SPP initiator which performs as a client, and it will register into the VFS. we aggregate **Secure Simple Pair** (**SSP**) into this example to show how to use SPP when creating your own APPs. We also provide the example `bt_spp_acceptor` or the example `bt_spp_vfs_acceptor` to create an SPP acceptor which performs as a server. In fact, you can create SPP acceptors and SPP initiators on a single device at the same time.
This is the demo for user to use ESP_APIs to create a SPP initator.
## How to use example
Options choose step:
1. `idf.py menuconfig`
2. enter menuconfig `Component config`, choose `Bluetooth`
3. enter menu Bluetooth, choose `Classic Bluetooth` and `SPP Profile`
4. choose your options.
### Hardware Required
After the program started, It will connect to bt_spp_vfs_acceptor and send data.
This example is designed to run on commonly available ESP32 development board, e.g. ESP32-DevKitC. To operate the example, you should be connect to an SPP acceptor running on a smartphone, a computer or on another ESP32 development board.
### Configure the project
1. Open the project configuration menu:
```
idf.py menuconfig
```
2. Enable the SPP functionality by choosing the path as following:
`Component config --> Bluetooth --> Bluedroid Options --> SPP`.
3. SSP is enabled as default in this example. If you prefer the legacy pairing, you can disable it in the following path.
`Component config --> Bluetooth--> Bluedroid Options --> Secure Simple Pair`.
### Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output:
```
idf.py -p PORT flash monitor
```
(Replace PORT with the name of the serial port to use.)
(To exit the serial monitor, type ``Ctrl-]``.)
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
## Example Description
After the program starts, the example will initiate a Bluetooth discovery procedure and filter out the peer device by the name in the EIR(Extended Inquiry Response). After discovering the SPP service, it will connect to the SPP acceptor and send data.
## FAQ
Please refer the FAQ part in the [README.md](../bt_spp_initiator/README.md)

View File

@ -1,3 +1,3 @@
idf_component_register(SRCS "example_spp_vfs_initiator_demo.c"
idf_component_register(SRCS "main.c"
"spp_task.c"
INCLUDE_DIRS ".")

View File

@ -53,26 +53,56 @@ static const uint8_t inq_len = 30;
static const uint8_t inq_num_rsps = 0;
#define SPP_DATA_LEN 20
static uint8_t spp_data[SPP_DATA_LEN];
static char *bda2str(uint8_t *bda, char *str, size_t size)
{
if (bda == NULL || str == NULL || size < 18) {
return NULL;
}
uint8_t *p = bda;
sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
p[0], p[1], p[2], p[3], p[4], p[5]);
return str;
}
static void spp_write_handle(void * param)
{
int size = 0;
int fd = (int)param;
printf("%s %d %p\n", __func__,fd,param);
do {
/*Controll the log frequency, retry after 1s*/
vTaskDelay(1000 / portTICK_PERIOD_MS);
uint8_t *spp_data = NULL;
uint16_t i = 0;
size = write (fd, spp_data, SPP_DATA_LEN);
ESP_LOGI(SPP_TAG, "fd = %d data_len = %d",fd, size);
spp_data = malloc(SPP_DATA_LEN);
if (!spp_data) {
ESP_LOGE(SPP_TAG, "malloc spp_data failed, fd:%d", fd);
goto done;
}
for (i = 0; i < SPP_DATA_LEN; ++i) {
spp_data[i] = i;
}
do {
/*
* The write function is blocked until all the target length of data has been sent to the lower layer
* successfully an error occurs.
*/
size = write(fd, spp_data, SPP_DATA_LEN);
if (size == -1) {
break;
} else if ( size == 0) {
/*write fail due to ringbuf is full, retry after 1s*/
vTaskDelay(1000 / portTICK_PERIOD_MS);
/*write fail due to ringbuf is full, retry after 500 ms*/
vTaskDelay(500 / portTICK_PERIOD_MS);
} else {
ESP_LOGI(SPP_TAG, "fd = %d data_len = %d", fd, size);
vTaskDelay(10 / portTICK_PERIOD_MS);
}
} while (1);
done:
if (spp_data) {
free(spp_data);
}
spp_wr_task_shut_down();
}
@ -112,37 +142,57 @@ static void esp_spp_cb(uint16_t e, void *p)
{
esp_spp_cb_event_t event = e;
esp_spp_cb_param_t *param = p;
uint8_t i = 0;
char bda_str[18] = {0};
switch (event) {
case ESP_SPP_INIT_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_INIT_EVT status=%d", param->init.status);
if (param->init.status == ESP_SPP_SUCCESS) {
ESP_LOGI(SPP_TAG, "ESP_SPP_INIT_EVT");
/* Enable SPP VFS mode */
esp_spp_vfs_register();
esp_bt_dev_set_device_name(EXAMPLE_DEVICE_NAME);
esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
esp_bt_gap_start_discovery(inq_mode, inq_len, inq_num_rsps);
} else {
ESP_LOGE(SPP_TAG, "ESP_SPP_INIT_EVT status:%d", param->init.status);
}
break;
case ESP_SPP_DISCOVERY_COMP_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_DISCOVERY_COMP_EVT status=%d scn_num=%d",param->disc_comp.status, param->disc_comp.scn_num);
if (param->disc_comp.status == ESP_SPP_SUCCESS) {
ESP_LOGI(SPP_TAG, "ESP_SPP_DISCOVERY_COMP_EVT scn_num:%d", param->disc_comp.scn_num);
for (i = 0; i < param->disc_comp.scn_num; i++) {
ESP_LOGI(SPP_TAG, "-- [%d] scn:%d service_name:%s", i, param->disc_comp.scn[i],
param->disc_comp.service_name[i]);
}
/* We only connect to the first found server on the remote SPP acceptor here */
esp_spp_connect(sec_mask, role_master, param->disc_comp.scn[0], peer_bd_addr);
} else {
ESP_LOGE(SPP_TAG, "ESP_SPP_DISCOVERY_COMP_EVT status=%d", param->disc_comp.status);
}
break;
case ESP_SPP_OPEN_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_OPEN_EVT status=%d", param->open.status);
if (param->open.status == ESP_SPP_SUCCESS) {
ESP_LOGI(SPP_TAG, "ESP_SPP_OPEN_EVT handle:%d fd:%d rem_bda:[%s]", param->open.handle, param->open.fd,
bda2str(param->open.rem_bda, bda_str, sizeof(bda_str)));
spp_wr_task_start_up(spp_write_handle, param->open.fd);
} else {
ESP_LOGE(SPP_TAG, "ESP_SPP_OPEN_EVT status:%d", param->open.status);
}
break;
case ESP_SPP_CLOSE_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_CLOSE_EVT");
ESP_LOGI(SPP_TAG, "ESP_SPP_CLOSE_EVT status:%d handle:%d close_by_remote:%d", param->close.status,
param->close.handle, param->close.async);
break;
case ESP_SPP_START_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_START_EVT");
break;
case ESP_SPP_CL_INIT_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_CL_INIT_EVT");
if (param->cl_init.status == ESP_SPP_SUCCESS) {
ESP_LOGI(SPP_TAG, "ESP_SPP_CL_INIT_EVT handle:%d sec_id:%d", param->cl_init.handle, param->cl_init.sec_id);
} else {
ESP_LOGE(SPP_TAG, "ESP_SPP_CL_INIT_EVT status:%d", param->cl_init.status);
}
break;
case ESP_SPP_SRV_OPEN_EVT:
ESP_LOGI(SPP_TAG, "ESP_SPP_SRV_OPEN_EVT");
@ -158,6 +208,7 @@ static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa
case ESP_BT_GAP_DISC_RES_EVT:
ESP_LOGI(SPP_TAG, "ESP_BT_GAP_DISC_RES_EVT");
esp_log_buffer_hex(SPP_TAG, param->disc_res.bda, ESP_BD_ADDR_LEN);
/* Find the target peer device name in the EIR data */
for (int i = 0; i < param->disc_res.num_prop; i++){
if (param->disc_res.prop[i].type == ESP_BT_GAP_DEV_PROP_EIR
&& get_name_from_eir(param->disc_res.prop[i].val, peer_bdname, &peer_bdname_len)){
@ -165,8 +216,10 @@ static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa
if (strlen(remote_device_name) == peer_bdname_len
&& strncmp(peer_bdname, remote_device_name, peer_bdname_len) == 0) {
memcpy(peer_bd_addr, param->disc_res.bda, ESP_BD_ADDR_LEN);
esp_spp_start_discovery(peer_bd_addr);
/* Have found the target peer device, cancel the previous GAP discover procedure. And go on
* dsicovering the SPP service on the peer device */
esp_bt_gap_cancel_discovery();
esp_spp_start_discovery(peer_bd_addr);
}
}
}
@ -231,16 +284,16 @@ static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa
static void esp_spp_stack_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
{
/* To avoid stucking Bluetooth stack, we dispatch the SPP callback event to the other lower priority task */
spp_task_work_dispatch(esp_spp_cb, event, param, sizeof(esp_spp_cb_param_t), NULL);
}
void app_main(void)
{
for (int i = 0; i < SPP_DATA_LEN; ++i) {
spp_data[i] = i;
}
esp_err_t ret = ESP_OK;
char bda_str[18] = {0};
esp_err_t ret = nvs_flash_init();
ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
@ -300,4 +353,6 @@ void app_main(void)
esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_VARIABLE;
esp_bt_pin_code_t pin_code;
esp_bt_gap_set_pin(pin_type, 0, pin_code);
ESP_LOGI(SPP_TAG, "Own address:[%s]", bda2str((uint8_t *)esp_bt_dev_get_address(), bda_str, sizeof(bda_str)));
}