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が応答していることが確認できます。
謝辞
UnityでのTCPサーバーはこちらの記事を参考にさせていただきました。
【Unity】Unity 同士で TCP 通信を行う
https://baba-s.hatenablog.com/entry/2020/09/08/090000
1
投稿者の人気記事
-
dreamdrive
さんが
2022/09/25
に
編集
をしました。
(メッセージ: 初版)
ログインしてコメントを投稿する