Nei precedenti articoli vi ho mostrato come ricevere e inviare pacchetti di advertising secondo lo standard Bluetooth LE.
Il payload (ovvero la porzione di dati “utili”) di tali pacchetti è al massimo 31 bytes. Si tratta di una quantità di dati piuttosto limitata: se ad esempio vogliamo includere il nome del nostro dispositivo, rimane poco spazio per altri dati.
Lo standard BLE consente alle periferiche di inviare dati aggiuntivi utilizzando il processo di scan request – scan response.
Quando un dispositivo riceve un pacchetto di advertising, può contattare chi ha effettuato la trasmissione inviando un pacchetto di scan request, ovvero richiedendo ulteriori informazioni. Ad un pacchetto di scan request, la periferica può rispondere con un pacchetto di scan response:
I pacchetti di advertising e di scan response hanno il medesimo formato; è quindi possibile trasferire, tramite scan response, ulteriori 31 bytes di dati.
esp32
Il framework esp-idf mette a disposizione due modalità per configurare il contenuto del pacchetto di scan response: tramite la struct esp_ble_adv_data_t o tramite un array di byte (raw mode). Si tratta delle medesime modalità già viste nei due articoli precedenti (struct e raw mode), relativi alla trasmissione di pacchetti di advertising.
Nel primo caso, dobbiamo definire una seconda struct, in aggiunta a quella relativa al pacchetto di advertising, per definire il contenuto del pacchetto di scan response:
static uint8_t manufacturer_data[6] = {0xE5,0x02,0x01,0x01,0x01,0x01}; static esp_ble_adv_data_t scan_rsp_data = { .set_scan_rsp = true, .manufacturer_len = 6, .p_manufacturer_data = manufacturer_data, }; |
Molto importante è configurare a true il parametro set_scan_rsp. E’ infatti questo parametro che indica al driver che questa struct è relativa al pacchetto di scan response.
Possiamo quindi passare la nuova struct al driver con lo stesso metodo usato in precedenza:
esp_ble_gap_config_adv_data(&scan_rsp_data); |
Il driver chiamerà la funzione di callback due volte: una per indicare l’avvenuta configurazione del pacchetto di advertising e una per la configurazione del pacchetto di scan response. I due eventi sono differenti:
case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: [...] case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT: [...] |
Dobbiamo attendere che entrambi gli eventi si siano verificati prima di lanciare il processo di advertising. Nel programma di esempio, che trovate nel mio repository Github, utilizzo due variabili boolean:
bool adv_data_set = false; bool scan_rsp_data_set = false; [...] case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: adv_data_set = true; if(scan_rsp_data_set) esp_ble_gap_start_advertising(&ble_adv_params); break; case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT: scan_rsp_data_set = true; if(adv_data_set) esp_ble_gap_start_advertising(&ble_adv_params); break; |
Se invece vogliamo configurare il pacchetto di scan response in modalità raw, dobbiamo definire un array di byte e memorizzarvi il contenuto del payload del pacchetto. Quindi utilizziamo una apposita funzione del framework per passare tale array al driver:
static uint8_t scan_rsp_raw_data[8] = {0x07,0xFF,0xE5,0x02,0x01,0x01,0x01,0x01}; [...] esp_ble_gap_config_scan_rsp_data_raw(scan_rsp_raw_data, 8); |
avete notato che il contenuto del pachetto di scan response è il medesimo nei due esempi?
Il driver segnalerà l’avvenuta configurazione con un apposito evento. Anche in questo caso dobbiamo attendere il termine di entrambe le configurazioni (advertising e scan response):
case ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT: scan_rsp_data_set = true; if(adv_data_set) esp_ble_gap_start_advertising(&ble_adv_params); break; |
Utilizzando l’app nRF Connect è possibile verificare che il pacchetto di scan response è correttamente ricevuto dallo smartphone:
Nel video seguente vi mostro come ho costruito il payload del pacchetto e il funzionamento del programma:
Ciao Luca, complimenti per gli articoli, li apprezzo molto, sono molto chiari. Continua così!
Sto indagando sulla possibilità di usare l’ESP32 per far comunicare via BLE (4.2) due dispositivi, un ESP32 e uno smartphone, SENZA INTERVENTO DELL’UTENTE.
Speravo si potesse fare senza connessione (pairing) ma da quanto ho capito in quel caso gli unici payload sono quelli dei pacchetti di advertisement e di scan response, quindi poche decine di byte.
C’è un modo per ovviare al problema o, eventualmente, per fare un pairing automatico per poi scambiare dati via GATT?
ciao Federico! Se sviluppi una app sullo smartphone, questa può tranquillamente effettuare lo scan, collegarsi alla periferica BLE e scambiare dati via GATT senza alcun altro intervento… funziona così ad esempio l’app di Fitbit…
You are one of the only people out there explaining the native BLE api for the esp32. Thank you! I really appreciate it.
But i have a question or rather a comment regarding this example. You’ve set the adv_type to ADV_TYPE_NONCONN_IND but the bluetooth specs say that you need ADV_SCAN_IND to enable scan responses. After changing that attribute of my ble_adv_params I finally got the scan response to work.
Maybe you should edit your tutorial for future visitors.
here are the 4 PDU Types explained:
http://blog.bluetooth.com/bluetooth-low-energy-it-starts-with-advertising
Cheers
Thanks Yannik! I’ll update my tutorial following your suggestion!
Complimenti per la guida: una domanda è per caso riuscito a misurare i consumi in modalità BLE dell’ESP32. Se si a quanto ammontano?
non con precisione ma la maggiore lamentela è che il chip non è in grado di supportare applicazioni BLE che richiedano bassissimi consumi