private bool IsException(ResponseBuffer buffer, ModbusRequest request, int timeout, out ModbusResponse responseMessage) { if ((Read(buffer, 1, timeout) & 0x80) == 0x80) { var codeValue = Read(buffer, 2, timeout); if (IsErrorCRC(buffer, 3, request, timeout)) { throw new ModbusCommException(ModbusCommErrorCode.ErrorCRC, buffer, request); } ModbusExceptionCode exceptionCode = ModbusExceptionCode.NotDefined; if (Enum.IsDefined(typeof(ModbusExceptionCode), codeValue)) { exceptionCode = (ModbusExceptionCode)codeValue; } responseMessage = new ModbusExceptionResponse(exceptionCode, request); return(true); } else { responseMessage = null; return(false); } }
/// <summary> /// Read Discrete Inputs from Server device (FC2). /// </summary> /// <param name="startingAddress">First discrete input to read</param> /// <param name="quantity">Number of discrete Inputs to read</param> /// <returns>Boolean Array which contains the discrete Inputs</returns> public Modbus.DiscreteInputs ReadDiscreteInputs(int startingAddress, int quantity) { Logger.Info($"FC2 (Read Discrete Inputs from StartingAddress: { startingAddress }, Quantity: { quantity }"); if (this.modbusChannel == null) { Logger.Error("ConnectionException Throwed"); throw new InvalidOperationException("No ModbusChannel initialized."); } if (startingAddress > 65535 || quantity > 2000) { Logger.Error("ArgumentException Throwed"); throw new ArgumentException("Starting address must be 0 - 65535; quantity must be 0 - 2000"); } var request = ModbusRequest.DiscriteInputRequest(startingAddress, quantity); var error = modbusChannel.SendReadCommand <DiscreteInputs>(request, out DiscreteInputs inputs); if (error != null) { throw ModbusException.FromProtocolException(error.ProtocolException); } return(inputs); }
internal ModbusResponse Deserialize(ResponseBuffer buffer, ModbusRequest request, int timeout) { ModbusResponse result; try { result = DeserializeResponse(buffer, request, timeout); } catch (TimeoutException ex) { throw new ModbusCommException(ModbusCommErrorCode.ResponseTimeout, buffer, ex, request); } catch (ModbusCommException ex) { throw new ModbusCommException(ex.Code, buffer, ex.InnerException, request); } catch (Exception ex) { throw new ModbusCommException(buffer, ex, request); } if (result is ModbusCommErrorResponse commErrorResponse) { throw new ModbusCommException(commErrorResponse.ErrorCode, commErrorResponse.ReceivedBytes, commErrorResponse.Request); } return(result); }
internal virtual ModbusResponse DeserializeResponse(ResponseBuffer buffer, ModbusRequest request, int timeout) { if (request is ModbusReadRequest readMessage) { switch (readMessage.ObjectType) { case ModbusObjectType.DiscreteInput: case ModbusObjectType.Coil: return(DeserializeReadBooleanResponse(buffer, readMessage, timeout)); case ModbusObjectType.InputRegister: case ModbusObjectType.HoldingRegister: return(DeserializeReadRegisterResponse(buffer, readMessage, timeout)); } } else if (request is ModbusWriteCoilRequest writeCoilMessage) { return(DeserializeWriteResponse(buffer, writeCoilMessage, timeout)); } else if (request is ModbusWriteHoldingRegisterRequest writeHoldingRegisterMessage) { return(DeserializeWriteResponse(buffer, writeHoldingRegisterMessage, timeout)); } throw new ArgumentOutOfRangeException(nameof(request)); }
internal override ModbusResponse DeserializeResponse(ResponseBuffer buffer, ModbusRequest request, int timeout) { ModbusResponse result = null; while (result == null || result is ModbusCommErrorResponse responseCommErrorMessage && responseCommErrorMessage.ErrorCode != ModbusCommErrorCode.ResponseTimeout) { if (buffer.Count > 0) { errorBuffer.Add(buffer[0]); buffer.RemoveAt(0); } buffer.Read(timeout); try { while (buffer[0] != 0x3a) { errorBuffer.Add(buffer[0]); buffer.RemoveAt(0); buffer.Read(timeout); } } catch { return(new ModbusCommErrorResponse(ModbusCommErrorCode.ResponseAsciiStartError, errorBuffer.Concat(buffer), request)); } result = base.DeserializeResponse(buffer, request, timeout); } if (result is ModbusCommErrorResponse responseCommError) { result = new ModbusCommErrorResponse(responseCommError.ErrorCode, errorBuffer.Concat(responseCommError.ReceivedBytes), request); } else { var asciiEnd = buffer.Read(2, timeout); if (!asciiEnd.SequenceEqual(new byte[] { 13, 10 })) { return(new ModbusCommErrorResponse(ModbusCommErrorCode.ResponseAsciiEndError, buffer, request)); } if (errorBuffer.Count > 0) { RaiseUnrecognized(buffer.Channel, errorBuffer.ToArray()); errorBuffer.Clear(); } } return(result); }
static void Main(string[] args) { RawTcp(); return;// byte[] buffer = new byte[] { 0x01, 0x00, 0x13, 0x00, 0x13 }; ModbusMessage mm = ModbusRequest.ParseBuffer(buffer); return; //ReflectMyClasses();return; //TestMessage();return; ModbusTcpClient client = new ModbusTcpClient(); Console.WriteLine($"Keep Alive : {client.KeepAlive}"); Console.WriteLine($"Receive Buffer Size : {client.ReceiveBufferSize = 1024}"); Console.WriteLine($"Send Buffer Size : {client.SendBufferSize = 1024}"); Console.WriteLine($"Receive Timeout : {client.ReceiveTimeout = 500}"); Console.WriteLine($"Send Timeout : {client.SendTimeout = 500}"); Console.WriteLine($"No Delay : {client.NoDelay}"); Console.WriteLine($"Reuse Address : {client.ReuseAddress = true}"); client.Connect("localhost"); bool running = true; Task.Run(() => { try { while (running && client.Connected) { int length = client.SendMessage(new WriteSingleRegisterRequest(9999, 1000)); Console.WriteLine($"{length} bytes sent"); Thread.Sleep(200); } if (client.Connected) { Console.WriteLine("Stopped"); } else { Console.WriteLine("Disconnected"); } } catch (Exception x) { Console.WriteLine($"Error: {x.Message}"); client = new ModbusTcpClient("localhost"); } }); Console.ReadLine(); running = false; //new ArraySegment<byte>() }
private ModbusRequest Get(ModbusResponse response) { ModbusRequest result = null; if (response != null) { lock (lockerRequestes) { result = requestes.Find(x => x.MBAPHeader.TransactionId == response.MBAPHeader.TransactionId); requestes.Remove(result); } } return(result); }
internal ModbusError SendReadCommand <T>(ModbusRequest request, out T responseType) where T : class, IModbusResponse { byte[] data = request.GetPDU(); var responseData = SendReadCommand(data); var response = new ModbusResponse(responseData); if (response.ExceptionCode > 0) { var err = new ModbusError(response.ExceptionCode); responseType = null; return(err); } else { responseType = (T)Activator.CreateInstance(typeof(T), response); return(null); } }
internal override ModbusResponse DeserializeResponse(ResponseBuffer buffer, ModbusRequest request, int timeout) { var responseWaitHandle = this.responseWaitHandles[request.TransactionID] = new ResponseWaitHandle(buffer, request, timeout); Task.Run(() => RunReceive(buffer.Channel)); responseWaitHandle.WaitOne(timeout); var result = responseWaitHandle.Response; if (result == null) { this.responseWaitHandles.Remove(request.TransactionID); return(new ModbusCommErrorResponse(ModbusCommErrorCode.ResponseTimeout, new byte[0], request)); } return(result); }
private bool Add(ModbusRequest request) { bool result = false; if (request != null) { lock (lockerRequestes) { if (requestes.Find(x => x.MBAPHeader.TransactionId == request.MBAPHeader.TransactionId) == null) { requestes.Add(request); result = true; } else { throw new ArgumentException("Запрос с таким Id транзакции уже есть в списке запросов!"); } } } return(result); }
private bool IsErrorLRC(ResponseBuffer buffer, int messageLength, ModbusRequest request, int timeout, out ModbusResponse responseMessage) { byte lrc = 0; foreach (var b in Read(buffer, 0, messageLength, timeout)) { lrc += b; } lrc = (byte)(-lrc & 0xff); if (lrc != Read(buffer, messageLength, timeout)) { responseMessage = new ModbusCommErrorResponse(ModbusCommErrorCode.ErrorLRC, buffer, request); return(true); } else { responseMessage = null; return(false); } }
/// <summary> /// Read Coils from Server device (FC1). /// </summary> /// <param name="startingAddress">First coil to read</param> /// <param name="quantity">Numer of coils to read</param> /// <returns>Boolean Array which contains the coils</returns> public Coils ReadCoils(int startingAddress, int quantity) { Logger.Info("FC1 (Read Coils from Master device), StartingAddress: " + startingAddress + ", Quantity: " + quantity); if (modbusChannel == null) { throw new InvalidOperationException("No ModbusChannel initialized."); } if (startingAddress > 65535 || quantity > 2000) { throw new ArgumentException("Starting address must be 0 - 65535; quantity must be 0 - 2000"); } var request = new ModbusRequest(ModbusFunctions.ReadCoils, startingAddress, quantity); var error = modbusChannel.SendReadCommand(request, out Coils coils); if (error != null) { throw ModbusException.FromProtocolException(error.ProtocolException); } return(coils); }
internal override ModbusResponse DeserializeResponse(ResponseBuffer buffer, ModbusRequest request, int timeout) { ModbusResponse result = base.DeserializeResponse(buffer, request, timeout); while (result is ModbusCommErrorResponse responseCommErrorMessage && responseCommErrorMessage.ErrorCode != ModbusCommErrorCode.ResponseTimeout) { errorBuffer.Add(buffer[0]); buffer.RemoveAt(0); result = base.DeserializeResponse(buffer, request, timeout); } if (result is ModbusCommErrorResponse responseCommError) { result = new ModbusCommErrorResponse(responseCommError.ErrorCode, errorBuffer.Concat(responseCommError.ReceivedBytes), request); } else if (errorBuffer.Count > 0) { RaiseUnrecognized(buffer.Channel, errorBuffer.ToArray()); errorBuffer.Clear(); } return(result); }
/// <summary> /// Read Holding Registers from Master device (FC3). /// </summary> /// <param name="startingAddress">First holding register to be read. Integer between 0 and 65535</param> /// <param name="quantity">Number of holding registers to be read. Integer between 0 and 125.</param> /// <returns>Int Array which contains the holding registers</returns> public HoldingRegisters ReadHoldingRegisters(int startingAddress, int quantity) { Logger.Info("FC3 Read Holding Registers from Master device), StartingAddress: " + startingAddress + ", Quantity: " + quantity); if (modbusChannel == null) { Logger.Error("ConnectionException Throwed"); throw new InvalidOperationException("No ModbusChannel initialized."); } if (startingAddress > 65535 || quantity > 125) { Logger.Error("ArgumentException Throwed"); throw new ArgumentException("Starting address must be 0 - 65535; quantity must be 0 - 125"); } var request = new ModbusRequest(ModbusFunctions.ReadHoldingRegisters, startingAddress, quantity); var error = modbusChannel.SendReadCommand(request, out HoldingRegisters holdingReg); if (error != null) { throw ModbusException.FromProtocolException(error.ProtocolException); } return(holdingReg); }
private bool IsErrorCRC(ResponseBuffer buffer, int messageLength, ModbusRequest request, int timeout) { var crc = Read(buffer, messageLength, 2, timeout).ToArray(); return(!CalculateCrc(buffer.Take(messageLength)).SequenceEqual(crc)); }
internal override ModbusRequest DeserializeRequest(RequestBuffer rawBuffer) { ModbusRequest result = null; while (!rawBuffer.Channel.IsDisposed) { if (errorBuffer.Count >= 256) { RaiseUnrecognized(rawBuffer.Channel, errorBuffer.ToArray()); errorBuffer.Clear(); } while (rawBuffer.Count < 17 && !rawBuffer.Channel.IsDisposed) { rawBuffer.Read(); } if (rawBuffer.Channel.IsDisposed) { break; } int messageLength = 0; if (rawBuffer[0] == 0x3a) { List <byte> buffer = new List <byte>(); for (int i = 0; i < 7; i++) { if (TryParseFromHex(rawBuffer, i * 2 + 1, out var byteValue)) { buffer.Add(byteValue); } else { break; } } if (buffer.Count < 7) { errorBuffer.AddRange(rawBuffer.Take((buffer.Count + 1) * 2 + 1)); rawBuffer.RemoveRange(0, (buffer.Count + 1) * 2 + 1); continue; } var slaveAddress = buffer[0]; if (rawBuffer.ModbusSlave.IsValidSlaveAddress(slaveAddress, rawBuffer.Channel) && Enum.IsDefined(typeof(ModbusFunction), buffer[1])) { ModbusFunction function = (ModbusFunction)buffer[1]; var address = ToUInt16(buffer, 2); var valueOrLength = ToUInt16(buffer, 4); switch (function) { case ModbusFunction.ReadCoils: case ModbusFunction.ReadDiscreteInputs: case ModbusFunction.ReadHoldingRegisters: case ModbusFunction.ReadInputRegisters: case ModbusFunction.WriteSingleCoil: case ModbusFunction.WriteSingleHoldingRegister: if ((-buffer.Take(6).Sum(b => b) & 0xff) == buffer[6] && rawBuffer[15] == '\r' && rawBuffer[16] == '\n') { messageLength = 17; switch (function) { case ModbusFunction.ReadCoils: case ModbusFunction.ReadDiscreteInputs: case ModbusFunction.ReadHoldingRegisters: case ModbusFunction.ReadInputRegisters: result = new ModbusReadRequest(slaveAddress, (ModbusObjectType)(byte)function, address, valueOrLength); break; case ModbusFunction.WriteSingleCoil: if (valueOrLength != 0xff00 && valueOrLength != 0) { result = new ModbusWriteCoilRequest(slaveAddress, address); } else { result = new ModbusWriteCoilRequest(slaveAddress, address, valueOrLength == 0xff00); } break; case ModbusFunction.WriteSingleHoldingRegister: result = new ModbusWriteHoldingRegisterRequest(slaveAddress, address, valueOrLength); break; } } break; case ModbusFunction.WriteMultipleCoils: case ModbusFunction.WriteMultipleHoldingRegisters: var byteLength = buffer[6]; messageLength = byteLength * 2 + 19; if (function == ModbusFunction.WriteMultipleCoils && byteLength == Math.Ceiling(valueOrLength / 8d) || function == ModbusFunction.WriteMultipleHoldingRegisters && byteLength == valueOrLength * 2) { while (rawBuffer.Count < messageLength && !rawBuffer.Channel.IsDisposed) { rawBuffer.Read(); } if (rawBuffer.Channel.IsDisposed) { break; } for (int i = 0; i < byteLength + 1; i++) { if (TryParseFromHex(rawBuffer, i * 2 + 15, out var byteValue)) { buffer.Add(byteValue); } else { break; } } if (buffer.Count < 8 + byteLength) { errorBuffer.AddRange(rawBuffer.Take((buffer.Count + 1) * 2 + 1)); rawBuffer.RemoveRange(0, (buffer.Count + 1) * 2 + 1); continue; } if ((-buffer.Take(7 + byteLength).Sum(b => b) & 0xff) == buffer[6] && rawBuffer[15] == '\r' && rawBuffer[16] == '\n') { switch (function) { case ModbusFunction.WriteMultipleCoils: result = new ModbusWriteCoilRequest(slaveAddress, address, buffer.Skip(7).Take(byteLength).SelectMany(b => ByteToBooleanArray(b)).Take(valueOrLength).ToArray()); break; case ModbusFunction.WriteMultipleHoldingRegisters: result = new ModbusWriteHoldingRegisterRequest(slaveAddress, address, buffer.Skip(7).Take(byteLength).ToArray()); break; } } } break; } } } if (result != null) { if (errorBuffer.Count > 0) { RaiseUnrecognized(rawBuffer.Channel, errorBuffer.ToArray()); errorBuffer.Clear(); } return(result); } else { errorBuffer.Add(rawBuffer[0]); rawBuffer.RemoveAt(0); continue; } } return(null); }
internal override ModbusRequest DeserializeRequest(RequestBuffer buffer) { ModbusRequest result = null; while (!buffer.Channel.IsDisposed) { if (errorBuffer.Count >= 256) { RaiseUnrecognized(buffer.Channel, errorBuffer.ToArray()); errorBuffer.Clear(); } while (buffer.Count < 8 && !buffer.Channel.IsDisposed) { buffer.Read(); } if (buffer.Channel.IsDisposed) { break; } var slaveAddress = buffer[0]; int messageLength = 0; if (buffer.ModbusSlave.IsValidSlaveAddress(slaveAddress, buffer.Channel) && Enum.IsDefined(typeof(ModbusFunction), buffer[1])) { ModbusFunction function = (ModbusFunction)buffer[1]; var address = ToUInt16(buffer, 2); var valueOrLength = ToUInt16(buffer, 4); switch (function) { case ModbusFunction.ReadCoils: case ModbusFunction.ReadDiscreteInputs: case ModbusFunction.ReadHoldingRegisters: case ModbusFunction.ReadInputRegisters: case ModbusFunction.WriteSingleCoil: case ModbusFunction.WriteSingleHoldingRegister: if (CalculateCrc(buffer.Take(6)).SequenceEqual(buffer.Skip(6).Take(2))) { messageLength = 8; switch (function) { case ModbusFunction.ReadCoils: case ModbusFunction.ReadDiscreteInputs: case ModbusFunction.ReadHoldingRegisters: case ModbusFunction.ReadInputRegisters: result = new ModbusReadRequest(slaveAddress, (ModbusObjectType)(byte)function, address, valueOrLength); break; case ModbusFunction.WriteSingleCoil: if (valueOrLength != 0xff00 && valueOrLength != 0) { result = new ModbusWriteCoilRequest(slaveAddress, address); } else { result = new ModbusWriteCoilRequest(slaveAddress, address, valueOrLength == 0xff00); } break; case ModbusFunction.WriteSingleHoldingRegister: result = new ModbusWriteHoldingRegisterRequest(slaveAddress, address, valueOrLength); break; } } break; case ModbusFunction.WriteMultipleCoils: case ModbusFunction.WriteMultipleHoldingRegisters: if (buffer.Count < 7 && !buffer.Channel.IsDisposed) { buffer.Read(); } if (buffer.Channel.IsDisposed) { break; } var byteLength = buffer[6]; messageLength = byteLength + 9; if (function == ModbusFunction.WriteMultipleCoils && byteLength == Math.Ceiling(valueOrLength / 8d) || function == ModbusFunction.WriteMultipleHoldingRegisters && byteLength == valueOrLength * 2) { while (buffer.Count < messageLength && !buffer.Channel.IsDisposed) { buffer.Read(); } if (buffer.Channel.IsDisposed) { break; } if (CalculateCrc(buffer.Take(byteLength + 7)).SequenceEqual(buffer.Skip(byteLength + 7).Take(2))) { switch (function) { case ModbusFunction.WriteMultipleCoils: result = new ModbusWriteCoilRequest(slaveAddress, address, buffer.Skip(7).Take(byteLength).SelectMany(b => ByteToBooleanArray(b)).Take(valueOrLength).ToArray()); break; case ModbusFunction.WriteMultipleHoldingRegisters: result = new ModbusWriteHoldingRegisterRequest(slaveAddress, address, buffer.Skip(7).Take(byteLength).ToArray()); break; } } } break; } } if (result != null) { if (errorBuffer.Count > 0) { RaiseUnrecognized(buffer.Channel, errorBuffer.ToArray()); errorBuffer.Clear(); } return(result); } else { errorBuffer.Add(buffer[0]); buffer.RemoveAt(0); continue; } } return(null); }
public ModbusCommErrorResponse(ModbusCommErrorCode errorCode, IEnumerable <byte> receivedMessage, ModbusRequest request) : base(request) { ErrorCode = errorCode; ReceivedBytes = receivedMessage?.ToArray() ?? new byte[0]; }
public ResponseWaitHandle(ResponseBuffer buffer, ModbusRequest request, int timeout) : base(false, EventResetMode.ManualReset) { ResponseBuffer = buffer; Request = request; Timeout = timeout; }