2026-01-26 14:51:28 +09:00

395 lines
13 KiB
C#

using Aurora.Api;
using Aurora.Api.Devices;
using Hermes;
using NModbus;
using NModbus.Serial;
using System;
using System.IO.Ports;
using System.Linq;
using System.Net.Sockets;
namespace AuroraDeviceCommon
{
public class ModbusConn : IModbus
{
private static readonly Logger LOG = new Logger("Modbus");
private SerialPort _SerialPort;
private TcpClient _TcpClient;
private IModbusMaster _ModbusMaster;
private int _Slave;
public ModbusConn()
{
}
public int Connect(IDeviceConfig config)
{
int err = E2.INVALID_ARGUMENT;
if (config.ConnConfig is ModbusTcpIpConnConfig tcpipConfig) {
_Slave = tcpipConfig.Slave;
err = ActiveTcpIp(tcpipConfig);
} else if (config.ConnConfig is ModbusSerialConnConfig serialConfig) {
_Slave = serialConfig.Slave;
err = ActiveSerial(serialConfig);
} else {
LOG.W($"Warning : wrong config {config}");
}
return err;
}
public int Disconnect()
{
_SerialPort?.Close();
_TcpClient?.Close();
_ModbusMaster?.Dispose();
return E1.OK;
}
SerialPort CreateSerialPort(SerialConnConfig config)
=> new SerialPort {
PortName = $"COM{config.PortNum}",
BaudRate = config.BaudRate,
Parity = config.Parity,
StopBits = config.StopBits,
DataBits = config.DataBits,
//RtsEnable = true,
ReadTimeout = config.ReadTimeout,
WriteTimeout = config.WriteTimeout,
};
int ConnectSerial(SerialPort serialPort)
{
try {
serialPort.Open();
return E1.OK;
} catch (Exception e) {
LOG.E(e.ToString());
return E1.NETWORK;
}
}
TcpClient ConnectTcpIp(ModbusTcpIpConnConfig config)
{
try {
var tcpClient = new TcpClient(config.Address.IpAddress
, config.Address.PortNumber);
return tcpClient;
} catch (Exception e) {
LOG.E(e.ToString());
return null;
}
}
internal int ActiveSerial(ModbusSerialConnConfig config)
{
_Slave = config.Slave;
_SerialPort?.Close();
_SerialPort = CreateSerialPort(config);
int err = ConnectSerial(_SerialPort);
if (err != E1.OK)
return err;
var factory = new ModbusFactory();
_ModbusMaster = factory.CreateRtuMaster(_SerialPort);
if (_ModbusMaster == null) {
LOG.E($"ERROR: fail to init modbus ");
return E.C(E1.NETWORK, E2.NOT_CONNECTED);
}
return E1.OK;
}
internal int ActiveTcpIp(ModbusTcpIpConnConfig config)
{
_Slave = config.Slave;
_TcpClient?.Close();
_TcpClient = ConnectTcpIp(config);
if (_TcpClient == null)
return E1.NETWORK;
var factory = new ModbusFactory();
_ModbusMaster = factory.CreateMaster(_TcpClient);
if (_ModbusMaster == null) {
LOG.E($"ERROR: fail to init modbus ");
return E.C(E1.NETWORK, E2.NOT_CONNECTED);
}
return E1.OK;
}
public int WriteBit(ushort address, bool bit)
=> WriteBit_NOLOCK(address, bit);
public int WriteWord(ushort address, short value)
=> WriteSingle_NOLOCK(address, (ushort)value);
public int WriteDoubleWord(ushort address, int value)
=> WriteFloat_NOLOCK(address, value);
public int WriteReal(ushort address, float word)
=> WriteFloat_NOLOCK(address, word);
public int WriteBitBlock(ushort address, bool[] bits)
{
try {
_ModbusMaster.WriteMultipleCoils(
BitConverter.GetBytes(_Slave)[0],
address,
bits
);
return E1.OK;
} catch (Exception e) {
LOG.E($"ERROR: fail to write registers - address: 0x{address:X}\n{e}");
return E1.NETWORK;
}
}
public int WriteWordBlock(ushort address, short[] words)
{
try {
_ModbusMaster.WriteMultipleRegisters(
BitConverter.GetBytes(_Slave)[0],
address,
words?.Select(b => (ushort)b).ToArray()
);
return E1.OK;
} catch (Exception e) {
LOG.E($"ERROR: fail to write registers - address: 0x{address:X}\n{e}");
return E1.NETWORK;
}
}
public (int err, bool value) ReadBit(ushort address)
{
(int err, bool[] value) = ReadBit_NOLOCK(address);
return (err, value[0]);
}
public (int err, bool value) ReadInputBit(ushort address)
{
(int err, bool[] value) = ReadInputBit_NOLOCK(address);
return (err, value[0]);
}
public (int err, short value) ReadWord(ushort address)
{
(int err, ushort value) = ReadSingle_NOLOCK(address);
return (err, (short)value);
}
public (int err, short value) ReadInputWord(ushort address)
{
(int err, ushort value) = ReadSingleInput_NOLOCK(address);
return (err, (short)value);
}
public (int err, int value) ReadDoubleWord(ushort address)
{
(int err, float value) = ReadFloat_NOLOCK(address);
return (err, (int)value);
}
public (int err, float value) ReadReal(ushort address)
=> ReadFloat_NOLOCK(address);
public (int err, bool[] bits) ReadBitBlock(ushort address, int count)
=> ReadBit_NOLOCK(address, (ushort)count);
public (int err, bool[] bits) ReadInputBitBlock(ushort address, int count)
=> ReadInputBit_NOLOCK(address, (ushort)count);
public (int err, short[] words) ReadWordBlock(ushort address, int count)
{
(int err, ushort[] words) = ReadMulti_NOLOCK(address, (ushort)count);
return (err, words?.Select(b => (short)b).ToArray());
}
public (int err, short[] words) ReadInputWordBlock(ushort address, int count)
{
(int err, ushort[] words) = ReadMultiInput_NOLOCK(address, (ushort)count);
return (err, words?.Select(b => (short)b).ToArray());
}
internal (int err, ushort[] value) ReadMulti_NOLOCK(ushort address, ushort count)
{
var values = Read_NOLOCK(address, count);
return (
err: values != null ? E1.OK : E1.NETWORK,
value: values
);
}
internal (int err, ushort[] value) ReadMultiInput_NOLOCK(ushort address, ushort count)
{
var values = ReadInput_NOLOCK(address, count);
return (
err: values != null ? E1.OK : E1.NETWORK,
value: values
);
}
internal int WriteBit_NOLOCK(ushort address, bool value)
{
try {
_ModbusMaster.WriteSingleCoil(
BitConverter.GetBytes(_Slave)[0],
address,
value
);
return E1.OK;
} catch (Exception e) {
LOG.E($"ERROR: fail to write bit - address: 0x{address:X}\n{e.ToString()}");
return E1.NETWORK;
}
}
internal int WriteSingle_NOLOCK(ushort address, ushort value)
{
try {
_ModbusMaster.WriteSingleRegister(
BitConverter.GetBytes(_Slave)[0],
address,
value
);
return E1.OK;
} catch (Exception e) {
LOG.E($"ERROR: fail to write word - address: 0x{address:X}\n{e.ToString()}");
return E1.NETWORK;
}
}
internal int WriteFloat_NOLOCK(ushort address, float value)
{
var bytes = BitConverter.GetBytes(value);
var ushorts = new[] {
(ushort)(bytes[1] << 8 | bytes[0]),
(ushort)(bytes[3] << 8 | bytes[2]),
};
return WriteRegisters_NOLOCK(address, ushorts);
}
internal int WriteRegisters_NOLOCK(ushort address, params ushort[] values)
{
try {
_ModbusMaster.WriteMultipleRegisters(
BitConverter.GetBytes(_Slave)[0],
address,
values
);
return E1.OK;
} catch (Exception e) {
LOG.E($"ERROR: fail to write registers - address: 0x{address:X}\n{e.ToString()}");
return E1.NETWORK;
}
}
internal (int err, bool[] value) ReadBit_NOLOCK(ushort address, ushort count = 1)
{
bool[] values = null;
try {
values = _ModbusMaster.ReadCoils(
BitConverter.GetBytes(_Slave)[0],
address,
count
);
} catch (Exception) {
LOG.E($"ERROR: fail to read word - address: 0x{address:X}");
}
return (
err: values != null ? E1.OK : E1.NETWORK,
value: values
);
}
internal (int err, bool[] value) ReadInputBit_NOLOCK(ushort address, ushort count = 1)
{
bool[] values = null;
try {
values = _ModbusMaster.ReadInputs(
BitConverter.GetBytes(_Slave)[0],
address,
count
);
} catch (Exception) {
LOG.E($"ERROR: fail to read word - address: 0x{address:X}");
}
return (
err: values != null ? E1.OK : E1.NETWORK,
value: values
);
}
internal (int err, ushort value) ReadSingle_NOLOCK(ushort address)
{
var values = Read_NOLOCK(address, 1);
return (
err: values != null ? E1.OK : E1.NETWORK,
value: values[0]
);
}
internal (int err, ushort value) ReadSingleInput_NOLOCK(ushort address)
{
var values = Read_NOLOCK(address, 1);
return (
err: values != null ? E1.OK : E1.NETWORK,
value: values[0]
);
}
internal (int err, float value) ReadFloat_NOLOCK(ushort address)
{
var values = Read_NOLOCK(address, 2);
var bytes = new[] {
(byte)(values[0] & 0xFF),
(byte)(values[0] >> 8 & 0xFF),
(byte)(values[1] & 0xFF),
(byte)(values[1] >> 8 & 0xFF),
};
return (
err: values != null ? E1.OK : E1.NETWORK,
value: BitConverter.ToSingle(bytes, 0)
);
}
internal ushort[] Read_NOLOCK(ushort address, ushort count)
{
ushort[] values = null;
try {
values = _ModbusMaster.ReadHoldingRegisters(
BitConverter.GetBytes(_Slave)[0],
address,
count
);
if (values?.Length != count) {
LOG.E($"ERROR: fail to read word - address: 0x{address:X} count: {count}");
return null;
}
} catch (Exception e) {
LOG.E($"ERROR: fail to read word - address: 0x{address:X} count: {count}\n{e.ToString()}");
}
return values;
}
internal ushort[] ReadInput_NOLOCK(ushort address, ushort count)
{
ushort[] values = null;
try {
values = _ModbusMaster.ReadInputRegisters(
BitConverter.GetBytes(_Slave)[0],
address,
count
);
if (values?.Length != count) {
LOG.E($"ERROR: fail to read word - address: 0x{address:X} count: {count}");
return null;
}
} catch (Exception e) {
LOG.E($"ERROR: fail to read word - address: 0x{address:X} count: {count}\n{e.ToString()}");
}
return values;
}
}
}