Skip to content

Commit bef9c84

Browse files
committed
user: add OTA over SPP feature (WIP)
1 parent f5b6bbb commit bef9c84

File tree

5 files changed

+213
-13
lines changed

5 files changed

+213
-13
lines changed

main/Kconfig.projbuild

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,15 @@ menu "Bluetooth Speaker"
22

33
config BT_NAME
44
string "Bluetooth Name"
5-
default "Bluetooth Speaker"
6-
help
7-
Bluetooth name exposed by the device.
5+
default "Bluetooth Speaker"
6+
help
7+
Bluetooth name exposed by the device.
8+
9+
config ENABLE_OTA_OVER_SPP
10+
bool "Enable OTA over SPP"
11+
default y
12+
help
13+
Enable OTA feature, you can use the SPP profile to upload the new firmware.
814

915
menu "VFX Configuration"
1016
config ENABLE_VFX
@@ -22,10 +28,10 @@ config ENABLE_BLE_CONTROL_IF
2228

2329
config BLE_ADV_NAME
2430
string "BLE Advertising Name"
25-
default "Bluetooth Speaker Control"
31+
default "Bluetooth Speaker Control"
2632
depends on ENABLE_BLE_CONTROL_IF
27-
help
28-
Advertising name for BLE Control Interface.
33+
help
34+
Advertising name for BLE Control Interface.
2935

3036
choice VFX_OUTPUT
3137
prompt "VFX Output Device"

main/inc/user/bt_app_spp.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/*
2+
* bt_app_spp.h
3+
*
4+
* Created on: 2019-07-03 15:48
5+
* Author: Jack Chen <redchenjs@live.com>
6+
*/
7+
8+
#ifndef INC_USER_BT_APP_SPP_H_
9+
#define INC_USER_BT_APP_SPP_H_
10+
11+
#include "esp_spp_api.h"
12+
13+
extern void bt_app_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param);
14+
15+
#endif /* INC_USER_BT_APP_SPP_H_ */

main/src/user/bt_app.c

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#include "user/bt_app.h"
1919
#include "user/bt_app_av.h"
20+
#include "user/bt_app_spp.h"
2021
#include "user/bt_app_core.h"
2122

2223
#define BT_APP_TAG "bt_app"
@@ -38,6 +39,22 @@ static void bt_app_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa
3839
}
3940
break;
4041
}
42+
case ESP_BT_GAP_PIN_REQ_EVT:{
43+
if (param->pin_req.min_16_digit) {
44+
ESP_LOGI(BT_GAP_TAG, "pin code: 0000 0000 0000 0000");
45+
esp_bt_pin_code_t pin_code = {0};
46+
esp_bt_gap_pin_reply(param->pin_req.bda, true, 16, pin_code);
47+
} else {
48+
ESP_LOGI(BT_GAP_TAG, "pin code: 1234");
49+
esp_bt_pin_code_t pin_code;
50+
pin_code[0] = '1';
51+
pin_code[1] = '2';
52+
pin_code[2] = '3';
53+
pin_code[3] = '4';
54+
esp_bt_gap_pin_reply(param->pin_req.bda, true, 4, pin_code);
55+
}
56+
break;
57+
}
4158
case ESP_BT_GAP_CFM_REQ_EVT:
4259
ESP_LOGI(BT_GAP_TAG, "please compare the numeric value: %d", param->cfm_req.num_val);
4360
esp_bt_gap_ssp_confirm_reply(param->cfm_req.bda, true);
@@ -65,6 +82,11 @@ static void bt_app_hdl_stack_evt(uint16_t event, void *p_param)
6582
/* register GAP callback */
6683
esp_bt_gap_register_callback(bt_app_gap_cb);
6784

85+
#ifdef CONFIG_ENABLE_OTA_OVER_SPP
86+
esp_spp_register_callback(bt_app_spp_cb);
87+
esp_spp_init(ESP_SPP_MODE_CB);
88+
#endif
89+
6890
/* initialize AVRCP controller */
6991
esp_avrc_ct_init();
7092
esp_avrc_ct_register_callback(bt_app_avrc_ct_cb);
@@ -106,13 +128,9 @@ void bt_app_init(void)
106128

107129
/*
108130
* Set default parameters for Legacy Pairing
109-
* Use fixed pin code
131+
* Use variable pin, input pin code when pairing
110132
*/
111-
esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_FIXED;
133+
esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_VARIABLE;
112134
esp_bt_pin_code_t pin_code;
113-
pin_code[0] = '1';
114-
pin_code[1] = '2';
115-
pin_code[2] = '3';
116-
pin_code[3] = '4';
117-
esp_bt_gap_set_pin(pin_type, 4, pin_code);
135+
esp_bt_gap_set_pin(pin_type, 0, pin_code);
118136
}

main/src/user/bt_app_spp.c

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
/*
2+
* bt_app_spp.c
3+
*
4+
* Created on: 2019-07-03 15:48
5+
* Author: Jack Chen <redchenjs@live.com>
6+
*/
7+
8+
#include <time.h>
9+
#include <string.h>
10+
#include <sys/time.h>
11+
12+
#include "esp_log.h"
13+
#include "esp_system.h"
14+
#include "esp_ota_ops.h"
15+
#include "esp_bt_main.h"
16+
#include "esp_bt_device.h"
17+
#include "esp_spp_api.h"
18+
19+
#include "freertos/FreeRTOS.h"
20+
#include "freertos/task.h"
21+
22+
#include "os/firmware.h"
23+
24+
#define BT_SPP_TAG "bt_spp"
25+
#define BT_OTA_TAG "bt_ota"
26+
27+
#define SPP_SERVER_NAME "OTA"
28+
29+
static struct timeval time_new, time_old;
30+
static long data_num = 0;
31+
32+
static const esp_spp_sec_t sec_mask = ESP_SPP_SEC_AUTHENTICATE;
33+
static const esp_spp_role_t role_slave = ESP_SPP_ROLE_SLAVE;
34+
35+
static uint8_t first_time = 1;
36+
static uint8_t ota_running = 0;
37+
static long image_length = 0;
38+
39+
static const esp_partition_t *update_partition = NULL;
40+
static esp_ota_handle_t update_handle = 0;
41+
static long binary_file_length = 0;
42+
43+
static void bt_spp_print_speed(void)
44+
{
45+
float time_old_s = time_old.tv_sec + time_old.tv_usec / 1000000.0;
46+
float time_new_s = time_new.tv_sec + time_new.tv_usec / 1000000.0;
47+
float time_interval = time_new_s - time_old_s;
48+
float speed = data_num * 8 / time_interval / 1000.0;
49+
ESP_LOGI(BT_SPP_TAG, "speed(%fs ~ %fs): %f kbit/s" , time_old_s, time_new_s, speed);
50+
data_num = 0;
51+
time_old.tv_sec = time_new.tv_sec;
52+
time_old.tv_usec = time_new.tv_usec;
53+
}
54+
55+
void bt_app_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
56+
{
57+
switch (event) {
58+
case ESP_SPP_INIT_EVT:
59+
esp_spp_start_srv(sec_mask, role_slave, 0, SPP_SERVER_NAME);
60+
break;
61+
case ESP_SPP_DISCOVERY_COMP_EVT:
62+
break;
63+
case ESP_SPP_OPEN_EVT:
64+
break;
65+
case ESP_SPP_CLOSE_EVT:
66+
ESP_LOGI(BT_SPP_TAG, "SPP connection state: disconnected");
67+
break;
68+
case ESP_SPP_START_EVT:
69+
break;
70+
case ESP_SPP_CL_INIT_EVT:
71+
break;
72+
case ESP_SPP_DATA_IND_EVT:
73+
if (ota_running == 0) {
74+
if (strncmp("FW+RST\r\n", (const char *)param->data_ind.data, param->data_ind.len) == 0) {
75+
ESP_LOGI(BT_SPP_TAG, "GET command: FW+RST");
76+
77+
esp_restart();
78+
} else if (strncmp("FW+VER?\r\n", (const char *)param->data_ind.data, param->data_ind.len) == 0) {
79+
ESP_LOGI(BT_SPP_TAG, "GET command: FW+VER?");
80+
81+
uint8_t rsp_len = strlen(firmware_get_version()) + 2;
82+
uint8_t *rsp_str = malloc(rsp_len * sizeof(uint8_t));
83+
strncpy((char *)rsp_str, firmware_get_version(), rsp_len - 2);
84+
rsp_str[rsp_len - 2] = '\r';
85+
rsp_str[rsp_len - 1] = '\n';
86+
87+
esp_spp_write(param->write.handle, rsp_len, rsp_str);
88+
} else if (strncmp("FW+UPD:", (const char *)param->data_ind.data, 7) == 0) {
89+
sscanf((const char *)param->data_ind.data, "FW+UPD:%ld\r\n", &image_length);
90+
ESP_LOGI(BT_SPP_TAG, "GET command: FW+UPD:%ld", image_length);
91+
92+
if (image_length != 0) {
93+
ota_running = 1;
94+
gettimeofday(&time_old, NULL);
95+
96+
uint8_t rsp_str[] = "OK\r\n";
97+
esp_spp_write(param->write.handle, sizeof(rsp_str), rsp_str);
98+
} else {
99+
uint8_t rsp_str[] = "ERROR\r\n";
100+
esp_spp_write(param->write.handle, sizeof(rsp_str), rsp_str);
101+
}
102+
}
103+
} else {
104+
if (binary_file_length != image_length) {
105+
if (first_time) {
106+
first_time = 0;
107+
108+
update_partition = esp_ota_get_next_update_partition(NULL);
109+
ESP_LOGI(BT_OTA_TAG, "writing to partition subtype %d at offset 0x%x",
110+
update_partition->subtype, update_partition->address);
111+
assert(update_partition != NULL);
112+
113+
esp_err_t err = esp_ota_begin(update_partition, OTA_SIZE_UNKNOWN, &update_handle);
114+
if (err != ESP_OK) {
115+
ESP_LOGE(BT_OTA_TAG, "esp_ota_begin failed (%s)", esp_err_to_name(err));
116+
goto exit;
117+
}
118+
119+
binary_file_length = 0;
120+
}
121+
esp_err_t err = esp_ota_write(update_handle, (const void *)param->data_ind.data, param->data_ind.len);
122+
if (err != ESP_OK) {
123+
ESP_LOGE(BT_OTA_TAG, "esp_ota_write failed (%s)", esp_err_to_name(err));
124+
goto exit;
125+
}
126+
binary_file_length += param->data_ind.len;
127+
ESP_LOGI(BT_OTA_TAG, "have written image length %ld", binary_file_length);
128+
} else {
129+
data_num = binary_file_length;
130+
131+
if (esp_ota_end(update_handle) != ESP_OK) {
132+
ESP_LOGE(BT_OTA_TAG, "esp_ota_end failed");
133+
goto exit;
134+
}
135+
esp_err_t err = esp_ota_set_boot_partition(update_partition);
136+
if (err != ESP_OK) {
137+
ESP_LOGE(BT_OTA_TAG, "esp_ota_set_boot_partition failed (%s)", esp_err_to_name(err));
138+
goto exit;
139+
}
140+
gettimeofday(&time_new, NULL);
141+
bt_spp_print_speed();
142+
exit:
143+
first_time = 1;
144+
ota_running = 0;
145+
image_length = 0;
146+
}
147+
}
148+
break;
149+
case ESP_SPP_CONG_EVT:
150+
break;
151+
case ESP_SPP_WRITE_EVT:
152+
break;
153+
case ESP_SPP_SRV_OPEN_EVT:
154+
ESP_LOGI(BT_SPP_TAG, "SPP connection state: connected");
155+
break;
156+
default:
157+
break;
158+
}
159+
}

sdkconfig.defaults

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ CONFIG_BLUEDROID_ENABLED=y
2525
CONFIG_CLASSIC_BT_ENABLED=y
2626
CONFIG_A2DP_ENABLE=y
2727
CONFIG_GATTS_ENABLE=y
28+
CONFIG_BT_SPP_ENABLED=y
29+
CONFIG_BT_STACK_NO_LOG=y
2830
CONFIG_BTDM_CONTROLLER_MODE_BTDM=y
2931

3032
#

0 commit comments

Comments
 (0)