ESP32 Bluetooth classic SPPを試す 後編

ESP32 Bluetooth classic SPPを試す 後編

今回はBluetooth SPPの後編です。

この記事は JTAG でデバッグすることを前提にして書いています。
環境構築については こちら をご覧になってください。

投稿時の開発環境を記しておきます。

PC:
Windows10 OS

開発ボード :
ESP32-DevKitCーVE
(Soc : ESP32-D0WD-V3)

デバッガー(H/W):
FT2232D

デバッガー (S/W) :
Visual Studio Code + PlatformIO + ESP-IDF Framework

PC側の追加設定を行う

先にデバッガーを起動しておき、プログラムを動かしておきます。

(esp_bt_gap_set_pin()にブレークポイントを貼っておき、そこまで到達することを確認しておいた方が安心です)

PCのステータスバーの ^ 部分を押して、左上のBluetoothアイコンをクリックし「設定を開く」を選択します。

次にスクロールして降りていき、その他のBluetoothオプションを選択します。

Bluetooth設定のウィンドウが出たら、COMポートのタブを押し、追加ボタンを押します。

COMポートの追加 ウィンドウが出たら、発信の方をチェックして参照ボタンを押します。

ESP_SPP_ACCEPTOR を選択してOKボタンを押します。

これで Bluetooth とCOMポートのひもづけができたので Tera Term から Bluetooth を介してSPP通信を行うことができるようになりました。

私の環境では COM23 を使うことになります。

コーディングする

esp_spp_cb()関数を以下のようにコーディングします。

uint32_t clientHandle = 0;

static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
{
    static char buffer[256];
    memset(buffer, 0, sizeof(buffer));

    switch (event) {
    case ESP_SPP_INIT_EVT:
        ESP_LOGI(SPP_TAG, "ESP_SPP_INIT_EVT");
        esp_bt_dev_set_device_name(EXAMPLE_DEVICE_NAME);
        esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
        esp_spp_start_srv(sec_mask,role_slave, 0, SPP_SERVER_NAME);
        break;
    case ESP_SPP_DISCOVERY_COMP_EVT:
        ESP_LOGI(SPP_TAG, "ESP_SPP_DISCOVERY_COMP_EVT");
        break;
    case ESP_SPP_OPEN_EVT:
        ESP_LOGI(SPP_TAG, "ESP_SPP_OPEN_EVT");
        break;
    case ESP_SPP_CLOSE_EVT:
        ESP_LOGI(SPP_TAG, "ESP_SPP_CLOSE_EVT");
        clientHandle = 0;
        break;
    case ESP_SPP_START_EVT:
        ESP_LOGI(SPP_TAG, "ESP_SPP_START_EVT");
        break;
    case ESP_SPP_CL_INIT_EVT:
        ESP_LOGI(SPP_TAG, "ESP_SPP_CL_INIT_EVT");
        break;
    case ESP_SPP_DATA_IND_EVT:
#if (SPP_SHOW_MODE == SPP_SHOW_DATA)
        ESP_LOGI(SPP_TAG, "ESP_SPP_DATA_IND_EVT len=%d handle=%d",
                 param->data_ind.len, param->data_ind.handle);
        esp_log_buffer_hex("",param->data_ind.data,param->data_ind.len);

//        char *p = (char *)&param->data_ind.data;
        for (int i = 0; i < param->data_ind.len; i++)
        {
//            buffer[i] = p[i];
            buffer[i] = (char)param->data_ind.data[i];
        }
        buffer[param->data_ind.len] = '\0';
        ESP_LOGI(SPP_TAG, "Receive Data=%s\r\n", buffer);

        char *msg = "Recv : Bluetooth SPP Data received.";

        if (clientHandle)
        {
            ESP_LOGI(SPP_TAG, "Write to SPP.");
            esp_spp_write(clientHandle, strlen(msg), (uint8_t *)msg);
        }
#else
        gettimeofday(&time_new, NULL);
        data_num += param->data_ind.len;
        if (time_new.tv_sec - time_old.tv_sec >= 3) {
            print_speed();
        }
#endif
        break;
    case ESP_SPP_CONG_EVT:
        ESP_LOGI(SPP_TAG, "ESP_SPP_CONG_EVT");
        break;
    case ESP_SPP_WRITE_EVT:
        ESP_LOGI(SPP_TAG, "ESP_SPP_WRITE_EVT");
        break;
    case ESP_SPP_SRV_OPEN_EVT:
        ESP_LOGI(SPP_TAG, "ESP_SPP_SRV_OPEN_EVT");
        gettimeofday(&time_old, NULL);
        clientHandle = param->srv_open.handle;  // つながったらハンドルを取得する
        break;
    case ESP_SPP_SRV_STOP_EVT:
        ESP_LOGI(SPP_TAG, "ESP_SPP_SRV_STOP_EVT");
        clientHandle = 0;   // ハンドルを解放する
        break;
    case ESP_SPP_UNINIT_EVT:
        ESP_LOGI(SPP_TAG, "ESP_SPP_UNINIT_EVT");
        break;
    default:
        break;
    }
}

ビルドして実行する

ビルドしてエラーがないことを確認してプログラムを実行します。

しばらくは esp_bt_gap_set_pin() にブレークポイントを貼って、起動後ここにたどり着くことを確認しておいた方が安心します。

その後、再びプログラムを実行しモニターを起動しておきます。

ファイルを作成する

Tera Term 上で文字を送ると1キャラクタ毎に送られるので効率が悪いです。

あらかじめファイルを作成しておいて、それを送るようにしてみます。

私は以下の内容で send.txt というファイルをデスクトップに作成しました。

Send : Hello ESP32 Bluetooth SPP world.

Tera Termを起動してファイルを送ってみる

Tera Termを起動して 先ほどのCOMポートを選択します。

左上のタイトルが「未接続」から「接続中」になって消えます。

エラーのウィンドウが出なければ大丈夫です。

次に設定 - 端末から以下のように設定を行います。

これで送受信のデータが Tera Term 上で確認できるようになります。

それではファイル – ファイル送信から先ほどつくった send.txt を選択して送信してみましょう。

“Recv : Bluetooth SPP Data received.”の文字列は ESP32からBluetoothで送ったものになります。

こちらまで表示されれば送受信ができたことになります。

プログラムの概要

esp_spp_cb()という関数はコールバック関数で、SPPのイベントが発生するとここに来てお知らせしてくれます。

ESP_SPP_SRV_OPEN_EVT に来たところで param->srv_pen.handle を clientHandle に記憶しておきます。

ESP_SPP_SRV_STOP_EVT で clientHandle = 0 にして解放します。

Tera Term から電文が送られてくると ESP_SPP_DATA_IND_EVT に来るので buffer に取り込みます。

// 部にあるように char *p として、そこから buffer に取り込もうとするとなぜかうまくいきませんでした。
// 関数の同期が関連しているのかな?と思い、buffer[]をstaticの変数にかえてみたけれどかわらず。。
// 原因がおわかりの方がいらっしゃいましたら教えてください m(__)m

電文を受信できてかつ、clientHandle が有効なら、esp_spp_write()で送信するようにしました。

ESP32の方は、わざわざUARTを使う必要はなさそうなので、このようにコーディングしました。

いかがでしたか?

皆さんの環境では、うまく動きましたか?

ソースコードを github esp32e-bt-spp-acceptor におきました。

( 環境: VSCode + PlatformIO , Espressif IoT Development Framework )

ESP-IDE環境で Bluetooth SPP を試してみたい方は参考になさってください。

参考というほど、できの良いものではありませんけれど (^_^)

bluetoothカテゴリの最新記事