2026-01-06 19:24:17 +08:00

541 lines
16 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data.SqlTypes;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
//using UnityEditor.PackageManager.UI;
using UnityEngine;
using UnityThreadingUtils;
using ZXKFramework;
public class SensorManager : MonoBehaviour /*MonoSingleton<SensorManager>*/
{
#region
//public enum DataType
//{
// 字符串,
// 字节流,
//}
//#region 串口参数,主要修改串口名与波特率
//[Header("串口名")]
//public string portName = "COM10";
//[Header("波特率")]
//public int baudRate = 115200;
//[Header("奇偶校验")]
//private Parity parity = Parity.None;
//[Header("数据位")]
//private int dataBits = 8;
//[Header("停止位")]
//private StopBits stopBits = StopBits.One;
//SerialPort sp = null;
//Thread dataReceiveThread;
//[Header("接收数据格式")]
//public DataType dataType;
//#endregion
//private Dictionary<string, Sensor> allSensor = new Dictionary<string, Sensor>();
//StringBuilder sb = new StringBuilder();
//private void Start()
//{
// sp = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
// foreach (Sensor s in GetComponentsInChildren<Sensor>())
// {
// allSensor.TryAdd(s.GetType().Name, s);
// }
// switch (dataType)
// {
// case DataType.字节流:
// dataReceiveThread = new Thread(new ThreadStart(DataReceiveBytesThread));
// break;
// case DataType.字符串:
// dataReceiveThread = new Thread(new ThreadStart(DataReceiveStrThread));
// break;
// }
// OpenPort();
//}
///// <summary>
///// 接收字节流
///// </summary>
//private void DataReceiveBytesThread()
//{
// while (true)
// {
// if (sp != null && sp.IsOpen)
// {
// try
// {
// if (sp.BytesToRead > 0)
// {
// byte[] buffer = new byte[sp.BytesToRead];
// sp.Read(buffer, 0, sp.BytesToRead);
// string receivedData = Encoding.Default.GetString(buffer);
// //Debug.Log(receivedData);
// UnityMainThreadDispatcher.Instance().Enqueue(() =>
// {
// foreach (var s in allSensor)
// {
// s.Value.ReceiveData(receivedData);
// }
// });
// }
// }
// catch (Exception)
// {
// Debug.Log("消息接收失败");
// }
// }
// Thread.Sleep(20);
// }
//}
///// <summary>
///// 接收字符串
///// </summary>
//private void DataReceiveStrThread()
//{
// while (true)
// {
// if (sp != null && sp.IsOpen)
// {
// try
// {
// if (sp.BytesToRead > 0)
// {
// sb.Append(sp.ReadExisting());
// //this.ColorLog(GDLog.LogColorState.Blue, sp.ReadLine());
// UnityMainThreadDispatcher.Instance().Enqueue(() =>
// {
// foreach (var s in allSensor)
// {
// s.Value.ReceiveData(sb.ToString());
// }
// sb.Clear();
// });
// }
// }
// catch (Exception)
// {
// Debug.Log("消息接收失败");
// }
// }
// Thread.Sleep(20);
// }
//}
///// <summary>
///// 发送消息
///// </summary>
///// <param name="dataSend"></param>
//public void SendFunction(string str)
//{
// try
// {
// byte[] dataSend = Encoding.ASCII.GetBytes(str);
// if (sp != null && sp.IsOpen)
// {
// if (dataSend != null && dataSend.Length > 0)
// {
// sp.Write(dataSend, 0, dataSend.Length);
// Debug.Log("发送消息成功:" + str);
// }
// }
// }
// catch (Exception)
// {
// Debug.Log("发送消息失败:" + str);
// }
//}
////获取指定传感器
//public T GetSensor<T>() where T : Sensor
//{
// try
// {
// string name = typeof(T).Name;
// if (!allSensor.ContainsKey(name))
// {
// allSensor.TryAdd(name, GetComponentInChildren<T>());
// allSensor[name].Init(this);
// }
// //Debug.Log("传感器获取成功");
// return allSensor[name] as T;
// }
// catch (Exception)
// {
// Debug.Log("传感器获取失败");
// return null;
// }
//}
//#region 串口开启关闭相关
////打开串口
//public void OpenPort()
//{
// try
// {
// if (!sp.IsOpen)
// {
// sp.Open();
// dataReceiveThread.Start();
// Debug.Log("串口打开成功");
// }
// }
// catch (Exception)
// {
// Debug.Log("串口打开失败");
// }
//}
////关闭串口
//public void ClosePort()
//{
// try
// {
// sp.Close();
// dataReceiveThread.Abort();
// Debug.Log("串口关闭");
// }
// catch (Exception)
// {
// Debug.Log("串口关闭失败");
// }
//}
//#endregion
//#region Unity 退出相关
//private void OnApplicationQuit()
//{
// ClosePort();
//}
//private void OnDisable()
//{
// this.Log("为什么关闭了:" + gameObject.name);
// ClosePort();
//}
//#endregion
#endregion
public enum DataType
{
,
,
}
#region
//[Header("端口名(多串口时自动获取)")]
//public string portName = "COM3";
[Header("波特率")]
public int baudRate = 115200;
[Header("奇偶校验")]
private Parity parity = Parity.None;
[Header("数据位")]
private int dataBits = 8;
[Header("停止位")]
private StopBits stopBits = StopBits.One;
[Header("接收数据格式")]
public DataType dataType;
#endregion
private Dictionary<string, Sensor> allSensor = new Dictionary<string, Sensor>();
List<string> COMPorts = new List<string>();
List<SerialPort> serialPorts = new List<SerialPort>();
List<Thread> dataReceiveThreads = new List<Thread>();
// 线程运行状态标志(每个串口对应一个标志)
private bool[] isThreadRunning;
private void Start()
{
COMPorts = GetAllWindowsCOMPorts().ToList();
// 初始化所有串口
for (int i = 0; i < COMPorts.Count; i++)
{
SerialPort sp = new SerialPort(COMPorts[i], baudRate, parity, dataBits, stopBits);
serialPorts.Add(sp);
}
// 初始化传感器
foreach (Sensor s in GetComponentsInChildren<Sensor>())
{
allSensor.TryAdd(s.GetType().Name, s);
}
// 初始化线程(绑定具体串口索引,避免索引混乱)
isThreadRunning = new bool[COMPorts.Count]; // 初始化标志位数组
for (int i = 0; i < COMPorts.Count; i++)
{
isThreadRunning[i] = true; // 默认启动线程
int portIndex = i; // 捕获当前索引(避免闭包陷阱)
Thread thread;
// 根据数据类型创建对应线程,并绑定端口索引
switch (dataType)
{
case DataType.:
thread = new Thread(() => DataReceiveBytesThread(portIndex));
break;
case DataType.:
thread = new Thread(() => DataReceiveStrThread(portIndex));
break;
default:
thread = null;
break;
}
if (thread != null)
{
dataReceiveThreads.Add(thread);
}
}
OpenPort();
}
/// <summary>
/// 字节流接收线程(绑定具体串口索引)
/// </summary>
private void DataReceiveBytesThread(int portIndex)
{
// 循环条件线程标志位为true且索引有效
while (isThreadRunning[portIndex] && portIndex < serialPorts.Count)
{
SerialPort sp = serialPorts[portIndex];
if (sp != null && sp.IsOpen)
{
try
{
if (sp.BytesToRead > 0)
{
byte[] buffer = new byte[sp.BytesToRead];
sp.Read(buffer, 0, buffer.Length);
string receivedData = Encoding.Default.GetString(buffer);
//Debug.Log($"串口 {sp.PortName} 接收字节流:{receivedData}");
// 主线程处理数据
UnityMainThreadDispatcher.Instance().Enqueue(() =>
{
foreach (var pair in allSensor)
{
pair.Value.ReceiveData(receivedData, sp);
}
});
}
}
catch (Exception ex)
{
Debug.Log($"串口 {sp.PortName} 字节流接收错误:{ex.Message}");
}
}
Thread.Sleep(10); // 降低CPU占用
}
}
/// <summary>
/// 字符串接收线程(绑定具体串口索引)
/// </summary>
private void DataReceiveStrThread(int portIndex)
{
// 每个线程独立的StringBuilder避免多线程冲突
StringBuilder sb = new StringBuilder();
// 循环条件线程标志位为true且索引有效
while (isThreadRunning[portIndex] && portIndex < serialPorts.Count)
{
SerialPort sp = serialPorts[portIndex];
if (sp != null && sp.IsOpen)
{
try
{
if (sp.BytesToRead > 0)
{
sb.Append(sp.ReadExisting());
string receivedData = sb.ToString();
UnityMainThreadDispatcher.Instance().Enqueue(() =>
{
foreach (var s in allSensor)
{
try
{
//Debug.LogError(s.Value.name);
s.Value.ReceiveData(receivedData, sp);
}
catch (Exception ex)
{
Debug.LogError($"传感器处理数据错误:{ex.Message}");
}
}
sb.Clear();
});
}
}
catch (Exception ex)
{
Debug.Log($"串口 {sp.PortName} 字符串接收错误:{ex.Message}");
}
}
Thread.Sleep(10); // 降低CPU占用
}
}
/// <summary>
/// 发送数据到所有已打开的串口
/// </summary>
public void SendFunction(string str)
{
try
{
byte[] dataSend = Encoding.ASCII.GetBytes(str);
for (int i = 0; i < serialPorts.Count; i++)
{
SerialPort sp = serialPorts[i];
if (sp != null && sp.IsOpen && dataSend != null && dataSend.Length > 0)
{
sp.Write(dataSend, 0, dataSend.Length);
Debug.Log($"向串口 {sp.PortName} 发送成功:{str}");
}
}
}
catch (Exception ex)
{
Debug.Log($"发送数据失败:{ex.Message},数据:{str}");
}
}
/// <summary>
/// 获取指定类型的传感器
/// </summary>
public T GetSensor<T>() where T : Sensor
{
try
{
string name = typeof(T).Name;
if (!allSensor.ContainsKey(name))
{
T sensor = GetComponentInChildren<T>();
if (sensor != null)
{
allSensor.TryAdd(name, sensor);
sensor.Init(this);
}
}
//Debug.Log($"获取传感器 {typeof(T).Name} 成功");
return allSensor[name] as T;
}
catch (Exception ex)
{
Debug.Log($"获取传感器 {typeof(T).Name} 失败:{ex.Message}");
return null;
}
}
#region
/// <summary>
/// 打开所有串口并启动对应线程
/// </summary>
public void OpenPort()
{
try
{
Debug.Log("正在打开串口...");
for (int i = 0; i < serialPorts.Count; i++)
{
SerialPort sp = serialPorts[i];
if (sp != null && !sp.IsOpen)
{
sp.Open();
Debug.Log($"串口 {sp.PortName} 打开成功");
}
// 启动对应线程(检查索引有效性)
if (i < dataReceiveThreads.Count && dataReceiveThreads[i] != null && !dataReceiveThreads[i].IsAlive)
{
dataReceiveThreads[i].Start();
}
}
}
catch (Exception ex)
{
Debug.Log($"串口打开失败:{ex.ToString()}");
}
}
/// <summary>
/// 关闭所有串口并停止线程安全终止避免Abort
/// </summary>
public void ClosePort()
{
for (int i = 0; i < serialPorts.Count; i++)
{
// 1. 停止线程(通过标志位)
if (i < isThreadRunning.Length)
{
isThreadRunning[i] = false; // 通知线程退出循环
}
// 等待线程终止最多1秒
if (i < dataReceiveThreads.Count && dataReceiveThreads[i] != null && dataReceiveThreads[i].IsAlive)
{
dataReceiveThreads[i].Join(1000);
dataReceiveThreads[i] = null;
}
// 2. 关闭串口
SerialPort sp = serialPorts[i];
if (sp != null && sp.IsOpen)
{
try
{
sp.Close();
Debug.Log($"串口 {sp.PortName} 关闭成功");
}
catch (Exception ex)
{
Debug.Log($"串口 {sp.PortName} 关闭失败:{ex.ToString()}");
}
serialPorts[i] = null;
}
}
}
#endregion
#region Unity
private void OnApplicationQuit()
{
ClosePort();
}
private void OnDisable()
{
ClosePort();
}
/// <summary>
/// 获取所有Windows串口并排序
/// </summary>
public string[] GetAllWindowsCOMPorts()
{
try
{
var ports = SerialPort.GetPortNames();
// 按COM端口号排序
Array.Sort(ports, (a, b) =>
{
if (int.TryParse(a.Replace("COM", ""), out int numA) &&
int.TryParse(b.Replace("COM", ""), out int numB))
{
return numA.CompareTo(numB);
}
return string.Compare(a, b);
});
return ports;
}
catch (Exception e)
{
Debug.LogError($"获取串口失败:{e.Message}\n{e.StackTrace}");
return Array.Empty<string>();
}
}
#endregion
}