実装: Unity 5.1.3-f1 on MacOS X 10.8.5
動作確認: Windows 8.1 Pro (64bit)
入力した文字を返すecho server.
<CR>
を受けた時にそれまで受信した文字列を<CR><LF>
付きで返すように実装した。
code
ポートオープンとクローズはMyRs232cUtil.cs
にて実装。
受信と送信部分は以下で実装。
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using System.Threading; // for Thread
using System.IO.Ports; // for RS-232C
using NS_MyRs232cUtil;
/*
* v0.1 2015/09/22
* - can echo back
*/
public class echoServerCS : MonoBehaviour {
private static bool doStart = false;
private static bool doStop = false;
private Thread rcvThr;
public InputField IF_comname;
public Text T_status;
private SerialPort mySP;
private string accRcvd = "";
void Update () {
if (doStart) {
doStart = false;
bool res = MyRs232cUtil.Open (IF_comname.text, out mySP);
mySP.ReadTimeout = 1;
if (res == false) {
T_status.text = "open fail";
return;
}
mySP.Write(">");
}
if (doStop) {
doStop = false;
MyRs232cUtil.Close(ref mySP);
T_status.text = "closed";
}
if (mySP.IsOpen) {
byte rcv;
char tmp;
try {
rcv = (byte)mySP.ReadByte();
if (rcv != 255) {
tmp = (char)rcv;
if (tmp != 0x0d && tmp != 0x0a) { // not CRLF
accRcvd = accRcvd + tmp.ToString();
}
if (tmp == 0x0d) { // CR
mySP.WriteLine(accRcvd);
T_status.text = "has read:" + accRcvd;
accRcvd = "";
}
}
} catch (System.Exception) {
}
}
Thread.Sleep (20); // without this app will freeze
}
public static void SetStart() {
doStart = true;
}
public static void SetStop() {
doStop = true;
}
}
使用例
以下を用意した
- USB-シリアル変換ケーブル (VE488) x 2本
- クロス用治具 (DSub-9pin x 2を TX, RXクロスで接続. GNDはそのまま接続)
上記をWindows8.1で使用すると、COM3とCOM4としてお互いが通信できるようになっていることを確認。
COM4側をTeraTermなどのターミナルソフトで立ち上げておいて、上記のスクリプトを実装してビルドした.exeファイルをWindows 8.1側で実行する。
Startボタンを押して、echo serverが動作を始める。
COM4で改行まで入力した文字列(例 abcdef)がecho serverによりecho backされる。ただし、Unityソフトがアクティブになっている時に返答するので、COM4入力後はUnityソフト側をクリックしないといけない。
Update()で処理しているためだ。スレッドにするなりすればこのあたりは改善するだろう。
v0.2 (Thread版)
(追記 2015/09/23)
Update()で送受信をすると実行ソフトがアクティブでない時に送受信できない。このあたりはおそらくコルーチンにしても同じだろう。
スレッドに変更したものをv0.2とした。
主な変更点は以下の2つの関数。
...
private bool rcvAndEcho(ref SerialPort mySP) {
byte rcv;
char tmp;
bool hasRcvd = false;
try {
rcv = (byte)mySP.ReadByte();
if (rcv != 255) {
hasRcvd = true;
tmp = (char)rcv;
if (tmp != 0x0d && tmp != 0x0a) { // not CRLF
accRcvd = accRcvd + tmp.ToString();
}
if (tmp == 0x0d) { // CR
mySP.WriteLine(accRcvd);
rcvdCRLF = true;
}
}
} catch (System.Exception) {
}
return hasRcvd;
}
private void FuncEcho()
{
Debug.Log ("func echo start");
bool res = MyRs232cUtil.Open (IF_comname.text, out mySP);
mySP.ReadTimeout = 1;
if (res == false) {
statusText = "open fail";
return;
}
statusText = IF_comname.text + " : open";
mySP.Write (">");
while (doStop == false) {
if (mySP != null && mySP.IsOpen) {
if (rcvAndEcho(ref mySP)) {
statusText = "has received: " + accRcvd;
if (rcvdCRLF) {
rcvdCRLF = false;
accRcvd = "";
}
}
}
Thread.Sleep(20); // without this app may freeze
}
Debug.Log ("func echo stop");
MyRs232cUtil.Close(ref mySP);
statusText = IF_comname.text + " : closed";
doStop = false;
}
...
1つ気になるのはThread(20);で常に20msec待っていること。
文字列受信を始めたら、20msec待たずに連続で受信するようにした方がいいだろう。