2017年4月12日水曜日

ESP32を2つ使い、GATT clientとGATT server間で情報をやりとりする方法


GATT clientのサンプルコードを書き換えて、前回作成したGATT serverに接続して、notifを取得できました。
方法を共有します。

使ったもの

  • ESP32モジュール2つ
  • esp-idfをインストールしたPC
  • シリアルモニタプログラム
    ログの確認に使いました。
    ubuntuのscreenコマンドを利用しました

GATT server

前回の投稿で作成したプログラムを利用しています。
詳しくはこちらをご覧ください。

プログラム: esp32-idf-samples/gatt_server_notif_switch/main/gatt_server_notif_switch.c
記事: ESP32からBLE GATTのnotifを発信し、nodejs(noble)で受信する方法

GATT client

利用したプログラムはこちらです。

esp32-idf-samples/gatt_client_listen_notif_then_output_to_led/main/gattc_demo.c

このプログラムは、esp-idfのgatt clientに関するサンプルプログラムの一部を変更したものです。
変更内容を説明します。

通知を受け取るGATT serverに合わせて設定変更

device_name, service_id, characteristic_idをそれぞれGATT serverとして利用するデバイスに合わせます。
今回は下記デバイスのnotifを受信します。

自作デバイスのnotif発信情報
device_name: ESP_GATTS_SWITCH
service_id: 0xff
characteristic_id: 0xff01

上記の設定を反映するために、編集を定義・編集します。
static esp_gatt_srvc_id_t alert_service_id = {
..
            .uuid = {.uuid16 = 0xff,}, //origin: 0x1811
..
};

static uint16_t listen_char_id = 0xff01;

static const char device_name[] = "ESP_GATTS_SWITCH"; //origin: "Alert Notification"

gatt_profile_a_event_handlerの内容を、先程定義した変数に変更します。
static void gattc_profile_a_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param)
{
..
    case ESP_GATTC_GET_CHAR_EVT:
..
        if (p_data->get_char.char_id.uuid.uuid.uuid16 == listen_char_id ) { //origin: 0x2a46
..

..
}

これで、自作したデバイスのnotifを受信できるようになりました。


受け取った通知の内容に応じて、LEDを光らせるための変更

ログを確認しなくても通知の受信を確認したいので、下記のように動作させとうと思います。

通知の値が0: LEDをON
通知の値が1: LEDをOFF

GPIOを使うためのライブラリと定数を宣言します。
#include "esp_system.h"

#define GPIO_OUTPUT_IO_0    2 // for LED
#define GPIO_OUTPUT_IO_1    19
#define GPIO_OUTPUT_PIN_SEL  ((1<<GPIO_OUTPUT_IO_0) | (1<<GPIO_OUTPUT_IO_1))


初期化とLEDの操作のための関数を定義します。
static void init_led() {
    gpio_config_t io_conf;
    //disable interrupt
    io_conf.intr_type = GPIO_PIN_INTR_DISABLE;
    //set as output mode
    io_conf.mode = GPIO_MODE_OUTPUT;
    //bit mask of the pins that you want to set
    io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL;
    //disable pull-down mode
    io_conf.pull_down_en = 0;
    //disable pull-up mode
    io_conf.pull_up_en = 0;
    //configure GPIO with the given settings
    gpio_config(&io_conf);

    printf("led initlalized");
}

static void switch_led(bool value) {
    int out_value = 0;
    if (value) {
        out_value = 1;
    }
    printf("out value %d\n", out_value);
    gpio_set_level(GPIO_OUTPUT_IO_0, out_value);
}


通知がきたら、値に応じてLEDの光り方を変化させます。
static void gattc_profile_a_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param)
{
..
    case ESP_GATTC_NOTIFY_EVT:
        switch_led(0 == (*(uint32_t *)p_data->notify.value % 2));
..
}


定義した初期化の関数をmainで呼びます。
void app_main()
{
..
    init_led();
}

これで、受信した通知の値によってLEDの光り方が変わるようになりました。

プログラムの書き込み

GATT clientとして動作させたいESP32をPCに接続して、下記のコマンドでプログラムを書き込みます。
cd [this gatt client project directory]
make flash

動作確認

それぞれのデバイスを単体で動作させると、何が起きているのか分かりにくいので、うまく動かない時はログを見ながら動作確認することをお勧めします。

ubuntu環境下では、ターミナルを2つ立ち上げ、それぞれでscreenコマンドを起動すると、2つのESP32からのログを確認できます。

ターミナルで下記のコマンドを実行します。
screen /dev/ttyUSB0

別ターミナルで下記のコマンドを実行します。
screen /dev/ttyUSB1

GATT接続が成功した時のログはこのような感じです。
左がGATT client、右がGATT serverです。



GATT serverのスイッチを押すと、双方のログが更新されると共に、GATT clientのLEDが点灯します。



共有する情報は以上です。

参考

how to send BLE notification to client
GATT SERVER API: esp_ble_gatts_send_indicate

変更履歴

2017.04.26
デバイス名比較に関する修正が反映されたので、それに関する記述を削除しました。

0 件のコメント :

コメントを投稿