@@ -53,6 +53,26 @@ static EventGroupHandle_t _spp_event_group = NULL;
53
53
static boolean secondConnectionAttempt;
54
54
static esp_spp_cb_t * custom_spp_callback = NULL ;
55
55
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
+
56
76
#define SPP_RUNNING 0x01
57
77
#define SPP_CONNECTED 0x02
58
78
#define SPP_CONGESTED 0x04
@@ -62,6 +82,47 @@ typedef struct {
62
82
uint8_t data[];
63
83
} spp_packet_t ;
64
84
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
+
65
126
static esp_err_t _spp_queue_packet (uint8_t *data, size_t len){
66
127
if (!data || !len){
67
128
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)
159
220
case ESP_SPP_INIT_EVT:
160
221
log_i (" ESP_SPP_INIT_EVT" );
161
222
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
+ }
163
227
xEventGroupSetBits (_spp_event_group, SPP_RUNNING);
228
+ _isInitialized = true ;
229
+ _isInitializing = false ;
230
+
164
231
break ;
165
232
166
233
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)
219
286
// should maybe delete those.
220
287
case ESP_SPP_DISCOVERY_COMP_EVT:// discovery complete
221
288
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
+ }
222
293
break ;
223
294
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 ;
226
304
case ESP_SPP_START_EVT:// server started
227
305
log_i (" ESP_SPP_START_EVT" );
228
306
break ;
@@ -235,8 +313,93 @@ static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
235
313
if (custom_spp_callback)(*custom_spp_callback)(event, param);
236
314
}
237
315
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
+
238
400
static bool _init_bt (const char *deviceName)
239
401
{
402
+ _isInitializing = false ;
240
403
if (!_spp_event_group){
241
404
_spp_event_group = xEventGroupCreate ();
242
405
if (!_spp_event_group){
@@ -297,6 +460,11 @@ static bool _init_bt(const char *deviceName)
297
460
}
298
461
}
299
462
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
+
300
468
if (esp_spp_register_callback (esp_spp_cb) != ESP_OK){
301
469
log_e (" spp register failed" );
302
470
return false ;
@@ -307,8 +475,20 @@ static bool _init_bt(const char *deviceName)
307
475
return false ;
308
476
}
309
477
478
+ log_i (" device name set" );
310
479
esp_bt_dev_set_device_name (deviceName);
311
480
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
+
312
492
// the default BTA_DM_COD_LOUDSPEAKER does not work with the macOS BT stack
313
493
esp_bt_cod_t cod;
314
494
cod.major = 0b00001 ;
@@ -318,12 +498,14 @@ static bool _init_bt(const char *deviceName)
318
498
log_e (" set cod failed" );
319
499
return false ;
320
500
}
321
-
501
+ _isInitializing = true ;
322
502
return true ;
323
503
}
324
504
325
505
static bool _stop_bt ()
326
506
{
507
+ _isInitialized = false ;
508
+ _isInitializing = false ;
327
509
if (btStarted ()){
328
510
if (_spp_client)
329
511
esp_spp_disconnect (_spp_client);
@@ -376,8 +558,9 @@ BluetoothSerial::~BluetoothSerial(void)
376
558
_stop_bt ();
377
559
}
378
560
379
- bool BluetoothSerial::begin (String localName)
561
+ bool BluetoothSerial::begin (String localName, bool isMaster )
380
562
{
563
+ _isMaster = isMaster;
381
564
if (localName.length ()){
382
565
local_name = localName;
383
566
}
@@ -445,4 +628,110 @@ esp_err_t BluetoothSerial::register_callback(esp_spp_cb_t * callback)
445
628
return ESP_OK;
446
629
}
447
630
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
+ }
448
737
#endif
0 commit comments