ESP32 (31) – BLE, GAP

luca 09/02/2018 4

Nei precedenti tutorial avete imparato come utilizzare le funzionalità wifi del chip esp32. A partire da questo tutorial vi illustrerò invece la seconda tecnologia di comunicazione wireless che il chip supporta: il bluetooth.

In particolare tratteremo lo standard Bluetooth Low Energy (BLE), chiamato anche Bluetooth 4.0 o Bluetooth Smart:

ble-001

Bluetooth Low Energy

BLE è una tecnologia per la realizzazione di reti personali wireless (WPAN); ovvero consente di mettere in comunicazione diversi dispositivi (computer, smartphones, smartwatches…) “vicini” tra loro (distanza massima teorica 100m). Come indica anche il nome, la versione 4.0 dello standard Bluetooth è stata disegnata per ridurre il consumo di energia dei dispositivi collegati.

I dispositivi sono suddivisi in due tipologie:

  • central
  • peripheral

I primi (central) sono dispositivi quali PC, tablet o smartphones con elevata quantità di memoria ed elevata capacità di calcolo. I secondi (peripheral) sono invece sensori, tag… con ridotte risorse hardware e bassi consumi. Un central device può essere connesso contemporaneamente a più peripheral devices, mentre non è vero il contrario:

ble-002

I dispositivi BLE segnalano periodicamente la loro presenza trasmettendo pacchetti di advertising. Il pacchetto di advertising può contenere fino a 31 bytes di dati e la frequenza di trasmissione può essere scelta dal singolo dispositivo: diminuendo tale frequenza è infatti possibile ridurre il consumo energetico.

Se un dispositivo BLE, alla ricezione di un pacchetto di avertising, vuole ottenere maggiori informazioni dal dispositivo che lo ha trasmesso, può richiedere a questo un secondo pacchetto di informazioni (sempre per un massimo di 31 bytes), il pacchetto di scan response. La trasmissione di questo secondo pacchetto di dati è facoltativo:

ble-003

Un dispositivo BLE può sfruttare i pacchetti di advertising per inviare dati in modalità broadcast. In questo caso tale dispositivo viene chiamato broadcaster, mentre i dispositivi che ricevono i dati sono chiamati observers.

Quanto spiegato sopra è definito all’interno di una specifica BLE chiamata Generic Access Profile (GAP).

esp32

In questo primo tutorial dedicato a BLE vediamo come sviluppare un programma che effettua periodicamente lo scan alla ricerca di periferiche BLE, ovvero riceve i pacchetti di advertising e visualizza in console i dati ricevuti.

Prima di poter eseguire un programma che utilizza il controller Bluetooth del chip, verifichiamo sempre (tramite menuconfig) che tale controller sia abilitato (Component config -> Bluetooth):

ble-004

Iniziamo il nostro programma includendo gli headers necessari:

#include "esp_bt.h"
#include "esp_bt_main.h"
#include "esp_gap_ble_api.h"

Per poter utilizzare il controller Bluetooth, abbiamo bisogno della partizione NVS:

ESP_ERROR_CHECK(nvs_flash_init());

Il controller Bluetooth del chip esp32 supporta sia la modalità classic che low energy. Se non è necessaria una delle due modalità, è possibile liberare la memoria normalmente allocata dal framework per gestirla con il comando esp_bt_controller_mem_release(). Nel nostro caso non utilizzeremo la modalità classic, quindi:

ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));

Possiamo ora configurare il controller (utilizzeremo la configurazione di default) e abilitarlo in modalità BLE:

esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
esp_bt_controller_init(&bt_cfg);
esp_bt_controller_enable(ESP_BT_MODE_BLE);

Il framework esp-idf utilizza lo stack Bluetooth Bluedroid. Questa libreria è stata sviluppata da Broadcom e utilizzata da Android dalla versione 4.2. Bluedroid viene inizializzato e abilitato con i seguenti comandi:

esp_bluedroid_init();
esp_bluedroid_enable();

Siamo ora pronti ad eseguire lo scan…

GAP, eventi

In maniera simile a quanto visto con il driver wifi, anche il driver bluetooth viene eseguito in un thread separato rispetto al nostro programma e comunica con esso tramite eventi. Per poter ricevere tali eventi, dobbiamo implementare una funzione di callback. Ogni volta che il driver bluetooth dovrà notificare un evento, chiamerà tale funzione.

Il prototipo della funzione di callback è:

static void esp_gap_cb(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param);

Si indica al driver quale funzione di callback utilizzare con il metodo esp_ble_gap_register_callback():

ESP_ERROR_CHECK(esp_ble_gap_register_callback(esp_gap_cb));

Gli eventi possibili sono tantissimi, vediamo quelli relativi al processo di scan:

ble-005

Prima di poter eseguire il processo di scan, è necessario configurare i relativi parametri. La configurazione avviene tramite la struct esp_ble_scan_params_t. Importante è che la variable che contiene i parametri sia disponibile durante tutto lo scan; conviene quindi definirla globale:

static esp_ble_scan_params_t ble_scan_params = {
  .scan_type              = BLE_SCAN_TYPE_ACTIVE,
  .own_addr_type          = BLE_ADDR_TYPE_PUBLIC,
  .scan_filter_policy     = BLE_SCAN_FILTER_ALLOW_ALL,
  .scan_interval          = 0x50,
  .scan_window            = 0x30
};

Con il metodo esp_ble_gap_set_scan_params() si configura il processo di scan passando al driver la struct sopra definita:

esp_ble_gap_set_scan_params(&ble_scan_params);

Quando il driver ha terminato la configurazione, chiama la funzione di callback con l’evento ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT. In base all’evento sollevato, la funzione di callback riceve anche dei parametri. La Programming Guide del framework riporta – per ogni evento – i relativi parametri. Per questo evento è disponibile la variabile scan_param_cmpl che contiene solo il parametro status.

Nella funzione di callback utilizziamo un comando switch per identificare il singolo evento:

switch (event) {
  case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT:
  [...]
  break;

e verifichiamo se la configurazione ha avuto esito positivo con:

if(param->scan_param_cmpl.status == ESP_BT_STATUS_SUCCESS)

In caso affermativo possiamo lanciare il processo di scan con:

esp_ble_gap_start_scanning(10);

Il parametro indica la durata (in secondi) della scansione.

Una volta avviato il processo di scan, il driver solleva l’evento ESP_GAP_BLE_SCAN_START_COMPLETE_EVT. Anche qui è possibile verificare la corretta esecuzione del processo leggendo il parametro status (attenzione, cambia il nome della variabile che lo contiene!):

case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT:
  if(param->scan_start_cmpl.status == ESP_BT_STATUS_SUCCESS)
    printf("Scan started\n\n");
  else 
    printf("Unable to start scan process");
  break;

GAP, processo di scan

Quando il processo di scan è in esecuzione, per ogni pacchetto di advertising ricevuto viene sollevato l’evento ESP_GAP_BLE_SCAN_RESULT_EVT.

Questo evento contiene a sua volta dei sottoeventi. E’ possibile identificare di quale sottoevento si tratta leggendo il parametro scan_rst.search_evt. Ci interessano due sottoeventi in particolare:

ble-006

il primo indica che un nuovo dispositivo è stato rilevato, mentre il secondo che il processo di scan è terminato.

Per ogni dispositivo rilevato sono disponibili diverse informazioni, per ora stampiamo in console il suo indirizzo:

case ESP_GAP_BLE_SCAN_RESULT_EVT:
  if(param->scan_rst.search_evt == ESP_GAP_SEARCH_INQ_RES_EVT) {
    printf("Device found: ADDR=");
    for(int i = 0; i < ESP_BD_ADDR_LEN; i++) {
      printf("%02X", param->scan_rst.bda[i]);
      if(i != ESP_BD_ADDR_LEN -1) printf(":");
    }

L’indirizzo è rappresentato da un array di uint8_t. La dimensione dell’array è definita dalla costante ESP_BD_ADDR_LEN. Normalmente l’indirizzo viene visualizzato in forma esadecimale, con i bytes divisi da :

ble-007

Gestione elenco devices

Come detto, l’evento ESP_GAP_BLE_SCAN_RESULT_EVT viene sollevato ogni volta che un dispositivo invia un pacchetto di advertising. Questo significa che un singolo dispositivo sarà rilevato più volte durante il processo di scansione.

E’ quindi necessario mantenere un elenco dei dispositivi già noti. Nel mio repository Github trovate un programma di esempio che effettua uno scan e stampa tutti i dispositivi rilevati.

E’ possibile verificare il corretto funzionamento confrontando quanto rilevato dal chip esp32 con quanto rilevato da uno smartphone… per Android ad esempio si può utilizzare l’ottima applicazione nRF Connect di Nordic.

Ecco quanto rilevato dal mio programma:

ble-008

ed ecco lo screenshot di nRF Connect:

ble-009

 

4 Comments »

  1. jawed Sayed 03/03/2018 at 20:04 - Reply

    good short article, enjoy them,
    Could you please address:
    a. BLE in peripheral mode.
    b. BLE and wiFi in a single program.

    when will you publish your next application.
    Thx – please keep up the good work

  2. awais ahmed 18/07/2018 at 05:49 - Reply

    Hi,
    how can i measure the latency and data rate of BLE ?

    • luca 04/08/2018 at 13:26 - Reply

      you can’t do it using only the framework, you probably have to implement some functions in your code (adding a timestamp to each packet can help in measuring the latency but tx and rx must be well syncronized…)

Leave A Response »

Questo sito usa i cookie per poterti offrire una migliore esperienza di navigazione maggiori informazioni

Questo sito utilizza i cookie per fonire la migliore esperienza di navigazione possibile. Continuando a utilizzare questo sito senza modificare le impostazioni dei cookie o clicchi su "Accetta" permetti al loro utilizzo.

Chiudi