Nei precedenti articoli abbiamo visto come utilizzare il chip esp32 per ricevere ed interpretare i pacchetti di advertising trasmessi da periferiche Bluetooth Low Energy. Come esempio pratico, abbiamo sviluppato un programma per rilevare la presenza di un particolare iBeacon e attivare di conseguenza una uscita.
Nel tutorial di oggi vedremo invece come trasmettere pacchetti di advertising.
Processo di advertising
Abbiamo già scoperto che il driver Bluetooth dello stack esp-idf viene eseguito in un thread separato. Ogni volta che il driver deve inviare una notifica al nostro programma, chiama una funzione di callback indicando quale evento si è scatenato.
Il processo di advertising è molto semplice:
- il programma configura i dati da trasmettere con il comando esp_ble_gap_config_adv_data()
- il driver segnala di aver terminato la configurazione con l’evento ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT
- il programma può ora avviare il processo di advertising con il comando esp_ble_gap_start_advertising()
- il driver segnala di aver avviato il processo con l’evento ESP_GAP_BLE_ADV_START_COMPLETE_EVT
Dati di advertising
E’ possibile indicare al driver quali dati includere nel pacchetto di advertising con il comando:
esp_err_t esp_ble_gap_config_adv_data(esp_ble_adv_data_t *adv_data); |
Il comando accetta come parametro un puntatore ad una struct esp_ble_adv_data_t:
Il significato dei vari parametri è dettagliato nel documento Supplement to the Bluetooth Core Specification.
Per prima cosa vediamo come trasmettere il nome del dispositivo. Dobbiamo utilizzare il metodo esp_ble_gap_set_device_name() per indicare al driver quale nome utilizzare e settare a true il campo include_name nella struct:
static esp_ble_adv_data_t adv_data = { .include_name = true, }; [...] ESP_ERROR_CHECK(esp_ble_gap_set_device_name("ESP32_BLE")); ESP_ERROR_CHECK(esp_ble_gap_config_adv_data(&adv_data)); |
Tramite i flags possiamo indicare alcune caratteristiche del nostro dispositivo. Le costanti a disposizione sono:
possiamo utilizzarle con l’operatore OR. Se ad esempio vogliamo indicare che il nostro dispositivo è limited discoverable (ovvero effettua la trasmissione dei pacchetti di advertising per un tempo limitato, solitamente 30 secondi) e che non supporta il Bluetooth classico (BR/EDR, Basic Rate/Enhanced Data Rate) scriveremo:
static esp_ble_adv_data_t adv_data = { .flag = ESP_BLE_ADV_FLAG_LIMIT_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT, }; |
Parametri di advertising
Dopo aver configurato il contenuto del pacchetto di advertising, dobbiamo indicare al driver anche la modalità con cui inviare tale pacchetto.
Il comando:
esp_err_t esp_ble_gap_start_advertising(esp_ble_adv_params_t *adv_params); |
accetta come parametro una struct esp_ble_adv_params_t:
Possiamo configurare l’intervallo minimo e massimo di trasmissione del pacchetto. I due parametri possono assumere un valore da 0x20 a 0x4000. Per conoscere l’intervallo in millisecondi, va moltiplicato il valore indicato per 0,625. Questo significa che il valore minimo (0x20) corrisponde ad un intervallo di 12,5ms.
Nel file esp_gap_ble_api.h sono elencate le costanti utilizzabili per gli altri parametri (esp_ble_adv_type_t, esp_ble_addr_type_t…).
Come esempio configuriamo il processo di advertising come segue:
[checklist]
- intervallo minimo di trasmissione 0x20 e massimo 0x40
- tipo di dispositivo non connectable (non accetta connessioni ma effettua solo invio dati in broadcast)
- indirizzo MAC pubblico
- trasmissione su tutti e 3 i canali dedicati ai pacchetti di advertising
- nessun filtro sui dispositivi che possono effettuare scan o collegarsi
[/checklist]
static esp_ble_adv_params_t ble_adv_params = { .adv_int_min = 0x20, .adv_int_max = 0x40, .adv_type = ADV_TYPE_NONCONN_IND, .own_addr_type = BLE_ADDR_TYPE_PUBLIC, .channel_map = ADV_CHNL_ALL, .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, }; [...] esp_ble_gap_start_advertising(&ble_adv_params); |
Demo
Ho preparato un programma che raccoglie quanto spiegato sopra, il codice sorgente è disponibile nel mio repository Github.
Ecco una demo del suo funzionamento (sottotitoli in italiano disponibili):
Hey there, Luca
thanks for all of these tutorials
they are quite useful!
I just noticed that minimum advertising interval you calculated is actually wrong.
0x20*0.625 = 32*0.625 = 20ms
Not a big deal but may lead to errors.
Thanks again!
Karlo, thanks for your comment!
Hello Luca,
First of all thanks to you for your great effort. Very nice and useful tutorial. I am eagerly waiting for more tutorial from you.
My best regards.
Asish