# TWELITE SDK (MWSDK) マニュアル

TWELITE SDK は、モノワイヤレス株式会社が製造販売する TWELITE (トワイライト) 無線モジュールのファームウェアをビルドするための環境を提供します。本資料では MWSDK と記述することもあります。

{% hint style="info" %}
TWELITE によるアプリケーションの書き換えやプログラミングを行う場合は、まず以下を参照ください。
{% endhint %}

|               | 詳細                                                                                                           |
| ------------- | ------------------------------------------------------------------------------------------------------------ |
| TWELITE STAGE | ビルド、書き込み、ビューア（ターミナルや簡易モニタなど）を、一つのアプリで行えます。→ [TWELITE STAGEの解説](https://mono-wireless.com/jp/products/stage/) |
| MWXライブラリ      | `setup(), loop()` を定義するより単純なプログラミングを行うためのC++ライブラリです。→ [MWXライブラリの解説](https://mwx.twelite.info)                |

TWELITE SDK (MWSDK) には以下が含まれます。

* コンパイルを行うためのツール群 (gcc, make など)
* TWELITE NET ライブラリ
  * マイコンなどの低水準ライブラリを含む
  * mwx ライブラリ
  * その他、ライブラリ
* TWELITE SDK マニュアル（本資料）
  * MWSDK フォルダや MWSDK全般の解説。
  * TWELITE STAGEを用いずに、アプリを書き換えたり、ソースコードからビルドする方法。
  * ファームウェア書き換え方法についての詳細。
  * 無線パケットや中継ネットワークについての解説。
  * TWELITE NET C ライブラリの API についての解説
    * イベントループなど内部処理の解説。

### 本資料の記載内容について

下記に関する用語については、文中では特に説明を行っていません。

* C言語によるマイコン開発について
* bash, make などコマンドラインの利用
* gcc ツールチェインの利用

### 本資料の表記について

* フォルダ（パス）区切りを / (スラッシュ) で統一します。Windows では \ (バックスラッシュまたは円マーク) ですが、読み替えて下さい。
* 表中で `\` ( バックスラッシュと空白) の２文字を挿入している場合があります。表示時に途中改行を促すものです。(例: `veryVeryLong\ DefName` は `veryVeryLongDefName` と読み替えてください。


# はじめに

{% hint style="success" %}
[資料の取り扱いについて](https://twelite.gitbook.io/general/about_documents)をご参照ください。  お気付きの点がありましたら、当サポート窓口にご連絡いただければ幸いです。
{% endhint %}


# TWELITE SDK 利用規定

本SDKの添付物（ソースコード、ライブラリ、資料）については、別途ライセンス記述があるものはその記述に従った上で、[モノワイヤレスソフトウェア使用許諾契約書](/overview/mwsla)(MW-SLA-1)に基づき取り扱われます。

MW-SLA-1 に基づき（別記ライセンスがある場合は、これに基づく）、お客さまはTWELITE SDK により生成した成果物は商用を含め利用できます。また、改変部分の開示義務はありません。

お客さまが改変したソースコードを公開する場合は、MW-SLA-1ライセンスに基づき、これを添付して公開してください。これ以外の取り扱いが必要なお客様は、当社サポート宛にお問い合わせください。

[資料の取り扱いについて](https://twelite.gitbook.io/general/about_documents)をご参照ください。&#x20;

> ※ お気付きの点がありましたら、当サポート窓口にご連絡いただければ幸いです。

### TWELITE NET (別名 TWENET, ToCoNet) ライブラリについて

{% hint style="warning" %}

* MW-SLA-1 に基づき取り扱われます。
* TWELITE NET ライブラリは無保証です。
* TWELITE NET ライブラリのバージョン間の互換性は保証しません。
  {% endhint %}


# サポート、対応

要望の依頼、問題の報告はモノワイヤレス株式会社の[技術問い合わせ窓口](https://mono-wireless.com/jp/contact/)にお願いいたします。ただし、当技術窓口は、別途サポート契約のあるお客さまに対して回答のお約束をしております。場合によってはご要望にお応え出来なかったり、ご返答できない場合もございます。予めご了承下さい。

以下にサポートサービスでの実施事項と対象外を記載します（2017/1-2版を元にしますが、サービス内容は予告なく変更されます）。サポートサービス契約がないお客さまにあっても、当サポートの原則としてご一読下さい。

### サポートサービス実施事項（参考）

TWELITE NETを用いたファームウェア作成方法（ツールの基本的な使用方法、基本的な送受信手続き、ペリフェラルAPIの使用方法、基本設計や考え方についての助言など）として基本的な送受信APIに基づく無線通信を行う方法について解説を行います。ただし、以下の内容または方法での案内はいたしません。

* 弊社が標準的に提供するTWELITE NET の手続きや弊社が案内するマニュアル類の記載を超える方法
  * IEEE802.15.4 MAC層または独自のMAC層は対応しません。
  * ZigBee PRO スタックライブラリは対応しません。
* TWELITE NET を用いたファームウェア開発方法についての、網羅的な解説を一度に実施すること
* TWELITE NET の内部情報や、規格書の定義に基づく解説
* お客様のアプリケーションを実現するために特有の手法やアルゴリズム周辺ハードウェア、筺体設計、アンテナ設置、無線を用いたシステム設計に関する助言

### サポートサービス対象外の内容（参考）

* パソコンの操作方法やオペレーティングシステム、弊社の商品以外の操作方法やデバイスドライバのインストール方法やそれらに関連した不具合解決。（各商品のメーカーにお問い合わせください。）
* ツールの使用法で、本モジュール向けのファームウェアのビルドに直接関係のない機能のお問い合わせ。（ツールの画面の色の変更方法など）
* ツールの使用法で、サポートでご案内する設定以外での使用。（特殊なフォルダで使用したい、弊社未確認のパッチを適用するなど）
* 他のツールやインストール環境の影響でツールが正常動作しない場合の回避方法の提示やツールの修正。 （クリーンインストール環境での使用をご案内します）
* お客様が作成されたファームウェアを前提とした対応。（問題を切り出し一般化した上でのお問い合わせをお願いします。）
* デバッグ、開発行為、性能評価に相当する対応。（お客様作成コードの問題点の特定、お客様のハードウェアで使用される他社製品部品のデータシートの読みこなし、弊社が参考として例示したソースコードや資料をお客様が十分読みこなしされない状態でのご質問などは十分なお答えが出来ない場合がございます。）
* API、開発ツールなどの不備に対する修正。（報告された現象については可能な限りの回避策のご提案を行います。）
* マニュアル等に記載されない非公開情報の開示。
* ツールの使用が起因で発生した、パソコン等の故障・データ損失・その他損害に対する保障。
* 弊社営業日以外の対応。
* 担当者を指定した回答要求。
* オンサイト、出張を伴う対応。


# モノワイヤレスソフトウェア使用許諾書

最新版のライセンスは[リンク先](https://mono-wireless.com/jp/products/TWE-NET/license.html)を参照してください。

{% code title="MW-SLA-1J.txt" %}

```

              モノワイヤレスソフトウェア使用許諾契約書

    VERSION 1, 8-DEC-2016 (MW-SLA-1J)
    Copyright (C) 2016 Mono Wireless Inc.

    本契約は、モノワイヤレス株式会社（以下、ライセンサー）が提供するソフト
ウェア製品（以下、本製品）をお客様（ライセンシー）がご利用する際に必要とな
る使用許諾を締結するものです。

    第１条（定義）
    １．本契約において、「本製品」とは、ライセンサーが提供するソースコード
およびライブラリ、スクリプトファイル、ユーティリティならびに取扱い説明書な
ど一式をいいます。
    ２．本契約において「知的財産権」とは、著作権、特許権（特許出願権を含む）、
商標権、ノウハウおよびその他の知的創作物に対する権利または法律上の利益をい
います。

    第２条（知的財産権の帰属）
    本製品に対する知的財産権の一切は、ライセンサーに帰属します。本契約の締
結によっても本製品の知的財産権がライセンサーからライセンシーに移転するもの
ではありません。

第３条（使用許諾）
    ライセンサーは、本契約の全項目に合意することを条件として、ライセンシー
に対し次の各号について非排他的な許諾を付与します。
    （１）本製品を、ライセンサー製の無線マイコンを用いたシステム内で利用す
ること
    （２）本製品におけるソースコードを、ライセンサー製の無線マイコン上向け
にビルドし、ライセンサー製の無線マイコン上で動作させること
    （３）本製品におけるソースコードの全部もしくは一部を修正、改変、翻訳、
翻案し、またはこれらを基づいて二次的著作物を創作すること
    （４）本契約の複製とともに、本製品におけるソースコード（前号を含む）を
複製、配布（商用目的も含む）すること

    第４条（禁止事項）
    ライセンシーは、次の各号の行為を行うことはできません。
    （１）本製品におけるソースコード（前条２号に定める修正、改変、翻訳、翻
案したソースコードおよび二次的著作物を含む）を、他社製のプロセッサ向けにビル
ド、動作、又は双方を行うこと
    （２）本製品（前条２号に定める修正、改変、翻訳、翻案したソースコードお
よび二次的著作物を含む）を、他社製プロセッサ上のシステムを開発する目的で利用
すること
    （３）本製品におけるライブラリ等、バイナリコードに対して、リバース・エ
ンジニアリング、逆コンパイル、逆アセンブルその他ソースコードおよび基礎とな
るアイデアまたはアルゴリズムの解析、再構築もしくは発見を試みること。

    第５条（免責）
    １．ライセンサーは、個別契約書に明示的に規定された場合を除き、「現状有
姿のまま」で本製品を提供します。ライセンサーは本製品の品質および機能がライ
センシーの使用目的に適合すること、中断または誤りなく動作すること、第三者の
知的財産権を侵害していないことおよびバグや不具合のないことを保証するもので
はなく、ライセンサーは本製品についての一切の責任は負いません。
    ２．ライセンサーは、本製品の使用または使用不能から発生した、直接的、間
接的、派生的、偶発的等いかなる損害に対して、一切責任を負わないものとします。
たとえライセンサーがかかる損害の可能性について知らされていた場合も同様です。
また、ライセンサーが損害賠償責任を負う事になった場合であっても、ライセンサー
の損害賠償責任は、その理由を問わず、本製品についてライセンシーが実際に支払っ
た金額を上限とします。

    第６条（譲渡）
    ライセンシーは、本契約に基づく権利または義務を第三者に譲渡することはで
きません。

    第７条（有効期間）
    本契約の有効期間は、ライセンサーが別途有効期間を定めた場合および本契約
の規定に従って解除される場合を除き、ライセンシーが本製品を使用した時からラ
イセンシーが本ソフトウェア製品の使用を停止するまでとします。

    第８条（本契約の解除）
    １．ライセンシーが本契約に違反した場合、ライセンサーは本契約を解除する
ことができます。この場合、ライセンシーは、本製品を一切使用することができな
いものとします。また、ライセンシーがライセンサーに支払った対価についても、
解除による返金には応じられません
    ２．ライセンシーは、本製品を破棄することにより本契約を終了させることが
できます。この場合、ライセンシーがライセンサーに支払った対価は返却いたしま
せん。
    ３．本契約が終了するか又は解除された場合、ライセンシーは、本製品をライ
センサーへ返却するか、または破棄するものとします。

    第９条（輸出の制限）
    ライセンシーは、輸出管理法令、日本の政府機関が要求する条件等を遵守する
ものとします。関連する輸出入に関する法規を順守せず、本製品を日本国外へ輸出
することおよび国外で使用することはできません。ライセンシーが本製品を日本国
外へ輸出または国外で使用した場合、当該行為から生ずる一切の責任はライセンシー
が負うものとします。

    第１０条（一般条項）
    １．本契約は、本製品の使用許諾に関し、本契約の締結以前にライセンシーと
ライセンサーとの間になされたすべての取り決めに優先して適用されます。
    ２．本契約は日本語版により締結され、当事者間のすべての伝達は日本語によ
るものします。この場合、本契約とその英訳に矛盾があった場合、日本語による本
契約の解釈を優先します．
    ３．本契約は、日本国法に準拠し、これに従って解釈されるものとします。
    ４．本契約に関連して発生した一切の紛争については、横浜地方裁判所を第一
審の専属的合意管轄裁判所とします。

                                                          以上
```

{% endcode %}


# TWELITE SDKの構成

### チップライブラリ

* TWELITE BLUE 用
* TWELITE RED用

### ツールチェイン

* GCC/MAKE など

### ファームウェア書換ツール

* TWE-Programmer (TWELITE 専用書換ツール, Windows専用)

### アプリケーション・サンプルコード

AppXXX はアプリケーションコードです。アプリケーションの最新版や開発途上版は[当社ウェブサイト](https://mono-wireless.com/jp/products/TWE-APPS/)よりダウンロードして下さい。

Samp\_XXX はサンプルコードです。単純な送受信を行ったり、I2Cなどのペリフェラルの取扱サンプルです。


# 最新版の取得

## TWELITE STAGE

{% hint style="info" %}
TWELITE NET 1.3.0 (2020/04) 以降は TWELITE STAGE として配布されます。

```
*** TWELITE STAGE フォルダ構成 ***
{STAGE TO FOLDER}/
  TWELITE_Stage.exe            -- STAGE 実行形式(Windowsの場合)
  dll/                         -- STAGE 実行用(Windowsの場合)
  TWELITE_Stage/               -- STAGE 関連ファイル
  BIN/                         -- .binファイル格納フォルダ
  
  MWSDK/                       -- TWELITE SDK(MWSDK)トップ
```

{% endhint %}

### リリース版

リリース版は、以下よりダウンロードしてください。MWSDK はTWELITE STAGEの配布物の一部となります。

{% embed url="<https://mono-wireless.com/jp/products/stage/index.html>" %}

## 正式リリース

{% hint style="info" %}
正式リリースには名前が付きます。名前の書式は `MWSTAGE2020_05` のように MWSTAGEに続いて {年}\_{月} を表記します。また TWELITE Stage ツールを含まない TWELITE SDK (MWSDK) のバージョンは、同様に `MWSDK2020_05` のように MWSDK に続いて {年}\_{月} です。

リリース名に `UNOFFICIAL` が付随する場合は「リリース間の更新」に対しての命名です。
{% endhint %}

以下より配布します。

> <https://mono-wireless.com/stage>

## リリース間の更新

リリース後に発見された問題や、サンプル等の更新などは、以下のGitHubリポジトリ（ソースコードやファイルを履歴を含めて格納したデータベース）に反映されます。

* [MWSDK\_COMMON](https://github.com/monowireless/MWSDK_COMMON) - MWSDK の共通部をまとめたレポジトリ。サブモジュールを用いているためGitの取り扱いに習熟している必要があります。
* [MWSDK\_COMMON\_SNAP](https://github.com/monowireless/MWSDK_COMMON_SNAP) - MWSDK の共通部を一括ダウンロードできるようにしたレポジトリ。zip形式でダウンロードできます。

{% hint style="warning" %}
これらの修正は中間的な内容、所定の動作確認などが省略されたものも含まれます。確認されていない副作用があったり、構成間の整合性が取れていない場合もあります。利用の可否はお客様のほうで判断いただくようお願い申し上げます。

原則としてリリース後の修正に対してのサポート対応は行っておりません。技術サポートは、リリース版をもとに依頼いただくようお願いいたします。

また、リリース後の修正に対して、お客様のほうで不都合など発見された場合は、お手数ですが技術サポートにご連絡頂けますと幸いです。

当サポートでは Git ならびに GitHub の利用方法についてのご質問はお受けできません。一般の解説などを参考いただくようお願い申し上げます。また、GitHubのサービスに対しては当社では対応できない場合もございます。
{% endhint %}

### MWSDK\_COMMON\_SNAP レポジトリ

> <https://github.com/monowireless/MWSDK_COMMON_SNAP/releases>

リリースごとのMWSDKファイル（共通部分）を一括格納しています。MWSDKの更新方法は、このリポジトリから zip ファイルをダウンロードして、フォルダやファイルを更新前のものと差し替えます。

リンク先には各リリース（暫定版はUNOFFICIAL）でのファイル一式へのリンクが含まれます。

![GitHub画面例](/files/-MGBJ2yY_8rPd9vWFHet)

レポジトリには以下のフォルダが含まれます。

* ChipLib
* LICENSE
* MkFiles
* TWENET

この４つのフォルダをTWELITE STAGEの配布フォルダ内で**差し替え**ます。

```
.../MWSTAGE/              --- TWELITE STAGE 配布フォルダ
        .../MWSDK         --- MWSDKフォルダ
              .../ChipLib <-- 以下の４フォルダを差し替える
              .../LICENSE
              .../MkFiles
              .../TWENET
```

### MWSDK\_COMMON レポジトリ

> <https://github.com/monowireless/MWSDK_COMMON>

このリポジトリにはMWSDKの共通部分のファイルを管理していますが、上述の MWSDK\_COMMON\_SNAP ではリリースごとのファイル差分のみに注目しているのに対して、各ライブラリやサンプルなどのレポジトリをサブモジュールとして、個別に更新履歴が参照できるようになっています。

{% hint style="warning" %}
zip ファイルによるダウンロードを行った場合、サブモジュールに対尾するフォルダにはファイルが格納されません。 (GitHubの仕様です)
{% endhint %}

#### リポジトリ利用について

* GITのsubmoduleを用いています。GitHubのサイトから.zip形式などでアーカイブをダウンロードした場合、submoduleの含まれるファイルは含まれません。(submodule付きのクローンを行うgitコマンド例は後述)
* MWSDK\_COMMON リポジトリは、配布の MWSDK フォルダから Tools フォルダと一部ファイル(Windows版の環境変数登録用の cmd ファイル)を除外したものです。Tools フォルダは配布済みのものを利用してください。

#### リポジトリからクローンする方法 (MWSDK 2020/04 以降)

ここでは、コマンドラインにて MWSDK の内容を GitHub からクローンする方法を記述します。あらかじめ git コマンドが利用できる環境を用意しておいてください。Windowsを利用の場合は bash を用いて作業することを想定します。

まず最初に配布のMWSDK(TWELITE STAGE)を展開しておきます。以下のような構成になっていると思います。

```
=== フォルダ構成 ===
.../MWSTAGE +- MWSDK +- TWENET
                      - ChipLib
                      - ...
                      - Tools               
```

配布時の MWSDK フォルダを別の名前に変更します。

```
$ cd .../MWSTAGE    ...はお客さまのインストールフォルダ
$ mv MWSDK MWSDK.orig

=== フォルダ構成 ===
.../MWSTAGE +- MWSDK.ORIG
                  +- TWENET
                   - ...
                   - Tools 
```

MWSTAGE フォルダ上で GitHubより MWSDK\_COMMON をクローンします。submodulesのファイルを取得するため`--recurse-submodules`オプションを追加します。

```
$ pwd
.../MWSTAGE
$ git clone --recurse-submodules https://github.com/monowireless/MWSDK_COMMON MWSDK
...(少し時間がかかります)

=== フォルダ構成 ===
.../MWSTAGE +- MWSDK
                  +- TWENET
                   - ... (Tools は含まれない)
             - MWSDK.ORIG
                  +- TWENET
                   - ...
                   - Tools 
```

最後に MWSDK.ORIG/Tools フォルダを MWSDK に移植します。

```
$ mv MWSDK.ORIG/Tools MWSDK/

=== フォルダ構成 ===
.../MWSTAGE +- MWSDK
                  +- TWENET
                   - ...
                   - Tools 
             - MWSDK.ORIG
                  +- TWENET
                   - ... (mv したのでTools は含まれない)
```

## TWELITE MWX ライブラリ SDK (2019/12)

MWXライブラリ専用の初版SDKです。

MWXによる開発は、最新版の TWELITE STAGE を利用ください。

## TWELITE NET 1.2.0 (2018/05) 以前

以下のリンクを参照ください。

{% embed url="<https://mono-wireless.com/jp/products/TWE-NET/index.html>" %}


# TWELITE SDK 改版履歴

MWSDK2020\_05以降の履歴情報は以下に記載します。

{% embed url="<https://github.com/monowireless/MWSDK_COMMON/blob/master/ReleaseNotes%2Emd>" %}

## MWSDK2020\_05

{% hint style="danger" %}
2019/12, 2020/04リリースのMWSDKを利用の場合は、更新を推奨します。
{% endhint %}

### 更新内容

* \[TWENET] イベントキューがスタックする場合があった
* \[TWENET] スリープ復帰後にシリアルポート出力がしない場合があった
* \[TWENET] スリープ復帰後に無線パケットの送受信キューのクリアをデフォルトの振る舞いとした
* \[TWENET] 重複チェッカ DUPCHK モジュールのパラメータを変更できるようにした
* \[MWX] 重複チェッカ duplicate\_checker の初期化等に不備があり期待通りの除去を行っていなかった
* \[MWX] format() の実装を機種依存の少ないものとした。また、引数を最大８までとした。64bit引数が含まれる場合は引数の数は制限される。
* MWSDK 以下 (Toolsフォルダ除く) を GitHub のレポジトリに格納した。

### 000manifest

```
NAME: MWSDK2020_05
DATE: 2020-05-29

COMMON FILES: https://github.com/monowireless/MWSDK_COMMON/releases/tag/MWSDK2020_05
  CHIP LIBRARY VERSION: SW4063V1416
  TWENET (TWELITE NET) C LIBRARY VERSION: L1303
  MWX C++ LIBRARY VERSION: https://github.com/monowireless/mwx/releases/tag/0.1.3
  TWESETTINGS LIBRARY: https://github.com/monowireless/twesettings/releases/tag/0.2.3
```

## MWSDK2020\_04

TWELITE STAGE に対応にした環境に変更しました。

* より記述内容が少なくなる Makefile に変更しました。\
  ※ 従来のプロジェクトでの Makefile から書き換えが必要になります。
* [mwx ライブラリ](https://mwx.twelite.info)に対応しました。

### TWELITE NET 1.2.0->1.3.0 の変更

* `Utils/Source/serial.[ch], uart.[ch]`UARTのflush時に異常なふるまい（文字化けなど）が発生する場合があった問題に対処。
* TickTimer, ADC完了イベントの消滅を抑制する実装をした。他のハードイベントが重なったときに内部キューに貯められず消滅する場合があるため、これら割り込み発生時には内部変数をを設定し優先してイベントコールバックを呼び出すようにした。cbAppColdStart(FALSE) 時に以下の変数を0に設定すれば無効化できる。 `volatile uint32 _u32_INT_ticktimer; volatile uint32 _u32_INT_adc_comp;`
* パケット送信要求のキューがフルかどうか判定して、フルの場合はエラーを返すようにした。
* WarmStart時に乱数生成が再開しなかった問題を修正。
* `tsEvent`構造体に`pvExtraData`を追加 (mwxライブラリでPRSEV状態遷移マシンを動作させるための修正)
* `volatile uint32 u32TickCount_ms`に変更(volatile の追加)
* メインループで CPU\_Doze をコントロールするための `bool_t _b_cpu_doze_dirty`変数を追加。`TRUE`にセットしておくと、メインループのDOZEをスキップする。
* mwx ライブラリ利用のため、一部関数ヘッダ定義を外部参照可能に修正 (ユーザー非開示：PRSEV:イベント関連、内部構造体など)
* mwx ライブラリ利用のため、ヘッダファイルのメンテナンス (extern "C")
* `Utils/Source/utils.[ch]`: PWM設定で DUTY の刻みを細かく設定できるように修正。構造体メンバー u16duty\_max に値を設定することで、刻み値を 1024 以外にも設定可能。刻みが1024,4096,16384の場合に除算実行の替わりにビットシフトにするようにした。
* `sToCoNet_AppContext.u32ChMask` の MSB を内部利用するように関連コードを一部修正。
* 内部チャネル変更関数中で、ソースコード上、現在の設定チャネルに変更される可能性があったコードを修正。

## TWELITE NET 1.2.0 (2018-05-14)

* TWELITE BLUE 用のSDKのツールチェインから、TWELITE RED 共用のツールチェインに変更
  * Windows用では cygwin から msys になります。
* 推奨開発環境を eclipse から VSCode に変更
* ライブラリ一式を 1.2.0 へ変更 (v1.0.6より)
  * TWELITE RED に対応
  * make のパラメータの整理 (make TWLIET={BLUE|RED})
  * 中継における上位ノードを決定する方法を、アクティブ方式の探索から、定期パケット（NBビーコン）を用いるパッシブ方式に変更 (App\_Tagの中継器に実装)
  * 32Kオシレータを利用する sToCoNet\_AppContext.u8Osc32Kmode を追加
  * アプリケーションID外のネットワークへの送信機能（実験的実装）
  * その他軽微な修正
    * 重複チェッカ(ToCoNet\_USE\_MOD\_DUPCHK)のタイムスタンプ更新方法の改良
    * 稀にチャネルが正しく切り替わらなかった問題の修正


# TWELITE SDKの使用法


# TWELITE SDKのインストール


# VSCode での利用

VSCode では、コード解釈 ([IntelliSense](https://code.visualstudio.com/docs/editor/intellisense)) 機能があるため、コード編集が効率的に行えます。またタスク機能により[ビルドコマンド](/twelite-sdk-howto/komandoraindenobirudo)の実行を VSCode から行うことができます。

## プロジェクトを開く

TWELITE のアプリをビルドするためにプロジェクトを Visual Studio Code で開く必要があります。\
プロジェクトを開く手順は下記の通りです。

![メニューバーの "ファイル" → "フォルダーを開く"を選択します。](/files/-LCCZy_dzy2xm29c_vKO)

![開きたいプリジェクトのフォルダを選択します。](/files/-LCC_2taPfeK9bYIJnVu)

![エクスプローラー上に開いたプロジェクトのフォルダが追加されます。](/files/-LCC_HPSeQFQNUzXFWLE)

## アプリをビルドする

アプリのビルドは下記の手順で行います。VSCode 上から make ユーティリティを実行しています。make の詳細については「[ビルド方法](/twelite-sdk-howto/komandoraindenobirudo)」や「[Makefileについて](/twelite-sdk-howto/birudonitsuite/makefile-nitsuite)」を参照してください。

例えば、超簡単！TWELITE標準アプリをビルドする場合、VSCode のタスク”Build App\_Twelite\_Master (BLUE)” を選択します。

![メニューバーの”タスク” → ”タスクの実行” を選択します。](/files/-LCC_elt3CiSmEEmAQpr)

![右図の赤枠内よりビルドしたい定義を選択します。](/files/-LCC_hGwxpDY6YrTZx9V)

![ターミナルより右図の赤枠内のような出力がされればビルド成功です。](/files/-LCC_lXN8is14R7YYyQc)

{% hint style="info" %}
VSCode からはコマンドラインの make を実行しているため、エラー等もコマンドラインのエラーメッセージが出力されます。
{% endhint %}

## コード解釈を切り替える

TWELITE BLUE 用のコード解釈と TWELITE RED 用のコード解釈を切り替えることができます。 コード解釈を切り替えるには図の示す場所をクリックして開発対象にあった TWELITE のモデルを選択してください。

{% hint style="info" %}
TWELITE モジュールの種別ごとに特有の C 定義を切り替えます。

コード解釈とコンパイラ解釈が完全に一致することを保証するわけではありません。またヘッダファイルの記述などにより一部解釈できない定義も発生します。
{% endhint %}

![コード解釈を切り替えます。](/files/-LCC_VYXk1QBc06tmr26)

{% hint style="info" %}
TWELITE モジュールの種別ごとに特有の C 定義を切り替えます。
{% endhint %}

{% hint style="warning" %}
コード解釈とコンパイラ解釈が完全に一致することを保証するわけではありません。またヘッダファイルの記述などにより一部解釈できない定義も発生します。

読み込むヘッダファイルは、コンパイラやライブラリのヘッダファイルを直接参照するわけではなく {SDKフォルダ}/Tools/VSCode/include　以下のコピーを参照します。
{% endhint %}

## JSON ファイルについて

上記のビルドやコード解釈については JSON ファイルに定義があります。

### .vscode/c\_cpp\_properties.json

ビルド時の暗黙定義などの定義やインクルードフォルダの指定を行っています。

追加の定義が必要な場合は、すでにあるファイル中の `"name" : "TWELITE_BLUE"` または `"name" : "TWELITE_RED"`\_ \_のエントリを複製または編集して使用します。

編集が必要になるのは `"name"` `"includePath"` などです。 特有のビルド定義が必要な場合は `"defines"` にエントリを追加します。

### .vscode/tasks.json

ビルドタスクの定義を行なっています。

新たにビルド定義を追加する場合は、すでにあるエントリをコピーして編集します。各ビルドタスクには windows, linux, osx 用のエントリーがあります。

編集が必要になるのは `"label"` `"options" の "cwd"` などです。

```bash
"tasks": [
{ 
  "label": "Build Samp_PingPong,PingPong (BLUE)",
  "type": "shell",
  ..
  "windows": {
     "command": "make",
     "args": [ "TWELITE=BLUE",  "clean", "all" ],
     "options": { "env": { "PATH": "${workspaceRoot}\\..\\..\\Tools\\MinGW\\msys\\1.0\\bin" } }
  },
  "problemMatcher": { "base": "$gcc", "fileLocation": [ "absolute" ] },
  "options": { "cwd": "${workspaceRoot}/PingPong/Build" }
},
..
```

{% hint style="info" %}

* `"options": { "cwd" ... }` の設定でビルドフォルダを指定しています。
* make 引数を追加したい場合は、\_ *`"args"`* \_の `TWELITE=???"` の後にエントリを追加します。
  {% endhint %}

#### 既存のビルドタスクに設定する

以下の例のように`group": { "kind": "build", "isDefault": true }` を追加します。そのタスクがデフォルトのビルド定義になり、\[タスク]>\[ビルドタスクの実行] やショートカットキーによる実行ができるようになります。

```bash
"tasks": [
{ 
  "label": "Build Samp_PingPong,PingPong (BLUE)",
  "type": "shell",
  ..
  "options": { "cwd": "${workspaceRoot}/PingPong/Build"},
  "group": { "kind": "build", "isDefault": true }
},
..
```


# フォルダ構成

TWELITE SDK は、インストール先のフォルダを基準にして、所定の場所にソースコードなどプロジェクトファイルを格納するように用意されています。

{% hint style="danger" %}
SDKインストールフォルダを含め、フォルダ名・ファイル名は英数文字 \*\*`a-z A-Z 0-9 _ -`\*\*と拡張子を区切る **`.`** ピリオドとし、空白・その他特殊記号や多バイト圏文字列（日本語など）が含まないようにしてください。
{% endhint %}

| フォルダ                    | 内容                    |
| ----------------------- | --------------------- |
| `.../MWSDK`             | TWELITE SDK の最上位フォルダ。 |
| `.../MWSDK/ChipLib`     | 半導体ライブラリ              |
| `.../MWSDK/License`     | モノワイヤレスソフトウェア仕様許諾書    |
| `.../MWSDK/MkFiles`     | makefile ライブラリ        |
| `.../MWSDK/Tools`       | toolchain、書き込みツールなど   |
| `.../MWSDK/TWENET`      | TWELITE NET ライブラリ     |
| `.../????_libTWENET`    | libTWENETUtils ソースコード |
| `.../MWSDL/Wks_TWELITE` | アプリ・サンプルのワークスペース      |

### Wks\_TWELITE ワークスペースについて

{% hint style="danger" %}
ワークスペースを格納するフォルダはMWSDK 直下で、かつ、後述する Makefile の相対フォルダも変更してはいけません。

`.../MWSDK/{ワークススペースフォルダ}/{プロジェクトフォルダ}/{構成フォルダ}/Build/Makefile`
{% endhint %}

プログラムをビルドするためのワークスペースには、複数のプロジェクトが格納されています。Wks\_TWELITE 内に格納されるプロジェクトは各々個別のアプリケーションをビルドするものです。

```
.../MWSDK/Wks_TWELITE/ProjectName1/...
.../MWSDK/Wks_TWELITE/ProjectName2/...
...
```

プロジェクト内は以下のような構成になっています。

```
.../ProjectNameX/
    Variant1/          : 構成１(var1)のビルド
       Source/         : var1 特有のソースコード
       Build/          : 生成バイナリの格納場所
           Makefile    : var1 の生成ルール
           Version.mk  : var1 のバージョン情報
    Variant2/...       : 構成2
    Common/            : 構成間共通のソースなど
```

* 同じプロジェクトでも、構成が一つのみの場合もあれば、親機・子機・中継機と構成が別れたソースコードになる場合もあります。


# コマンドラインでのビルド方法

## コマンドラインによるビルド方法

{% hint style="info" %}
VSCode を利用する場合、VSCode 内からコマンドラインが呼び出されていますので、以下の手順については意識する必要はありません。
{% endhint %}

### 事前準備

コマンドラインの make ユーティリティが実行できるようにしておいてください。

{% hint style="warning" %}
以下の解説では bash コマンドラインを前提に解説します。
{% endhint %}

#### Windows

SDK 添付の BASH (msysによる) を利用します。

{MWSDKインストールフォルダ} にある BASH.CMD をエクプローラから実行してください。Wks\_TWELITE ワークスペースをカレントフォルダにした bash コマンドラインが表示されます。ツールチェインへの PATH の TWELITE SDK 向けに設定します。

```bash
user1@MACHINE_NAME   /c/MWSDK/Wks_TWELITE
$ pwd
/c/MWSDK/Wks_TWELITE

$ ls
App_IO  App_Tag  Samp_PER  Samp_Wayback
App_Melody  
...
```

#### macOS

コマンドライン (bash) にて、make を実行した時エラーが出る場合は XCode のインストールを行います。

```c
$ xcode-select --install
```

インストール完了後、make を入力して以下のメッセージが出れば OK です。

```c
$ make
make: *** No targets specified and no makefile found.  Stop.
```

### ビルド

例として Samp\_PingPong をビルドしてみます。

最初にビルドプロジェクト Samp\_PingPong のビルドフォルダに移動します。

```bash
$ pwd
/c/MWSDK/Wks_TWELITE
$ cd Samp_PingPong/PingPong/Build/
$ pwd
/c/MWSDK/Wks_TWELITE/Samp_PingPong/PingPong/Build/
```

次に clean を実行します。ここでは TWELITE BLUE のビルドで clean を実行する例を挙げます。

```
$ make TWELITE=BLUE clean
../../../../MkFiles/chipsel.mk:36: "WARNING: TWELITE BLUE"
```

{% hint style="info" %}
make を実行する際には TWELITE=BLUE または TWELITE=RED の指定が必ず必要です。

WARNING が出ますが、これは TWELITE BLUE のビルドであることを明示するためで、問題を指摘しているものではありません。

make を実行せずに Build フォルダをクリーン状態にするには、Build フォルダ中の .bin ファイルと objs\_\* フォルダを消去します。
{% endhint %}

clean が終われば、ビルドを実行します。

```bash
$ make TWELITE=BLUE
rm -f objs_BLUE/PingPong.o
mkdir -p objs_BLUE
Compiling /c/MWSDK/Wks_TWELITE/Samp_PingPong/Pi..
...
/c/MWSDK/ChipLib/SW4063V1416/../../Tools/ba-elf-ba2-r..
y -S -O binary objs_BLUE/Samp_PingPong_PingPong_BLUE_..
Samp_PingPong_PingPong_BLUE_L1200_V0-1-4.bin

$ ls *.bin
Samp_PingPong_PingPong_BLUE_L1200_V0-1-4.bin
```

{% hint style="info" %}
ビルド実行後 [.bin ファイル](/twelite-sdk-howto/birudonitsuite/binfuiru)が出来上がっていれば成功です。ビルドが成功しない場合は、何らかのエラーメッセージが出ています。

中間ファイルは objs\_{ARCH} フォルダに格納されます。
{% endhint %}


# ビルド定義について


# Makefile について

ビルド対象のソースコードや諸定義は Makefile に記述します。

| TWELITE                          | ビルドするモデルを指定する。TWELITE BLUE (TWE-001 Lite) の場合は BLUE、TWELITE RED の場合は RED を指定する。                        |
| -------------------------------- | ------------------------------------------------------------------------------------------------------ |
| PROJNAME                         | 生成ファイル名を決めます。指定が無い場合は ../.. フォルダ名を使用します。                                                               |
| APPSRC                           | コンパイル対象ファイルを指定します。APPSRC+=test.c のように += 演算子を使用します。                                                    |
| TARGET\_TYPE                     | 生成する対象を指定します。TARGET\_TYPE = bin を指定した場合は実行形式、TARGET\_TYPE = a を指定した場合はライブラリとなります。                      |
| TOCONET\_DEBUG                   | 1ならスタックのデバッグコードを含めます。出力ファイル名に \_TDBG が付記されます。スタックデバッグコードについては、API解説を参照してください。0は含めず、バイナリサイズが若干小さくなります。  |
| CFLAGS                           | コンパイル時の gcc オプションを追加します。CFLAGS += -DMY\_DEBUG のように += 演算子を利用します。最適化オプションなどは事前定義されていますので指定しないようにしてください。 |
| APP\_COMMON\_SRC\_DIR\_ADD1 .. 4 | ソースおよびヘッダファイルの検索パスを指定します。APP\_COMMON\_SRC\_DIR\_ADD1 = ../mydir のようにMakefile のあるフォルダからの相対パスを指定します。     |
| INCFLAGS                         | インクルードフォルダのみを追加指定したい場合は、INCLFAGS == -I../mydir のように相対パス指定します。                                          |
| ADDITIONAL\_LIBS                 | 追加でリンクしたいライブラリ (.a) を指定します。ADDITIONAL\_LIBS += ../mylib.a のように追加します。                                   |
| ADDITIONAL\_OBJS                 | 追加でリンクしたいオブジェクトファイル (.o) を指定します。ADDITIONAL\_OBJS += ../myobj.o のように追加します。                              |
| LDLIBS                           | コンパイラ付属ライブラリ (math, sppなど) を指定します。LDLIBS += m のように追加します。この指定では-lmがリンカに渡されます。                           |
| LDFLAGS                          | リンカへの追加オプションです。LDFLAGS += -u dummy のように追加指定します。必要なオプションは事前に定義されています。                                   |
| OBJDIR\_SUFF                     | オブジェクト格納フォルダ名に設定した文字列を含める。                                                                             |
| TARGET\_SUFF                     | ターゲット(.bin)ファイル名に設定した文字列を含める。                                                                          |


# Version.mk について

Version.mk ファイルは、各ターゲットの Source フォルダに格納し、Makefile から参照され、出力ファイル名のバージョンなどの決定に使用されます。

以下のように指定します。

```
VERSION_MAIN = 1 	← 主バージョン(0-255)
VERSION_SUB  = 3	← 副バージョン(0-255)
VERSION_VAR  = 10	← ビルドなどの派生(0-255)
```

Makefile は Version.mk から以下のコンパイルオプションを追加します。

上記の例ではコンパイル時に -DVERSION\_MAIN=1 -DVERSION\_SUB=3 -DVERSION\_VAR=10 を追加します。

{% hint style="warning" %}
SDK 2013/11版までは Version.h が生成されましたが省略されます。ソース中で Version.h をインクルードしている場合は、Version.h を空ファイルにする、またはインクルードしないようにしてください。
{% endhint %}


# binファイル命名則

binファイル名の基本の形は以下になります。

> {プロジェクト名}\_{バリアント名}\_{ARCH名}\_{TWENETライブラリバージョン}\_{Version.mkバージョン}
>
> 例: Samp\_PingPong\_PingPong\_BLUE\_L1200\_V0-1-4.bin

| 名前               | 解説                                                                                      | 例              |
| ---------------- | --------------------------------------------------------------------------------------- | -------------- |
| プロジェクト名          | 通常プロジェクトの最上位フォルダ名です。                                                                    | Samp\_PingPong |
| バリアント（派生）名       | 通常プロジェクト中のサブフォルダ名です。１プロジェクト中に親機用・子機用を別々に生成するよう場合に使います。                                  | PingPong       |
| ARCH名            | BLUE: TWELITE BLUE, RED: TWELITE RED                                                    | BLUE           |
| TWENETライブラリバージョン | バージョン識別子です。                                                                             | L1200          |
| Version.mk バージョン | [Version.mk ](/twelite-sdk-howto/birudonitsuite/versionmk-nitsuite)ファイルに記述されたバージョン番号です。 | V0-1-4         |

{% hint style="info" %}
ファイル名は [Makefile](/twelite-sdk-howto/birudonitsuite/makefile-nitsuite) により一部カスタマイズ可能です。
{% endhint %}


# ファームウェア書換

出来上がった bin ファイルを書き換えるには、PC のシリアル接続と、TWELITE 無線モジュールのポート制御が必要になります。

TWELITE DIP と TWELITE R の組み合わせでは、書き換え制御を自動化するため処理が容易です。

## TWE-Programmer による書き換え(Windows)

[リンク先](https://mono-wireless.com/jp/products/TWE-APPS/LiteProg/index.html)を参照してください。

## tweterm.py による書き換え (OS X, Linux)

[リンク先](/twelite-sdk-howto/fumuua/tweterm.py)を参照してください。

## 独自の基板に TWELITE SMD を実装した場合

[リンク先](/twelite-sdk-howto/fumuua/fumuua)を参照してください。


# ファームウェア書換用配線

ファームウェアを書き換えるための配線について解説します。

{% hint style="info" %}
TWELITE R2 互換の配線については「[一般情報＞技術情報＞ファーム書き換え用配線](https://twelite.gitbook.io/general/technical-info/progpins)」を参照ください。
{% endhint %}

{% hint style="warning" %}
表面実装(SMD)版のモジュールを実装して、独自に基板設計される場合は、必ずファームウェアの書き換えを行える配線を基板上に用意してください。
{% endhint %}

## ピンについて

プログラムモードで用いる配線を以下に列挙します。これらの信号線を外部からアクセスできるようにします。

| **名称** | **信号名** | **TWELITE DIP#** | **TWELITE SMD #** | **備考**                                            |
| ------ | ------- | ---------------- | ----------------- | ------------------------------------------------- |
| RST    | RESETN  | 21               | 21                | モジュールをリセットする（配線しない場合は電源投入で代替できる）                  |
| RXD    | DIO7    | 3                | 9                 | シリアル通信線（PC側はTX端子に接続)                              |
| PRG    | SPIMISO | 7                | 2                 | 本品をLO(GND)にしてからリセットし、開放(またはHI) にするとプログラムモードに遷移する。 |
| TXD    | DIO6    | 10               | 8                 | シリアル通信線（PC側はRX端子に接続)                              |
| GND    | GND     | 1,14             | 20,28             | 電源供給のため（ピンが複数定義されているが、内部で接続されているため１本接続でも可）        |
|        |         |                  |                   |                                                   |
| VCC    | VCC     | 28               | 5                 | 電源供給のため                                           |

{% hint style="warning" %}
TWELITE R に接続する場合も同名の信号を TWELITE 無線マイコンに直接配線し、VCC も供給します。VCC はTWELITE Rからの出力を流用できます。

まず、当該信号ラインに他の回路が接続されておらず、かつ、上記に挙げない信号線は未接続でお試しください。他の回路が影響して、プログラムモードへの遷移ができなかったり、書き換え時に実行されるシリアル通信に問題が出る場合があります。
{% endhint %}

{% hint style="info" %}
[TWELITE R](https://mono-wireless.com/jp/products/TWE-LITE-R/) では、上記の RST RXD PRG TXD GND の順番に 2.54mm ピッチのヘッダピン、ソケットが接続できるようになっています。同じ配列を基板上に用意すれば TWELITE R を流用することができます。
{% endhint %}

## プログラムモード設定手順

| 1 | 無線モジュールを電源OFFにしておきます。                                    |
| - | -------------------------------------------------------- |
| 2 | PRG(SPIMISO)ピンをGNDに接続します。                                |
| 3 | 電源ONにします。（またはリセットでも構いません）                                |
| 4 | PRG(SPIMISO)ピンを未接続にします。（内部プルアップによりピンの状態は Hi になる）         |
|   | *この時点でTWELITE 無線モジュールは、ファームウェアを書き換え可能なプログラムモードで起動しています。* |
| 5 | PC側のファームウェアプログラマーを起動し、対象のシリアルポートに対して接続確認を行います。           |
|   | *接続応答がない場合（シリアル番号などの表示がない、無応答でタイムアウト）は、最初からやり直します。*      |

{% hint style="info" %}
TWELITE R と TWE-Programmer の組み合わせでは、上記 1 〜 5 の手順を自動化しています。

* TWE-Programmer の SAFE モードを設定すれば、自動的なプログラムモード遷移の手続きを省略します。
  {% endhint %}

## 配線例（押しボタンスイッチによる制御）

以下のような配線を行います。PRG や RST ピンには押しボタンスイッチが接続されており、ボタンを押すことで GND に落ちるようになっています。

![配線例](/files/-LC8Su52RS08aTGJTSFk)

以下のように PGM ピンと RST ピンを制御します。PGMピンのボタンを離した直後に TWELITE 無線モジュールはプログラムモードに遷移します。

![](/files/-LC8TNAIrye4lvqanU9g)

{% hint style="warning" %}
スイッチのチャタリング等でうまくいかない場合もあります。TWELITE 無線マイコンが反応しない場合は、やり直してください。

待ち時間については 100ms 程度の短い時間で十分です。
{% endhint %}


# tweterm.py

本プログラムは pyftdi (<https://github.com/eblot/pyftdi>) ライブラリサンプルスクリプト pyterm.py に TWELITE 用のファームウェア書き込みスクリプトを組み込んだものです。以下の機能があります。

* TWELITE 用ファームウェアの書き込み　(TWELITE R/MONOSTICK)
* シリアルポートでの動作振る舞いの確認

{% hint style="warning" %}
本スクリプトの OS X での実行には Python3 インタプリタが必要です。コマンドライン環境ならびに Python インタプリタの取り扱いに慣れた方を対象とします。
{% endhint %}

{% hint style="warning" %}
本スクリプトを Linux で動作させるには同等のパッケージ (libusb-dev, pyserial, pyftdi) を用意します。コマンドライン環境ならびに Python インタプリタの取り扱いに慣れた方を対象とします。

* 参考環境：Ubuntu 16.04 (i386 32bit), Python3.5.2 / Ubuntu 18.04 (x86-64 64bit), Python 3.6.5
  {% endhint %}

## 保証・ライセンス

本パッケージ内で、ライセンス上特別な記述のないものは、[モノワイヤレスソフトウェア使用許諾契約書](/overview/mwsla)を適用します。

本ソフトウェアについては、モノワイヤレス株式会社が正式にサポートを行うものではありません。お問い合わせにはご回答できない場合もございます。予めご了承ください。

不具合などのご報告に対してモノワイヤレス株式会社は、修正や改善をお約束するものではありません。

また導入パッケージなどお客様の環境に依存して動作しない場合もございます。

```python
# Copyright (C) 2017 Mono Wireless Inc. All Rights Reserved.
# Released under MW-SLA-*J,*E (MONO WIRELESS SOFTWARE LICENSE
# AGREEMENT)
```

## 動作環境・必要パッケージ

* Mac OS X または Linux
* python3.5 以降
* libusb
* pyserial
* pyftdi

### 開発環境

以下の環境で開発、動作確認を実施しました。ただし、これら環境で動作を保証するものではありません。

| 環境                                      |
| --------------------------------------- |
| Mac OS X 10.11.6, Python3.5.1 (2018/05) |
| Ubuntu 18.04, Python3.6.7 (2018/05)     |
| Mac OS X 10.14.2, Python3.7.2 (2019/01) |

*

## インストール

### パッケージのインストール

#### macOS

以下では、Homebrew を用いた新しく全パッケージをインストールする例をご紹介します。

#### Homebrew

Homebrew をインストールします。

```bash
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
```

#### Python3

```bash
$ brew install python3
```

#### libusb

```bash
$ brew install libusb
```

#### pyserial

```bash
$ pip3 install pyserial
```

#### pyftdi

```bash
$ pip3 install pyftdi
```

#### Linux

お使いのディストリビューションのパッケージ導入法を調べてください。以下のパッケージが必要です。

* python3.5 以降 (多くの場合導入されています)
* libusb-dev
* pyserial
* pyftdi

パッケージ導入コマンド例。

```bash
$ sudo apt-get install libusb-dev
$ sudo apt-get install python3-pip
$ pip3 install pyserial
$ pip3 install pyftdi
```

### 実行

TWELITE SDK をインストールしたフォルダを `${TWELITESDK}` と記載します。

スクリプトは以下になります。

```bash
${TWELITESDK}/Tools/tweterm/tweterm.py
```

スクリプトに実行許可を与えます。

```bash
$ chmod +x ${TWELITESDK}/Tools/tweterm/tweterm.py
```

必要に応じて環境変数 PATH に追加しておきます。

```bash
$ PATH=${TWELITESDK}/Tools/tweterm:$PATH
```

## 利用方法

### USBドライバのアンロード

{% hint style="warning" %}
libusb と OS のドライバが競合するため、ドライバをアンロードしておきます。
{% endhint %}

#### macOS

FTDI 関連のドライバをアンロードします。

```bash
$ sudo kextunload -b com.apple.driver.AppleUSBFTDI
```

#### Linux

ドライバのアンロードは不要です。

{% hint style="warning" %}
エラーが出る場合は、ドライバをアンロードを試してみてください。

```bash
$ sudo rmmod ftdi_sio
$ sudo rmmod usbserial
```

{% endhint %}

### コマンドパラメータ

| パラメータ                   | 解説                                                   |
| ----------------------- | ---------------------------------------------------- |
| `-p ftdi:///?` または `-p` | デバイス一覧を表示します。                                        |
| `-p [デバイス名]`            | デバイスを指定します。                                          |
|                         | `ftdi:///1` 他にデバイスがない時。                              |
|                         | `ftdi://::MW19ZZUB/1` シリアル番号による指定。\`                 |
| `-b [ボーレート]`            | ボーレートを指定します。                                         |
|                         | `-b 115200` 115200bps を指定。                           |
| `-F [ファームウェア]`          | ファームウェアを書き込みます。                                      |
|                         | `-F App_Twelite.bin` ファイル名が App\_Twelite.binを書き込みます。 |
| `--no-color`            | 文字のカラー出力を抑制します。                                      |
| `--no-term`             | ファームウェアの書き込みのみを実施しターミナルを開きません。                       |

### キーボード操作

`Ctrl+C` キーを入力することで制御プロンプトを表示し、いくつかの特別な操作が可能です。それ以外の場合は、直接 TWELITE 無線モジュールに入力文字列が送付されます。

| 入力キー                           | 解説                                                                  |
| ------------------------------ | ------------------------------------------------------------------- |
| `Ctrl+C Ctrl+C`                | ターミナルを終了します。                                                        |
| `Ctrl+C Ctrl+R` または `Ctrl+C r` | TWELITE 無線マイコンをリセットします。                                             |
| `Ctrl+C Ctrl+I` または `Ctrl+C i` | インタラクティブモードへ遷移する + + + コマンドを入力します。インタラクティブモード対応ファームウェアのみ有効です。       |
| `Ctrl+C A`                     | 書式の解釈を開始します。TWELITE無線マイコンからの出力とキー入力に対して、アスキー形式の解釈を行います。             |
| `Ctrl+C B`                     | 書式の解釈を開始します。TWELITE無線マイコンからの出力に対してバイナリ形式の解釈を行います。キー入力はアスキー形式で解釈します。 |
| `Ctrl+C N`                     | 書式の解釈を停止します。                                                        |

{% hint style="info" %}
書式解釈中は TWELITE からの電文は解釈できた電文のみ表示し、キーボードの入力はエコーバックされますが、アスキー形式の電文が完成した時に TWELITE に送付されます。
{% endhint %}

## \[実行例]

実行例中では、適宜改行を挟んでいます。

{% hint style="warning" %}
エラーが発生する場合は、シリアルポートの権限の問題かもしれません。root権限(sudo等)で実行します。
{% endhint %}

#### ＜最初にデバイスがリストされるかを確認します＞

```bash
$ tweterm.py -p ftdi:///?
Available interfaces:
  ftdi://ftdi:232:MW19ZZUB/1   (MONOSTICK)
  Please specify the USB device
```

#### ＜ファームウェアを書き込んでターミナルを起動します＞

以下の例では App\_UART (UART 通信アプリ) を書き込み、起動メッセージを確認しています。

```bash
$ tweterm.py -p ftdi://ftdi:232:MW19ZZUB/1 -b 115200 -F ../App_Uart_Master_RED_L1101_V1-2-15.bin 
*** TWE Wrting firmware ... ../App_Uart_Master_RED_L1101_V1-2-15.bin
MODEL: TWEModel.TWELite
SER: 102eebd

 file info: 0f 03 000b
erasing sect #0..#1..#2..
0%..10%..20%..30%..40%..50%..60%..70%..80%..90%..done - 10.24 kb/s
Entering minicom mode

!INF TWE UART APP V1-02-15, SID=0x8102EEBD, LID=0x78
8102EEBD:0> 
```

#### ＜Ctrl+Cを入力すると制御プロンプトが表示されます＞

```
*** r:reset i:+++ A:ASCFMT B:BINFMT x:exit>
```

#### ＜続けて i を入力します。インタラクティブモードに入ります＞

```
*** r:reset i:+++ A:ASCFMT B:BINFMT x:exit>[+ + +]
--- CONFIG/TWE UART APP V1-02-15/SID=0x8102eebd/LID=0x00 -E ---
 a: set Application ID (0x67720103) 
 i: set Device ID (121=0x79) 
... ＜省略＞ 
```

通常通り + + + と３回入力しても同じ結果になります。

#### ＜書式の解釈の例：App\_UART をバイナリ形式に設定しておきます＞

インタラクティブモードで `m` `B` `Enter` `S` と順に入力します。

```
--- CONFIG/TWE UART APP V1-02-15/SID=0x8102eebd/LID=0x00 -E ---
 a: set Application ID (0x67720103) 
 i: set Device ID (121=0x79) 
 c: set Channels (18) 
 x: set RF Conf (3) 
 r: set Role (0x0) 
 l: set Layer (0x1) 
 b: set UART baud (38400) 
 B: set UART option (8N1) 
 m: set UART mode (B)*
 h: set handle name [sadkasldja] 
 C: set crypt mode (0) 
 o: set option bits (0x00000000) 
---
 S: save Configuration
 R: reset to Defaults
 
!INF Write config Success
!INF RESET SYSTEM...
```

#### ＜書式の解釈の例＞

以下の例ではApp\_UARTがバイナリ形式で入出力を行ないます。`Ctrl+C B` を入力します。

```
*** r:reset i:+++ A:ASCFMT B:BINFMT x:exit>
[FMT: console ASCII, serial BINARY]
```

この状態では入出力は書式形式となります。キーボードの入力はアスキー形式、 TWELITE からの電文はバイナリ形式として解釈します。

TWELITE からの電文を受け取る例を示します。一番簡単な方法は TWELITE をリセットします。`Ctrl+C r` を入力します。

```
*** r:reset i:+++ A:ASCFMT B:BINFMT x:exit>[RESET TWE]
[dbf1677201030001020f008102eebd0000]
```

出力された `[dbf...]` がTWELITEからの電文で実際は`0xdb 0xf1 0x67...` と続くバイナリ列になります。

反対に TWELITE に電文を送る場合はアスキー書式で入力します。`:7800112233AABBCCDDX` と入力します。 ここでは ペイロードが 0x7800112233AABBCCDD のデータをバイナリ形式で TWELITE に送付しています。直後に応答として `[dba18001]` が戻ってきています。

```
:7800112233AABBCCDDX[dba18001]
```

#### ＜終了します＞

`Ctrl+C Ctrl+C` を入力します。

```
*** r:reset i:+++ A:ASCFMT B:BINFMT x:exit>[
[EXIT]
Bye.
```


# TWELIET NET API 解説


# 用語

## TWELITE NET

本TWELITE SDKに含まれる、無線通信の手続きライブラリ。

## 単純ネット

TWELITE NETでは特別な中継処理はせず、アプリケーションIDやアドレスによる単純な中継を行う。

## 中継ネット

TWELITE NET内で中継処理を行うための処理を行う方式。

## MAC ACK、ACK、ACK付き

IEEE802.15.4 で定められた配送先がパケットを受信したかどうかを確認する手続き。受信完了直後にごく短い ACK パケットを送り返す。

例外的にACK送信またはACK受信に失敗する場合があるため、ACKが確認が相手先に伝わったことを保証するわけではなく、反対に ACK が得られなかった場合、相手先に伝わらなかったことを保証するわけでもない。

## ノード、局

ある一つの無線機、または、ある共通機能を有する無線機の総称。無線局、親局、子局、中継局のように記述されます。

## [アドレス](/twelite-net-api-expl/paketto/adoresuno)（ロングアドレス、ショートアドレス）

無線局を特定するための識別番号。

## 同報通信

無線局を特定せずに一斉に通信する方法。電波を受信できた無線局に伝達される。全ての無線局に伝達されることを保証するわけではない。

## [アプリケーションID](/twelite-net-api-expl/paketto/apurikshonid)

ネットワーク識別子。同一のアプリケーションIDを有する無線局間のみで通信ができる。

## LQI

Link Quality Indicator。IEEE802.15.4 で規定される通信品質を評価するための値。厳密な定義は違うが RSSI も同じ目的の用語として用いられる。

LQI は規格上、無線パケット通信における物理量や現象に対しての厳格な定義は定められていないが、TWELITE NET では受信時の電界強度相当の値を利用している。

## [DIO](/hw-api-ref/perifuraru/dio)

汎用IO (GPIO) のこと。デジタル入力、出力利用が可能です。


# TWELITE NET ライブラリ構造

ユーザアプリケーションは TWELITE NET (TWENET) のライブラリおよびペリフェラルAPIを介して無線モジュールを制御します。TWELITE NET のライブラリは３つに分かれています。

![TWENET ライブラリ構造](/files/-LAvfr-VXP8W-5ZubS2o)

### libTWENET\_{ARCH}.a

アプリケーションループの定義、イベント処理、無線ネットワーク処理など

### libTWENETExt\_{ARCH}.a

始動処理、MAC層へのインタフェースなど

### libTWENETUtils\_{ARCH}.a

一般的なアルゴリズムやペリフェラルの手続きなど

*（ソース添付：MWSDK/TWENET/????/TWENETUtils/Source : ????にはライブラリバージョンに相当するフォルダ名が入ります）*

{% hint style="info" %}
{ARCH} は、TWELITE のモデル名が入ります。BLUE, REDなど。
{% endhint %}


# TWENET 動作フロー

TWENET の基本フローを図示します。

![](/files/-LAvkdLM1-YURckvTS6I)

より詳細な動作については、本ページの子ページに記述します。


# 始動フロー

システム始動時のフローです。

![](/files/-LB48BbzLGRYHP7VxdFA)

{% hint style="warning" %}
E\_EVENT\_START\_UP イベントは、ユーザイベント処理関数にのみ発生します。
{% endhint %}


# メインループフロー

![](/files/-LB48MEJLVU38b6czrmf)


# 無線関連フロー

## 受信と送信完了イベント

![](/files/-LB48ZL6ekn5cHnsq-AE)

## 送信時の詳細

![](/files/-LB48dlOYVEyLtduQXM-)


# ハードウェアフロー

![](/files/-LB490eL4RGui_mhDCBG)


# ユーザ定義イベント処理関数フロー

![](/files/-LB498Z5QBeSh5j4L0q9)


# ソースコードの構造

TWELITE NET でのアプリケーションの構成要素は以下となります。

* [コールバック関数](/twelite-net-api-ref/krubakku)や[モジュール](/twelite-net-api-expl/mojru)の定義：必須定義でメインファイルに記述します。
* [ユーザ定義イベント処理関数](/twelite-net-api-expl/twenet-fur/yzaibentofur)：必要に応じて記述します。ステートマシン（状態遷移マシン）によるアプリケーションの動作を想定した関数です。
* ユーザ定義諸関数：その他処理関数で、アプリケーション特有のコードです。

以下にメインファイルについて補足します。

## メインファイル

TWENET API では、メインファイルには以下の定義を記述します。

* モジュール宣言
* 必須ヘッダファイルインクルード
* コールバック関数

これ以外の処理を、メインファイル以外のファイルに記述しても構いません。

{% hint style="info" %}
TWENTE API では C 言語の処理系で一般的な main() 関数がありません。最初に呼び出されるのは [cbAppColdStart](/twelite-net-api-ref/krubakku/cbappcoldstart)() 関数です。
{% endhint %}

### モジュールの定義と必須ヘッダファイルのインクルード

ビルドバイナリや実行時のメモリを最小化するため、コンパイル時に静的に決定する関数やメモリの定義を行います。

モジュール利用宣言の定義を cbAppColdStart() の前に記述し、cbAppColdStart() で ToCoNet\_REG\_MOD\_ALL() マクロを呼び出して初期化します。

ヘッダファイルについては "ToCoNet.h" と "ToCoNet\_mod\_prototype.h" が必要になります。

```c
// Select Modules (define befor include "ToCoNet.h")
#define ToCoNet_USE_MOD_RXQUEUE_BIG
#define ToCoNet_USE_MOD_CHANNEL_MGR

// Includes
#include "ToCoNet.h"
#include "ToCoNet_mod_prototype.h"

…
void cbAppColdStart(bool_t bStart) {
  if (!bStart) {
    // Module Registration
    ToCoNet_REG_MOD_ALL();
  } else {
…
```

### コールバック関数

ソースコードには必ず以下の[コールバック](/twelite-net-api-ref/krubakku)関数を定義します。


# モジュール

TWELITE NET のライブラリの機能取捨選択をコンパイル時に行います。いくつかの機能は依存関係があります。

| モジュール定義                                                                                                 | 解説                                                                                                                                                               |
| ------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ToCoNet\_REG\_MOD\_ENERGYSCAN                                                                           | <p>チャネルの入力レベルを計測します。入力時には送受信が不可能になります。<br>関数： ToCoNet\_EnergyScan\_bStart()イベント：E\_EVENT\_TOCONET\_ENERGY\_SCAN\_COMPLETE</p>                                    |
| <p>ToCoNet\_USE\_MOD\_NBSCAN<br>ToCoNet\_USE\_MOD\_NBSCAN\_SLAVE</p>                                    | 近隣のモジュールを探索します。関数：ToCoNet\_NbScan\_bStart(), ToCoNet\_NbScan\_bStartToFindRole(), ToCoNet\_NbScan\_bStartToFindAddr()イベント：E\_EVENT\_TOCONET\_NWK\_SCAN\_COMPLETE |
| <p>ToCoNet\_USE\_MOD\_RAND\_XOR\_SHIFT<br></p>                                                          | 乱数生成アルゴリズムを登録します。登録しない場合は、内蔵のハードウェア乱数が使用されます。ただし、連続的に 32bit の乱数系列が必要な場合はソフトウェア乱数を使用します。外部の32kHz水晶振動子や発振器を接続する場合は、XOR\_SHIFT の定義が必要です。                            |
| ToCoNet\_USE\_MOD\_NWK\_LAYERTREE                                                                       | レイヤーツリー型ネットワーク層を利用します。依存モジュール： ToCoNet\_USE\_MOD\_NBSCAN, ToCoNet\_USE\_MOD\_NBSCAN\_SLAVE, ToCoNet\_USE\_MOD\_DUPCHK                                            |
| ToCoNet\_USE\_MOD\_NWK\_ LAYERTREE\_MININODES                                                           | 同報送信専用のレイヤーツリー型ネットワークにデータ送信可能な省電力「ミニノード」。依存モジュール: ToCoNet\_USE\_MOD\_DUCHK                                                                                       |
| ToCoNet\_USE\_MOD\_DUPCHK                                                                               | パケットの重複チェッカ。最大４０ノードまでの重複パケットを管理する。レイヤーツリー型「ミニノード」を使用する時には必須定義モジュール。                                                                                              |
| ToCoNet\_REG\_MOD\_NWK \_MESSAGE\_POOL                                                                  | メッセージプール機能を利用します。依存モジュール：ToCoNet\_USE\_MOD\_NWK\_LAYERTREE                                                                                                       |
| ToCoNet\_USE\_MOD\_CHANNEL\_MGR                                                                         | チャネルアジリティを利用します。u32ChMask に指定したチャネルを利用して、複数チャネル駆動の通信を行います。                                                                                                       |
| ToCoNet\_USE\_MOD\_TXRXQUEUE\_SMALL　ToCoNet\_USE\_MOD\_TXRXQUEUE\_MID　ToCoNet\_USE\_MOD\_TXRXQUEUE\_BIG | 送信キューのサイズを決定します。SMALLは送信用で 3ヶ、MIDは6ヶ、BIGは20ヶのキューを確保します。パケット分割を行うような一度に多くのパケットを連続的に送信する場合はBIGを指定します。１ヶあたり約128バイトのメモリを消費し、未定義時は MID となります。                         |


# 無線パケット

## 宛先について

無線パケットを配送する際には宛先情報が必要になります。宛先は３つの要素を意識する必要があります。

* チャネル
* アプリケーションID
* 宛先アドレス

チャネルは物理的な通信チャネルのことで ch11 〜 26 までの合計１６チャネルが指定できます。通信チャネルが違う場合は、物理的に受信することができません。通信をするにはまず、通信チャネルを一致させる必要があります。

通信チャネルが同じであっても、複数の無線システムを稼働できる必要があります。TWENET を用いるシステムが同じ場所に複数あって同じチャネルで通信する可能性がある場合は、アプリケーションIDにより別々のネットワークとして取り扱います。

最後に、チャネルもアプリケーションIDも一致していれば、宛先アドレスを適切に設定すれば通信が可能となります。宛先アドレスは、ショートアドレス（12bit 値の範囲で任意に設定できる）、ロングアドレス（個体識別アドレスで通信する）、同報通信の３種類があります。

## 送り主のアドレス

TWELITE NET では、送り主のアドレスをショートアドレスまたはロングアドレスとして送信できます。

## パケットの最大長

無線パケットは IEEE802.15.4 規格のパケット構造を元になっていますが、宛先データやTWENET で用いるヘッダなどユーザが直接利用しないデータを差し引いた分が最大で通信できるデータサイズとなります。

データサイズを小さくする（ペイロードを節約する、ショートアドレスを積極的に利用する）ことで電流消費の多い無線通信時間を短縮できます。また小さいパケットは比較的失敗しにくくなります。


# パケットの最大長

| ネットワーク層 | 暗号化 | 宛先   | 送信元  | ペイロードの最大 |
| ------- | --- | ---- | ---- | -------- |
| なし      | なし  | ショート | ショート | 110      |
| なし      | あり  | ショート | ショート | 108      |
| なし      | なし  | ショート | ロング  | 102      |
| なし      | あり  | ショート | ロング  | 100      |
| なし      | なし  | ロング  | ロング  | 96       |
| なし      | あり  | ロング  | ロング  | 94       |
| あり      | なし  | 指定不可 | 指定不可 | 88       |
| あり      | あり  | 指定不可 | 指定不可 | 86       |

※ MWSDK2020\_12までの案内では、上記パケットサイズは IEEE802.15.4 のパケットサイズから6バイト分の余裕がありましたが、2バイト分を将来のための予備と変更しました。この２バイトについてもユーザの判断で利用できます。


# アドレスの指定

## 単純ネットの場合

送り主と宛先アドレスの指定方法はロングアドレスとショートアドレスの２種類あります。

### ロングアドレス

TWELITE の32bitモジュールシリアル番号(32bit)を指定します。アドレスは ToCoNet\_u32GetSerial() API により取得できます。

また、TWELITE モジュールのシールド缶に表示されている７桁の１６進数の S/N (シリアル番号) に 0x80000000 を加えたものになります。例えば 1012ABC というシリアル番号の場合は 0x81012ABC となります。

{% hint style="warning" %}
宛先をロングで指定する場合、パケットのペイロードサイズは小さくなります。（[パケットの最大長](/twelite-net-api-expl/paketto/pakettono)）
{% endhint %}

{% hint style="info" %}
IEEE802.15.4 規格では、64bit の MAC アドレスを使用しています。32bitモジュールアドレスを元に 64bit MAC アドレスを指定しています。
{% endhint %}

### ショートアドレス

0x0000 〜 0x0FFF までのアドレスを指定できます。アドレスは [cbAppColdStart](/twelite-net-api-ref/krubakku/cbappcoldstart)() 関数中で　[sToCoNet\_AppContext](/twelite-net-api-ref/gou-zao-ti/stoconet_appcontext).u16ShortAddress に設定します。

### 同報通信（ショートアドレス 0xFFFF）

同報通信を行う場合に使用するアドレスです。


# アプリケーションID

TWELIET NET では32bitで指定されるアプリケーションIDにより、同じ物理チャネルの通信でも互いに違うネットワークを構成します。つまり違うアプリケーションID同士の通信は出来ません。

{% hint style="info" %}
IEEE802.15.4 では 16bit の PAN ID により、ネットワークを識別します。TWELITE NET でも PAN ID の仕組みを利用してアプリケーションIDを実装しています。
{% endhint %}

## アプリケーションIDのルール

解説のため 32bit を HHHHLLLL と表記します。つまり、上位１６ビットをHHHH、下位１６ビットを LLLL とします。

### ユーザが指定設定可能な値

この範囲に指定するアドレスは、他のユーザが設定する可能性もあります。万が一重複した場合は、設置者間による調整をする前提で運用してください。

* HHHH : 0x0001 - 0x7FFF
* LLLL: 0x0001 - 0x7FFF

### TWELITE モジュールオーナーが設定可能な値

お持ちの TWELITE モジュールのシリアル番号に 0x80000000 を加えたIDを重複しないアドレスとして利用可能です。

* HHHH : 0x8000 - 0x8FFF
* LLLL: 0x0001 - 0xFFFE


# ネットワークについて

TWELITE NETでは無線パケットの配送について、2つの方式を用意しています。

## 単純ネット

単純ネットでは、アプリケーションIDとアドレスのみでの通信を行います。電波範囲内の通信は自由です。親機と子機という概念も存在せず、アプリケーションが役割を決定します。

例えば、ショートアドレスを 0 を親局とし、子局は1〜100の最大101台のネットワークです。子局は常にアドレス 0 に送信すれば親局への通信となります。

単純ネットでは以下の通信を行います。

* [ショートアドレス](broken://pages/-LB0B9HP7r0M_p1j7fql#shtoadoresu)を指定した通信
* [ロングアドレス](broken://pages/-LB0B9HP7r0M_p1j7fql#ronguadoresu)を指定した通信
* 電波到達範囲全てに行う同報通信

また、通信の成功を知る方法も用意されています。

* 送信先から確認パケットを受け取る [MAC ACK 通信](broken://pages/-LB1q9jHCya5M6h0xVA-#mac-ackackackki)

{% hint style="info" %}
MAC ACK は、相手先への到着確認が出来る（例外的に正しく確認ができない場合があります。）という点で便利ですが、相手先のアドレスが事前にわかっていなければなりません。

MAC ACK を使用する場合は、一定回数の再送が自動的に行われますが、電波状況が良い場合は再送がありませんが、悪い場合は最大回数再送を行う振る舞いをします。対して使用しない場合は、常に2回または3回同じパケットを送信します。どちらが良いかはケースバイケースです。

MAC ACK を使用する場合の難点の一つが、中継を行う場合です。子局が親局へ中継機を通じて通信したい場合、子局は送信前に親局へ直接送信するか、中継機に送信するかを決めなければ MAC ACK は利用できません。事前に設置時に送り先が決まっていれば問題ありませんが、多くのアプリケーションでは動的に近い局に送信するような設置をする要求がありますが、最も近在にあり通信可能性が高い局を決定するには、少なくとも１往復の通信が必要になります。この通信は失敗する場合もありますし不確実な中継先を選ぶ可能性もあります。また電池消耗の原因にもなります。安定した通信が見込める中継機が確定し、その状態が維持される限り効率的な通信が可能ですがそうでない場合は、通信途絶など不安定なネットワークになります。

[App\_Twelite](https://mono-wireless.com/jp/products/TWE-APPS/App_Twelite/) など、単純ネットを用いるアプリケーションでは、MAC ACK を敢えて使用せず、同報通信により中継を行っています。パケットが一定回数中継したらそれ以上中継しない、同じパケットは再度中継しないという２つの単純なルールにより中継を行います。中継段数が多くない場合はそれほど効率は悪化しませんし、なによりも、子局がパケットを送りさえすれば、周りに中継機が居る限り常に親局へ届く可能性が高いという点で安定的です。
{% endhint %}

## 中継ネット

中継ネットは、ネットワークの構成などに一定の条件を定め、その範囲で中継ネットワークの構築と配送を自動化します。


# 単純ネット

単純ネットでは、TWENET 内での中継配送手続きの介在を行わず、単純なノード間通信を行います。通信方法はアドレス指定によるもの、同報通信による２種類を利用します。標準アプリケーション [App\_Twelite](https://mono-wireless.com/jp/products/TWE-APPS/App_Twelite/index.html) など多くのアプリケーションはこの単純ネットを用いています。

### 中継について

単純ネットでサポートする通信自体は中継を実施しないスター型のネットワークになりますが、簡単で実用的な中継を実装する方法もあります。

{% hint style="info" %}
中継配送を行う場合は、いくつかの方法があります。代表的な中継方法を紹介します。

同報通信により中継を実施する方法。受信したパケット内に中継回数にあたる寿命データを含めておいて、中継ごとに寿命カウントを減少させて、一定回数無条件に中継する。
{% endhint %}

{% hint style="info" %}
特定の要求に基づいたネットワークの実装も可能です。例えばショートアドレスを決め打ちにしたリニア型のネットワークです。

親局は 0x0000 のアドレスとし、親局から順に 0x0001 0x0002 ... とショートアドレスを振っていきます。自局の前後のアドレスは常に通信可能という前提をおきます。

こうすれば、子局から親局の配送は、自局のアドレスより１小さいアドレスに配送します。
{% endhint %}

{% hint style="danger" %}

#### ネットワークの自動構成について

周囲の中継器を探索し、中継局を決定することは、無線通信においては非常にオーバヘッドが大きいため、多くのアプリケーションでは推奨されません。

* 通信相手先を決定するのに多くの無線通信が必要になる。
  * 電池の消耗
  * 起動後から通信可能になるまでの時間がかかる
* 安定性が高くない中継局が選ばれてしまう場合がある。
  * 通信相手先の探索条件を、その時もっとも良い通信とした場合、偶然条件が良かった遠くの局が選ばれてしまう。
* 通信相手先の途絶を知るにも時間がかかる。
  * 通信失敗が連続したといった条件を成立するまでは、通信相手先の途絶とすることができないため、通信相手先の再探索まで長い時間が必要（または動的に通信相手先を切り替えるといった処方が必要）
* 中継ネットワークを維持するために多くの無線通信が必要になる。
  * 帯域の圧迫となり、結果として、収容可能ノード数が減少する。

上記のような中継局を決定・維持するための原理的な問題があります。どのような手法を取っても一長一短があり、要求に合わせて考慮する必要があります。

一般に電池駆動のノードでは、こういった中継のための通信は現実的でありません。
{% endhint %}

### 役割と宛先について

単純ネットであっても、通常は親子といった役割を定めたネットワークとします。この役割についても、無線パケット通信ではいくつかの実装方法があります。

{% hint style="info" %}

#### アドレスによるもの。

無線パケットでサポートするアドレス方式をそのまま用いて、アプリケーションでの役割を実現する方法です。具体的には[ショートアドレス](broken://pages/-LB0B9HP7r0M_p1j7fql#nettono)を用いて、親局のアドレスを 0x0000 とし、子局のアドレスを 0x0001 ... とする方法です。

子局は親局に配送する場合は、常に 0x0000 宛に配送すればよく、また、中継を必要としない場合は、ACK 通信を用いて効率的な無線配送が可能です。
{% endhint %}

{% hint style="info" %}

#### パケット内のデータによるもの。

中継を実現したい場合は、アドレスや役割に相当するもの（ここでは論理アドレスと言います）を無線パケット内のデータとして格納します。

親局には 0x00 という論理アドレスを割り振ります。子局には0x01...という論理アドレスを割り振ります。この論理アドレスは、無線送信時のパケット内のデータとして、送り主・宛先として格納します。

ショートアドレスの仕組みを使用したいところですが、中継を行う時に都合が良くないため（中継局のショートアドレスを送信元アドレスとして中継パケットを送るため）、パケット内のデータとして格納します。

無線パケットは全て同報通信として送信します。同報通信であるため、電波到達可能範囲の全てのノードがそのパケットを受信します。（注：宛先を指定したパケットであっても、その内容は電波到達範囲であれば全てのノードが受信します。宛先が違うためその受信データを無視しているだけです。）

受信されたパケットのデータを参照して、自局で処理すべきか、中継すべきかといったことをアプリケーション側で決定します。
{% endhint %}


# 送信

単純ネットワークでの送信手続きは、[tsTxDataApp](/twelite-net-api-ref/gou-zao-ti/tstxdataapp) 構造体を確保し、この構造体に送信に必要な情報を格納します。

1. ローカル変数として tsTxDataApp 構造体を確保し、構造体全体をゼロクリアする。
2. 送信したいデータを .auData にコピーする（ペイロード）。
3. ペイロードの格納バイト数を .u8Len に格納する。
4. .u32DstAddr を格納する（宛先）
5. .u32SrcAddr を格納する（送り元のアドレス）
6. その他送信オプションを指定します。
7. [ToCoNet\_bMacTxReq](/twelite-net-api-ref/twelite-net-guan-shu/toconet_bmactxreq)() を実行します。
8. TWENET 内での送信処理が終了すると [cbToCoNet\_TxEvent](/twelite-net-api-ref/krubakku/cbtoconet_vtxevent)() が実行されます。

{% hint style="warning" %}
完了イベントが消滅することは例外的ですが、タイムアウトを設け例外処理するようにしてください。 tsTxDataApp 構造体中で遅延や再送遅延が極端に長く設定されていないなら、通常 100ms も必要としません。
{% endhint %}

### サンプルコード

```c
static int16 i16TransmitIoData() {
  tsTxDataApp sTx;
  memset(&sTx, 0, sizeof(sTx)); // ゼロクリア
  uint8 *q = sTx.auData;

  // ペイロードを構成
  S_OCTET(sAppData.u8AppIdentifier);
  S_BE_WORD(sAppData.sIOData_now.u16Volt);
  ...
	
  // 送信
  sTx.u8Len = q - sTx.auData; // パケット長
  sTx.u8Cmd = TOCONET_PACKET_CMD_APP_USER_IO_DATA; // パケット種別

  // 送信する
  sTx.u32DstAddr  = TOCONET_MAC_ADDR_BROADCAST; // ブロードキャスト
  sTx.u8Retry     = 0x81; // 1回再送

  // フレームカウントとコールバック識別子の指定
  sAppData.u16TxFrame++;
  sTx.u8Seq = (sAppData.u16TxFrame & 0xFF);
  sTx.u8CbId = sTx.u8Seq;

  /* MAC モードでは細かい指定が可能 */
  sTx.bAckReq = FALSE;
  sTx.u32SrcAddr = sToCoNet_AppContext.u16ShortAddress;
  sTx.u16RetryDur = 4; // 再送間隔[ms]
  sTx.u16DelayMax = 16; // 送信開始タイミングにブレを作る(最大16ms)

  // 送信API
  if (ToCoNet_bMacTxReq(&sTx)) {
    // 成功（処理が終わると cbToCoNet_vTxEvent() が発生する
    return sTx.u8CbId; // 成功
  } else {
    // 失敗
    return -1; // 失敗
  }
}
```

{% hint style="info" %}
[S\_OCTET](/twelite-net-api-ref/twelite-net-makuro/utils.h#s_octet-x)() [S\_BE\_WORD](/twelite-net-api-ref/twelite-net-makuro/utils.h#s_be_word-x-s_le_word-x)() [S\_BE\_DWORD](/twelite-net-api-ref/twelite-net-makuro/utils.h#s_be_word-x-s_le_word-x)() マクロは、uint8 \*q をペイロード格納領域のポインタとして宣言しておいた時に使う 1,2,4 バイト格納マクロです。
{% endhint %}


# 受信

パケットの受信は常にコールバック関数 [cbToCoNet\_vRxEvent](/twelite-net-api-ref/krubakku/cbtoconet_vrxevent)() の呼び出しによって行われます。パラメータとして [tsRxDataApp](/twelite-net-api-ref/gou-zao-ti/tsrxdataapp) 構造体へのポインタが渡されます。この構造体の内容を参照し、アプリケーションの各処理を実施します。

{% hint style="danger" %}
本関数の終了(return)を遅延させるべきではありません。通常無線パケットは一般でも最短で 1ms 程度の間隔をあけて伝達されますが、これを超えた長時間の遅延により、無線パケットの取りこぼしが発生するかもしれません。
{% endhint %}


# 中継ネット

TWELITE NETでは中継ネットとして、LayerTree (レイヤーツリー) ネットワークがあります。

LayerTree （レイヤーツリー）ネットワークは、上り方向の配送を効率的に実施する目的を持って設計された中継ネットワークです。もっぱら送信のみを行う LayerTree\_mininodes も LayterTree ネットワークの一部です。

## 基本ルール

* 親機は１台のみで、全ての通信は親機に集約されます。
* 原則として配送方向は、末端ノードから上位へ、最終的には親機に配送します。
  * 親機から下り方向の配送は、同報通信による配送となります。
  * 子機や中継器同士の通信は親機に一旦配送してから通信します。
    * ただし電波到達範囲にあるノード間は、アドレスを指定することで直接送信できます。
* 中継器は、自身の階層数を事前確定しておきます。
* 電波到達範囲にある、自身の階層数より上位の中継器（階層数の小さい番号をもつ中継器）に接続します。
* 送信先中継器を決めずもっぱら送信のみを行う LayerTree Mininodes を用いると、電池の消費が非常に小さいセンサーノードとして振る舞えます。(App\_Tag)

![](/files/-LCXu_-U5HGL9oUdRssx)

## レイヤーについて

親機は0番で、最大63までレイヤーの番号を振ることができます。

![](/files/-LCXwAmtt8qKqGN_USgU)

昇順であれば、番号が飛んでも構いません。


# 親機の実装

親機の基本的な実装を見ます。

## モジュール定義, include

```c
#define ToCoNet_USE_MOD_NWK_LAYERTREE
#define ToCoNet_USE_MOD_NBSCAN
#define ToCoNet_USE_MOD_NBSCAN_SLAVE
#define ToCoNet_USE_MOD_NWK_MESSAGE_POOL
#define ToCoNet_USE_MOD_DUPCHK

// includes
#include "ToCoNet.h"
#include "ToCoNet_mod_prototype.h"
```

## cbAppColdStart()

アプリケーションIDやチャネルは、ここで決めておきます。また初期化処理等は `vProcessEvCore()` 関数に記述します。

```c
void cbAppColdStart(bool_t bAfterAhiInit) {
	if (!bAfterAhiInit) { // before AHI init, very first of code.
		// Register modules
		ToCoNet_REG_MOD_ALL();
	} else {
		// TWELITE NET configuration
		sToCoNet_AppContext.u32AppId = 0x12345678;
		sToCoNet_AppContext.u8Channel = 18;
		sToCoNet_AppContext.bRxOnIdle = TRUE;

		// Register user PRSEV.
		ToCoNet_Event_Register_State_Machine(vProcessEvCore);
	}
}
```

## cbToCoNet\_vNwkEvent()

親機では `E_EVENT_TOCONET_NWK_START` メッセージを処理します。

```c
void cbToCoNet_vNwkEvent(teEvent eEvent, uint32 u32arg) {
	switch (eEvent) {
	case E_EVENT_TOCONET_NWK_START:
		// send this event to the local event machine.
		ToCoNet_Event_Process(eEvent, u32arg, vProcessEvCore);
		break;
	default:
		break;
	}
}
```

## cbToCoNet\_vRxEvent()

受信方法は単純ネットと大きく変わりません。[`tsRxDataApp` 構造体](/twelite-net-api-ref/netto-api/structure/tsrxdataapp-netto)には違いがあります。

```c
void cbToCoNet_vRxEvent(tsRxDataApp *pRx) {
	uint8 *p = pRx->auData;

	// パケットの表示
	if (pRx->u8Cmd == TOCONET_PACKET_CMD_APP_DATA) {
		// 基本情報
		uint8 u8lqi_1st = pRx->u8Lqi; // LQI
		uint32 u32addr_1st = pRx->u32SrcAddr; // 送信元

		// データの解釈
		uint8 u8b = G_OCTET();
		...
	}
}
```

## vProcessEvCore()

システム始動時 [`E_EVENT_START_UP`](/twelite-net-api-ref/yzaibento/ibento) に、[`tsToCoNet_NwkLyTr_Config`](/twelite-net-api-ref/netto-api/layertree-netto/tstoconet_nwklytr_context) 構造体の設定、[`ToCoNet_NwkLyTr_psConfig()`](/twelite-net-api-ref/netto-api/layertree-netto/toconet_nwklytr_psconfig) 関数の実行、 [`ToCoNet_Nwk_bInit()`](https://github.com/monowireless/doc_TWENET_JP/blob/jp_new/twelite-net-api-ref/netto-api/sys_callbacks/toconet_nwk_binit.md) 関数によるネットワークの初期化、[`ToCoNet_Nwk_bStart()`](https://github.com/monowireless/doc_TWENET_JP/blob/jp_new/twelite-net-api-ref/netto-api/sys_callbacks/toconet_nwk_bstart.md) 関数によるネットワークの開始を行います。

ネットワーク開始後に、`E_EVENT_TOCONET_NWK_START` イベントを受け取ります。

```c
static tsToCoNet_NwkLyTr_Config sNwkLayerTreeConfig;
static tsToCoNet_Nwk_Context* pContextNwk;

static void vProcessEvCore(tsEvent *pEv, teEvent eEvent, uint32 u32evarg) {
	switch (pEv->eState) {
	case E_STATE_IDLE:
		if (eEvent == E_EVENT_START_UP) {
			V_PRINTF(LB"[E_STATE_IDLE]");

			// Configure the Network
			sNwkLayerTreeConfig.u8Layer = 0;
			sNwkLayerTreeConfig.u8Role 
				= TOCONET_NWK_ROLE_PARENT;

			pContextNwk =
				ToCoNet_NwkLyTr_psConfig(&sNwkLayerTreeConfig);
			if (pContextNwk) {
				ToCoNet_Nwk_bInit(pContextNwk);
				ToCoNet_Nwk_bStart(pContextNwk);
			}

		} else if (eEvent == E_EVENT_TOCONET_NWK_START) {
			// START イベントを持って RUNNING 状態に遷移
			// * cbToCoNet_vNwkEvent() より伝達
			ToCoNet_Event_SetState(pEv, E_STATE_RUNNING);
		} else {
			;
		}
		break;

	case E_STATE_RUNNING:
		if (eEvent == E_EVENT_NEW_STATE) {
			V_PRINTF(LB"[E_STATE_RUNNING]");
		} else {
			; // DO SOMETHING ELSE!
		}
		break;

	default:
		break;
	}
}
```


# 中継器の実装

中継機の基本的な実装を見ます。

{% hint style="info" %}
中継器は、ネットワークの要求に応えて中継する機能を提供しますが、中継以外にもセンサー情報の送信といった処理も可能です。原則として常時給電で動作させます。
{% endhint %}

## モジュール定義, include

```c
#define ToCoNet_USE_MOD_NWK_LAYERTREE
#define ToCoNet_USE_MOD_NBSCAN
#define ToCoNet_USE_MOD_NBSCAN_SLAVE
#define ToCoNet_USE_MOD_NWK_MESSAGE_POOL
#define ToCoNet_USE_MOD_DUPCHK

// includes
#include "ToCoNet.h"
#include "ToCoNet_mod_prototype.h"
```

## cbAppColdStart()

アプリケーションIDやチャネルは、ここで決めておきます。また初期化処理等は `vProcessEvCore()` 関数に記述します。

```c
void cbAppColdStart(bool_t bAfterAhiInit) {
	if (!bAfterAhiInit) { // before AHI init, very first of code.
		// Register modules
		ToCoNet_REG_MOD_ALL();
	} else {
		// TWELITE NET configuration
		sToCoNet_AppContext.u32AppId = 0x12345678;
		sToCoNet_AppContext.u8Channel = 18;
		sToCoNet_AppContext.bRxOnIdle = TRUE;

		// Register user PRSEV.
		ToCoNet_Event_Register_State_Machine(vProcessEvCore);
	}
}
```

## cbToCoNet\_vNwkEvent()

中継機では `E_EVENT_TOCONET_NWK_START` `E_EVENT_TOCONET_NWK_DISCONNECT` メッセージを処理します。

```c
void cbToCoNet_vNwkEvent(teEvent eEvent, uint32 u32arg) {
	switch (eEvent) {
	case E_EVENT_TOCONET_NWK_START:
		A_PRINTF( LB"[E_EVENT_TOCONET_NWK_START]");
		break;

	case E_EVENT_TOCONET_NWK_DISCONNECT:
		A_PRINTF( LB"[E_EVENT_TOCONET_NWK_DISCONNECT]");
		break;
	}
}
```

## cbToCoNet\_vRxEvent()

受信方法は単純ネットと大きく変わりません。[`tsRxDataApp` 構造体](/twelite-net-api-ref/netto-api/structure/tsrxdataapp-netto)には違いがあります。

{% hint style="info" %}
中継パケットは `cbToCoNet_vRxEvent()` コールバックでは処理されません。中継器に直接届いたパケット(送信専用の子機からパケットなど)を処理します。
{% endhint %}

```c
void cbToCoNet_vRxEvent(tsRxDataApp *pRx) {
	uint8 *p = pRx->auData;

	// パケットの表示
	if (pRx->u8Cmd == TOCONET_PACKET_CMD_APP_DATA) {
		// 基本情報
		uint8 u8lqi_1st = pRx->u8Lqi; // LQI
		uint32 u32addr_1st = pRx->u32SrcAddr; // 送信元

		// データの解釈
		uint8 u8b = G_OCTET();
		...
	}
}
```

## vProcessEvCore()

システム始動時 [`E_EVENT_START_UP`](/twelite-net-api-ref/yzaibento/ibento) に、[`tsToCoNet_NwkLyTr_Config`](/twelite-net-api-ref/netto-api/layertree-netto/tstoconet_nwklytr_context) 構造体の設定、[`ToCoNet_NwkLyTr_psConfig()`](/twelite-net-api-ref/netto-api/layertree-netto/toconet_nwklytr_psconfig) 関数の実行、 [`ToCoNet_Nwk_bInit()`](https://github.com/monowireless/doc_TWENET_JP/blob/jp_new/twelite-net-api-ref/netto-api/sys_callbacks/toconet_nwk_binit.md) 関数によるネットワークの初期化、[`ToCoNet_Nwk_bStart()`](https://github.com/monowireless/doc_TWENET_JP/blob/jp_new/twelite-net-api-ref/netto-api/sys_callbacks/toconet_nwk_bstart.md) 関数によるネットワークの開始を行います。

設定では中継器の指定(`TOCONET_NWK_ROLE_ROUTER`)、レイヤー 数、NBビーコンの指定(`TOCONET_MOD_LAYERTREE_STARTOPT_NB_BEACON`)が必須です。

ネットワーク開始後に、`E_EVENT_TOCONET_NWK_START` イベントを受け取ります。また、上位ノードをロストした場合 `E_EVENT_TOCONET_NWK_DISCONNECT` を受け取ります。

```c
static tsToCoNet_NwkLyTr_Config sNwkLayerTreeConfig;
static tsToCoNet_Nwk_Context* pContextNwk;

static void vProcessEvCore(tsEvent *pEv, teEvent eEvent, uint32 u32evarg) {
	switch (pEv->eState) {
	case E_STATE_IDLE:
		if (eEvent == E_EVENT_START_UP) {
			memset(&sNwkLayerTreeConfig, 0, sizeof(sNwkLayerTreeConfig));
			
			// layer 数の決定
			sNwkLayerTreeConfig.u8Layer = 4;

			// NBビーコン方式のネットワークを使用する
			sNwkLayerTreeConfig.u8StartOpt =
				TOCONET_MOD_LAYERTREE_STARTOPT_NB_BEACON;

			// 中継器として始動
			sNwkLayerTreeConfig.u8Role = TOCONET_NWK_ROLE_ROUTER;
			pContextNwk = ToCoNet_NwkLyTr_psConfig(&sNwkLayerTreeConfig);
			if (pContextNwk) {
				ToCoNet_Nwk_bInit(pContextNwk);
				ToCoNet_Nwk_bStart(pContextNwk);
			} else {
				// fatal error
			}
		}
		break;

	default:
		break;
	}
}
```


# 子機の実装 (MININODES)

子機の基本的な実装を見ます。

{% hint style="info" %}
本ページでは LAYERTREE\_MININODES モジュールによる、送信専用子機について紹介します。
{% endhint %}

## モジュール定義, include

```c
#define ToCoNet_USE_MOD_NWK_LAYERTREE_MININODES

// includes
#include "ToCoNet.h"
#include "ToCoNet_mod_prototype.h"
```

## cbAppColdStart()

アプリケーションIDやチャネルは、ここで決めておきます。また初期化処理等は `vProcessEvCore()` 関数に記述します。

```c
void cbAppColdStart(bool_t bAfterAhiInit) {
	if (!bAfterAhiInit) { // before AHI init, very first of code.
		// Register modules
		ToCoNet_REG_MOD_ALL();
	} else {
		// TWELITE NET configuration
		/// Application ID
		sToCoNet_AppContext.u32AppId = 0x12345678;
		sToCoNet_AppContext.u8Channel = 18;
		
		/// 受信回路は OFF
		sToCoNet_AppContext.bRxOnIdle = FALSE;
		
		/// CCA は最小限にする
		sToCoNet_AppContext.u8CCA_Level = 1;
		sToCoNet_AppContext.u8CCA_Retry = 0;

		/// 起動時の MAC 初期化を後回しにする。
		///   送信直前で初期化し、不要な場合は初期化しない。
		sToCoNet_AppContext.u8MacInitPending = TRUE;

		// Register user PRSEV.
		ToCoNet_Event_Register_State_Machine(vProcessEvCore);
	}
}
```

## cbAppWarmStart()

単純ネットと同様にハードウェアの初期化等を実施するが、中継ネット特有の処理は `vProcessEvCore()` にて実施する。

## cbToCoNet\_vNwkEvent()

LayerTree MININODES は、上位ノードの決定といった手続きは省略されるため、 `E_EVENT_TOCONET_NWK_START` `E_EVENT_TOCONET_NWK_DISCONNECT` イベントについては処理する必要がありません。

## cbToCoNet\_vRxEvent()

受信方法は単純ネットと大きく変わりません。[`tsRxDataApp` 構造体](/twelite-net-api-ref/netto-api/structure/tsrxdataapp-netto)には違いがあります。

{% hint style="info" %}
中継パケットは [`cbToCoNet_vRxEvent()`](/twelite-net-api-ref/krubakku/cbtoconet_vrxevent) コールバックでは処理されません。中継器に直接届いたパケット(送信専用の子機からパケットなど)を処理します。
{% endhint %}

```c
void cbToCoNet_vRxEvent(tsRxDataApp *pRx) {
	uint8 *p = pRx->auData;

	// パケットの表示
	if (pRx->u8Cmd == TOCONET_PACKET_CMD_APP_DATA) {
		// 基本情報
		uint8 u8lqi_1st = pRx->u8Lqi; // LQI
		uint32 u32addr_1st = pRx->u32SrcAddr; // 送信元

		// データの解釈
		uint8 u8b = G_OCTET();
		...
	}
}
```

## vProcessEvCore()

システム始動時 [`E_EVENT_START_UP`](/twelite-net-api-ref/yzaibento/ibento) に、[`tsToCoNet_NwkLyTr_Config`](/twelite-net-api-ref/netto-api/layertree-netto/tstoconet_nwklytr_context) 構造体の設定、[`ToCoNet_NwkLyTr_psConfig_MiniNodes()`](/twelite-net-api-ref/netto-api/layertree-netto/toconet_nwklytr_psconfig_mininodes) 関数の実行、 [`ToCoNet_Nwk_bInit()`](https://github.com/monowireless/doc_TWENET_JP/blob/jp_new/twelite-net-api-ref/netto-api/sys_callbacks/toconet_nwk_binit.md) 関数によるネットワークの初期化、[`ToCoNet_Nwk_bStart()`](https://github.com/monowireless/doc_TWENET_JP/blob/jp_new/twelite-net-api-ref/netto-api/sys_callbacks/toconet_nwk_bstart.md) 関数によるネットワークの開始を行います。

スリープ前には[`ToCoNet_Nwk_bPause()`](https://github.com/monowireless/doc_TWENET_JP/blob/jp_new/twelite-net-api-ref/netto-api/sys_callbacks/toconet_nwk_bpause.md)、スリープからの起床時には [`ToCoNet_Nwk_bResumte()`](https://github.com/monowireless/doc_TWENET_JP/blob/jp_new/twelite-net-api-ref/netto-api/sys_callbacks/toconet_nwk_bresume.md) を実行します。

```c
static tsToCoNet_NwkLyTr_Config sNwkLayerTreeConfig;
static tsToCoNet_Nwk_Context* pContextNwk;

static void vProcessEvCore(tsEvent *pEv, teEvent eEvent, uint32 u32evarg) {
	switch (pEv->eState) {
	case E_STATE_IDLE:
		if (eEvent == E_EVENT_START_UP) {
			if (u32evarg & EVARG_START_UP_WAKEUP_RAMHOLD_MASK) {
				// RESUME
				ToCoNet_Nwk_bResume(pContextNwk);
			} else {
				// 始動時の処理
				memset(&sNwkLayerTreeConfig, 0, sizeof(sNwkLayerTreeConfig));
				sNwkLayerTreeConfig.u8Role = 
						TOCONET_NWK_ROLE_ENDDEVICE;
				// ネットワークの初期化
				pContextNwk = 
					ToCoNet_NwkLyTr_psConfig_MiniNodes(&sNwkLayerTreeConfig);
	
				if (sAppData.pContextNwk) {
					ToCoNet_Nwk_bInit(pContextNwk);
					ToCoNet_Nwk_bStart(pContextNwk);
				}
			}
		}
		// RUNNING状態へ遷移
		ToCoNet_Event_SetState(pEv, E_STATE_RUNNING);
	break;
	
	case E_STATE_RUNNING:
		if (E_EVENT_NEW_STATE) {
			// センサーデータの取得など
		} else {
			// 
			tsTxDataApp sTx;
			memset(&sTx, 0, sizeof(sTx)); // 必ず０クリアしてから使う！
			uint8 *q =  sTx.auData;
		
			sTx.u32SrcAddr = ToCoNet_u32GetSerial();
		
			if (IS_APPCONF_OPT_TO_ROUTER()) {
				// ルータがアプリ中で一度受信して、ルータから親機に再配送
				sTx.u32DstAddr = TOCONET_NWK_ADDR_NEIGHBOUR_ABOVE;
			} else {
				// ルータがアプリ中では受信せず、単純に中継する
				sTx.u32DstAddr = TOCONET_NWK_ADDR_PARENT;
			}
		
			// ペイロードの準備
			S_OCTET('T');
			S_OCTET(sAppData.sFlash.sData.u8id);
			S_BE_WORD(sAppData.u16frame_count);		

			//	センサ固有のデータ
			memcpy(q,pu8Data,u8Len);
			q += u8Len;
		
			sTx.u8Cmd = 0; // 0..7 の値を取る。パケットの種別を分けたい時に使用する
			sTx.u8Len = q - sTx.auData; // パケットのサイズ
			sTx.u8CbId = sAppData.u16frame_count & 0xFF; // TxEvent で通知される番号、送信先には通知されない
			sTx.u8Seq = sAppData.u16frame_count & 0xFF; // シーケンス番号(送信先に通知される)
			sTx.u8Retry = sAppData.u8Retry;

			if (ToCoNet_Nwk_bTx(pNwk, &sTx)) {
				ToCoNet_Event_SetState(pEv, E_STATE_APP_WAIT_TX);
			} else {
				// ...失敗した（スリープ処理)
				ToCoNet_Event_SetState(pEv, E_STATE_SLEEP);
			}
		}
		break;
		
	case E_STATE_APP_WAIT_TX:
		if (...) { // Wait Tx Completion
			ToCoNet_Event_SetState(pEv, E_STATE_SLEEP);
		}
		break;
	
	case E_STATE_APP_SLEEP:
		if (eEvent == E_EVENT_NEW_STATE) {
			// 中継ネットのポーズ処理を行う
			ToCoNet_Nwk_bPause(sAppData.pContextNwk);

			// 周期スリープに入る
			//  - 初回は５秒あけて、次回以降はスリープ復帰を基点に５秒
			vSleep(5000, TRUE, FALSE);
		}
		break;

	default:
		break;
	}
}
```


# NBビーコン方式の接続

中継器や親機は定期的にNBビーコンを送出し、このビーコンを受信したルータは、受信した NBビーコンにもとづき上位ノードを決定する方法です。

{% hint style="info" %}
各ノードが始動時などに[近隣探索](/twelite-net-api-ref/mojru-raiburari/nb-scan)(NBSCAN)を実行し、上位ノードを決定する方法もあります。これに比べ以下のメリットがあります。

* ネットワークが一斉に始動した時の混乱を避けられる
* 非常に混雑したネットワークでの探索失敗リスクが減少する

反面NBビーコンを受信できるまで上位ノードが決定できないため、電波条件が良い場合は余分に時間を必要とすることです。
{% endhint %}

{% hint style="warning" %}
TWELITE NET 1.2 では、従来提供していた[近隣探索](/twelite-net-api-ref/mojru-raiburari/nb-scan)(NBSCAN)を用いた方式も動作可能ですが、新規実装には推奨しません。
{% endhint %}

## プログラミングについて

`tsToCoNet_NwkLyTr_Config` 構造体の設定パラメータにより NB ビーコンモードを設定する。本モードを利用する場合 Parent ならびに Router は必ず設定が必要である。

コード例

```c
tsToCoNet_NwkLyTr_Config sNwkLayerTreeConfig;
  
// set NB beacon mode
sNwkLayerTreeConfig.u8Second_To_Beacon = 3; // set NB beacon interval
sNwkLayerTreeConfig.u8StartOpt = 0x02; // set NB beacon mode
  
// set as Router
sAppData.sNwkLayerTreeConfig.u8Role = TOCONET_NWK_ROLE_ROUTER;
    /* 親機の場合 TOCONET_NWK_ROLE_PARENT を設定する */;
pContextNwk = ToCoNet_NwkLyTr_psConfig(&ssNwkLayerTreeConfig);
```

## 上位ノード決定方法について

上位ノードは原則として約10秒に１回NBビーコン送信を行います。過去 120 秒以内に到達したパケットで、到達回数や[LQI](/twelite-net-api-expl/yong-yu#lqi)を評価して上位ノードを決定します。

到達履歴として最大６ノード、各ノードにつき８パケット分を評価します。

## 制限事項

* 子機は LAYERTREE\_MININODE 方式、中継器、親機は NBビーコン方式という組み合わせを想定します 。（App\_Tag向け）
* 同一レイヤ内を中継する SUBTREE には対応しません。


# 中継ネットのアドレス

中継ネット特有のアドレス指定です。

| 定義名                                  | 値            | 意味                             |
| ------------------------------------ | ------------ | ------------------------------ |
| `TOCONET_NWK_ADDR_PARENT`            | `0x80000000` | 親機                             |
| `TOCONET_NWK_ADDR_\ NEIGHBOUR_ABOVE` | `0x80000001` | ネットワークアドレス、直接接続している中継・親機       |
| `TOCONET_NWK_ADDR_BROADCAST`         | `0x8000FFFF` | ネットワークアドレス、ブロードキャスト（親機からの指定のみ） |


# 上位アドレスを固定した静的中継

LayerTree ネットワークで、上位アドレスを固定して静的に中継する方法です。

`tsNwkLayerTreeConfig` 構造体にメンバーを以下のように設定します。

```c
sNwkLayerTreeConfig.u8StartOpt = 
    TOCONET_MOD_LAYERTREE_STARTOPT_FIXED_PARENT;
            // 開始時にスキャンしない

sNwkLayerTreeConfig.u8ResumeOpt = 
    TOCONET_MOD_LAYERTREE_RESUMEOPT_NO_RELOCATE_ON_RESUME;			
            // レジューム時にも固定親機運用する

sNwkLayerTreeConfig.u32AddrHigherLayer = 0x80012345;
            // 0x80012345 のノードを上位とする

```

{% hint style="warning" %}
[NBビーコン](broken://pages/-LCXwQyCwqKDzhUii2wj)(`TOCONET_MOD_LAYERTREE_STARTOPT_NB_BEACON`)を指定した場合は、NBビーコンによる上位決定ができない時に限り固定設定アドレスが有効になります。
{% endhint %}


# TWELITE NET API リファレンス


# コールバック関数

コールバック関数は、TWENET の様々なイベントが発生したときに処理するための関数です（[フロー図](/twelite-net-api-expl/twenet-fur)）。TWENET ライブラリでアプリケーションをビルドする際に、すべて実装が必要です。特に重要な処理を記述するのが [cbAppColdStart](/twelite-net-api-ref/krubakku/cbappcoldstart)() で、一般的な main() 関数に相当する関数です。

* [cbAppColdStart](/twelite-net-api-ref/krubakku/cbappcoldstart)() – 電源投入時に呼び出される関数
* [cbAppWarmStart](/twelite-net-api-ref/krubakku/cbappwarmstart)() – スリープ復帰時に呼び出される関数
* [cbToCoNet\_vMain](/twelite-net-api-ref/krubakku/cbtoconet_vmain)() – メインループ 無限ループではなく割り込みなどの発生を起点として呼び出されます
* [cbToCoNet\_vRxEvent](/twelite-net-api-ref/krubakku/cbtoconet_vrxevent)() – 無線パケット受信時に呼び出されます
* [cbToCoNet\_vTxEvent](/twelite-net-api-ref/krubakku/cbtoconet_vtxevent)() – 無線パケット送信完了時に呼び出されます
* [cbToCoNet\_vNwkEvent](/twelite-net-api-ref/krubakku/cbtoconet_vnwkevent)() – MAC層やネットワーク層の各種イベント通知
* [cbToCoNet\_vHwEvent](/twelite-net-api-ref/krubakku/cbtoconet_vhwevent) () – ペリフェラルの割り込み処理の遅延実行部。割り込み処理後に呼び出されます
* [cbToCoNet\_u8HwInt](/twelite-net-api-ref/krubakku/cbtoconet_u8hwint)() – ペリフェラルの割り込みハンドラ
* ユーザ定義イベント処理関数 – 状態遷移によるタスク処理を記述します

いずれのコールバック関数も、呼び出された後に制御を返す必要があり、非常に長い処理を記述すると全体の振る舞いに影響します。特に割り込みハンドラの記述には気を配ります。


# cbAppColdStart()

## 解説

`cbAppColdStart(bool_t bStart)` は、`bStart == FALSE` で最初に呼び出され、その後 `bStart == TRUE` で呼び出されます。`bStart == TRUE` の節でアプリケーションの初期化処理を行います。

ここで TWELITE NET の重要な初期化 ([`sToCoNet_AppContext`](broken://pages/-LB-iFVz_Ov3iZzxfW1U) 構造体) を行う必要が有ります。一部の機能はここでしか設定できません。

[`ToCoNet_Event_Register_State_Machine()`](/twelite-net-api-ref/yzaibento/toconet_event-api/toconet_event_register_state_machine) 関数にて、ユーザ定義イベント処理関数を登録しています。

この処理の最後で [`ToCoNet_vMacStart()`](/twelite-net-api-ref/twelite-net-guan-shu/toconet_vmacstart) 関数を呼び出します。

API の手続きとして MAC 層の開始を明示しています。

## 引数

| 型        | 名前       | 詳細                                    |
| -------- | -------- | ------------------------------------- |
| `bool_t` | `bStart` | 起動時に２回呼び出され、最初が`FALSE`、2回目が`TRUE`となる。 |

#### bStart

`FALSE`：マイコンの起動直後で、ペリフェラル等の初期化も行われていない。ここでモジュール登録の [`ToCoNet_REG_MOD_ALL()`](broken://pages/-LB-k-KjxdeixZFXN5c7)マクロを呼び出す。

`TRUE`：TWELITE NET ライブラリやハードウェアAPIの初期化が行わた後、ライブラリの初期化前で呼び出される。ここでは以下の手続きを記述する。

* [`sToCoNet_AppContext`](broken://pages/-LB-iFVz_Ov3iZzxfW1U) 構造体に初期パラメータの設定
* [`ToCoNet_Event_Register_State_Machine()`](/twelite-net-api-ref/yzaibento/toconet_event-api/toconet_event_register_state_machine) によりステートマシンの登録
* アプリケーション独自のメモリ領域等の初期化
* ハードウェアの初期化
* [`ToCoNet_vMacStart()`](/twelite-net-api-ref/twelite-net-guan-shu/toconet_vmacstart) によるMAC 層の開始

## 戻り値

なし

## サンプル

```c
void cbAppColdStart(bool_t bAfterAhiInit)
{
	if (!bAfterAhiInit) {
		// before AHI init, very first of code.

		// Register modules
		ToCoNet_REG_MOD_ALL();

	} else {
		// disable brown out detect
		vAHI_BrownOutConfigure(0,//0:2.0V 1:2.3V
				FALSE,
				FALSE,
				FALSE,
				FALSE);

		// clear application context
		memset (&sAppData, 0x00, sizeof(sAppData));
		sAppData.u8channel = CHANNEL;

		// ToCoNet configuration
		sToCoNet_AppContext.u32AppId = APP_ID;
		sToCoNet_AppContext.u8Channel = CHANNEL;

		sToCoNet_AppContext.bRxOnIdle = TRUE;

		// others
		SPRINTF_vInit128();

		// Register
		ToCoNet_Event_Register_State_Machine(vProcessEvCore);

		// Others
		vInitHardware(FALSE);

		// MAC start
		ToCoNet_vMacStart();
	}
}
```


# cbAppWarmStart()

## 解説

`cbAppWarmStart(bool_t bStart)` は、`bStart == FALSE` で RAM 保持スリープ復帰後に呼び出され、その後 `bStart == TRUE` で呼び出されます。`bStart == TRUE` の節でアプリケーションの初期化処理を行います。

{% hint style="info" %}
RAMが保持されないスリープからの復帰時は、[`cbAppColdStart()`](/twelite-net-api-ref/krubakku/cbappcoldstart) が呼び出されます。
{% endhint %}

RAMや[DIO](/hw-api-ref/perifuraru/dio)等の一部のハードウェア状態は保持されるため、これらの再初期化は不要です。

## 引数

| 型        | 名前       | 詳細                                        |
| -------- | -------- | ----------------------------------------- |
| `bool_t` | `bStart` | スリープ復帰時に２回呼び出され、最初が`FALSE`、2回目が`TRUE`となる。 |

#### bStart

`FALSE`：マイコンの起動直後で、ペリフェラル等の初期化も行われていない。ここではスリープからの復帰要因（タイマーによるものなのかDIO割り込みによるものかなど）を確認できます。

`TRUE`：TWELITE NET ライブラリやハードウェアAPIの初期化が行わた後、ライブラリの初期化前で呼び出される。ここでは以下の手続きを記述します。

* ハードウェアの初期化（多くのペリフェラルは再初期化します。DIOの設定はスリープ中も保持されます）
* [`ToCoNet_vMacStart()`](/twelite-net-api-ref/twelite-net-guan-shu/toconet_vmacstart) によるMAC 層の開始

## 戻り値

なし

## サンプル

```c
uint32 u32DioPortWakeUp; // DIO interrupt mask bits 
static bool_t bWakeupByButton; // TRUE: woke up by DIO interrupt

void cbAppWarmStart(bool_t bStart)
{
	if (!bStart) {
		// before AHI init, very first of code.
		//  to check interrupt source, etc.
		bWakeupByButton = FALSE;

		if(u8AHI_WakeTimerFiredStatus()) {
			// wake up timer
		} else
		if(u32AHI_DioWakeStatus() & u32DioPortWakeUp) {
			// woke up from DIO events
			bWakeupByButton = TRUE;
		} else {
			bWakeupByButton = FALSE;
		}
	} else {
		// Initialize hardware
		vInitHardware(TRUE);

		// MAC start
		ToCoNet_vMacStart();
	}
}
```


# cbToCoNet\_vMain()

## 解説

TWELITE NET のアプリケーションメインループからの呼び出されます。電力を節約するドーズ(DOZE)から復帰後に呼び出され、UART からの入力処理など頻繁に確認する必要のある処理を記述します。

{% hint style="info" %}
アプリケーションの主処理は、ユーザ定義イベント処理関数で記述することを推奨します。
{% endhint %}

主な割り込み要因は、[UART](/hw-api-ref/perifuraru/uart), [TickTimer](/hw-api-ref/perifuraru/ticktimer), 無線イベント(送信完了、受信)です。

## 引数

なし

## 戻り値

なし

## サンプル

```c
void cbToCoNet_vMain(void) {
	// Handle serial (uart) input
	vHandleSerialInput(SERIAL_FROM_QUEUE);
}
```


# cbToCoNet\_vRxEvent()

## 解説

無線パケット受信後に呼び出されます。引数に [`tsRxDataApp`](broken://pages/-LCSQBsTPXoLivWdwxrd) `*psRx` が渡されます、受信データ（パケットの中身、アドレス情報など）が格納されます。構造体は本コールバック関数の呼び出しスコープ内で有効で、一旦関数を抜けると値は保証されません。

{% hint style="warning" %}
頻繁に受信される場合は、本関数を終了を遅延すべきではありません。受信キューの解放が遅れ取りこぼしが発生するかもしれません。

受信パケットは、内部のMAC層の割り込みにより、FIFO キューに蓄積されます。アプリケーションループの制御下になったとき、このキューから取り出し、コールバック関数が実行されます。
{% endhint %}

## 引数

| 型                                                        | 名前     | 詳細                           |
| -------------------------------------------------------- | ------ | ---------------------------- |
| [`tsRxDataApp`](broken://pages/-LCSQBsTPXoLivWdwxrd) `*` | `psRx` | 受信されたデータが格納される。詳細は構造体の解説を参照。 |

## 戻り値

なし。

## サンプル

```c
// display packet content 
void cbToCoNet_vRxEvent(tsRxDataApp *pRx) {
	int i;
	static uint16 u16seqPrev = 0xFFFF;
	uint8 *p = pRx->auData; // pointer to the payload

	// print control info
	vfPrintf(&sSerStream, LB"[PKT Ad:%04x,Ln:%03d,Seq:%03d,Lq:%03d,Tms:%05d \"",
			pRx->u32SrcAddr, // source address
			pRx->u8Len, // payload size
			pRx->u8Seq, // seq number
			pRx->u8Lqi, // LQI
			pRx->u32Tick & 0xFFFF); // time stamp
	// print first 32 bytes
	for (i = 0; i < pRx->u8Len; i++) {
		if (i < 32) {
			sSerStream.bPutChar(sSerStream.u8Device,
				(pRx->auData[i] >= 0x20 && pRx->auData[i] <= 0x7f) ? pRx->auData[i] : '.');
		} else {
			vfPrintf(&sSerStream, "..");
			break;
		}
	}
	vfPrintf(&sSerStream, "C\"]");
}
```


# cbToCoNet\_vTxEvent()

## 解説

無線パケットの送信が終了したときに、完了通知として呼び出される。

無線パケットの送信は API により送信要求を行うが、送信完了まで不確定の遅延が発生します。また、TWENET では送信に遅延を設定したり、再送を行ったりする機能があり、場合によっては複数の送信要求と実際の送信完了の順序が前後することもあります。

{% hint style="info" %}
Ack 付き送信の場合は、Ack を受け取ったら成功。
{% endhint %}

{% hint style="info" %}
出来るだけ短い時間に多くのパケットを送りたい場合は、送信完了確認後、速やかに次の送信要求を行います。
{% endhint %}

{% hint style="info" %}
送信要求は送信キューに格納されます。送信キューを超えた要求は無視されます。

遅延を設定した送信を複数要求した場合、同時に処理される要求数はデフォルトで３です。（[モジュール ToCoNet\_USE\_MOD\_TXRXQUEUE\_MID](/twelite-net-api-expl/mojru)）
{% endhint %}

## 引数

| 型       | 名前         | 詳細                                      |
| ------- | ---------- | --------------------------------------- |
| `uint8` | `u8CbId`   | 送信要求との紐付けを目的としてアプリケーションで設定するID。         |
| `uint8` | `u8Status` | `(u8Status & 0x01) == 0` なら失敗。`1` なら成功。 |

### u8Status

| 送信種別         | 成功条件                                                                     |
| ------------ | ------------------------------------------------------------------------ |
| MAC Ack 付き送信 | MAC Ack を受け取れば成功。                                                        |
| MAC Ack 無し送信 | 一度でもパケットが送信されたら成功。                                                       |
| ネットワーク層の送信   | 隣接ノードへの配送が実施されれば成功（複数ホップをすることで最終配送先に伝達されるが、最終配送先へ届いたかどうかは本ステータスでは確認できない） |

{% hint style="warning" %}
MAC Ack は単純な電文応答です。実際は相手に送信できていたが失敗と報告される場合、また、ごく稀に成功と報告されたが相手が受け取っていない場合があります。
{% endhint %}

## 戻り値

なし。

## サンプル

```c
void cbToCoNet_vTxEvent(uint8 u8CbId, uint8 bStatus) {
	if(bStatus & 0x01) {
		// success
	} else {
		// fail
	}
}
```


# cbToCoNet\_vNwkEvent()

## 解説

本イベントは、ネットワーク層などの各モジュールによって生成されます。詳細は、各[モジュール](/twelite-net-api-expl/mojru)で解説されます。

## 引数

| 型         | 名前       | 詳細     |
| --------- | -------- | ------ |
| `teEvent` | `eEvent` | イベント番号 |
| `uint32`  | `u32arg` | イベント引数 |

## 戻り値

なし


# cbToCoNet\_vHwEvent()

## 解説

ハードウェアの割り込みなどのイベントです。[`cbToCoNet_u8HwInt()`](broken://pages/-LB0RiCaC_jCBHEqL0py) 割り込みハンドラが終了した後に呼び出されます。割り込みに対応する通常のアプリケーション処理は、本コールバック関数内に記述します。

## 引数

| 型        | 名前              | 詳細        |
| -------- | --------------- | --------- |
| `uint32` | `u32DeviceId`   | 割り込み源     |
| `uint32` | `u32ItemBitmap` | 割り込みパラメータ |

## 戻り値

なし。

## サンプル

```c
void cbToCoNet_vHwEvent(Uint32 u32DeviceId, uint32 u32ItemBitmap) {
    Switch (u32DeviceId) {
    case E_AHI_DEVICE_SYSCTRL: // DIO etc
        if (u32ItemBitmap & (1UL << 12) {
            ; // interrupt on DIO12
        }
        break;
    case E_AHI_DEVICE_TICK_TIMER: // TickTimer
        vPortSet_TrueAsLo(18, u32TickCount_ms & 0x400); // blink LED every sec.
        break;
    default:
        break;
}
```


# cbToCoNet\_u8HwInt()

## 解説 <a href="#jie" id="jie"></a>

ハードウェアの割り込みの割り込みハンドラです。

{% hint style="info" %}
呼び出し遅延が少ないため、[DIO](/hw-api-ref/perifuraru/dio) ポートの制御により直接外部ハードウェアを制御するといった目的に利用できます。
{% endhint %}

{% hint style="warning" %}
割り込みハンドラの処理は最小限にし、速やかに関数から `return` してください。
{% endhint %}

## 引数 <a href="#yin-shu" id="yin-shu"></a>

| 型        | 名前              | 詳細        |
| -------- | --------------- | --------- |
| `uint32` | `u32DeviceId`   | 割り込み源     |
| `uint32` | `u32ItemBitmap` | 割り込みパラメータ |

## 戻り値 <a href="#ri" id="ri"></a>

| 型       | 解説                                                                                                                    |
| ------- | --------------------------------------------------------------------------------------------------------------------- |
| `uint8` | `FALSE` では [`cbToCoNet_vHwEvent()`](/twelite-net-api-ref/krubakku/cbtoconet_vhwevent) を呼び出しますが、`TRUE` を返すと呼び出しを行いません。 |

{% hint style="info" %}
頻繁なタイマー割り込みなどでアプリケーションループに負担をかけたくない場合は `TRUE` を選択します。
{% endhint %}

## サンプル <a href="#sanpuru" id="sanpuru"></a>

```c
uint8 cbToCoNet_u8HwInt(uint32 u32DeviceId, uint32 u32ItemBitmap) {
    uint8 u8handled = FALSE;
    switch (u32DeviceId) {
    case E_AHI_DEVICE_TIMER0: // increment countr on TIMER0
        u32counter++;
        u8handled = TRUE; // no vHwEvent()
        break;
    default:
        break;
    }
    return u8handled;
}
```


# TWELITE NET関数


# ToCoNet\_vMacStart()

## 解説

MAC 層の初期化処理を行います。

{% hint style="info" %}
スリープ起床したとき、無線の送受信を行わず、マイコン処理のみを行う場合は、本関数を呼び出さずに実行します。
{% endhint %}

起動時に[`cbAppColdStart()`](/twelite-net-api-ref/krubakku/cbappcoldstart) , [`cbAppWarmStart()`](broken://pages/-LAw9HYwdIalArKudw6K) で、`TRUE`を引数とした２回目の呼び出し処理部の末尾に通常は記述します。

{% hint style="warning" %}
cbAppColdStart(), cbAppWarmStart() 以外での呼び出しについては、問題が発生しうる内部設計ではありませんが、動作については未定義とします。必要に応じて、一旦スリープを実行し、スリープ復帰後に無線送信を実施するようにしてください。
{% endhint %}

{% hint style="info" %}
[`sToCoNet_AppContext.u8MacInitPending`](broken://pages/-LB-iFVz_Ov3iZzxfW1U) を設定した場合は、本関数は呼び出しません。
{% endhint %}

## 引数

なし。

## 戻り値

なし。

## サンプル

```c
void cbAppWarmStart(bool_t bStart) {
    if (!bStart) {
        // very initial call
    } else {
        // initializing...
        
        // finally start the MAC layer
        ToCoNet_vMacStart();
    }
}
```


# ToCoNet\_bMacTxReq()

## 解説

単純ネットにおける無線送信要求を行います。送信キューに要求を登録したのち、本関数は終了します。実際の送信処理は後で実行されます。

{% hint style="warning" %}
[中継ネット](/twelite-net-api-expl/nettowkunitsuite/netto-1)を利用している場合でも、[単純ネット](/twelite-net-api-expl/nettowkunitsuite/netto)の送受信は並存可能です。中継ネット稼働時に本関数による送信要求を行なった場合、想定しない振る舞い等が発生することも考えられますので（例えば、中継ネットではバックグラウンドで多数の通信をしている場合があり、その通信に割り込む形で送信要求を投げる）、十分な検証の上使用してください。
{% endhint %}

## 引数

| 型                                                                                  | 名前     | 詳細                                            |
| ---------------------------------------------------------------------------------- | ------ | --------------------------------------------- |
| [`tsTxDataApp`](/twelite-net-api-ref/netto-api/structure/tstoconet_nwk_context)`*` | `psTx` | 送信情報を格納した構造体です。呼び出しスコープ内のローカル変数として確保しても構いません。 |

{% hint style="danger" %}
tsTxDataApp 構造体のメモリ領域は、必ずゼロクリアしてから値を格納します。
{% endhint %}

## 戻り値

| 型        | 詳細                                          |
| -------- | ------------------------------------------- |
| `boot_t` | `TRUE` なら要求は受け付けられ、`FALSE` なら要求は受け付けられなかった。 |

## サンプル

```c
static int16 i16TransmitIoData() {
  tsTxDataApp sTx;
  memset(&sTx, 0, sizeof(sTx)); // 必ずセロクリアする
  uint8 *q = sTx.auData; // S_OCTET() などのマクロ用

  // ペイロードを構成
  S_OCTET(sAppData.u8AppIdentifier);
  S_BE_WORD(sAppData.sIOData_now.u16Volt);
  ...
	
  // 送信
  sTx.u8Len = q - sTx.auData; // パケット長
  sTx.u8Cmd = TOCONET_PACKET_CMD_APP_USER_IO_DATA; // パケット種別

  // 送信する
  sTx.u32DstAddr  = TOCONET_MAC_ADDR_BROADCAST; // ブロードキャスト
  sTx.u8Retry     = 0x81; // 1回再送

  // フレームカウントとコールバック識別子の指定
  sAppData.u16TxFrame++;
  sTx.u8Seq = (sAppData.u16TxFrame & 0xFF);
  sTx.u8CbId = sTx.u8Seq;

  /* MAC モードでは細かい指定が可能 */
  sTx.bAckReq = FALSE;
  sTx.u32SrcAddr = sToCoNet_AppContext.u16ShortAddress;
  sTx.u16RetryDur = 4; // 再送間隔[ms]
  sTx.u16DelayMax = 16; // 送信開始タイミングにブレを作る(最大16ms)

  // 送信API
  if (ToCoNet_bMacTxReq(&sTx)) {
    // 成功（処理が終わると cbToCoNet_vTxEvent() が発生する
    return sTx.u8CbId; // 成功
  } else {
    // 失敗
    return -1; // 失敗
  }
}
```


# ToCoNet\_u32GetSerial()

## 解説

モジュールシリアル番号を得る。このシリアル番号はモジュール個体の値で、通信相手を指定する目的でも使用されます。

{% hint style="info" %}
TWEモジュールに表示されている１６進のシリアル番号に`0x80000000` を加えた値となります。
{% endhint %}

## 引数

なし

## 戻り値

| 型        | 詳細                |
| -------- | ----------------- |
| `uint32` | 32bitのモジュールシリアル値。 |

## サンプル

```c
uint32 u32ser;
u32ser = ToCoNet_u32GetSerial();
```


# ToCoNet\_u32GetRand()

## 解説

32bitの乱数を得ます。乱数の生成方法は [`sToCoNet_AppContext.u8RandMode`](/twelite-net-api-ref/gou-zao-ti/stoconet_appcontext) で指定します。

{% hint style="warning" %}
デフォルトはハードウェアによる16bit乱数に基づき値が生成されます。

[WakeTimer](/hw-api-ref/perifuraru/waketimer) に 32Khz 水晶発振子や発振器を用いた場合、乱数は生成されません。必ずソフトウェア乱数[モジュール](/twelite-net-api-expl/mojru)を利用してください。
{% endhint %}

## 引数

なし。

## 戻り値

| 型        | 詳細       |
| -------- | -------- |
| `uint32` | 32bitの乱数 |

## サンプル

```c
uint32 u32rand;
u32rand = ToCoNet_u32GetRand();
```


# ToCoNet\_vSleep()

## 解説

[WakeTimer](/hw-api-ref/perifuraru/waketimer) によるスリープを行います。

#### 起床割り込みについて

WakeTimer 以外の割り込み源を設定することもできます。本関数呼び出し前にあらかじめ設定しておきます。

#### E\_EVENT\_TOCONET\_ON\_SLEEP イベント

スリープ直前に、各[ユーザ定義イベント処理](/twelite-net-api-ref/yzaibento)関数に `E_EVENT_TOCONET_ON_SLEEP` が伝達されます。

{% hint style="warning" %}
`ToCoNet_vSleep()` が再帰的に呼び出されないように、以下のコード例では `E_EVENT_NEW_STATE` の処理としています。
{% endhint %}

```c
void vMyProcessEv(...) {
    ...
    case E_STATE_SLEEPING:　
        if (eEvent == E_EVENT_NEW_STATE) { 
            ToCoNet_vSleep(…);
        }
        break;
    ...
}
```

#### スリープ時間について

WakeTimer は 32kHz のオシレータの精度により動作する都合、起床精度についてはオシレータの精度が大きく関わります。内蔵のオシレータは必ずキャリブレーションを実施してから利用するようにしてください（特に[`sToCoNet_AppContext`](/twelite-net-api-ref/gou-zao-ti/stoconet_appcontext)での指定がなければコールドスタート時に TWENET ライブラリ内で実行されます）。

{% hint style="warning" %}
極端に短いスリープ間隔は設定できません。概ね30ms程度を下限とします。

起床時間については WakeTimer の精度次第ですが、もっとも良い場合でも±1ms程度の誤差は発生します。
{% endhint %}

## 引数

| 型        | 名前            | 詳細                                                                                                                                                |
| -------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `uint8`  | `u8Device`    | 使用するウェイクアップタイマー。                                                                                                                                  |
| `uint32` | `u32Periodms` | スリープ期間を ms で指定する。                                                                                                                                 |
| `bool_t` | `bPeriodic`   | 周期スリープを行うかどうかを指定します。 周期スリープを指定した場合、前回の起床時間からの経過時間を差し引いて次の起床を行います。すでに次の周期をすぎていた場合は本関数呼び出し時点から指定期間のスリープとし、周期スリープを指定しない場合、本関数呼び出し時点から指定期間のスリープを行います。 |
| `bool_t` | `bRamOff`     | `FALSE` なら RAM を保持した状態でスリープを行います。`TRUE` なら、RAMを保持しないスリープを行います。                                                                                    |

## 戻り値

なし。

## サンプル

```c
// set UART Rx port as interrupt source
vAHI_DioSetDirection(u32DioPortWakeUp, 0); // set as input

// set DIO wakeup source
(void)u32AHI_DioInterruptStatus(); // clear interrupt register
vAHI_DioWakeEnable(u32DioPortWakeUp, 0); // enable ports
vAHI_DioWakeEdge(u32DioPortWakeUp, 0); // set edge (rising)

// 10sec
ToCoNet_vSleep(E_AHI_WAKE_TIMER_0, 10000, FALSE, FALSE); 
```


# ToCoNet\_vDebugInit()

## 解説

TWELITE NET のデバッグメッセージ出力の初期化を行います。

指定した [UART](/hw-api-ref/perifuraru/uart) 出力は、アプリケーションの出力と共用で利用され、アプリケーションの出力の間にデバッグメッセージが出力されます。

{% hint style="warning" %}
[Makefile](/twelite-sdk-howto/birudonitsuite/makefile-nitsuite) にて`TOCONET_DEBUG`を`1`に設定して、ビルドを実行します。
{% endhint %}

{% hint style="danger" %}
デバッグメッセージは TWELITE NET の内部開発向けで、出力書式等については開示しません。問題の解析等を行う際に、お客様に出力をご連絡いただく場合があります。
{% endhint %}

## 引数

| 型                                                                   | 名前     | 詳細                     |
| ------------------------------------------------------------------- | ------ | ---------------------- |
| [`tsFILE`](/hw-api-ref/perifuraru/uart/fprintf-raiburari/tsfile)`*` | `pSer` | UART出力先を定義した構造体へのポインタ。 |

## 戻り値

なし。

## サンプル

```c
#include "serial.h"
#include "fprintf.h"

tsFILE sSerStream; // use for fprintf
tsSerialPortSetup sSerPort;

void initser() {
  //... setup serial port
  sSerPort.u8SerialPort = E_AHI_UART_0;
  //...
  SERIAL_vInitEx(&sSerPort, pUartOpt);
  
  // setup fprintf
  sSerStream.bPutChar = SERIAL_bTxChar; // lib function
  sSerStream.u8Device = E_AHI_UART_0; // UART0
  
  // setup TWELITE NET debug message.
  ToCoNet_vDebugInit(&sSerStream);
  ToCoNet_vDebugLevel(0); // start with no debug message.
}
```


# ToCoNet\_vDebugLevel()

## 解説

TWELITE NET のデバッグ出力レベルを変更する。

レベルは 0 が出力なしで、最大5です。大きくなればなるほど、多くのメッセージが出力されます。

{% hint style="warning" %}
[`ToCoNet_vDebugInit()`](/twelite-net-api-ref/twelite-net-guan-shu/toconet_vdebuginit) により初期化します。

[Makefile](/twelite-sdk-howto/birudonitsuite/makefile-nitsuite) にて`TOCONET_DEBUG`を`1`に設定します。
{% endhint %}

{% hint style="danger" %}
デバッグメッセージは TWELITE NET の内部開発向けで、出力書式等については開示しません。問題の解析等を行う際に、お客様に出力をご連絡いただく場合があります。
{% endhint %}

## 引数

| 型       | 名前      | 詳細                                 |
| ------- | ------- | ---------------------------------- |
| `uint8` | `u8lvl` | 新しいデバッグ出力レベル。(0: 出力なし、1...5: 出力あり) |

## 戻り値

なし。

## サンプル

```c
    // get a serial input byte.
	case 'd': case 'D':
		_C {
			static uint8 u8DgbLvl;

			u8DgbLvl++;
			if(u8DgbLvl > 5) u8DgbLvl = 0;
			ToCoNet_vDebugLevel(u8DgbLvl);

			vfPrintf(&sSerStream, "set NwkCode debug level to %d.", u8DgbLvl);
		}
		break;
```


# ToCoNet\_u32GetVersion()

## 解説

ライブラリのバージョンを取得します。

以下の３関数が利用できます。

```
ToCoNet_u32GetVersion() .. 基本ライブラリ
ToCoNet_u32GetVersion_LibEx() .. EXT
ToCoNet_u32GetVersion_LibUtils() .. UTILS
```

## 引数

なし

## 戻り値

| 型        | 詳細                                                 |
| -------- | -------------------------------------------------- |
| `uint32` | バージョン番号 `0x00XXYYZZ` (XX:メジャー番号 YY:マイナー番号 ZZ:派生番号) |

## サンプル

```c
uint32 u32ver = ToCoNet_u32GetVersion();
```


# ToCoNet\_bRegisterAesKey()

## 解説

通信時に用いる暗号化鍵を設定します。

この処理はシステム起動時の [`E_EVENT_START_UP` イベント](/twelite-net-api-ref/yzaibento/ibento)に記述します。稼働途中での変更はできません。

{% hint style="warning" %}
鍵自体を暗号化する事は出来ません。EEPROM への保管・ファームウェア読み出しにより解析されてしまうことを防ぎたい場合は、鍵の秘匿化のためのアルゴリズムを含めるようにしてください。

暗号化については AES128 を利用していますが、詳細は非公開です。

復号化のための確認として 16bit のチェックサムをパケットのデータ中に追加します。このため格納できるデータ量は２バイト少なくなりますが、パケットの識別性は高くなります。
{% endhint %}

## 引数

| 型               | 名前           | 詳細               |
| --------------- | ------------ | ---------------- |
| `uint8 *`       | `pu8Key`     | １６バイトの鍵データへのポインタ |
| `tsCryptDefs *` | `sCryptDefs` | 予約(`NULL`を指定します) |

## 戻り値

| 型        | 詳細                                   |
| -------- | ------------------------------------ |
| `bool_t` | `TRUE`: 鍵が登録できた。 `FALSE`: 鍵の登録に失敗した。 |

## サンプル

```c
const char *pu8enckey = "abcd1234VWXY7890";
ToCoNet_bRegisterAesKey(pu8enckey, NULL);
```


# ToCoNet\_vRfConfig()

## 解説

MAC 層のパラメータ変更を行います。[`sToCoNet_AppContext`](broken://pages/-LB-iFVz_Ov3iZzxfW1U)構造体の以下に挙げるメンバーが変更可能です。

| `u8Channel`       | \*1 | チャネルを切り替える。切り替えに失敗した場合は、構造体の `u8Channel` は、設定前の値に戻ります。 |
| ----------------- | --- | ------------------------------------------------------ |
| `u32ChMask`       | \*1 |                                                        |
| `u16ShortAddress` | \*1 | 自局のショートアドレスを変更する。                                      |
| `u8CPUClk`        |     | CPUクロックの切り替えには数十usec程度かかります。                           |
| `u8TxPower`       | \*1 |                                                        |
| `bRxOnIdle`       |     | `FALSE`にすると、無線パケットを受信しなくなります。                          |

{% hint style="warning" %}
\*1 これらの設定項目の変更を行う場合、無線の送受信中の結果は不定です。

新たに送信するパケットに対して変更を有効にするには、送信キューがすべて処理されてから変更してください。

パケットの直前から受信完了までのタイミングでの変更に関しても、原理的にそのパケットが受信されないことも発生しえます。多くのアプリケーションでは、受信側はいつパケットを受けるか判らないため、切り替えタイミングを調整しない実装を行います。
{% endhint %}

## 引数

なし

## 戻り値

なし

## サンプル

```c
sToCoNet_AppContext.u8Channel = 25;
sToCoNet_u8TxPower = 2;
ToCoNet_vRfConfig();
```


# ToCoNet\_vChConfig()

## 解説

チャネルを変更します。

{% hint style="info" %}
`ToCoNet_vRfConfig()` はチャネル以外の設定も適用しますが、本関数はチャネルのみの変更となります。
{% endhint %}

{% hint style="warning" %}
送信中や受信中などチャネル変更できないタイミングでは、変更が行われません。変更が行われない場合は [`sToCoNet_AppContext.u8Channel`](/twelite-net-api-ref/gou-zao-ti/stoconet_appcontext) の値が変更前のチャネルに戻されます。
{% endhint %}

{% hint style="warning" %}
[モジュール](/twelite-net-api-expl/mojru) `ToCoNet_USE_MOD_CHANNEL_MGR` を利用する場合は、本関数によるチャネル変更は行われません。
{% endhint %}

## 引数

なし

## 戻り値

なし

## サンプル

```c
sToCoNet_AppContext.u8Channel = 25;
ToCoNet_vChConfig();
if (sToCoNet_AppContext.u8Channel != 25) {
  // Oops! Channel is not changed to 25.
}
```


# ToCoNet\_Tx\_vProcessEventQueue()

## 解説

無線パケット送信要求を速やかに処理する。

本関数は [`ToCoNet_bMacTxReq()`](broken://pages/-LB537jQf-VLPtcp1s1b) 要求直後に呼び出すことで、送信要求を速やかに処理します。この要求を行わない場合は、システムタイマー (デフォルト 4ms) のタイミングで無線送信が処理されます。

{% hint style="warning" %}
速やかに無線送信されるのは、その時点で処理されている送信要求が存在せず、かつ、該当する送信要求に送信遅延が設定されていない場合です。例えば、送信完了を待って、連続的に送信をするような場合に有効です。
{% endhint %}

## 引数

なし

## 戻り値

なし

## サンプル

```c
/* 送信完了を待って次のパケット要求を行う */
void cbToCoNet_vTxEvent(uint8 u8CbId, uint8 bStatus) {
	if (sAppData.bOnTx) { // 送信中のフラグ
		vTransmit();
	}
	return;
}

static void vTransmit() {
	_C {
		// transmit Ack back
		tsTxDataApp tsTx;
		memset(&tsTx, 0, sizeof(tsTxDataApp));

		tsTx.u32SrcAddr = ToCoNet_u32GetSerial(); // 自身のアドレス
		tsTx.u32DstAddr = 0xFFFF; // ブロードキャスト

		tsTx.bAckReq = FALSE;

		tsTx.u8Retry = 0; // 再送なし
		tsTx.u16DelayMin = 0;
		tsTx.u16DelayMax = 0;
		tsTx.u16RetryDur = 0; // 遅延は0で速やかに送信

		// ペイロード生成など
		...
		
		// 送信
		if (ToCoNet_bMacTxReq(&tsTx)) {
			// 送信要求が受け付けられたら速やかに処理する。
			ToCoNet_Tx_vProcessQueue(); 
		}
	}
}
```


# ToCoNet\_u16RcCalib()

## 解説 <a href="#jie" id="jie"></a>

​ RCタイマーをキャリブレーションします。

* キャリブレーションの実行
* キャリブレーション値の取得
* キャリブレーション値の設定

{% hint style="info" %}
キャリブレーション値の取得には `ToCoNet_u16GetRcCalib()` も利用できます。
{% endhint %}

### 32768Hz 外部オシレータの利用

キャリブレーションは不要で 固定値 `9766` (32000/32768) カウントを指定します。[`cbAppColdStart()`](/twelite-net-api-ref/krubakku/cbappcoldstart) にて以下の例のように指定します。

```c
// TWENET ライブラリ 1.2.0 以降のみで有効
void cbAppColdStart(bool_t bAfterAhiInit)
{
	if (!bAfterAhiInit) {
		ToCoNet_REG_MOD_ALL();
	} else {
		ToCoNet_Event_Register_State_Machine(vProcessEvCore);
		...
		// システム起動時のキャリブレーションの省略
		sToCoNet_AppContext.bSkipBootCalib = TRUE;
		// 固定値の設定(v1.2以降)
		ToCoNet_u16RcCalib(9766);
	}
}

void vProcessEvCore(
        tsEvent *pEv,
        teEvent eEvent,
        uint32 u32evarg) {
        
     if (eEvent == E_EVENT_START_UP) { //システム始動時
     	// 固定値の設定
 		ToCoNet_u16RcCalib(9766);
     }
 }

```

## 引数 <a href="#yin-shu" id="yin-shu"></a>

| 型         | 名前        | 値            | 内容                                             |
| --------- | --------- | ------------ | ---------------------------------------------- |
| ​`uint16` | `​u16val` | `0`          | キャリブレーションを実施する。キャリブレーションには1ms未満ですが、若干の時間を要します。 |
|           |           | `5000-15000` | キャリブレーション値を設定します。                              |
|           |           | `0xFFFF`     | 設定値を取得します。                                     |

## 戻り値 <a href="#ri" id="ri"></a>

| 型         | 詳細                                           |
| --------- | -------------------------------------------- |
| `​uint16` | `u16val == 0xFFFF` のときに、現在の設定値を返す。それ以外は未定義。​ |

## サンプル <a href="#sanpuru" id="sanpuru"></a>

```c
vfPrintf(&sSerStream, "RC Calib = %d"LB,  ToCoNet_u16GetRcCalib());
```


# 中継ネット API


# functions


# ToCoNet\_Nwk\_bInit()

## 解説

中継ネットの初期化を行う。

事前に中継ネットの構成手続き(LayerTree を構成する場合は [`ToCoNet_NwkLyTr_psConfig()`](/twelite-net-api-ref/netto-api/layertree-netto/toconet_nwklytr_psconfig)) [`tsToCoNet_Nwk_Context`](/twelite-net-api-ref/netto-api/structure/tstoconet_nwk_context) 構造体へのポインタを得ておく。

## 引数

| 型                                                                                            | 名前          | 詳細                  |
| -------------------------------------------------------------------------------------------- | ----------- | ------------------- |
| [`tsToCoNet_Nwk_Context`](/twelite-net-api-ref/netto-api/structure/tstoconet_nwk_context)`*` | pContextNwk | 中継ネットの内部情報を管理する構造体。 |

## 戻り値

| 型       | 詳細                     |
| ------- | ---------------------- |
| bool\_t | `TRUE`: 成功、`FALSE`: 失敗 |

## サンプル

```c
static tsToCoNet_NwkLyTr_Config sNwkLayerTreeConfig;
static tsToCoNet_Nwk_Context* pContextNwk;
...
			pContextNwk =
				ToCoNet_NwkLyTr_psConfig(&sNwkLayerTreeConfig);
			if (pContextNwk) {
				ToCoNet_Nwk_bInit(pContextNwk);
				ToCoNet_Nwk_bStart(pContextNwk);
			}
```


# ToCoNet\_Nwk\_bStart()

## 解説

中継ネットを開始する。

{% hint style="info" %}
ネットワーク開始後に、`E_EVENT_TOCONET_NWK_START` イベントを受け取ります。
{% endhint %}

## 引数

| 型                                                                                            | 名前          | 詳細                  |
| -------------------------------------------------------------------------------------------- | ----------- | ------------------- |
| [`tsToCoNet_Nwk_Context`](/twelite-net-api-ref/netto-api/structure/tstoconet_nwk_context)`*` | pContextNwk | 中継ネットの内部情報を管理する構造体。 |

## 戻り値

| 型       | 詳細                     |
| ------- | ---------------------- |
| bool\_t | `TRUE`: 成功、`FALSE`: 失敗 |

## サンプル

```c
static tsToCoNet_NwkLyTr_Config sNwkLayerTreeConfig;
static tsToCoNet_Nwk_Context* pContextNwk;
...
			pContextNwk =
				ToCoNet_NwkLyTr_psConfig(&sNwkLayerTreeConfig);
			if (pContextNwk) {
				ToCoNet_Nwk_bInit(pContextNwk);
				ToCoNet_Nwk_bStart(pContextNwk);
			}
```


# ToCoNet\_Nwk\_bPause()

## 解説

中継ネットを中断する。

{% hint style="info" %}
スリープを実行するまえに呼び出します。
{% endhint %}

## 引数

| 型                                                                                            | 名前          | 詳細                  |
| -------------------------------------------------------------------------------------------- | ----------- | ------------------- |
| [`tsToCoNet_Nwk_Context`](/twelite-net-api-ref/netto-api/structure/tstoconet_nwk_context)`*` | pContextNwk | 中継ネットの内部情報を管理する構造体。 |

## 戻り値

| 型       | 詳細                     |
| ------- | ---------------------- |
| bool\_t | `TRUE`: 成功、`FALSE`: 失敗 |

## サンプル

```c
static tsToCoNet_NwkLyTr_Config sNwkLayerTreeConfig;
static tsToCoNet_Nwk_Context* pContextNwk;
...
	case E_STATE_IDLE:
		if (eEvent == E_EVENT_START_UP) {
			if (u32evarg & EVARG_START_UP_WAKEUP_RAMHOLD_MASK) {
				// RESUME
				ToCoNet_Nwk_bResume(pContextNwk);
			} else {
				// 始動時の処理
				memset(&sNwkLayerTreeConfig, 0, sizeof(sNwkLayerTreeConfig));
				sNwkLayerTreeConfig.u8Role = 
						TOCONET_NWK_ROLE_ENDDEVICE;
				// ネットワークの初期化
				pContextNwk = 
					ToCoNet_NwkLyTr_psConfig_MiniNodes(&sNwkLayerTreeConfig);
	
				if (sAppData.pContextNwk) {
					ToCoNet_Nwk_bInit(pContextNwk);
					ToCoNet_Nwk_bStart(pContextNwk);
				}
			}
...
	case E_STATE_APP_SLEEP:
		if (eEvent == E_EVENT_NEW_STATE) {
			// 中継ネットのポーズ処理を行う
			ToCoNet_Nwk_bPause(sAppData.pContextNwk);
​
			// 周期スリープに入る
			//  - 初回は５秒あけて、次回以降はスリープ復帰を基点に５秒
			vSleep(5000, TRUE, FALSE);
		}
```


# ToCoNet\_Nwk\_bResume()

## 解説

中継ネットを再開する。

{% hint style="info" %}
スリープ前に`ToCoNet_Nwk_bPause()` を呼び出しておき、起床後に本関数を呼び出すことで、中継ネットの動作を再開できます。
{% endhint %}

## 引数

| 型                                                                                            | 名前          | 詳細                  |
| -------------------------------------------------------------------------------------------- | ----------- | ------------------- |
| [`tsToCoNet_Nwk_Context`](/twelite-net-api-ref/netto-api/structure/tstoconet_nwk_context)`*` | pContextNwk | 中継ネットの内部情報を管理する構造体。 |

## 戻り値

| 型       | 詳細                     |
| ------- | ---------------------- |
| bool\_t | `TRUE`: 成功、`FALSE`: 失敗 |

## サンプル

```c
static tsToCoNet_NwkLyTr_Config sNwkLayerTreeConfig;
static tsToCoNet_Nwk_Context* pContextNwk;
...
	case E_STATE_IDLE:
		if (eEvent == E_EVENT_START_UP) {
			if (u32evarg & EVARG_START_UP_WAKEUP_RAMHOLD_MASK) {
				// RESUME
				ToCoNet_Nwk_bResume(pContextNwk);
			} else {
				// 始動時の処理
				memset(&sNwkLayerTreeConfig, 0, sizeof(sNwkLayerTreeConfig));
				sNwkLayerTreeConfig.u8Role = 
						TOCONET_NWK_ROLE_ENDDEVICE;
				// ネットワークの初期化
				pContextNwk = 
					ToCoNet_NwkLyTr_psConfig_MiniNodes(&sNwkLayerTreeConfig);
	
				if (sAppData.pContextNwk) {
					ToCoNet_Nwk_bInit(pContextNwk);
					ToCoNet_Nwk_bStart(pContextNwk);
				}
			}
...
	case E_STATE_APP_SLEEP:
		if (eEvent == E_EVENT_NEW_STATE) {
			// 中継ネットのポーズ処理を行う
			ToCoNet_Nwk_bPause(sAppData.pContextNwk);
​
			// 周期スリープに入る
			//  - 初回は５秒あけて、次回以降はスリープ復帰を基点に５秒
			vSleep(5000, TRUE, FALSE);
		}
```


# ToCoNet\_Nwk\_bTx()

## 解説

中継ネットでの無線パケットの送信要求を行う。

{% hint style="warning" %}
配送に関する詳細は [`tsTxDataApp`](/twelite-net-api-ref/netto-api/structure/tstxdataapp-netto) 構造体の解説を参照してください。
{% endhint %}

### 宛先について

配送先は２種類選択できます。

{% hint style="info" %}
`TOCONET_NWK_ADDR_NEIGHBOUR_ABOVE` を指定することで、近隣の親機、中継器に直接伝達されますが、この時の子機と親機、中継器間の LQI を集計することで、どの親機、中継器が子機に近い位置にいるかどうかを判定できます。

*LQIと距離の精度は高くなく、１m以内といったごく近い位置にいるか、それ以外かを弁別できる程度です。*
{% endhint %}

| 宛先アドレス                             | 解説                                                                  |
| ---------------------------------- | ------------------------------------------------------------------- |
| `TOCONET_NWK_ADDR_NEIGHBOUR_ABOVE` | 電波到達可能な親機または中継器（複数あればその全て）に直接伝達する。                                  |
| `TOCONET_NWK_ADDR_PARENT`          | 親機宛に配送する。（中継器がパケットを受信しても `ToCoNet_vRxEvent()` によりパケットの受信を知ることは出来ない) |

## 引数

| 型                                                                                            | 名前          | 詳細                  |
| -------------------------------------------------------------------------------------------- | ----------- | ------------------- |
| [`tsToCoNet_Nwk_Context`](/twelite-net-api-ref/netto-api/structure/tstoconet_nwk_context)`*` | pContextNwk | 中継ネットの内部情報を管理する構造体。 |
| [`tsTxDataApp`](/twelite-net-api-ref/netto-api/structure/tstxdataapp-netto)`*`               | sTx         | 送信データを格納した構造体。      |

## 戻り値

| 型       | 詳細                                        |
| ------- | ----------------------------------------- |
| bool\_t | `TRUE`: 要求が受け付けられた、`FALSE`: 要求が受け付けられなかった |

## サンプル

```c
static tsToCoNet_NwkLyTr_Config sNwkLayerTreeConfig;
static tsToCoNet_Nwk_Context* pContextNwk;
...
	} else {
		// 
		tsTxDataApp sTx;
		memset(&sTx, 0, sizeof(sTx)); // 必ず０クリアしてから使う！
		uint8 *q =  sTx.auData;
	
		sTx.u32SrcAddr = ToCoNet_u32GetSerial();
	
		if (IS_APPCONF_OPT_TO_ROUTER()) {
			// ルータがアプリ中で一度受信して、ルータから親機に再配送
			sTx.u32DstAddr = TOCONET_NWK_ADDR_NEIGHBOUR_ABOVE;
		} else {
			// ルータがアプリ中では受信せず、単純に中継する
			sTx.u32DstAddr = TOCONET_NWK_ADDR_PARENT;
		}
	
		// ペイロードの準備
		S_OCTET('T');
		S_OCTET(sAppData.sFlash.sData.u8id);
		S_BE_WORD(sAppData.u16frame_count);		
​
		//	センサ固有のデータ
		memcpy(q,pu8Data,u8Len);
		q += u8Len;
	
		sTx.u8Cmd = 0; // 0..7 の値を取る。パケットの種別を分けたい時に使用する
		sTx.u8Len = q - sTx.auData; // パケットのサイズ
		sTx.u8CbId = sAppData.u16frame_count & 0xFF; // TxEvent で通知される番号、送信先には通知されない
		sTx.u8Seq = sAppData.u16frame_count & 0xFF; // シーケンス番号(送信先に通知される)
		sTx.u8Retry = sAppData.u8Retry;
​
		if (ToCoNet_Nwk_bTx(pNwk, &sTx)) {
			ToCoNet_Event_SetState(pEv, E_STATE_APP_WAIT_TX);
		} else {
			// ...失敗した（スリープ処理)
			ToCoNet_Event_SetState(pEv, E_STATE_SLEEP);
		}
```


# Structure


# tsTxDataApp (中継ネット)

[中継ネット](/twelite-net-api-expl/nettowkunitsuite/netto-1)で使用する送信用の構造体。

{% hint style="warning" %}
構造体は必ず 0 で初期化してから使用します。ローカル変数での定義でも構いません。

この構造体は単純ネットと共用して使用されます。単純ネットまたは中継ネットどちらかでしか使わないメンバーも存在します。未使用のメンバーは 0 で初期化されている前提を置きます。
{% endhint %}

| 定義名                                            | 解説                                                                                                                                                                                                                                         |
| ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `uint32 u32DstAddr`                            | 宛先アドレス。以下の定義済みアドレスは特殊な意味合いを持つ。 子機からは親機に送信する際は`TOCONET_NWK_ADDR_PARENT` を指定するが、電波到達範囲内の中継器に直接送信する`TOCONET_NWK_ADDR_NEIGHBOUR_ABOVE` を指定する。親機からは対象の子機のロングアドレスまたは全ノードに伝達する `TOCONET_NWK_ADDR_BROADCAST` を指定する。                                |
| `uint8 u8Cmd`                                  | パケット種別。アプリケーションで自由に設定できる。値域は 0..7。                                                                                                                                                                                                         |
| `uint8 u8CbId`                                 | コールバックID。送信要求時に設定した値が [`cbToCoNet_TxEvent()`](/twelite-net-api-ref/krubakku/cbtoconet_vtxevent) により渡されます。この値によって送信したパケットと送信完了イベントを対応付けます。本値は送信パケットには含まれません。値域：0-255                                                                        |
| `uint8 au8Data[]`                              | パケットのペイロード([パケットの最大長](/twelite-net-api-expl/paketto/pakettono))。                                                                                                                                                                           |
| `uint8 u8Retry`                                | LAYERTREE\_MININODES で使用します。再送回数は `0x80` (再送ない) `0x81`(再送1回) ... `0x8F`(再送16回) と指定します。                                                                                                                                                     |
| `uint16 u16DelayMin, u16DelayMax, u16RetryDur` | LayerTree ネットワーク層では使用されない。ただし LAYERTREE\_MININODES で使用します。パケットの送信遅延を設定します。内容は [tsTxDataApp](/twelite-net-api-ref/gou-zao-ti/tstxdataapp) を参照。                                                                                              |
| `uint16 bSecurePkt`                            | 平文で送信する場合は `FALSE`, 暗号化する場合は `TRUE` を指定します。事前に [`ToCoNet_bRegisterAesKey()`](/twelite-net-api-ref/twelite-net-guan-shu/toconet_bregisteraeskey) により暗号化鍵を登録しておきます。※最大利用バイト数が２バイト減少します([パケットの最大長](/twelite-net-api-expl/paketto/pakettono))。 |


# tsRxDataApp (中継ネット)

[中継ネット](/twelite-net-api-expl/nettowkunitsuite/netto-1)でパケットを受信した時に cbToCoNet\_vRxEvent() に渡される構造体。

{% hint style="warning" %}
[単純ネット](/twelite-net-api-expl/nettowkunitsuite/netto)と共通の構造体です。中継ネット、単純ネットどちらかでしか使用されないメンバーもあります。
{% endhint %}

| 定義名                                                                     | 解説                                                                                                                                                                                                                  |
| ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `uint8 u8Cmd`                                                           | パケット種別。送信元で任意に指定できます。データ用、コマンド用といった区分けに使います。値域：0-7                                                                                                                                                                  |
| `uint8 u8Len`                                                           | ペイロード長。後述の `au8Data[]` に格納されるデータ長。                                                                                                                                                                                  |
| `uint8 u8Seq`                                                           | シーケンス番号。送信元で任意に設定できます。重複パケットの判定などに使用します。値域: 0-255                                                                                                                                                                   |
| <p><code>uint32 u32SrcAddr</code><br><code>uint32 u32DstAddr</code></p> | 送信元、送信先アドレス。拡張アドレスが格納されます。                                                                                                                                                                                          |
| `uint8 auData[]`                                                        | ペイロード。送信元で任意に設定できます。                                                                                                                                                                                                |
| `uint8 u8Lqi`                                                           | 受信品質 LQI 値。中継されてきた場合は、最後の中継機のパケットの受信強度になります。値域：0..255 （受信時の電界強度に対応し 0 が最弱、255 が最強）                                                                                                                                  |
| `uint8 u8Tick`                                                          | 受信時のミリ秒カウンタ                                                                                                                                                                                                         |
| `uint8 u8Hops`                                                          | 中継ホップ数（直接受信した場合は 0）                                                                                                                                                                                                 |
| `uint8 u8RouteXOR`                                                      | <p>中継経路の中継機のアドレスの XOR 値で中継経路の推定に使用します。<br>直接受信した場合は 0 となり、<code>0x81234567</code> と <code>0x82345678</code> の中継機を経由した場合、<code>0x81 0x23 0x45 0x67 0x82 0x34 0x56 0x78</code> の XOR 値 <code>0x18</code> が格納されます。</p> |
| `uint8 u8Lqi1st`                                                        | 最初の中継機が受信したときの LQI 値が格納されます。                                                                                                                                                                                        |
| `uint8 bSecurePkt`                                                      | パケットが暗号化されていた場合 `TRUE` になります。この時点で既に `auData[]` は平文に復号されています。このメンバーが `FALSE` で受信されたパケットの処理をしなければ、平文パケットを無視し、より安全な暗号化パケットのみを処理することになります。                                                                             |

## Can I become who I want to be?

That's a tough question but thankfully, our team is on it. Please bear with us while we're investigating.

## Have you had a chance to answer the previous question?

Yes, after a few months we finally found the answer. Sadly, Mike is on vacations right now so I'm afraid we are not able to provide the answer at this point.


# tsToCoNet\_Nwk\_Context

中継ネットの基本的なパラメータを定義します。

{% hint style="info" %}
将来の拡張性のためごく基本的な内容を tsToCoNet\_Nwk\_Context 構造体にまとめ、この構造体を拡張する形で、例えば[`tsToCoNet_NwkLrTr_Context`](/twelite-net-api-ref/netto-api/layertree-netto/tstoconet_nwklytr_context)構造体を定義します。中継ネットAPIでは、常に `tsToCoNet_Nwk_Context *` にキャストして利用します。
{% endhint %}

| 定義名                                       | 解説                                                                                                                                                                                                                                                 |
| ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `tsToCoNet_Nwk_\ Context_Base_Info sInfo` | ネットワーク情報の共通構造体。本構造体は主にデバッグ表示目的として参照できる。                                                                                                                                                                                                            |
| `sInfo.u8Role`                            | ネットワークの役割(親機`TOCONET_NWK_ROLE_PARENT`・中継機`TOCONET_NWK_ROLE_ROUTER`・子機`TOCONET_NWK_ROLE_ENDDEVICE`)。                                                                                                                                                |
| `sInfo.u8State`                           | <p>接続状態を示す。<br><code>TOCONET\_NWK\_STATUS\_INACTIVE</code> (<code>0x00</code>) : ネットワークが開始されていない<br><code>TOCONET\_NWK\_STATUS\_START\_MASK</code> : ネットワークが開始ビット（未接続の場合も）<code>TOCONET\_NWK\_STATUS\_READY\_MASK</code> : ネットワークが接続可能を意味するビット</p> |
| `sInfo.u8Layer`                           | 中継機の場合、設定したレイヤ数（接続先のレイヤではなく自身のレイヤ）子機の場合、接続先のレイヤ数                                                                                                                                                                                                   |
| `sInfo.u8NwkTypeId`                       | どの種類のネットワークかを格納する。`TOCONET_NWK_TYPE_LAYER_TREE`はLayerTree ネットワークとなり、本構造体は`tsToCoNet_NwkLyTr_Context *` にダウンキャストできます。                                                                                                                               |


# LayerTree ネット


# ToCoNet\_NwkLyTr\_psConfig()

## 解説

中継ネットとしてLayerTreeネットワークを選択し、親機または中継器を構成する。

## 引数

| 型                                                                                                        | 名前          | 詳細               |
| -------------------------------------------------------------------------------------------------------- | ----------- | ---------------- |
| [`tsToCoNet_NwkLyTr_Context*`](/twelite-net-api-ref/netto-api/layertree-netto/tstoconet_nwklytr_context) | pContextNwk | 中継ネットの設定情報格納構造体。 |

## 戻り値

| 型                                                                                          | 詳細                |
| ------------------------------------------------------------------------------------------ | ----------------- |
| [`tsToCoNet_Nwk_Context*`](/twelite-net-api-ref/netto-api/structure/tstoconet_nwk_context) | 設定済みの内部構造体へのポインタ。 |

## サンプル

```c
static tsToCoNet_NwkLyTr_Config sNwkLayerTreeConfig;
static tsToCoNet_Nwk_Context* pContextNwk;
...
		// layer 数の決定
		sNwkLayerTreeConfig.u8Layer = 4;
​
		// NBビーコン方式のネットワークを使用する
		sNwkLayerTreeConfig.u8StartOpt =
			TOCONET_MOD_LAYERTREE_STARTOPT_NB_BEACON;

		// Router として始動
		sNwkLayerTreeConfig.u8Role = TOCONET_NWK_ROLE_ROUTER;
		pContextNwk = ToCoNet_NwkLyTr_psConfig(&sNwkLayerTreeConfig);
		if (pContextNwk) {
			ToCoNet_Nwk_bInit(pContextNwk);
			ToCoNet_Nwk_bStart(pContextNwk);
		} else {
			// fatal error
		}

```


# ToCoNet\_NwkLyTr\_psConfig\_MiniNodes()

## 解説

[中継ネット](/twelite-net-api-expl/nettowkunitsuite/netto-1)としてLayerTreeネットワークを選択し、送信専用として振る舞う LAYERTREE\_MONINODES を構成する。

## 引数

| 型                                                                                                        | 名前          | 詳細               |
| -------------------------------------------------------------------------------------------------------- | ----------- | ---------------- |
| [`tsToCoNet_NwkLyTr_Context*`](/twelite-net-api-ref/netto-api/layertree-netto/tstoconet_nwklytr_context) | pContextNwk | 中継ネットの設定情報格納構造体。 |

## 戻り値

| 型                                                                                          | 詳細                |
| ------------------------------------------------------------------------------------------ | ----------------- |
| [`tsToCoNet_Nwk_Context*`](/twelite-net-api-ref/netto-api/structure/tstoconet_nwk_context) | 設定済みの内部構造体へのポインタ。 |

## サンプル

```c
static tsToCoNet_NwkLyTr_Config sNwkLayerTreeConfig;
static tsToCoNet_Nwk_Context* pContextNwk;
...
		// 始動時の処理
		memset(&sNwkLayerTreeConfig, 0, sizeof(sNwkLayerTreeConfig));
		sNwkLayerTreeConfig.u8Role = 
				TOCONET_NWK_ROLE_ENDDEVICE;
		// ネットワークの初期化
		pContextNwk = 
			ToCoNet_NwkLyTr_psConfig_MiniNodes(&sNwkLayerTreeConfig);

		if (sAppData.pContextNwk) {
			ToCoNet_Nwk_bInit(pContextNwk);
			ToCoNet_Nwk_bStart(pContextNwk);
		}
```


# tsToCoNet\_NwkLyTr\_Context

[`ToCoNet_NwkLyTr_psConfig()`](/twelite-net-api-ref/netto-api/layertree-netto/toconet_nwklytr_psconfig) のパラメータとして LayterTree ネットワークを設定します。本構造体はローカル変数で確保しても構いません。

| 定義名                                       | 解説                                                                                                                                           |
| ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `tsToCoNet_Nwk_Context_\ Base_Info sInfo` | ネットワーク情報の共通構造体。                                                                                                                              |
| `tsToCoNet_NwkLyTr_Config sConf`          | 設定情報です。[`ToCoNet_NwkLyTr_psConfig()`](/twelite-net-api-ref/netto-api/layertree-netto/toconet_nwklytr_psconfig) による設定が行われたときに、規定値の展開などが行われます。 |
| `uint32 u32AddrHigherLayer`               | 接続先の上位ノードのアドレス                                                                                                                               |
| `uint8 u8Ct_Second_To_Rescan`             | 上位を再探索するまでのカウント \[秒]                                                                                                                         |
| `uint8 u8Ct_Second_To_Relocate`           | 上位の存在確認を行うまでのカウント \[秒]                                                                                                                       |
| `uint8 u8Ct_LostParent`                   | 上位の存在確認の失敗数カウント （この値が規定回数まで達すると上位喪失として、再探索が行われる）                                                                                             |


# 型 typedef, よく使うマクロ

ソース中で利用される主な typedef型は jendefs.h 定義されている。

| typedef | 型              | 解説          |
| ------- | -------------- | ----------- |
| bool\_t | unsigned char  | ブール型として利用する |
| string  | char \*        |             |
| uint8   | unsigned char  |             |
| int8    | char           |             |
| uint16  | unsigned short |             |
| int16   | short          |             |
| uint32  | unsigned long  |             |
| int32   | long           |             |

以下に、コード中でよく利用されるマクロ定義を列挙します。

| 定義名     |        |                  |
| ------- | ------ | ---------------- |
| FALSE   | 0      |                  |
| TRUE    | 1      |                  |
| PUBLIC  |        | 公開関数であることを明示する。  |
| PRIVATE | static | 非公開関数であることを明示する。 |


# 構造体


# sToCoNet\_AppContext

TWELITE NET の動作を決める構造体で `sToCoNet_AppConetext` として静的に確保されています。始動時に呼び出されるコールバック関数 [`cbAppColdStart()`](/twelite-net-api-ref/krubakku/cbappcoldstart)にて設定したり、始動後 `sToCoNetAppContext` を直接書き換え [`ToCoNet_vRfConfig()`](/twelite-net-api-ref/twelite-net-guan-shu/toconet_vrfconfig) を呼び出すことで設定変更します。

| 定義名解説                                                 | 解説                                                                                                                                                                     |
| ----------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| <p><code>uint32 u32AppId</code><br>(必須、始動後変更不可)</p>   | 32bitのアプリケーションID。本IDでTWELITE NET同士の識別を行います。値域： `????0000`, `????FFFF`, `0000????`, `FFFF????` は設定できません。規定値： `0xFFFFFFFF`。必ずアプリケーションから設定します。                            |
| <p><code>uint32 u32ChMask</code><br>(モジュールによって必須)</p> | 利用するチャネル群。ch13 をマスクに加える場合は 1UL << 13 のビットを１にします。規定値: 0x07fff800UL (ch11～26)必須モジュール: CHANNEL\_MGR, NBSCAN, NBSCAN\_SLAVE, LAYERTREE                                     |
| `uint16 u16ShortAddress`                              | モジュールのショートアドレス。指定しなければモジュールのシリアル番号から自動生成されます。0xFFFFは指定出来ません。ネットワーク層利用時は指定できません。 規定値: モジュールシリアル番号から自動設定                                                                 |
| `uint8 u8Channel` (必須)                                | モジュールの利用チャネル。上記 `u32ChMask` に含まれるチャネルを指定します。※ [モジュール](/twelite-net-api-expl/mojru)ToCoNet\_USE\_MOD\_CHANNEL\_MGR 利用時は設定不要ですが、アプリケーションからのチャネル変更は出来ません。値域: 11～26規定値: 18 |
| `uint8 u8CPUClk` (変更推奨せず)                             | 通常稼働時のCPUクロック。3:32MHz, 2:16Mhz, 1:8Mhz, 0:4Mhz を指定します。規定値: 2:16MHz                                                                                                     |
| `unit8 u8TxPower`                                     | モジュールの出力 3:最大 2: -11.5db 1: -23db 0:-34.5db となります。(規定値: 3 )                                                                                                            |
| `uint8 u8TxMacRetry`                                  | MAC層の再送回数 0..7 を指定します。(規定値: 3)                                                                                                                                         |
| `bool_t bRxOnIdle`                                    | TRUE:無線回路アイドル時も受信回路を動作させます。受信が必要な場合は必ずTRUEに設定にしますが、受信時は常に受信電流を消費します。規定値: FALSE (ネットワーク層では TRUE 必須)                                                                     |
| `uint8 u8CCA_Retry`                                   | CCA のリトライ回数 (通常は変更しません)                                                                                                                                                |
| `uint8 u8CCA_Level`                                   | CCA アルゴリズムの開始レベル (通常は変更しません)                                                                                                                                           |
| `uint8 u8Osc32Kmode`                                  | 32K 水晶のモード (0x00: 内蔵RC, 0x02: 32K水晶振動子, 0x03: 32K発振器)。外部オシレータを利用する際は、始動時にクロック安定化をするための時間が必要となります。                                                                      |
| `uint8 u8RandMode`                                    | 乱数生成方法の指定。0:内部ハードを利用(32K外部オシレータが利用されたときは XorShift を採用します) 3:XorShift法によるアルゴリズム(乱数の種は始動時に内部ハードより生成します)                                                                  |
| `uint16 u16TickHz` (変更推奨せず)                           | システムの Tick カウントの周期(1000で割り切れる値にすること。1000, 500, 250, 200, 100)規定値: 250 (4ms)                                                                                            |
| `bool_t bSkipBootCalib`                               | 起床時の RC タイマーのキャリブレーション値の計算を省略する。明示的にキャリブレーションを設定するには [`ToCoNet_u16RcCalib()`](/twelite-net-api-ref/twelite-net-guan-shu/toconet_u16rccalib) API を利用します。                |
| `uint8 u8MacInitPending`                              | TRUE ならMAC層の初期化の遅延実施する。センサー処理等のみで起床する場合など、時間と電流消費のある MAC 層の初期化をさせない目的で設定する。                                                                                            |

{% hint style="warning" %}
ch26 は海外認証(FCC/IC)で使用できない場合があります(u8Channel, u32ChMask)
{% endhint %}


# tsRxDataApp

無線パケットの受信時に[`cbToCoNet_vRxEvent()`](/twelite-net-api-ref/krubakku/cbtoconet_vrxevent)に渡される構造体。

| 定義名                                   | 解説                                                                                                                                      |
| ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `uint8 u8Cmd`                         | パケット種別。送信元で任意に指定します。データ用、コマンド用といった区分けに使います。値域：`0-7`                                                                                     |
| `uint8 u8Len`                         | ペイロード長。後述の `au8Data[]` に格納されるデータ長。（[最大パケットサイズ](/twelite-net-api-expl/paketto/pakettono)）                                                |
| `uint8 u8Seq`                         | シーケンス番号。送信元で任意に設定します。重複パケットの判定などに使用します。値域: `0-255`                                                                                      |
| `uint32 u32SrcAddr uint32 u32DstAddr` | 送信元、送信先アドレス。`0-0xFFFF` の範囲はショートアドレスモード、`0x8000000` 以上は拡張アドレスによる送受信を示します。`0xFFFF` はブロードキャスト（同報）通信になります。                                  |
| `uint8 auData[]`                      | ペイロード。ペイロード長分のデータが有効（[最大パケットサイズ](https://sdk.twelite.info/~/edit/drafts/-LAzW5puLXpmlZOxrWPi/twenet_api_overview/packet/packet_maxlen)） |
| `uint8 u8Lqi`                         | 受信品質 LQI 値。値域：0..255 （受信時の電界強度に対応し 0 が最弱、255 が最強）                                                                                       |
| `uint8 bSecurePkt`                    | パケットが暗号化されていた場合 TRUE になります。この時点で既に auData\[] は平文に復号されています。                                                                              |
| `uint32 u32Tick`                      | 受信時のタイムスタンプ([`u32TickCount_ms`](/twelite-net-api-ref/gurbaru/uint32-u32tickcount_ms))                                                   |


# tsTxDataApp

無線送信を行うとき、送信したいデータ、宛先、送信時の諸設定を構造体に格納し、送信API にポインタとして渡す。

### メンバー一覧（単純ネット）

| 定義名                                            | 解説                                                                                                                                                                                                                                                                |
| ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `uint32 u32SrcAddr`                            | 送信元アドレス。`0xFFFF` 未満ならショートアドレス。`0x8000000` 以上は拡張アドレス。通常は [`sToCoNet_AppContext.u16ShortAddress`](/twelite-net-api-ref/gou-zao-ti/stoconet_appcontext) または [`ToCoNet_u32GetSerial()`](/twelite-net-api-ref/twelite-net-guan-shu/toconet_u32getserial) より自アドレスを指定する。 |
| `uint32 u32DstAddr`                            | 宛先アドレス。0xFFFF 以下ならショートアドレス。`0x8000000` 以上は拡張アドレス。 `TOCONET_MAC_ADDR_BROADCAST(0xFFFF)`は ブロードキャスト送信を示す。                                                                                                                                                            |
| `uint8 u8Cmd`                                  | <p>パケット種別。アプリケーションで自由に設定できる。<br>値域: <code>0..7</code></p>                                                                                                                                                                                                         |
| `uint8 u8CbId`                                 | コールバックID。送信要求時に設定した値が [`cbToCoNet_TxEvent()`](/twelite-net-api-ref/krubakku/cbtoconet_vtxevent) により渡されます。この値によって送信したパケットと送信完了イベントを対応付けます。本値は送信パケットには含まれません。値域：0-255                                                                                               |
| `uint8 au8Data[]`                              | パケットのペイロード（[最大パケットサイズ](/twelite-net-api-expl/paketto/pakettono)）                                                                                                                                                                                                  |
| bool\_t bAckReq                                | `TRUE` ならACK送信要求を設定します。同報通信時には `FALSE` を設定します。                                                                                                                                                                                                                    |
| `uint8 u8Retry`                                | ToCoNet で実施する再送回数。MAC層での再送に失敗した場合、ToCoNet で再度パケット送信を試みます。MSB を設定すると、成功失敗に関わらず指定回数の再送を行います。同報通信では殆どの場合送信が成功するため、複数回送信が必要な場合はこのビットを立てます。例えば0x83 を指定すると、都合４回送信が行われます。値域は 0x0～0xF, 0x80～0x8F。                                                                         |
| `uint16 u16DelayMin, u16DelayMax, u16RetryDur` | 送信開始まで `u16DelayMin` \[ms] 遅延し、最大 `u16DelayMax` \[ms] 待ちます。最大値は乱数により決定するため、送信にタイミングに意図的なブレを作るため使用します。送信開始後は `u16RetryDur`\[ms] 間隔で再送が行われます（この間隔は固定）。この処理はシステムのタイマーにより制御されるため、タイマー刻みの精度（標準は4ms）で実行されます。値域には制限はありませんが、一般的には、長くとも 1000ms 程度です。                       |
| `uint16 bSecurePkt`                            | 平文で送信する場合は `ALSE`, 暗号化する場合は `TRUE` を指定します。事前に [`ToCoNet_bRegisterAesKey()`](/twelite-net-api-ref/twelite-net-guan-shu/toconet_bregisteraeskey) により暗号化鍵を登録しておきます。※最大利用バイト数が２バイト減少します。（[最大パケットサイズ](/twelite-net-api-expl/paketto/pakettono)）                        |


# TWELITE NET マクロ


# ToCoNet\_REG\_MOD\_ALL()

[モジュール](/twelite-net-api-expl/mojru)登録用の手続き。[cbAppColdStart](/twelite-net-api-ref/krubakku/cbappcoldstart)() 関数の FALSE 引数時に記述する。


# utils.h

utils.h をインクルードすることで利用できるマクロを紹介します。

## S\_OCTET(x)

１バイトをメモリを書き込む。

```c
uint8 *q = &sTx.au8Data[0];

S_OCTET(0x12);　
S_BE_WORD(0x1234); 
S_BE_DWORD(0x12345678);
```

uint8 \*q をローカル変数として宣言しておき、データを読み込みたい領域のポインタとしておく。代入演算子の評価後 q++ が実行される。

## S\_BE\_WORD(x)

２バイトをメモリを書き込む。

```c
uint8 *q = &sTx.au8Data[0];

S_OCTET(0x12);　
S_BE_WORD(0x1234); 
S_BE_DWORD(0x12345678);
```

uint8 \*q をローカル変数として宣言しておき、データを読み込みたい領域のポインタとしておく。代入演算子の評価後 q+=2 が実行される。

BE はビッグエンディアン、LE はリトルエンディアン。

## S\_BE\_DWORD(x)

４バイトをメモリを書き込む。

```c
uint8 *q = &sTx.au8Data[0];

S_OCTET(0x12);　
S_BE_WORD(0x1234); 
S_BE_DWORD(0x12345678);
```

uint8 \*q をローカル変数として宣言しておき、データを読み込みたい領域のポインタとしておく。代入演算子の評価後 q+=4 が実行される。

BE はビッグエンディアン、LE はリトルエンディアン。

## G\_OCTET()

１バイトメモリを読み込み uint8 型の変数に値を格納する。

```c
uint8 *p = &sRx.au8Data[0];

uint8 u8data1 = OCTET();　
uint16 u16data2 = G_BE_WORD(); 
uint32 u32data3 = G_BE_DWORD();
```

uint8 \*p をローカル変数として宣言しておき、データを読み込みたい領域のポインタとしておく。=演算子の評価後 p++ が実行される。

## G\_BE\_WORD()

２バイトメモリを読み込み uint16 型の変数に値を格納する。

```c
uint8 *p = &sRx.au8Data[0];

uint8 u8data1 = OCTET();　
uint16 u16data2 = G_BE_WORD(); 
uint32 u32data3 = G_BE_DWORD();
```

uint8 \*p をローカル変数として宣言しておき、データを読み込みたい領域のポインタとしておく。=演算子の評価後 p+=2 が実行される。

BE はビッグエンディアン、LE はリトルエンディアン。

## G\_BE\_DWORD()

１バイトメモリを読み込み uint8 型の変数に値を格納する。

```c
uint8 *p = &sRx.au8Data[0];

uint8 u8data1 = OCTET();　
uint16 u16data2 = G_BE_WORD(); 
uint32 u32data3 = G_BE_DWORD();
```

uint8 \*p をローカル変数として宣言しておき、データを読み込みたい領域のポインタとしておく。=演算子の評価後 p+=4 が実行される。

BE はビッグエンディアン、LE はリトルエンディアン。

## ENCODE\_VOLT(x)

2000～3600 の値を 8bit 値に変換します。

* 1.95\~2.80V は 5mV 刻み
* 2.81\~3.65V は 10mV 刻み

```c
// utils.h の定義
#define ENCODE_VOLT(m) \
	(m < 1950 ? 0 : \
		(m > 3650 ? 255 : \
			(m <= 2802 ? ((m-1950+2)/5) : ((m-2800-5)/10+171)) ))

...
uint16 u16Volt = 2860;
uint8 u8Volt_enc = ENCODE_VOLT(u16Volt);
uint16 u16Volt_dec = DECODE_VOLT(u8Volt_Enc);
```

2000～2800 の値は 5 刻み、2800～は10 刻みで 8bit 値に割り当てます。

## DECODE\_VOLT(x)

ENCODE\_VOLT() により得られた8bit値を元の値に戻します。

* 1.95\~2.80V は 5mV 刻み
* 2.81\~3.65V は 10mV 刻み

```c
// utils.h の定義
#define DECODE_VOLT(i) \
	(i <= 170 ? (1950+i*5) : (2800+(i-170)*10) )

...
uint16 u16Volt = 2860;
uint8 u8Volt_enc = ENCODE_VOLT(u16Volt);
uint16 u16Volt_dec = DECODE_VOLT(u8Volt_Enc);
```

2000～2800 の値は 5 刻み、2800～は10 刻みで 8bit 値に割り当てます。

## vPortAsInput(c)

ポートcを入力に設定する

```c
#define vPortAsInput(c) vAHI_DioSetDirection(1UL << (c), 0)
```

## vPortAsOutput(c) <a href="#vportasinput-c" id="vportasinput-c"></a>

ポートcを出力に設定する

```c
#define vPortAsOutput(c) vAHI_DioSetDirection(0, 1UL << (c))
```

## ​vPortSetHi(c)

ポートcをHi状態にする

```c
#define vPortSetHi(c) vAHI_DioSetOutput(1UL << (c), 0)
```

## ​​vPortSetLo(c)

ポートcをLo状態にする

```c
#define vPortSetLo(c) vAHI_DioSetOutput(0, 1UL << (c))
```

## ​​​vPortSet\_TrueAsLo(c, s)

ポート c を s が TRUE なら Lo, FALSE なら Hi に設定する

```c
#define vPortSet_TrueAsLo(c, s)  vAHI_DioSetOutput((s) ? \
    0 : 1UL << (c), s ? 1UL << (c) : 0)
```

## bPortRead(c)

ポート c を読み出す。Loレベルなら TRUE が返る

```c
#define bPortRead(c) ((u32AHI_DioReadInput() & \
    (1UL<<(c))) ? FALSE : TRUE)
```

## ​u32PortReadBitmap()

ポート c を読み出す。Loレベルなら TRUE が返る。

```c
#define u32PortReadBitmap() (u32AHI_DioReadInput())
```

{% hint style="warning" %}
ビットマップの1がHi,0がLoとなります。
{% endhint %}

## ​bPortCheckBitmap(bitmap, c)

読みだしたビットマップのポート c に対応するビットがLoレベルならTRUEを返す。

```c
#define bPortCheckBitmap(bitmap, c) \
    (bitmap & (1UL<<(c))) ? FALSE : TRUE)
```

## vPortDisablePullup(c)

ポート c のプルアップを停止する。

```c
#define vPortDisablePullup(c) vAHI_DioSetPullup(0x0, 1UL << (c))
```

## \_C

switch でスコープを定義したい場合 \_C { … } と記述している。

```c
#define _C if(1)

// for example
switch(c) {
case 1:
  _C {
    uint8 u8work;
    ; // work
  } break;
default:
}
```

## LB

改行コード (CRLF) 文字列です。

{% hint style="warning" %}
２バイトの文字列リテラルですので、[vPutChar](/hw-api-ref/perifuraru/uart/fprintf-raiburari/vputchar)() では利用できません。
{% endhint %}

```c
#define LB "\r\n"

// for example
vfPrintf(&sSerStream, "HELLO WORLD!" LB);
```


# ユーザ定義イベント処理関数

ユーザ定義イベント処理関数は、TWENET からコールバックとして呼び出される形でイベント処理を行う目的でユーザが独自に定義する関数です。関数と呼んでいますが、ステート（状態遷移）マシンとして振るいます。

```c
void cbAppColdStart(bool_t bInit) {
    if (bInit == FALSE) {
 		...
    } else {
    	...
    	ToCoNet_Event_Register_State_Machine(vProcessEvCore);
    }
}

void vProcessEvCore(
        tsEvent *pEv,
        teEvent eEvent,
        uint32 u32evarg) {
    // check boot seq
	if (eEvent == E_EVENT_START_UP) {
		if (u32evarg & EVARG_START_UP_WAKEUP_RAMHOLD_MASK) {
			// woke from NORMAL SLEEP (RAMHOLD)
		}
	    if (u32evarg & EVARG_START_UP_WAKEUP_MASK) {
			// woke from DEEP SLEEP
	    } else {
			// COLD boot
	    }
	}
	
	switch (pEv->eState) {
	case E_STATE_IDLE:
		; // some task
		ToCoNet_Event_SetState(pEv, E_STATE_APP_NORMAL);
		break;
	case E_STATE_APP_NORMAL:
		; // some task (e.g. send s Tx packet)
		if (cond) {
			ToCoNet_Event_SetState(pEv, E_STATE_APP_WAIT_TX);
		}
		break;
	case E_STATE_APP_WAIT_TX:
		; // some task (e.g. wait until Tx finishes)
		if (cond) {
		    ToCoNet_Event_SetState(pEv, E_STATE_APP_NORMAL);
		}
		break;
	}
}
```

### 登録

ユーザ定義イベント処理関数は [ToCoNet\_Event\_Register\_State\_Machine](/twelite-net-api-ref/yzaibento/toconet_event-api/toconet_event_register_state_machine)() により最大２つまで登録します。

{% hint style="info" %}
[E\_EVENT\_START\_UP](/twelite-net-api-ref/yzaibento/ibento)イベントを受け取るにはユーザ定義イベント処理関数の登録が必要です。
{% endhint %}

### 伝達されるイベント

伝達されるイベントは以下の３イベントです。これ以外のイベントは [ToCoNet\_Event\_Process](/twelite-net-api-ref/yzaibento/toconet_event-api/toconet_event_process)() 関数により関数のコールバック呼び出しとして伝達されます。

* [E\_EVENT\_START\_UP](/twelite-net-api-ref/yzaibento/ibento) : 始動時
* [E\_EVENT\_TICK\_TIMER](/twelite-net-api-ref/yzaibento/ibento) : 4ms 周期（デフォルト）
* [E\_EVENT\_TICK\_SECOND](/twelite-net-api-ref/yzaibento/ibento) : １秒周期

以下のコードは送信完了をユーザ定義イベント処理関数 vProcessEvCore に伝達する例です。

```c
cbToCoNet_vTxEvent(uint8 u8CbId, uint8 u8Stat) {
    ToCoNet_Event_Process(E_EVENT_APP_TX_COMPLETE, 
        u8CbId, vProcessEvCore);
}
```

{% hint style="warning" %}
ToCoNet\_Event\_Process() を用いずに vProcessEvCore() を呼び出すことは避けるべきです。[フロー図](/twelite-net-api-expl/twenet-fur/yzaibentofur)に示した状態遷移が行われず、また、ユーザ定義イベント処理関数の管理構造体に含まれる情報に矛盾が発生します。

割り込みハンドラから呼び出してはいけません。
{% endhint %}

### 状態遷移について

ユーザ定義イベント処理関数のステートマシンは、[E\_STATE\_IDLE](https://github.com/monowireless/doc_TWENET_JP/blob/jp_new/twelite-net-api-ref/yzaibento/broken-reference/README.md)\_ \_(0) から開始します。

ユーザ定義イベント処理関数が呼び出される際に、ToCoNet\_Event\_SetState() 関数を呼び出すことで状態遷移を宣言します。状態遷移を宣言したのちユーザ定義イベント処理関数を脱出すると、[E\_EVENT\_NEW\_STATE](/twelite-net-api-ref/yzaibento/ibento) イベントをパラメータにもう一度関数が呼び出されます。状態遷移が続く限りこの処理は連続します（[フロー図](/twelite-net-api-expl/twenet-fur/yzaibentofur)）。

{% hint style="info" %}
スリープ(RAM保持)前に [ToCoNet\_Event\_vKeepStateOnRamHoldSleep](/twelite-net-api-ref/yzaibento/toconet_event-api/toconet_event_vkeepstateonramholdsleep)() を呼び出しておくことで直前の状態を保持でき、スリープ復帰後に [E\_EVENT\_START\_UP](/twelite-net-api-ref/yzaibento/ibento) イベントを受け取ることができます。
{% endhint %}


# ステート（状態）

## 組み込み状態

E\_STATE\_IDLE以外の状態名は、ユーザ定義イベント処理関数で自由に使うことができます。また、状態名をユーザ定義することも可能です。

| 状態名                | 解説         |
| ------------------ | ---------- |
| E\_STATE\_IDLE     | 初期状態。値は 0。 |
| E\_STATE\_RUNNING  | 実行中。       |
| E\_STATE\_FINISHED | 完了。        |

## ユーザ独自定義

ToCoNet\_EVENT\_APP\_BASE 定義以降の値を利用してください。

```c
#include "ToCoNet_event.h"

typedef enum
{
    E_STATE_APP_BASE = ToCoNet_STATE_APP_BASE,
    E_STATE_USER_INIT,
    E_STATE_USER_FINISH,
    E_STATE_USER_MEASURING
} teStateApp;
```

{% hint style="warning" %}
enum を 16bit や 8bit に小さくするコンパイルオプションは適用しないでください。
{% endhint %}


# イベント

## 組み込みイベント

| 定義                     | 解説                                                                                                                                                                                                 |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| E\_EVENT\_START\_UP    | システム起動（またはスリープ復帰）時に発生します。イベント引数は EVARG\_START\_UP\_WAKEUP\_MASK または(EVARG\_START\_UP\_WAKEUP\_MASK \| EVARG\_START\_UP\_WAKEUP\_ RAMHOLD\_MASK) が与えられ、前者はDEEPスリープからの復帰、後者は通常のRAM保持スリープからの復帰を意味します。 |
| E\_EVENT\_NEW\_STATE   | 状態遷移したときに最初に呼ばれるイベントです。※ システム始動時には呼び出されません（START\_UPイベントが発生する）。イベント引数は未定義。                                                                                                                         |
| E\_EVENT\_TICK\_TIMER  | システムタイマー(4ms)毎に呼び出されます。イベント引数は未定義。※ システム内のモジュール処理が終わった後に呼ばれます。呼び出しはばらつきが発生するため、タイミングを優先したい処理は cbToCoNet\_u8HwInt() 中の割り込みハンドラ中の E\_AHI\_DEVICE\_TICK\_TIMER に記述します。                                |
| E\_EVENT\_TICK\_SECOND | １秒ごとに呼び出されます。イベント引数は未定義。                                                                                                                                                                           |
| E\_ORDER\_INITIALIZE   | 初期化を促すメッセージとして利用する。                                                                                                                                                                                |
| E\_ORDER\_KICK         | 開始を促すメッセージとして利用する。                                                                                                                                                                                 |

## ユーザ定義イベント

ユーザ定義のイベント名を用意する場合は、ToCoNet\_EVENT\_APP\_BASE以降の値を割り振るようにしてください。

```c
typedef enum
{
	E_EVENT_APP_BASE = ToCoNet_EVENT_APP_BASE,
    E_EVENT_TICK_A,
    E_EVENT_SCAN_FINISH,
    E_EVENT_SLAVE_CONF_FAIL,
    E_EVENT_SLEEP_REQUEST
} teEventApp;
```

{% hint style="warning" %}
enum を 16bit や 8bit に小さくするコンパイルオプションは適用しないでください。
{% endhint %}


# ToCoNet\_Event API


# ToCoNet\_Event\_Register\_State\_Machine()

## 解説

ユーザ定義イベント処理関数をシステムに登録する。本関数は [cbAppColdStart](/twelite-net-api-ref/krubakku/cbappcoldstart)(TRUE) で実行する。

## 引数

| 型      | 名前     | 詳細                       |
| ------ | ------ | ------------------------ |
| void\* | pvFunc | ユーザ定義イベント処理関数(\*1)を指定する。 |

```
*1: pvFunc の関数プロトタイプは以下である。
void vProcessEvCore(
        tsEvent *pEv,
        teEvent eEvent,
        uint32 u32evarg)
```

## 戻り値

| 型     | 詳細                    |
| ----- | --------------------- |
| uint8 | ユーザ定義イベント処理関数のハンドル番号。 |

## サンプル

```c
void vProcessEvCore(
        tsEvent *pEv,
        teEvent eEvent,
        uint32 u32evarg);

void cbAppColdStart(bool_t bInit) {
    if (bInit == FALSE) {
 		...
    } else {
    	...
    	ToCoNet_Event_Register_State_Machine(vProcessEvCore);
    }
}
```


# ToCoNet\_Event\_Process()

## 解説

指定したユーザ定義イベント処理関数でのイベント処理を行う。ハンドルにより指定する場合は ToCoNet\_Event\_ProcessH() を呼び出します。

{% hint style="info" %}
この処理は関数呼び出しとして同期的に実行されます。
{% endhint %}

{% hint style="warning" %}
ユーザ定義イベント処理関数を直接呼び出してはいけません。適切な状態遷移が実施されず、また内部の管理情報と矛盾が発生することがあります。
{% endhint %}

## 引数

### ToCoNet\_Event\_Process()

| 型                    | 名前       | 詳細            |
| -------------------- | -------- | ------------- |
| teEvent (または uint32) | eEvent   | イベント名         |
| uint32               | u32evarg | イベント引数        |
| void\*               | pvFunc   | ユーザ定義イベント処理関数 |

### ToCoNet\_Event\_ProcessH()

| 型                    | 名前       | 詳細                  |
| -------------------- | -------- | ------------------- |
| teEvent (または uint32) | eEvent   | イベント名               |
| uint32               | u32evarg | イベント引数              |
| uint8                | u8Handle | ユーザ定義イベント処理関数へのハンドル |

## 戻り値

なし。

## サンプル

```c
static u8hnd; // ハンドル
...
    // 登録
    u8hnd = ToCoNet_Event_Register_State_Machine(vProcessEvCore);
... 
// 送信完了を vProcessEvCore に伝える。
cbToCoNet_vTxEvent(uint8 u8CbId, uint8 u8Stat) {
    ToCoNet_Event_Process(E_EVENT_APP_TX_COMPLETE, 
        u8CbId, vProcessEvCore);
    // または
    ToCoNet_Event_Process(E_EVENT_APP_TX_COMPLETE, 
        u8CbId, u8hnd);
}
```


# ToCoNet\_Event\_SetState()

## 解説

ユーザ定義イベント処理関数内で状態遷移を行う。

{% hint style="info" %}
ユーザ定義イベント処理関数を終了後に、続けて新しい状態にて E\_EVENT\_NEW\_STATE イベントが呼び出されます。
{% endhint %}

## 引数

| 型          | 名前        | 詳細                 |
| ---------- | --------- | ------------------ |
| tsEvent \* | pEv       | ユーザイベント定義関数の管理構造体。 |
| teState    | eNewState | 新しい状態。             |

## 戻り値

なし

## サンプル

```c
sToCoNet_Event_SetState(pEv, E_STATE_APP_NORMAL);
```




---

[Next Page](/llms-full.txt/1)

