2026-04-14 14:34:04 +08:00

229 lines
6.3 KiB
C#

// SensorManager.cs
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Text;
using System.Threading;
using UnityEngine;
using UnityThreadingUtils;
public class SensorManager : MonoBehaviour
{
public enum DataType
{
,
,
}
#region
[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
// 1. 修改:使用列表存储多个串口及相关线程
private List<SerialPort> serialPorts = new List<SerialPort>();
private List<Thread> receiveThreads = new List<Thread>();
private Dictionary<string, Sensor> allSensor = new Dictionary<string, Sensor>();
public GameObject sensorView;
private void Start()
{
// 1. 自动查找并连接所有可用端口
List<string> connectedPorts = AutoConnectAll();
if (connectedPorts.Count == 0)
{
Debug.LogError("没有找到可用的串口设备。");
return;
}
// 2. 初始化传感器
foreach (Sensor s in GetComponentsInChildren<Sensor>())
{
allSensor.TryAdd(s.GetType().Name, s);
s.Init(this); // 立即初始化
}
}
/// <summary>
/// 自动查找并连接所有可用的串口
/// </summary>
/// <returns>成功连接的端口名称列表</returns>
private List<string> AutoConnectAll()
{
List<string> connectedPorts = new List<string>();
string[] portNames = SerialPort.GetPortNames();
if (portNames.Length == 0)
{
Debug.LogWarning("未检测到任何串口硬件。");
return connectedPorts;
}
foreach (string name in portNames)
{
try
{
SerialPort sp = new SerialPort(name, baudRate, parity, dataBits, stopBits);
sp.ReadTimeout = 1000;
sp.Open();
// 连接成功,加入列表
serialPorts.Add(sp);
connectedPorts.Add(name);
Debug.Log($"成功连接设备: {name}");
// 2. 为每一个端口启动独立的接收线程
Thread thread = new Thread(() => DataReceiveThread(sp));
thread.IsBackground = true;
thread.Start();
receiveThreads.Add(thread);
}
catch (Exception e)
{
Debug.LogWarning($"端口 {name} 连接失败: {e.Message}");
}
}
return connectedPorts;
}
/// <summary>
/// 通用的数据接收线程方法(每个串口一个)
/// </summary>
/// <param name="port">当前处理的串口对象</param>
private void DataReceiveThread(SerialPort port)
{
while (true)
{
// 检查端口是否还有效
if (port == null || !port.IsOpen) break;
try
{
if (port.BytesToRead > 0)
{
string receivedData = "";
// 根据格式解析数据
if (dataType == DataType.)
{
byte[] buffer = new byte[port.BytesToRead];
port.Read(buffer, 0, buffer.Length);
receivedData = Encoding.Default.GetString(buffer);
}
else // 字符串
{
receivedData = port.ReadExisting();
}
// 使用调度器将任务抛回主线程
UnityMainThreadDispatcher.Instance().Enqueue(() =>
{
// 3. 关键:将数据和端口名一起分发给所有传感器
// 你可以在这里写逻辑,比如只处理特定端口的数据,或者广播给所有
foreach (var sensor in allSensor.Values)
{
sensor.ReceiveData(receivedData, port.PortName);
}
});
}
}
catch (TimeoutException)
{
// 超时正常,继续循环
continue;
}
catch (Exception ex)
{
Debug.Log($"读取 {port.PortName} 时出错: {ex.Message}");
break; // 读取出错,退出线程循环
}
Thread.Sleep(20); // 防止CPU占用过高
}
}
/// <summary>
/// 发送数据(广播模式:向所有打开的端口发送)
/// </summary>
/// <param name="str"></param>
public void SendFunction(string str)
{
if (string.IsNullOrEmpty(str)) return;
byte[] dataSend = Encoding.ASCII.GetBytes(str);
// 遍历所有串口,向每一个发送数据
foreach (var sp in serialPorts)
{
try
{
if (sp != null && sp.IsOpen)
{
sp.Write(dataSend, 0, dataSend.Length);
Debug.Log($"向 {sp.PortName} 发送: {str}");
}
}
catch (Exception e)
{
Debug.LogError($"发送失败 {sp?.PortName}: {e.Message}");
}
}
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
if (sensorView.activeSelf)
{
sensorView.SetActive(false);
}
else
{
sensorView.SetActive(true);
}
}
}
// 获取传感器逻辑保持不变
public T GetSensor<T>() where T : Sensor
{
string name = typeof(T).Name;
if (!allSensor.ContainsKey(name))
{
T comp = GetComponentInChildren<T>();
if (comp != null)
{
allSensor[name] = comp;
comp.Init(this);
}
}
return allSensor[name] as T;
}
// 退出时关闭所有端口
private void OnApplicationQuit()
{
foreach (var sp in serialPorts)
{
try
{
if (sp != null && sp.IsOpen) sp.Close();
sp?.Dispose();
}
catch (Exception e) { Debug.Log(e.Message); }
}
serialPorts.Clear();
receiveThreads.Clear();
}
}