nRF52840でOpenThread（１）：MDBT50Qでサンプルの実行

#はじめに
　nRF52840を搭載したMDBT50Q-DBを使ってOpenThreadの開発をしてみました。
　OpenThreadはGoogleがホームネットワーク用に開発した無線通信規格で特徴はメッシュネットワークを構築できるのとIPv6に対応しているという点でしょうか。詳しくはこちらを参照ください。https://openthread.io/

#開発環境
　nRF52と標準的な開発環境である、nRF52 SDKとSEGGER Emebded Studioを使います。開発環境としてArduinoを使うこともできますが、私の調べた限りではArduinoではOpenThreadの開発は難しそうでした（調査が足りないだけかも）。
　環境構築はこちらの「nRF52でBLEデバイスを開発する（１）Adafruit FeatherとSEGGER Embeded Studio」を見て準備をしていきます。
　・ https://qiita.com/jiro-aqua/items/63d3c04ba33eac57ebd0
　SDKのみOpenThread用のSDKをダウンロードする必要があるため、以下からダウンロードします。
　・ https://www.nordicsemi.com/Software-and-tools/Software/nRF5-SDK-for-Thread-and-Zigbee/Download#infotabs

#開発ボード
　今回は以下の機材を使用しました。
　・ nRF52840-DK ： https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-DK
　・ MDBT50Q-DB ： https://www.switch-science.com/catalog/5532/
　
　nRF52840-DKはNordic純正の開発ボードです。SEGGER J-Linkも組み込まれているのでこれ一つで開発できます。ただ技適が取れていない点に注意です。その点、MDBT50Q-DBは技適が取れているので、nRF52840-DKはMDBT50Q-DBにプログラムを書き込む用として使用します。また、MDBT50Q-DBの他にAdafruit Feather 52840 Expressという開発ボードもあります。こちらも技適を取得できているのでどちらかを選ぶことを推奨します。

#simple_coap_clinetとsimple_coap_server
　SDK 中の examples/thread/simple_coap_clientとexamples/thread/simple_coap_serverを使います。ただ、そのまま書き込んでも動作しないため、変更点と簡単なプログラムの解説を記述します。まずはsimple_coap_clientを見てみます（simple_coap_clientは変更はありません）。examples/thread/simple_coap_client/pca10056/blank/ses/thread_simple_coap_client_pca10056.emProjectを開きます。
　main.c内の以下のコードでボタンを押した時に挙動が設定されています。ボタン1（MDBT50Q-DBのSW2ボタン）を押すとマルチキャストのリクエストが送信されることがわかります。

```c:main.c
/***************************************************************************************************
 * @section Buttons
 **************************************************************************************************/

static void bsp_event_handler(bsp_event_t event)
{
    switch (event)
    {
        case BSP_EVENT_KEY_0:
            thread_coap_utils_unicast_light_request_send(THREAD_COAP_UTILS_LIGHT_CMD_TOGGLE);
            break;

        case BSP_EVENT_KEY_1:
        {
            m_command = ((m_command == THREAD_COAP_UTILS_LIGHT_CMD_OFF) ? THREAD_COAP_UTILS_LIGHT_CMD_ON :
                                                                          THREAD_COAP_UTILS_LIGHT_CMD_OFF);

            thread_coap_utils_multicast_light_request_send(m_command,
                                                           THREAD_COAP_UTILS_MULTICAST_REALM_LOCAL);
            break;
        }

        case BSP_EVENT_KEY_3:
            thread_coap_utils_provisioning_request_send();
            break;

        default:
            return; // no implementation needed
    }
}
```
　
　次に、以下の画像のようにExample内にthread_coap_utils.cというファイルがあります。ここに実際にCoAPメッセージを送信する際のコードや受信した際のコードが書かれています。
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603307/5084bbde-0700-c1e9-3c95-e5e0ea1f6fe8.png)

　ダブルクリックしてthread_coap_utils.cを開きます。
　thread_coap_utils.c内の以下の部分に先ほどのマルチキャストのリクエストを送信するメソッドが用意されています。

```c:thread_coap_utils.c
void thread_coap_utils_multicast_light_request_send(uint8_t                             command,
                                                    thread_coap_utils_multicast_scope_t scope)
{
    otError       error = OT_ERROR_NONE;
    otMessage   * p_request;
    otMessageInfo message_info;
    const char  * p_scope = NULL;
    otInstance  * p_instance = thread_ot_instance_get();

    do
    {
        p_request = otCoapNewMessage(p_instance, NULL);
        if (p_request == NULL)
        {
            NRF_LOG_INFO("Failed to allocate message for CoAP Request\r\n");
            break;
        }

        otCoapMessageInit(p_request, OT_COAP_TYPE_NON_CONFIRMABLE, OT_COAP_CODE_PUT);

        error = otCoapMessageAppendUriPathOptions(p_request, "light");
        ASSERT(error == OT_ERROR_NONE);

        error = otCoapMessageSetPayloadMarker(p_request);
        ASSERT(error == OT_ERROR_NONE);

        error = otMessageAppend(p_request, &command, sizeof(command));
        if (error != OT_ERROR_NONE)
        {
            break;
        }

        switch (scope)
        {
        case THREAD_COAP_UTILS_MULTICAST_LINK_LOCAL:
            p_scope = "ff02::1";
            break;

        case THREAD_COAP_UTILS_MULTICAST_REALM_LOCAL:
            p_scope = "ff03::1";
            break;

        default:
            ASSERT(false);
        }

        memset(&message_info, 0, sizeof(message_info));
        message_info.mPeerPort = OT_DEFAULT_COAP_PORT;

        error = otIp6AddressFromString(p_scope, &message_info.mPeerAddr);
        ASSERT(error == OT_ERROR_NONE);

        error = otCoapSendRequest(p_instance, p_request, &message_info, NULL, NULL);
    } while (false);

    if (error != OT_ERROR_NONE && p_request != NULL)
    {
        NRF_LOG_INFO("Failed to send CoAP Request: %d\r\n", error);
        otMessageFree(p_request);
    }
}
```

　次にsimple_coap_serverをみてみます。　　
　examples/thread/simple_coap_server/pca10056/blank/ses/thread_simple_coap_server_pca10056.emProjectを開きます。先ほどと同様にthread_coap_utils.cを開きます。
　以下でリクエストを受信した時に光らせるLEDを設定しています。サンプルではBSP_LED_3_MASK（0~3の4種類）が設定されていますが、今回使用しているMDBT50Q-DBは0〜2の3種類しかLEDがないのでBSP_LED_3_MASKを設定してもLEDが光りません。なので、BSP_LED_3_MASKをBSP_LED_2_MASKに変更します。


```c:thread_coap_utils.c
static void light_changed_default(thread_coap_utils_light_command_t light_command)
{
    switch (light_command)
    {
        case THREAD_COAP_UTILS_LIGHT_CMD_ON:
            LEDS_ON(BSP_LED_3_MASK);
            break;

        case THREAD_COAP_UTILS_LIGHT_CMD_OFF:
            LEDS_OFF(BSP_LED_3_MASK);
            break;

        case THREAD_COAP_UTILS_LIGHT_CMD_TOGGLE:
            LEDS_INVERT(BSP_LED_3_MASK);
            break;

        default:
            break;
    }
}
```

　これでプログラムを書き込みます。以下の画像のように接続します。Build → Build and Runで書き込みます。
　
![図2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603307/4b1367ad-9d7e-a175-16e4-0bf588c61fda.png)

　動作確認。simple_coap_clientを書き込んだボードのSW2ボタンを押すと、simple_coap_serverを書き込んだボードの3つ目のLEDが光りました。
![図3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603307/f76e3a6c-4ad9-4f6c-3619-4c1e3b8510f0.png)

#まとめ
　nRF52840-DKとMDBT50Q-DB、SEGGER Emebded Studioを使ってOpenThreadのサンプルを動かしました。デバイスがもうちょっと届いたらメッシュネットワークになってるかの確認とかパケットの到達率とかを計測する実験をしてみようかな。あとはやっぱセンサデータとかも送りたいから任意の文字列が送れるようにプログラムを変更していきます。