slambb 10 ماه پیش
والد
کامیت
61e9919455

+ 8 - 0
Assets/SerialPortCustom.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: c1b8a052b5b2a5248bbdb1f995f881c2
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/SerialPortCustom/Plugins.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 0b86f80795f43df44be87944b5bc7bce
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/SerialPortCustom/Plugins/Android.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 5343da4ef8334a546a0e48f6c4a35dcd
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/SerialPortCustom/Plugins/Android/arm64-v8a.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: a85644e12e4cf6d4daad53dbf6b35eb0
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Assets/SerialPortCustom/Plugins/Android/arm64-v8a/libSerialPortCustom.so


+ 70 - 0
Assets/SerialPortCustom/Plugins/Android/arm64-v8a/libSerialPortCustom.so.meta

@@ -0,0 +1,70 @@
+fileFormatVersion: 2
+guid: ce41861f8db350045a6ce05c24817a6b
+PluginImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  iconMap: {}
+  executionOrder: {}
+  defineConstraints: []
+  isPreloaded: 0
+  isOverridable: 0
+  isExplicitlyReferenced: 0
+  validateReferences: 1
+  platformData:
+  - first:
+      : Any
+    second:
+      enabled: 0
+      settings:
+        Exclude Android: 0
+        Exclude Editor: 0
+        Exclude Linux64: 0
+        Exclude OSXUniversal: 0
+        Exclude Win: 0
+        Exclude Win64: 0
+  - first:
+      Android: Android
+    second:
+      enabled: 1
+      settings:
+        CPU: ARM64
+  - first:
+      Any: 
+    second:
+      enabled: 1
+      settings: {}
+  - first:
+      Editor: Editor
+    second:
+      enabled: 1
+      settings:
+        CPU: ARM64
+        DefaultValueInitialized: true
+        OS: OSX
+  - first:
+      Standalone: Linux64
+    second:
+      enabled: 1
+      settings:
+        CPU: None
+  - first:
+      Standalone: OSXUniversal
+    second:
+      enabled: 1
+      settings:
+        CPU: ARM64
+  - first:
+      Standalone: Win
+    second:
+      enabled: 1
+      settings:
+        CPU: None
+  - first:
+      Standalone: Win64
+    second:
+      enabled: 1
+      settings:
+        CPU: None
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/SerialPortCustom/Plugins/Android/armeabi-v7a.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: a3a8d9c2e5908d94ca8fd5a4c92dc580
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Assets/SerialPortCustom/Plugins/Android/armeabi-v7a/libSerialPortCustom.so


+ 27 - 0
Assets/SerialPortCustom/Plugins/Android/armeabi-v7a/libSerialPortCustom.so.meta

@@ -0,0 +1,27 @@
+fileFormatVersion: 2
+guid: 71a14ff9cba317543939ff5a361c6ff3
+PluginImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  iconMap: {}
+  executionOrder: {}
+  defineConstraints: []
+  isPreloaded: 0
+  isOverridable: 0
+  isExplicitlyReferenced: 0
+  validateReferences: 1
+  platformData:
+  - first:
+      Any: 
+    second:
+      enabled: 1
+      settings: {}
+  - first:
+      Editor: Editor
+    second:
+      enabled: 0
+      settings:
+        DefaultValueInitialized: true
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Assets/SerialPortCustom/Plugins/Android/serialport-release.aar


+ 32 - 0
Assets/SerialPortCustom/Plugins/Android/serialport-release.aar.meta

@@ -0,0 +1,32 @@
+fileFormatVersion: 2
+guid: e7dca7e0234f4f4429efbdbd6c80f67b
+PluginImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  iconMap: {}
+  executionOrder: {}
+  defineConstraints: []
+  isPreloaded: 0
+  isOverridable: 0
+  isExplicitlyReferenced: 0
+  validateReferences: 1
+  platformData:
+  - first:
+      Android: Android
+    second:
+      enabled: 1
+      settings: {}
+  - first:
+      Any: 
+    second:
+      enabled: 0
+      settings: {}
+  - first:
+      Editor: Editor
+    second:
+      enabled: 0
+      settings:
+        DefaultValueInitialized: true
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/SerialPortCustom/Scripts.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: c1514e74a3bd58141aa903cc6527c508
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 195 - 0
Assets/SerialPortCustom/Scripts/SerialPortInterface.cs

@@ -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);
+			}
+		}
+	}
+
+}
+
+

+ 11 - 0
Assets/SerialPortCustom/Scripts/SerialPortInterface.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 4e186f98ccbe3b348b29eded4478baad
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 36 - 0
Assets/SerialPortCustom/Scripts/UnityMainThreadDispatcher.cs

@@ -0,0 +1,36 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+public class UnityMainThreadDispatcher : MonoBehaviour
+{
+    private static readonly Queue<System.Action> _executionQueue = new Queue<System.Action>();
+
+    private static UnityMainThreadDispatcher _instance;
+    public static UnityMainThreadDispatcher Instance()
+    {
+        if (_instance == null)
+        {
+            GameObject go = new GameObject("MainThreadDispatcher");
+            _instance = go.AddComponent<UnityMainThreadDispatcher>();
+            DontDestroyOnLoad(go);
+        }
+        return _instance;
+    }
+
+    public void Enqueue(System.Action action)
+    {
+        lock (_executionQueue)
+        {
+            _executionQueue.Enqueue(action);
+        }
+    }
+
+    private void Update()
+    {
+        while (_executionQueue.Count > 0)
+        {
+            var action = _executionQueue.Dequeue();
+            action();
+        }
+    }
+}

+ 11 - 0
Assets/SerialPortCustom/Scripts/UnityMainThreadDispatcher.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c0e11a6c0d1891849898cc3981273237
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: