using System; using System.Net; using System.Net.Sockets; using System.Text; using LightGlue.Unity.Config; using UnityEngine; namespace LightGlue.Unity.Roma { /// /// OrangePi WiFi 图传控制(JSON over UDP,端口默认 8008)。 /// 参考:orangepizero2w/UDP_PROTOCOL.md、上位机参考.md /// public sealed class RomaWifiCameraControlClient : MonoBehaviour { [Header("Device")] [Tooltip("设备IP(从广播发现获取后写入)")] public string deviceIp = ""; [Tooltip("设备控制端口(固定 8008)")] public int deviceControlPort = 8008; [Header("Target (PC / Python)")] [Tooltip("图像流目标IP(通常是本机IP,不要用127.0.0.1)")] public string targetIp = ""; [Tooltip("图像流目标端口(Python WiFi 图传接收端口)。注意不要填 12345(广播端口)")] public int targetPort = 9000; [Header("Behavior")] [Tooltip("发现设备IP后,是否自动发送 config + stream_on")] public bool autoConfigAndStartOnDeviceDiscovered = false; [Tooltip("若启用自动下发,是否由 RomaNetworkConfigUIController 统一执行(确保使用 localTargetIpField)。建议保持 true。")] public bool autoConfigHandledByUi = true; [Tooltip("当 targetIp 为空或为 127.0.0.1 时,是否自动填充为本机网卡 IP(用于下发给设备)。")] public bool autoFillTargetIpIfEmpty = true; [Tooltip("发送 config 后等待的毫秒数(给设备一点应用时间)")] public int delayMsBetweenConfigAndOn = 30; public event Action OnConfigSent; public event Action OnStreamOnSent; private UdpClient _client; private IPEndPoint _deviceEp; private void OnEnable() { EnsureClient(); } private void OnDisable() { try { _client?.Close(); } catch { /* ignore */ } try { _client?.Dispose(); } catch { /* ignore */ } _client = null; _deviceEp = null; } public void BindDiscovery(RomaDeviceDiscoveryListener discovery) { if (discovery == null) return; discovery.OnDeviceIpDiscovered -= HandleDeviceDiscovered; discovery.OnDeviceIpDiscovered += HandleDeviceDiscovered; } private void HandleDeviceDiscovered(string ip) { deviceIp = ip; Debug.Log($"[RomaWiFiCtrl] Device discovered: {deviceIp}"); if (!autoConfigAndStartOnDeviceDiscovered) return; if (autoConfigHandledByUi) return; if (autoFillTargetIpIfEmpty && (string.IsNullOrWhiteSpace(targetIp) || targetIp.Trim() == "127.0.0.1")) { string localIp = NetworkConfig.GetLocalBindIp(); if (!string.IsNullOrWhiteSpace(localIp) && localIp != "127.0.0.1") { targetIp = localIp; Debug.Log($"[RomaWiFiCtrl] Auto filled targetIp: {targetIp}"); } else { Debug.LogWarning("[RomaWiFiCtrl] targetIp 为空/127.0.0.1,且未能获取有效本机IP;将不会自动下发 config,请在 UI 中填写本机IP 后再发送。"); return; } } ConfigStream(targetIp, targetPort); if (delayMsBetweenConfigAndOn > 0) { Invoke(nameof(StartStream), delayMsBetweenConfigAndOn / 1000f); } else { StartStream(); } } public void ConfigStream(string newTargetIp, int newTargetPort) { // 允许在配置时自动补齐本机IP,避免 Validate 直接失败导致用户误以为“没发送” if (autoFillTargetIpIfEmpty && (string.IsNullOrWhiteSpace(targetIp) || targetIp.Trim() == "127.0.0.1")) { string localIp = NetworkConfig.GetLocalBindIp(); if (!string.IsNullOrWhiteSpace(localIp) && localIp != "127.0.0.1") targetIp = localIp; } if (!Validate()) return; if (!string.IsNullOrWhiteSpace(newTargetIp)) targetIp = newTargetIp.Trim(); if (newTargetPort > 0) targetPort = newTargetPort; string json = $"{{\"type\":\"config\",\"data\":{{\"target_ip\":\"{targetIp}\",\"target_port\":{targetPort}}}}}"; SendJson(json); Debug.Log($"[RomaWiFiCtrl] Sent config: target={targetIp}:{targetPort}"); OnConfigSent?.Invoke(targetIp, targetPort); } public void StartStream() { if (!Validate()) return; SendJson("{\"type\":\"stream_on\",\"data\":{}}"); Debug.Log("[RomaWiFiCtrl] Sent stream_on"); OnStreamOnSent?.Invoke(); } public void StopStream() { if (!Validate()) return; SendJson("{\"type\":\"stream_off\",\"data\":{}}"); Debug.Log("[RomaWiFiCtrl] Sent stream_off"); } private void SendJson(string json) { EnsureClient(); if (_client == null) return; try { _deviceEp = new IPEndPoint(IPAddress.Parse(deviceIp), deviceControlPort); byte[] payload = Encoding.UTF8.GetBytes(json); _client.Send(payload, payload.Length, _deviceEp); } catch (Exception ex) { Debug.LogWarning($"[RomaWiFiCtrl] Send failed: {ex.Message}"); } } private bool Validate() { if (string.IsNullOrWhiteSpace(deviceIp)) { Debug.LogWarning("[RomaWiFiCtrl] deviceIp 为空(尚未发现设备)"); return false; } if (deviceControlPort <= 0 || deviceControlPort > 65535) { Debug.LogWarning($"[RomaWiFiCtrl] deviceControlPort 无效: {deviceControlPort}"); return false; } if (string.IsNullOrWhiteSpace(targetIp)) { Debug.LogWarning("[RomaWiFiCtrl] targetIp 为空(请填写本机IP)"); return false; } if (targetPort <= 0 || targetPort > 65535) { Debug.LogWarning($"[RomaWiFiCtrl] targetPort 无效: {targetPort}"); return false; } if (targetPort == 12345) { Debug.LogWarning("[RomaWiFiCtrl] targetPort=12345 是广播端口,建议不要用(会冲突/混乱)。请改为 9000 或其他端口。"); } return true; } private void EnsureClient() { if (_client != null) return; try { _client = new UdpClient(); } catch (Exception ex) { Debug.LogError($"[RomaWiFiCtrl] Create UdpClient failed: {ex.Message}"); _client = null; } } } }