feat: 添加I2C与Camera初始化的支持
This commit is contained in:
		@@ -35,6 +35,25 @@ class Camera
 | 
			
		||||
        this.timeout = timeout;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async ValueTask<Result<bool>> Init()
 | 
			
		||||
    {
 | 
			
		||||
        var i2c = new Peripherals.I2cClient.I2c(this.address, this.port, this.timeout);
 | 
			
		||||
        var ret = await i2c.WriteData(0x78, new byte[] { 0x08, 0x30, 0x02 }, Peripherals.I2cClient.I2cProtocol.I2c);
 | 
			
		||||
        if (!ret.IsSuccessful)
 | 
			
		||||
        {
 | 
			
		||||
            logger.Error($"I2C write failed during camera initialization for {this.address}:{this.port}, error: {ret.Error}");
 | 
			
		||||
            return new(ret.Error);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!ret.Value)
 | 
			
		||||
        {
 | 
			
		||||
            logger.Error($"I2C write returned unsuccessful result during camera initialization for {this.address}:{this.port}");
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 读取一帧图像数据
 | 
			
		||||
    /// </summary>
 | 
			
		||||
@@ -47,7 +66,7 @@ class Camera
 | 
			
		||||
        logger.Trace($"Clear up udp server {this.address} receive data");
 | 
			
		||||
 | 
			
		||||
        // 使用UDPClientPool读取图像帧数据
 | 
			
		||||
        var result = await UDPClientPool.ReadAddrBytes(
 | 
			
		||||
        var result = await UDPClientPool.ReadAddr4Bytes(
 | 
			
		||||
            this.ep,
 | 
			
		||||
            2, // taskID
 | 
			
		||||
            CameraAddr.Base,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										269
									
								
								server/src/Peripherals/I2cClient.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										269
									
								
								server/src/Peripherals/I2cClient.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,269 @@
 | 
			
		||||
using System.Net;
 | 
			
		||||
using DotNext;
 | 
			
		||||
 | 
			
		||||
namespace Peripherals.I2cClient;
 | 
			
		||||
 | 
			
		||||
static class I2cAddr
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    const UInt32 Base = 0x6000_0000;
 | 
			
		||||
 | 
			
		||||
    /// <summary> 
 | 
			
		||||
    /// 0x0000_0000: 
 | 
			
		||||
    /// [7:0] 本次传输的i2c地址(最高位总为0);
 | 
			
		||||
    /// [8] 1为读,0为写;
 | 
			
		||||
    /// [16] 1为SCCB协议,0为I2C协议;
 | 
			
		||||
    /// [24] 1为开启本次传输,自动置零
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public const UInt32 BaseConfig = Base + 0x0000_0000;
 | 
			
		||||
 | 
			
		||||
    /// <summary> 
 | 
			
		||||
    /// 0x0000_0001:
 | 
			
		||||
    /// [15:0] 本次传输的数据量(以字节为单位,0为传1个字节);
 | 
			
		||||
    /// [31:16] 若本次传输为读的DUMMY数据量(字节为单位,0为传1个字节)
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public const UInt32 TranConfig = Base + 0x0000_0001;
 | 
			
		||||
 | 
			
		||||
    /// <summary> 
 | 
			
		||||
    /// 0x0000_0002: [0] cmd_done; [8] cmd_error;
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public const UInt32 Flag = Base + 0x0000_0002;
 | 
			
		||||
 | 
			
		||||
    /// <summary> 
 | 
			
		||||
    /// 0x0000_0003: FIFO写入口,仅低8位有效,只写
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public const UInt32 Write = Base + 0x0000_0003;
 | 
			
		||||
 | 
			
		||||
    /// <summary> 
 | 
			
		||||
    /// 0x0000_0004: FIFO读出口,仅低8位有效,只读
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public const UInt32 Read = Base + 0x0000_0003;
 | 
			
		||||
 | 
			
		||||
    /// <summary> 
 | 
			
		||||
    /// 0x0000_0005: [0] FIFO写入口清空;[8] FIFO读出口清空;
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public const UInt32 Clear = Base + 0x0000_0003;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// <summary> 
 | 
			
		||||
/// [TODO:Enum]
 | 
			
		||||
/// </summary>
 | 
			
		||||
public enum I2cProtocol
 | 
			
		||||
{
 | 
			
		||||
    /// <summary> 
 | 
			
		||||
    /// [TODO:Enum]
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    I2c = 0,
 | 
			
		||||
 | 
			
		||||
    /// <summary> 
 | 
			
		||||
    /// [TODO:Enum]
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    SCCB = 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// [TODO:description]
 | 
			
		||||
/// </summary>
 | 
			
		||||
public class I2c
 | 
			
		||||
{
 | 
			
		||||
    private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
 | 
			
		||||
 | 
			
		||||
    readonly int timeout = 2000;
 | 
			
		||||
 | 
			
		||||
    readonly int port;
 | 
			
		||||
    readonly string address;
 | 
			
		||||
    private IPEndPoint ep;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// [TODO:description]
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="address">[TODO:parameter]</param>
 | 
			
		||||
    /// <param name="port">[TODO:parameter]</param>
 | 
			
		||||
    /// <param name="timeout">[TODO:parameter]</param>
 | 
			
		||||
    /// <returns>[TODO:return]</returns>
 | 
			
		||||
    public I2c(string address, int port, int timeout = 2000)
 | 
			
		||||
    {
 | 
			
		||||
        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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 向指定I2C设备写入数据
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="devAddr">I2C设备地址</param>
 | 
			
		||||
    /// <param name="data">要写入的数据</param>
 | 
			
		||||
    /// <param name="proto">I2C协议类型</param>
 | 
			
		||||
    /// <returns>操作结果,成功返回true,否则返回异常信息</returns>
 | 
			
		||||
    public async ValueTask<Result<bool>> WriteData(UInt32 devAddr, byte[] data, I2cProtocol proto)
 | 
			
		||||
    {
 | 
			
		||||
        if (data.Length > 0x0000_FFFF)
 | 
			
		||||
        {
 | 
			
		||||
            logger.Error($"Data length {data.Length} exceeds maximum allowed 0x0000_FFFF");
 | 
			
		||||
            return new(new ArgumentException($"Data length {data.Length} exceeds maximum allowed 0x0000_FFFF"));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 清除UDP服务器接收缓冲区
 | 
			
		||||
        await MsgBus.UDPServer.ClearUDPData(this.address, 2);
 | 
			
		||||
 | 
			
		||||
        logger.Trace($"Clear up udp server {this.address} receive data");
 | 
			
		||||
 | 
			
		||||
        // 写入数据到I2C FIFO写入口
 | 
			
		||||
        {
 | 
			
		||||
            var ret = await UDPClientPool.WriteAddr(this.ep, 2, I2cAddr.Write, data);
 | 
			
		||||
            if (!ret.IsSuccessful)
 | 
			
		||||
            {
 | 
			
		||||
                logger.Error($"Failed to write data to I2C FIFO: {ret.Error}");
 | 
			
		||||
                return new(ret.Error);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!ret.Value)
 | 
			
		||||
            {
 | 
			
		||||
                logger.Error("WriteAddr to I2C FIFO returned false");
 | 
			
		||||
                return new(new Exception("Failed to write data to I2C FIFO"));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 配置本次传输数据量
 | 
			
		||||
        {
 | 
			
		||||
            var ret = await UDPClientPool.WriteAddr(this.ep, 2, I2cAddr.TranConfig, ((uint)(data.Length - 1)));
 | 
			
		||||
            if (!ret.IsSuccessful)
 | 
			
		||||
            {
 | 
			
		||||
                logger.Error($"Failed to configure transfer length: {ret.Error}");
 | 
			
		||||
                return new(ret.Error);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!ret.Value)
 | 
			
		||||
            {
 | 
			
		||||
                logger.Error("WriteAddr to TranConfig returned false");
 | 
			
		||||
                return new(new Exception("Failed to configure transfer length"));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 配置I2C地址、协议及启动传输
 | 
			
		||||
        {
 | 
			
		||||
            var ret = await UDPClientPool.WriteAddr(
 | 
			
		||||
                this.ep, 2, I2cAddr.BaseConfig, (devAddr << 1) | (((uint)proto) << 16) | (1 << 24));
 | 
			
		||||
            if (!ret.IsSuccessful)
 | 
			
		||||
            {
 | 
			
		||||
                logger.Error($"Failed to configure I2C address/protocol/start: {ret.Error}");
 | 
			
		||||
                return new(ret.Error);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!ret.Value)
 | 
			
		||||
            {
 | 
			
		||||
                logger.Error("WriteAddr to BaseConfig returned false");
 | 
			
		||||
                return new(new Exception("Failed to configure I2C address/protocol/start"));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 等待I2C命令完成
 | 
			
		||||
        {
 | 
			
		||||
            var ret = await UDPClientPool.ReadAddrWithWait(this.ep, 2, I2cAddr.Flag, 0x0000_0001, 0xFFFF_FFFF);
 | 
			
		||||
            if (!ret.IsSuccessful)
 | 
			
		||||
            {
 | 
			
		||||
                logger.Error($"Failed to wait for I2C command completion: {ret.Error}");
 | 
			
		||||
                return new(ret.Error);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!ret.Value)
 | 
			
		||||
            {
 | 
			
		||||
                logger.Error("ReadAddrWithWait for I2C command completion returned false");
 | 
			
		||||
                return new(new Exception("I2C command did not complete successfully"));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 从指定I2C设备读取数据
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="devAddr">I2C设备地址</param>
 | 
			
		||||
    /// <param name="length">要读取的数据长度</param>
 | 
			
		||||
    /// <param name="proto">I2C协议类型</param>
 | 
			
		||||
    /// <returns>操作结果,成功返回读取到的数据,否则返回异常信息</returns>
 | 
			
		||||
    public async ValueTask<Result<byte[]>> ReadData(UInt32 devAddr, int length, I2cProtocol proto)
 | 
			
		||||
    {
 | 
			
		||||
        if (length <= 0 || length > 0x0000_FFFF)
 | 
			
		||||
        {
 | 
			
		||||
            logger.Error($"Read length {length} is invalid or exceeds maximum allowed 0x0000_FFFF");
 | 
			
		||||
            return new(new ArgumentException($"Read length {length} is invalid or exceeds maximum allowed 0x0000_FFFF"));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 清除UDP服务器接收缓冲区
 | 
			
		||||
        await MsgBus.UDPServer.ClearUDPData(this.address, 2);
 | 
			
		||||
 | 
			
		||||
        logger.Trace($"Clear up udp server {this.address} receive data");
 | 
			
		||||
 | 
			
		||||
        // 配置本次传输数据量
 | 
			
		||||
        {
 | 
			
		||||
            var ret = await UDPClientPool.WriteAddr(this.ep, 2, I2cAddr.TranConfig, ((uint)(length - 1)));
 | 
			
		||||
            if (!ret.IsSuccessful)
 | 
			
		||||
            {
 | 
			
		||||
                logger.Error($"Failed to configure transfer length: {ret.Error}");
 | 
			
		||||
                return new(ret.Error);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!ret.Value)
 | 
			
		||||
            {
 | 
			
		||||
                logger.Error("WriteAddr to TranConfig returned false");
 | 
			
		||||
                return new(new Exception("Failed to configure transfer length"));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 配置I2C地址、协议及启动传输(读操作)
 | 
			
		||||
        {
 | 
			
		||||
            var ret = await UDPClientPool.WriteAddr(
 | 
			
		||||
                this.ep, 2, I2cAddr.BaseConfig, (devAddr << 1) | (1 << 8) | (((uint)proto) << 16) | (1 << 24));
 | 
			
		||||
            if (!ret.IsSuccessful)
 | 
			
		||||
            {
 | 
			
		||||
                logger.Error($"Failed to configure I2C address/protocol/start: {ret.Error}");
 | 
			
		||||
                return new(ret.Error);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!ret.Value)
 | 
			
		||||
            {
 | 
			
		||||
                logger.Error("WriteAddr to BaseConfig returned false");
 | 
			
		||||
                return new(new Exception("Failed to configure I2C address/protocol/start"));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 等待I2C命令完成
 | 
			
		||||
        {
 | 
			
		||||
            var ret = await UDPClientPool.ReadAddrWithWait(this.ep, 2, I2cAddr.Flag, 0x0000_0001, 0xFFFF_FFFF);
 | 
			
		||||
            if (!ret.IsSuccessful)
 | 
			
		||||
            {
 | 
			
		||||
                logger.Error($"Failed to wait for I2C command completion: {ret.Error}");
 | 
			
		||||
                return new(ret.Error);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!ret.Value)
 | 
			
		||||
            {
 | 
			
		||||
                logger.Error("ReadAddrWithWait for I2C command completion returned false");
 | 
			
		||||
                return new(new Exception("I2C command did not complete successfully"));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 读取数据
 | 
			
		||||
        {
 | 
			
		||||
            var ret = await UDPClientPool.ReadAddr(this.ep, 2, I2cAddr.Read, length);
 | 
			
		||||
            if (!ret.IsSuccessful)
 | 
			
		||||
            {
 | 
			
		||||
                logger.Error($"Failed to read data from I2C FIFO: {ret.Error}");
 | 
			
		||||
                return new(ret.Error);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (ret.Value.Options.Data == null || ret.Value.Options.Data.Length != length)
 | 
			
		||||
            {
 | 
			
		||||
                logger.Error($"ReadAddr returned unexpected data length: {ret.Value.Options.Data?.Length ?? 0}");
 | 
			
		||||
                return new(new Exception("Failed to read expected amount of data from I2C FIFO"));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return ret.Value.Options.Data;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -2,6 +2,7 @@ using System.Collections;
 | 
			
		||||
using System.Net;
 | 
			
		||||
using DotNext;
 | 
			
		||||
using Newtonsoft.Json;
 | 
			
		||||
using server;
 | 
			
		||||
using WebProtocol;
 | 
			
		||||
 | 
			
		||||
namespace Peripherals.JtagClient;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										36
									
								
								server/src/Peripherals/OscilloscopeClient.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								server/src/Peripherals/OscilloscopeClient.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
			
		||||
using System.Net;
 | 
			
		||||
using DotNext;
 | 
			
		||||
 | 
			
		||||
namespace Peripherals.OscilloscopeClient;
 | 
			
		||||
 | 
			
		||||
static class OscilloscopeAddr
 | 
			
		||||
{
 | 
			
		||||
    public const UInt32 Base = 0x0000_0000;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class Oscilloscope
 | 
			
		||||
{
 | 
			
		||||
    private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
 | 
			
		||||
 | 
			
		||||
    readonly int timeout = 2000;
 | 
			
		||||
 | 
			
		||||
    readonly int port;
 | 
			
		||||
    readonly string address;
 | 
			
		||||
    private IPEndPoint ep;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 初始化示波器客户端
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="address">示波器设备IP地址</param>
 | 
			
		||||
    /// <param name="port">示波器设备端口</param>
 | 
			
		||||
    /// <param name="timeout">超时时间(毫秒)</param>
 | 
			
		||||
    public Oscilloscope(string address, int port, int timeout = 2000)
 | 
			
		||||
    {
 | 
			
		||||
        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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user