using ModbusSimulationProtocol.Interface; using NModbus; using System.Net; using System.Net.Sockets; using SlaveDataStore = ModbusSimulationProtocol.Data.SlaveDataStore; namespace ModbusSimulationProtocol.Services; public class ModbusSlaveService : IModbusSlaveService { private readonly IModbusLogger? _logger; private readonly ModbusFactory _factory; private readonly ISlaveDataStore _slaveDataStore; private IModbusTcpSlaveNetwork? _network; private bool disposedValue; public ModbusSlaveService(IModbusLogger? logger) { _logger = logger; _factory = new ModbusFactory(logger: _logger); _slaveDataStore = new SlaveDataStore(); } public ISlaveDataStore SlaveDataStore => _slaveDataStore; public bool Initialize(string ip, ushort port, byte slaveId = 1) { if (string.IsNullOrWhiteSpace(ip)) { WriteLog(LoggingLevel.Error, "Incorrect ip address."); return false; } if (_network is not null) { WriteLog(LoggingLevel.Warning, "The slave network has been created."); return false; } try { TcpListener listener = new(IPAddress.Parse(ip), (int)port); _network = _factory.CreateSlaveNetwork(listener); var slave = _factory.CreateSlave(slaveId, _slaveDataStore); _network.AddSlave(slave); WriteLog(LoggingLevel.Information, "Completed initailization."); return true; } catch (Exception ex) { WriteLog(LoggingLevel.Error, ex.ToString()); return false; } } public bool Open() { if (_network is null) { WriteLog(LoggingLevel.Error, "Performs initializing before doing any operation."); return false; } Task.Run(async () => { try { WriteLog(LoggingLevel.Information, "Starts Tcp Listening"); await _network.ListenAsync(); } catch (Exception ex) { WriteLog(LoggingLevel.Error, ex.ToString()); } }); return true; } public bool TryWriteValues(IPointSource source, ushort address, TPoint[] points) { if (_network is null) { WriteLog(LoggingLevel.Error, "Performs initializing before doing any operation."); return false; } try { source.WritePoints(address, points); return true; } catch (Exception ex) { WriteLog(LoggingLevel.Error, ex.ToString()); return false; } } public bool TryReadValues(IPointSource source, ushort address, ushort count, out TPoint[]? outPoints) { if (_network is null) { WriteLog(LoggingLevel.Error, "Performs initializing before doing any operation."); outPoints = null; return false; } try { outPoints = source.ReadPoints(address, count); return true; } catch (Exception ex) { WriteLog(LoggingLevel.Error, ex.ToString()); outPoints = null; return false; } } private void WriteLog(LoggingLevel loggingLevel, string log) { _logger?.Log(loggingLevel, $"[{nameof(ModbusSlaveService)}]:{log}"); } protected virtual void Dispose(bool disposing) { if (!disposedValue) { if (disposing) { // TODO: dispose managed state (managed objects) _network?.Dispose(); } // TODO: free unmanaged resources (unmanaged objects) and override finalizer // TODO: set large fields to null disposedValue = true; } } // // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources // ~ModbusSlaveService() // { // // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method // Dispose(disposing: false); // } public void Dispose() { // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method Dispose(disposing: true); GC.SuppressFinalize(this); } }