SerialPortInterface.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Runtime.InteropServices;
  4. using AOT;
  5. using UnityEngine;
  6. using UnityEngine.Events;
  7. using System.Threading;
  8. namespace MySerialPortInterface
  9. {
  10. [System.Serializable]
  11. public class SerialPortSystemEventObject : UnityEngine.Events.UnityEvent<SerialPortInterface, string> { }
  12. public class SerialPortInterface : MonoBehaviour
  13. {
  14. private const string SERIALPORTAPI = "com/example/serialport/serialport_api";
  15. //java对象
  16. private AndroidJavaObject serialPortApiObj = null;
  17. public string ComPort = "/dev/ttyS0";
  18. public int BaudRate = 115200;
  19. public string DeviceName = "ttyS0";
  20. int serialPortId = -1;
  21. // 使用 UnityEvent 使事件公开在 Inspector 中
  22. [System.Serializable]
  23. public class SerialPortUpdateEvent : UnityEvent<byte[], int> { }
  24. [HideInInspector]
  25. public SerialPortSystemEventObject SystemEventObject = new SerialPortSystemEventObject();
  26. // 在 Inspector 中可以赋值的事件
  27. public SerialPortUpdateEvent OnSerialPortUpdateEvent;
  28. private SynchronizationContext _syncContext;
  29. void Awake()
  30. {
  31. // 获取主线程的 SynchronizationContext
  32. _syncContext = SynchronizationContext.Current;
  33. try
  34. {
  35. // 创建 serialPortApi 对象
  36. serialPortApiObj = new AndroidJavaObject(SERIALPORTAPI);
  37. }
  38. catch (Exception e)
  39. {
  40. Debug.LogError("UVC_MANAGER Exception: " + e.Message);
  41. }
  42. }
  43. void Start()
  44. {
  45. //初始化端口
  46. //Open();
  47. }
  48. public void Open()
  49. {
  50. //如果已经注册过了
  51. if (serialPortId != -1) return;
  52. serialPortId = serialPortApiObj.Call<int>("initSerialPort", ComPort, BaudRate);
  53. if (serialPortId != -1)
  54. {
  55. Debug.Log("initSerialPort 初始化成功!");
  56. if (SystemEventObject != null)
  57. SystemEventObject.Invoke(this, "OPENED");
  58. //注册c回调
  59. Add(this);
  60. }
  61. else
  62. {
  63. Debug.LogError("initSerialPort 初始化失败!");
  64. if (SystemEventObject != null)
  65. SystemEventObject.Invoke(this, "OPEN_ERROR");
  66. }
  67. //SendTest();
  68. }
  69. private void OnDestroy()
  70. {
  71. if (Application.platform == RuntimePlatform.Android) {
  72. Remove(this);
  73. Close();
  74. }
  75. }
  76. public void SendTest()
  77. {
  78. serialPortApiObj.Call("SendTest");
  79. }
  80. public void Close()
  81. {
  82. serialPortApiObj.Call("closeSerialPort");
  83. if (SystemEventObject != null)
  84. SystemEventObject.Invoke(this, "CLOSED");
  85. serialPortId = -1;
  86. }
  87. public void Write(byte[] data)
  88. {
  89. //
  90. // Debug.Log("Unity调用Android的sendSerialPort方法");
  91. sbyte[] mySByte = new sbyte[data.Length];
  92. for (int i = 0; i < data.Length; i++)
  93. {
  94. if (data[i] > 127)
  95. mySByte[i] = (sbyte)(data[i] - 256);
  96. else
  97. mySByte[i] = (sbyte)data[i];
  98. }
  99. serialPortApiObj.Call("sendSerialPort", new object[] { mySByte, data.Length });
  100. Debug.Log($"[SerialPortInterface]Write:{ComPort}, data: {BitConverter.ToString(data)},length: {data.Length}");
  101. }
  102. public void OnSerialPortUpdate(byte[] buffer, int size)
  103. {
  104. // 处理数据
  105. Debug.Log($"[SerialPortInterface]回调:{ComPort}, data: {BitConverter.ToString(buffer)},length: {buffer.Length} ,size: {size}");
  106. // 触发事件
  107. OnSerialPortUpdateEvent?.Invoke(buffer, size);
  108. }
  109. [UnmanagedFunctionPointer(CallingConvention.StdCall)]
  110. public delegate void SerialPortUpdateDelegate(Int32 id, IntPtr buffer, int size);
  111. [DllImport("SerialPortCustom")]
  112. private static extern void RegisterSerialPortUpdateCallback(Int32 id, SerialPortUpdateDelegate callback);
  113. [DllImport("SerialPortCustom")]
  114. private static extern void UnregisterSerialPortUpdateCallback(Int32 id, SerialPortUpdateDelegate callback);
  115. //记录MyUVCInterface
  116. private static Dictionary<Int32, SerialPortInterface> mSerialPortInterfaces = new Dictionary<Int32, SerialPortInterface>();
  117. private static SerialPortUpdateDelegate serialPortUpdateDelegate;
  118. //注册回调事件
  119. public static void Add(SerialPortInterface mySerialPortInterface)
  120. {
  121. Int32 id = mySerialPortInterface.serialPortId;
  122. serialPortUpdateDelegate = new SerialPortUpdateDelegate(SerialPortUpdateHandler);
  123. mSerialPortInterfaces.Add(id, mySerialPortInterface);
  124. RegisterSerialPortUpdateCallback(id, serialPortUpdateDelegate);
  125. }
  126. //移除回调事件
  127. public static void Remove(SerialPortInterface mySerialPortInterface)
  128. {
  129. Int32 id = mySerialPortInterface.GetHashCode();
  130. UnregisterSerialPortUpdateCallback(id, serialPortUpdateDelegate);
  131. mSerialPortInterfaces.Remove(id);
  132. }
  133. //数据更新时候回调
  134. [MonoPInvokeCallback(typeof(SerialPortUpdateDelegate))]
  135. // 修改回调处理
  136. private static void SerialPortUpdateHandler(Int32 id, IntPtr buffer, int size)
  137. {
  138. byte[] managedBuffer = new byte[size];
  139. Marshal.Copy(buffer, managedBuffer, 0, size);
  140. // Debug.Log($"Received buffer in C#: {BitConverter.ToString(managedBuffer)}, size: {size}, buffer.Length: {managedBuffer.Length}");
  141. var mySerialPortInterface = mSerialPortInterfaces.ContainsKey(id) ? mSerialPortInterfaces[id] : null;
  142. // 使用 SynchronizationContext 将操作调度到主线程
  143. mySerialPortInterface?.EnqueueOnMainThread(() => mySerialPortInterface.OnSerialPortUpdate(managedBuffer, size));
  144. }
  145. // 调度操作到主线程
  146. public void EnqueueOnMainThread(Action action)
  147. {
  148. // 如果 _syncContext 为 null,可能是没有正确初始化,可以检查并加以处理
  149. if (_syncContext != null)
  150. {
  151. _syncContext.Post(_ => action(), null);
  152. }
  153. else
  154. {
  155. // 如果找不到 SynchronizationContext,使用 Unity 的主线程调度
  156. UnityMainThreadDispatcher.Instance().Enqueue(action);
  157. }
  158. }
  159. }
  160. }