internal static void AssertModbusMessagePropertiesAreEqual(IModbusMessage obj1, IModbusMessage obj2) { Assert.AreEqual(obj1.FunctionCode, obj2.FunctionCode); Assert.AreEqual(obj1.SlaveAddress, obj2.SlaveAddress); Assert.AreEqual(obj1.MessageFrame, obj2.MessageFrame); Assert.AreEqual(obj1.ProtocolDataUnit, obj2.ProtocolDataUnit); }
public void ValidateResponse(IModbusMessage response) { ReadHoldingInputRegistersResponse typedResponse = (ReadHoldingInputRegistersResponse) response; int expectedByteCount = ReadRequest.NumberOfPoints * 2; if (expectedByteCount != typedResponse.ByteCount) { throw new IOException(String.Format(CultureInfo.InvariantCulture, "Unexpected byte count in response. Expected {0}, received {1}.", expectedByteCount, typedResponse.ByteCount)); } }
public void ValidateResponse(IModbusMessage response) { ReadCoilsInputsResponse typedResponse = (ReadCoilsInputsResponse) response; // best effort validation - the same response for a request for 1 vs 6 coils (same byte count) will pass validation. int expectedByteCount = (NumberOfPoints + 7) / 8; if (expectedByteCount != typedResponse.ByteCount) { throw new IOException(String.Format(CultureInfo.InvariantCulture, "Unexpected byte count. Expected {0}, received {1}.", expectedByteCount, typedResponse.ByteCount)); } }
public void ValidateResponse(IModbusMessage response) { var typedResponse = response as ReadHoldingInputRegistersResponse; Debug.Assert(typedResponse != null, "Argument response should be of type ReadHoldingInputRegistersResponse."); var expectedByteCount = NumberOfPoints * 2; if (expectedByteCount != typedResponse.ByteCount) { throw new IOException(String.Format(CultureInfo.InvariantCulture, "Unexpected byte count. Expected {0}, received {1}.", expectedByteCount, typedResponse.ByteCount)); } }
internal virtual T UnicastMessage <T>(IModbusMessage message) where T : IModbusMessage, new() { IModbusMessage response = null; int attempt = 1; bool success = false; do { try { lock (_syncLock) { Write(message); bool readAgain; do { readAgain = false; response = ReadResponse <T>(); if (response is SlaveExceptionResponse exceptionResponse) { // if SlaveExceptionCode == ACKNOWLEDGE we retry reading the response without resubmitting request readAgain = exceptionResponse.SlaveExceptionCode == Modbus.Acknowledge; if (readAgain) { Debug.WriteLine($"Received ACKNOWLEDGE slave exception response, waiting {_waitToRetryMilliseconds} milliseconds and retrying to read response."); Sleep(WaitToRetryMilliseconds); } else { throw new SlaveException(exceptionResponse); } } else if (ShouldRetryResponse(message, response)) { readAgain = true; } }while (readAgain); } ValidateResponse(message, response); success = true; } catch (SlaveException se) { if (se.SlaveExceptionCode != Modbus.SlaveDeviceBusy) { throw; } if (SlaveBusyUsesRetryCount && attempt++ > _retries) { throw; } Debug.WriteLine($"Received SLAVE_DEVICE_BUSY exception response, waiting {_waitToRetryMilliseconds} milliseconds and resubmitting request."); Sleep(WaitToRetryMilliseconds); } catch (Exception e) { if (e is FormatException || e is NotImplementedException || e is TimeoutException || e is IOException) { Debug.WriteLine($"{e.GetType().Name}, {_retries - attempt + 1} retries remaining - {e}"); if (attempt++ > _retries) { throw; } } else { throw; } } }while (!success); return((T)response); }
// TODO unit test internal IModbusMessage ApplyRequest(IModbusMessage request) { IModbusMessage response; _log.Info(request.ToString()); switch (request.FunctionCode) { case Modbus.ReadCoils: response = ReadDiscretes((ReadCoilsInputsRequest) request, DataStore.CoilDiscretes); break; case Modbus.ReadInputs: response = ReadDiscretes((ReadCoilsInputsRequest) request, DataStore.InputDiscretes); break; case Modbus.ReadHoldingRegisters: response = ReadRegisters((ReadHoldingInputRegistersRequest) request, DataStore.HoldingRegisters); break; case Modbus.ReadInputRegisters: response = ReadRegisters((ReadHoldingInputRegistersRequest) request, DataStore.InputRegisters); break; case Modbus.WriteSingleCoil: response = WriteSingleCoil((WriteSingleCoilRequestResponse) request, DataStore.CoilDiscretes); break; case Modbus.WriteSingleRegister: response = WriteSingleRegister((WriteSingleRegisterRequestResponse) request, DataStore.HoldingRegisters); break; case Modbus.Diagnostics: response = request; break; case Modbus.WriteMultipleCoils: response = WriteMultipleCoils((WriteMultipleCoilsRequest) request, DataStore.CoilDiscretes); break; case Modbus.WriteMultipleRegisters: response = WriteMultipleRegisters((WriteMultipleRegistersRequest) request, DataStore.HoldingRegisters); break; case Modbus.ReadWriteMultipleRegisters: ReadWriteMultipleRegistersRequest readWriteRequest = (ReadWriteMultipleRegistersRequest) request; WriteMultipleRegisters(readWriteRequest.WriteRequest, DataStore.HoldingRegisters); response = ReadRegisters(readWriteRequest.ReadRequest, DataStore.HoldingRegisters); break; default: string errorMessage = String.Format("Unsupported function code {0}", request.FunctionCode); _log.Error(errorMessage); throw new ArgumentException(errorMessage, "request"); } return response; }
internal override void OnValidateResponse(IModbusMessage request, IModbusMessage response) { // no-op }
internal override void Write(IModbusMessage message) { throw new NotImplementedException(); }
public IModbusMessage HandleSlaveRequest(IModbusMessage request, ISlaveDataStore dataStore) { Console.WriteLine("HMI Buffer Message Receieved"); throw new NotImplementedException(); }
private Task PerformWriteRequestAsync <T>(IModbusMessage request) where T : IModbusMessage, new() { return(Task.Factory.StartNew(() => Transport.UnicastMessage <T>(request))); }
internal override bool ChecksumsMatch(IModbusMessage message, byte[] messageFrame) { return(BitConverter.ToUInt16(messageFrame, messageFrame.Length - 2) == BitConverter.ToUInt16(ModbusUtility.CalculateCrc(message.MessageFrame), 0)); }
internal override void Write(IModbusMessage message) { byte[] frame = BuildMessageFrame(message); _log.InfoFormat("TX: {0}", StringUtility.Join(", ", frame)); _tcpStreamAdapter.Write(frame, 0, frame.Length); }
/// <summary> /// 通讯正常,把返回的数据返回到此函数接口。在Protocol类中的CheckData函数对数据进行校验。 /// </summary> /// <param name="info"></param> public override void Communicate(IResponseInfo info) { if (_sendObject == null) { OnDeviceRuningLog("没有获得对应的发送请求实例"); return; } byte[] revData = info.Data; IModbusMessage requestMessage = _sendObject.ModbusMessage; ITag tag = _sendObject.Tag; bool deal = false; object val = null; if (tag.Function == Modbus.Modbus.ReadCoils) { #region bool[] responseVals = _modbusTcpMaster.GetReadCoilsResponse(revData, tag.Quantity, requestMessage); if (responseVals.Length >= 1) { val = responseVals[0] == true ? 1 : 0; this.DeviceDynamic.DynamicData.Write(tag.TagName, val); deal = true; } #endregion } else if (tag.Function == Modbus.Modbus.ReadInputs) { #region bool[] responseVals = _modbusTcpMaster.GetReadInputsResponse(revData, tag.Quantity, requestMessage); if (responseVals.Length >= 1) { val = responseVals[0] == true ? 1 : 0; this.DeviceDynamic.DynamicData.Write(tag.TagName, val); deal = true; } #endregion } else if (tag.Function == Modbus.Modbus.ReadHoldingRegisters) { #region ushort[] responseVals = _modbusTcpMaster.GetReadHoldingRegistersResponse(revData, requestMessage); if (responseVals.Length >= 1) { val = responseVals[0]; this.DeviceDynamic.DynamicData.Write(tag.TagName, val); deal = true; } #endregion } else if (tag.Function == Modbus.Modbus.ReadInputRegisters) { #region ushort[] responseVals = _modbusTcpMaster.GetReadInputRegistersResponse(revData, requestMessage); if (responseVals.Length >= 1) { val = responseVals[0]; this.DeviceDynamic.DynamicData.Write(tag.TagName, val); deal = true; } #endregion } if (deal && val != null) { OnDeviceRuningLog("通讯正常,已经处理数据,值:" + (val == null ? "未知" : val.ToString())); this.DeviceDynamic.Save(); } }
public SendObject(IModbusMessage modbusMessage, ITag tag) { ModbusMessage = modbusMessage; Tag = tag; }
internal IModbusMessage ApplyRequest(IModbusMessage request) { IModbusMessage response; try { Debug.WriteLine(request.ToString()); var eventArgs = new ModbusSlaveRequestEventArgs(request); ModbusSlaveRequestReceived.Raise(this, eventArgs); switch (request.FunctionCode) { case Modbus.ReadCoils: response = ReadDiscretes((ReadCoilsInputsRequest)request, DataStore, DataStore.CoilDiscretes); break; case Modbus.ReadInputs: response = ReadDiscretes((ReadCoilsInputsRequest)request, DataStore, DataStore.InputDiscretes); break; case Modbus.ReadHoldingRegisters: response = ReadRegisters((ReadHoldingInputRegistersRequest)request, DataStore, DataStore.HoldingRegisters); break; case Modbus.ReadInputRegisters: response = ReadRegisters((ReadHoldingInputRegistersRequest)request, DataStore, DataStore.InputRegisters); break; case Modbus.Diagnostics: response = request; break; case Modbus.WriteSingleCoil: response = WriteSingleCoil((WriteSingleCoilRequestResponse)request, DataStore, DataStore.CoilDiscretes); WriteComplete.Raise(this, eventArgs); break; case Modbus.WriteSingleRegister: response = WriteSingleRegister((WriteSingleRegisterRequestResponse)request, DataStore, DataStore.HoldingRegisters); WriteComplete.Raise(this, eventArgs); break; case Modbus.WriteMultipleCoils: response = WriteMultipleCoils((WriteMultipleCoilsRequest)request, DataStore, DataStore.CoilDiscretes); WriteComplete.Raise(this, eventArgs); break; case Modbus.WriteMultipleRegisters: response = WriteMultipleRegisters((WriteMultipleRegistersRequest)request, DataStore, DataStore.HoldingRegisters); WriteComplete.Raise(this, eventArgs); break; case Modbus.ReadWriteMultipleRegisters: ReadWriteMultipleRegistersRequest readWriteRequest = (ReadWriteMultipleRegistersRequest)request; WriteMultipleRegisters(readWriteRequest.WriteRequest, DataStore, DataStore.HoldingRegisters); WriteComplete.Raise(this, eventArgs); response = ReadRegisters(readWriteRequest.ReadRequest, DataStore, DataStore.HoldingRegisters); break; default: string errorMessage = String.Format(CultureInfo.InvariantCulture, "Unsupported function code {0}", request.FunctionCode); Debug.WriteLine(errorMessage); throw new InvalidModbusRequestException(Modbus.IllegalFunction); } } catch (InvalidModbusRequestException ex) // Catches the exception for an illegal function or a custom exception from the ModbusSlaveRequestReceived event. { response = new SlaveExceptionResponse(request.SlaveAddress, (byte)(Modbus.ExceptionOffset + request.FunctionCode), ex.ExceptionCode); } return response; }
public byte[] BuildMessageFrame(IModbusMessage message) { return(Array.Empty <byte>()); }
internal ModbusSlaveRequestEventArgs(IModbusMessage message) { Message = message; }
internal override bool ChecksumsMatch(IModbusMessage message, byte[] messageFrame) { return(ModbusUtility.CalculateLrc(message.MessageFrame) == messageFrame[messageFrame.Length - 1]); }
public TResponse ExecuteCustomMessage <TResponse>(IModbusMessage request) where TResponse : IModbusMessage, new() { return((TResponse)request); }
/// <summary> /// Provide hook to check whether receiving a response should be retried /// </summary> internal virtual bool OnShouldRetryResponse(IModbusMessage request, IModbusMessage response) { return(false); }
public override byte[] BuildMessageFrame(IModbusMessage message) { throw new NotImplementedException(); }
public TResponse ExecuteCustomMessage <TResponse>(IModbusMessage request) where TResponse : IModbusMessage, new() { throw new NotImplementedException(); }
public TResponse ExecuteCustomMessage <TResponse>(IModbusMessage request) where TResponse : IModbusMessage, new() { return(Transport.UnicastMessage <TResponse>(request)); }
/// <summary> /// Provide hook to do transport level message validation. /// </summary> internal abstract void OnValidateResponse(IModbusMessage request, IModbusMessage response);
internal abstract bool ChecksumsMatch(IModbusMessage message, byte[] messageFrame);
internal abstract byte[] BuildMessageFrame(IModbusMessage message);
/// <summary> /// Start slave listening for requests. /// </summary> public override void Listen() { // This external Variable can stop this process stop = false; while (!stop) { try { try { // read request and build message byte[] frame = SerialTransport.ReadRequest(); IModbusMessage request = ModbusMessageFactory.CreateModbusRequest(frame); // here for debugging purposes writes what port is being read // using (StreamWriter outHandle = new StreamWriter("Output.txt", true)) // { // if (request.FunctionCode == Modbus.ReadHoldingRegisters) // { // outHandle.WriteLine("{0} Reading Port {1} functioncode {2} startadress {3} points {4}", DateTime.Now.ToString(), request.SlaveAddress, request.FunctionCode, // ((ReadHoldingInputRegistersRequest)request).StartAddress, ((ReadHoldingInputRegistersRequest)request).NumberOfPoints); // } // else if (request.FunctionCode == Modbus.ReadInputRegisters) // { // outHandle.WriteLine("{0} Reading Port {1} functioncode {2} startadress {3} points {4}", DateTime.Now.ToString(), request.SlaveAddress, request.FunctionCode, //((ReadHoldingInputRegistersRequest)request).StartAddress, ((ReadHoldingInputRegistersRequest)request).NumberOfPoints); // } // //response = ReadRegisters((ReadHoldingInputRegistersRequest) request, DataStore, DataStore.HoldingRegisters); // //break; // //case Modbus.ReadInputRegisters: // //outHandle.WriteLine("{0} Reading Port {1}", DateTime.Now.ToString(), request.SlaveAddress, request.FunctionCode ); // } if (SerialTransport.CheckFrame && !SerialTransport.ChecksumsMatch(request, frame)) { string errorMessage = String.Format(CultureInfo.InvariantCulture, "Checksums failed to match {0} != {1}", request.MessageFrame.Join(", "), frame.Join(", ")); _logger.Error(errorMessage); throw new IOException(errorMessage); } // only service requests addressed to this particular slave if (m_internalMap != null) { if (!doesIdExist(request.SlaveAddress)) { _logger.DebugFormat("NModbus Slave {0} ignoring request intended for NModbus Slave {1}", UnitId, request.SlaveAddress); continue; } } else { if (request.SlaveAddress != UnitId) { _logger.DebugFormat("NModbus Slave {0} ignoring request intended for NModbus Slave {1}", UnitId, request.SlaveAddress); continue; } } // perform action if (m_internalMap != null) { DataStore = m_internalMap[request.SlaveAddress]; } IModbusMessage response = ApplyRequest(request); // write response SerialTransport.Write(response); } catch (IOException ioe) { _logger.ErrorFormat("IO Exception encountered while listening for requests - {0}", ioe.Message); SerialTransport.DiscardInBuffer(); } catch (TimeoutException te) { _logger.ErrorFormat("Timeout Exception encountered while listening for requests - {0}", te.Message); SerialTransport.DiscardInBuffer(); } // TODO better exception handling here, missing FormatException, NotImplemented... } catch (InvalidOperationException) { // when the underlying transport is disposed break; } } }
internal abstract void Write(IModbusMessage message);
internal override void OnValidateResponse(IModbusMessage request, IModbusMessage response) { throw new NotImplementedException(); }
public T UnicastMessage <T>(IModbusMessage message) where T : IModbusMessage, new() { return(new T()); }
internal IModbusMessage ApplyRequest(IModbusMessage request) { _logger.Info(request.ToString()); EventHandler<ModbusSlaveRequestEventArgs> handler = ModbusSlaveRequestReceived; if (handler != null) handler(this, new ModbusSlaveRequestEventArgs(request)); IModbusMessage response; switch (request.FunctionCode) { case Modbus.ReadCoils: response = ReadDiscretes((ReadCoilsInputsRequest) request, DataStore, DataStore.CoilDiscretes); break; case Modbus.ReadInputs: response = ReadDiscretes((ReadCoilsInputsRequest) request, DataStore, DataStore.InputDiscretes); break; case Modbus.ReadHoldingRegisters: response = ReadRegisters((ReadHoldingInputRegistersRequest) request, DataStore, DataStore.HoldingRegisters); break; case Modbus.ReadInputRegisters: response = ReadRegisters((ReadHoldingInputRegistersRequest) request, DataStore, DataStore.InputRegisters); break; case Modbus.Diagnostics: response = request; break; case Modbus.WriteSingleCoil: response = WriteSingleCoil((WriteSingleCoilRequestResponse) request, DataStore, DataStore.CoilDiscretes); break; case Modbus.WriteSingleRegister: response = WriteSingleRegister((WriteSingleRegisterRequestResponse) request, DataStore, DataStore.HoldingRegisters); break; case Modbus.WriteMultipleCoils: response = WriteMultipleCoils((WriteMultipleCoilsRequest) request, DataStore, DataStore.CoilDiscretes); break; case Modbus.WriteMultipleRegisters: response = WriteMultipleRegisters((WriteMultipleRegistersRequest) request, DataStore, DataStore.HoldingRegisters); break; case Modbus.ReadWriteMultipleRegisters: ReadWriteMultipleRegistersRequest readWriteRequest = (ReadWriteMultipleRegistersRequest) request; response = ReadRegisters(readWriteRequest.ReadRequest, DataStore, DataStore.HoldingRegisters); WriteMultipleRegisters(readWriteRequest.WriteRequest, DataStore, DataStore.HoldingRegisters); break; default: string errorMessage = String.Format(CultureInfo.InvariantCulture, "Unsupported function code {0}", request.FunctionCode); _logger.Error(errorMessage); throw new ArgumentException(errorMessage, "request"); } return response; }
internal override void Write(IModbusMessage message) { byte[] frame = BuildMessageFrame(message); Debug.WriteLine($"TX: {string.Join(", ", frame)}"); StreamResource.Write(frame, 0, frame.Length); }
internal ModbusSlaveRequestEventArgs(IModbusMessage message) { _message = message; }
internal IModbusMessage ApplyRequest(IModbusMessage request) { _logger.Info(request.ToString()); ModbusSlaveRequestReceived.Raise(this, new ModbusSlaveRequestEventArgs(request)); IModbusMessage response; /* * ANGELOXX: if datastore is null, this Slave returns an error to the Master * I use the datastore = null asignment to emulate a missing device. Returned * error is 0x02 -> Illegal Data Address */ if (DataStore == null) { byte[] messageFrame = new byte[] { request.SlaveAddress, (byte)(Modbus.ExceptionOffset + request.FunctionCode), 2 }; return ModbusMessageFactory.CreateModbusMessage<SlaveExceptionResponse>(messageFrame); } switch (request.FunctionCode) { case Modbus.ReadCoils: response = ReadDiscretes((ReadCoilsInputsRequest) request, DataStore, DataStore.CoilDiscretes); break; case Modbus.ReadInputs: response = ReadDiscretes((ReadCoilsInputsRequest) request, DataStore, DataStore.InputDiscretes); break; case Modbus.ReadHoldingRegisters: response = ReadRegisters((ReadHoldingInputRegistersRequest) request, DataStore, DataStore.HoldingRegisters); break; case Modbus.ReadInputRegisters: response = ReadRegisters((ReadHoldingInputRegistersRequest) request, DataStore, DataStore.InputRegisters); break; case Modbus.Diagnostics: response = request; break; case Modbus.WriteSingleCoil: response = WriteSingleCoil((WriteSingleCoilRequestResponse) request, DataStore, DataStore.CoilDiscretes); break; case Modbus.WriteSingleRegister: response = WriteSingleRegister((WriteSingleRegisterRequestResponse) request, DataStore, DataStore.HoldingRegisters); break; case Modbus.WriteMultipleCoils: response = WriteMultipleCoils((WriteMultipleCoilsRequest) request, DataStore, DataStore.CoilDiscretes); break; case Modbus.WriteMultipleRegisters: response = WriteMultipleRegisters((WriteMultipleRegistersRequest) request, DataStore, DataStore.HoldingRegisters); break; case Modbus.ReadWriteMultipleRegisters: ReadWriteMultipleRegistersRequest readWriteRequest = (ReadWriteMultipleRegistersRequest) request; response = ReadRegisters(readWriteRequest.ReadRequest, DataStore, DataStore.HoldingRegisters); WriteMultipleRegisters(readWriteRequest.WriteRequest, DataStore, DataStore.HoldingRegisters); break; default: string errorMessage = String.Format(CultureInfo.InvariantCulture, "Unsupported function code {0}", request.FunctionCode); _logger.Error(errorMessage); throw new ArgumentException(errorMessage, "request"); } return response; }
#pragma warning restore CS1591 // O comentário XML ausente não foi encontrado para o tipo ou membro visível publicamente internal virtual T UnicastMessage <T>(IModbusMessage message) where T : IModbusMessage, new() { IModbusMessage response = null; int attempt = 1; bool readAgain; bool success = false; do { try { lock (_syncLock) { Write(message); do { readAgain = false; response = ReadResponse <T>(); var exceptionResponse = response as SlaveExceptionResponse; if (exceptionResponse != null) { // if SlaveExceptionCode == ACKNOWLEDGE we retry reading the response without resubmitting request if (readAgain = exceptionResponse.SlaveExceptionCode == Modbus.Acknowledge) { _logger.InfoFormat("Received ACKNOWLEDGE slave exception response, waiting {0} milliseconds and retrying to read response.", _waitToRetryMilliseconds); Thread.Sleep(WaitToRetryMilliseconds); } else { throw new SlaveException(exceptionResponse); } } } while (readAgain); } ValidateResponse(message, response); success = true; } catch (SlaveException se) { if (se.SlaveExceptionCode != Modbus.SlaveDeviceBusy) { throw; } _logger.InfoFormat("Received SLAVE_DEVICE_BUSY exception response, waiting {0} milliseconds and resubmitting request.", _waitToRetryMilliseconds); Thread.Sleep(WaitToRetryMilliseconds); } catch (Exception e) { if (e is FormatException || e is NotImplementedException || e is TimeoutException || e is IOException) { _logger.WarnFormat("{0}, {1} retries remaining - {2}", e.GetType().Name, _retries - attempt + 1, e); if (attempt++ > _retries) { error = e.ToString(); } return((T)response); } else { error = e.ToString(); return((T)response); } } } while (!success); return((T)response); }
public void Write(IModbusMessage message) { }
public abstract byte[] BuildMessageFrame(IModbusMessage message);
private async Task HandleRequestAsync() { var serialTransport = (IModbusSerialTransport)Transport; while (true) { try { // read request and build message byte[] frame = serialTransport.ReadRequest(); //Create the request IModbusMessage request = _modbusFactory.CreateModbusRequest(frame); //Check the message if (serialTransport.CheckFrame && !serialTransport.ChecksumsMatch(request, frame)) { string msg = $"Checksums failed to match {string.Join(", ", request.MessageFrame)} != {string.Join(", ", frame)}."; //Logger.Warning(msg); throw new IOException(msg); } //Apply the request // TODO: почистить класс и предусмотреть броадкаст request.SlaveAddress ==0 IModbusMessage response = _slaveNetwork.GetSlave(request.SlaveAddress) .ApplyRequest(request); if (response == null) { serialTransport.IgnoreResponse(); } else { Transport.Write(response); } } catch (IOException /*ioe*/) { //Logger.Warning($"IO Exception encountered while listening for requests - {ioe.Message}"); serialTransport.DiscardInBuffer(); ModbusMasterTcpConnectionClosed?.Invoke(this, new TcpConnectionEventArgs(EndPoint)); } catch (TimeoutException /*te*/) { //Logger.Trace($"Timeout Exception encountered while listening for requests - {te.Message}"); serialTransport.DiscardInBuffer(); } catch (InvalidOperationException) { // when the underlying transport is disposed break; } catch (Exception /*ex*/) { //Logger.Error($"{GetType()}: {ex.Message}"); serialTransport.DiscardInBuffer(); } /* // OLD CODE * // //Logger.Debug($"Begin reading header from Master at IP: {EndPoint}"); * * int readBytes = await Stream.ReadAsync(_mbapHeader, 0, 6).ConfigureAwait(false); * if (readBytes == 0) * { * //Logger.Debug($"0 bytes read, Master at {EndPoint} has closed Socket connection."); * ModbusMasterTcpConnectionClosed?.Invoke(this, new TcpConnectionEventArgs(EndPoint)); * return; * } * * ushort frameLength = (ushort)IPAddress.HostToNetworkOrder(BitConverter.ToInt16(_mbapHeader, 4)); * //Logger.Debug($"Master at {EndPoint} sent header: \"{string.Join(", ", _mbapHeader)}\" with {frameLength} bytes in PDU"); * * _messageFrame = new byte[frameLength]; * readBytes = await Stream.ReadAsync(_messageFrame, 0, frameLength).ConfigureAwait(false); * if (readBytes == 0) * { * //Logger.Debug($"0 bytes read, Master at {EndPoint} has closed Socket connection."); * ModbusMasterTcpConnectionClosed?.Invoke(this, new TcpConnectionEventArgs(EndPoint)); * return; * } * * //Logger.Debug($"Read frame from Master at {EndPoint} completed {readBytes} bytes"); * byte[] frame = _mbapHeader.Concat(_messageFrame).ToArray(); * //Logger.Trace($"RX from Master at {EndPoint}: {string.Join(", ", frame)}"); * * var request = _modbusFactory.CreateModbusRequest(_messageFrame); * request.TransactionId = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(frame, 0)); * * IModbusSlave slave = _slaveNetwork.GetSlave(request.SlaveAddress); * * if (slave != null) * { * //TODO: Determine if this is appropriate * * // perform action and build response * IModbusMessage response = slave.ApplyRequest(request); * response.TransactionId = request.TransactionId; * * // write response * byte[] responseFrame = Transport.BuildMessageFrame(response); * //Logger.Information($"TX to Master at {EndPoint}: {string.Join(", ", responseFrame)}"); * await Stream.WriteAsync(responseFrame, 0, responseFrame.Length).ConfigureAwait(false); * } */ } }