159 lines
4.8 KiB
C#
159 lines
4.8 KiB
C#
using InnovEnergy.Lib.Protocols.Modbus.Reflection;
|
|
using InnovEnergy.Lib.Protocols.Modbus.Reflection.Attributes;
|
|
|
|
namespace InnovEnergy.Lib.Protocols.Modbus.Clients;
|
|
|
|
public class ModbusSlave<S, C> where S : notnull, new() where C : notnull
|
|
{
|
|
private readonly ModbusClient _ModbusClient;
|
|
|
|
public ModbusSlave(ModbusClient modbusClient) => _ModbusClient = modbusClient;
|
|
|
|
public S? Read()
|
|
{
|
|
try
|
|
{
|
|
return ReadInto(new S());
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
return default; // TODO :stdErr
|
|
}
|
|
}
|
|
|
|
public Exception? Write(C controlRecord)
|
|
{
|
|
try
|
|
{
|
|
WriteHoldingRegisters(controlRecord);
|
|
WriteCoils(controlRecord);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
_ModbusClient.Connection.Close();
|
|
return e;
|
|
}
|
|
|
|
return default;
|
|
}
|
|
|
|
|
|
public S ReadInto(S statusRecord)
|
|
{
|
|
Int32 holdingRegisters;
|
|
Int32 coils;
|
|
Int32 inputRegisters;
|
|
Int32 discreteInputs;
|
|
|
|
try
|
|
{
|
|
holdingRegisters = ReadHoldingRegisters(statusRecord).Count(); // force enumeration!
|
|
inputRegisters = ReadInputRegisters(statusRecord).Count();
|
|
discreteInputs = ReadDiscreteInputs(statusRecord).Count();
|
|
coils = ReadCoils(statusRecord).Count();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
_ModbusClient.Connection.Close();
|
|
throw;
|
|
}
|
|
|
|
|
|
var nUpdated = holdingRegisters
|
|
+ inputRegisters
|
|
+ discreteInputs
|
|
+ coils;
|
|
|
|
if (nUpdated == 0)
|
|
throw new ArgumentException(nameof(statusRecord));
|
|
|
|
return statusRecord;
|
|
}
|
|
|
|
// returns an enumerable of read addresses
|
|
private IEnumerable<UInt16> ReadDiscreteInputs(Object statusRecord)
|
|
{
|
|
return from batch in statusRecord.GetModbusBooleanBatches<DiscreteInputAttribute>()
|
|
let received = _ModbusClient.ReadDiscreteInputs(batch[0].Address, (UInt16)batch.Length)
|
|
from address in batch.SetStatusRecordMembersFromRawModbusValues(received)
|
|
select address;
|
|
}
|
|
|
|
// returns an enumerable of read addresses
|
|
private IEnumerable<UInt16> ReadCoils(Object statusRecord)
|
|
{
|
|
return from batch in statusRecord.GetModbusBooleanBatches<CoilAttribute>()
|
|
let received = _ModbusClient.ReadCoils(batch[0].Address, (UInt16)batch.Length)
|
|
from address in batch.SetStatusRecordMembersFromRawModbusValues(received)
|
|
select address;
|
|
}
|
|
|
|
// returns an enumerable of read addresses
|
|
private IEnumerable<UInt16> ReadInputRegisters(Object statusRecord)
|
|
{
|
|
return from batch in statusRecord.GetModbusRegisterBatches<InputRegisterAttribute>()
|
|
let received = _ModbusClient.ReadInputRegisters(batch[0].Address, (UInt16)batch.Length)
|
|
from address in batch.SetStatusRecordMembersFromRawModbusValues(received)
|
|
select address;
|
|
}
|
|
|
|
// returns an enumerable of read addresses
|
|
private IEnumerable<UInt16> ReadHoldingRegisters(Object statusRecord)
|
|
{
|
|
return from batch in statusRecord.GetModbusRegisterBatches<HoldingRegisterAttribute>()
|
|
let received = _ModbusClient.ReadHoldingRegisters(batch[0].Address, (UInt16)batch.Length)
|
|
from address in batch.SetStatusRecordMembersFromRawModbusValues(received)
|
|
select address;
|
|
}
|
|
|
|
private Int32 WriteCoils(C controlRecord)
|
|
{
|
|
var nBatches = 0;
|
|
|
|
foreach (var batch in controlRecord.GetModbusBooleanBatches<CoilAttribute>())
|
|
{
|
|
var values = batch.GetRawModbusValuesFromControlRecord();
|
|
_ModbusClient.WriteCoils(batch[0].Address, values);
|
|
nBatches++;
|
|
}
|
|
|
|
return nBatches;
|
|
}
|
|
|
|
|
|
private Int32 WriteHoldingRegisters(C controlRecord)
|
|
{
|
|
var nBatches = 0;
|
|
|
|
foreach (var batch in controlRecord.GetModbusRegisterBatches<HoldingRegisterAttribute>())
|
|
{
|
|
var values = batch.GetRawModbusValuesFromControlRecord();
|
|
_ModbusClient.WriteRegisters(batch[0].Address, values);
|
|
nBatches++;
|
|
}
|
|
|
|
return nBatches;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
public class ModbusSlave<T> : ModbusSlave<T, T> where T : notnull, new()
|
|
{
|
|
public ModbusSlave(ModbusClient modbusClient) : base(modbusClient)
|
|
{
|
|
}
|
|
}
|
|
|
|
public static class ModbusSlave
|
|
{
|
|
public static ModbusSlave<T> Slave<T>(this ModbusClient modbusClient) where T : notnull, new()
|
|
{
|
|
return new ModbusSlave<T>(modbusClient);
|
|
}
|
|
|
|
public static ModbusSlave<S,C> Slave<S,C>(this ModbusClient modbusClient) where S : notnull, new() where C : notnull
|
|
{
|
|
return new ModbusSlave<S, C>(modbusClient);
|
|
}
|
|
} |