ESP32のBLEテキスト通信モジュールを考えてみた

 数年前より使いはじめたArduinoManagerはESP32のBLE通信を用いて
iOS機からESP32の情報などを閲覧・設定等可能な良いアプリでした。
　　　　　でした・・・　過去形です・・・
しかし先日のArduinoManagerソフトウェアアップデートで私の作った
ソフトはことごとく動かなくなりました。

そこで新規一転でPythonista3とこのESP32BLEテキスト通信ソフトで
2023年4月まで乗り切ってきました。　良いアプリでした。
　　　　　でした・・・　過去形です・・・
またも2023年4月末のPythonista3のアップデートで私の作ったソフトは
動かなくなりました。
　　　　　　　　　　　　　　　　私のプログラム達の冥福を～～～



今回修復したところで再びのソフトウェアアップデートで自作ソフトが
動かなくなるのは無駄なのでArduinoManagerを使うのを諦める事にしました。
なら以前の様に１台１台ＳＳＩＤとＰＡＳＳＷＯＲＤ埋め込みコンパイルを使う？
なんて事は考えられないので、BLEテキスト通信モジュールを自作することにしました。
以前からiOS機のPythonista3でソフト開発したいなと思っていたので良い機会です。

Pythonista3のBLE通信ソフトが死んでしまった際にBLE通信部をUDP通信に置き換えて
ソフトを作ったのですが、通信部と処理部で完全分離させると楽に移行できますね。

2023年にSwift PlaygroundでBLE通信をする

#実行に必要なリソース
　　ESP32とArduinoIDE開発環境
　　iOS機とSwift Playground開発環境（多分更新すると思います


#機能
　　ESP32側はSerial通信と同じような使い方がしたいので、私がよく使う
　　Serial通信のメソッドだけサポートしてみました。
　　begin
　　connected
　　available
　　read
　　SendChars
　　＝＝あまり厳密なテストは行っていませんので、意図しない制約があると思います＝＝


#使い方
　　私が作ったPythonista3コードと組み合わせて送受信を行えます。
　　iOS機から通信したいESP32機を選んで通信を行う流れになります。



```ino:esp32BLE.ino:
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include <BLE2902.h>

// BLEサーバーとConnectしているか
class BLE_MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {      Connected = ConnectOnce = true;     advertisingStop();  }
    void onDisconnect(BLEServer* pServer) {   Connected = ConnectOnce = false;    advertisingStart(); }
public:;
  BLEAdvertising* pAdvertising;
  bool Connected, ConnectOnce;
  BLE_MyServerCallbacks(){    Connected = false;  }
  void advertisingSet( const char *SERVICE_UUID ){  
    pAdvertising = BLEDevice::getAdvertising();
    pAdvertising->addServiceUUID(SERVICE_UUID);
    pAdvertising->setScanResponse(true);
    pAdvertising->setMinPreferred(0x06);
    pAdvertising->setMinPreferred(0x12);
  }
  void advertisingStart(){  pAdvertising->start();  }
  void advertisingStop(){   pAdvertising->stop();   }
};
// BLEサーバーからの受信バッファ制御
#define BLE_BUFFER_SIZE 255
class BLE_MyCharacteristicCallbacks : public BLECharacteristicCallbacks {
    void onWrite(BLECharacteristic* pCharacteristic) {
        std::string value = pCharacteristic->getValue();
        if( value.length() == 0 ) return;
        receivedOne = true;
        for( int i=0 ; i<value.length() ; i++ ){
          area[ writePos ] = (byte)value[i];
          writePos = ( writePos==(BLE_BUFFER_SIZE-1) ? 0 : writePos+1 );
        }
    }
public:;
  byte area[ BLE_BUFFER_SIZE ];
  int writePos, readPos;
  bool receivedOne;
  BLE_MyCharacteristicCallbacks(){
    writePos = readPos = 0;
    receivedOne = false;
  }
};

class ESP32_BLE_COM
{
private:
  const char *BLE_SERVER_NAME;
  String SERVICE_UUID;
  String CHAR_UUID;
  BLECharacteristic* pCharacteristic;
  BLE_MyServerCallbacks *servercallbacks;
  BLE_MyCharacteristicCallbacks *Buffer;
  BLEService* pService;
public:
  ESP32_BLE_COM(){  }

  void beign( const char *serverName, char *serviceUUID, char *charUUID ){
    BLE_SERVER_NAME = serverName;
    SERVICE_UUID = serviceUUID;
    CHAR_UUID = charUUID;
    BLEDevice::init( BLE_SERVER_NAME );
    BLEServer* pServer = BLEDevice::createServer();
    servercallbacks = new BLE_MyServerCallbacks();
    pServer->setCallbacks( servercallbacks );
    pService = pServer->createService(SERVICE_UUID.c_str());
    pCharacteristic = pService->createCharacteristic(
        CHAR_UUID.c_str(),
        BLECharacteristic::PROPERTY_READ |
        BLECharacteristic::PROPERTY_WRITE |
        BLECharacteristic::PROPERTY_NOTIFY |
        BLECharacteristic::PROPERTY_INDICATE
    );
    Buffer = new BLE_MyCharacteristicCallbacks();
    pCharacteristic->setCallbacks( Buffer );
    pCharacteristic->addDescriptor(new BLE2902());    
    pService->start();
    servercallbacks->advertisingSet(SERVICE_UUID.c_str());
    servercallbacks->advertisingStart();
  }
  void deinit( bool releasememory ){
    if( BLE_SERVER_NAME==NULL )  return;
    BLEDevice::deinit( releasememory );
    BLE_SERVER_NAME = NULL;
  }
  // データが送信可能になて始めてコネクテッドになります
  bool connected(){   if( !servercallbacks->Connected )         return false;
                      //if( !Buffer->receivedOne )	        return false;
                      return true;
  }
  // 接続後１回の確認のみtrueを返します
  bool connectOnce(){ if( !connected() ) 	                return false;
                      if( !servercallbacks->ConnectOnce ) 	return false;
                      Serial.printf("BLE connect\n");
                      servercallbacks->ConnectOnce = false; 	return true;
  }
  bool available(){   if(Buffer->readPos==Buffer->writePos) return false; else return true;    }
  int  read(){
    if( !available() ) return -1;
    byte ret = Buffer->area[Buffer->readPos];
    Buffer->readPos = ( Buffer->readPos==(BLE_BUFFER_SIZE-1) ? 0 : Buffer->readPos+1 );
    return (int)ret;
  }
  // BLEサーバーへの送信 (複数byte)
  void SendChars( char *c, int len ){
      pCharacteristic->setValue( (uint8_t *)c, len );     // 実はテキスト数値を送っています
      pCharacteristic->notify();
  }
  /*
  void SendChars( char *c, int len ){    for( int i=0 ; i<len ; i++ )  SendChar( c[i] );    }
  // BLEサーバーへの送信 (1byte)
  void SendChar( char b ){
      pCharacteristic->setValue( String((byte)b).c_str() );     // 実はテキスト数値を送っています
      pCharacteristic->notify();
  }
  */
  // 
  void start(){   pService->start();   Serial.printf("BLE service start\n");   }
  void stop(){    pService->stop();   Serial.printf("BLE service stop\n");   }

};

int count;
byte BUFFER[128];
int BUFFER_POS = 0;

ESP32_BLE_COM BLE;

void setup(){
    Serial.begin(115200);
    BLE.beign( "ESP32_BLE_SERVER", "FFAA", "0001" );
}

void loop() {
    if( !BLE.connected() )      return;
    if( BLE.available() ){
      int num = BLE.read();
      BUFFER[BUFFER_POS] = num;
      BUFFER_POS++;
      if( num==0 ){
        Serial.println( String( (char*)BUFFER ) );
        BUFFER_POS = 0;

        char str[30];
        sprintf( str, "ESP32 Message:%d", count );
        Serial.println( str );
        BLE.SendChars( str, strlen(str)+1 );
        count ++;
      }
      return;
    }
}

```

あとがき
　　以前はESP32にWebServerを実装して設定変更等を行っていたのですが
　スマホから接続可能なESP32機を調べる方法に悩んでいました。
　調べてみるとWebに記事が無いもんですね（汗）　びっくりです。
　なので今後誰かがマトモなBLEのシリアルライブラリを作ってくれると
　良いなぁと考えつつ、シリアル通信のメソッドを模倣して作りました。

　2024年になってPython BLEAKとESP32C3などの通信を行った際にソースを小変更しました。