So-net無料ブログ作成

ESP32 の機能を再確認してみた! [Arduino]

ESP32 をなんとなく使いこなす自信もついてきたので、ESP32 の機能を再確認してみることにしました。ESP32 の Datasheet から主要機能をピックアップしてみました。

ESP32 Datasheet
ESP32_datasheet.png
http://espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf


Wi-Fi は、2.4GHz帯 のみですね。まぁ値段がこれですから当然か。でも n に対応しているのはポイント高いです。

1.2 Wi-Fi Key Features
 802.11 b/g/n/e/i
 802.11 n (2.4 GHz), up to 150 Mbps
 802.11 e: QoS for wireless multimedia technology
 WMM-PS, UAPSD
 A-MPDU and A-MSDU aggregation
 Block ACK
 Fragmentation and defragmentation
 Automatic Beacon monitoring/scanning
 802.11 i security features: pre-authentication and TSN
 Wi-Fi Protected Access (WPA)/WPA2/WPA2-Enterprise/Wi-Fi Protected Setup (WPS)
 Infrastructure BSS Station mode/SoftAP mode
 Wi-Fi Direct (P2P), P2P Discovery, P2P Group Owner mode and P2P Power Management
 UMA compliant and certified
 Antenna diversity and selection


Bluetooth は、v4.2 対応です。BLEならびにGATTもサポートしています。HeartRateブロファイルで確認清みですね。A2DP/HSP/HFP もサポートしているので、ヘッドセットみたいなのもできそうですね。

1.3 BT Key Features
 Compliant with Bluetooth v4.2 BR/EDR and BLE specification
 Class-1, class-2 and class-3 transmitter without external power amplifier
 Enhanced power control
 +12 dBm transmitting power
 NZIF receiver with -97 dBm sensitivity
 Adaptive Frequency Hopping (AFH)
 Standard HCI based on SDIO/SPI/UART
 High-speed UART HCI, up to 4 Mbps
 BT 4.2 controller and host stack
 Service Discover Protocol (SDP)
 General Access Profile (GAP)
 Security Manage Protocol (SMP)
 ATT/GATT
 HID
 All GATT-based profile supported
 SPP-like GATT-based profile
 BLE Beacon
 A2DP/AVRCP/SPP, HSP/HFP, RFCOMM
 CVSD and SBC for audio codec
 Bluetooth Piconet and Scatternet


CPUはデュアルコアですね。メモリは520kB+15kB。外付けの Quad SPI Flash がつくようです。駆動電圧は 3.3V。

1.4.1 CPU and Memory
 Xtensa[レジスタードトレードマーク] single-/dual-core 32-bit LX6 microprocessor(s), up to 600 DMIPS (200 DMIPS for single-core microprocessor)
 448 kB ROM
 520 kB SRAM
 16 kB SRAM in RTC
 QSPI flash/SRAM, up to 4 x 16 MB
 Power supply: 2.3V to 3.6V


タイマーは2系統のようです。RTCは当然ありますね。Wi-Fiと相性が良いので助かります。

1.4.2 Clocks and Timers
 Internal 8 MHz oscillator with calibration
 Internal RC oscillator with calibration
 External 2 MHz to 60 MHz crystal oscillator (40 MHz only for Wi-Fi/BT functionality)
 External 32 kHz crystal oscillator for RTC with calibration
 Two timer groups, including 2 x 64-bit timers and 1 x main watchdog in each group
 RTC timer with sub-second accuracy
 RTC watchdog


12-bit ADCが18チャンネルもあるってスゴイですね。ただサンプリングレートが明記されていません。遅いのかな。CANもサポートとしているので車関連のアプリも作れますね。プリアンプも載っているんですね。DACが2系統あるし、音を出すためかな。すごいなぁ。

1.4.3 Advanced Peripheral Interfaces
 12-bit SAR ADC up to 18 channels
 2 × 8-bit DAC
 10 × touch sensors
 Temperature sensor
 4 × SPI
 2 × I2S
 2 × I2C
 3 × UART
 1 host (SD/eMMC/SDIO)
 1 slave (SDIO/SPI)
 Ethernet MAC interface with dedicated DMA and IEEE 1588 support
 CAN 2.0
 IR (TX/RX)
 Motor PWM
 LED PWM up to 16 channels
 Hall sensor
 Ultra-low-noise analog pre-amplifier


セキュアブートをサポートしていて、ハードウェアの暗号化エンジンもあります。フラッシュ暗号化もサポートしているので、セキュリティはばっちりですね。

1.4.4 Security
 IEEE 802.11 standard security features are all supported, including WFA, WPA/WPA2 and WAPI
 Secure boot
 Flash encryption
 1024-bit OTP, up to 768-bit for customers
 Cryptographic hardware acceleration:
  > AES
  > HASH (SHA-2) library
  > RSA
  > ECC
  > Random Number Generator (RNG)

スマホのSoCに比べると、計算能力やワークメモリの容量はとても及びませんが、基本機能はほぼ匹敵するといってもいいくらいです。ESP32の全機能が使いこなせるようになったら面白そうです。
(^^)/~





waves ESP32-DevKitC ESP-WROOM-32 ESP32 DevKitC V2 WiFi BLE 技適取得済 国内発送

waves ESP32-DevKitC ESP-WROOM-32 ESP32 DevKitC V2 WiFi BLE 技適取得済 国内発送

  • 出版社/メーカー: waves(ウェイブス)
  • メディア: エレクトロニクス



waves ESP32 ESPDuino-32 (ESP-WROOM-32) 技適取得品

waves ESP32 ESPDuino-32 (ESP-WROOM-32) 技適取得品

  • 出版社/メーカー: waves(ウェイブス)
  • メディア: おもちゃ&ホビー



MicroPython for ESP32 Development Workshop (English Edition)

MicroPython for ESP32 Development Workshop (English Edition)

  • 出版社/メーカー:
  • 発売日: 2017/08/19
  • メディア: Kindle版




タグ:ESP32
nice!(32)  コメント(0) 

ESP32 で高周波クロックをPWMで生成してみた! [Arduino]

ESP32 で 1MHz の高周波クロックが生成できるか試してました。波形はオシロスコープで確認しました。

DSC04871.JPG


最初に試してみたのは、サーボモーターをコントロールした方法。スケッチを以下に示します。

#include "esp_system.h"

void setup() {
  ledcSetup(0, 1000000, 8);  // 0ch, 1MHz, 8bit
  ledcAttachPin(15, 0); // 15pin 0ch
  ledcWrite(0, 128); // 0ch, duty 50% (128/256)
}

void loop() {
}



観測した波形がこちら。


ESP32_pwm_simple.png


1MHz にはほど遠いだいたい310kHz程度の上、波形をよくよく見るとパルス幅が不揃いで、安定した波形が得られていません。

で、いろいろと調べてみたら、ESP32 の PWM で高周波クロックを出力するには、HIGH_SPEED モードに設定する必要があるようです。スケッチを以下に示します。


#include "esp_system.h"
#include "driver/ledc.h"

void setup() {
   ledc_timer_bit_t bit_num = (ledc_timer_bit_t) 3; // duty range = 2^3 = 8

   // Enable LEDC PWM peripheral
   periph_module_enable(PERIPH_LEDC_MODULE);

   // Set Duty
   int duty = pow(2, (int) bit_num) / 2;  // (2^3) /2 = 4 : 50% 

   // setup the timer
   ledc_timer_config_t clk_timer;
   clk_timer.bit_num = bit_num; // 3
   clk_timer.freq_hz = 1000000; // 1MHz
   clk_timer.speed_mode = LEDC_HIGH_SPEED_MODE;
   clk_timer.timer_num = LEDC_TIMER_0;
   ledc_timer_config(&clk_timer);

   // setup the pwm channel
   ledc_channel_config_t pwm_channel;
   pwm_channel.channel = LEDC_CHANNEL_0;
   pwm_channel.duty = duty;
   pwm_channel.gpio_num = GPIO_NUM_15;
   pwm_channel.intr_type = LEDC_INTR_DISABLE;
   pwm_channel.speed_mode = LEDC_HIGH_SPEED_MODE;
   pwm_channel.timer_sel = LEDC_TIMER_0;
   ledc_channel_config(&pwm_channel);

   // Set the PWM to the duty specified
   ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_0, duty);
   ledc_update_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_0);
}

void loop() {

}



波形を確認してみます。


ESP32_pwm_complex.png


比較的安定した波形が得られました。オシロスコープが MHz の信号を観測するには性能不足なので、少し誤差が出ていますが、ほぼ 1MHz のクロックが得られたようです。

ESP32はまだ出たばかりなので、使いこなすのはちょっと面倒ですね。
σ(^_^;





waves ESP32-DevKitC ESP-WROOM-32 ESP32 DevKitC V2 WiFi BLE 技適取得済 国内発送

waves ESP32-DevKitC ESP-WROOM-32 ESP32 DevKitC V2 WiFi BLE 技適取得済 国内発送

  • 出版社/メーカー: waves(ウェイブス)
  • メディア: エレクトロニクス



waves ESP32 ESPDuino-32 (ESP-WROOM-32) 技適取得品

waves ESP32 ESPDuino-32 (ESP-WROOM-32) 技適取得品

  • 出版社/メーカー: waves(ウェイブス)
  • メディア: おもちゃ&ホビー



SparkFun ESP32 Thing Development Workshop (English Edition)

SparkFun ESP32 Thing Development Workshop (English Edition)

  • 出版社/メーカー: PE Press
  • 発売日: 2017/04/09
  • メディア: Kindle版




nice!(31)  コメント(2) 
共通テーマ:趣味・カルチャー

ESP32 の BLEデバイス化にチャレンジ!(4)ついに完結! [Arduino]

ずっと苦労していた ESP32 のBLEデバイス化ですが、ようやくうまく行きました!(涙)
。・゚・(ノД`)・゚・。


DSC04856.JPG


まずは成功した証。スマホアプリ LAPIS Semconductor さん謹製の BLE TOOL の画面を披露します。


ESP32_Heart_Rate.png



ばっちり心拍データを受信しています。実際に心拍を測定しているわけでなく、ランダムデータなんですけどね。^^; いろんな試行錯誤をした後、完成したスケッチがこちらです。

#pragma GCC diagnostic push
#pragma GCC diagnostic warning "-fpermissive"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "bt.h"
#include "bta_api.h"

#include "esp_gap_ble_api.h"
#include "esp_gatts_api.h"
#include "esp_bt_defs.h"
#include "esp_bt_main.h"

#define HRPS_HT_MEAS_MAX_LEN  13

///Attributes State Machine
enum {
    HRS_IDX_SVC,

    HRS_IDX_HR_MEAS_CHAR,
    HRS_IDX_HR_MEAS_VAL,
    HRS_IDX_HR_MEAS_NTF_CFG,
    
    HRS_IDX_NB,
};

#define ESP_HEART_RATE_APP_ID           0x55
#define SAMPLE_DEVICE_NAME              "ESP_HEART_RATE"
#define SAMPLE_MANUFACTURER_DATA_LEN    17
#define HEART_RATE_SVC_INST_ID          0

static uint8_t heart_rate_service_uuid[16] = {
    /* LSB <--------------------------------------------------------------------------------> MSB */
    // first uuid, 16bit, [12],[13] is the value
    0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x18, 0x0D, 0x00, 0x00,
};

static esp_ble_adv_data_t heart_rate_adv_config = {
    .set_scan_rsp = false,
    .include_name = true,
    .include_txpower = true,
    .min_interval = 0x20,
    .max_interval = 0x40,
    .appearance = 0x00,
    .manufacturer_len = 0, //TEST_MANUFACTURER_DATA_LEN,
    .p_manufacturer_data =  NULL, //&test_manufacturer[0],
    .service_data_len = 0,
    .p_service_data = NULL,
    .service_uuid_len = sizeof(heart_rate_service_uuid),
    .p_service_uuid = heart_rate_service_uuid,
    .flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT),
};

static esp_ble_adv_params_t heart_rate_adv_params; 

struct gatts_profile_inst {
    esp_gatts_cb_t gatts_cb;
    uint16_t gatts_if;
    uint16_t app_id;
    uint16_t conn_id;
    uint16_t service_handle;
    esp_gatt_srvc_id_t service_id;
    uint16_t char_handle;
    esp_bt_uuid_t char_uuid;
    esp_gatt_perm_t perm;
    esp_gatt_char_prop_t property;
    uint16_t descr_handle;
    esp_bt_uuid_t descr_uuid;
};


static void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param);

/* One gatt-based profile one app_id and one gatts_if, this array will store the gatts_if returned by ESP_GATTS_REG_EVT */
static struct gatts_profile_inst heart_rate_profile = {
    .gatts_cb = gatts_profile_event_handler,
    .gatts_if = ESP_GATT_IF_NONE, 
};

/// Heart Rate Sensor Service
static const uint16_t heart_rate_svc = ESP_GATT_UUID_HEART_RATE_SVC;

#define CHAR_DECLARATION_SIZE   (sizeof(uint8_t))
static const uint16_t primary_service_uuid = ESP_GATT_UUID_PRI_SERVICE;
static const uint16_t character_declaration_uuid = ESP_GATT_UUID_CHAR_DECLARE;
static const uint16_t character_client_config_uuid = ESP_GATT_UUID_CHAR_CLIENT_CONFIG;
static const uint8_t char_prop_notify = ESP_GATT_CHAR_PROP_BIT_NOTIFY;
static const uint8_t char_prop_read = ESP_GATT_CHAR_PROP_BIT_READ;
static const uint8_t char_prop_read_write = ESP_GATT_CHAR_PROP_BIT_WRITE|ESP_GATT_CHAR_PROP_BIT_READ;

/// Heart Rate Sensor Service - Heart Rate Measurement Characteristic, notify
static const uint16_t heart_rate_meas_uuid = ESP_GATT_HEART_RATE_MEAS;
static const uint8_t heart_measurement_ccc[2] ={ 0x00, 0x00};

/// Full HRS Database Description - Used to add attributes into the database
static const esp_gatts_attr_db_t heart_rate_gatt_db[HRS_IDX_NB] =
{
    // Heart Rate Service Declaration
    [HRS_IDX_SVC]                       =  
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&primary_service_uuid, ESP_GATT_PERM_READ,
      sizeof(uint16_t), sizeof(heart_rate_svc), (uint8_t *)&heart_rate_svc}},

    // Heart Rate Measurement Characteristic Declaration
    [HRS_IDX_HR_MEAS_CHAR]            = 
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ,
      CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_notify}},
      
    // Heart Rate Measurement Characteristic Value
    [HRS_IDX_HR_MEAS_VAL]               =   
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&heart_rate_meas_uuid, ESP_GATT_PERM_READ,
      HRPS_HT_MEAS_MAX_LEN, 0, NULL}},

    // Heart Rate Measurement Characteristic - Client Characteristic Configuration Descriptor
    [HRS_IDX_HR_MEAS_NTF_CFG]       =    
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_client_config_uuid, ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE,
      sizeof(uint16_t),sizeof(heart_measurement_ccc), (uint8_t *)heart_measurement_ccc}},
};


static uint16_t heart_rate_handle_table[HRS_IDX_NB];


//////////////////////////////////////////////////////
static void ble_indicate() {
    if (heart_rate_profile.gatts_if == ESP_GATT_IF_NONE) {
        Serial.println("cannot indicate: gatts_if_for_indicate is NONE");
        return;
    }
    uint8_t hrm_value = random(30, 220);
    uint8_t hrm_value_arr[] = {0x00, hrm_value};
    Serial.println(hrm_value);
    esp_ble_gatts_send_indicate(heart_rate_profile.gatts_if, 
        heart_rate_profile.conn_id, heart_rate_handle_table[HRS_IDX_HR_MEAS_VAL], 
        sizeof(hrm_value_arr), hrm_value_arr, false);
}
//////////////////////////////////////////////////////


static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
    switch (event) {
    case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT:
        Serial.println("gap start advertising....");
        esp_ble_gap_start_advertising(&heart_rate_adv_params);
        break;
    case ESP_GAP_BLE_ADV_START_COMPLETE_EVT:
        //advertising start complete event to indicate advertising start successfully or failed
        if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) {
            Serial.println("gap advertising failed");
        }
        Serial.println("gap advertising success");
        break;
    default:
        break;
    }
}

static bool bConnected = false;

static void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) 
{
    switch (event) {
    case ESP_GATTS_REG_EVT:
        Serial.println("gatt server register event");
        esp_ble_gap_set_device_name(SAMPLE_DEVICE_NAME);
        esp_ble_gap_config_adv_data(&heart_rate_adv_config);
        esp_ble_gatts_create_attr_tab(heart_rate_gatt_db, gatts_if, HRS_IDX_NB, HEART_RATE_SVC_INST_ID);
        break;
    case ESP_GATTS_READ_EVT: 
        Serial.println("gatt server read event");
        break;
    case ESP_GATTS_WRITE_EVT: 
        Serial.println("gatt server write event");       
        break;
    case ESP_GATTS_EXEC_WRITE_EVT:
        Serial.println("gatt server exec write event");       
        break;
    case ESP_GATTS_MTU_EVT:
        Serial.println("gatt server mtu event?");       
         break;
   case ESP_GATTS_CONF_EVT:
        Serial.println("gatt server configuration event");       
        heart_rate_profile.gatts_if = gatts_if;
        heart_rate_profile.conn_id = param->connect.conn_id;
        break;
   case ESP_GATTS_UNREG_EVT:
        Serial.println("gatt server unregister event");       
        break;
   case ESP_GATTS_DELETE_EVT:
        Serial.println("gatt server delete event");       
        break;
   case ESP_GATTS_START_EVT:
        Serial.println("gatt server start event");       
        break; 
   case ESP_GATTS_STOP_EVT:
        Serial.println("gatt server stop event");       
        break;
   case ESP_GATTS_CONNECT_EVT:
        Serial.println("gatt server connect event");       
        heart_rate_profile.gatts_if = gatts_if;
        heart_rate_profile.conn_id = param->connect.conn_id;
        bConnected = true;
        break;
   case ESP_GATTS_CREATE_EVT:
        Serial.println("gatt server create event");  
        break;
   case ESP_GATTS_ADD_CHAR_EVT:
        Serial.println("gatt server add char event");  
        break;
   case ESP_GATTS_ADD_CHAR_DESCR_EVT:
        Serial.println("gatt server add char descriptor event");  
        break;
   case ESP_GATTS_DISCONNECT_EVT:
        Serial.println("gatt server disconnect event");     
        esp_ble_gap_start_advertising(&heart_rate_adv_params);
        bConnected = false;
        break;
   case ESP_GATTS_OPEN_EVT:
        Serial.println("gatt server open event");     
        break;
   case ESP_GATTS_CANCEL_OPEN_EVT:
        Serial.println("gatt server cancel open event");     
        break;
   case ESP_GATTS_CLOSE_EVT:
        Serial.println("gatt server close event");     
        break;
   case ESP_GATTS_LISTEN_EVT:
        Serial.println("gatt server listen event");     
        break;
   case ESP_GATTS_CONGEST_EVT:
        Serial.println("gatt server congest event?");     
        break;
   case ESP_GATTS_CREAT_ATTR_TAB_EVT:
        {
            if (param->add_attr_tab.status != ESP_GATT_OK){
                Serial.println("create attribute table failed");
            } else if (param->add_attr_tab.num_handle != HRS_IDX_NB){
                Serial.println("create attribute table abnormally");
            } else {
                memcpy(heart_rate_handle_table, param->add_attr_tab.handles, sizeof(heart_rate_handle_table));
                esp_ble_gatts_start_service(heart_rate_handle_table[HRS_IDX_SVC]);
                Serial.println("gatt server create attribute tab successfully");     
            }
        }
        break;
   default:
        break;
   }
}

static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if,  esp_ble_gatts_cb_param_t *param)
{
    /* If event is register event, store the gatts_if for each profile */
    if (event == ESP_GATTS_REG_EVT) {
        if (param->reg.status == ESP_GATT_OK) {
            Serial.println("gatt server register accepted");
            heart_rate_profile.gatts_if = gatts_if;
        } else {
            Serial.println("gatt server register app failed");
            return;
        }
    }
  
    do {
        int idx;
        if (gatts_if == ESP_GATT_IF_NONE || gatts_if == heart_rate_profile.gatts_if) {
            if (heart_rate_profile.gatts_cb) {
                heart_rate_profile.gatts_cb(event, gatts_if, param);
            }
        }
    } while (0);
}

void setup() {

    Serial.begin(115200);

    /* initialize advertising info */
    heart_rate_adv_params.adv_int_min = 0x20;
    heart_rate_adv_params.adv_int_max = 0x40;
    heart_rate_adv_params.adv_type = ADV_TYPE_IND;
    heart_rate_adv_params.own_addr_type = BLE_ADDR_TYPE_PUBLIC;
    heart_rate_adv_params.channel_map = ADV_CHNL_ALL;
    heart_rate_adv_params.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY;

    btStart();

    esp_err_t ret;

    Serial.println("Init bluetooth");
    ret = esp_bluedroid_init();
    if (ret) {
        Serial.println("esp_bluedroid_init failed");
        return;
    }
    ret = esp_bluedroid_enable();
    if (ret) {
        Serial.println("esp_bluedroid_enable failed");
        return;
    }

    esp_ble_gatts_register_callback(gatts_event_handler);
    esp_ble_gap_register_callback(gap_event_handler);
    esp_ble_gatts_app_register(ESP_HEART_RATE_APP_ID);
}

void loop() {
  if (bConnected) {
      ble_indicate();
  } 
  delay(1000);
}



ポイントは二つ。ひとつは esp_ble_gatts_send_indicate の handle を CREATE_ATTR_TAB で取得したものを使ったのと、もう一つは、心拍データを16bit で送る必要があったことの2点です。この心拍データが 16bit 必要というのが気が付かずに、かなり時間をかけてしまいました。

全般的に、ESP32 SDK の BLE は mbed の Nordic のものよりも分かり難いですねぇ。でも、使い方のコツは分かったので、これから ESP32 を BLEデバイスとして活用できそうです!
(^_^)/~





waves ESP32-DevKitC ESP-WROOM-32 ESP32 DevKitC V2 WiFi BLE 技適取得済 国内発送

waves ESP32-DevKitC ESP-WROOM-32 ESP32 DevKitC V2 WiFi BLE 技適取得済 国内発送

  • 出版社/メーカー: waves(ウェイブス)
  • メディア: エレクトロニクス



waves ESP32 ESPDuino-32 (ESP-WROOM-32) 技適取得品

waves ESP32 ESPDuino-32 (ESP-WROOM-32) 技適取得品

  • 出版社/メーカー: waves(ウェイブス)
  • メディア: おもちゃ&ホビー



MicroPython for ESP32 Development Workshop (English Edition)

MicroPython for ESP32 Development Workshop (English Edition)

  • 出版社/メーカー:
  • 発売日: 2017/08/19
  • メディア: Kindle版



タグ:Arduino BLE ESP32
nice!(32)  コメント(2) 
共通テーマ:趣味・カルチャー

ESP32 の BLEデバイス化にチャレンジ!(3) [Arduino]

今日は久しぶりに時間ができたので、じっくりと ESP32 の BLE について調べることができました。


DSC04860.JPG


なんとなく構造が分かってきたので、少しスケッチを整理してみました。見通しをよくするために "Body Sensor Location" や "Heart Rate Control Point" など、余計な "Characteristics" は省いてしまいました。

#pragma GCC diagnostic push
#pragma GCC diagnostic warning "-fpermissive"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "bt.h"
#include "bta_api.h"

#include "esp_gap_ble_api.h"
#include "esp_gatts_api.h"
#include "esp_bt_defs.h"
#include "esp_bt_main.h"
#include "esp_bt_main.h"

#define HRPS_HT_MEAS_MAX_LEN            13

///Attributes State Machine
enum {
    HRS_IDX_SVC,

    HRS_IDX_HR_MEAS_CHAR,
    HRS_IDX_HR_MEAS_VAL,
    HRS_IDX_HR_MEAS_NTF_CFG,

    HRS_IDX_NB,
};

#define ESP_HEART_RATE_APP_ID           0x55
#define SAMPLE_DEVICE_NAME              "ESP_HEART_RATE"
#define SAMPLE_MANUFACTURER_DATA_LEN    17
#define HEART_RATE_SVC_INST_ID          0

uint16_t heart_rate_handle_table[HRS_IDX_NB];

static uint8_t heart_rate_service_uuid[16] = {
    /* LSB <--------------------------------------------------------------------------------> MSB */
    //first uuid, 16bit, [12],[13] is the value
    0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x18, 0x0D, 0x00, 0x00,
};

static esp_ble_adv_data_t heart_rate_adv_config = {
    .set_scan_rsp = false,
    .include_name = true,
    .include_txpower = true,
    .min_interval = 0x20,
    .max_interval = 0x40,
    .appearance = 0x00,
    .manufacturer_len = 0, //TEST_MANUFACTURER_DATA_LEN,
    .p_manufacturer_data =  NULL, //&test_manufacturer[0],
    .service_data_len = 0,
    .p_service_data = NULL,
    .service_uuid_len = sizeof(heart_rate_service_uuid),
    .p_service_uuid = heart_rate_service_uuid,
    .flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT),
};

static esp_ble_adv_params_t heart_rate_adv_params; 

struct gatts_profile_inst {
    esp_gatts_cb_t gatts_cb;
    uint16_t gatts_if;
    uint16_t app_id;
    uint16_t conn_id;
    uint16_t service_handle;
    esp_gatt_srvc_id_t service_id;
    uint16_t char_handle;
    esp_bt_uuid_t char_uuid;
    esp_gatt_perm_t perm;
    esp_gatt_char_prop_t property;
    uint16_t descr_handle;
    esp_bt_uuid_t descr_uuid;
};

static void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param);

/* One gatt-based profile one app_id and one gatts_if, this array will store the gatts_if returned by ESP_GATTS_REG_EVT */
static struct gatts_profile_inst heart_rate_profile = {
    .gatts_cb = gatts_profile_event_handler,
    .gatts_if = ESP_GATT_IF_NONE, 
};

/// Heart Rate Sensor Service
static const uint16_t heart_rate_svc = ESP_GATT_UUID_HEART_RATE_SVC;

#define CHAR_DECLARATION_SIZE   (sizeof(uint8_t))
static const uint16_t primary_service_uuid = ESP_GATT_UUID_PRI_SERVICE;
static const uint16_t character_declaration_uuid = ESP_GATT_UUID_CHAR_DECLARE;
static const uint16_t character_client_config_uuid = ESP_GATT_UUID_CHAR_CLIENT_CONFIG;
static const uint8_t char_prop_notify = ESP_GATT_CHAR_PROP_BIT_NOTIFY;
static const uint8_t char_prop_read = ESP_GATT_CHAR_PROP_BIT_READ;
static const uint8_t char_prop_read_write = ESP_GATT_CHAR_PROP_BIT_WRITE|ESP_GATT_CHAR_PROP_BIT_READ;

/// Heart Rate Sensor Service - Heart Rate Measurement Characteristic, notify
static const uint16_t heart_rate_meas_uuid = ESP_GATT_HEART_RATE_MEAS;
static const uint8_t heart_measurement_ccc[2] ={ 0x00, 0x00};

static uint8_t hrm_value = 0x00;

/// Full HRS Database Description - Used to add attributes into the database
static const esp_gatts_attr_db_t heart_rate_gatt_db[HRS_IDX_NB] =
{
    // Heart Rate Service Declaration
    [HRS_IDX_SVC]                       =  
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&primary_service_uuid, ESP_GATT_PERM_READ,
      sizeof(uint16_t), sizeof(heart_rate_svc), (uint8_t *)&heart_rate_svc}},

    // Heart Rate Measurement Characteristic Declaration
    [HRS_IDX_HR_MEAS_CHAR]            = 
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ,
      CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_notify}},
      
    // Heart Rate Measurement Characteristic Value
    [HRS_IDX_HR_MEAS_VAL]               =   
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&heart_rate_meas_uuid, ESP_GATT_PERM_READ,
      HRPS_HT_MEAS_MAX_LEN, sizeof(hrm_value), (uint8_t *)&hrm_value}},

    // Heart Rate Measurement Characteristic - Client Characteristic Configuration Descriptor
    [HRS_IDX_HR_MEAS_NTF_CFG]       =    
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_client_config_uuid, ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE,
      sizeof(uint16_t),sizeof(heart_measurement_ccc), (uint8_t *)heart_measurement_ccc}},
};

//////////////////////////////////////////////////////
static void ble_indicate() {
    if (heart_rate_profile.gatts_if == ESP_GATT_IF_NONE) {
        Serial.println("cannot indicate: gatts_if_for_indicate is NONE");
        return;
    }
    hrm_value = random(100);
    Serial.println(hrm_value);

    esp_ble_gatts_send_indicate(heart_rate_profile.gatts_if, heart_rate_profile.conn_id, heart_rate_profile.char_handle, 
        sizeof(hrm_value), (uint8_t *)&hrm_value, true);

}
//////////////////////////////////////////////////////


static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
    switch (event) {
    case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT:
        Serial.println("gap start advertising....");
        esp_ble_gap_start_advertising(&heart_rate_adv_params);
        break;
    case ESP_GAP_BLE_ADV_START_COMPLETE_EVT:
        //advertising start complete event to indicate advertising start successfully or failed
        if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) {
            Serial.println("gap advertising failed");
        }
        Serial.println("gap advertising success");
        break;
    default:
        break;
    }
}

static bool bConnected = false;

static void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) 
{

    switch (event) {
    case ESP_GATTS_REG_EVT:
        Serial.println("gatt server register event");
        esp_ble_gap_set_device_name(SAMPLE_DEVICE_NAME);
        esp_ble_gap_config_adv_data(&heart_rate_adv_config);
        esp_ble_gatts_create_attr_tab(heart_rate_gatt_db, gatts_if, HRS_IDX_NB, HEART_RATE_SVC_INST_ID);
        break;
    case ESP_GATTS_READ_EVT: 
        Serial.println("gatt server read event");
        break;
    case ESP_GATTS_WRITE_EVT: 
        Serial.println("gatt server write event");       
        break;
    case ESP_GATTS_EXEC_WRITE_EVT:
        Serial.println("gatt server exec write event");       
        break;
    case ESP_GATTS_MTU_EVT:
        Serial.println("gatt server mtu event?");       
         break;
   case ESP_GATTS_CONF_EVT:
        Serial.println("gatt server configuration event");       
        break;
   case ESP_GATTS_UNREG_EVT:
        Serial.println("gatt server unregister event");       
        break;
   case ESP_GATTS_DELETE_EVT:
        Serial.println("gatt server delete event");       
        break;
   case ESP_GATTS_START_EVT:
        Serial.println("gatt server start event");       
        break; 
   case ESP_GATTS_STOP_EVT:
        Serial.println("gatt server stop event");       
        break;
   case ESP_GATTS_CONNECT_EVT:
        heart_rate_profile.gatts_if = gatts_if;
        heart_rate_profile.conn_id = param->connect.conn_id;
        heart_rate_profile.char_handle = param->add_char.attr_handle;
        bConnected = true;
        break;
   case ESP_GATTS_DISCONNECT_EVT:
        Serial.println("gatt server disconnect event");     
        heart_rate_profile.gatts_if = ESP_GATT_IF_NONE;
        bConnected = false;
        break;
   case ESP_GATTS_OPEN_EVT:
        Serial.println("gatt server open event");     
        break;
   case ESP_GATTS_CANCEL_OPEN_EVT:
        Serial.println("gatt server cancel open event");     
        break;
   case ESP_GATTS_CLOSE_EVT:
        Serial.println("gatt server close event");     
        break;
   case ESP_GATTS_LISTEN_EVT:
        Serial.println("gatt server listen event");     
        break;
   case ESP_GATTS_CONGEST_EVT:
        Serial.println("gatt server congest event?");     
        break;
   case ESP_GATTS_CREAT_ATTR_TAB_EVT:
        {
            if (param->add_attr_tab.status != ESP_GATT_OK){
                Serial.println("create attribute table failed");
            } else if (param->add_attr_tab.num_handle != HRS_IDX_NB){
                Serial.println("create attribute table abnormally");
            } else {
                Serial.println("gatt server create attribute tab successfully");     
                memcpy(heart_rate_handle_table, param->add_attr_tab.handles, sizeof(heart_rate_handle_table));
                esp_ble_gatts_start_service(heart_rate_handle_table[HRS_IDX_SVC]);
            }
        }
        break;
   default:
        break;
   }
}

static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if,  esp_ble_gatts_cb_param_t *param)
{
    /* If event is register event, store the gatts_if for each profile */
    if (event == ESP_GATTS_REG_EVT) {
        if (param->reg.status == ESP_GATT_OK) {
            Serial.println("gatt server register accepted");
            heart_rate_profile.gatts_if = gatts_if;
        } else {
            Serial.println("gatt server register app failed");
            return;
        }
    }
  
    do {
        int idx;
        if (gatts_if == ESP_GATT_IF_NONE || gatts_if == heart_rate_profile.gatts_if) {
            if (heart_rate_profile.gatts_cb) {
                heart_rate_profile.gatts_cb(event, gatts_if, param);
            }
        }
    } while (0);
}

void setup() {

    Serial.begin(115200);

    /* initialize advertising info */
    heart_rate_adv_params.adv_int_min = 0x20;
    heart_rate_adv_params.adv_int_max = 0x40;
    heart_rate_adv_params.adv_type = ADV_TYPE_IND;
    heart_rate_adv_params.own_addr_type = BLE_ADDR_TYPE_PUBLIC;
    heart_rate_adv_params.channel_map = ADV_CHNL_ALL;
    heart_rate_adv_params.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY;
   
    esp_err_t ret;

    btStart();

    Serial.println("Init bluetooth");
    ret = esp_bluedroid_init();
    if (ret) {
        Serial.println("esp_bluedroid_init failed");
        return;
    }
    ret = esp_bluedroid_enable();
    if (ret) {
        Serial.println("esp_bluedroid_enable failed");
        return;
    }

    esp_ble_gatts_register_callback(gatts_event_handler);
    esp_ble_gap_register_callback(gap_event_handler);
    esp_ble_gatts_app_register(ESP_HEART_RATE_APP_ID);
}

void loop() {
  if (bConnected) {
      ble_indicate();
  } 
  delay(1000);
}



LAPIS Semicondocutor の BLE TOOL で Android スマホから接続してみたら、HRM として認識させることに成功しました!やった。


Screenshot_2017-11-19-00-14-12.png


でも、値を受け取ることはできませんでした。NOTIFY をうまく伝えることができていないようです。あと一息なんだけどなぁ。 orz...


Screenshot_2017-11-19-00-14-48.png


こちらがログになります。

Init bluetooth
gatt server register accepted
gatt server register event
gatt server create attribute tab successfully
gap start advertising....
gatt server start event
gap advertising success
90
85
71
gatt server write event
69
10
97
32
91
62
19
gatt server write event
78
47
83
gatt server disconnect event


どうも Attribute の handle 値が正しく設定されていないようなのですが、どう値を持ってくればよいのかよく分かりません。ESP32 の BLE 関連の情報がほとんどなくしばらく苦戦しそうです。うーむ。
(。-`ω´-)





waves ESP32-DevKitC ESP-WROOM-32 ESP32 DevKitC V2 WiFi BLE 技適取得済 国内発送

waves ESP32-DevKitC ESP-WROOM-32 ESP32 DevKitC V2 WiFi BLE 技適取得済 国内発送

  • 出版社/メーカー: waves(ウェイブス)
  • メディア: エレクトロニクス



waves ESP32 ESP-WROOM-32 WiFi/Bluetoothモジュール(技適取得済み) ブレイクアウトボード付属

waves ESP32 ESP-WROOM-32 WiFi/Bluetoothモジュール(技適取得済み) ブレイクアウトボード付属

  • 出版社/メーカー: waves(ウェイブス)
  • メディア: おもちゃ&ホビー



SparkFun ESP32 Thing Development Workshop (English Edition)

SparkFun ESP32 Thing Development Workshop (English Edition)

  • 出版社/メーカー: PE Press
  • 発売日: 2017/04/09
  • メディア: Kindle版




タグ:Arduino BLE ESP32
nice!(25)  コメント(2) 
共通テーマ:趣味・カルチャー

ESP32 の BLEデバイス化にチャレンジ!(2) [Arduino]

ESP32をGATTデバイス化しようにも、すっかりBLEの仕様も忘れてしまっているし、ESP32のESP-IDFと言われるSDKもよく分からないし、しかも調べる時間ないし…


DSC04860.JPG


なにかよい資料がないかなとあら探しをしていたら、ESP32 による Heart Rate Profile のサンプルを見つけました!


esp-idf/examples/bluetooth/gatt_server_service_table/main/gatts_table_creat_demo.c


Heart Rate Profile なら mbed HRM1017 を使った開発経験があります。


mbed HRM1017 で Heart Rate Profile をサポートしてみる
http://makers-with-myson.blog.so-net.ne.jp/archive/c2306056631-1


これをヒントに、ESP32のBLEの使い方を習熟していきたいと思います。とりあえずダメもとで ESP-IDF のコードを Arduino のスケッチに移植してしみました。


#pragma GCC diagnostic push
#pragma GCC diagnostic warning "-fpermissive"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "bt.h"
#include "bta_api.h"

#include "esp_gap_ble_api.h"
#include "esp_gatts_api.h"
#include "esp_bt_defs.h"
#include "esp_bt_main.h"
#include "esp_bt_main.h"

#define HRPS_HT_MEAS_MAX_LEN            (13)

#define HRPS_MANDATORY_MASK             (0x0F)
#define HRPS_BODY_SENSOR_LOC_MASK       (0x30)
#define HRPS_HR_CTNL_PT_MASK            (0xC0)


///Attributes State Machine
enum {
    HRS_IDX_SVC,

    HRS_IDX_HR_MEAS_CHAR,
    HRS_IDX_HR_MEAS_VAL,
    HRS_IDX_HR_MEAS_NTF_CFG,

    HRS_IDX_BOBY_SENSOR_LOC_CHAR,
    HRS_IDX_BOBY_SENSOR_LOC_VAL,

    HRS_IDX_HR_CTNL_PT_CHAR,
    HRS_IDX_HR_CTNL_PT_VAL,

    HRS_IDX_NB,
};


#define GATTS_TABLE_TAG "GATTS_TABLE_DEMO"

#define HEART_PROFILE_NUM  1
#define HEART_PROFILE_APP_IDX   0
#define ESP_HEART_RATE_APP_ID  0x55
#define SAMPLE_DEVICE_NAME     "ESP_HEART_RATE"
#define SAMPLE_MANUFACTURER_DATA_LEN  17
#define HEART_RATE_SVC_INST_ID   0

#define GATTS_DEMO_CHAR_VAL_LEN_MAX   0x40

uint8_t char1_str[] ={0x11,0x22,0x33};

uint16_t heart_rate_handle_table[HRS_IDX_NB];

esp_attr_value_t gatts_demo_char1_val = 
{
  .attr_max_len = GATTS_DEMO_CHAR_VAL_LEN_MAX,
  .attr_len   = sizeof(char1_str),
  .attr_value     = char1_str,
};


static uint8_t heart_rate_service_uuid[16] = {
    /* LSB <--------------------------------------------------------------------------------> MSB */
    //first uuid, 16bit, [12],[13] is the value
    0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x18, 0x0D, 0x00, 0x00,
};


static esp_ble_adv_data_t heart_rate_adv_config = {
    .set_scan_rsp = false,
    .include_name = true,
    .include_txpower = true,
    .min_interval = 0x20,
    .max_interval = 0x40,
    .appearance = 0x00,
    .manufacturer_len = 0, //TEST_MANUFACTURER_DATA_LEN,
    .p_manufacturer_data =  NULL, //&test_manufacturer[0],
    .service_data_len = 0,
    .p_service_data = NULL,
    .service_uuid_len = sizeof(heart_rate_service_uuid),
    .p_service_uuid = heart_rate_service_uuid,
    .flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT),
};

static esp_ble_adv_params_t heart_rate_adv_params; 

struct gatts_profile_inst {
    esp_gatts_cb_t gatts_cb;
    uint16_t gatts_if;
    uint16_t app_id;
    uint16_t conn_id;
    uint16_t service_handle;
    esp_gatt_srvc_id_t service_id;
    uint16_t char_handle;
    esp_bt_uuid_t char_uuid;
    esp_gatt_perm_t perm;
    esp_gatt_char_prop_t property;
    uint16_t descr_handle;
    esp_bt_uuid_t descr_uuid;
};

static void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param);

/* One gatt-based profile one app_id and one gatts_if, this array will store the gatts_if returned by ESP_GATTS_REG_EVT */
static struct gatts_profile_inst heart_rate_profile_tab[HEART_PROFILE_NUM] = {
    [HEART_PROFILE_APP_IDX] = {
        .gatts_cb = gatts_profile_event_handler,
        .gatts_if = ESP_GATT_IF_NONE,       /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */
    },
    
};

/*
 * HTPT PROFILE ATTRIBUTES
 ****************************************************************************************
 */


/*
 *  Heart Rate PROFILE ATTRIBUTES
 ****************************************************************************************
 */

/// Heart Rate Sensor Service
static const uint16_t heart_rate_svc = ESP_GATT_UUID_HEART_RATE_SVC;

#define CHAR_DECLARATION_SIZE   (sizeof(uint8_t))
static const uint16_t primary_service_uuid = ESP_GATT_UUID_PRI_SERVICE;
static const uint16_t character_declaration_uuid = ESP_GATT_UUID_CHAR_DECLARE;
static const uint16_t character_client_config_uuid = ESP_GATT_UUID_CHAR_CLIENT_CONFIG;
static const uint8_t char_prop_notify = ESP_GATT_CHAR_PROP_BIT_NOTIFY;
static const uint8_t char_prop_read = ESP_GATT_CHAR_PROP_BIT_READ;
static const uint8_t char_prop_read_write = ESP_GATT_CHAR_PROP_BIT_WRITE|ESP_GATT_CHAR_PROP_BIT_READ;

/// Heart Rate Sensor Service - Heart Rate Measurement Characteristic, notify
static const uint16_t heart_rate_meas_uuid = ESP_GATT_HEART_RATE_MEAS;
static const uint8_t heart_measurement_ccc[2] ={ 0x00, 0x00};


/// Heart Rate Sensor Service -Body Sensor Location characteristic, read
static const uint16_t body_sensor_location_uuid = ESP_GATT_BODY_SENSOR_LOCATION;
static const uint8_t body_sensor_loc_val[1] = {0x00};


/// Heart Rate Sensor Service - Heart Rate Control Point characteristic, write&read
static const uint16_t heart_rate_ctrl_point = ESP_GATT_HEART_RATE_CNTL_POINT;
static const uint8_t heart_ctrl_point[1] = {0x00};

/// Full HRS Database Description - Used to add attributes into the database
static const esp_gatts_attr_db_t heart_rate_gatt_db[HRS_IDX_NB] =
{
    // Heart Rate Service Declaration
    [HRS_IDX_SVC]                       =  
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&primary_service_uuid, ESP_GATT_PERM_READ,
      sizeof(uint16_t), sizeof(heart_rate_svc), (uint8_t *)&heart_rate_svc}},

    // Heart Rate Measurement Characteristic Declaration
    [HRS_IDX_HR_MEAS_CHAR]            = 
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ,
      CHAR_DECLARATION_SIZE,CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_notify}},
      
    // Heart Rate Measurement Characteristic Value
    [HRS_IDX_HR_MEAS_VAL]               =   
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&heart_rate_meas_uuid, ESP_GATT_PERM_READ,
      HRPS_HT_MEAS_MAX_LEN,0, NULL}},

    // Heart Rate Measurement Characteristic - Client Characteristic Configuration Descriptor
    [HRS_IDX_HR_MEAS_NTF_CFG]       =    
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_client_config_uuid, ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE,
      sizeof(uint16_t),sizeof(heart_measurement_ccc), (uint8_t *)heart_measurement_ccc}},

    // Body Sensor Location Characteristic Declaration
    [HRS_IDX_BOBY_SENSOR_LOC_CHAR]  = 
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ,
      CHAR_DECLARATION_SIZE,CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_read}},

    // Body Sensor Location Characteristic Value
    [HRS_IDX_BOBY_SENSOR_LOC_VAL]   = 
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&body_sensor_location_uuid, ESP_GATT_PERM_READ,
      sizeof(uint8_t), sizeof(body_sensor_loc_val), (uint8_t *)body_sensor_loc_val}},

    // Heart Rate Control Point Characteristic Declaration
    [HRS_IDX_HR_CTNL_PT_CHAR]          = 
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ,
      CHAR_DECLARATION_SIZE,CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_read_write}},
                                              
    // Heart Rate Control Point Characteristic Value
    [HRS_IDX_HR_CTNL_PT_VAL]             = 
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&heart_rate_ctrl_point, ESP_GATT_PERM_WRITE|ESP_GATT_PERM_READ,
      sizeof(uint8_t), sizeof(heart_ctrl_point), (uint8_t *)heart_ctrl_point}},  
};



static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
    Serial.println("gap_event_handler");

    switch (event) {
    case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT:
        Serial.println(" ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT");
        esp_ble_gap_start_advertising(&heart_rate_adv_params);
        break;
    case ESP_GAP_BLE_ADV_START_COMPLETE_EVT:
        //advertising start complete event to indicate advertising start successfully or failed
        Serial.println(" ESP_GAP_BLE_ADV_START_COMPLETE_EVT");
        if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) {
            Serial.println("Advertising start failed");
        }
        break;
    default:
        break;
    }
}

static void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) 
{
    Serial.println("gatts_profile_event_handler:");
    switch (event) {
    case ESP_GATTS_REG_EVT:
        Serial.println(" ESP_GATTS_REG_EVT");
        esp_ble_gap_set_device_name(SAMPLE_DEVICE_NAME);
        esp_ble_gap_config_adv_data(&heart_rate_adv_config);
        esp_ble_gatts_create_attr_tab(heart_rate_gatt_db, gatts_if, HRS_IDX_NB, HEART_RATE_SVC_INST_ID);
        break;
    case ESP_GATTS_READ_EVT: 
        Serial.println(" ESP_GATTS_READ_EVT");
        char hrp1 = 0x1E; // dummy data
        char hrp2 = 0x00; // dummy data
        esp_gatt_rsp_t rsp;
        memset(&rsp, 0, sizeof(esp_gatt_rsp_t));
        rsp.attr_value.handle = param->read.handle;
        rsp.attr_value.len = 2;
        rsp.attr_value.value[0] = hrp1;
        rsp.attr_value.value[1] = hrp2;
        esp_ble_gatts_send_response(gatts_if, param->read.conn_id, param->read.trans_id, ESP_GATT_OK, &rsp);
        break;
    case ESP_GATTS_WRITE_EVT: 
        Serial.println(" ESP_GATTS_WRITE_EVT");       
        break;
    case ESP_GATTS_EXEC_WRITE_EVT:
        Serial.println(" ESP_GATTS_EXEC_WRITE_EVT");       
        break;
    case ESP_GATTS_MTU_EVT:
        Serial.println(" ESP_GATTS_MTU_EVT");       
         break;
   case ESP_GATTS_CONF_EVT:
        Serial.println(" ESP_GATTS_CONF_EVT");       
        break;
   case ESP_GATTS_UNREG_EVT:
        Serial.println(" ESP_GATTS_UREG_EVT");       
        break;
   case ESP_GATTS_DELETE_EVT:
        Serial.println(" ESP_GATTS_DELETE_EVT");       
        break;
   case ESP_GATTS_START_EVT:
        Serial.println(" ESP_GATTS_START_EVT");       
        break; 
   case ESP_GATTS_STOP_EVT:
        Serial.println(" ESP_GATTS_STOP_EVT");       
        break;
   case ESP_GATTS_CONNECT_EVT:
        Serial.println(" ESP_GATTS_CONNECT_EVT");       
        break;
   case ESP_GATTS_DISCONNECT_EVT:
        Serial.println(" ESP_GATTS_DISCONNECT_EVT");       
        break;
   case ESP_GATTS_OPEN_EVT:
        Serial.println(" ESP_GATTS_OPEN_EVT");       
        break;
   case ESP_GATTS_CANCEL_OPEN_EVT:
        Serial.println(" ESP_GATTS_CANCEL_OPEN_EVT");       
        break;
   case ESP_GATTS_CLOSE_EVT:
        Serial.println(" ESP_GATTS_CLOSE_EVT");       
        break;
   case ESP_GATTS_LISTEN_EVT:
        Serial.println(" ESP_GATTS_LISTEN_EVT");       
        break;
   case ESP_GATTS_CONGEST_EVT:
        Serial.println(" ESP_GATTS_CONGEST_EVT");       
        break;
   case ESP_GATTS_CREAT_ATTR_TAB_EVT:{
            Serial.println("ESP_GATTS_CREAT_ATTR_TAB_EVT");
            if (param->add_attr_tab.status != ESP_GATT_OK){
                Serial.println("Create attribute table failed");
            } else if (param->add_attr_tab.num_handle != HRS_IDX_NB){
                Serial.println("Create attribute table abnormally");
            } else {
                memcpy(heart_rate_handle_table, param->add_attr_tab.handles, sizeof(heart_rate_handle_table));
                esp_ble_gatts_start_service(heart_rate_handle_table[HRS_IDX_SVC]);
            }
        }
        break;
   default:
        break;
   }
}


static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if,  esp_ble_gatts_cb_param_t *param)
{
    Serial.println("gatts_event_handler:");

    /* If event is register event, store the gatts_if for each profile */
    if (event == ESP_GATTS_REG_EVT) {
        if (param->reg.status == ESP_GATT_OK) {
            Serial.println("  Reg app success");
            heart_rate_profile_tab[HEART_PROFILE_APP_IDX].gatts_if = gatts_if;
        } else {
            Serial.println("  Reg app failed");
            return;
        }
    }
  
    do {
        int idx;
        for (idx = 0; idx < HEART_PROFILE_NUM; idx++) {
            if (gatts_if == ESP_GATT_IF_NONE || /* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function */
                    gatts_if == heart_rate_profile_tab[idx].gatts_if) {
                if (heart_rate_profile_tab[idx].gatts_cb) {
                    heart_rate_profile_tab[idx].gatts_cb(event, gatts_if, param);
                }
            }
        }
    } while (0);
}



void setup() {

    Serial.begin(115200);
    /* initialize advertising info */
    heart_rate_adv_params.adv_int_min = 0x20;
    heart_rate_adv_params.adv_int_max = 0x40;
    heart_rate_adv_params.adv_type = ADV_TYPE_IND;
    heart_rate_adv_params.own_addr_type = BLE_ADDR_TYPE_PUBLIC;
    heart_rate_adv_params.channel_map = ADV_CHNL_ALL;
    heart_rate_adv_params.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY;
    
    esp_err_t ret;
    esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
    ret = esp_bt_controller_init(&bt_cfg);
    if (ret) {
        Serial.println("esp_bt_controller_init failed");
        return;
    }

    ret = esp_bt_controller_enable(ESP_BT_MODE_BTDM);
    if (ret) {
        Serial.println("esp_bt_controller_enable enable controller");
        return;
    }

    Serial.println("Init bluetooth");
    ret = esp_bluedroid_init();
    if (ret) {
        Serial.println("esp_bluedroid_init failed");
        return;
    }
    ret = esp_bluedroid_enable();
    if (ret) {
        Serial.println("esp_bluedroid_enable failed");
        return;
    }

    esp_ble_gatts_register_callback(gatts_event_handler);
    esp_ble_gap_register_callback(gap_event_handler);
    esp_ble_gatts_app_register(ESP_HEART_RATE_APP_ID);
}

void loop() {
  // put your main code here, to run repeatedly:

}



何も考えずに移植したコードなので、うまく動かないだろうなぁと思いつつ試してみました。

Init bluetooth
gatts_event_handler:
  Reg app success
gatts_profile_event_handler:
 ESP_GATTS_REG_EVT
gatts_event_handler:
gatts_profile_event_handler:
gap_event_handler
 ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT
gap_event_handler
 ESP_GAP_BLE_ADV_START_COMPLETE_EVT
gatts_event_handler:
gatts_profile_event_handler:
gap_event_handler



とりあえずログは出ましたがそれらしい動きは一切なし。やっぱダメですね。ぼちぼち調べていくかぁ。
(´・ω・`)





waves ESP32-DevKitC ESP-WROOM-32 ESP32 DevKitC V2 WiFi BLE 技適取得済 国内発送

waves ESP32-DevKitC ESP-WROOM-32 ESP32 DevKitC V2 WiFi BLE 技適取得済 国内発送

  • 出版社/メーカー: waves(ウェイブス)
  • メディア: エレクトロニクス



SparkFun ESP32 Thing Development Workshop (English Edition)

SparkFun ESP32 Thing Development Workshop (English Edition)

  • 出版社/メーカー: PE Press
  • 発売日: 2017/04/09
  • メディア: Kindle版



MicroPython for ESP32 Development Workshop (English Edition)

MicroPython for ESP32 Development Workshop (English Edition)

  • 出版社/メーカー:
  • 発売日: 2017/08/19
  • メディア: Kindle版




タグ:Arduino GATT BLE ESP32
nice!(26)  コメント(2) 
共通テーマ:趣味・カルチャー

ESP32 の BLEデバイス化にチャレンジ!(1) [Arduino]

ESP32 をスマホからBLEデバイスにするために試行錯誤をしています。コードを解析すればうまくいくかなと思ったのですが、なかなかうまくいかない。


DSC04856.JPG


BLEデバイスの中でも一番簡単なTHERMOMETER デバイスなら簡単にいくだろうと思い、 スケッチ化してみることにしました。参考にしたサイトはこちら。


Development of ESP-WROOM-32
https://github.com/mitazet/esp/blob/master/thermometer/main/gatts_thermometer.c


改造した Arduino のスケッチ?(ほぼCのプログラムですが)がこちらです。デバッグコードが入っていて、少し見苦しいですが我慢ください。


#pragma GCC diagnostic push
#pragma GCC diagnostic warning "-fpermissive"

#include 
#include 
#include 
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "bt.h"
#include "bta_api.h"

#include "esp_gap_ble_api.h"
#include "esp_gatts_api.h"
#include "esp_bt_defs.h"
#include "esp_bt_main.h"
#include "esp_bt_main.h"

#include "sdkconfig.h"

#define GATTS_TAG "GATTS_THERMO"

static void gatts_profile_thermo_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param);

#define GATTS_SERVICE_UUID_THERMOMETER 0x00FF
#define GATTS_CHAR_UUID_THERMOMETER 0xFF01

#define GATTS_DESCR_UUID_THERMOMETER 0x3333
#define GATTS_NUM_HANDLE_THERMOMETER 4

#define TEST_DEVICE_NAME "ESP_THERMOMETER"


#define GATTS_DEMO_CHAR_VAL_LEN_MAX 0x40

#define PREPARE_BUF_MAX_SIZE 1024

#define PROFILE_NUM 1
#define PROFILE_THERMOMETER_ID 0

uint8_t char1_str[] = {0x11,0x22,0x33};
esp_attr_value_t gatts_demo_char1_val =
{
    .attr_max_len = GATTS_DEMO_CHAR_VAL_LEN_MAX,
    .attr_len = sizeof(char1_str),
    .attr_value = char1_str,
};

static uint8_t service_uuid128[32] = {
    /* LSB <--------------------------------------------------------------------------------> MSB */
    //first uuid, 16bit, [12],[13] is the value
    0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xAB, 0xCD, 0x00, 0x00,
    //second uuid, 32bit, [12], [13], [14], [15] is the value
    0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xAB, 0xCD, 0xAB, 0xCD,
};

static esp_ble_adv_data_t test_adv_data = {
    .set_scan_rsp = false,
    .include_name = true,
    .include_txpower = true,
    .min_interval = 0x20,
    .max_interval = 0x40,
    .appearance = 0x00,
    .manufacturer_len = 0,
    .p_manufacturer_data = NULL,
    .service_data_len = 0,
    .p_service_data = NULL,
    .service_uuid_len = 32,
    .p_service_uuid = service_uuid128,
    .flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT),
};

static esp_ble_adv_params_t test_adv_params;

struct gatts_profile_inst {
    esp_gatts_cb_t gatts_cb;
    uint16_t gatts_if;
    uint16_t app_id;
    uint16_t conn_id;
    uint16_t service_handle;
    esp_gatt_srvc_id_t service_id;
    esp_bt_uuid_t char_uuid;
    esp_bt_uuid_t descr_uuid;
    uint16_t char_handle;
    esp_gatt_perm_t perm;
    esp_gatt_char_prop_t property;
    uint16_t descr_handle;
};

static struct gatts_profile_inst test_profile;

typedef struct {
    uint8_t *prepare_buf;
    int prepare_len;
} prepare_type_env_t;

static prepare_type_env_t a_prepare_write_env;

void example_write_event_env(esp_gatt_if_t gatts_if, prepare_type_env_t *prepare_write_env, esp_ble_gatts_cb_param_t *param);
void example_exec_write_event_env(prepare_type_env_t *prepare_write_env, esp_ble_gatts_cb_param_t *param);

static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
    Serial.println("gap_event_handler");

    switch (event) {
    case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT:
        Serial.println("ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT");
        esp_ble_gap_start_advertising(&test_adv_params);
        break;
        
    case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT:
        Serial.println("ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT");
        esp_ble_gap_start_advertising(&test_adv_params);
        break;
        
    case ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT:
        Serial.println("ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT");
        esp_ble_gap_start_advertising(&test_adv_params);
        break;
        
    case ESP_GAP_BLE_ADV_START_COMPLETE_EVT:
        Serial.println("ESP_GAP_BLE_ADV_START_COMPLETE_EVT");
        if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) {
            Serial.println("Advertising start failed\n");
        }
        break;
    case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT:
        Serial.println("ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT");
        if (param->adv_stop_cmpl.status != ESP_BT_STATUS_SUCCESS) {
            Serial.println("Advertising stop failed\n");
        }
        else {
            Serial.println("Stop adv successfully\n");
        }
        break;
    case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT:
        Serial.println("ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT");
        break;
    default:
        break;
    }
}

void example_write_event_env(esp_gatt_if_t gatts_if, prepare_type_env_t *prepare_write_env, esp_ble_gatts_cb_param_t *param){
    
    Serial.println("example_write_event_env");
    
    esp_gatt_status_t status = ESP_GATT_OK;

    if (param->write.need_rsp){
        if (param->write.is_prep){
            if (prepare_write_env->prepare_buf == NULL) {
                prepare_write_env->prepare_buf = (uint8_t*)malloc(PREPARE_BUF_MAX_SIZE*sizeof(uint8_t));
                prepare_write_env->prepare_len = 0;
            } else {
                if(param->write.offset > PREPARE_BUF_MAX_SIZE) {
                    status = ESP_GATT_INVALID_OFFSET;
                } else if ((param->write.offset + param->write.len) > PREPARE_BUF_MAX_SIZE) {
                    status = ESP_GATT_INVALID_ATTR_LEN;
                }
            }
            esp_gatt_rsp_t *gatt_rsp = (esp_gatt_rsp_t*)malloc(sizeof(esp_gatt_rsp_t));
            gatt_rsp->attr_value.len = param->write.len;
            gatt_rsp->attr_value.handle = param->write.handle;
            gatt_rsp->attr_value.offset = param->write.offset;
            gatt_rsp->attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE;
            memcpy(gatt_rsp->attr_value.value, param->write.value, param->write.len);
            esp_err_t response_err = esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, status, gatt_rsp);
            free(gatt_rsp);
            if (status != ESP_GATT_OK) {
                return;
            }
            memcpy(prepare_write_env->prepare_buf + param->write.offset, param->write.value, param->write.len);
            prepare_write_env->prepare_len += param->write.len;
        }else{
            esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, status, NULL);
        }
    }
}

void example_exec_write_event_env(prepare_type_env_t *prepare_write_env, esp_ble_gatts_cb_param_t *param){ 
    
    Serial.println("example_exec_write_event_env");
    
    if (param->exec_write.exec_write_flag == ESP_GATT_PREP_WRITE_EXEC){
        esp_log_buffer_hex(GATTS_TAG, prepare_write_env->prepare_buf, prepare_write_env->prepare_len);
    }
    
    if (prepare_write_env->prepare_buf) {
        free(prepare_write_env->prepare_buf);
        prepare_write_env->prepare_buf = NULL;
    }
    
    prepare_write_env->prepare_len = 0;
}

static void gatts_profile_thermo_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) {
  
    switch (event) {
    case ESP_GATTS_REG_EVT:
        Serial.println("ESP_GATTS_REG_EVT");    
        test_profile.service_id.is_primary = true;
        test_profile.service_id.id.inst_id = 0x00;
        test_profile.service_id.id.uuid.len = ESP_UUID_LEN_16;
        test_profile.service_id.id.uuid.uuid.uuid16 = GATTS_SERVICE_UUID_THERMOMETER;
        esp_ble_gap_set_device_name(TEST_DEVICE_NAME);
        esp_ble_gap_config_adv_data(&test_adv_data);
        esp_ble_gatts_create_service(gatts_if, &test_profile.service_id, GATTS_NUM_HANDLE_THERMOMETER);
        break;
        
    case ESP_GATTS_READ_EVT: {
        Serial.println("ESP_GATTS_READ_EVT");
        char temp1 = 0x1E; // dummy data
        char temp2 = 0x00; // dummy data
        esp_gatt_rsp_t rsp;
        memset(&rsp, 0, sizeof(esp_gatt_rsp_t));
        rsp.attr_value.handle = param->read.handle;
        rsp.attr_value.len = 2;
        rsp.attr_value.value[0] = temp1;
        rsp.attr_value.value[1] = temp2;
        esp_ble_gatts_send_response(gatts_if, param->read.conn_id, param->read.trans_id, ESP_GATT_OK, &rsp);
        break;
    }
    case ESP_GATTS_WRITE_EVT: {
        Serial.println("ESP_GATTS_WRITE_EVT");
        example_write_event_env(gatts_if, &a_prepare_write_env, param);
        break;
    }
    case ESP_GATTS_EXEC_WRITE_EVT:
        Serial.println("ESP_GATTS_EXEC_EVT");
        esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, NULL);
        example_exec_write_event_env(&a_prepare_write_env, param);
        break;
        
    case ESP_GATTS_MTU_EVT:
        Serial.println("ESP_GATTS_MTU_EVT");
        break;
        
    case ESP_GATTS_CONF_EVT:
        Serial.println("ESP_GATTS_CONF_EVT");
        break;
        
    case ESP_GATTS_UNREG_EVT:
        Serial.println("ESP_GATTS_UNREG_EVT");
        break;
        
    case ESP_GATTS_CREATE_EVT:
        Serial.println("ESP_GATTS_CREATE_EVT");
        test_profile.service_handle = param->create.service_handle;
        test_profile.char_uuid.len = ESP_UUID_LEN_16;
        test_profile.char_uuid.uuid.uuid16 = GATTS_CHAR_UUID_THERMOMETER;
        
        esp_ble_gatts_start_service(test_profile.service_handle);
        esp_ble_gatts_add_char(test_profile.service_handle, &test_profile.char_uuid, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_NOTIFY, &gatts_demo_char1_val, NULL);
        break;
        
    case ESP_GATTS_ADD_INCL_SRVC_EVT:
        Serial.println("ESP_GATTS_ADD_INCL_SRVC_EVT");
        break;

    case ESP_GATTS_ADD_CHAR_EVT: {
        uint16_t length = 0;
        const uint8_t *prf_char;
        
        Serial.println("ESP_GATTS_ADD_CHAR_EVT");
        
        test_profile.char_handle = param->add_char.attr_handle;
        test_profile.descr_uuid.len = ESP_UUID_LEN_16;
        test_profile.descr_uuid.uuid.uuid16 = ESP_GATT_UUID_CHAR_CLIENT_CONFIG;
        
        esp_ble_gatts_get_attr_value(param->add_char.attr_handle, &length, &prf_char);
        esp_ble_gatts_add_char_descr(test_profile.service_handle, &test_profile.descr_uuid, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, NULL, NULL);
        break;
    }

    case ESP_GATTS_ADD_CHAR_DESCR_EVT:
        Serial.println("ESP_GATTS_ADD_CHAR_DESCR_EVT");
        break;
        
    case ESP_GATTS_DELETE_EVT:
        Serial.println("ESP_GATTS_DELETE_EVT");
        break;
        
    case ESP_GATTS_START_EVT:
        Serial.println("ESP_GATTS_START_EVT");
        break;
        
    case ESP_GATTS_STOP_EVT:
        Serial.println("ESP_GATTS_STOP_EVT");
        break;
        
    case ESP_GATTS_CONNECT_EVT: {
        Serial.println("ESP_GATTS_CONNECT_EVT");
        
        esp_ble_conn_update_params_t conn_params = {0};
        memcpy(conn_params.bda, param->connect.remote_bda, sizeof(esp_bd_addr_t));
        
        /* For the IOS system, please reference the apple official documents about the ble connection parameters restrictions. */
        conn_params.latency = 0;
        conn_params.max_int = 0x50; // max_int = 0x50*1.25ms = 100ms
        conn_params.min_int = 0x30; // min_int = 0x30*1.25ms = 60ms
        conn_params.timeout =  400; // timeout = 400*10ms = 4000ms
        test_profile.conn_id = param->connect.conn_id;
        
        //start sent the update connection parameters to the peer device.
        esp_ble_gap_update_conn_params(&conn_params);
        break;
    }
    case ESP_GATTS_DISCONNECT_EVT:
        Serial.println("ESP_GATTS_DISCONNECT_EVT");
        esp_ble_gap_start_advertising(&test_adv_params);
        break;
        
    case ESP_GATTS_OPEN_EVT:
        Serial.println("ESP_GATTS_OPEN_EVT");
        break;

    case ESP_GATTS_CANCEL_OPEN_EVT:
        Serial.println("ESP_GATTS_CANCEL_OPEN_EVT");
        break;

    case ESP_GATTS_CLOSE_EVT:
        Serial.println("ESP_GATTS_CLOSE_EVT");
        break;

    case ESP_GATTS_LISTEN_EVT:
        Serial.println("ESP_GATTS_LISTEN_EVT");
        break;

    case ESP_GATTS_CONGEST_EVT:
        Serial.println("ESP_GATTS_CONGEST_EVT");
        break;

    default:
        break;
    }
}

static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
{
    Serial.println("gatts_event_handler");

    /* If event is register event, store the gatts_if for each profile */
    if (event == ESP_GATTS_REG_EVT) {
        if (param->reg.status == ESP_GATT_OK) {
            test_profile.gatts_if = gatts_if;
        } else {
            return;
        }
    }

    if (gatts_if == ESP_GATT_IF_NONE || gatts_if == test_profile.gatts_if) {
        if (test_profile.gatts_cb) {
            test_profile.gatts_cb(event, gatts_if, param);
        }
    }
}

void setup() {

    Serial.begin(115200);

    /* initialize advertising info */
    test_adv_params.adv_int_min       = 0x20;
    test_adv_params.adv_int_max      = 0x40;
    test_adv_params.adv_type            = ADV_TYPE_IND;
    test_adv_params.own_addr_type  = BLE_ADDR_TYPE_PUBLIC;
    test_adv_params.channel_map     = ADV_CHNL_ALL;
    test_adv_params.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY;

    /* initialize profile and characteristic */
    test_profile.gatts_cb = gatts_profile_thermo_event_handler;
    test_profile.gatts_if = ESP_GATT_IF_NONE; 

    esp_err_t ret;
    
    btStart();
    ret = esp_bluedroid_init();
    if (ret) {
        Serial.println("Init bluetooth failed");
        return;
    }
    ret = esp_bluedroid_enable();
    if (ret) {
        Serial.println("Enable bluetooth failed");
        return;
    }

    esp_ble_gatts_register_callback(gatts_event_handler);
    esp_ble_gap_register_callback(gap_event_handler);
    esp_ble_gatts_app_register(PROFILE_THERMOMETER_ID);

    Serial.println("Bluetooth setup success!");
}

void loop() {
}



LAPIS Computer から出しているスマホアプリの BLE Tools を起動してみると、ESP32_THERMOMETER が見えました!


ESP32_THERMO_1.png


しかし、値は取れず…残念。


ESP32_THERMO_2.png


シリアルモニターを確認すると、CONNECTまでは成功していますが、その後にREADのイベントが発生していません。

Bluetooth setup success!
gatts_event_handler
ESP_GATTS_REG_EVT
gap_event_handler
ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT
gatts_event_handler
ESP_GATTS_CREATE_EVT
gap_event_handler
ESP_GAP_BLE_ADV_START_COMPLETE_EVT
gatts_event_handler
ESP_GATTS_START_EVT
gatts_event_handler
ESP_GATTS_ADD_CHAR_EVT
gatts_event_handler
ESP_GATTS_ADD_CHAR_DESCR_EVT
gatts_event_handler
ESP_GATTS_CONNECT_EVT
gap_event_handler
ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT
gatts_event_handler



うーん、何が原因なのか。そもそもシーケンスが間違っているのか。。。もう少し追いかけてみたいところですが、最近は忙しくて時間がとれないんだよなぁ。
(;´д`)トホホ





waves ESP32-DevKitC ESP-WROOM-32 ESP32 DevKitC V2 WiFi BLE 技適取得済 国内発送

waves ESP32-DevKitC ESP-WROOM-32 ESP32 DevKitC V2 WiFi BLE 技適取得済 国内発送

  • 出版社/メーカー: waves(ウェイブス)
  • メディア: エレクトロニクス



SparkFun ESP32 Thing Development Workshop (English Edition)

SparkFun ESP32 Thing Development Workshop (English Edition)

  • 出版社/メーカー: PE Press
  • 発売日: 2017/04/09
  • メディア: Kindle版



MicroPython for ESP32 Development Workshop (English Edition)

MicroPython for ESP32 Development Workshop (English Edition)

  • 出版社/メーカー:
  • 発売日: 2017/08/19
  • メディア: Kindle版




タグ:Arduino BLE ESP32
nice!(28)  コメント(0) 
共通テーマ:趣味・カルチャー

ESP32 を Gatt デバイスにしようとするも早くも心が挫けそう。 [Arduino]

ESP32 を BLE デバイスとして使うなら Gatt に準拠したデバイスとして使いたいところ。


DSC04860.JPG


少し調べてみると、Espressif の SDK を使えば Gatt Client にも Gatt Server としても使えそうなのですが、いかんせん面倒。楽して使いたい。

Arduinoで簡単に使えるものがないかなと調べてみたもののやっと見つけたのがこれ。


How to use Arduino ESP32 BLE as a GATT server
http://www.iotsharing.com/2017/07/how-to-use-ble-in-arduino-esp32.html


ちょっと面倒すぎでしょ。毎回こんなにコード書いてらんないし...。簡単に使えるようにならないか、コードとにらめっこしながら考えてみたいと思います。
(ーω ー;





waves ESP32-DevKitC ESP-WROOM-32 ESP32 DevKitC V2 WiFi BLE 技適取得済 国内発送

waves ESP32-DevKitC ESP-WROOM-32 ESP32 DevKitC V2 WiFi BLE 技適取得済 国内発送

  • 出版社/メーカー: waves(ウェイブス)
  • メディア: エレクトロニクス



Bluetooth Low Energyをはじめよう (Make:PROJECTS)

Bluetooth Low Energyをはじめよう (Make:PROJECTS)

  • 作者: Kevin Townsend
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2015/02/25
  • メディア: 単行本(ソフトカバー)



RN4020搭載、簡単Bluetooth LE スティック

RN4020搭載、簡単Bluetooth LE スティック

  • 出版社/メーカー: マイクロテクニカ
  • メディア: おもちゃ&ホビー




タグ:Arduino GATT BLE ESP32
nice!(27)  コメント(2) 
共通テーマ:趣味・カルチャー

ESP32 で Simple BLE Device を試してみる [Arduino]

ESP32 には、Wi-Fi の他に BLE もついています。サンプルコードに Simple BLE Device というものがあったので、試して見ることにしました。


DSC04860.JPG


スケッチにはボタンをつけろと出ていたので、2番ピンにボタンを追加しました。


simplebledevice.png


スケッチも2番ピンに変更します。こちらがスケッチです。ボタンを押すとクロックから取得した値を割った数をデバイス名”BLE name: ”に追加するようになっています。


// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Sketch shows how to use SimpleBLE to advertise the name of the device and change it on the press of a button
// Useful if you want to advertise some sort of message
// Button is attached between GPIO 0 and GND, and the device name changes each time the button is pressed

#include "SimpleBLE.h"

#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif

SimpleBLE ble;

void onButton(){
    String out = "BLE32 name: ";
    out += String(millis() / 1000);
    Serial.println(out);
    ble.begin(out);
}

void setup() {
    Serial.begin(115200);
    Serial.setDebugOutput(true);
    pinMode(2, INPUT_PULLUP);
    Serial.print("ESP32 SDK: ");
    Serial.println(ESP.getSdkVersion());
    ble.begin("ESP32 SimpleBLE");
    Serial.println("Press the button to change the device's name");
}

void loop() {
    static uint8_t lastPinState = 1;
    uint8_t pinState = digitalRead(2);
    if(!pinState && lastPinState){
        onButton();
    }
    lastPinState = pinState;
    while(Serial.available()) Serial.write(Serial.read());
}




実際に動かしてみます。コンソールにはボタンを押せと出ていたので、ボタンを押してみます。すると、"BLE32 name: 5" と出ました。


bledevice_console.png


スマホで確認してみると確かにBLE32 name: 5 というデバイスが現れました。


Screenshot.png


でも、このサンプルこれだけ。ここから何かできるわけではありません。うーん、せめてスマホにデータを送るくらいはしたいよなぁ。
(´・ω・`)





waves ESP32-DevKitC ESP-WROOM-32 ESP32 DevKitC V2 WiFi BLE 技適取得済 国内発送

waves ESP32-DevKitC ESP-WROOM-32 ESP32 DevKitC V2 WiFi BLE 技適取得済 国内発送

  • 出版社/メーカー: waves(ウェイブス)
  • メディア: エレクトロニクス



ESP-WROOM-32 WiFi + Bluetooth 無線モジュール お得な2個セット

ESP-WROOM-32 WiFi + Bluetooth 無線モジュール お得な2個セット

  • 出版社/メーカー: マイクロテクニカ
  • メディア: エレクトロニクス



MicroPython for ESP32 Development Workshop (English Edition)

MicroPython for ESP32 Development Workshop (English Edition)

  • 出版社/メーカー:
  • 発売日: 2017/08/19
  • メディア: Kindle版




nice!(30)  コメント(2) 
共通テーマ:趣味・カルチャー

ESP32 Simple WiFi Server を試してみた [Arduino]

ESP32なら WiFi の機能を試してみなければということで、ESP32 のライブラリの中になるサンプルプログラムを試してみました。


DSC04856.JPG


場所は "Documents\Arduino\hardware\espressif\esp32\libraries\WiFi\examples にあります。念のため、サンプルプログラムを貼っておきます。自宅の環境にあわせて SSID と Password を変更しておいてください。


/*
 WiFi Web Server LED Blink

 A simple web server that lets you blink an LED via the web.
 This sketch will print the IP address of your WiFi Shield (once connected)
 to the Serial monitor. From there, you can open that address in a web browser
 to turn on and off the LED on pin 5.

 If the IP address of your shield is yourAddress:
 http://yourAddress/H turns the LED on
 http://yourAddress/L turns it off

 This example is written for a network using WPA encryption. For
 WEP or WPA, change the Wifi.begin() call accordingly.

 Circuit:
 * WiFi shield attached
 * LED attached to pin 5

 created for arduino 25 Nov 2012
 by Tom Igoe

ported for sparkfun esp32 
31.01.2017 by Jan Hendrik Berlin
 
 */

#include 

const char* ssid     = "your ssid";
const char* password = "your password";

WiFiServer server(80);

void setup()
{
    Serial.begin(115200);
    pinMode(4, OUTPUT);      // set the LED pin mode

    delay(10);

    // We start by connecting to a WiFi network

    Serial.println();
    Serial.println();
    Serial.print("Connecting to ");
    Serial.println(ssid);

    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }

    Serial.println("");
    Serial.println("WiFi connected.");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
    
    server.begin();

}

int value = 0;

void loop(){
 WiFiClient client = server.available();   // listen for incoming clients

  if (client) {                             // if you get a client,
    Serial.println("New Client.");           // print a message out the serial port
    String currentLine = "";                // make a String to hold incoming data from the client
    while (client.connected()) {            // loop while the client's connected
      if (client.available()) {             // if there's bytes to read from the client,
        char c = client.read();             // read a byte, then
        Serial.write(c);                    // print it out the serial monitor
        if (c == '\n') {                    // if the byte is a newline character

          // if the current line is blank, you got two newline characters in a row.
          // that's the end of the client HTTP request, so send a response:
          if (currentLine.length() == 0) {
            // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
            // and a content-type so the client knows what's coming, then a blank line:
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println();

            // the content of the HTTP response follows the header:
            client.print("Click here to turn the LED on pin 4 on.
"); client.print("Click here to turn the LED on pin 4 off.
"); // The HTTP response ends with another blank line: client.println(); // break out of the while loop: break; } else { // if you got a newline, then clear currentLine: currentLine = ""; } } else if (c != '\r') { // if you got anything else but a carriage return character, currentLine += c; // add it to the end of the currentLine } // Check to see if the client request was "GET /H" or "GET /L": if (currentLine.endsWith("GET /H")) { digitalWrite(4, HIGH); // GET /H turns the LED on } if (currentLine.endsWith("GET /L")) { digitalWrite(4, LOW); // GET /L turns the LED off } } } // close the connection: client.stop(); Serial.println("Client Disconnected."); } }


LEDはサンプルでは LED は 5番ピンでしたが、私は4番ピンに変更しています。Arduino のシリアルモニタを立ち上げておくと、取得したIPアドレスが分かります。

Connecting to xxxxxxxx
.........
WiFi connected.
IP address: 
192.168.2.118



それでは実際の動きをみてみましょう。




今回はビデオ作成用に新しいツールを導入したので、ちょっと凝って Picture In Picture +音楽を試してみました。なんとこれフリーなんですよね。こちらの記事もそのうち。
(^_^)/~





waves ESP32-DevKitC ESP-WROOM-32 ESP32 DevKitC V2 WiFi BLE 技適取得済 国内発送

waves ESP32-DevKitC ESP-WROOM-32 ESP32 DevKitC V2 WiFi BLE 技適取得済 国内発送

  • 出版社/メーカー: waves(ウェイブス)
  • メディア: エレクトロニクス



ESP-WROOM-32 WiFi + Bluetooth 無線モジュール お得な2個セット

ESP-WROOM-32 WiFi + Bluetooth 無線モジュール お得な2個セット

  • 出版社/メーカー: マイクロテクニカ
  • メディア: エレクトロニクス



SparkFun ESP32 Thing Development Workshop (English Edition)

SparkFun ESP32 Thing Development Workshop (English Edition)

  • 出版社/メーカー: PE Press
  • 発売日: 2017/04/09
  • メディア: Kindle版




タグ:WiFi Arduino ESP32
nice!(32)  コメント(2) 
共通テーマ:趣味・カルチャー

ESP32 でLチカをやってみた! [Arduino]

ESP32をついに動かしてみましたー。とは言ってもLチカだけですけども。環境のセットアップはちょっと想定外のことがありましたが、比較的すんなりいきました。


DSC04446.JPG


最初に ESP32 のGitHubから Arduino の開発環境がまとまったZIPをダウンロードしてきます。

ESP32_ArduinoCore.png
https://github.com/espressif/arduino-esp32


右端にある緑の「Clone or download」ボタンをクリックして「Download ZIP」を選択しダウンロードします。解凍をしたら、Documentディレクトリの Arduino\hardware 以下に "espressif\esp32"というディレクトリを作って、そこにまるっと中身を置きます。


ESP32_Install.png


次に、"Arduino\hardware\espressif/esep32/tools/get.exe" をクリックして起動します。


ESP32_Install2.png


するとDOS窓が開いて、コンパイラをダウンロードしはじめます。


ESP32_Install3.png


処理が終わると、自動的にDOS窓が閉じます。これでセットアップは終わりです。Arduinoを開くと、ESP32 のボード設定が見えていますね。

ESP32_Arduino.png


で、ESP32 をつないで見たのですが、シリアルポートを認識しません。


DSC04856.JPG


少し調べてみたら、このブレイクアウトボードは、SiliconLabs の USB-UART チップを使っている模様。なので、ドライバをダウンロードしてきました。


vcp_driver.png
https://jp.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers


さて、これで準備完了なので、スケッチを書き込んでみました。

void setup() {
  pinMode(2, OUTPUT);
}

void loop() {
  digitalWrite(2, HIGH);
  delay(500);
  digitalWrite(2, LOW);
  delay(500);
}


コンパイルは無事済んでで、書き込みをしようとしたところで、なんとエラーが出てしまいました。フラッシュ書き込み用のプログラムがないと怒られてしまいました。

error: "C:\USERS\Documents\Arduino\hardware\epsressif\esp32/tools/gen_esp32part.exe": file does not exist
ボードESP32 Dev Moduleに対するコンパイル時にエラーが発生しました。



で、いろいろ調べたらノートンさんがプログラムを削除してしまった模様。どうも世界中で、利用者が数百人しかいない実績ないプログラムと認識してしまったようです。ESP32って、まだそんなマイナーなんだっけ???


norton.png


対策を講じてようやく動いた様子がこちらです。





これでようやくスタート地点にたちました。(^_^)/~






waves ESP32-DevKitC ESP-WROOM-32 ESP32 DevKitC V2 WiFi BLE 技適取得済 国内発送

waves ESP32-DevKitC ESP-WROOM-32 ESP32 DevKitC V2 WiFi BLE 技適取得済 国内発送

  • 出版社/メーカー: waves(ウェイブス)
  • メディア: エレクトロニクス



ESP-WROOM-32 WiFi + Bluetooth 無線モジュール お得な2個セット

ESP-WROOM-32 WiFi + Bluetooth 無線モジュール お得な2個セット

  • 出版社/メーカー: マイクロテクニカ
  • メディア: エレクトロニクス



SparkFun ESP32 Thing Development Workshop (English Edition)

SparkFun ESP32 Thing Development Workshop (English Edition)

  • 出版社/メーカー: PE Press
  • 発売日: 2017/04/09
  • メディア: Kindle版




タグ:Arduino ESP32
nice!(27)  コメント(2) 
共通テーマ:趣味・カルチャー