using InnovEnergy.Lib.Protocols.Modbus.Reflection; using InnovEnergy.Lib.Protocols.Modbus.Reflection.Attributes; namespace InnovEnergy.Lib.Protocols.Modbus.Clients; public class ModbusSlave 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 ReadDiscreteInputs(Object statusRecord) { return from batch in statusRecord.GetModbusBooleanBatches() 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 ReadCoils(Object statusRecord) { return from batch in statusRecord.GetModbusBooleanBatches() 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 ReadInputRegisters(Object statusRecord) { return from batch in statusRecord.GetModbusRegisterBatches() 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 ReadHoldingRegisters(Object statusRecord) { return from batch in statusRecord.GetModbusRegisterBatches() 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()) { 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()) { var values = batch.GetRawModbusValuesFromControlRecord(); _ModbusClient.WriteRegisters(batch[0].Address, values); nBatches++; } return nBatches; } } public class ModbusSlave : ModbusSlave where T : notnull, new() { public ModbusSlave(ModbusClient modbusClient) : base(modbusClient) { } } public static class ModbusSlave { public static ModbusSlave Slave(this ModbusClient modbusClient) where T : notnull, new() { return new ModbusSlave(modbusClient); } public static ModbusSlave Slave(this ModbusClient modbusClient) where S : notnull, new() where C : notnull { return new ModbusSlave(modbusClient); } }