dreamdriveのアイコン画像
dreamdrive 2022年09月25日作成 © MIT
セットアップや使用方法 セットアップや使用方法 閲覧数 1259
dreamdrive 2022年09月25日作成 © MIT セットアップや使用方法 セットアップや使用方法 閲覧数 1259

SPRESENSE Wi-Fi Add-onボード iS110BでUnityとTCP通信テスト

SPRESENSE Wi-Fi Add-onボード iS110BでUnityとTCP通信テスト

Spresenseのマルチコアを活かして、非同期でコアごとに制御を分けたシステムを作りたいのですが、この記事は、その要素技術として、SPRESENSE Wi-Fi Add-onボード iS110Bを使用して、UnityとTCPで通信する忘備録です。

用意するもの

  • Spresense - 1個
  • Spresense拡張ボード - 1個
  • SPRESENSE Wi-Fi Add-onボード iS110B - 1個
  • Unity 2020.3.XXf1 とそれが動くPC
  • WiFi環境

Spresense 側のプログラム

https://github.com/jittermaster/GS2200-WiFi
のサンプル「TCPClient」のApp_TCPClient_Test関数を下記の通り書き換えます。
config.hは、適宜WiFi環境に合わせて設定してください

/*---------------------------------------------------------------------------*
   App_TCPClient_Test
  ---------------------------------------------------------------------------
   Description:
       Connect TCP server, send data on and on
       Show the received data from the TCP server
  ---------------------------------------------------------------------------*/

void App_TCPClient_Test(void)
{
  ATCMD_RESP_E resp;
  char server_cid = 0;
  bool served = false;
  ATCMD_NetworkStatus networkStatus;
  uint32_t timer = 0;
  bool transmit_allow = true; // このフラグが立っている時だけ送って良いよ

  AtCmd_Init();

  App_InitModule();
  App_ConnectAP();

  while (1) {
    if (!served) {
      resp = ATCMD_RESP_UNMATCH;
      // Start a TCP client
      ConsoleLog( "Start TCP Client");
      resp = AtCmd_NCTCP( (char *)TCPSRVR_IP, (char *)TCPSRVR_PORT, &server_cid);
      if (resp != ATCMD_RESP_OK) {
        ConsoleLog( "No Connect!" );
        delay(2000);
        continue;
      }
      if (server_cid == ATCMD_INVALID_CID) {
        ConsoleLog( "No CID!" );
        delay(2000);
        continue;
      }

      do {
        resp = AtCmd_NSTAT(&networkStatus);
      } while (ATCMD_RESP_OK != resp);

      ConsoleLog( "Connected" );
      ConsolePrintf("IP: %d.%d.%d.%d\r\n",
                    networkStatus.addr.ipv4[0], networkStatus.addr.ipv4[1], networkStatus.addr.ipv4[2], networkStatus.addr.ipv4[3]);

      served = true;
    }
    else {
      ConsoleLog( "Start to send TCP Data");
      // Prepare for the next chunck of incoming data
      WiFi_InitESCBuffer();

      // Start the infinite loop to send the data
      while ( 1 ) {

        // 送信許可フラグが立っていない時は送信しない
        if (transmit_allow) {
            transmit_allow = false;  // 送信したら送信許可フラグを倒す
          if ( ATCMD_RESP_OK != AtCmd_SendBulkData( server_cid, TCP_Data, strlen(TCP_Data) ) ) {
            // Data is not sent, we need to re-send the data
            delay(10);
            transmit_allow = true;  // ただし、送信失敗した際は、次回再度送信するように送信許可フラグを戻す
          }
        }

        while ( Get_GPIO37Status() ) {
          resp = AtCmd_RecvResponse();
          if ( ATCMD_RESP_BULK_DATA_RX == resp ) {
            if ( Check_CID( server_cid ) ) {
              ConsolePrintf( "Receive %d byte:%s \r\n", ESCBufferCnt - 1, ESCBuffer + 1 );
              // 受信した際に送信許可フラグを立てる
              transmit_allow = true;
            }
            WiFi_InitESCBuffer();
          }
        }

        if ( msDelta( timer ) > 100 ) {
          timer = millis();
          led_effect();
        }
        
      }
    }
  }
}

Unityのサーバー側プログラム

下記のソースコードを適当なゲームオブジェクトにアタッチします。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

public class tcp : MonoBehaviour
{
    //================================================================================
    // 変数
    //================================================================================
    // この IP アドレスとポート番号はクライアント側と統一すること
    public string m_ipAddress = "127.0.0.1";
    public int m_port = 10001;

    private TcpListener m_tcpListener;
    private TcpClient m_tcpClient;
    private NetworkStream m_networkStream;

    private string m_message = string.Empty; // クライアントから受信した文字列

    //================================================================================
    // 関数
    //================================================================================
    /// <summary>
    /// 初期化する時に呼び出されます
    /// </summary>
    private void Awake()
    {
        // クライアントから文字列を受信する処理を非同期で実行します
        // 非同期で実行しないと接続が終了するまで受信した文字列を UI に表示できません
        Task.Run(() => OnProcess());
    }

    /// <summary>
    /// クライアント側から通信を監視し続けます
    /// </summary>
    private void OnProcess()
    {
        byte[] TCP_Data = System.Text.Encoding.ASCII.GetBytes("Unity to SPRESENSE");

        var ipAddress = IPAddress.Parse(m_ipAddress);
        m_tcpListener = new TcpListener(ipAddress, m_port);
        m_tcpListener.Start();

        Debug.Log("待機中");

        // クライアントからの接続を待機します
        m_tcpClient = m_tcpListener.AcceptTcpClient();

        Debug.Log("接続完了");

        // クライアントからの接続が完了したので
        // クライアントから文字列が送信されるのを待機します
        m_networkStream = m_tcpClient.GetStream();

        while (true)
        {
            var buffer = new byte[256];
            var count = m_networkStream.Read(buffer, 0, buffer.Length);

            // クライアントからの接続が切断された場合は
            if (count == 0)
            {
                Debug.Log("切断");

                // 通信に使用したインスタンスを破棄して
                OnDestroy();

                // 再度クライアントからの接続を待機します
                Task.Run(() => OnProcess());

                break;
            }
            else {

                // クライアントから文字列を受信した場合はログに出力します
                var message = Encoding.UTF8.GetString(buffer, 0, count);
                Debug.LogFormat("受信成功:{0}", message);

                // データ送信(応答)
                m_networkStream.Write(TCP_Data, 0, TCP_Data.Length);
            }
        }
    }

    /// <summary>
    /// 破棄する時に呼び出されます
    /// </summary>
    private void OnDestroy()
    {
        // 通信に使用したインスタンスを破棄します
        m_networkStream?.Dispose();
        m_tcpClient?.Dispose();
        m_tcpListener?.Stop();
    }
}

実行結果

SPRESENSEからのデータに対して、Unityが応答していることが確認できます。

SPRESENSEからのデータを受け付けたら応答を返す様子

謝辞

UnityでのTCPサーバーはこちらの記事を参考にさせていただきました。

【Unity】Unity 同士で TCP 通信を行う
https://baba-s.hatenablog.com/entry/2020/09/08/090000

1
ログインしてコメントを投稿する