Skip to content

Commit bc2cafc

Browse files
author
Victor Tchistiak
committed
20190916 - initial: support for Master mode, Pin and SSP
1 parent 06a399b commit bc2cafc

File tree

2 files changed

+304
-6
lines changed

2 files changed

+304
-6
lines changed

libraries/BluetoothSerial/src/BluetoothSerial.cpp

100644100755
Lines changed: 294 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,26 @@ static EventGroupHandle_t _spp_event_group = NULL;
5353
static boolean secondConnectionAttempt;
5454
static esp_spp_cb_t * custom_spp_callback = NULL;
5555

56+
#define SPP_TAG "BluetoothSerial"
57+
static const esp_spp_sec_t sec_mask = ESP_SPP_SEC_AUTHENTICATE;
58+
static const esp_spp_role_t role_master = ESP_SPP_ROLE_MASTER;
59+
static esp_bd_addr_t _peer_bd_addr;
60+
static uint8_t peer_bdname_len;
61+
static char peer_bdname[ESP_BT_GAP_MAX_BDNAME_LEN + 1];
62+
static const esp_bt_inq_mode_t inq_mode = ESP_BT_INQ_MODE_GENERAL_INQUIRY;
63+
static const uint8_t inq_len = 30;
64+
static const uint8_t inq_num_rsps = 0;
65+
static char _remote_name[ESP_BT_GAP_MAX_BDNAME_LEN + 1];
66+
static bool _isRemoteAddressSet;
67+
static esp_bd_addr_t _remote_address;
68+
static bool _isMaster;
69+
static esp_bt_pin_code_t _pin_code;
70+
static int _pin_len;
71+
static bool _isPinSet;
72+
static bool _enableSSP;
73+
static bool _isInitializing;
74+
static bool _isInitialized;
75+
5676
#define SPP_RUNNING 0x01
5777
#define SPP_CONNECTED 0x02
5878
#define SPP_CONGESTED 0x04
@@ -62,6 +82,47 @@ typedef struct {
6282
uint8_t data[];
6383
} spp_packet_t;
6484

85+
static bool get_name_from_eir(uint8_t *eir, char *bdname, uint8_t *bdname_len)
86+
{
87+
uint8_t *rmt_bdname = NULL;
88+
uint8_t rmt_bdname_len = 0;
89+
90+
if (!eir) {
91+
return false;
92+
}
93+
94+
rmt_bdname = esp_bt_gap_resolve_eir_data(eir, ESP_BT_EIR_TYPE_CMPL_LOCAL_NAME, &rmt_bdname_len);
95+
if (!rmt_bdname) {
96+
rmt_bdname = esp_bt_gap_resolve_eir_data(eir, ESP_BT_EIR_TYPE_SHORT_LOCAL_NAME, &rmt_bdname_len);
97+
}
98+
99+
if (rmt_bdname) {
100+
if (rmt_bdname_len > ESP_BT_GAP_MAX_BDNAME_LEN) {
101+
rmt_bdname_len = ESP_BT_GAP_MAX_BDNAME_LEN;
102+
}
103+
104+
if (bdname) {
105+
memcpy(bdname, rmt_bdname, rmt_bdname_len);
106+
bdname[rmt_bdname_len] = '\0';
107+
}
108+
if (bdname_len) {
109+
*bdname_len = rmt_bdname_len;
110+
}
111+
return true;
112+
}
113+
114+
return false;
115+
}
116+
117+
static bool btSetPin() {
118+
if (_isPinSet) {
119+
log_i("pin set");
120+
esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_FIXED;
121+
return (esp_bt_gap_set_pin(pin_type, _pin_len, _pin_code) == ESP_OK);
122+
}
123+
return false;
124+
}
125+
65126
static esp_err_t _spp_queue_packet(uint8_t *data, size_t len){
66127
if(!data || !len){
67128
log_w("No data provided");
@@ -159,8 +220,14 @@ static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
159220
case ESP_SPP_INIT_EVT:
160221
log_i("ESP_SPP_INIT_EVT");
161222
esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
162-
esp_spp_start_srv(ESP_SPP_SEC_NONE, ESP_SPP_ROLE_SLAVE, 0, _spp_server_name);
223+
if (!_isMaster) {
224+
log_i("ESP_SPP_INIT_EVT: slave: start");
225+
esp_spp_start_srv(ESP_SPP_SEC_NONE, ESP_SPP_ROLE_SLAVE, 0, _spp_server_name);
226+
}
163227
xEventGroupSetBits(_spp_event_group, SPP_RUNNING);
228+
_isInitialized = true;
229+
_isInitializing = false;
230+
164231
break;
165232

166233
case ESP_SPP_SRV_OPEN_EVT://Server connection open
@@ -219,10 +286,21 @@ static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
219286
//should maybe delete those.
220287
case ESP_SPP_DISCOVERY_COMP_EVT://discovery complete
221288
log_i("ESP_SPP_DISCOVERY_COMP_EVT");
289+
if (param->disc_comp.status == ESP_SPP_SUCCESS) {
290+
log_i("ESP_SPP_DISCOVERY_COMP_EVT: spp connect to remote");
291+
esp_spp_connect(sec_mask, role_master, param->disc_comp.scn[0], _peer_bd_addr);
292+
}
222293
break;
223294
case ESP_SPP_OPEN_EVT://Client connection open
224-
log_i("ESP_SPP_OPEN_EVT");
225-
break;
295+
if (!_spp_client){
296+
_spp_client = param->open.handle;
297+
} else {
298+
secondConnectionAttempt = true;
299+
esp_spp_disconnect(param->open.handle);
300+
}
301+
xEventGroupSetBits(_spp_event_group, SPP_CONNECTED);
302+
log_i("ESP_SPP_OPEN_EVT");
303+
break;
226304
case ESP_SPP_START_EVT://server started
227305
log_i("ESP_SPP_START_EVT");
228306
break;
@@ -235,8 +313,93 @@ static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
235313
if(custom_spp_callback)(*custom_spp_callback)(event, param);
236314
}
237315

316+
static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
317+
{
318+
switch(event){
319+
case ESP_BT_GAP_DISC_RES_EVT:
320+
log_i("ESP_BT_GAP_DISC_RES_EVT");
321+
esp_log_buffer_hex(SPP_TAG, param->disc_res.bda, ESP_BD_ADDR_LEN);
322+
for (int i = 0; i < param->disc_res.num_prop; i++){
323+
if (param->disc_res.prop[i].type == ESP_BT_GAP_DEV_PROP_EIR
324+
&& get_name_from_eir((uint8_t*)param->disc_res.prop[i].val, peer_bdname, &peer_bdname_len)){
325+
log_v("ESP_BT_GAP_DISC_RES_EVT : EIR : %s", peer_bdname);
326+
if (strlen(_remote_name) == peer_bdname_len
327+
&& strncmp(peer_bdname, _remote_name, peer_bdname_len) == 0) {
328+
log_v("ESP_BT_GAP_DISC_RES_EVT : SPP_DISCOVERY_EIR : %s", peer_bdname);
329+
_isRemoteAddressSet = true;
330+
memcpy(_peer_bd_addr, param->disc_res.bda, ESP_BD_ADDR_LEN);
331+
esp_spp_start_discovery(_peer_bd_addr);
332+
esp_bt_gap_cancel_discovery();
333+
}
334+
} else if (param->disc_res.prop[i].type == ESP_BT_GAP_DEV_PROP_BDNAME) {
335+
strcpy(peer_bdname, (char *)param->disc_res.prop[i].val);
336+
peer_bdname_len = strlen(peer_bdname);
337+
log_v("ESP_BT_GAP_DISC_RES_EVT : BDNAME : %s", peer_bdname);
338+
if (strlen(_remote_name) == peer_bdname_len
339+
&& strncmp(peer_bdname, _remote_name, peer_bdname_len) == 0) {
340+
log_v("ESP_BT_GAP_DISC_RES_EVT : SPP_DISCOVERY_BDNAME : %s", peer_bdname);
341+
_isRemoteAddressSet = true;
342+
memcpy(_peer_bd_addr, param->disc_res.bda, ESP_BD_ADDR_LEN);
343+
esp_spp_start_discovery(_peer_bd_addr);
344+
esp_bt_gap_cancel_discovery();
345+
}
346+
}
347+
}
348+
break;
349+
case ESP_BT_GAP_DISC_STATE_CHANGED_EVT:
350+
log_i("ESP_BT_GAP_DISC_STATE_CHANGED_EVT");
351+
break;
352+
case ESP_BT_GAP_RMT_SRVCS_EVT:
353+
log_i( "ESP_BT_GAP_RMT_SRVCS_EVT");
354+
break;
355+
case ESP_BT_GAP_RMT_SRVC_REC_EVT:
356+
log_i("ESP_BT_GAP_RMT_SRVC_REC_EVT");
357+
break;
358+
case ESP_BT_GAP_AUTH_CMPL_EVT:{
359+
if (param->auth_cmpl.stat == ESP_BT_STATUS_SUCCESS) {
360+
log_v("authentication success: %s", param->auth_cmpl.device_name);
361+
esp_log_buffer_hex(SPP_TAG, param->auth_cmpl.bda, ESP_BD_ADDR_LEN);
362+
} else {
363+
log_e("authentication failed, status:%d", param->auth_cmpl.stat);
364+
}
365+
break;
366+
}
367+
case ESP_BT_GAP_PIN_REQ_EVT:{
368+
// default pairing pins
369+
log_i("ESP_BT_GAP_PIN_REQ_EVT min_16_digit:%d", param->pin_req.min_16_digit);
370+
if (param->pin_req.min_16_digit) {
371+
log_i("Input pin code: 0000 0000 0000 0000");
372+
esp_bt_pin_code_t pin_code = {0};
373+
esp_bt_gap_pin_reply(param->pin_req.bda, true, 16, pin_code);
374+
} else {
375+
log_i("Input pin code: 1234");
376+
esp_bt_pin_code_t pin_code;
377+
pin_code[0] = '1';
378+
pin_code[1] = '2';
379+
pin_code[2] = '3';
380+
pin_code[3] = '4';
381+
esp_bt_gap_pin_reply(param->pin_req.bda, true, 4, pin_code);
382+
}
383+
break;
384+
}
385+
case ESP_BT_GAP_CFM_REQ_EVT:
386+
log_i("ESP_BT_GAP_CFM_REQ_EVT Please compare the numeric value: %d", param->cfm_req.num_val);
387+
esp_bt_gap_ssp_confirm_reply(param->cfm_req.bda, true);
388+
break;
389+
case ESP_BT_GAP_KEY_NOTIF_EVT:
390+
log_i("ESP_BT_GAP_KEY_NOTIF_EVT passkey:%d", param->key_notif.passkey);
391+
break;
392+
case ESP_BT_GAP_KEY_REQ_EVT:
393+
log_i("ESP_BT_GAP_KEY_REQ_EVT Please enter passkey!");
394+
break;
395+
default:
396+
break;
397+
}
398+
}
399+
238400
static bool _init_bt(const char *deviceName)
239401
{
402+
_isInitializing = false;
240403
if(!_spp_event_group){
241404
_spp_event_group = xEventGroupCreate();
242405
if(!_spp_event_group){
@@ -297,6 +460,11 @@ static bool _init_bt(const char *deviceName)
297460
}
298461
}
299462

463+
if (_isMaster && esp_bt_gap_register_callback(esp_bt_gap_cb) != ESP_OK) {
464+
log_e("gap register failed");
465+
return false;
466+
}
467+
300468
if (esp_spp_register_callback(esp_spp_cb) != ESP_OK){
301469
log_e("spp register failed");
302470
return false;
@@ -307,8 +475,20 @@ static bool _init_bt(const char *deviceName)
307475
return false;
308476
}
309477

478+
log_i("device name set");
310479
esp_bt_dev_set_device_name(deviceName);
311480

481+
if (_isPinSet) {
482+
btSetPin();
483+
}
484+
485+
if (_enableSSP) {
486+
log_i("Simple Secure Pairing");
487+
esp_bt_sp_param_t param_type = ESP_BT_SP_IOCAP_MODE;
488+
esp_bt_io_cap_t iocap = ESP_BT_IO_CAP_IO;
489+
esp_bt_gap_set_security_param(param_type, &iocap, sizeof(uint8_t));
490+
}
491+
312492
// the default BTA_DM_COD_LOUDSPEAKER does not work with the macOS BT stack
313493
esp_bt_cod_t cod;
314494
cod.major = 0b00001;
@@ -318,12 +498,14 @@ static bool _init_bt(const char *deviceName)
318498
log_e("set cod failed");
319499
return false;
320500
}
321-
501+
_isInitializing = true;
322502
return true;
323503
}
324504

325505
static bool _stop_bt()
326506
{
507+
_isInitialized = false;
508+
_isInitializing = false;
327509
if (btStarted()){
328510
if(_spp_client)
329511
esp_spp_disconnect(_spp_client);
@@ -376,8 +558,9 @@ BluetoothSerial::~BluetoothSerial(void)
376558
_stop_bt();
377559
}
378560

379-
bool BluetoothSerial::begin(String localName)
561+
bool BluetoothSerial::begin(String localName, bool isMaster)
380562
{
563+
_isMaster = isMaster;
381564
if (localName.length()){
382565
local_name = localName;
383566
}
@@ -445,4 +628,110 @@ esp_err_t BluetoothSerial::register_callback(esp_spp_cb_t * callback)
445628
return ESP_OK;
446629
}
447630

631+
632+
//Simple Secure Pairing
633+
void BluetoothSerial::enableSSP() {
634+
_enableSSP = true;
635+
}
636+
/*
637+
* Set default parameters for Legacy Pairing
638+
* Use fixed pin code
639+
*/
640+
bool BluetoothSerial::setPin(const char * pin) {
641+
if (pin && *pin) {
642+
int i = 0;
643+
while(*(pin + i) && i < ESP_BT_PIN_CODE_LEN) {
644+
_pin_code[i] = *(pin+i);
645+
i++;
646+
}
647+
_pin_len = i;
648+
} else if (pin){
649+
_pin_len = 0; // resetting pin to none
650+
} else {
651+
log_e("No pin is provided");
652+
return false;
653+
}
654+
_isPinSet = true;
655+
if (isReady(false)) {
656+
btSetPin();
657+
}
658+
return true;
659+
}
660+
661+
bool BluetoothSerial::connect(String remoteName)
662+
{
663+
if (!isReady(true)) return false;
664+
if (remoteName && remoteName.length() < 1) {
665+
log_e("No remote name is provided");
666+
return false;
667+
}
668+
_isRemoteAddressSet = false;
669+
strncpy(_remote_name, remoteName.c_str(), ESP_BT_GAP_MAX_BDNAME_LEN);
670+
_remote_name[ESP_BT_GAP_MAX_BDNAME_LEN] = 0;
671+
log_i("master : remoteName");
672+
return (esp_bt_gap_start_discovery(inq_mode, inq_len, inq_num_rsps) == ESP_OK);
673+
}
674+
675+
bool BluetoothSerial::connect(uint8_t remoteAddress[])
676+
{
677+
if (!isReady(true)) return false;
678+
if (!remoteAddress) {
679+
log_e("No remote address is provided");
680+
return false;
681+
}
682+
_remote_name[0] = 0;
683+
_isRemoteAddressSet = true;
684+
memcpy(_remote_address, remoteAddress, ESP_BD_ADDR_LEN);
685+
memcpy(_peer_bd_addr, _remote_address, ESP_BD_ADDR_LEN);
686+
log_i("master : remoteAddress");
687+
return ( esp_spp_start_discovery(_peer_bd_addr) == ESP_OK);
688+
}
689+
690+
bool BluetoothSerial::connect()
691+
{
692+
if (!isReady(true)) return false;
693+
if (_remote_name[0]) {
694+
log_i("master : remoteName");
695+
return (esp_bt_gap_start_discovery(inq_mode, inq_len, inq_num_rsps) == ESP_OK);
696+
} else if (_isRemoteAddressSet){
697+
log_i("master : remoteAddress");
698+
memcpy(_peer_bd_addr, _remote_address, ESP_BD_ADDR_LEN);
699+
return (esp_spp_start_discovery(_peer_bd_addr) == ESP_OK);
700+
} else {
701+
log_e("Neither Remote name nor address was provided");
702+
}
703+
return false;
704+
}
705+
706+
bool BluetoothSerial::disconnect() {
707+
if (_spp_client) {
708+
return (esp_spp_disconnect(_spp_client) == ESP_OK);
709+
}
710+
return false;
711+
}
712+
713+
bool BluetoothSerial::connected() {
714+
return _spp_client != 0;
715+
}
716+
717+
bool BluetoothSerial::isReady(bool checkMaster)
718+
{
719+
if (checkMaster && !_isMaster) {
720+
log_e("Master mode is not active. Call begin(localName, true) to enanbe Master mode");
721+
return false;
722+
}
723+
// btStarted() is not sufficient to indicate ESP_SPP_INIT_EVT is complete
724+
if (_isInitializing) {
725+
int retry = 10;
726+
do {
727+
delay(500);
728+
log_i("waiting for intialization to complete...");
729+
} while(!_isInitialized && retry-- > 0);
730+
}
731+
if (!_isInitialized) {
732+
log_e("Timeout waiting for bt initialization to complete");
733+
return false;
734+
}
735+
return true;
736+
}
448737
#endif

0 commit comments

Comments
 (0)