add: 添加了HDMI视频流Client
This commit is contained in:
		@@ -1,6 +1,7 @@
 | 
			
		||||
using System.Net;
 | 
			
		||||
using DotNext;
 | 
			
		||||
using Peripherals.PowerClient;
 | 
			
		||||
using WebProtocol;
 | 
			
		||||
 | 
			
		||||
namespace Peripherals.CameraClient;
 | 
			
		||||
 | 
			
		||||
@@ -225,6 +226,7 @@ class Camera
 | 
			
		||||
            this.taskID, // taskID
 | 
			
		||||
            FrameAddr,
 | 
			
		||||
            (int)_currentFrameLength, // 使用当前分辨率的动态大小
 | 
			
		||||
            BurstType.ExtendBurst,
 | 
			
		||||
            this.timeout);
 | 
			
		||||
 | 
			
		||||
        if (!result.IsSuccessful)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										118
									
								
								server/src/Peripherals/HdmiInClient.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								server/src/Peripherals/HdmiInClient.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,118 @@
 | 
			
		||||
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字节对齐
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 初始化HDMI输入客户端
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="address">HDMI输入设备IP地址</param>
 | 
			
		||||
    /// <param name="port">HDMI输入设备端口</param>
 | 
			
		||||
    /// <param name="timeout">超时时间(毫秒)</param>
 | 
			
		||||
    public HdmiIn(string address, int port, 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.timeout = timeout;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async ValueTask<Result<bool>> 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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 读取一帧图像数据
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <returns>包含图像数据的字节数组</returns>
 | 
			
		||||
    public async ValueTask<Result<byte[]>> 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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 获取当前分辨率
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <returns>当前分辨率(宽度, 高度)</returns>
 | 
			
		||||
    public (int Width, int Height) GetCurrentResolution()
 | 
			
		||||
    {
 | 
			
		||||
        return (_currentWidth, _currentHeight);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 获取当前帧长度
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <returns>当前帧长度</returns>
 | 
			
		||||
    public UInt32 GetCurrentFrameLength()
 | 
			
		||||
    {
 | 
			
		||||
        return _currentFrameLength;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -2,6 +2,7 @@ using System.Collections;
 | 
			
		||||
using System.Net;
 | 
			
		||||
using Common;
 | 
			
		||||
using DotNext;
 | 
			
		||||
using WebProtocol;
 | 
			
		||||
 | 
			
		||||
namespace Peripherals.LogicAnalyzerClient;
 | 
			
		||||
 | 
			
		||||
@@ -475,6 +476,7 @@ public class Analyzer
 | 
			
		||||
            this.taskID,
 | 
			
		||||
            AnalyzerAddr.STORE_OFFSET_ADDR,
 | 
			
		||||
            capture_length,
 | 
			
		||||
            BurstType.ExtendBurst, // 使用扩展突发读取
 | 
			
		||||
            this.timeout
 | 
			
		||||
        );
 | 
			
		||||
        if (!ret.IsSuccessful)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
using System.Net;
 | 
			
		||||
using Common;
 | 
			
		||||
using DotNext;
 | 
			
		||||
using WebProtocol;
 | 
			
		||||
 | 
			
		||||
namespace Peripherals.OscilloscopeClient;
 | 
			
		||||
 | 
			
		||||
@@ -319,6 +320,7 @@ class Oscilloscope
 | 
			
		||||
            this.taskID,
 | 
			
		||||
            OscilloscopeAddr.RD_DATA_ADDR,
 | 
			
		||||
            (int)OscilloscopeAddr.RD_DATA_LENGTH / 32,
 | 
			
		||||
            BurstType.ExtendBurst, // 使用扩展突发读取
 | 
			
		||||
            this.timeout
 | 
			
		||||
        );
 | 
			
		||||
        if (!ret.IsSuccessful)
 | 
			
		||||
 
 | 
			
		||||
@@ -433,11 +433,12 @@ public class UDPClientPool
 | 
			
		||||
    /// <param name="endPoint">IP端点(IP地址与端口)</param>
 | 
			
		||||
    /// <param name="taskID">任务ID</param>
 | 
			
		||||
    /// <param name="devAddr">设备地址</param>
 | 
			
		||||
    /// <param name="burstType">突发类型</param>
 | 
			
		||||
    /// <param name="dataLength">要读取的数据长度(4字节)</param>
 | 
			
		||||
    /// <param name="timeout">超时时间(毫秒)</param>
 | 
			
		||||
    /// <returns>读取结果,包含接收到的字节数组</returns>
 | 
			
		||||
    public static async ValueTask<Result<byte[]>> ReadAddr4BytesAsync(
 | 
			
		||||
        IPEndPoint endPoint, int taskID, UInt32 devAddr, int dataLength, int timeout = 1000)
 | 
			
		||||
        IPEndPoint endPoint, int taskID, UInt32 devAddr, int dataLength, BurstType burstType, int timeout = 1000)
 | 
			
		||||
    {
 | 
			
		||||
        var pkgList = new List<SendAddrPackage>();
 | 
			
		||||
        var resultData = new List<byte>();
 | 
			
		||||
@@ -460,7 +461,7 @@ public class UDPClientPool
 | 
			
		||||
 | 
			
		||||
            var opts = new SendAddrPackOptions
 | 
			
		||||
            {
 | 
			
		||||
                BurstType = BurstType.FixedBurst,
 | 
			
		||||
                BurstType = burstType,
 | 
			
		||||
                CommandID = Convert.ToByte(taskID),
 | 
			
		||||
                IsWrite = false,
 | 
			
		||||
                BurstLength = (byte)(currentSegmentSize - 1),
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user