nRF52840 ボードと OpenThread で Thread ネットワークを構築

1. はじめに

26b7f4f6b3ea0700.png

Google がリリースした OpenThread は、Thread® ネットワーク プロトコルのオープンソース実装です。Google Nest は、Google Nest 製品で使用されている技術を幅広く利用できるようにし、スマートホーム製品の開発を加速させるため、OpenThread をリリースしました。

Thread 仕様は、家庭用アプリケーション向けに IPv6 ベースの信頼性、安全性、消費電力の優れたワイヤレス デバイス間通信プロトコルを定義しています。OpenThread は、IPv6、6LoWPAN、MAC セキュリティを備えた IEEE 802.15.4、メッシュリンク確立、メッシュルーティングなど、すべての Thread ネットワーキングレイヤを実装しています。

この Codelab では、実際のハードウェア上で OpenThread をプログラミングし、Thread ネットワークを作成して管理し、ノード間でメッセージを渡します。

4806d16a8c137c6d.jpeg

学習内容

  • OpenThread CLI バイナリをビルドして開発ボードに書き込む
  • Linux マシンと開発ボードで構成される RCP を構築する
  • OpenThread Daemon と ot-ctl を使用して RCP と通信する
  • GNU Screen と OpenThread CLI を使用して Thread ノードを手動で管理する
  • Thread ネットワークでのデバイスのコミッショニングを安全に行う
  • IPv6 マルチキャストの仕組み
  • UDP を使用して Thread ノード間でメッセージを受け渡す

必要なもの

ハードウェア:

  • Nordic Semiconductor nRF52840 開発ボード x 3
  • ボードを接続するための USB - マイクロ USB ケーブル x 3
  • USB ポートが 3 つ以上ある Linux マシン

ソフトウェア:

  • GNU ツールチェーン
  • Nordic nRF5x コマンドライン ツール
  • Segger J-Link ソフトウェア
  • OpenThread
  • Git

2. 開始するには

OpenThread シミュレーション

始める前に、OpenThread シミュレーションの Codelab に目を通し、Thread の基本的なコンセプトと OpenThread CLI に慣れておくことをおすすめします。

シリアルポート ターミナル

ターミナルを通じてシリアルポートに接続する方法に精通している必要があります。この Codelab では GNU Screen を使用して使用状況の概要を説明しますが、他のターミナル ソフトウェアも使用できます。

Linux マシン

この Codelab は、i386 または x86 ベースの Linux マシンを使用して、無線コプロセッサ(RCP)Thread デバイスのホストとして機能し、すべての Thread 開発ボードをフラッシュするように設計されています。すべてのステップは、Ubuntu 14.04.5 LTS(Trusty Tahr)でテストされました。

Nordic Semiconductor nRF52840 ボード

この Codelab では 3 つの nRF52840 PDK ボードを使用します。

a6693da3ce213856.png

SEGGER J-Link を使用して、オンボードの JTAG モジュールを搭載した nRF52840 ボードをプログラムします。Linux マシンにインストールします。

お使いのマシンに適したパッケージをダウンロードし、適切な場所にインストールします。Linux では /opt/SEGGER/JLink です。

nRF5x コマンドライン ツールをインストールする

nRF5x コマンドライン・ツールを使用すると、OpenThread バイナリを nRF52840 ボードにフラッシュできます。適切な nRF5x-Command-Line-Tools-<OS> をインストールします。Linux マシンでビルドします。

抽出したパッケージをルートフォルダ ~/ に配置します。

ARM GNU Toolchain をインストールする

ビルドには ARM GNU ツールチェーンを使用します。

抽出したアーカイブを Linux マシンの /opt/gnu-mcu-eclipse/arm-none-eabi-gcc/ に保存することをおすすめします。インストール手順については、アーカイブの readme.txt ファイルをご覧ください。

インストール画面(省略可)

Screen は、シリアルポートで接続されたデバイスにアクセスするためのシンプルなツールです。この Codelab では Screen を使用しますが、任意のシリアルポート ターミナル アプリケーションを使用できます。

$ sudo apt-get install screen

3. リポジトリのクローンを作成する

OpenThread

OpenThread のクローンを作成してインストールします。script/bootstrap コマンドにより、ツールチェーンがインストールされ、環境が適切に構成されていることを確認します。

$ mkdir -p ~/src
$ cd ~/src
$ git clone --recursive https://github.com/openthread/openthread.git
$ cd openthread
$ ./script/bootstrap

OpenThread Daemon をビルドします。

$ script/cmake-build posix -DOT_DAEMON=ON

これで、OpenThread をビルドして nRF52840 ボードに書き込める準備が整いました。

4. RCP Joiner を設定する

ビルドとフラッシュ

Joiner とネイティブ USB 機能を使用して、OpenThread nRF52840 サンプルをビルドします。デバイスは Joiner ロールを使用して、Thread ネットワークへの安全な認証とコミッショニングを行います。ネイティブ USB により、nRF52840 とホスト間のシリアル トランスポートとして USB CDC ACM を使用できます。

必ず、最初に rm -rf build を実行して、以前のビルドのリポジトリをクリーンアップします。

$ cd ~/src
$ git clone --recursive https://github.com/openthread/ot-nrf528xx.git
$ cd ot-nrf528xx
$ script/build nrf52840 USB_trans

OpenThread RCP バイナリのあるディレクトリに移動し、16 進数形式に変換します。

$ cd ~/src/ot-nrf528xx/build/bin
$ arm-none-eabi-objcopy -O ihex ot-rcp ot-rcp.hex

nRF52840 ボードの外部電源ピンの横にある Micro-USB デバッグ ポートに USB ケーブルを接続し、Linux マシンに接続します。nRF52840 ボードの nRF 電源スイッチを VDD に設定します。正しく接続されると、LED5 が点灯します。

20a3b4b480356447.png

これが Linux マシンに接続する最初のボードの場合は、シリアルポート /dev/ttyACM0 として表示されます(すべての nRF52840 ボードはシリアルポート ID に ttyACM を使用します)。

$ ls /dev/ttyACM*
/dev/ttyACM0

RCP に使用している nRF52840 ボードのシリアル番号を確認します。

c00d519ebec7e5f0.jpeg

nRFx コマンドライン・ツールの場所に移動し、ボードのシリアル番号を使用して、OpenThread RCP の 16 進ファイルを nRF52840 ボードに書き込みます。なお、--verify フラグを省略すると、フラッシュ処理がエラーなしで失敗する可能性があるという警告メッセージが表示されます。

$ cd ~/nrfjprog/
$ ./nrfjprog -f nrf52 -s 683704924  --verify --chiperase --program \
       ~/src/ot-nrf528xx/build/bin/ot-rcp.hex --reset

成功すると、次の出力が生成されます。

Parsing hex file.
Erasing user available code and UICR flash areas.
Applying system reset.
Checking that the area to write is not protected.
Programing device.
Applying system reset.
Run.

ボードに「RCP」というラベルを付ける後で役員の役割を混同しないようにできます。

ネイティブ USB への接続

OpenThread RCP ビルドではネイティブ USB CDC ACM をシリアル トランスポートとして使用できるため、RCP ホスト(Linux マシン)との通信には nRF52840 ボードの nRF USB ポートを使用する必要があります。

USB ケーブルのマイクロ USB 端子を、フラッシュした nRF52840 ボードのデバッグポートから外し、[RESET] ボタンの横にあるマイクロ USB nRF USB ポートに再び接続します。[nRF 電源] スイッチを [USB] に設定します。

46e7b670d2464842.png

OpenThread デーモンを開始する

RCP 設計では、OpenThread Daemon を使用して Thread デバイスとの通信と管理を行います。詳細フラグ -v を指定して ot-daemon を開始します。これにより、ログ出力が表示され、実行中であることを確認できます。

$ cd ~/src/openthread
$ sudo ./build/posix/src/posix/ot-daemon -v \
    'spinel+hdlc+uart:///dev/ttyACM0?uart-baudrate=115200'

成功すると、詳細モードの ot-daemon は次のような出力を生成します。

ot-daemon[12463]: Running OPENTHREAD/thread-reference-20200818-1938-g0f10480ed; POSIX; Aug 30 2022 10:55:05
ot-daemon[12463]: Thread version: 4
ot-daemon[12463]: Thread interface: wpan0
ot-daemon[12463]: RCP version: OPENTHREAD/thread-reference-20200818-1938-g0f10480ed; SIMULATION; Aug 30 2022 10:54:10

ot-daemon のログを表示できるように、このターミナル ウィンドウは開いたままにしておきます。

ot-ctl を使用して RCP ノードと通信します。ot-ctl は OpenThread CLI アプリと同じ CLI を使用します。そのため、シミュレートされた他の Thread デバイスと同じ方法で ot-daemon ノードを制御できます。

2 つ目のターミナル ウィンドウで、ot-ctl を開始します。

$ sudo ./build/posix/src/posix/ot-ctl
>

ot-daemon で開始したノード 2(RCP ノード)の state を確認します。

> state
disabled
Done

5. FTD を設定する

この Codelab で使用する他の 2 つのスレッド ノードは、標準のシステム オン チップ(SoC)設計のフル スレッド デバイス(FTD)です。本番環境では、本番環境レベルのネットワーク インターフェース ドライバである wpantund を使用して OpenThread NCP インスタンスを制御できますが、この Codelab では OpenThread CLI の ot-ctl を使用します。

一方のデバイスはコミッショナーとして機能し、そのネットワークで安全に認証とコミッショナーを行います。もう一方のデバイスは、コミッショナーが Thread ネットワークに対して認証できる Joiner として機能します。

ビルドとフラッシュ

コミッショナーと Joiner のロールを有効にして、nRF52840 プラットフォーム用の OpenThread FTD サンプルをビルドします。

$ cd ~/src/ot-nrf528xx
$ rm -rf build
$ script/build nrf52840 USB_trans -DOT_JOINER=ON -DOT_COMMISSIONER=ON

OpenThread Full Thread Device(FTD)CLI バイナリがあるディレクトリに移動し、16 進数形式に変換します。

$ cd ~/src/ot-nrf528xx/build/bin
$ arm-none-eabi-objcopy -O ihex ot-cli-ftd ot-cli-ftd.hex

nRF52840 ボードの外部電源ピンの横にある Micro-USB ポートに USB ケーブルを接続し、Linux マシンに接続します。RCP がまだ Linux マシンに接続されている場合、この新しいボードはシリアルポート /dev/ttyACM1 として表示されます(すべての nRF52840 ボードはシリアルポート ID に ttyACM を使用します)。

$ ls /dev/ttyACM*
/dev/ttyACM0  /dev/ttyACM1

前と同様に、FTD に使用している nRF52840 ボードのシリアル番号をメモします。

c00d519ebec7e5f0.jpeg

nRFx コマンドライン・ツールの場所に移動し、ボードのシリアル番号を使用して、OpenThread CLI FTD 16 進ファイルを nRF52840 ボードに書き込みます。

$ cd ~/nrfjprog/
$ ./nrfjprog -f nrf52 -s 683704924 --verify --chiperase --program \
       ~/src/ot-nrf528xx/build/bin/ot-cli-ftd.hex --reset

取締役会に「コミッショナー」というラベルを付けます。

ネイティブ USB への接続

OpenThread FTD ビルドでは、ネイティブ USB CDC ACM をシリアル トランスポートとして使用できるため、nRF52840 ボードの nRF USB ポートを使用して RCP ホスト(Linux マシン)と通信する必要があります。

USB ケーブルのマイクロ USB 端子を、フラッシュした nRF52840 ボードのデバッグポートから外し、[RESET] ボタンの横にあるマイクロ USB nRF USB ポートに再び接続します。[nRF 電源] スイッチを [USB] に設定します。

46e7b670d2464842.png

ビルドを検証する

ターミナル ウィンドウから GNU Screen を使用して OpenThread CLI にアクセスし、ビルドが成功したことを確認します。nRF52840 ボードは、115200 のボーレートを使用します。

$ screen /dev/ttyACM1 115200

新しいウィンドウで、キーボードの Return キーを数回押して、OpenThread CLI の > プロンプトを表示します。IPv6 インターフェースを起動して、アドレスを確認します。

> ifconfig up
Done
> ipaddr
fe80:0:0:0:1cd6:87a9:cb9d:4b1d
Done

Ctrl+A → キーを使用

dFTD Commissioner CLI 画面から切断して Linux ターミナルに戻り、次のボードをフラッシュできるようにします。コマンドラインから screen -r を使用すれば、いつでも CLI を再開できます。使用可能な画面のリストを表示するには、screen -ls を使用します。

$ screen -ls
There is a screen on:
        74182.ttys000.mylinuxmachine        (Detached)
1 Socket in /tmp/uscreens/S-username.

FTD Joiner を設定する

既存の ot-cli-ftd.hex ビルドを使用して上記の手順を繰り返し、3 台目の nRF52840 ボードをフラッシュします。完了したら、nRF USB ポートを使用して Board を PC に再接続し、[nRF power source] スイッチを [VDD] に設定します。

この 3 つ目のボードが接続されたときに他の 2 つのノードが Linux マシンに接続されると、シリアルポート /dev/ttyACM2 として表示されます。

$ ls /dev/ttyACM*
/dev/ttyACM0  /dev/ttyACM1  /dev/ttyACM2

ボードに「Joiner」というラベルを付けます。

Screen を使用して確認する場合は、コマンドラインから Screen の新しいインスタンスを作成するのではなく、既存のインスタンスに再度アタッチし、その中に新しいウィンドウ(FTD コミッショナーに使用したもの)を作成します。

$ screen -r

Ctrl+A → c を使用して、Screen 内に新しいウィンドウを作成します。

新しいコマンドライン プロンプトが表示されます。FTD Joiner の OpenThread CLI にアクセスします。

$ screen /dev/ttyACM2 115200

この新しいウィンドウで、キーボードの Return キーを数回押して、OpenThread CLI の > プロンプトを表示します。IPv6 インターフェースを起動して、アドレスを確認します。

> ifconfig up
Done
> ipaddr
fe80:0:0:0:6c1e:87a2:df05:c240
Done

FTD Joiner CLI が FTD コミッショナーと同じ Screen のインスタンスに追加されたため、Ctrl+A → n を使用して切り替えることができます。

Ctrl+A → キーを使用

d であれば、いつでも画面を終了できます。

6. ターミナル ウィンドウの設定

今後は、Thread デバイスを頻繁に切り替えることになるため、すべてのデバイスが公開されていて、簡単にアクセスできることを確認してください。これまでは、Screen を使用して 2 つの FTD にアクセスしてきましたが、このツールで同じターミナル ウィンドウで画面を分割することもできます。これを使用して、あるノードが別のノードで発行されたコマンドにどう反応するかを確認します。

理想的には、すぐに利用できる 4 つのウィンドウが必要です。

  1. ot-daemon サービス / ログ
  2. ot-ctl 経由の RCP Joiner
  3. FTD コミッショナー(OpenThread CLI を使用)
  4. OpenThread CLI を介した FTD Joiner

独自の端子 / シリアルポート構成またはツールを使用する場合は、スキップして次のステップに進みます。すべてのデバイスのターミナル ウィンドウを最適な方法で構成します。

画面の使用

使いやすさを考慮し、開始画面セッションは 1 回だけにしてください。両方の FTD を設定する際に、すでに 1 つのデータがあるはずです。

Screen 内のコマンドはすべて Ctrl+A で開始します。

基本的なスクリーン コマンド:

Screen セッションに(コマンドラインから)再接続する

screen -r

画面セッションから退出

Ctrl+A → d

スクリーン セッション内に新しいウィンドウを作成する

Ctrl+A → c

同じ画面セッションでウィンドウを切り替える

Ctrl+A → n(前方)Ctrl+A → p(戻る)

Screen セッションで現在のウィンドウを強制終了する

Ctrl+A → k

分割スクリーン

Screen では、ターミナルを複数のウィンドウに分割できます。

f1cbf1258cf0a5a.png

screen のコマンドにアクセスするには、Ctrl+A キーを押します。すべてのコマンドは、このアクセスキーの組み合わせで始まる必要があります。

Codelab に正確に従っている場合は、同じ Screen インスタンスに 2 つのウィンドウ(FTD Commissioner、FTD Joiner)があるはずです。画面を分割するには、まず既存の画面セッションを開始します。

$ screen -r

いずれかの FTD デバイスを使用している必要があります。画面上の手順は次のとおりです。

  1. Ctrl+A → S キーでウィンドウを水平方向に分割
  2. Ctrl+A → Tab: カーソルを新しい空白ウィンドウに移動する
  3. Ctrl+A → n キーを押すと、新しいウィンドウが切り替わります
  4. 上部のウィンドウと同じ場合は、Ctrl+A → n キーをもう一度押して、別の FTD デバイスを表示します。

両方が表示されるようになりました。モードを切り替えるには、Ctrl+A → Tab キーを使用します。混乱を避けるため、Ctrl+A → A で各ウィンドウのタイトルを変更することをおすすめします。

高度な授業・利用向け

画面をさらに分割して ot-daemon ログと RCP Joiner ot-ctl を表示するには、これらのサービスを同じ画面インスタンス内で開始する必要があります。そのためには、ot-daemon を停止して ot-ctl を終了し、新しい画面ウィンドウで再起動します(Ctrl+A → c)。

この設定は必須ではなく、ユーザーの演習として残しておきます。

ウィンドウを分割して移動するには、次のコマンドを使用します。

新しいウィンドウを作成

Ctrl+A → c

ウィンドウを縦に分割

Ctrl+A →

ウィンドウを水平に分割

Ctrl+A → S

次に表示されるウィンドウに移動する

Ctrl+A → Tab

表示されたウィンドウを前後に切り替える

Ctrl+A → n または p

現在のウィンドウの名前を変更する

Ctrl+A → A

Ctrl+A → d キーを押していつでも Screen を終了し、コマンドラインから screen -r を使用して再度アタッチします。

Screen の詳細については、GNU Screen クイック リファレンスをご覧ください。

7. Thread ネットワークを作成する

すべてのターミナル ウィンドウと画面を設定したので、Thread ネットワークを作成しましょう。FTD コミッショナーで、新しい運用データセットを作成し、アクティブなデータセットとして commit します。運用データセットは、作成する Thread ネットワークの構成です。

## FTD Commissioner ##
----------------------

> dataset init new
Done
> dataset
Active Timestamp: 1
Channel: 11
Channel Mask: 07fff800
Ext PAN ID: c0de7ab5c0de7ab5
Mesh Local Prefix: fdc0:de7a:b5c0/64
Network Key: 1234c0de7ab51234c0de7ab51234c0de
Network Name: OpenThread-c0de
PAN ID: 0xc0de
PSKc: ebb4f2f8a68026fc55bcf3d7be3e6fe4
Security Policy: 0, onrcb
Done

後で使用できるように、ネットワーク キー 1234c0de7ab51234c0de7ab51234c0de をメモしておきます。

このデータセットをアクティブなデータセットとして commit します。

> dataset commit active
Done

IPv6 インターフェースを起動します。

> ifconfig up
Done

スレッド プロトコル オペレーションを開始します。

> thread start
Done

しばらく待ってから、デバイスの状態を確認します。リーダーである必要があります。後で参照できるように RLOC16 も入手します。

## FTD Commissioner ##
----------------------

> state
leader
Done
> rloc16
0c00
Done

デバイスの IPv6 アドレスを確認します。

## FTD Commissioner ##
----------------------

> ipaddr
fdc0:de7a:b5c0:0:0:ff:fe00:fc00        # Leader Anycast Locator (ALOC)
fdc0:de7a:b5c0:0:0:ff:fe00:c00         # Routing Locator (RLOC)
fdc0:de7a:b5c0:0:6394:5a75:a1ad:e5a    # Mesh-Local EID (ML-EID)
fe80:0:0:0:1cd6:87a9:cb9d:4b1d         # Link-Local Address (LLA)

「Codelab」は他の Thread デバイスからスキャンしたときにネットワークが表示されるようになりました。

RCP Joinerot-ctl から:

## RCP Joiner ##
----------------

> scan
| PAN  | MAC Address      | Ch | dBm | LQI |
+------+------------------+----+-----+-----+
| c0de | 1ed687a9cb9d4b1d | 11 | -36 | 232 |

FTD Joiner の OpenThread CLI から:

## FTD Joiner ##
----------------

> scan
| PAN  | MAC Address      | Ch | dBm | LQI |
+------+------------------+----+-----+-----+
| c0de | 1ed687a9cb9d4b1d | 11 | -38 | 229 |

「Codelab」ネットワークがリストに表示されない場合は、もう一度スキャンをお試しください。

8. RCP Joiner を追加する

Thread コミッショニングがネットワークでアクティブになっていないため、帯域外コミッショニング プロセスを使用して作成した Thread ネットワークに RCP Joiner を追加する必要があります。

FTD コミッショナーでは、ネットワーク キーをメモしました(例: 1234c0de7ab51234c0de7ab51234c0de)。ネットワーク キーを再度検索する必要がある場合は、FTD コミッショナーで次のコマンドを実行します。

## FTD Commissioner ##

> dataset networkkey
1234c0de7ab51234c0de7ab51234c0de
Done

次に、[RCP Joiner] で、そのアクティブなデータセットのネットワーク キーを FTD Commissioner ネットワーク キーに設定します。

## RCP Joiner ##
----------------

> dataset networkkey 1234c0de7ab51234c0de7ab51234c0de
Done
> dataset commit active
Done

データセットが正しく設定されていることを確認します。

## RCP Joiner ##
----------------

> dataset
Network Key: 1234c0de7ab51234c0de7ab51234c0de

Thread を起動して RCP Joiner が「Codelab」に参加できるようにする接続します数秒待ってから、状態、RLOC16 とその IPv6 アドレスを確認します。

## RCP Joiner ##
----------------

> ifconfig up
Done
> thread start
Done
> state
child
Done
> rloc16
0c01
Done
> ipaddr
fdc0:de7a:b5c0:0:0:ff:fe00:0c01         # Routing Locator (RLOC)
fdc0:de7a:b5c0:0:66bf:99b9:24c0:d55f    # Mesh-Local EID (ML-EID)
fe80:0:0:0:18e5:29b3:a638:943b          # Link-Local Address (LLA)
Done

後で使用するため、メッシュローカル IPv6 アドレス(ここでは fdc0:de7a:b5c0:0:66bf:99b9:24c0:d55f)をメモします。

FTD コミッショナーに戻り、ルーターと子のテーブルで、両方のデバイスが同じネットワークに属していることを確認します。RLOC16 を使用して RCP Joiner を特定します。

## FTD Commissioner ##
----------------------

> router table
| ID | RLOC16 | Next Hop | Path Cost | LQ In | LQ Out | Age | Extended MAC     |
+----+--------+----------+-----------+-------+--------+-----+------------------+
|  3 | 0x0c00 |        3 |         0 |     0 |      0 |  35 | 1ed687a9cb9d4b1d |

Done
> child table
| ID  | RLOC16 | Timeout    | Age        | LQ In | C_VN |R|S|D|VER| Extended MAC     |
+-----+--------+------------+------------+-------+------+-+-+-+---+------------------+
|   1 | 0x0c01 |        240 |         25 |     3 |   89 |1|1|1|  2| 1ae529b3a638943b |
Done

RCP Joiner のメッシュローカル アドレス(RCP Joiner の ipaddr 出力から取得したメッシュ ローカル アドレス)に ping して、接続を確認します。

## FTD Commissioner ##
----------------------

> ping fdc0:de7a:b5c0:0:66bf:99b9:24c0:d55f
> 8 bytes from fdc0:de7a:b5c0:0:66bf:99b9:24c0:d55f: icmp_seq=1 hlim=64 time=40ms

以下のトポロジ図に示すように、2 つのノードで構成される Thread ネットワークが完成しました。

otcodelab_top01C_2nodes.png

トポロジ図

この Codelab の残りの部分では、ネットワークの状態が変わるたびに新しいスレッド トポロジ図を示します。ノードのロールは次のように表されます。

b75a527be4563215.png

ルーターは常に五角形であり、エンドデバイスは常に円形です。各ノードの数字は、その時点での各ノードの現在のロールと状態に応じて、CLI 出力に表示されるルーター ID または子 ID を表します。

9. FTD Joiner をコミッションする

3 つ目の Thread デバイスを「Codelab」に追加しましょう。接続します今回は、より安全な帯域内コミッショニング プロセスを使用し、FTD Joiner のみが参加できるようにします。

FTD Joiner で、FTD コミッショナーが識別できるように eui64 を取得します。

## FTD Joiner ##
----------------

> eui64
2f57d222545271f1
Done

FTD コミッショナーでコミッショナーを開始し、参加できるデバイスの eui64 と Joiner の認証情報(J01NME など)を指定します。Joiner 認証情報は、すべて大文字の英数字(0 ~ 9 と A ~ Y。読みやすくするために I、O、Q、Z を除く)で構成されたデバイス固有の文字列で、長さは 6 ~ 32 文字です。

## FTD Commissioner ##
----------------------

> commissioner start
Done
> commissioner joiner add 2f57d222545271f1 J01NME
Done

[FTD Joiner] に切り替えます。FTD コミッショナーで設定した Joiner 認証情報を使用して、Joiner ロールを開始します。

## FTD Joiner ##
----------------

> ifconfig up
Done
> joiner start J01NME
Done

1 分ほどで、認証が成功したことを示す確認メッセージが表示されます。

## FTD Joiner ##
----------------

>
Join success

Thread を起動して FTD Joiner が「Codelab」に参加すぐに状態と RLOC16 を確認します。

## FTD Joiner ##
----------------

> thread start
Done
> state
child
Done
> rloc16
0c02
Done

デバイスの IPv6 アドレスを確認します。ALOC がないことを確認します。これは、このデバイスがリーダーではなく、ALOC を必要とするエニーキャスト固有のロールを保持していないためです。

## FTD Joiner ##
----------------

> ipaddr
fdc0:de7a:b5c0:0:0:ff:fe00:c02         # Routing Locator (RLOC)
fdc0:de7a:b5c0:0:3e2e:66e:9d41:ebcd    # Mesh-Local EID (ML-EID)
fe80:0:0:0:e4cd:d2d9:3249:a243         # Link-Local Address (LLA)

すぐに FTD コミッショナーに切り替えてルーターと子のテーブルを調べ、「Codelab」に 3 つのデバイスが存在することを確認します。network:

## FTD Commissioner ##
----------------------

> router table
| ID | RLOC16 | Next Hop | Path Cost | LQ In | LQ Out | Age | Extended MAC     |
+----+--------+----------+-----------+-------+--------+-----+------------------+
|  3 | 0x0c00 |        3 |         0 |     0 |      0 |  50 | 1ed687a9cb9d4b1d |

> child table
| ID  | RLOC16 | Timeout    | Age        | LQ In | C_VN |R|S|D|N| Extended MAC     |
+-----+--------+------------+------------+-------+------+-+-+-+-+------------------+
|   1 | 0x0c01 |        240 |         25 |     3 |   89 |1|1|1|1| 1ae529b3a638943b |
|   2 | 0x0c02 |        240 |         15 |     3 |   44 |1|1|1|1| e6cdd2d93249a243 |
Done

RLOC16 に基づいて、FTD Joiner はエンドデバイス(子)としてネットワークに接続しています。更新後のトポロジは次のとおりです。

otcodelab_top01C_ed01.png

10. スレッドの実例

この Codelab の Thread デバイスは、ルーター適格エンド デバイス(REED)と呼ばれる特定のタイプのフルスレッド デバイス(FTD)です。つまり、ルーターまたはエンドデバイスとして機能し、エンドデバイスからルーターに自身を昇格させることができます。

Thread は最大 32 台のルーターをサポートできますが、ルーターの数を 16 ~ 23 に維持しようとします。REED がエンドデバイス(子)として接続され、Router の数が 16 未満の場合、2 分間のランダムな時間が経つと、REED は自動的に Router に昇格します。

FTD Joiner を追加した後に Thread ネットワークに子が 2 人いる場合は、2 分以上待ってから、FTD Commissioner でルーターと子テーブルを再確認します。

## FTD Commissioner ##
----------------------

> router table
| ID | RLOC16 | Next Hop | Path Cost | LQ In | LQ Out | Age | Extended MAC     |
+----+--------+----------+-----------+-------+--------+-----+------------------+
|  3 | 0x0c00 |        3 |         0 |     0 |      0 |  50 | 1ed687a9cb9d4b1d |
| 46 | 0xb800 |       63 |         0 |     3 |      3 |   1 | e6cdd2d93249a243 |

> child table
| ID  | RLOC16 | Timeout    | Age        | LQ In | C_VN |R|S|D|N| Extended MAC     |
+-----+--------+------------+------------+-------+------+-+-+-+-+------------------+
|   1 | 0x0c01 |        240 |         61 |     3 |   89 |1|1|1|1| 1ae529b3a638943b |
Done

FTD Joiner(拡張 MAC = e6cdd2d93249a243)が自身をルーターに昇格しました。RLOC16 は異なることに注意してください(0c02 ではなく b800)。これは、RLOC16 がデバイスのルーター ID と子 ID に基づいているためです。エンドデバイスからルーターに移行すると、ルーター ID と子 ID の値が変更され、RLOC16 も変更されます。

otcodelab_top01C.png

FTD Joiner で新しい状態と RLOC16 を確認します。

## FTD Joiner ##
----------------

> state
router
Done
> rloc16
b800
Done

FTD Joiner をダウングレードする

この動作をテストするには、ルーターからエンドデバイスに手動で FTD Joiner をダウングレードします。状態を子に変更し、RLOC16 を確認します。

## FTD Joiner ##
----------------

> state child
Done
> rloc16
0c03
Done

otcodelab_top01C_ed02.png

FTD コミッショナーに戻ると、子テーブル(ID = 3)に FTD Joiner が表示されます。移行中は、両方に含まれることもあります。

## FTD Commissioner ##
----------------------

> router table
| ID | RLOC16 | Next Hop | Path Cost | LQ In | LQ Out | Age | Extended MAC     |
+----+--------+----------+-----------+-------+--------+-----+------------------+
|  3 | 0x0c00 |        3 |         0 |     0 |      0 |  50 | 1ed687a9cb9d4b1d |
| 46 | 0xb800 |       63 |         0 |     3 |      3 |   1 | e6cdd2d93249a243 |

> child table
| ID  | RLOC16 | Timeout    | Age        | LQ In | C_VN |R|S|D|N| Extended MAC     |
+-----+--------+------------+------------+-------+------+-+-+-+-+------------------+
|   1 | 0x0c01 |        240 |         61 |     3 |   89 |1|1|1|1| 1ae529b3a638943b |
|   3 | 0x0c03 |        240 |         16 |     3 |   94 |1|1|1|1| e6cdd2d93249a243 |
Done

しばらくすると、RLOC が b800 の Router に戻ります。

otcodelab_top01C.png

リーダーを削除する

リーダーはすべての Thread ルーターの中で自己選出されます。つまり、現在のリーダーが Thread ネットワークから削除されると、他のルーターの 1 つが新しいリーダーになります。

FTD コミッショナーで、Thread をシャットダウンして Thread ネットワークから削除します。

## FTD Commissioner ##
----------------------

> thread stop
Done
> ifconfig down
Done

2 分以内に、FTD Joiner が新しい Thread リーダーになります。FTD Joiner の状態と IPv6 アドレスを調べて、以下を確認します。

## FTD Joiner ##
----------------

> state
leader
Done
> ipaddr
fdc0:de7a:b5c0:0:0:ff:fe00:fc00       # Now it has the Leader ALOC!
fdc0:de7a:b5c0:0:0:ff:fe00:b800
fdc0:de7a:b5c0:0:3e2e:66e:9d41:ebcd
fe80:0:0:0:e4cd:d2d9:3249:a243
Done

otcodelab_top02C_01.png

子テーブルを確認します。新しい RLOC16 が表示されます。ID と拡張 MAC で示される RCP ジョインナーです。Thread ネットワークをまとめるために、親ルーターを FTD コミッショナーから FTD Joiner に切り替えました。これにより、RCP Joiner に新しい RLOC16 が生成されます(ルーター ID が 3 から 46 に変更されているため)。

## FTD Joiner ##
----------------

> child table
| ID  | RLOC16 | Timeout    | Age        | LQ In | C_VN |R|S|D|N| Extended MAC     |
+-----+--------+------------+------------+-------+------+-+-+-+-+------------------+
|   1 | 0xb801 |        240 |         27 |     3 |  145 |1|1|1|1| 1ae529b3a638943b |
Done

RCP Joiner が子として FTD Joiner にアタッチされるまで数分かかる場合があります。状態と RLOC16 をチェックして、次のことを確認します。

## RCP Joiner ##
--------------

> state
child
> rloc16
b801

FTD コミッショナーを再度アタッチする

2 つのノードを持つ Thread ネットワークはあまり楽しくありません。FTD コミッショナーをオンラインに戻しましょう。

FTD Commissioner で、Thread を再起動します。

## FTD Commissioner ##
----------------------

> ifconfig up
Done
> thread start
Done

2 分以内に自動的に「Codelab」に再アタッチされます。その後、自身をルーターに昇格させます。

## FTD Commissioner ##
----------------------

> state
router
Done

FTD Joiner のルーターと子テーブルで以下を確認します。

## FTD Joiner ##
----------------

> router table
| ID | RLOC16 | Next Hop | Path Cost | LQ In | LQ Out | Age | Extended MAC     |
+----+--------+----------+-----------+-------+--------+-----+------------------+
|  3 | 0x0c00 |       63 |         0 |     3 |      3 |   0 | 1ed687a9cb9d4b1d |
| 46 | 0xb800 |       46 |         0 |     0 |      0 |  15 | e6cdd2d93249a243 |

> child table
| ID  | RLOC16 | Timeout    | Age        | LQ In | C_VN |R|S|D|N| Extended MAC     |
+-----+--------+------------+------------+-------+------+-+-+-+-+------------------+
|   1 | 0xb801 |        240 |        184 |     3 |  145 |1|1|1|1| 1ae529b3a638943b |
Done

otcodelab_top02C_02.png

ここでも Thread ネットワークは 3 つのノードで構成されています。

11. トラブルシューティング

異なるターミナルや画面ウィンドウで複数のデバイスを使用する Thread ネットワークの管理は、複雑になることがあります。次のヒントを参考にして「リセット」してください。問題が発生した場合にネットワークやワークスペースの状態を確認し、

画面

構成で混乱してしまった場合は(画面ウィンドウが多すぎる、または画面内の画面が多すぎる)、Ctrl+A → K を使用して画面ウィンドウを強制終了し、何も表示されなくなるまで画面ウィンドウを強制終了し、コマンドラインの screen -lsNo Sockets found を出力します。その後、デバイスごとに画面ウィンドウを再作成します。画面が強制終了されても、デバイスの状態は保持されます。

スレッドノード

Thread ネットワーク トポロジがこの Codelab に記載されていない場合や、ノードがなんらかの理由で(ノードに電力を供給している Linux マシンがスリープ状態になったため)切断された場合は、Thread を停止し、ネットワーク認証情報を消去して、Thread ネットワークを作成するステップからやり直すことをおすすめします。

FTD をリセットするには:

## FTD Commissioner or FTD Joiner ##
------------------------------------

> thread stop
Done
> ifconfig down
Done
> factoryreset
Done

RCP は、ot-ctl を使用して同じ方法でリセットできます。

## RCP Joiner ##
----------------

> thread stop
Done
> ifconfig down
Done
> factoryreset
Done

12. マルチキャストの使用

マルチキャストは、デバイスのグループに一度に情報を伝達するために使用します。Thread ネットワークでは、スコープに応じて異なるデバイス グループでマルチキャスト用に特定のアドレスが予約されます。

IPv6 アドレス

範囲

配送先

ff02::1

リンクローカル

すべての FTD と MED

ff02::2

リンクローカル

すべての FTD とボーダー ルーター

ff03::1

メッシュローカル

すべての FTD と MED

ff03::2

メッシュローカル

すべての FTD とボーダー ルーター

この Codelab ではボーダー ルーターを使用しないため、FTD と MED の 2 つのマルチキャスト アドレスに注目します。

リンクローカル スコープは、単一の無線通信または単一の「ホップ」で到達可能なすべてのスレッド インターフェースで構成されます。ネットワーク トポロジによって、どのデバイスが ff02::1 マルチキャスト アドレスへの ping に応答するかが決まります。

FTD コミッショナーから ff02::1 に ping します。

## FTD Commissioner ##
----------------------

> ping ff02::1
> 8 bytes from fe80:0:0:0:e4cd:d2d9:3249:a243: icmp_seq=2 hlim=64 time=9ms

ネットワークには他の 2 台のデバイス(FTD Joiner と RCP Joiner)がありますが、FTD コミッショナーは FTD Joiner のリンクローカル アドレス(LLA)からの応答を 1 つだけ受信しました。つまり、FTD コミッショナーがシングルホップでアクセスできるデバイスは FTD Joiner のみとなります。

otcodelab_top02C_02_LL.png

次に、FTD Joiner から ff02::1 に ping します。

## FTD Joiner ##
----------------

> ping ff02::1
> 8 bytes from fe80:0:0:0:1cd6:87a9:cb9d:4b1d: icmp_seq=1 hlim=64 time=11ms
8 bytes from fe80:0:0:0:18e5:29b3:a638:943b: icmp_seq=1 hlim=64 time=24ms

回答は 2 つです。他のデバイスの IPv6 アドレスを確認すると、1 つ目(末尾が 4b1d)は FTD Commissioner の LLA で、2 つ目(末尾は 943b)は RCP Joiner の LLA です。

otcodelab_top02C_02_LL02.png

つまり、FTD Joiner は FTD Commissioner と RCP Joiner の両方に直接接続され、これによりトポロジが確認されます。

メッシュローカル

Mesh-Local のスコープは、同じ Thread ネットワーク内で到達可能なすべての Thread インターフェースで構成されます。ff03::1 マルチキャスト アドレスへの ping に対するレスポンスを見てみましょう。

FTD コミッショナーから ff03::1 に ping します。

## FTD Commissioner ##
----------------------

> ping ff03::1
> 8 bytes from fdc0:de7a:b5c0:0:0:ff:fe00:b800: icmp_seq=3 hlim=64 time=9ms
8 bytes from fdc0:de7a:b5c0:0:66bf:99b9:24c0:d55f: icmp_seq=3 hlim=64 time=68ms

今回、FTD コミッショナーは 2 つのレスポンスを受け取りました。1 つは FTD Joiner's Routing Locator(RLOC、末尾が b800)から、もう 1 つは RCP Joiner のメッシュ ローカル EID(ML-EID、d55f で終わる)からのレスポンスです。これは、メッシュローカル スコープが Thread ネットワーク全体を構成するためです。デバイスは、ネットワーク内の場所にかかわらず、ff03::1 アドレスに登録されます。

otcodelab_top02C_02_ML.png

FTD Joiner から ff03::1 に ping して、同じ動作を確認します。

## FTD Joiner ##
----------------

> ping ff03::1
> 8 bytes from fdc0:de7a:b5c0:0:0:ff:fe00:c00: icmp_seq=2 hlim=64 time=11ms
8 bytes from fdc0:de7a:b5c0:0:66bf:99b9:24c0:d55f: icmp_seq=2 hlim=64 time=23ms

otcodelab_top02C_02_LL02.png

両方の ping 出力で RCP Joiner の応答時間を確認します。RCP Joiner は、FTD Joiner に到達するまでに要した時間(23 ms)よりも、FTD コミッショナーに到達するまでにはるかに長い時間がかかっています(68 ms)。これは、FTD コミッショナーに到達するまでに 2 ホップする必要があるのに対し、FTD Joiner は 1 ホップする必要があるためです。

また、メッシュローカル マルチキャスト ping が RCP Joiner ではなく、2 つの FTD に対してのみ RLOC で応答したことにもお気づきかもしれません。これは、FTD がネットワーク内のルーターであり、RCP がエンドデバイスであるためです。

RCP Joiner の状態を確認します。

## RCP Joiner ##
----------------

> state
child

13. UDP でメッセージを送信する

OpenThread が提供するアプリケーション サービスの 1 つに、Transport Layer プロトコルである User Datagram Protocol(UDP)があります。OpenThread 上に構築されたアプリケーションは、UDP API を使用して、Thread ネットワーク内のノード間や、外部ネットワーク内の他のデバイス(Thread ネットワークにボーダー ルーター機能がある場合はインターネットなど)にメッセージを渡すことができます。

UDP ソケットは OpenThread CLI を介して公開されます。これを使用して、2 つの FTD 間でメッセージをやり取りしてみましょう。

FTD Joiner のメッシュローカル EID アドレスを取得します。Thread ネットワーク内のどこからでも到達可能であるため、このアドレスを使用しています。

## FTD Joiner ##
----------------

> ipaddr
fdc0:de7a:b5c0:0:0:ff:fe00:fc00        # Leader Anycast Locator (ALOC)
fdc0:de7a:b5c0:0:0:ff:fe00:b800        # Routing Locator (RLOC)
fe80:0:0:0:e4cd:d2d9:3249:a243         # Link-Local Address (LLA)
fdc0:de7a:b5c0:0:3e2e:66e:9d41:ebcd    # Mesh-Local EID (ML-EID)
Done

UDP を起動し、任意の IPv6 アドレスのソケットにバインドします。

## FTD Joiner ##
----------------

> udp open
Done
> udp bind :: 1212

FTD コミッショナーに切り替えて UDP を起動し、ML-EID を使用して FTD Joiner に設定したソケットに接続します。

## FTD Commissioner ##
----------------------

> udp open
Done
> udp connect fdc0:de7a:b5c0:0:3e2e:66e:9d41:ebcd 1212
Done

2 つのノード間で UDP 接続が確立されている必要があります。FTD コミッショナーからメッセージを送信します。

## FTD Commissioner ##
----------------------

> udp send hellothere
Done

FTD Joiner で、UDP メッセージを受信しました。

## FTD Joiner ##
----------------

> 10 bytes from fdc0:de7a:b5c0:0:0:ff:fe00:c00 49153 hellothere

14. 完了

これで、Thread の物理的なネットワークが作成されました。

b915c433e7027cc7.png

学習しました。

  • Thread のデバイスタイプ、ロール、スコープの違い
  • Thread デバイスがネットワーク内で状態を管理する方法
  • UDP を使用してノード間で単純なメッセージを渡す方法

次のステップ

この Codelab をベースに、次の演習に挑戦してみましょう。

  • ot-cli-mtd バイナリを使用して FTD Joiner ボードを MTD として再フラッシュし、自身をルーターにアップグレードしたり、リーダーになることを試みたりしないことを確認します。
  • ネットワークにデバイスをさらに追加し(別のプラットフォームを試してください)、ルーターと子テーブル、マルチキャスト アドレスへの ping を使用してトポロジを描きます。
  • pyspinel を使用して NCP を制御する
  • OpenThread ボーダー ルーターを使用して NCP をボーダー ルーターに変換し、Thread ネットワークをインターネットに接続する

関連情報

以下のような OpenThread リソースについては、openthread.ioGitHub をご覧ください。

関連資料: