This is a sample using ESP32 AT command for BLE.

Information

Japanese version is available in lower part of this page.
このページの後半に日本語版が用意されています.


What is this ?

This is a sample using ESP32 AT command for BLE.
You can test communication with your smartphone using the following GATT profile. In the sample, the GR board is the server and the smartphone is the client. In GR-LYCHEE, pressing the UB 0 button writes the value to C 300, and pressing the UB 1 button performs Notification to C 305.

UUIDAccess PropetySize(Byte)Characteristic Index
A002Read2-
C300Read11
C301Read5122
C302Write13
C303Write Without Response34
C304Write25
C305Notify56
C306Indicate57



概要

ESP32のBLE用ATコマンドを使用したサンプルです。
以下のGATTプロファイルを利用して、スマートフォンとの通信をテストできます。サンプルではGRボードがサーバとなり、スマートフォンがクライアントです。GR-LYCHEEでは、UB0ボタンを押すとC300への値書込み、UB1ボタンを押すとC305へのNotificationが行われます。

UUIDAccess PropetySize(Byte)Characteristic Index
A002Read2-
C300Read11
C301Read5122
C302Write13
C303Write Without Response34
C304Write25
C305Notify56
C306Indicate57
Revision:
0:81023cbaf4d2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Wed Nov 29 03:11:12 2017 +0000
@@ -0,0 +1,234 @@
+#include "mbed.h"
+#include "ESP32.h"
+
+#define BLE_NOTIFICATION_CHAR 6
+#define BLE_INDICATION_CHAR   7
+
+BufferedSerial esp32(P7_1, P0_1, 1024);
+ATParser_os esp_parser(esp32);
+Serial pc(USBTX, USBRX); // tx, rx
+DigitalOut esp_en(P5_3);
+DigitalOut esp_io0(P3_14);
+DigitalOut led_green(LED1);
+DigitalOut led_yellow(LED2);
+DigitalOut led_orange(LED3);
+DigitalOut led_red(LED4);
+InterruptIn button0(USER_BUTTON0);
+InterruptIn button1(USER_BUTTON1);
+Semaphore event_sem(0);
+
+const char ble_name[] = "GR-LYCHEE";
+bool ble_advertizing;
+bool ble_connected;
+uint8_t ble_conn_index;
+uint8_t ble_srv_index;
+
+bool button0_flag = false;
+bool button1_flag = false;
+bool ble_notification_on = false;
+bool ble_indication_on = false;
+
+void esp32_event() {
+    event_sem.release();
+}
+
+void ble_client_read() {
+    uint8_t mac[6] = {0};
+
+    led_yellow = 1;
+    esp_parser.recv("%hhd,\"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx\"",
+            &ble_conn_index, &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
+    printf("conn_index=%d, mac[%x:%x:%x:%x:%x:%x]\r\n",
+            ble_conn_index, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+    led_yellow = 0;
+}
+
+void ble_client_write() {
+    uint8_t char_index, desc_index = 0;
+    uint16_t len;
+
+    led_orange = 1;
+    esp_parser.recv("%hhd,%hhd,%hhd,", &ble_conn_index, &ble_srv_index, &char_index);
+    printf("conn=%d srv=%d char=%d\r\n", ble_conn_index, ble_srv_index, char_index);
+
+    char c = esp_parser.getc();
+    if (c != ',') {
+        desc_index = c;
+        esp_parser.getc(); // to read ',' after desc_index.
+        printf("desc=%d\r\n", desc_index);
+    }
+
+    esp_parser.recv("%hhd,", &len);
+    printf("length=%d\r\n", len);
+
+    uint8_t *data = (uint8_t *)malloc(len * sizeof(uint8_t));
+    for (int i = 0; i < len; i++) {
+        data[i] = esp_parser.getc();
+        printf("%x\r\n", data[i]);
+    }
+
+    if ((desc_index == 49) && (char_index == BLE_NOTIFICATION_CHAR)) {
+        if (data[0] == 1) {
+            printf("Notification On\r\n");
+            ble_notification_on = true;
+        } else {
+            printf("Notification Off\r\n");
+            ble_notification_on = false;
+        }
+    } else if ((desc_index == 49) && (char_index == BLE_INDICATION_CHAR)) {
+        if (data[0] == 2) {
+            printf("Indication On\r\n");
+            ble_indication_on = true;
+        } else {
+            printf("Indication Off\r\n");
+            ble_indication_on = false;
+        }
+    }
+    led_orange = 0;
+}
+
+void ble_client_disconn() {
+    led_green = 0;
+    printf("disconnected client\r\n");
+    ble_connected = false;
+}
+
+void ble_client_conn() {
+    uint8_t mac[6] = {0};
+    esp_parser.recv("%hhd,\"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx\"",
+                    &ble_conn_index, &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
+    printf("connected client conn_index is %d, mac[%x:%x:%x:%x:%x:%x]\r\n",
+            ble_conn_index, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+
+    led_green = 1;
+    ble_advertizing = false;
+    ble_connected = true;
+}
+
+void ub0_interrupt() {
+    if (button0_flag == false) {
+        button0_flag = true;
+        event_sem.release();
+    }
+}
+
+void ub1_interrupt() {
+    if (button1_flag == false) {
+        button1_flag = true;
+        event_sem.release();
+    }
+}
+
+int main() {
+
+    printf("Bluetooth sample started\r\n");
+    led_green = 0;
+    led_yellow = 0;
+    led_orange = 0;
+    led_red = 0;
+    ble_advertizing = false;
+    ble_connected = false;
+    button0.fall(ub0_interrupt);
+    button1.fall(ub1_interrupt);
+
+    // Initializing esp32 access
+    esp32.baud(115200);
+    esp32.attach(Callback<void()>(esp32_event));
+    esp_io0 = 1;
+    esp_en = 0;
+    Thread::wait(10);
+    esp_en = 1;
+    esp_parser.setTimeout(1500);
+    if (esp_parser.recv("ready")) {
+        printf("ESP32 ready\r\n");
+    } else {
+        printf("ESP32 error\r\n");
+        led_red = 1;
+        while (1);
+    }
+
+    // Initializing esp32 as a server with GATT service
+    esp_parser.setTimeout(5000);
+    if (esp_parser.send("AT+BLEINIT=2") && esp_parser.recv("OK")
+            && esp_parser.send("AT+BLENAME=\"%s\"", ble_name) && esp_parser.recv("OK")
+            && esp_parser.send("AT+BLEGATTSSRVCRE") && esp_parser.recv("OK")
+            && esp_parser.send("AT+BLEGATTSSRVSTART") && esp_parser.recv("OK")) {
+        printf("GATT initialized\r\n");
+    } else {
+        printf("fail to initialize\r\n");
+        led_red = 1;
+        while (1);
+    }
+
+    uint8_t start, type;
+    uint16_t uuid;
+    esp_parser.send("AT+BLEGATTSSRV?");
+    if (esp_parser.recv("+BLEGATTSSRV:%hhd,%hhd,%hhx,%hhd\r\nOK", &ble_srv_index, &start, &uuid, &type)) {
+        printf("srv_index is %d\r\n", ble_srv_index);
+    } else {
+        printf("fail to get service\r\n");
+        led_red = 1;
+    }
+
+    esp_parser.oob("+READ:", ble_client_read);
+    esp_parser.oob("+WRITE:", ble_client_write);
+    esp_parser.oob("+BLEDISCONN:", ble_client_disconn);
+    esp_parser.oob("+BLECONN:", ble_client_conn);
+
+    while (1) {
+        esp_parser.setTimeout(5000);
+        if (esp_parser.send("AT+BLEADVSTART") && esp_parser.recv("OK")) {
+            printf("Advertising started. Please connect to any client\r\n");
+            ble_advertizing = true;
+        } else {
+            printf("fail to start advertising\r\n");
+            led_red = 1;
+            while (1);
+        }
+
+        while (ble_connected || ble_advertizing) {
+            event_sem.wait();
+            esp_parser.setTimeout(5);
+            esp_parser.recv(" ");  //dummy read for parser callback
+
+            // Set attribute of C300
+            if (button0_flag) {
+                static uint8_t data = 1; // write data
+                esp_parser.setTimeout(5000);
+                // AT+BLEGATTSSETATTR=<srv_index>,<char_index>[,<desc_index>],<length>
+                if (esp_parser.send("AT+BLEGATTSSETATTR=%d,1,,1", ble_srv_index) && esp_parser.recv(">")) {
+                    if (esp_parser.putc(data) && esp_parser.recv("OK")) {
+                        printf("success to send\r\n");
+                    } else {
+                        printf("fail to send\r\n");
+                    }
+                } else {
+                    printf("fail to command AT\r\n");
+                }
+                esp_parser.flush();
+                button0_flag = false;
+                data++;
+            }
+
+            // Set notification of C305
+            if (button1_flag && ble_notification_on) {
+                static uint8_t data = 0xff; // write data
+                esp_parser.setTimeout(5000);
+                // AT+BLEGATTSNTFY=<conn_index>,<srv_index>,<char_index>,<length>
+                if (esp_parser.send("AT+BLEGATTSNTFY=%d,%d,%d,1", ble_conn_index, ble_srv_index, BLE_NOTIFICATION_CHAR)
+                    && esp_parser.recv(">")) {
+                    if (esp_parser.putc(data) && esp_parser.recv("OK")) {
+                        printf("success to notify\r\n");
+                    } else {
+                        printf("fail to notify\r\n");
+                    }
+                } else {
+                    printf("fail to command AT\r\n");
+                }
+                esp_parser.flush();
+                button1_flag = false;
+                data--;
+            }
+        }
+    }
+}