|
|
@@ -0,0 +1,195 @@
|
|
|
+using System;
|
|
|
+using System.Collections.Generic;
|
|
|
+using System.Runtime.InteropServices;
|
|
|
+using AOT;
|
|
|
+using UnityEngine;
|
|
|
+using UnityEngine.Events;
|
|
|
+
|
|
|
+using System.Threading;
|
|
|
+
|
|
|
+namespace MySerialPortInterface
|
|
|
+{
|
|
|
+ [System.Serializable]
|
|
|
+ public class SerialPortSystemEventObject : UnityEngine.Events.UnityEvent<SerialPortInterface, string> { }
|
|
|
+
|
|
|
+ public class SerialPortInterface : MonoBehaviour
|
|
|
+ {
|
|
|
+ private const string SERIALPORTAPI = "com/example/serialport/serialport_api";
|
|
|
+ //java对象
|
|
|
+ private AndroidJavaObject serialPortApiObj = null;
|
|
|
+
|
|
|
+ public string ComPort = "/dev/ttyS0";
|
|
|
+ public int BaudRate = 115200;
|
|
|
+ public string DeviceName = "ttyS0";
|
|
|
+ int serialPortId = -1;
|
|
|
+
|
|
|
+ // 使用 UnityEvent 使事件公开在 Inspector 中
|
|
|
+ [System.Serializable]
|
|
|
+ public class SerialPortUpdateEvent : UnityEvent<byte[], int> { }
|
|
|
+
|
|
|
+ [HideInInspector]
|
|
|
+ public SerialPortSystemEventObject SystemEventObject = new SerialPortSystemEventObject();
|
|
|
+
|
|
|
+ // 在 Inspector 中可以赋值的事件
|
|
|
+ public SerialPortUpdateEvent OnSerialPortUpdateEvent;
|
|
|
+
|
|
|
+ private SynchronizationContext _syncContext;
|
|
|
+
|
|
|
+ void Awake()
|
|
|
+ {
|
|
|
+ // 获取主线程的 SynchronizationContext
|
|
|
+ _syncContext = SynchronizationContext.Current;
|
|
|
+
|
|
|
+ try
|
|
|
+ {
|
|
|
+ // 创建 serialPortApi 对象
|
|
|
+ serialPortApiObj = new AndroidJavaObject(SERIALPORTAPI);
|
|
|
+
|
|
|
+ }
|
|
|
+ catch (Exception e)
|
|
|
+ {
|
|
|
+ Debug.LogError("UVC_MANAGER Exception: " + e.Message);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ void Start()
|
|
|
+ {
|
|
|
+ //初始化端口
|
|
|
+ //Open();
|
|
|
+ }
|
|
|
+
|
|
|
+ public void Open()
|
|
|
+ {
|
|
|
+ //如果已经注册过了
|
|
|
+ if (serialPortId != -1) return;
|
|
|
+
|
|
|
+ serialPortId = serialPortApiObj.Call<int>("initSerialPort", ComPort, BaudRate);
|
|
|
+ if (serialPortId != -1)
|
|
|
+ {
|
|
|
+ Debug.Log("initSerialPort 初始化成功!");
|
|
|
+ if (SystemEventObject != null)
|
|
|
+ SystemEventObject.Invoke(this, "OPENED");
|
|
|
+
|
|
|
+ //注册c回调
|
|
|
+ Add(this);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ Debug.LogError("initSerialPort 初始化失败!");
|
|
|
+ if (SystemEventObject != null)
|
|
|
+ SystemEventObject.Invoke(this, "OPEN_ERROR");
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ //SendTest();
|
|
|
+ }
|
|
|
+ private void OnDestroy()
|
|
|
+ {
|
|
|
+ if (Application.platform == RuntimePlatform.Android) {
|
|
|
+ Remove(this);
|
|
|
+ Close();
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ public void SendTest()
|
|
|
+ {
|
|
|
+ serialPortApiObj.Call("SendTest");
|
|
|
+ }
|
|
|
+ public void Close()
|
|
|
+ {
|
|
|
+ serialPortApiObj.Call("closeSerialPort");
|
|
|
+
|
|
|
+ if (SystemEventObject != null)
|
|
|
+ SystemEventObject.Invoke(this, "CLOSED");
|
|
|
+
|
|
|
+ serialPortId = -1;
|
|
|
+ }
|
|
|
+ public void Write(byte[] data)
|
|
|
+ {
|
|
|
+ //
|
|
|
+ // Debug.Log("Unity调用Android的sendSerialPort方法");
|
|
|
+ sbyte[] mySByte = new sbyte[data.Length];
|
|
|
+
|
|
|
+ for (int i = 0; i < data.Length; i++)
|
|
|
+ {
|
|
|
+ if (data[i] > 127)
|
|
|
+ mySByte[i] = (sbyte)(data[i] - 256);
|
|
|
+ else
|
|
|
+ mySByte[i] = (sbyte)data[i];
|
|
|
+ }
|
|
|
+ serialPortApiObj.Call("sendSerialPort", new object[] { mySByte, data.Length });
|
|
|
+
|
|
|
+ Debug.Log($"[SerialPortInterface]Write:{ComPort}, data: {BitConverter.ToString(data)},length: {data.Length}");
|
|
|
+ }
|
|
|
+ public void OnSerialPortUpdate(byte[] buffer, int size)
|
|
|
+ {
|
|
|
+ // 处理数据
|
|
|
+ Debug.Log($"[SerialPortInterface]回调:{ComPort}, data: {BitConverter.ToString(buffer)},length: {buffer.Length} ,size: {size}");
|
|
|
+
|
|
|
+ // 触发事件
|
|
|
+ OnSerialPortUpdateEvent?.Invoke(buffer, size);
|
|
|
+ }
|
|
|
+
|
|
|
+ [UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
|
|
+ public delegate void SerialPortUpdateDelegate(Int32 id, IntPtr buffer, int size);
|
|
|
+
|
|
|
+ [DllImport("SerialPortCustom")]
|
|
|
+ private static extern void RegisterSerialPortUpdateCallback(Int32 id, SerialPortUpdateDelegate callback);
|
|
|
+
|
|
|
+ [DllImport("SerialPortCustom")]
|
|
|
+ private static extern void UnregisterSerialPortUpdateCallback(Int32 id, SerialPortUpdateDelegate callback);
|
|
|
+
|
|
|
+ //记录MyUVCInterface
|
|
|
+ private static Dictionary<Int32, SerialPortInterface> mSerialPortInterfaces = new Dictionary<Int32, SerialPortInterface>();
|
|
|
+
|
|
|
+ private static SerialPortUpdateDelegate serialPortUpdateDelegate;
|
|
|
+ //注册回调事件
|
|
|
+ public static void Add(SerialPortInterface mySerialPortInterface)
|
|
|
+ {
|
|
|
+ Int32 id = mySerialPortInterface.serialPortId;
|
|
|
+ serialPortUpdateDelegate = new SerialPortUpdateDelegate(SerialPortUpdateHandler);
|
|
|
+ mSerialPortInterfaces.Add(id, mySerialPortInterface);
|
|
|
+ RegisterSerialPortUpdateCallback(id, serialPortUpdateDelegate);
|
|
|
+ }
|
|
|
+ //移除回调事件
|
|
|
+ public static void Remove(SerialPortInterface mySerialPortInterface)
|
|
|
+ {
|
|
|
+ Int32 id = mySerialPortInterface.GetHashCode();
|
|
|
+ UnregisterSerialPortUpdateCallback(id, serialPortUpdateDelegate);
|
|
|
+ mSerialPortInterfaces.Remove(id);
|
|
|
+ }
|
|
|
+
|
|
|
+ //数据更新时候回调
|
|
|
+ [MonoPInvokeCallback(typeof(SerialPortUpdateDelegate))]
|
|
|
+ // 修改回调处理
|
|
|
+ private static void SerialPortUpdateHandler(Int32 id, IntPtr buffer, int size)
|
|
|
+ {
|
|
|
+ byte[] managedBuffer = new byte[size];
|
|
|
+ Marshal.Copy(buffer, managedBuffer, 0, size);
|
|
|
+ // Debug.Log($"Received buffer in C#: {BitConverter.ToString(managedBuffer)}, size: {size}, buffer.Length: {managedBuffer.Length}");
|
|
|
+ var mySerialPortInterface = mSerialPortInterfaces.ContainsKey(id) ? mSerialPortInterfaces[id] : null;
|
|
|
+
|
|
|
+ // 使用 SynchronizationContext 将操作调度到主线程
|
|
|
+ mySerialPortInterface?.EnqueueOnMainThread(() => mySerialPortInterface.OnSerialPortUpdate(managedBuffer, size));
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ // 调度操作到主线程
|
|
|
+ public void EnqueueOnMainThread(Action action)
|
|
|
+ {
|
|
|
+ // 如果 _syncContext 为 null,可能是没有正确初始化,可以检查并加以处理
|
|
|
+ if (_syncContext != null)
|
|
|
+ {
|
|
|
+ _syncContext.Post(_ => action(), null);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // 如果找不到 SynchronizationContext,使用 Unity 的主线程调度
|
|
|
+ UnityMainThreadDispatcher.Instance().Enqueue(action);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+
|