0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

CoreBluetoothForUnityAdvent Calendar 2023

Day 5

CoreBluetoothForUnity で M5Stack と通信する

Last updated at Posted at 2023-12-04

本記事について

この記事は CoreBluetoothForUnity Advent Calendar 2023 の5日目の記事です。

本記事では CoreBluetoothForUnity のサンプル 02_ButtonInformation と通信するための M5Stack 側のプログラムを紹介します。

環境

  • MacBook Air M2
  • M5AtomS3

M5Stack の開発関連記事

Hello World や 段階的に BLE 通信を行う方法等は別記事ですでに書いているためそちらのリンクを貼っておきます。

02_ButtonInformation と通信するときのポイント

  1. Service, Characteristic の UUID を適切に指定
  2. ボタンの押下状態の取得
  3. ボタンの状態を BLE 通信で送信できる形にフォーマット

これらが基本的な Notify のコードから変える必要のある部分です。

実装方法

長いですが、読みづらくはないと思うため先に全文載せてしまいます。

main.cpp
#include <M5Unified.h>
#include "BLEDevice.h"
#include "BLEServer.h"
#include <BLE2902.h>

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/

#define SERVICE_UUID "068C47B7-FC04-4D47-975A-7952BE1A576F"
#define CHARACTERISTIC_UUID "E91E5ECB-A460-4DB1-97F7-F13D52222E15"

static int8_t state = 0;

#define STATE_ADVERTISING 0
#define STATE_CONNECTING 1
#define STATE_CONNECTED 2
#define STATE_DISCONNECTED 3

static bool redraw = false;

BLECharacteristic *pButtonInformationCharacteristic;

class MyServerCallbacks : public BLEServerCallbacks
{
  void onConnect(BLEServer *pServer)
  {
    state = STATE_CONNECTED;
    BLEDevice::stopAdvertising();
    redraw = true;
  };

  void onDisconnect(BLEServer *pServer)
  {
    state = STATE_DISCONNECTED;
    redraw = true;
  }
};

void startServer()
{
  BLEServer *pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  BLEService *pService = pServer->createService(SERVICE_UUID);
  pButtonInformationCharacteristic = pService->createCharacteristic(
      CHARACTERISTIC_UUID,
      BLECharacteristic::PROPERTY_READ |
          BLECharacteristic::PROPERTY_NOTIFY);
  pButtonInformationCharacteristic->addDescriptor(new BLE2902());

  pService->start();

  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(true);
  BLEDevice::startAdvertising();
}

void setup()
{
  auto cfg = M5.config();
  M5.begin(cfg);
  USBSerial.begin(115200);
  M5.Display.setTextSize(2);

  BLEDevice::init("M5AtomS3");
  startServer();
  state = STATE_ADVERTISING;
  redraw = true;
}

std::string getButtonInformation(int buttonId, bool isPressed)
{
  std::string buff = "";
  buff += (char)buttonId;
  buff += (char)(isPressed ? 0x80 : 0x00);
  return buff;
}

void onPressBtnA()
{
  if (state != STATE_CONNECTED)
  {
    return;
  }

  std::string buff = getButtonInformation(1, true);
  pButtonInformationCharacteristic->setValue(buff);
  pButtonInformationCharacteristic->notify();
}

void onReleaseBtnA()
{
  if (state != STATE_CONNECTED)
  {
    return;
  }

  std::string buff = getButtonInformation(1, false);
  pButtonInformationCharacteristic->setValue(buff);
  pButtonInformationCharacteristic->notify();
}

void handleButtonEvent()
{
  if (M5.BtnA.wasPressed())
  {
    onPressBtnA();
  }

  if (M5.BtnA.wasReleased())
  {
    onReleaseBtnA();
  }
}

void drawAdvertising()
{
  M5.Display.startWrite();
  M5.Display.clear(BLACK);
  M5.Display.setCursor(0, 20);
  M5.Display.printf("Advertising");
  M5.Display.endWrite();
}

void drawConnected()
{
  M5.Display.startWrite();
  M5.Display.clear(BLACK);
  M5.Display.setCursor(0, 20);
  M5.Display.println("Connected");
  M5.Display.endWrite();
}

void drawDisplay()
{
  switch (state)
  {
  case STATE_ADVERTISING:
    drawAdvertising();
    break;
  case STATE_CONNECTED:
    drawConnected();
    break;
  }
}

void loop()
{
  M5.update();
  handleButtonEvent();

  if (state == STATE_DISCONNECTED)
  {
    state = STATE_ADVERTISING;
    BLEDevice::startAdvertising();
    redraw = true;
  }

  if (!redraw)
    return;
  redraw = false;
  drawDisplay();
}

UUID は Unity 側と同じ値を設定しています。

SampleButtonInformation_Data.cs
public class SampleButtonInformation_Data
{
...
    public static readonly string ServiceUUID = "068C47B7-FC04-4D47-975A-7952BE1A576F";
    public static readonly string ButtonInformationCharacteristicUUID = "E91E5ECB-A460-4DB1-97F7-F13D52222E15";

ボタンの押下状態

main.cpp
void handleButtonEvent()
{
  if (M5.BtnA.wasPressed())
  {
    onPressBtnA();
  }

  if (M5.BtnA.wasReleased())
  {
    onReleaseBtnA();
  }
}

wasPressed() と wasReleased() で取得しています。

ボタンの状態の取得方法は以下の M5Unified のドキュメントに書かれています。

ボタンの状態を BLE 通信で送信できる形にフォーマット

ここが本記事の本題です。

Characteristic の値を更新する setValue() の引数は複数ありますが、byte[] を渡すような感覚で使用できるのは以下の2つです。

void BLECharacteristic::setValue(uint8_t *data, size_t size)
void BLECharacteristic::setValue(std::string value)

setValue

上記の実装では std::stringを用いています。

main.cpp
std::string getButtonInformation(int buttonId, bool isPressed)
{
  std::string buff = "";
  buff += (char)buttonId;
  buff += (char)(isPressed ? 0x80 : 0x00);
  return buff;
}

数字を char に変換して std::string に追加しています。

uint8_t で渡す場合には以下のように書くことができます。

main.cpp
void getButtonInformation(uint8_t buff[2], int buttonId, bool isPressed)
{
  buff[0] = buttonId;
  buff[1] = (isPressed ? 0x80 : 0x00);
}

void onPressBtnA()
{
  if (state != STATE_CONNECTED)
  {
    return;
  }

  uint8_t buff[2];
  getButtonInformation(buff, 1, true);
  pButtonInformationCharacteristic->setValue(buff, sizeof(buff));
  pButtonInformationCharacteristic->notify();
}

どちらを使っても動作することは確認できました。

おわりに

本記事では CoreBluetoothForUnity のサンプル 02_ButtonInformation と通信するための M5Stack 側のプログラムを紹介しました。

M5Stack を使うと Unity で作ったゲームのコントローラーを作ったり、なんらかのアウトプットに利用したりなど表現の幅は広がるかなと思います。
こちらのプログラムが参考になれば幸いです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?