feat: readwithwait函数增加了新参数;camera有更多分辨率选择。
This commit is contained in:
		@@ -483,49 +483,6 @@ class Camera
 | 
			
		||||
    /// <returns>配置结果</returns>
 | 
			
		||||
    public async ValueTask<Result<bool>> ConfigureResolution1280x720()
 | 
			
		||||
    {
 | 
			
		||||
        // var Registers = new UInt16[][]
 | 
			
		||||
        // {
 | 
			
		||||
        //     // 1280x720, 15fps
 | 
			
		||||
        //     // input clock 24Mhz, PCLK 42Mhz
 | 
			
		||||
        //     // [0x3035, 0x41], // PLL
 | 
			
		||||
        //     // [0x3036, 0x69], // PLL
 | 
			
		||||
        //     [0x3c07, 0x07], // lightmeter 1 threshold[7:0]
 | 
			
		||||
        //     [0x3820, 0x41], // flip
 | 
			
		||||
        //     [0x3821, 0x07], // mirror
 | 
			
		||||
        //     [0x3814, 0x31], // timing X inc
 | 
			
		||||
        //     [0x3815, 0x31], // timing Y inc
 | 
			
		||||
        //     [0x3800, 0x00], // HS
 | 
			
		||||
        //     [0x3801, 0x00], // HS
 | 
			
		||||
        //     [0x3802, 0x00], // VS
 | 
			
		||||
        //     [0x3803, 0xfa], // VS
 | 
			
		||||
        //     [0x3804, 0x0a], // HW (HE)
 | 
			
		||||
        //     [0x3805, 0x3f], // HW (HE)
 | 
			
		||||
        //     [0x3806, 0x06], // VH (VE)
 | 
			
		||||
        //     [0x3807, 0xa9], // VH (VE)
 | 
			
		||||
        //     [0x3808, 0x05], // DVPHO
 | 
			
		||||
        //     [0x3809, 0x00], // DVPHO
 | 
			
		||||
        //     [0x380a, 0x02], // DVPVO
 | 
			
		||||
        //     [0x380b, 0xd0], // DVPVO
 | 
			
		||||
        //     [0x380c, 0x0B], // HTS
 | 
			
		||||
        //     [0x380d, 0x1C], // HTS
 | 
			
		||||
        //     [0x380e, 0x07], // VTS
 | 
			
		||||
        //     [0x380f, 0xB0], // VTS
 | 
			
		||||
        //     [0x3810, 0x00], // Timing Hoffset[11:8]
 | 
			
		||||
        //     [0x3811, 0x10], // Timing Hoffset[7:0]
 | 
			
		||||
        //     [0x3812, 0x00], // Timing Voffset[10:8]
 | 
			
		||||
        //     [0x3813, 0x04], // timing V offset
 | 
			
		||||
        //     [0x3618, 0x00],
 | 
			
		||||
        //     [0x3612, 0x29],
 | 
			
		||||
        //     [0x3709, 0x52],
 | 
			
		||||
        //     [0x370c, 0x03] 
 | 
			
		||||
        //     // [0x3a02, 0x02], // 60Hz max exposure
 | 
			
		||||
        //     // [0x3a03, 0xe0], // 60Hz max exposure 
 | 
			
		||||
        //     // [0x3a14, 0x02], // 50Hz max exposure
 | 
			
		||||
        //     // [0x3a15, 0xe0]  // 50Hz max exposure
 | 
			
		||||
        // };
 | 
			
		||||
 | 
			
		||||
        // await ConfigureRegisters(Registers);
 | 
			
		||||
 | 
			
		||||
        return await ConfigureResolution(
 | 
			
		||||
            hStart: 0, vStart: 250,
 | 
			
		||||
            dvpHo: 1280, dvpVo: 720,
 | 
			
		||||
@@ -533,6 +490,37 @@ class Camera
 | 
			
		||||
            hOffset: 16, vOffset: 4,
 | 
			
		||||
            hWindow: 2624, vWindow: 1456
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 配置为1280x720分辨率
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <returns>配置结果</returns>
 | 
			
		||||
    public async ValueTask<Result<bool>> ConfigureResolution1280x960()
 | 
			
		||||
    {
 | 
			
		||||
        return await ConfigureResolution(
 | 
			
		||||
            hStart: 0, vStart: 250,
 | 
			
		||||
            dvpHo: 1280, dvpVo: 960,
 | 
			
		||||
            hts: 2844, vts: 1968,
 | 
			
		||||
            hOffset: 16, vOffset: 4,
 | 
			
		||||
            hWindow: 2624, vWindow: 1456
 | 
			
		||||
        );
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 配置为1920x1080分辨率
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <returns>配置结果</returns>
 | 
			
		||||
    public async ValueTask<Result<bool>> ConfigureResolution1920x1080()
 | 
			
		||||
    {
 | 
			
		||||
        return await ConfigureResolution(
 | 
			
		||||
            hStart: 0, vStart: 250,
 | 
			
		||||
            dvpHo: 1920, dvpVo: 1080,
 | 
			
		||||
            hts: 2844, vts: 1968,
 | 
			
		||||
            hOffset: 16, vOffset: 4,
 | 
			
		||||
            hWindow: 2624, vWindow: 1456
 | 
			
		||||
        );
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -558,6 +546,12 @@ class Camera
 | 
			
		||||
                case "1280x720":
 | 
			
		||||
                    result = await ConfigureResolution1280x720();
 | 
			
		||||
                    break;
 | 
			
		||||
                case "1280x960":
 | 
			
		||||
                    result = await ConfigureResolution1280x960();
 | 
			
		||||
                    break;
 | 
			
		||||
                case "1920x1080":
 | 
			
		||||
                    result = await ConfigureResolution1920x1080();
 | 
			
		||||
                    break;
 | 
			
		||||
                default:
 | 
			
		||||
                    logger.Error($"不支持的分辨率: {width}x{height}");
 | 
			
		||||
                    return new(new ArgumentException($"不支持的分辨率: {width}x{height}"));
 | 
			
		||||
@@ -956,8 +950,8 @@ class Camera
 | 
			
		||||
            [0x3035, 0x21], // 60fps
 | 
			
		||||
            [0x3036, PLL_MUX],// PLL倍频
 | 
			
		||||
            [0x3c07, 0x08],
 | 
			
		||||
            [0x3820, 0x41], // vflip
 | 
			
		||||
            [0x3821, 0x00], // mirror
 | 
			
		||||
            [0x3820, 0x40], // vflip
 | 
			
		||||
            [0x3821, 0x01], // mirror
 | 
			
		||||
            [0x3814, 0x11], // timing X inc
 | 
			
		||||
            [0x3815, 0x11]  // timing Y inc
 | 
			
		||||
        };
 | 
			
		||||
@@ -1336,37 +1330,38 @@ class Camera
 | 
			
		||||
            [0x3026, 0x00],
 | 
			
		||||
            [0x3027, 0x00],
 | 
			
		||||
            [0x3028, 0x00],
 | 
			
		||||
            [0x3029, 0x7F], // 状态寄存器
 | 
			
		||||
            [0x3000, 0x00]  // 启动MCU
 | 
			
		||||
            [0x3029, 0xFF], // 状态寄存器
 | 
			
		||||
            [0x3000, 0x00], // 启动MCU
 | 
			
		||||
            [0x3004, 0xFF]  // 使能中断
 | 
			
		||||
        };
 | 
			
		||||
        var result = await ConfigureRegisters(focusRegisters);
 | 
			
		||||
        if (!result.IsSuccessful) return result;
 | 
			
		||||
 | 
			
		||||
        // 读取寄存器判断初始化是否完毕
 | 
			
		||||
        for (int iteration = 1000; iteration > 0; iteration--)
 | 
			
		||||
        {
 | 
			
		||||
            var readResult = await ReadRegister(0x3029);
 | 
			
		||||
            if (!readResult.IsSuccessful)
 | 
			
		||||
            {
 | 
			
		||||
                logger.Error($"读取自动对焦初始化状态失败: {readResult.Error}");
 | 
			
		||||
                return new(readResult.Error);
 | 
			
		||||
            }
 | 
			
		||||
        // // 读取寄存器判断初始化是否完毕
 | 
			
		||||
        // for (int iteration = 1000; iteration > 0; iteration--)
 | 
			
		||||
        // {
 | 
			
		||||
        //     var readResult = await ReadRegister(0x3029);
 | 
			
		||||
        //     if (!readResult.IsSuccessful)
 | 
			
		||||
        //     {
 | 
			
		||||
        //         logger.Error($"读取自动对焦初始化状态失败: {readResult.Error}");
 | 
			
		||||
        //         return new(readResult.Error);
 | 
			
		||||
        //     }
 | 
			
		||||
 | 
			
		||||
            logger.Debug($"自动对焦初始化状态检查, state=0x{readResult.Value:X2}");
 | 
			
		||||
        //     logger.Debug($"自动对焦初始化状态检查, state=0x{readResult.Value:X2}");
 | 
			
		||||
 | 
			
		||||
            if (readResult.Value != 0x7F)
 | 
			
		||||
            {
 | 
			
		||||
                break; // 初始化完成
 | 
			
		||||
            }
 | 
			
		||||
        //     if (readResult.Value != 0x7F)
 | 
			
		||||
        //     {
 | 
			
		||||
        //         break; // 初始化完成
 | 
			
		||||
        //     }
 | 
			
		||||
 | 
			
		||||
            if (iteration == 1)
 | 
			
		||||
            {
 | 
			
		||||
                logger.Error($"自动对焦初始化状态检查超时!! state=0x{readResult.Value:X2}");
 | 
			
		||||
                return new(new Exception($"自动对焦初始化状态检查超时, state=0x{readResult.Value:X2}"));
 | 
			
		||||
            }
 | 
			
		||||
        //     if (iteration == 1)
 | 
			
		||||
        //     {
 | 
			
		||||
        //         logger.Error($"自动对焦初始化状态检查超时!! state=0x{readResult.Value:X2}");
 | 
			
		||||
        //         return new(new Exception($"自动对焦初始化状态检查超时, state=0x{readResult.Value:X2}"));
 | 
			
		||||
        //     }
 | 
			
		||||
 | 
			
		||||
            await Task.Delay(1);
 | 
			
		||||
        }
 | 
			
		||||
        //     await Task.Delay(1);
 | 
			
		||||
        // }
 | 
			
		||||
 | 
			
		||||
        logger.Info("OV5640自动对焦功能初始化完成");
 | 
			
		||||
        return true;
 | 
			
		||||
 
 | 
			
		||||
@@ -174,7 +174,7 @@ public class I2c
 | 
			
		||||
 | 
			
		||||
        // 等待I2C命令完成
 | 
			
		||||
        {
 | 
			
		||||
            var ret = await UDPClientPool.ReadAddrWithWait(this.ep, this.taskID, I2cAddr.Flag, 0x0000_0001, 0xFFFF_FFFF);
 | 
			
		||||
            var ret = await UDPClientPool.ReadAddrWithWait(this.ep, this.taskID, I2cAddr.Flag, 0x0000_0001, 0xFFFF_FFFF, 10);
 | 
			
		||||
            if (!ret.IsSuccessful)
 | 
			
		||||
            {
 | 
			
		||||
                logger.Error($"Failed to wait for I2C command completion: {ret.Error}");
 | 
			
		||||
@@ -280,7 +280,7 @@ public class I2c
 | 
			
		||||
 | 
			
		||||
        // 等待I2C命令完成
 | 
			
		||||
        {
 | 
			
		||||
            var ret = await UDPClientPool.ReadAddrWithWait(this.ep, this.taskID, I2cAddr.Flag, 0x0000_0001, 0xFFFF_FFFF);
 | 
			
		||||
            var ret = await UDPClientPool.ReadAddrWithWait(this.ep, this.taskID, I2cAddr.Flag, 0x0000_0001, 0xFFFF_FFFF, 10);
 | 
			
		||||
            if (!ret.IsSuccessful)
 | 
			
		||||
            {
 | 
			
		||||
                logger.Error($"Failed to wait for I2C command completion: {ret.Error}");
 | 
			
		||||
 
 | 
			
		||||
@@ -452,7 +452,7 @@ public class Jtag
 | 
			
		||||
        await Task.Delay(TimeSpan.FromMilliseconds(delayMilliseconds));
 | 
			
		||||
 | 
			
		||||
        {
 | 
			
		||||
            var ret = await UDPClientPool.ReadAddrWithWait(this.ep, 0, JtagAddr.STATE, result, resultMask, this.timeout);
 | 
			
		||||
            var ret = await UDPClientPool.ReadAddrWithWait(this.ep, 0, JtagAddr.STATE, result, resultMask, 0, this.timeout);
 | 
			
		||||
            if (!ret.IsSuccessful) return new(ret.Error);
 | 
			
		||||
            return ret.Value;
 | 
			
		||||
        }
 | 
			
		||||
@@ -471,7 +471,7 @@ public class Jtag
 | 
			
		||||
        await Task.Delay(TimeSpan.FromMilliseconds(delayMilliseconds));
 | 
			
		||||
 | 
			
		||||
        {
 | 
			
		||||
            var ret = await UDPClientPool.ReadAddrWithWait(this.ep, 0, JtagAddr.STATE, result, resultMask, this.timeout);
 | 
			
		||||
            var ret = await UDPClientPool.ReadAddrWithWait(this.ep, 0, JtagAddr.STATE, result, resultMask, 0, this.timeout);
 | 
			
		||||
            if (!ret.IsSuccessful) return new(ret.Error);
 | 
			
		||||
            return ret.Value;
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -99,7 +99,7 @@ public class RemoteUpdater
 | 
			
		||||
    const int FLASH_SECTOR_LENGTH = 4 * 1024;
 | 
			
		||||
 | 
			
		||||
    readonly int timeout = 2000;
 | 
			
		||||
    readonly int timeoutForWait = 60 * 1000;
 | 
			
		||||
    readonly int timeoutForWait = 20 * 1000;
 | 
			
		||||
 | 
			
		||||
    readonly int port;
 | 
			
		||||
    readonly string address;
 | 
			
		||||
@@ -152,7 +152,7 @@ public class RemoteUpdater
 | 
			
		||||
        {
 | 
			
		||||
            var ret = await UDPClientPool.ReadAddrWithWait(
 | 
			
		||||
                this.ep, 0, RemoteUpdaterAddr.WriteSign,
 | 
			
		||||
                0x00_00_00_01, 0x00_00_00_01, this.timeoutForWait);
 | 
			
		||||
                0x00_00_00_01, 0x00_00_00_01, 100, this.timeoutForWait);
 | 
			
		||||
            if (!ret.IsSuccessful) return new(ret.Error);
 | 
			
		||||
            if (!ret.Value) return new(new Exception(
 | 
			
		||||
                $"Flash clear failed after {this.timeoutForWait} milliseconds"));
 | 
			
		||||
@@ -167,7 +167,7 @@ public class RemoteUpdater
 | 
			
		||||
        {
 | 
			
		||||
            var ret = await UDPClientPool.ReadAddrWithWait(
 | 
			
		||||
                this.ep, 0, RemoteUpdaterAddr.WriteSign,
 | 
			
		||||
                0x00_00_01_00, 0x00_00_01_00, this.timeoutForWait);
 | 
			
		||||
                0x00_00_01_00, 0x00_00_01_00, 100, this.timeoutForWait);
 | 
			
		||||
            if (!ret.IsSuccessful) return new(ret.Error);
 | 
			
		||||
            return ret.Value;
 | 
			
		||||
        }
 | 
			
		||||
@@ -332,7 +332,7 @@ public class RemoteUpdater
 | 
			
		||||
        {
 | 
			
		||||
            var ret = await UDPClientPool.ReadAddrWithWait(
 | 
			
		||||
                this.ep, 0, RemoteUpdaterAddr.ReadSign,
 | 
			
		||||
                0x00_00_01_00, 0x00_00_01_00, this.timeoutForWait);
 | 
			
		||||
                0x00_00_01_00, 0x00_00_01_00, 10, this.timeoutForWait);
 | 
			
		||||
            if (!ret.IsSuccessful) return new(ret.Error);
 | 
			
		||||
            if (!ret.Value) return new(new Exception(
 | 
			
		||||
                $"Read bitstream failed after {this.timeoutForWait} milliseconds"));
 | 
			
		||||
 
 | 
			
		||||
@@ -946,14 +946,6 @@ public class HttpVideoStreamService : BackgroundService
 | 
			
		||||
        {
 | 
			
		||||
            logger.Info($"正在设置视频流分辨率为 {width}x{height}");
 | 
			
		||||
 | 
			
		||||
            // 验证分辨率
 | 
			
		||||
            if (!IsSupportedResolution(width, height))
 | 
			
		||||
            {
 | 
			
		||||
                var message = $"不支持的分辨率: {width}x{height},支持的分辨率: 640x480, 1280x720";
 | 
			
		||||
                logger.Error(message);
 | 
			
		||||
                return (false, message);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Camera? currentCamera = null;
 | 
			
		||||
            lock (_cameraLock)
 | 
			
		||||
            {
 | 
			
		||||
@@ -1007,18 +999,6 @@ public class HttpVideoStreamService : BackgroundService
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 检查是否支持该分辨率
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="width">宽度</param>
 | 
			
		||||
    /// <param name="height">高度</param>
 | 
			
		||||
    /// <returns>是否支持</returns>
 | 
			
		||||
    private bool IsSupportedResolution(int width, int height)
 | 
			
		||||
    {
 | 
			
		||||
        var resolution = $"{width}x{height}";
 | 
			
		||||
        return resolution == "640x480" || resolution == "1280x720";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 获取支持的分辨率列表
 | 
			
		||||
    /// </summary>
 | 
			
		||||
@@ -1028,7 +1008,9 @@ public class HttpVideoStreamService : BackgroundService
 | 
			
		||||
        return new List<(int, int, string)>
 | 
			
		||||
        {
 | 
			
		||||
            (640, 480, "640x480 (VGA)"),
 | 
			
		||||
            (1280, 720, "1280x720 (HD)")
 | 
			
		||||
            (1280, 720, "1280x720 (HD)"),
 | 
			
		||||
            (1280, 960, "1280x960 (SXGA)"),
 | 
			
		||||
            (1920, 1080, "1920x1080 (Full HD)")
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -306,10 +306,11 @@ public class UDPClientPool
 | 
			
		||||
    /// <param name="devAddr">设备地址</param>
 | 
			
		||||
    /// <param name="result">期望的结果值</param>
 | 
			
		||||
    /// <param name="resultMask">结果掩码,用于位校验</param>
 | 
			
		||||
    /// <param name="waittime">等待间隔时间(毫秒)</param>
 | 
			
		||||
    /// <param name="timeout">超时时间(毫秒)</param>
 | 
			
		||||
    /// <returns>校验结果,true表示在超时前数据匹配期望值</returns>
 | 
			
		||||
    public static async ValueTask<Result<bool>> ReadAddrWithWait(
 | 
			
		||||
            IPEndPoint endPoint, int taskID, uint devAddr, UInt32 result, UInt32 resultMask, int timeout = 1000)
 | 
			
		||||
            IPEndPoint endPoint, int taskID, uint devAddr, UInt32 result, UInt32 resultMask, int waittime = 100, int timeout = 1000)
 | 
			
		||||
    {
 | 
			
		||||
        var address = endPoint.Address.ToString();
 | 
			
		||||
 | 
			
		||||
@@ -319,7 +320,7 @@ public class UDPClientPool
 | 
			
		||||
            var elapsed = DateTime.Now - startTime;
 | 
			
		||||
            if (elapsed >= TimeSpan.FromMilliseconds(timeout)) break;
 | 
			
		||||
            var timeleft = TimeSpan.FromMilliseconds(timeout) - elapsed;
 | 
			
		||||
 | 
			
		||||
            await Task.Delay(waittime);
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                var ret = await ReadAddr(endPoint, taskID, devAddr, Convert.ToInt32(timeleft.TotalMilliseconds));
 | 
			
		||||
@@ -637,21 +638,23 @@ public class UDPClientPool
 | 
			
		||||
            IsWrite = true,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        var max4BytesPerRead = 128; // 1024 bytes per read
 | 
			
		||||
 | 
			
		||||
        // Check Msg Bus
 | 
			
		||||
        if (!MsgBus.IsRunning)
 | 
			
		||||
            return new(new Exception("Message bus not working!"));
 | 
			
		||||
 | 
			
		||||
        var hasRest = dataArray.Length % (256 * (32 / 8)) != 0;
 | 
			
		||||
        var hasRest = dataArray.Length % (max4BytesPerRead * (32 / 8)) != 0;
 | 
			
		||||
        var writeTimes = hasRest ?
 | 
			
		||||
            dataArray.Length / (256 * (32 / 8)) + 1 :
 | 
			
		||||
            dataArray.Length / (256 * (32 / 8));
 | 
			
		||||
            dataArray.Length / (max4BytesPerRead * (32 / 8)) + 1 :
 | 
			
		||||
            dataArray.Length / (max4BytesPerRead * (32 / 8));
 | 
			
		||||
        for (var i = 0; i < writeTimes; i++)
 | 
			
		||||
        {
 | 
			
		||||
            // Sperate Data Array
 | 
			
		||||
            var isLastData = i == writeTimes - 1;
 | 
			
		||||
            var sendDataArray = isLastData ?
 | 
			
		||||
                dataArray[(i * (256 * (32 / 8)))..] :
 | 
			
		||||
                dataArray[(i * (256 * (32 / 8)))..((i + 1) * (256 * (32 / 8)))];
 | 
			
		||||
                dataArray[(i * (max4BytesPerRead * (32 / 8)))..] :
 | 
			
		||||
                dataArray[(i * (max4BytesPerRead * (32 / 8)))..((i + 1) * (max4BytesPerRead * (32 / 8)))];
 | 
			
		||||
 | 
			
		||||
            // Calculate BurstLength
 | 
			
		||||
            opts.BurstLength = ((byte)(
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user