feat: 完善camera复位逻辑

This commit is contained in:
alivender 2025-07-14 17:15:35 +08:00
parent e8a16fd446
commit d901a440a7
3 changed files with 38 additions and 34 deletions

View File

@ -3,7 +3,7 @@
/// </summary> /// </summary>
public static class MsgBus public static class MsgBus
{ {
private static readonly UDPServer udpServer = new UDPServer(1234, 11); private static readonly UDPServer udpServer = new UDPServer(1234, 12);
/// <summary> /// <summary>
/// 获取UDP服务器 /// 获取UDP服务器
/// </summary> /// </summary>

View File

@ -1,5 +1,6 @@
using System.Net; using System.Net;
using DotNext; using DotNext;
using Peripherals.PowerClient;
namespace Peripherals.CameraClient; namespace Peripherals.CameraClient;
@ -27,7 +28,7 @@ class Camera
const uint CAM_I2C_ADDR = 0x3C; const uint CAM_I2C_ADDR = 0x3C;
const Peripherals.I2cClient.I2cProtocol CAM_PROTO = Peripherals.I2cClient.I2cProtocol.SCCB; const Peripherals.I2cClient.I2cProtocol CAM_PROTO = Peripherals.I2cClient.I2cProtocol.SCCB;
const byte PLL_MUX = 60; const byte PLL_MUX = 105;
const UInt32 FrameAddr = 0x00; const UInt32 FrameAddr = 0x00;
// 动态分辨率参数 // 动态分辨率参数
@ -54,6 +55,8 @@ class Camera
public async ValueTask<Result<bool>> Init() public async ValueTask<Result<bool>> Init()
{ {
await PowerHardwareCamera(true);
await SleepHardwareCamera(false);
// 步骤1: 复位 // 步骤1: 复位
var resetResult = await Reset(); var resetResult = await Reset();
if (!resetResult.IsSuccessful) return resetResult; if (!resetResult.IsSuccessful) return resetResult;
@ -139,14 +142,16 @@ class Camera
var resolutionResult = await ConfigureResolution1280x720(); var resolutionResult = await ConfigureResolution1280x720();
if (!resolutionResult.IsSuccessful) return resolutionResult; if (!resolutionResult.IsSuccessful) return resolutionResult;
// 步骤22: 开始流 // // 步骤22: 开始流
var startResult = await StartStreaming(); var startResult = await StartStreaming();
if (!startResult.IsSuccessful) return startResult; if (!startResult.IsSuccessful) return startResult;
// var resetResult2 = await Reset();
// if (!resetResult2.IsSuccessful) return resetResult2;
return true; return true;
} }
public async ValueTask<Result<bool>> EnableCamera(bool isEnable) public async ValueTask<Result<bool>> EnableHardwareTrans(bool isEnable)
{ {
var ret = await UDPClientPool.WriteAddr(this.ep, this.taskID, CameraAddr.CAPTURE_ON, Convert.ToUInt32(isEnable)); var ret = await UDPClientPool.WriteAddr(this.ep, this.taskID, CameraAddr.CAPTURE_ON, Convert.ToUInt32(isEnable));
if (!ret.IsSuccessful) if (!ret.IsSuccessful)
@ -162,7 +167,7 @@ class Camera
return true; return true;
} }
public async ValueTask<Result<bool>> EnableCameraHardware(bool isEnable) public async ValueTask<Result<bool>> PowerHardwareCamera(bool isEnable)
{ {
{ {
var ret = await UDPClientPool.WriteAddr(this.ep, this.taskID, CameraAddr.CAMERA_POWER, (isEnable ? 0x00000001u : 0x00000000u)); var ret = await UDPClientPool.WriteAddr(this.ep, this.taskID, CameraAddr.CAMERA_POWER, (isEnable ? 0x00000001u : 0x00000000u));
@ -180,7 +185,7 @@ class Camera
return true; return true;
} }
public async ValueTask<Result<bool>> SleepCameraHardware(bool isEnable) public async ValueTask<Result<bool>> SleepHardwareCamera(bool isEnable)
{ {
{ {
var ret = await UDPClientPool.WriteAddr(this.ep, this.taskID, CameraAddr.CAMERA_POWER, (isEnable ? 0x00000101u : 0x00000001u)); var ret = await UDPClientPool.WriteAddr(this.ep, this.taskID, CameraAddr.CAMERA_POWER, (isEnable ? 0x00000101u : 0x00000001u));
@ -323,7 +328,7 @@ class Camera
} }
else else
{ {
await Task.Delay(3); // 其他命令延时3ms await Task.Delay(5); // 其他命令延时3ms
} }
} }
} }
@ -404,11 +409,6 @@ class Camera
// 2. 配置I2C寄存器 // 2. 配置I2C寄存器
var resolutionRegisters = new UInt16[][] var resolutionRegisters = new UInt16[][]
{ {
// H_OFFSET/V_OFFSET
[0x3810, unchecked((byte)((hOffset >> 8) & 0xFF))],
[0x3811, unchecked((byte)(hOffset & 0xFF))],
[0x3812, unchecked((byte)((vOffset >> 8) & 0xFF))],
// H_START/V_START // H_START/V_START
[0x3800, unchecked((byte)((hStart >> 8) & 0xFF))], [0x3800, unchecked((byte)((hStart >> 8) & 0xFF))],
[0x3801, unchecked((byte)(hStart & 0xFF))], [0x3801, unchecked((byte)(hStart & 0xFF))],
@ -433,6 +433,10 @@ class Camera
[0x380E, unchecked((byte)((vts >> 8) & 0xFF))], [0x380E, unchecked((byte)((vts >> 8) & 0xFF))],
[0x380F, unchecked((byte)(vts & 0xFF))], [0x380F, unchecked((byte)(vts & 0xFF))],
// H_OFFSET/V_OFFSET
[0x3810, unchecked((byte)((hOffset >> 8) & 0xFF))],
[0x3811, unchecked((byte)(hOffset & 0xFF))],
[0x3812, unchecked((byte)((vOffset >> 8) & 0xFF))],
// Timing Voffset // Timing Voffset
[0x3813, unchecked((byte)(vOffset & 0xFF))] [0x3813, unchecked((byte)(vOffset & 0xFF))]
}; };
@ -561,10 +565,11 @@ class Camera
{ {
var resetRegisters = new UInt16[][] var resetRegisters = new UInt16[][]
{ {
[0x30, 0x08, 0x82] // 复位命令 [0x3103, 0x11],// system clock from pad, bit[1]
[0x3008, 0x82] // 复位命令
}; };
return await ConfigureRegisters(resetRegisters, customDelayMs: 5); // 复位后等待5ms return await ConfigureRegisters(resetRegisters, customDelayMs: 50); // 复位后等待5ms
} }
/// <summary> /// <summary>
@ -589,7 +594,7 @@ class Camera
{ {
var basicRegisters = new UInt16[][] var basicRegisters = new UInt16[][]
{ {
[0x3103, 0x02], [0x3103, 0x02], // system clock from pad, bit[1]
[0x3017, 0xff], [0x3017, 0xff],
[0x3018, 0xff], [0x3018, 0xff],
[0x3037, 0x13], [0x3037, 0x13],
@ -646,9 +651,7 @@ class Camera
{ {
[0x3905, 0x02], [0x3905, 0x02],
[0x3906, 0x10], [0x3906, 0x10],
[0x3901, 0x0a], [0x3901, 0x0a]
[0x3035, 0x11], // 30fps
[0x3036, PLL_MUX] // PLL倍频
}; };
return await ConfigureRegisters(clockRegisters); return await ConfigureRegisters(clockRegisters);
@ -706,7 +709,6 @@ class Camera
[0x3c04, 0x28], [0x3c04, 0x28],
[0x3c05, 0x98], [0x3c05, 0x98],
[0x3c06, 0x00], [0x3c06, 0x00],
[0x3c07, 0x08],
[0x3c08, 0x00], [0x3c08, 0x00],
[0x3c09, 0x1c], [0x3c09, 0x1c],
[0x3c0a, 0x9c], [0x3c0a, 0x9c],
@ -766,10 +768,6 @@ class Camera
[0x3a1e, 0x26], // AEC控制;stable range out low [0x3a1e, 0x26], // AEC控制;stable range out low
[0x3a11, 0x60], // AEC控制; fast zone high [0x3a11, 0x60], // AEC控制; fast zone high
[0x3a1f, 0x14], // AEC控制; fast zone low [0x3a1f, 0x14], // AEC控制; fast zone low
[0x3a02, 0x17], // 60Hz max exposure
[0x3a03, 0x10], // 60Hz max exposure
[0x3a14, 0x17], // 50Hz max exposure
[0x3a15, 0x10], // 50Hz max exposure
[0x3b07, 0x0a] // 帧曝光模式 [0x3b07, 0x0a] // 帧曝光模式
}; };
@ -913,14 +911,13 @@ class Camera
{ {
var timingRegisters = new UInt16[][] var timingRegisters = new UInt16[][]
{ {
[0x3820, 0x46], // vflip [0x3035, 0x11], // 60fps
[0x3821, 0x01], // mirror [0x3036, PLL_MUX],// PLL倍频
[0x3814, 0x31], // timing X inc [0x3c07, 0x08],
[0x3815, 0x31], // timing Y inc [0x3820, 0x41], // vflip
[0x3618, 0x00], [0x3821, 0x00], // mirror
[0x3612, 0x29], [0x3814, 0x11], // timing X inc
[0x3709, 0x52], [0x3815, 0x11] // timing Y inc
[0x370c, 0x03]
}; };
return await ConfigureRegisters(timingRegisters); return await ConfigureRegisters(timingRegisters);
@ -934,14 +931,22 @@ class Camera
{ {
var testRegisters = new UInt16[][] var testRegisters = new UInt16[][]
{ {
[0x3618, 0x00],
[0x3612, 0x29],
[0x3709, 0x52],
[0x370c, 0x03],
[0x4004, 0x02], // BLC(背光) 2 lines [0x4004, 0x02], // BLC(背光) 2 lines
[0x4713, 0x03], // JPEG mode 3 [0x4713, 0x03], // JPEG mode 3
[0x4407, 0x04], // 量化标度 [0x4407, 0x04], // 量化标度
[0x460c, 0x20], [0x460c, 0x20],
[0x3a02, 0x17], // 60Hz max exposure
[0x3a03, 0x10], // 60Hz max exposure
[0x3a14, 0x17], // 50Hz max exposure
[0x3a15, 0x10], // 50Hz max exposure
[0x4837, 0x22], // DVP CLK divider [0x4837, 0x22], // DVP CLK divider
[0x3824, 0x02], // DVP CLK divider [0x3824, 0x02], // DVP CLK divider
// 彩条测试禁用 // 彩条测试禁用
[0x503d, 0x00], [0x503d, 0x80],
[0x4741, 0x00], [0x4741, 0x00],
// 闪光灯配置 // 闪光灯配置
[0x3016, 0x02], [0x3016, 0x02],

View File

@ -156,8 +156,7 @@ public class HttpVideoStreamService : BackgroundService
throw new Exception("Please config camera first"); throw new Exception("Please config camera first");
} }
_cameraEnable = isEnabled; _cameraEnable = isEnabled;
await _camera.EnableCamera(_cameraEnable); await _camera.EnableHardwareTrans(_cameraEnable);
await _camera.SleepCameraHardware(!_cameraEnable);
} }
/// <summary> /// <summary>