using System; using System.Collections; using System.Collections.Generic; using System.Threading; using System.IO.Ports; using System.Linq; using UnityEngine; public class Serial : MonoBehaviour { const byte CMD_GET_SYNC_BOARD_VER = 0xa0; const byte CMD_NEXT_READ = 0x72; const byte CMD_GET_UNIT_BOARD_VER = 0xa8; const byte CMD_MYSTERY1 = 0xa2; const byte CMD_MYSTERY2 = 0x94; const byte CMD_START_AUTO_SCAN = 0xc9; const byte CMD_BEGIN_WRITE = 0x77; const byte CMD_NEXT_WRITE = 0x20; private Thread _touchThread; private Queue _touchQueue; static SerialPort ComL = new SerialPort ("COM5", 115200); static SerialPort ComR = new SerialPort ("COM6", 115200); byte inByte; string SYNC_BOARD_VER = "190523"; string UNIT_BOARD_VER = "190514"; string read1 = " 0 0 1 2 3 4 5 15 15 15 15 15 15 11 11 11"; string read2 = " 11 11 11 128 103 103 115 138 127 103 105 111 126 113 95 100"; string read3 = " 101 115 98 86 76 67 68 48 117 0 82 154 0 6 35 4"; byte[] SettingData_160 = new byte[8]; byte[] SettingData_162 = new byte[7]; byte[] SettingData_148 = new byte[7]; byte[] SettingData_201 = new byte[7]; static byte[] TouchPackL = new byte[36]; static byte[] TouchPackR = new byte[36]; bool StartUp = false; void Start() { try { ComL.Open(); ComR.Open(); } catch (Exception ex) { Console.WriteLine($"Failed to Open Serial Ports: {ex}"); } Debug.Log("Touch Serial Initializing.."); SetSettingData_160(); SetSettingData_201(); SetSettingData_162(); SetSettingData_148(); //Send touch update periodically to keep "read" alive _touchQueue = Queue.Synchronized(new Queue()); _touchThread = new Thread(TouchThreadLoop); InvokeRepeating("PingTouchThread", 0, 1); //Send touch updates whenever actual state changes to achieve desired update frequency without overloading ColliderToSerial.touchDidChange += PingTouchThread; } private void PingTouchThread() { _touchQueue.Enqueue(1); } private void TouchThreadLoop() { while(true) { if(_touchQueue.Count > 0) { _touchQueue.Dequeue(); SendTouchState(); } } } private void OnDestroy() { ComL.Close(); ComR.Close(); } void Update() { if(ComL.IsOpen) ReadHead(ComL, 0); if (ComR.IsOpen) ReadHead(ComR, 1); // if (Input.GetKeyDown(KeyCode.M)) //this is a touch test code // StartCoroutine(TouchTest(true)); if (Input.GetKeyDown(KeyCode.M) && StartUp) SendTouchState(); } private void SendTouchState() { if(StartUp) { Debug.Log("Sending Touch State"); // Debug.Log("Sending Left"); SendTouch(ComL, TouchPackL); // Debug.Log("Sending Right"); SendTouch(ComR, TouchPackR); } } private void FixedUpdate() { //SendTouchState(); } IEnumerator TouchTest(bool State) //this is a touch test code { for (int i = 0; i < 240; i++) { SetTouch(i, true); Debug.Log(i); yield return new WaitForSeconds(0.05f); SetTouch(i, false); yield return new WaitForSeconds(0.05f); } } void ReadHead(SerialPort Serial, int side) //Read head byte { if(Serial.BytesToRead > 0) { inByte = Convert.ToByte(Serial.ReadByte()); var data = Serial.ReadExisting(); SendResp(Serial, side, data); } } void SendResp(SerialPort Serial, int side, string data) { switch(inByte) { case CMD_GET_SYNC_BOARD_VER: //Response: cmd byte + sync board ver + checksum StartUp = false; List syncbytes = new List(); syncbytes.Add(inByte); syncbytes.AddRange(ByteHelper.ConvertStringToByteArray(SYNC_BOARD_VER)); byte syncCheckSum = (byte)44; syncbytes.Add(syncCheckSum); Serial.Write(syncbytes.ToArray(), 0, syncbytes.Count); Debug.Log($"GET SYNC BOARD VER {side}"); break; case CMD_NEXT_READ: //Response: corresponding read bytes + checksum StartUp = false; Debug.Log($"Side {side} NEXT READ {Convert.ToByte(data[2])}"); switch (Convert.ToByte(data[2])) { case 0x30: var bytes = ByteHelper.ConvertStringToByteArray(read1); bytes.Add(ByteHelper.CalCheckSum(bytes.ToArray(), bytes.Count)); Debug.Log("Read 1"); Serial.Write(bytes.ToArray(), 0, bytes.Count); break; case 0x31: var bytes2 = ByteHelper.ConvertStringToByteArray(read2); bytes2.Add(ByteHelper.CalCheckSum(bytes2.ToArray(), bytes2.Count)); Debug.Log("Read 2"); Serial.Write(bytes2.ToArray(), 0, bytes2.Count); break; case 0x33: var bytes3 = ByteHelper.ConvertStringToByteArray(read3); bytes3.Add(ByteHelper.CalCheckSum(bytes3.ToArray(), bytes3.Count)); Debug.Log("Read 3"); Serial.Write(bytes3.ToArray(), 0, bytes3.Count); break; default: Debug.Log("Extra Read"); break; } break; case CMD_GET_UNIT_BOARD_VER: //Response: cmd byte + sync board ver bytes + 'L'/'R' based on side + unit board ver bytes x6 + checksum StartUp = false; List unitBytes = new List(); byte sideByte = (side == 0 ? Convert.ToByte('R') : Convert.ToByte('L')); byte unitCheckSum = (side == 0 ? (byte)118 : (byte)104); unitBytes.Add(inByte); unitBytes.AddRange(ByteHelper.ConvertStringToByteArray(SYNC_BOARD_VER)); unitBytes.Add(sideByte); for (int i = 0; i < 6; i++) unitBytes.AddRange(ByteHelper.ConvertStringToByteArray(UNIT_BOARD_VER)); unitBytes.Add(unitCheckSum); Serial.Write(unitBytes.ToArray(), 0, unitBytes.Count); Debug.Log($"GET UNIT BOARD VER {side}"); break; case CMD_MYSTERY1: StartUp = false; Serial.Write(SettingData_162, 0, 3); Debug.Log($"MYSTERY 1 SIDE {side}"); break; case CMD_MYSTERY2: StartUp = false; Serial.Write(SettingData_148, 0, 3); Debug.Log($"MYSTERY 2 SIDE {side}"); break; case CMD_START_AUTO_SCAN: Serial.Write(SettingData_201.ToArray(), 0, 3); Debug.Log($"START AUTO SCAN SIDE {side}"); StartUp = true; if (!_touchThread.IsAlive) _touchThread.Start(); break; case CMD_BEGIN_WRITE: // Debug.Log($"Begin Write For Side {side}"); break; case CMD_NEXT_WRITE: // Debug.Log($"Continue Write For Side {side}"); break; case 154: StartUp = false; Debug.Log("BAD"); break; } } byte[] GetTouchPack(byte[] Pack) //convert touch to right format for game { Pack[0] = 129; Pack[34] = Pack[34]++; Pack[35] = 128; Pack[35] = ByteHelper.CalCheckSum(Pack, 36); if (Pack[34] > 127) Pack[34] = 0; return Pack; } void SendTouch(SerialPort Serial, byte[] Pack) //Send touch data { if (StartUp) { // Debug.Log($"Pack {string.Join(" ", Pack)}"); var output = GetTouchPack(Pack); // Debug.Log($"Output {string.Join(" ", output)}"); Serial.Write(output, 0, 36); } } public static void SetTouch(int Area, bool State) //set touch data 0-239 { Area +=1; if (Area < 121) { Area += (Area-1) / 5 * 3 + 7; ByteHelper.SetBit(TouchPackR, Area, State); } else if (Area >= 120) { Area -= 120; Area += (Area-1) / 5 * 3 + 7; ByteHelper.SetBit(TouchPackL, Area, State); } } void SetSettingData_160() { SettingData_160[0]=160; SettingData_160[1]=49; SettingData_160[2]=57; SettingData_160[3]=48; SettingData_160[4]=53; SettingData_160[5]=50; SettingData_160[6]=51; SettingData_160[7]=44; } void SetSettingData_201() { SettingData_201[0]=201; SettingData_201[1]=0; SettingData_201[2]=73; } void SetSettingData_162() { SettingData_162[0]=162; SettingData_162[1]=63; SettingData_162[2]=29; } void SetSettingData_148() { SettingData_148[0]=148; SettingData_148[1]=0; SettingData_148[2]=20; } } public static class ByteHelper { public static byte[] SetBit(this byte[] self, int index, bool value) { var bitArray = new BitArray(self); bitArray.Set(index, value); bitArray.CopyTo(self, 0); return self; } public static byte CalCheckSum(byte[] _PacketData,int PacketLength) { Byte _CheckSumByte = 0x00; for (int i = 0; i < PacketLength; i++) _CheckSumByte ^= _PacketData[i]; return _CheckSumByte; } public static List ConvertStringToByteArray(string data) { List tempList = new List(100); for(int i = 0; i < data.Length; i++) tempList.Add(Convert.ToByte(data[i])); return tempList; } }