private void ReadInputRegisters(IModbusInterface intf, bool isBroadcast, object telegramContext, ModbusFunctionCode fc, short dataPos, short dataLength) { if (dataLength < 4) { SendErrorResult(intf, isBroadcast, _deviceAddress, telegramContext, fc, ModbusErrorCode.IllegalDataValue); } else { ushort startAddress = ModbusUtils.ExtractUShort(_buffer, dataPos); ushort registerCount = ModbusUtils.ExtractUShort(_buffer, dataPos + 2); ushort[] registers = new ushort[registerCount]; var err = OnReadInputRegisters(isBroadcast, startAddress, registers); if (isBroadcast) { return; } if (err != ModbusErrorCode.NoError) { SendErrorResult(intf, false, _deviceAddress, telegramContext, fc, err); } else { short telegramLength; intf.CreateTelegram(_deviceAddress, (byte)fc, (short)(1 + 2 * registers.Length), _buffer, out telegramLength, out dataPos, true, ref telegramContext); _buffer[dataPos] = (byte)(2 * registers.Length); for (int i = 0; i < registerCount; i++) { ModbusUtils.InsertUShort(_buffer, dataPos + 1 + 2 * i, registers[i]); } intf.SendTelegram(_buffer, telegramLength); } } }
private void WriteSingleRegister(IModbusInterface intf, bool isBroadcast, object telegramContext, ModbusFunctionCode fc, short dataPos, short dataLength) { if (dataLength < 4) { SendErrorResult(intf, isBroadcast, _deviceAddress, telegramContext, fc, ModbusErrorCode.IllegalDataValue); } else { ushort address = ModbusUtils.ExtractUShort(_buffer, dataPos); ushort value = ModbusUtils.ExtractUShort(_buffer, dataPos + 2); var err = OnWriteSingleRegister(isBroadcast, address, value); if (isBroadcast) { return; } if (err != ModbusErrorCode.NoError) { SendErrorResult(intf, false, _deviceAddress, telegramContext, fc, err); } else { short telegramLength; intf.CreateTelegram(_deviceAddress, (byte)fc, 4, _buffer, out telegramLength, out dataPos, true, ref telegramContext); ModbusUtils.InsertUShort(_buffer, dataPos, address); ModbusUtils.InsertUShort(_buffer, dataPos + 2, value); intf.SendTelegram(_buffer, telegramLength); } } }
/// <summary> /// Creates a modbus master using the given interface /// </summary> /// <param name="intf">Interface to use for the master</param> /// <param name="syncObject">Object to use for multi threaded communication locking.</param> public ModbusMaster(IModbusInterface intf, object syncObject = null) { _Interface = intf; _SyncObject = syncObject ?? new object(); _Buffer = new byte[_Interface.MaxTelegramLength]; _Interface.PrepareWrite(); }
/// <summary> /// Creates a modbus master using the given interface /// </summary> /// <param name="intf">Interface to use for the master</param> /// <param name="syncObject">Object to use for multi threaded communication locking.</param> public RoSchmiModbusMaster(IModbusInterface intf, object syncObject = null) { _Interface = intf; _SyncObject = syncObject ?? new object(); _Buffer = new byte[_Interface.MaxTelegramLength]; _Interface.PrepareWrite(); }
private void WriteMultipleCoils(IModbusInterface intf, bool isBroadcast, object telegramContext, ModbusFunctionCode fc, short dataPos, short dataLength) { if (dataLength < 5) { SendErrorResult(intf, isBroadcast, _deviceAddress, telegramContext, fc, ModbusErrorCode.IllegalDataValue); } else { ushort startAddress = ModbusUtils.ExtractUShort(_buffer, dataPos); ushort outputCount = ModbusUtils.ExtractUShort(_buffer, dataPos + 2); byte byteCount = _buffer[dataPos + 4]; byte[] values = new byte[byteCount]; Array.Copy(_buffer, dataPos + 5, values, 0, values.Length); var err = OnWriteMultipleCoils(isBroadcast, startAddress, outputCount, values); if (isBroadcast) { return; } if (err != ModbusErrorCode.NoError) { SendErrorResult(intf, false, _deviceAddress, telegramContext, fc, err); } else { short telegramLength; intf.CreateTelegram(_deviceAddress, (byte)fc, 4, _buffer, out telegramLength, out dataPos, true, ref telegramContext); ModbusUtils.InsertUShort(_buffer, dataPos, startAddress); ModbusUtils.InsertUShort(_buffer, dataPos + 2, outputCount); intf.SendTelegram(_buffer, telegramLength); } } }
/// <summary> /// Creates a new ModebusDevice with one initial interface. /// </summary> /// <param name="intf">Initial interface.</param> /// <param name="deviceAddress">Device address. Must be between 1 and 247 for RTU and should be 248 for TCP.</param> /// <param name="syncObject">Optional object for communication interface synchronization.</param> /// <remarks> /// More interfaces can be add or removed by AddInterface and RemoveInterface methods. /// </remarks> protected ModbusDevice(IModbusInterface intf, byte deviceAddress, object syncObject = null) : this(deviceAddress, syncObject) { intf.PrepareRead(); _interfaces.Add(intf); _buffer = new byte[intf.MaxTelegramLength]; }
/// <summary> /// Handles a received message. /// </summary> /// <param name="intf">Interface by which the message was received.</param> /// <param name="deviceAddress">Address of the target device</param> /// <param name="isBroadcast">true if the message is a broadcast. For broadcast messages no response is sent.</param> /// <param name="telegramLength">Length of the message in bytes.</param> /// <param name="telegramContext">Interface specific message context.</param> /// <param name="fc">Function code.</param> /// <param name="dataPos">Index of function code specific data.</param> /// <param name="dataLength">Length of the function code specific data in bytes.</param> protected virtual void OnHandleTelegram(IModbusInterface intf, byte deviceAddress, bool isBroadcast, short telegramLength, object telegramContext, ModbusFunctionCode fc, short dataPos, short dataLength) { try { switch (fc) { case ModbusFunctionCode.ReadCoils: ReadCoils(intf, isBroadcast, telegramContext, fc, dataPos, dataLength); break; case ModbusFunctionCode.ReadDiscreteInputs: ReadDiscreteInputs(intf, isBroadcast, telegramContext, fc, dataPos, dataLength); break; case ModbusFunctionCode.ReadHoldingRegisters: ReadHoldingRegisters(intf, isBroadcast, telegramContext, fc, dataPos, dataLength); break; case ModbusFunctionCode.ReadInputRegisters: ReadInputRegisters(intf, isBroadcast, telegramContext, fc, dataPos, dataLength); break; case ModbusFunctionCode.WriteSingleCoil: WriteSingleCoil(intf, isBroadcast, telegramContext, fc, dataPos, dataLength); break; case ModbusFunctionCode.WriteSingleRegister: WriteSingleRegister(intf, isBroadcast, telegramContext, fc, dataPos, dataLength); break; case ModbusFunctionCode.WriteMultipleCoils: WriteMultipleCoils(intf, isBroadcast, telegramContext, fc, dataPos, dataLength); break; case ModbusFunctionCode.WriteMultipleRegisters: WriteMultipleRegisters(intf, isBroadcast, telegramContext, fc, dataPos, dataLength); break; case ModbusFunctionCode.ReadWriteMultipleRegisters: ReadWriteMultipleRegisters(intf, isBroadcast, telegramContext, fc, dataPos, dataLength); break; case ModbusFunctionCode.ReadDeviceIdentification: case ModbusFunctionCode.ReadDeviceIdentification2: ReadDeviceIdentification(intf, isBroadcast, telegramContext, fc, dataPos, dataLength); break; default: if (!OnCustomTelegram(intf, isBroadcast, _buffer, telegramLength, telegramContext, fc, dataPos, dataLength)) { SendErrorResult(intf, isBroadcast, _deviceAddress, telegramContext, fc, ModbusErrorCode.IllegalFunction); } break; } } catch { SendErrorResult(intf, isBroadcast, _deviceAddress, telegramContext, fc, ModbusErrorCode.ServerDeviceFailure); } }
public GatewayMaster(IModbusInterface masterInterface, byte targetAddress, int timeout) { MasterInterface = masterInterface; TargetAddress = targetAddress; Timeout = timeout; Buffer = new byte[masterInterface.MaxTelegramLength]; }
/// <summary> /// Creates a modbus master using the given interface /// </summary> /// <param name="intf">Interface to use for the master</param> /// <param name="syncObject">Object to use for multi threaded communication locking.</param> public ModbusMaster(IModbusInterface intf, object syncObject = null) { this.@interface = intf; this.syncObject = syncObject ?? new object(); this.buffer = new byte[[email protected]]; [email protected](); }
/// <summary> /// Handles a received message. /// </summary> /// <param name="intf">Interface by which te message was received.</param> /// <param name="deviceAddress">Address of the target device</param> /// <param name="isBroadcast">true if the message is a broadcast. For broadcast messages no reponse is sent.</param> /// <param name="telegramLength">Length of the message in bytes.</param> /// <param name="telegramContext">Interface specific message context.</param> /// <param name="fc">Function code.</param> /// <param name="dataPos">Index of function code specific data.</param> /// <param name="dataLength">Length of the function code specific data in bytes.</param> protected override void OnHandleTelegram(IModbusInterface intf, byte deviceAddress, bool isBroadcast, short telegramLength, object telegramContext, ModbusFunctionCode fc, short dataPos, short dataLength) { var master = (GatewayMaster)_masterMap[deviceAddress]; if (master != null) { short masterTelegramLength; short masterDataPos; object masterTelegramContext = null; master.MasterInterface.CreateTelegram(master.TargetAddress, (byte)fc, dataLength, master.Buffer, out masterTelegramLength, out masterDataPos, false, ref masterTelegramContext); Array.Copy(Buffer, dataPos, master.Buffer, masterDataPos, dataLength); try { var masterDataLength = SendReceive(master.MasterInterface, master.Buffer, master.TargetAddress, fc, master.Timeout, masterTelegramLength, -1, masterTelegramContext, ref masterDataPos); intf.CreateTelegram(deviceAddress, (byte)fc, masterDataLength, Buffer, out telegramLength, out dataPos, true, ref telegramContext); Array.Copy(master.Buffer, masterDataPos, Buffer, dataPos, masterDataLength); intf.SendTelegram(Buffer, telegramLength); } catch (ModbusException ex) { try { if (ex.ErrorCode == ModbusErrorCode.Timeout) { SendErrorResult(intf, false, deviceAddress, telegramContext, fc, ModbusErrorCode.GatewayTargetDeviceFailedToRespond); } else if (((ushort)ex.ErrorCode & 0xff00) != 0) { SendErrorResult(intf, false, deviceAddress, telegramContext, fc, ModbusErrorCode.GatewayTargetDeviceFailedToRespond); } else { SendErrorResult(intf, false, deviceAddress, telegramContext, fc, ex.ErrorCode); } } // ReSharper disable once EmptyGeneralCatchClause catch { } } catch { try { SendErrorResult(intf, false, deviceAddress, telegramContext, fc, ModbusErrorCode.GatewayPathUnavailable); } // ReSharper disable once EmptyGeneralCatchClause catch { } } } else { base.OnHandleTelegram(intf, deviceAddress, isBroadcast, telegramLength, telegramContext, fc, dataPos, dataLength); } }
/// <summary> /// Adds an additional master interface with an custom device id mapping /// </summary> /// <param name="masterInterface">master interface to add</param> /// <param name="timeout">Timeout for master interface</param> /// <param name="addressMap">A hashtable where the key is the incoming device id that is mapped to it's value as device id on the master interface. /// Both, key and value of the hashtable must be of type byte.</param> public void AddMaster(IModbusInterface masterInterface, int timeout, Hashtable addressMap) { masterInterface.PrepareWrite(); foreach (byte sourceAddress in addressMap.Keys) { _masterMap[sourceAddress] = new GatewayMaster(masterInterface, (byte)addressMap[sourceAddress], timeout); } }
private short SendReceive(IModbusInterface masterInterface, byte[] buffer, byte deviceAddress, ModbusFunctionCode fc, int timeout, short telegramLength, short desiredDataLength, object telegramContext, ref short dataPos) { lock (masterInterface) { masterInterface.SendTelegram(buffer, telegramLength); if (deviceAddress == ModbusConst.BroadcastAddress) { return(0); } try { masterInterface.PrepareRead(); byte responseDeviceAddress; byte responseFc = 0; short dataLength = 0; while (timeout > 0) { var ts = DateTime.Now.Ticks; if (!masterInterface.ReceiveTelegram(buffer, desiredDataLength, timeout, out telegramLength)) { throw new ModbusException(ModbusErrorCode.Timeout); } timeout -= (int)((DateTime.Now.Ticks - ts) / 10000); // if this is not the response we are waiting for wait again until time runs out if (masterInterface.ParseTelegram(buffer, telegramLength, true, ref telegramContext, out responseDeviceAddress, out responseFc, out dataPos, out dataLength) && responseDeviceAddress == deviceAddress && (responseFc & 0x7f) == (byte)fc) { break; } if (timeout <= 0) { throw new ModbusException(ModbusErrorCode.Timeout); } } if ((responseFc & 0x80) != 0) { // error response throw new ModbusException((ModbusErrorCode)buffer[dataPos]); } return(dataLength); } finally { masterInterface.PrepareWrite(); } } }
/// <summary> /// Adds an additional master interface with a 1:1 device id mapping /// </summary> /// <param name="masterInterface">Master interface to add</param> /// <param name="timeout">Timeout for master interface</param> public void AddMaster(IModbusInterface masterInterface, int timeout) { var addressMap = new Hashtable(); for (byte n = 1; n < 248; ++n) { addressMap.Add(n, n); } AddMaster(masterInterface, timeout, addressMap); }
/// <summary> /// Removes an interface. /// </summary> /// <param name="intf">Interface to remove.</param> public void RemoveInterface(IModbusInterface intf) { lock (this.syncObject) { this.interfaces.Remove(intf); if (this.interfaces.Count == 0) { this.Buffer1 = null; } } }
/// <summary> /// Removes an interface. /// </summary> /// <param name="intf">Interface to remove.</param> public void RemoveInterface(IModbusInterface intf) { lock (_syncObject) { _interfaces.Remove(intf); if (_interfaces.Count == 0) { _buffer = null; } } }
/// <summary> /// Adds an additional interface to be polled for incoming messages. /// </summary> /// <param name="intf">Interface to add.</param> public void AddInterface(IModbusInterface intf) { lock (this.syncObject) { if (this.Buffer1 == null || intf.MaxTelegramLength > this.Buffer1.Length) { this.Buffer1 = new byte[intf.MaxTelegramLength]; } intf.PrepareRead(); this.interfaces.Add(intf); } }
/// <summary> /// Adds an additional interface to be polled for incoming messages. /// </summary> /// <param name="intf">Interface to add.</param> public void AddInterface(IModbusInterface intf) { lock (_syncObject) { if (_buffer == null || intf.MaxTelegramLength > _buffer.Length) { _buffer = new byte[intf.MaxTelegramLength]; } intf.PrepareRead(); _interfaces.Add(intf); } }
/// <summary> /// Sends a error result message. /// </summary> /// <param name="intf">Interface to send message to.</param> /// <param name="isBroadcast">true if the message is a broadcast. For broadcast messages no reponse is sent.</param> /// <param name="deviceAddress">Device address for response</param> /// <param name="telegramContext">Interface specific telegram context.</param> /// <param name="fc">Function code. The msg is automatically set.</param> /// <param name="modbusErrorCode">Modbus error code to send.</param> protected virtual void SendErrorResult(IModbusInterface intf, bool isBroadcast, byte deviceAddress, object telegramContext, ModbusFunctionCode fc, ModbusErrorCode modbusErrorCode) { if (isBroadcast) { return; } short telegramLength; short dataPos; intf.CreateTelegram(deviceAddress, (byte)((byte)fc | 0x80), 1, _buffer, out telegramLength, out dataPos, true, ref telegramContext); _buffer[dataPos] = (byte)modbusErrorCode; intf.SendTelegram(_buffer, telegramLength); }
private void ReadDiscreteInputs(IModbusInterface intf, bool isBroadcast, object telegramContext, ModbusFunctionCode fc, short dataPos, short dataLength) { if (dataLength < 4) { SendErrorResult(intf, isBroadcast, _deviceAddress, telegramContext, fc, ModbusErrorCode.IllegalDataValue); } else { ushort startAddress = ModbusUtils.ExtractUShort(_buffer, dataPos); ushort inputCount = ModbusUtils.ExtractUShort(_buffer, dataPos + 2); byte[] inputs; if (inputCount % 8 == 0) { inputs = new byte[inputCount / 8]; } else { inputs = new byte[inputCount / 8 + 1]; inputs[inputs.Length - 1] = 0; } var err = OnReadDiscreteInputs(isBroadcast, startAddress, inputCount, inputs); if (isBroadcast) { return; } if (err != ModbusErrorCode.NoError) { SendErrorResult(intf, false, _deviceAddress, telegramContext, fc, err); } else { short telegramLength; intf.CreateTelegram(_deviceAddress, (byte)fc, (short)(1 + inputs.Length), _buffer, out telegramLength, out dataPos, true, ref telegramContext); _buffer[dataPos] = (byte)(inputs.Length); Array.Copy(inputs, 0, _buffer, dataPos + 1, inputs.Length); intf.SendTelegram(_buffer, telegramLength); } } }
private void WriteMultipleRegisters(IModbusInterface intf, bool isBroadcast, object telegramContext, ModbusFunctionCode fc, short dataPos, short dataLength) { if (dataLength < 5) { SendErrorResult(intf, isBroadcast, _deviceAddress, telegramContext, fc, ModbusErrorCode.IllegalDataValue); } else { ushort startAddress = ModbusUtils.ExtractUShort(_buffer, dataPos); ushort registerCount = ModbusUtils.ExtractUShort(_buffer, dataPos + 2); //byte byteCount = _Buffer[dataPos + 4]; ushort[] registers = new ushort[registerCount]; for (int i = 0; i < registerCount; i++) { registers[i] = ModbusUtils.ExtractUShort(_buffer, dataPos + 5 + 2 * i); } var err = OnWriteMultipleRegisters(isBroadcast, startAddress, registers); if (isBroadcast) { return; } if (err != ModbusErrorCode.NoError) { SendErrorResult(intf, false, _deviceAddress, telegramContext, fc, err); } else { short telegramLength; intf.CreateTelegram(_deviceAddress, (byte)fc, 4, _buffer, out telegramLength, out dataPos, true, ref telegramContext); ModbusUtils.InsertUShort(_buffer, dataPos, startAddress); ModbusUtils.InsertUShort(_buffer, dataPos + 2, registerCount); intf.SendTelegram(_buffer, telegramLength); } } }
public ModbusSlave(IModbusInterface intf, byte ModbusID, object syncObject = null) : base(intf, ModbusID, syncObject) { this.onCoilsChanged = this.OnCoilsChanged; this.onInputsChanged = this.OnInputsChanged; }
/// <summary> /// Is called when ever a modbus message was received, no matter if it was for this device or not. /// </summary> /// <param name="modbusInterface">Interface by which the message was received</param> /// <param name="deviceAddress">Address to which device the message was sent</param> /// <param name="functionCode">Function code</param> protected virtual void OnMessageReeived(IModbusInterface modbusInterface, byte deviceAddress, ModbusFunctionCode functionCode) { }
private void ReadWriteMultipleRegisters(IModbusInterface intf, bool isBroadcast, object telegramContext, ModbusFunctionCode fc, short dataPos, short dataLength) { if (dataLength < 9) { SendErrorResult(intf, isBroadcast, _deviceAddress, telegramContext, fc, ModbusErrorCode.IllegalDataValue); } else { ushort readStartAddress = ModbusUtils.ExtractUShort(_buffer, dataPos); ushort readCount = ModbusUtils.ExtractUShort(_buffer, dataPos + 2); ushort writeStartAddress = ModbusUtils.ExtractUShort(_buffer, dataPos + 4); ushort writeCount = ModbusUtils.ExtractUShort(_buffer, dataPos + 6); //byte byteCount = _Buffer[dataPos + 8]; ushort[] writeRegisters = new ushort[writeCount]; for (int i = 0; i < writeCount; i++) { writeRegisters[i] = ModbusUtils.ExtractUShort(_buffer, dataPos + 5 + 2 * i); } ushort[] readRegisters = new ushort[readCount]; var err = OnReadWriteMultipleRegisters(isBroadcast, writeStartAddress, writeRegisters, readStartAddress, readRegisters); if (isBroadcast) { return; } if (err != ModbusErrorCode.NoError) { SendErrorResult(intf, false, _deviceAddress, telegramContext, fc, err); } else { short telegramLength; intf.CreateTelegram(_deviceAddress, (byte)fc, (short)(1 + 2 * readRegisters.Length), _buffer, out telegramLength, out dataPos, true, ref telegramContext); _buffer[dataPos] = (byte)(2 * readRegisters.Length); for (int i = 0; i < readCount; i++) { ModbusUtils.InsertUShort(_buffer, dataPos + 1 + 2 * i, readRegisters[i]); } intf.SendTelegram(_buffer, telegramLength); } } }
/// <summary> /// Creates a new Modbus Gateway with a single master interface and an 1:1 device id mapping /// </summary> /// <param name="deviceAddress">Address of this device</param> /// <param name="masterInterface">Master interface to add</param> /// <param name="timeout">Timeout for master interface</param> public ModbusGateway(byte deviceAddress, IModbusInterface masterInterface, int timeout) : this(deviceAddress) { AddMaster(masterInterface, timeout); }
public MyModbusDevice(IModbusInterface intf, byte deviceAddress, object syncObject = null) : base(intf, deviceAddress, syncObject) { }
/// <summary> /// OnCustomTelegram is called for any function code which is not explicitly handeled by a On"FunctionCode" methos. /// </summary> /// <param name="intf">Interface which sent the request.</param> /// <param name="isBroadcast">true if the request is a broadcast</param> /// <param name="buffer">Buffer containing the message.</param> /// <param name="telegramLength">Total length of message in bytes.</param> /// <param name="telegramContext">Interface specific message context.</param> /// <param name="fc">Function code.</param> /// <param name="dataPos">Index of the function code specific data.</param> /// <param name="dataLength">Length of the function code specific data in bytes.</param> /// <returns></returns> /// <remarks> /// Look at http://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b3.pdf for more details about function codes. /// </remarks> protected virtual bool OnCustomTelegram(IModbusInterface intf, bool isBroadcast, byte[] buffer, short telegramLength, object telegramContext, ModbusFunctionCode fc, short dataPos, short dataLength) { return(false); }
/// <summary> /// OnCustomTelegram is called for any function code which is not explicitly handeled by a On"FunctionCode" methos. /// </summary> /// <param name="intf">Interface which sent the request.</param> /// <param name="isBroadcast">true if the request is a broadcast</param> /// <param name="buffer">Buffer containing the message.</param> /// <param name="telegramLength">Total length of message in bytes.</param> /// <param name="telegramContext">Interface specific message context.</param> /// <param name="fc">Function code.</param> /// <param name="dataPos">Index of the function code specific data.</param> /// <param name="dataLength">Length of the function code specific data in bytes.</param> /// <returns></returns> /// <remarks> /// Look at http://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b3.pdf for more details about function codes. /// </remarks> protected virtual bool OnCustomTelegram(IModbusInterface intf, bool isBroadcast, byte[] buffer, short telegramLength, object telegramContext, ModbusFunctionCode fc, short dataPos, short dataLength) { return false; }
/// <summary> /// Is called when the device identification of this devuice is requested. /// </summary> /// <param name="intf">Interface from wich the requst was received</param> /// <param name="isBroadcast">true if request is a broadcast</param> /// <param name="telegramContext">Conext of the telegram</param> /// <param name="fc">Function code</param> /// <param name="dataPos">Posittion (offset) of the data in the buffer</param> /// <param name="dataLength">Length of the data in the buffer</param> protected virtual void ReadDeviceIdentification(IModbusInterface intf, bool isBroadcast, object telegramContext, ModbusFunctionCode fc, short dataPos, short dataLength) { if (isBroadcast) { return; } if (dataLength < 3) { SendErrorResult(intf, false, _deviceAddress, telegramContext, fc, ModbusErrorCode.IllegalDataValue); } else { byte deviceIdCode = _buffer[dataPos + 1]; if (deviceIdCode < 1 || deviceIdCode > 4) { SendErrorResult(intf, false, _deviceAddress, telegramContext, fc, ModbusErrorCode.IllegalDataValue); return; } byte objectId = _buffer[dataPos + 2]; byte lastObjectId; switch (deviceIdCode) { case 0x00: lastObjectId = 0x02; // basic break; case 0x01: lastObjectId = 0x7f; // regular break; case 0x02: lastObjectId = 0xff; // extended break; default: lastObjectId = objectId; // specific break; } byte[] values = new byte[intf.MaxTelegramLength - 6]; byte objectCount = 0; short valuePos = 0; bool moreFolows = false; byte nextId = 0; for (short id = objectId; id <= lastObjectId; ++id) { var value = OnGetDeviceIdentification((ModbusObjectId)id); if (value == null) { // no more values break; } if (values.Length - (valuePos + 2) >= value.Length) { ++objectCount; values[valuePos++] = (byte)id; values[valuePos++] = (byte)value.Length; for (int c = 0; c < value.Length; c++) { values[valuePos++] = (byte)value[c]; } } else { // more to come moreFolows = true; nextId = (byte)(id + 1); break; } } short telegramLength; intf.CreateTelegram(_deviceAddress, (byte)fc, (short)(6 + valuePos), _buffer, out telegramLength, out dataPos, true, ref telegramContext); _buffer[dataPos] = 0x0e; _buffer[dataPos + 1] = deviceIdCode; _buffer[dataPos + 2] = (byte)((byte)GetConformityLevel() & 0x80); _buffer[dataPos + 3] = (byte)(moreFolows ? 0xff : 0x00); _buffer[dataPos + 4] = nextId; _buffer[dataPos + 5] = objectCount; Array.Copy(values, 0, _buffer, dataPos + 6, valuePos); intf.SendTelegram(_buffer, telegramLength); } }
private short SendReceive(IModbusInterface masterInterface, byte[] buffer, byte deviceAddress, ModbusFunctionCode fc, int timeout, short telegramLength, short desiredDataLength, object telegramContext, ref short dataPos) { lock (masterInterface) { masterInterface.SendTelegram(buffer, telegramLength); if (deviceAddress == ModbusConst.BroadcastAddress) { return 0; } try { masterInterface.PrepareRead(); byte responseDeviceAddress; byte responseFc = 0; short dataLength = 0; while (timeout > 0) { var ts = DateTime.Now.Ticks; if (!masterInterface.ReceiveTelegram(buffer, desiredDataLength, timeout, out telegramLength)) { throw new ModbusException(ModbusErrorCode.Timeout); } timeout -= (int) ((DateTime.Now.Ticks - ts)/10000); // if this is not the response we are waiting for wait again until time runs out if (masterInterface.ParseTelegram(buffer, telegramLength, true, ref telegramContext, out responseDeviceAddress, out responseFc, out dataPos, out dataLength) && responseDeviceAddress == deviceAddress && (responseFc & 0x7f) == (byte) fc) { break; } if (timeout <= 0) { throw new ModbusException(ModbusErrorCode.Timeout); } } if ((responseFc & 0x80) != 0) { // error response throw new ModbusException((ModbusErrorCode) buffer[dataPos]); } return dataLength; } finally { masterInterface.PrepareWrite(); } } }