using ModbusSimulationProtocol.Data; using ModbusSimulationProtocol.Interface; using NModbus; using System.Net; using System.Net.Sockets; namespace ModbusSimulationProtocol.Services; public class ModbusSlaveService : IModbusSlaveService, IDisposable { private readonly IModbusLogger? _logger; private readonly ModbusFactory _factory; private IModbusTcpSlaveNetwork? _network = null; private bool disposedValue; public ModbusSlaveService(IModbusLogger? logger) { _logger = logger; _factory = new ModbusFactory(logger: _logger); } public void Initialize(string ip, ushort port) { ArgumentNullException.ThrowIfNullOrWhiteSpace(ip); if (_network is not null) { WriteLog(LoggingLevel.Information, "The slave network has been created."); return; } try { TcpListener listener = new TcpListener(IPAddress.Parse(ip), (int)port); _network = _factory.CreateSlaveNetwork(listener); } catch (Exception ex) { WriteLog(LoggingLevel.Error, ex.ToString()); } } public void ActivateNetwork() { if (_network is null) { WriteLog(LoggingLevel.Warning, "Performs initializing before activating network."); return; } Task.Run(async () => { try { WriteLog(LoggingLevel.Information, $"Starts async listening."); await _network.ListenAsync(); } catch (Exception ex) { WriteLog(LoggingLevel.Error, ex.ToString()); } }); } public void AddSlave(byte slaveId, int coilCount, int discreteInputCount, int holdingRegisterCount, int inputRegisterCount) { if (_network is null) { WriteLog(LoggingLevel.Warning, "Performs initializing before adding any slave."); return; } try { var slave = _factory.CreateSlave(slaveId, new SlaveDataStore(coilCount, discreteInputCount, holdingRegisterCount, inputRegisterCount)); _network.AddSlave(slave); } catch (Exception ex) { WriteLog(LoggingLevel.Error, ex.ToString()); } } public void RemoveSlave(byte slaveId) { if (_network is null) { WriteLog(LoggingLevel.Warning, "The slave network do not exist even."); return; } if (_network.GetSlave(slaveId) is null) { WriteLog(LoggingLevel.Warning, "The specified slave do not exist. Failed to remove."); return; } try { _network.RemoveSlave(slaveId); WriteLog(LoggingLevel.Information, $"The slave {slaveId} has been removed."); } catch (Exception ex) { WriteLog(LoggingLevel.Error, ex.ToString()); } } public int GetConnectedMasterCount() { if (_network is null) { WriteLog(LoggingLevel.Warning, "The slave network do not exist even."); return 0; } return _network.Masters.Count; } 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(); _network = null; } // 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); } }