143 lines
4.2 KiB
C#
143 lines
4.2 KiB
C#
using System.IO.Ports;
|
|
using System.Text;
|
|
|
|
namespace InverterMon.Server.InverterService;
|
|
|
|
public static class Inverter
|
|
{
|
|
static SerialPort? _serialPort;
|
|
static FileStream? _fileStream;
|
|
|
|
public static bool Connect(string devicePath, ILogger logger)
|
|
{
|
|
try
|
|
{
|
|
if (devicePath.Contains("/hidraw", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
_fileStream = new(devicePath, FileMode.Open, FileAccess.ReadWrite);
|
|
|
|
return true;
|
|
}
|
|
|
|
if (devicePath.Contains("/ttyUSB", StringComparison.OrdinalIgnoreCase) || devicePath.Contains("COM", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
_serialPort = new(devicePath)
|
|
{
|
|
BaudRate = 2400,
|
|
Parity = Parity.None,
|
|
DataBits = 8,
|
|
StopBits = StopBits.One,
|
|
Handshake = Handshake.None
|
|
};
|
|
_serialPort.Open();
|
|
|
|
return true;
|
|
}
|
|
logger.LogError("device path [{path}] is not acceptable!", devicePath);
|
|
}
|
|
catch (Exception x)
|
|
{
|
|
logger.LogError("connection error at [{path}]. reason: [{reason}]", devicePath, x.Message);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public static void Disconnect()
|
|
{
|
|
_serialPort?.Close();
|
|
_serialPort?.Dispose();
|
|
_fileStream?.Close();
|
|
_fileStream?.Dispose();
|
|
}
|
|
|
|
static readonly byte[] _writeBuffer = new byte[512];
|
|
|
|
public static Task Write(string command, CancellationToken ct)
|
|
{
|
|
var cmdBytes = Encoding.ASCII.GetBytes(command);
|
|
var crc = CalculateXmodemCrc16(command);
|
|
|
|
Buffer.BlockCopy(cmdBytes, 0, _writeBuffer, 0, cmdBytes.Length);
|
|
_writeBuffer[cmdBytes.Length] = (byte)(crc >> 8);
|
|
_writeBuffer[cmdBytes.Length + 1] = (byte)(crc & 0xff);
|
|
_writeBuffer[cmdBytes.Length + 2] = 0x0d;
|
|
|
|
if (_fileStream != null)
|
|
return _fileStream.WriteAsync(_writeBuffer, 0, cmdBytes.Length + 3, ct);
|
|
|
|
return _serialPort != null
|
|
? _serialPort.BaseStream.WriteAsync(_writeBuffer, 0, cmdBytes.Length + 3, ct)
|
|
: Task.CompletedTask;
|
|
}
|
|
|
|
static readonly byte[] _readBuffer = new byte[1024];
|
|
|
|
public static async Task<string> Read(CancellationToken ct)
|
|
{
|
|
var pos = 0;
|
|
const byte eol = 0x0d;
|
|
|
|
if (_fileStream != null)
|
|
{
|
|
do
|
|
{
|
|
var readCount = await _fileStream.ReadAsync(_readBuffer.AsMemory(pos, _readBuffer.Length - pos), ct);
|
|
|
|
if (readCount > 0)
|
|
{
|
|
pos += readCount;
|
|
|
|
for (var i = pos - readCount; i < pos; i++)
|
|
{
|
|
if (_readBuffer[i] == eol)
|
|
return Encoding.ASCII.GetString(_readBuffer, 0, i - 2).Sanitize();
|
|
}
|
|
}
|
|
} while (pos < _readBuffer.Length);
|
|
}
|
|
else if (_serialPort != null)
|
|
{
|
|
do
|
|
{
|
|
var readCount = await _serialPort.BaseStream.ReadAsync(_readBuffer.AsMemory(pos, _readBuffer.Length - pos), ct);
|
|
|
|
if (readCount > 0)
|
|
{
|
|
pos += readCount;
|
|
|
|
for (var i = pos - readCount; i < pos; i++)
|
|
{
|
|
if (_readBuffer[i] == eol)
|
|
return Encoding.ASCII.GetString(_readBuffer, 0, i - 2).Sanitize();
|
|
}
|
|
}
|
|
} while (pos < _readBuffer.Length);
|
|
}
|
|
else
|
|
throw new InvalidOperationException("inverter not connected.");
|
|
|
|
throw new InvalidOperationException("buffer overflow.");
|
|
}
|
|
|
|
static ushort CalculateXmodemCrc16(string data)
|
|
{
|
|
ushort crc = 0;
|
|
var length = data.Length;
|
|
|
|
for (var i = 0; i < length; i++)
|
|
{
|
|
crc ^= (ushort)(data[i] << 8);
|
|
|
|
for (var j = 0; j < 8; j++)
|
|
{
|
|
if ((crc & 0x8000) != 0)
|
|
crc = (ushort)((crc << 1) ^ 0x1021);
|
|
else
|
|
crc <<= 1;
|
|
}
|
|
}
|
|
|
|
return crc;
|
|
}
|
|
} |