| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201 |
- using System;
- using System.Net;
- using System.Net.Sockets;
- using System.Text;
- using LightGlue.Unity.Config;
- using UnityEngine;
- namespace LightGlue.Unity.Roma
- {
- /// <summary>
- /// OrangePi WiFi 图传控制(JSON over UDP,端口默认 8008)。
- /// 参考:orangepizero2w/UDP_PROTOCOL.md、上位机参考.md
- /// </summary>
- 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<string, int> 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;
- }
- }
- }
- }
|