【BLEHF2Service(.h/.cpp)編】micro:bitにおけるDAL(V1)とCODAL(V2)とのBLEサービス実装の違いを確認する

# V1とV2での実装の違い
次の記事で、micro:bitにおけるDAL(V1)とCODAL(V2)とのBLEサービス実装の違いを確認していますが、本記事では、BLEHF2Serviceサービスを例に、その違いを確認しました。

https://qiita.com/jp-96/items/73e6fc42e6592b78c43e

# おさらい（pxt-microbitにおけるbluetoothの実装）
pxt-microbitでは、bluetoothが実装されており、ソースコードが公開されています。
https://github.com/microsoft/pxt-microbit/tree/master/libs/bluetooth

## DALとCODAL
micro:bitには、大きく分けて、V1とV2とが存在し、V1では、DALを使用し、V2では、CODALを使用します。
DAL/CODALで、V1とV2の違いを吸収して共通化されているのですが、bluetoothに関しては、共通化されていません。

## micro:bit ランタイムとNordic nRF5 SDK

MakeCodeで、HEX形式ファイルをビルドする際に、micro:bitランタイムやNordic nRF5 SDKといったライブラリが必要です。これらのライブラリは、micro:bitのバージョンにより異なります。

|micro:bit|ランタイム|nRF5|
|---|---|---|
|**V1**|dal  | Soft Device 110|
|**V2**|codal| Soft Device 113|

その為、拡張機能を独自に実装する際には、micro:bitの各バージョンに合わせたライブラリに対する実装が必要ですので、プリプロセッサ ディレクティブによる切り分けた実装を行います（MICROBIT_CODALがゼロ以外かどうか）。

|MICROBIT_CODAL|micro:bit|
|--------------|---------|
|ゼロ           |V1 - DAL   |
|ゼロ以外       |V2 - CODAL |

## BLE(Gattサーバー)の操作
ペリフェラルとしてBLEサービスを提供するために、Gattサーバーを操作しますが、V1とV2とではその実装方法が異なります。
Gattサーバーを操作する為に、V1の場合は、`uBit.ble`に委譲した実装を行い、V2の場合は、`MicroBitBLEService`クラスを継承した実装を行います。

:::note warn
**uBit.bleの正体**
V1/V2ともに`uBit.ble`は、`BLEDevice`型(`ble.h`)ですが、V2における`uBit.ble`の実体は、`MicrobitBLEManager`型(クラス)です。
→ [ソースコード](https://github.com/lancaster-university/codal-microbit-v2/blob/master/inc/bluetooth/MicroBitBLEManager.h#L66)
```codal-microbit-v2/inc/bluetooth/MicroBitBLEManager.h

class MicroBitBLEManager;
typedef MicroBitBLEManager BLEDevice;

```
:::

# BLEHF2Service における実装の違い

[pxt-microbit/bluetooth](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth)のソースコードに含まれる`BLEHF2Service`サービスを例に、実装の違いを確認します。

- [(github:microsoft) pxt-microbit/libs/bluetooth/BLEHF2Service.h](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.h)
- [(github:microsoft) pxt-microbit/libs/bluetooth/BLEHF2Service.cpp](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.cpp)


## BLEHF2Service.h - 違い

BLEHF2Service.hにおける、大きな違いは、次の２つです。

- MicroBitBLEServiceを継承しているかどうか
- Characteristicハンドルを配列で保持するかどうか

| # | 項目 | (V1)DAL | (V2)CODAL |
|:-:|---|---|---|
|  1 | [#include "MicroBitConfig.h"](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.h#L4)| (共通) | (共通) |
|  2 | [#include "MicroBitThermometer.h"](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.h#L5) | (共通) | (共通) |
|  3 | [#include "EventModel.h"](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.h#L6) |(共通) | (共通) |
|  4 | [#include "pxt.h"](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.h#L7) |(共通) | (共通) |
|  5 | [#define HF2_ID 9501](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.h#L9) |(共通) | (共通) |
|  6 | [#define BLEHF2_FLAG_SERIAL_OUT 0x80](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.h#L11) |(共通) | (共通) |
|  7 | [#define BLEHF2_FLAG_SERIAL_ERR 0xC0](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.h#L12) |(共通) | (共通) |
|  8 | [#define BLEHF2_DATA_LENGTH 19](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.h#L13) |(共通) | (共通) |
|  9 | [extern const uint8_t  BLEHF2ServiceUUID\[\];](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.h#L16) |**(共通)** | (共通-未使用) |
| 10 | [extern const uint8_t  BLEHF2TxCharacteristicUUID\[\];]() |**(共通)** | (共通-未使用) |
| 11 | [struct BLEHF2Packet {...};](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.h#L19) |(共通) | (共通) |
| 11 | [#include "ble/BLE.h"](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.h#L81) | **(V1)** |  |
| 11 | [#include "MicroBitBLEManager.h"](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.h#L28) |  | **(V2)** |
| 12 | [#include "MicroBitBLEService.h"](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.h#L29) |  | **(V2)** |
| 13 | 継承元 | [(なし)](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.h#L83) | [**MicroBitBLEService**](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.h#L31) |
| 14 | コンストラクタ | [(同等)](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.h#L92) | [(同等)](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.h#L40) |
| 15 | *void sendSerial(const char \*data, int len, bool isError);* | [(同等)](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.h#L97) | [(同等)](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.h#L45) |
| 16 | BLEDevice &ble; | [(同等)](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.h#L102) | [(同等)](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.h#L50) |
| 17 | BLEHF2Packet txCharacteristicMessage; | [(同等)](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.h#L105) | [(同等)](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.h#L53) |
| 18 | Charactersiticハンドル等の保持 | [**変数**](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.h#L107) | [**継承と配列**](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.h#L55) |

## BLEHF2Service.h - 共通(はじめ)

``` BLEHF2Service.h
#ifndef BLE_HF2_SERVICE_H
#define BLE_HF2_SERVICE_H

#include "MicroBitConfig.h"
#include "MicroBitThermometer.h"
#include "EventModel.h"
#include "pxt.h"

#define HF2_ID 9501

#define BLEHF2_FLAG_SERIAL_OUT 0x80
#define BLEHF2_FLAG_SERIAL_ERR 0xC0
#define BLEHF2_DATA_LENGTH 19

// UUIDs for our service and characteristics
extern const uint8_t  BLEHF2ServiceUUID[];
extern const uint8_t  BLEHF2TxCharacteristicUUID[];

struct BLEHF2Packet {
  uint8_t command;
  uint8_t data[BLEHF2_DATA_LENGTH];
};
```
## BLEHF2Service.h - (V2) CODAL

``` BLEHF2Service.h
//================================================================
#if MICROBIT_CODAL
//================================================================

#include "MicroBitBLEManager.h"
#include "MicroBitBLEService.h"

class BLEHF2Service : public MicroBitBLEService
{
    public:

    /**
      * Constructor.
      * Create a representation of the TemperatureService
      * @param _ble The instance of a BLE device that we're running on.
      */
    BLEHF2Service(BLEDevice &_ble);

    /**
    * Sends text
    */
    void sendSerial(const char *data, int len, bool isError);

    private:

    // Bluetooth stack we're running on.
    BLEDevice &ble;

    // memory for buffers.
    BLEHF2Packet txCharacteristicMessage;
    
    // Index for each charactersitic in arrays of handles and UUIDs
    typedef enum mbbs_cIdx
    {
        mbbs_cIdxMESSAGE,
        mbbs_cIdxCOUNT
    } mbbs_cIdx;
    
    // UUIDs for our service and characteristics
    static const uint8_t  service_base_uuid[ 16];
    static const uint8_t  char_base_uuid[ 16];
    static const uint16_t serviceUUID;
    static const uint16_t charUUID[ mbbs_cIdxCOUNT];
    
    // Data for each characteristic when they are held by Soft Device.
    MicroBitBLEChar      chars[ mbbs_cIdxCOUNT];

    public:
    
    int              characteristicCount()          { return mbbs_cIdxCOUNT; };
    MicroBitBLEChar *characteristicPtr( int idx)    { return &chars[ idx]; };
};

``` 

## BLEHF2Service.h - (V1) DAL

``` BLEHF2Service.h
//================================================================
#else // MICROBIT_CODAL
//================================================================

#include "ble/BLE.h"

class BLEHF2Service
{
    public:

    /**
      * Constructor.
      * Create a representation of the TemperatureService
      * @param _ble The instance of a BLE device that we're running on.
      */
    BLEHF2Service(BLEDevice &_ble);

    /**
    * Sends text
    */
    void sendSerial(const char *data, int len, bool isError); 

    private:

    // Bluetooth stack we're running on.
    BLEDevice &ble;

    // memory for buffers.
    BLEHF2Packet txCharacteristicMessage;

    // Handles to access each characteristic when they are held by Soft Device.
    GattAttribute::Handle_t txCharacteristicHandle;
};
```

## BLEHF2Service.h - 共通(おわり)

``` BLEHF2Service.h

//================================================================
#endif // MICROBIT_CODAL
//================================================================

#endif
```

## BLEHF2Service.cpp - 違い

BLEHF2Service.cppにおける、大きな違いは、次の２つです。

- UUIDをロング(ベース)とショートで扱っているかどうか
- bleインスタンスを操作するか、継承元に委譲しているかどうか

| # | 項目 | (V1)DAL | (V2)CODAL |
|:-:|---|---|---|
|  1 | [MicroBitConfig.h](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.cpp#L1) | (共通) | (共通) |
|  2 | [BLEHF2Service.h](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.cpp#L2) | (共通) | (共通) |
|  3 | [MicroBitEvent.h](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.cpp#L3) | (共通) | (共通) |
|  4 | [ble/UUID.h](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.cpp#L54) | **(V1)** |  |
|  5 | [const uint8_t  BLEHF2Service::service_base_uuid\[\];](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.cpp#L9) |  | **(V2)** |
|  6 | [const uint8_t  BLEHF2Service::char_base_uuid\[\];](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.cpp#L12) |  | **(V2)** |
|  7 | [const uint16_t BLEHF2Service::serviceUUID = 0xf5e6;](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.cpp#L15) |  | **(V2)** |
|  8 | [const uint16_t BLEHF2Service::charUUID\[ mbbs_cIdxCOUNT\] = { 0xf5e6 };](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.cpp#L16) |  | **(V2)** |
|  9 | [GattCharacteristic](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.cpp#L69) | **(V1)** |  |
| 10 | [GattService](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.cpp#L70) | **(V1)** |  |
| 11 | [ble.addService(service);](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.cpp#L71) | **(V1)** |  |
| 12 | [CreateService( serviceUUID);](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.cpp#L27) |  | **(V2)** |
| 13 | [CreateCharacteristic](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.cpp#L30)|  | **(V2)** |
| 14 | 接続状況| [ble.getGapState().connected](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.cpp#L81) | [getConnected()](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.cpp#L37) |
| 15 | notify| [ble.gattServer().notify()](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.cpp#L88) | [notifyChrValue()](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.cpp#L44) |
| 16 | [const uint8_t  BLEHF2ServiceUUID\[\];](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.cpp#L94) | **(V1)** |  |
| 17 | [const uint8_t  BLEHF2TxCharacteristicUUID\[\];](https://github.com/microsoft/pxt-microbit/blob/master/libs/bluetooth/BLEHF2Service.cpp#L98)| **(V1)** |  |

### 違いの補足説明（BLEHF2Service.cpp）

**【(V1) DAL】**
UUIDをロング形式で定義しています。
サービスの構築のために、コンストラクタで、GattCharacteristicインスタンスやGattServiceインスタンスを生成し、bleインスタンスにサービスを追加しています。
sendSerialメソッドでは、bleインスタンスを操作し、接続状況の取得やnotify呼び出しを行っています。

**【(V2) CODAL】**
UUIDをロング形式のベース部分とショート形式とで定義しています。
サービス構築のために、コンストラクタで、継承元のメソッドを呼び出してサービスを追加しています。
sendSerialメソッドでも、継承元のメソッドを呼び出し、接続状況の取得やnotify呼び出しを行っています。尚、notifyChrValue()メソッドの引数では、Characteristicハンドルの値ではなく、配列変数の添え字を渡しています。


## BLEHF2Service.cpp - 共通（はじめ）

``` BLEHF2Service.cpp
#include "MicroBitConfig.h"
#include "BLEHF2Service.h"
#include "MicroBitEvent.h"
```

## BLEHF2Service.cpp - (V2) CODAL

``` BLEHF2Service.cpp
//================================================================
#if MICROBIT_CODAL
//================================================================

const uint8_t  BLEHF2Service::service_base_uuid[ 16] =
{ 0xb1,0x12,0x00,0x00,0x26,0x79,0x30,0xda,0xa2,0x6e,0x02,0x73,0xb6,0x04,0x38,0x49 };

const uint8_t  BLEHF2Service::char_base_uuid[ 16] =
{ 0xb1,0x12,0x00,0x00,0x26,0x79,0x30,0xda,0xa2,0x6e,0x02,0x73,0xb6,0x04,0x38,0x4a };

const uint16_t BLEHF2Service::serviceUUID               = 0xf5e6;
const uint16_t BLEHF2Service::charUUID[ mbbs_cIdxCOUNT] = { 0xf5e6 };


BLEHF2Service::BLEHF2Service(BLEDevice &_ble) :
        ble(_ble)
{
    // Initialise our characteristic values.
    memset(&txCharacteristicMessage, 0, sizeof(txCharacteristicMessage));
    
    // Register the base UUID and create the service.
    RegisterBaseUUID( service_base_uuid);
    CreateService( serviceUUID);

    RegisterBaseUUID( char_base_uuid);
    CreateCharacteristic( mbbs_cIdxMESSAGE, charUUID[ mbbs_cIdxMESSAGE],
                         (uint8_t *)&txCharacteristicMessage,
                         sizeof(txCharacteristicMessage), sizeof(txCharacteristicMessage),
                         microbit_propNOTIFY);
}

void BLEHF2Service::sendSerial(const char *data, int len, bool isError) {
    if (getConnected())
    {
        int32_t sent = 0;
        while(sent < len) {
            int32_t n = min(BLEHF2_DATA_LENGTH, len - sent);
            txCharacteristicMessage.command = (isError ? BLEHF2_FLAG_SERIAL_OUT : BLEHF2_FLAG_SERIAL_ERR) | n;
            memcpy(&txCharacteristicMessage.data, data + sent, n);
            notifyChrValue(mbbs_cIdxMESSAGE,(uint8_t *)&txCharacteristicMessage, sizeof(txCharacteristicMessage));
            sent += n;
        }
    }
}
```

## BLEHF2Service.cpp - (V1) DAL

``` BLEHF2Service.cpp

//================================================================
#else // MICROBIT_CODAL
//================================================================

#include "ble/UUID.h"

BLEHF2Service::BLEHF2Service(BLEDevice &_ble) :
        ble(_ble)
{
    GattCharacteristic  txCharacteristic(BLEHF2TxCharacteristicUUID, (uint8_t *)&txCharacteristicMessage, 0,
    sizeof(txCharacteristicMessage), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);

    // Initialise our characteristic values.
    memset(&txCharacteristicMessage, 0, sizeof(txCharacteristicMessage));

    // Set default security requirements
    txCharacteristic.requireSecurity(SecurityManager::MICROBIT_BLE_SECURITY_LEVEL);

    // setup GATT table
    GattCharacteristic *characteristics[] = {&txCharacteristic};
    GattService service(BLEHF2ServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *));
    ble.addService(service);

    // retreive handles
    txCharacteristicHandle = txCharacteristic.getValueHandle();

    // initialize data
    ble.gattServer().write(txCharacteristicHandle,(uint8_t *)&txCharacteristicMessage, sizeof(txCharacteristicMessage));
}

void BLEHF2Service::sendSerial(const char *data, int len, bool isError) {
    if (ble.getGapState().connected)
    {
        int32_t sent = 0;
        while(sent < len) {
            int32_t n = min(BLEHF2_DATA_LENGTH, len - sent);
            txCharacteristicMessage.command = (isError ? BLEHF2_FLAG_SERIAL_OUT : BLEHF2_FLAG_SERIAL_ERR) | n;
            memcpy(&txCharacteristicMessage.data, data + sent, n);
            ble.gattServer().notify(txCharacteristicHandle,(uint8_t *)&txCharacteristicMessage, sizeof(txCharacteristicMessage));
            sent += n;
        }
    }
}

const uint8_t  BLEHF2ServiceUUID[] = {
    0xb1,0x12,0xf5,0xe6,0x26,0x79,0x30,0xda,0xa2,0x6e,0x02,0x73,0xb6,0x04,0x38,0x49
};

const uint8_t  BLEHF2TxCharacteristicUUID[] = {
    0xb1,0x12,0xf5,0xe6,0x26,0x79,0x30,0xda,0xa2,0x6e,0x02,0x73,0xb6,0x04,0x38,0x4a
};

```

## BLEHF2Service.cpp - 共通（おわり）

``` BLEHF2Service.cpp
//================================================================
#endif // MICROBIT_CODAL
//================================================================
```

# まとめ

BLEHF2Serviceサービスの実装においても、Gattサーバーを操作する為に、V1の場合は、`uBit.ble`に委譲した実装を行い、V2の場合は、`MicroBitBLEService`クラスを継承した実装を行っていることを確認しました。