using System.Net; using DotNext; using Peripherals.PowerClient; using WebProtocol; namespace Peripherals.HdmiInClient; static class HdmiInAddr { public const UInt32 BASE = 0xA000_0000; public const UInt32 HdmiIn_CTRL = BASE + 0x0; //[0]: rstn, 0 is reset. public const UInt32 HdmiIn_READFIFO = BASE + 0x1; } class HdmiIn { private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); readonly int timeout = 500; readonly int taskID; readonly int port; readonly string address; private IPEndPoint ep; // 动态分辨率参数 private UInt16 _currentWidth = 960; private UInt16 _currentHeight = 540; private UInt32 _currentFrameLength = 960 * 540 * 2 / 4; // RGB565格式,2字节/像素,按4字节对齐 /// /// 初始化HDMI输入客户端 /// /// HDMI输入设备IP地址 /// HDMI输入设备端口 /// 任务ID /// 超时时间(毫秒) public HdmiIn(string address, int port, int taskID, int timeout = 500) { if (timeout < 0) throw new ArgumentException("Timeout couldn't be negative", nameof(timeout)); this.address = address; this.port = port; this.ep = new IPEndPoint(IPAddress.Parse(address), port); this.taskID = taskID; this.timeout = timeout; } public async ValueTask> EnableTrans(bool isEnable) { var ret = await UDPClientPool.WriteAddr(this.ep, this.taskID, HdmiInAddr.HdmiIn_CTRL, (isEnable ? 0x00000001u : 0x00000000u)); if (!ret.IsSuccessful) { logger.Error($"Failed to write HdmiIn_CTRL to HdmiIn at {this.address}:{this.port}, error: {ret.Error}"); return new(ret.Error); } if (!ret.Value) { logger.Error($"HdmiIn_CTRL write returned false for HdmiIn at {this.address}:{this.port}"); return false; } return true; } /// /// 读取一帧图像数据 /// /// 包含图像数据的字节数组 public async ValueTask> ReadFrame() { // 只在第一次或出错时清除UDP缓冲区,避免每帧都清除造成延迟 // MsgBus.UDPServer.ClearUDPData(this.address, this.taskID); logger.Trace($"Reading frame from HdmiIn {this.address}"); // 使用UDPClientPool读取图像帧数据 var result = await UDPClientPool.ReadAddr4BytesAsync( this.ep, this.taskID, // taskID HdmiInAddr.HdmiIn_READFIFO, (int)_currentFrameLength, // 使用当前分辨率的动态大小 BurstType.FixedBurst, this.timeout); if (!result.IsSuccessful) { logger.Error($"Failed to read frame from HdmiIn {this.address}:{this.port}, error: {result.Error}"); // 读取失败时清除缓冲区,为下次读取做准备 try { MsgBus.UDPServer.ClearUDPData(this.address, this.taskID); } catch (Exception ex) { logger.Warn($"Failed to clear UDP data after read error: {ex.Message}"); } return new(result.Error); } logger.Trace($"Successfully read frame from HdmiIn {this.address}:{this.port}, data length: {result.Value.Length} bytes"); return result.Value; } /// /// 获取当前分辨率 /// /// 当前分辨率(宽度, 高度) public (int Width, int Height) GetCurrentResolution() { return (_currentWidth, _currentHeight); } /// /// 获取当前帧长度 /// /// 当前帧长度 public UInt32 GetCurrentFrameLength() { return _currentFrameLength; } }