FPGA_WebLab/server/src/Peripherals/I2cClient.cs

316 lines
11 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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_0004;
/// <summary>
/// 0x0000_0005: [0] FIFO写入口清空[8] FIFO读出口清空
/// </summary>
public const UInt32 Clear = Base + 0x0000_0005;
}
/// <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 taskID;
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="taskID">[TODO:parameter]</param>
/// <param name="timeout">[TODO:parameter]</param>
/// <returns>[TODO:return]</returns>
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;
}
/// <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服务器接收缓冲区
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;
}
/// <summary>
/// 从指定I2C设备读取数据
/// </summary>
/// <param name="devAddr">I2C设备地址</param>
/// <param name="data">要写入的数据dummy数据</param>
/// <param name="dataReadLength">要读取的数据长度</param>
/// <param name="proto">I2C协议类型</param>
/// <returns>操作结果,成功返回读取到的数据,否则返回异常信息</returns>
public async ValueTask<Result<byte[]>> 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个字节
}
}
}