using System.Net; using DotNext; namespace Peripherals.I2cClient; static class I2cAddr { const UInt32 Base = 0x6000_0000; /// /// 0x0000_0000: /// [7:0] 本次传输的i2c地址(最高位总为0); /// [8] 1为读,0为写; /// [16] 1为SCCB协议,0为I2C协议; /// [24] 1为开启本次传输,自动置零 /// public const UInt32 BaseConfig = Base + 0x0000_0000; /// /// 0x0000_0001: /// [15:0] 本次传输的数据量(以字节为单位,0为传1个字节); /// [31:16] 若本次传输为读的DUMMY数据量(字节为单位,0为传1个字节) /// public const UInt32 TranConfig = Base + 0x0000_0001; /// /// 0x0000_0002: [0] cmd_done; [8] cmd_error; /// public const UInt32 Flag = Base + 0x0000_0002; /// /// 0x0000_0003: FIFO写入口,仅低8位有效,只写 /// public const UInt32 Write = Base + 0x0000_0003; /// /// 0x0000_0004: FIFO读出口,仅低8位有效,只读 /// public const UInt32 Read = Base + 0x0000_0004; /// /// 0x0000_0005: [0] FIFO写入口清空;[8] FIFO读出口清空; /// public const UInt32 Clear = Base + 0x0000_0005; } /// /// [TODO:Enum] /// public enum I2cProtocol { /// /// [TODO:Enum] /// I2c = 0, /// /// [TODO:Enum] /// SCCB = 1 } /// /// [TODO:description] /// public class I2c { private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); readonly int timeout = 2000; readonly int taskID; readonly int port; readonly string address; private IPEndPoint ep; /// /// [TODO:description] /// /// [TODO:parameter] /// [TODO:parameter] /// [TODO:parameter] /// [TODO:parameter] /// [TODO:return] public I2c(string address, int port, int taskID, int timeout = 2000) { if (timeout < 0) throw new ArgumentException("Timeout couldn't be negative", nameof(timeout)); this.address = address; this.taskID = taskID; this.port = port; this.ep = new IPEndPoint(IPAddress.Parse(address), port); this.timeout = timeout; } /// /// 向指定I2C设备写入数据 /// /// I2C设备地址 /// 要写入的数据 /// I2C协议类型 /// 操作结果,成功返回true,否则返回异常信息 public async ValueTask> 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服务器接收缓冲区 MsgBus.UDPServer.ClearUDPData(this.address, this.taskID); logger.Trace($"Clear up udp server {this.address} receive data"); // 写入数据到I2C FIFO写入口 { var i2cData = new byte[data.Length * 4]; int i = 0; foreach (var item in data) { i2cData[i++] = 0x00; i2cData[i++] = 0x00; i2cData[i++] = 0x00; i2cData[i++] = item; } var ret = await UDPClientPool.WriteAddr(this.ep, this.taskID, I2cAddr.Write, i2cData); 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, this.taskID, 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, this.taskID, I2cAddr.BaseConfig, (devAddr) | (((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, this.taskID, I2cAddr.Flag, 0x0000_0001, 0xFFFF_FFFF, 10); 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; } /// /// 从指定I2C设备读取数据 /// /// I2C设备地址 /// 要写入的数据(dummy数据) /// 要读取的数据长度 /// I2C协议类型 /// 操作结果,成功返回读取到的数据,否则返回异常信息 public async ValueTask> ReadData(UInt32 devAddr, byte[] data, int dataReadLength, I2cProtocol proto) { if (dataReadLength < 1 || dataReadLength > 0x0000_FFFF) { logger.Error($"Read length {dataReadLength} is invalid or exceeds maximum allowed 0x0000_FFFF"); return new(new ArgumentException($"Read length {dataReadLength} is invalid or exceeds maximum allowed 0x0000_FFFF")); } 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服务器接收缓冲区 MsgBus.UDPServer.ClearUDPData(this.address, this.taskID); logger.Trace($"Clear up udp server {this.address} receive data"); // 配置写FIFO内容,内容为data[] { var i2cData = new byte[data.Length * 4]; int i = 0; foreach (var item in data) { i2cData[i++] = 0x00; i2cData[i++] = 0x00; i2cData[i++] = 0x00; i2cData[i++] = item; } var ret = await UDPClientPool.WriteAddr(this.ep, this.taskID, I2cAddr.Write, i2cData); 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")); } } // 配置本次传输数据量:[15:0]为读长度(length-1),[31:16]为dummy长度(data.Length-1) { uint tranConfig = ((uint)(dataReadLength - 1)) | (((uint)(data.Length - 1)) << 16); var ret = await UDPClientPool.WriteAddr(this.ep, this.taskID, I2cAddr.TranConfig, tranConfig); 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, this.taskID, I2cAddr.BaseConfig, (devAddr) | (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, this.taskID, I2cAddr.Flag, 0x0000_0001, 0xFFFF_FFFF, 10); 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, this.taskID, I2cAddr.Read); if (!ret.IsSuccessful) { logger.Error($"Failed to read data from I2C FIFO: {ret.Error}"); return new(ret.Error); } if (ret.Value.Options.Data == null) { 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[3..]; // 返回读取到的数据,跳过前3个字节 } } }