はじめに
TCP/IPとはインターネットなどに代表される通信ネットワークにおいて全世界で標準的に使用されている通信プロトコルで、これに準拠する事でOSや環境に依らず機器間で通信が可能になっています。Webページを閲覧する時はそのTCP/IPの中のTCPという「送ったデータを 相手が 受け取れたか確認しながら通信する」といったプロトコルを用い、動画サイトなど高速なデータ通信が必要な場合はUDPという「相手が受け取ったかは不問とする」プロトコルが良く用いられます。
概要
WFI32 Cutiosity Board とスマホ間でTCP通信を行います。GitHub上にサンプルソフトが有りますので、以下のような構成で動作を確認します。
WFI32 Curiosity Boardについてはこちらで紹介しています。
ハードウェア
- WFI32 Cutiosity Board
- Home Rooter
- スマートフォン
- PC
- USB-Uart変換ボード
ソフトウェア
- Teraterm(PC側)
- UDP/TCP/REST Network Tool(スマホアプリ)
全体構成

MPLAB Harmony
サンプルソフトウェアは MPLAB Harmony3という統合フレームワークで開発されており、(fig.2)のように共通のシステムサービスや、周辺モジュールライブラリ層、ミドルウェア層といったブロックで構成されます。

ソフトウェアコンポーネントとしては(fig.3)のようなライブラリやドライバが含まれており、逐次追加されている模様です。

MPLAB Harmony は、PIC32 マイクロコントローラ向けの柔軟で包括的なファームウェア統合開発環境です。相互動作可能な RTOS対応ライブラリの開発を可能にします。また、迅速かつ広範なサポートによりサードパーティ製ソフトウェアを統合できます。
それらのソフトウェアコンポーネントは開発環境であるMPLAB Xに MPLAB Harmony Configuratorというプラグインで提供され、これを用いる事でGUIにてクロックの設定やI/Oピン設定、上記のシステムサービス、ミドルウェアなどのコードを自動で生成可能となっています。
開発の進め方
1.GitLabからのサンプルプロジェクトダウンロード
①GitHubのGitHub – マイクロチップ-MPLAB-ハーモニー/ワイヤレス:ハーモニー3ワイヤレスソリューションページから「TCPサーバ」をクリック

②開いたWebページから「top level of the repository」をクリック

③開いたWebページから「Code」をクリックしメニューを開き「Download Zip」でPC上にDLします。

2.MPLAB X IDEでの操作
①ダウンロードした「tcp_server\pic32mz_w1_curiosity_freertos.X」プロジェクトを適当なフォルダにコピーして開きます。
②メインメニュー>「Tools」>「Embedded」> 「MPLAB Harmony 3 Configurator」をクリック
(メニューにない場合、プラグインをインストールする必要が有ります)

③「Harmonyツール」が立ち上がるので「WIFI SERVICE」をクリックし以下の設定を行います。
| 項目 | 値 |
| Device Mode | STA |
| STA Mode | チェック |
| SSID | Home RooterのSSID |
| Password | Home Rooterのパスワード |

③「Net Service」をクリックし以下の設定を行う。
| 項目 | 値 |
| Instance 0 | チェック |
| Intf | WIFI |
| Ip Protocol | TCP |
| Mode | SERVER |
| Server Port | 5555 |
| Host Name/ IP Address | 192.168.0.1(ここは適当で良い) |

④「Code」を押してソースファイルを自動生成する。

⑤プロジェクトをビルドし、ターゲットボードに書き込む。
3.Tera TermとUDP/TCP/REST Network Tool で動作確認
①Tera Termを起動しポートの指定とボーレート(115,200bps)を設定し接続すると、マイコンリセットタイミングでコンソール上に(fig.13)のように表示されます。

② UDP/TCP/REST Network Tool のTCPタブを開き以下の、以下の設定を行い「Connect」をクリック。Remote Hostの値は各自環境で異なります。(コンソール上のIP Addres obtainedで表示された値 )
| 項目 | 値 |
| Mode | Client |
| Remote Host | 192.168.0.8(※) |
| Port | 5555 |

③コンソール上に「Recived a connection」「TcpServCallback(): Status UP」と表示されます。

④スマフォ側アプリのMessageに適当な文字を入力し「Send」を押下すると、Tera Tarm上に受信データ内容が表示されると共に、スマホ側にも同じメッセージをコールバックします。

クライアント側への応答メッセージ
デフォルトではクライアントから受信したメッセージをそのままコールバックしています。この処理は「app.c」の以下のTcpServCallback関数内で処理をしています。
ネットシステムサービスにより主要な処理は隠蔽され、ユーザーはコールバック関数内の下記のイベントが発生したタイミングでなんらかの処理を行えば良い訳です。サンプルでは受信イベントで受信データを処理し、「 SYS_NET_SendMsg ()」でメッセージを送信しています。
| 項目 | 値 | イベント |
| SYS_NET_EVNT_CONNECTED | 0 | NETソケットがPeerに接続された |
| SYS_NET_EVNT_DISCONNECTED | 1 | NET ソケットが切断された |
| SYS_NET_EVNT_RCVD_DATA | 2 | Peerに接続された NETソケットが データを受信した |
| SYS_NET_EVNT_SSL_FAILED | 3 | SSLネゴシエーションに失敗した |
| SYS_NET_EVNT_DNS_RESOLVE_FAILED | 4 | DNSリゾルブに失敗した |
| SYS_NET_EVNT_SOCK_OPEN_FAILED | 5 | ソケットのオープンに失敗した |
| SYS_NET_EVNT_LL_INTF_DOWN | 6 | PPPがダウン(Connected Stateでのみ受信) |
| SYS_NET_EVNT_LL_INTF_UP | 7 | PPPがアップ(Connected Stateでのみ受信) |
| SYS_NET_EVNT_SERVER_AWAITING_CONNECTION | 8 | TCP サーバの接続待ち |
今回は受信した回数を返信するようにサンプルコードを改造しました。下記コードの「//追加」の行を追加し、「//コメントアウト//」の行をコメントアウトします。
void TcpServCallback(uint32_t event, void *data, void* cookie)
{
static uint16_t RcvNum = 0; //追加
uint8_t SndBuff[16]; //追加
uint16_t SndLen; //追加
switch(event)
{
case SYS_NET_EVNT_CONNECTED:
{
SYS_CONSOLE_PRINT("TcpServCallback(): Status UP\r\n");
while(SYS_NET_SendMsg(g_tcpServHandle, (uint8_t*)"hello", 5) <= 0);
break;
}
case SYS_NET_EVNT_DISCONNECTED:
{
SYS_CONSOLE_PRINT("TcpServCallback(): Status DOWN\r\n");
break;
}
case SYS_NET_EVNT_RCVD_DATA:
{
int32_t cumm_len = 0;
int32_t len = RECV_BUFFER_LEN;
while(len == RECV_BUFFER_LEN)
{
len = SYS_NET_RecvMsg(g_tcpServHandle, recv_buffer, RECV_BUFFER_LEN);
if(len>0)
{
if(cumm_len == 0)
{
uint8_t buffer[33];
int32_t tmp_len = (len > 32)? 32 : len;
memcpy(buffer, recv_buffer, tmp_len);
buffer[tmp_len] = '\0';
SYS_CONSOLE_PRINT("TcpServCallback(): Data Rcvd = %s\r\n", buffer);
}
cumm_len += len;
//SYS_NET_SendMsg(g_tcpServHandle, recv_buffer, len); //コメントアウト
SndLen = sprintf((char *)SndBuff,"Num = %d",RcvNum++); //追加
SYS_NET_SendMsg(g_tcpServHandle, SndBuff, SndLen); //追加
}
}
SYS_CONSOLE_PRINT("TcpServCallback(): Total Data Rcvd = %d Bytes\r\n", cumm_len);
break;
}
case SYS_NET_EVNT_LL_INTF_DOWN:
{
/*
** User needs to take a decision if they want to close the socket or
** wait for the Lower layer to come up
*/
SYS_CONSOLE_PRINT("TcpServCallback(): Lower Layer Down\r\n");
break;
}
case SYS_NET_EVNT_LL_INTF_UP:
{
/*
** The lower layer was down and now it has come up again.
** The socket was in connected state all this while
*/
SYS_CONSOLE_PRINT("TcpServCallback(): Lower Layer Up\r\n");
break;
}
case SYS_NET_EVNT_SERVER_AWAITING_CONNECTION:
{
/*
** The server is awaiting connection from the client
*/
SYS_CONSOLE_PRINT("TcpServCallback(): Server Awaiting Connection\r\n");
break;
}
}
}
注意点①
当初作成したプログラムをビルドして書き込む事は可能ですが、デバッグモードで「Debug」ボタンを押した後、何分かけてもデバッグ情報の生成が終わらずデバッグができない状況でした。
これは以下の様にMicrochipフォーラムでもスレッドが立っている通り、GCCコンパイラのバージョンがV3以上の場合に詳細なデバッグ情報を書き出すために、非常に時間がかかるようです。ここでGCCオプションに「-gdwarf-4」を入れると速くなるとの事でしたので、これで「我慢できる速さ」でデバッグが可能となりました。

注意点②
Harmony上で 「Device Mode」を「AP」に設定すると、WFI32がアクセスポイントになり外部のルータ不要で直接クライアント側との通信が可能となります。ただし原因は分かりませんが外部ルータを使用する場合と比べ、非常に通信速度が遅くなる現象が発生しました。これに関しては追って調査したいと思います。

コメント