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;
}
}
}
}