nRF connect SDK:NUS(Nordic UART Service)

#初めてのBLE通信
NordicのnRFシリーズを触り始めて最初に実行するBLEでのデータ通信はおそらくNUS(Nordic UART Service)を触ることだと思います。ちなみにこのNUSというのはNordicのSDKには当たり前のように登場しますが**BLE標準サービスではない**です。
#NUSの実装
NUSの実態はNordicのカスタムUUIDなのですが、Nordic側で送受信に必要な関数は全て用意してくれていますのでそれを組み込むだけという形になっています。このあたりからもBLEを初めて使う人が入りやすい仕組みを作ってくれていると思います。
早速アドバタイズのところで作成したアドバタイズ部分にNUS部分を追加します。

```main.c
/*
 * Copyright (c) 2012-2014 Wind River Systems, Inc.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <zephyr.h>
#include <sys/printk.h>

#include <bluetooth/bluetooth.h>
#include <bluetooth/gatt.h>
#include <bluetooth/services/nus.h>
#include <drivers/uart.h>
#include <settings/settings.h>

#define DEVICE_NAME CONFIG_BT_DEVICE_NAME
#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)

static const struct bt_data ad[] = {
    BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
    BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
};

static void bt_receive_cb(struct bt_conn *conn, const uint8_t *const data,
              uint16_t len)
{
    uint8_t buf[256] = {0};

    printk("Received data\n");
    memcpy(buf, data, len);
    printk("%s", buf);
    printk("\n");
}

static struct bt_nus_cb nus_cb = {
    .received = bt_receive_cb,
};

static void connected(struct bt_conn *conn, uint8_t err)
{
    printk("Connected\n");
}

static void disconnected(struct bt_conn *conn, uint8_t reason)
{
    printk("Disconnected\n");
}

static struct bt_conn_cb conn_callbacks = {
    .connected    = connected,
    .disconnected = disconnected,
};

void main(void)
{
    int err = 0;

    err = bt_enable(NULL);
    if (err) {
        printk("Blutooth failed to start (err %d)\n", err);
        return;
    }

    if (IS_ENABLED(CONFIG_SETTINGS)) {
        settings_load();
    }

    err = bt_nus_init(&nus_cb);
    if (err) {
        printk("Failed to initialize Nordic UART service (err: %d)\n", err);
        return;
    }

    bt_conn_cb_register(&conn_callbacks);

    err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), NULL, 0);
    if (err) {
        printk("Advertising failed to start (err %d)\n", err);
        return;
    }

    uint8_t data[32];
    uint16_t len;
    strcpy(data, "UART test\n");
    len = 10;
    while (1)
    {
        // Send
        if (bt_nus_send(NULL, data, len))
        {
            printk("Failed to send data over BLE connection\n");
        }
        k_msleep(1000);
    }
}
```

ちなみにNUSについてはサンプルプロジェクトがありますので、それをそのまま使うのもよいと思います。ここでは関連する最低限の部分だけ切り出して分かり易くしています。

```prj.conf
# Use bluetooth
CONFIG_BT=y
CONFIG_BT_DEVICE_NAME="NCS NUS"

# Enable the NUS service
CONFIG_BT_NUS=y
```

CONFIG_BT_NUSというコンフィギュレーションが用意されているので有効にします。ちなみにnRF SDK時代も同様にsdk_config.h内にNUS_ENABLEDという項目がありました。
#接続
コンパイルして実行し、nRF connect for mobileで接続を試みます。
![Screenshot_20210806-091631.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340602/844bbcef-e777-f5a2-c2c5-9cd8137588e8.png)

RX Characteristicのアップロードで文字列を送ってみましょう。
![Screenshot_20210806-091656.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340602/54504f58-6c27-a643-e4ac-2250eea29ab9.png)

コンソール側で受信した文字列が表示されます。
![cmd.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340602/e8a907ed-5f32-b2b8-cedf-e10390c7e64a.png)

メインスレッドで１秒毎にデータを送信しているので、nRF Connect for MobileのNotificationをONにすると送信が成立してコンソールにエラーメッセージが出なくなります。