Files
2026-06-25 12:19:29 +03:00

134 lines
5.0 KiB
C#

using LibUsbDotNet.LibUsb;
using LibUsbDotNet.Main;
namespace RTCSync.Utils;
public static class I2CUtils
{
private const int VID = 0x1A86;
private const int PID = 0x5512; // CH341T
// Команды CH341 для I2C
private const byte CH341_CMD_I2C_STREAM = 0xAA;
private const byte CH341_CMD_I2C_STM_STA = 0x74; // START
private const byte CH341_CMD_I2C_STM_STO = 0x75; // STOP
private const byte CH341_CMD_I2C_STM_OUT = 0x80; // write byte (len в младших битах)
private const byte CH341_CMD_I2C_STM_IN = 0xC0; // read byte
private const byte CH341_CMD_I2C_STM_END = 0x00; // конец стрима
public static void ScanDevice(IUsbDevice device)
{
var writer = device.OpenEndpointWriter(WriteEndpointID.Ep02);
var reader = device.OpenEndpointReader(ReadEndpointID.Ep02);
Console.WriteLine("Сканирование I2C шины (0x03 - 0x77)...");
for (byte addr = 0x03; addr < 0x78; addr++)
{
// Пробуем послать START + адрес + STOP
// Если устройство есть — придёт ACK, если нет — NACK
var cmd = new byte[]
{
CH341_CMD_I2C_STREAM, // CH341_CMD_I2C_STREAM
CH341_CMD_I2C_STM_STA, // START
CH341_CMD_I2C_STM_OUT | 1, // OUT, 1 байт
(byte)(addr << 1), // адрес + write bit
CH341_CMD_I2C_STM_STO, // STOP
CH341_CMD_I2C_STM_END // END
};
writer.Write(cmd, 500, out int written);
var buf = new byte[4];
reader.Read(buf, 200, out int read);
// CH341 возвращает статус: 0x00 = ACK получен (устройство есть)
// Первый байт ответа — статус последней I2C операции
if (read > 0 && buf[0] == 0x00)
{
Console.WriteLine($" Найдено устройство: 0x{addr:X2}");
}
}
Console.WriteLine("Сканирование завершено.");
}
public static void CH341Init(IUsbDevice device)
{
Console.WriteLine("Пытаемся инициализировать устройство");
var writer = device.OpenEndpointWriter(WriteEndpointID.Ep02);
// Установка скорости I2C: 0x00=20kHz, 0x01=100kHz, 0x02=400kHz, 0x03=750kHz
var cmd = new byte[]
{
CH341_CMD_I2C_STREAM,
0x60 | 0x01, // CH341_CMD_I2C_STM_SET | 100kHz
CH341_CMD_I2C_STM_END
};
writer.Write(cmd, 1000, out _);
}
public static byte[] Read(IUsbDevice device, byte address, byte reg, int length)
{
// Формируем пакет: START → write addr+reg → RESTART → read → STOP
var cmd = new byte[]
{
CH341_CMD_I2C_STREAM,
CH341_CMD_I2C_STM_STA,
CH341_CMD_I2C_STM_OUT | 2, // 2 байта: адрес + регистр
(byte)(address << 1), // write
reg,
CH341_CMD_I2C_STM_STA, // repeated START
CH341_CMD_I2C_STM_OUT | 1,
(byte)((address << 1) | 1), // read
(byte)(CH341_CMD_I2C_STM_IN | (length - 1)),
CH341_CMD_I2C_STM_STO,
CH341_CMD_I2C_STM_END
};
var writer = device.OpenEndpointWriter(WriteEndpointID.Ep02);
var reader = device.OpenEndpointReader(ReadEndpointID.Ep02);
writer.Write(cmd, 1000, out _);
var buf = new byte[length];
reader.Read(buf, 1000, out var transferred);
return buf;
}
public static byte[] ReadWithRetry(IUsbDevice device, byte address, byte reg, int length)
{
for (var attempt = 0; attempt < 100; attempt++)
{
var result = Read(device, address, reg, length);
if (result[0] != 0x03)
return result;
Thread.Sleep(10);
}
throw new Exception("Ошибка чтения CH431 после 100 попыток");
}
public static void Write(IUsbDevice device, byte address, byte reg, byte[] data)
{
// START → write addr → write reg → write data[0..n] → STOP
// CH341_CMD_I2C_STM_OUT | N означает "записать N байт"
// N = 1 (адрес) + 1 (регистр) + data.Length
var cmd = new byte[5 + data.Length + 2];
int i = 0;
cmd[i++] = CH341_CMD_I2C_STREAM;
cmd[i++] = CH341_CMD_I2C_STM_STA;
cmd[i++] = (byte)(CH341_CMD_I2C_STM_OUT | (2 + data.Length)); // адрес + регистр + данные
cmd[i++] = (byte)(address << 1); // write bit = 0
cmd[i++] = reg;
foreach (var b in data)
cmd[i++] = b;
cmd[i++] = CH341_CMD_I2C_STM_STO;
cmd[i] = CH341_CMD_I2C_STM_END;
var writer = device.OpenEndpointWriter(WriteEndpointID.Ep02);
writer.Write(cmd, 1000, out _);
}
}