public interface Modbus {

	/**
	 * JVM flag for debug mode. Can be set passing the system property
	 * net.wimpi.modbus.debug=false|true (-D flag to the jvm).
	 */
	public static final boolean debug = "true".equals(System
			.getProperty("net.wimpi.modbus.debug"));

	/**
	 * Defines the class 0 function code for <tt>read multiple registers</tt>.
	 */
	public static final int READ_MULTIPLE_REGISTERS = 3;

	/**
	 * Defines the class 0 function code for <tt>write multiple registers</tt>.
	 */
	public static final int WRITE_MULTIPLE_REGISTERS = 16;

	/**
	 * Defines the class 1 function code for <tt>read coils</tt>.
	 */
	public static final int READ_COILS = 1;

	/**
	 * Defines a class 1 function code for <tt>read input discretes</tt>.
	 */
	public static final int READ_INPUT_DISCRETES = 2;

	/**
	 * Defines a class 1 function code for <tt>read input registers</tt>.
	 */
	public static final int READ_INPUT_REGISTERS = 4;

	/**
	 * Defines a class 1 function code for <tt>write coil</tt>.
	 */
	public static final int WRITE_COIL = 5;

	/**
	 * Defines a standard function code for <tt>write multiple coils</tt>.
	 */
	public static final int WRITE_MULTIPLE_COILS = 15;

	/**
	 * Defines a class 1 function code for <tt>write single register</tt>.
	 */
	public static final int WRITE_SINGLE_REGISTER = 6;

	/**
	 * Defines the byte representation of the coil state <b>on</b>.
	 */
	public static final int COIL_ON = (byte) 255;

	/**
	 * Defines the byte representation of the coil state <b>pos</b>.
	 */
	public static final int COIL_OFF = 0;

	/**
	 * Defines the word representation of the coil state <b>on</b>.
	 */
	public static final byte[] COIL_ON_BYTES = { (byte) COIL_ON,
			(byte) COIL_OFF };

	/**
	 * Defines the word representation of the coil state <b>pos</b>.
	 */
	public static final byte[] COIL_OFF_BYTES = { (byte) COIL_OFF,
			(byte) COIL_OFF };

	/**
	 * Defines the maximum number of bits in multiple read/write of input
	 * discretes or coils (<b>2000</b>).
	 */
	public static final int MAX_BITS = 2000;

	/**
	 * Defines the Modbus slave exception offset that is added to the function
	 * code, to flag an exception.
	 */
	public static final int EXCEPTION_OFFSET = 128; // the last valid function
													// code is 127

	/**
	 * Defines the Modbus slave exception type <tt>illegal function</tt>. This
	 * exception code is returned if the slave:
	 * <ul>
	 * <li>does not implement the function code <b>or</b></li>
	 * <li>is not in a state that allows it to process the function</li>
	 * </ul>
	 */
	public static final int ILLEGAL_FUNCTION_EXCEPTION = 1;

	/**
	 * Defines the Modbus slave exception type <tt>illegal data address</tt>.
	 * This exception code is returned if the reference:
	 * <ul>
	 * <li>does not exist on the slave <b>or</b></li>
	 * <li>the combination of reference and length exceeds the bounds of the
	 * existing registers.</li>
	 * </ul>
	 */
	public static final int ILLEGAL_ADDRESS_EXCEPTION = 2;

	/**
	 * Defines the Modbus slave exception type <tt>illegal data value</tt>. This
	 * exception code indicates a fault in the structure of the data values of a
	 * complex request, such as an incorrect implied length.<br>
	 * <b>This code does not indicate a problem with application specific
	 * validity of the value.</b>
	 */
	public static final int ILLEGAL_VALUE_EXCEPTION = 3;

	/**
	 * Defines the default port number of Modbus (=<tt>502</tt>).
	 */
	public static final int DEFAULT_PORT = 502;

	/**
	 * Defines the maximum message length for serial transport in bytes (=
	 * <tt>256</tt>). RS232 / RS485 ADU = 253 bytes + Server address (1 byte) +
	 * CRC (2 bytes) = 256 bytes.
	 */
	public static final int MAX_MESSAGE_LENGTH = 256;

	/**
	 * Defines the maximum message length for IP transport in bytes (=
	 * <tt>260</tt>). TCP MODBUS ADU = 253 bytes + MBAP (7 bytes) = 260 bytes.
	 */
	public static final int MAX_IP_MESSAGE_LENGTH = 260;

	/**
	 * Defines the default transaction identifier (=<tt>0</tt>).
	 */
	public static final int DEFAULT_TRANSACTION_ID = 0;

	/**
	 * Defines the default protocol identifier (=<tt>0</tt>).
	 */
	public static final int DEFAULT_PROTOCOL_ID = 0;

	/**
	 * Defines the default unit identifier (=<tt>0</tt>).
	 */
	public static final int DEFAULT_UNIT_ID = 0;

	/**
	 * Defines the default setting for validity checking in transactions (=
	 * <tt>true</tt>).
	 */
	public static final boolean DEFAULT_VALIDITYCHECK = true;

	/**
	 * Defines the default setting for I/O operation timeouts in milliseconds (=
	 * <tt>3000</tt>).
	 */
	public static final int DEFAULT_TIMEOUT = 3000;

	/**
	 * Defines the default reconnecting setting for transactions (=
	 * <tt>false</tt>).
	 */
	public static final boolean DEFAULT_RECONNECTING = false;

	/**
	 * Defines the default amount of retires for opening a connection (=
	 * <tt>3</tt>).
	 */
	public static final int DEFAULT_RETRIES = 3;

	/**
	 * Defines the default number of msec to delay before transmission (=
	 * <tt>50</tt>).
	 */
	public static final int DEFAULT_TRANSMIT_DELAY = 0;

	/**
	 * Defines the maximum value of the transaction identifier.
	 */
	public static final int MAX_TRANSACTION_ID = (Short.MAX_VALUE * 2) - 1;

	/**
	 * Defines the serial encoding "ASCII".
	 */
	public static final String SERIAL_ENCODING_ASCII = "ascii";

	/**
	 * Defines the serial encoding "RTU".
	 */
	public static final String SERIAL_ENCODING_RTU = "rtu";

	/**
	 * Defines the serial encoding "BIN".
	 */
	public static final String SERIAL_ENCODING_BIN = "bin";

	/**
	 * Defines the default serial encoding (ASCII).
	 */
	public static final String DEFAULT_SERIAL_ENCODING = SERIAL_ENCODING_ASCII;

}// class Modbus @SuppressWarnings("serial")
public class ModbusException extends Exception {

	/**
	 * Constructs a new <tt>ModbusException</tt> instance.
	 */
	public ModbusException() {
		super();
	}// constructor

	/**
	 * Constructs a new <tt>ModbusException</tt> instance with the given
	 * message.
	 * <p>
	 * 
	 * @param message
	 *            the message describing this <tt>ModbusException</tt>.
	 */
	public ModbusException(String message) {
		super(message);
	}// constructor

}// ModbusException @SuppressWarnings("serial")
public class ModbusIOException extends ModbusException {

	private boolean m_EOF = false;

	/**
	 * Constructs a new <tt>ModbusIOException</tt> instance.
	 */
	public ModbusIOException() {
	}// constructor

	/**
	 * Constructs a new <tt>ModbusIOException</tt> instance with the given
	 * message.
	 * <p>
	 * 
	 * @param message
	 *            the message describing this <tt>ModbusIOException</tt>.
	 */
	public ModbusIOException(String message) {
		super(message);
	}// constructor(String)

	/**
	 * Constructs a new <tt>ModbusIOException</tt> instance.
	 * 
	 * @param b
	 *            true if caused by end of stream, false otherwise.
	 */
	public ModbusIOException(boolean b) {
		m_EOF = b;
	}// constructor

	/**
	 * Constructs a new <tt>ModbusIOException</tt> instance with the given
	 * message.
	 * <p>
	 * 
	 * @param message
	 *            the message describing this <tt>ModbusIOException</tt>.
	 * @param b
	 *            true if caused by end of stream, false otherwise.
	 */
	public ModbusIOException(String message, boolean b) {
		super(message);
		m_EOF = b;
	}// constructor(String)

	/**
	 * Tests if this <tt>ModbusIOException</tt> is caused by an end of the
	 * stream.
	 * <p>
	 * 
	 * @return true if stream ended, false otherwise.
	 */
	public boolean isEOF() {
		return m_EOF;
	}// isEOF

	/**
	 * Sets the flag that determines whether this <tt>ModbusIOException</tt> was
	 * caused by an end of the stream.
	 * <p>
	 * 
	 * @param b
	 *            true if stream ended, false otherwise.
	 */
	public void setEOF(boolean b) {
		m_EOF = b;
	}// setEOF

}// ModbusIOException @SuppressWarnings("serial")
public class ModbusSlaveException extends ModbusException {

	// instance attributes
	private int m_Type = -1;

	/**
	 * Constructs a new <tt>ModbusSlaveException</tt> instance with the given
	 * type.<br>
	 * Types are defined according to the protocol specification in
	 * <tt>net.wimpi.modbus.Modbus</tt>.
	 * <p>
	 * 
	 * @param TYPE
	 *            the type of exception that occured.
	 * 
	 * @see net.wimpi.modbus.Modbus
	 */
	public ModbusSlaveException(int TYPE) {
		super();
		m_Type = TYPE;
	}// constructor

	/**
	 * Returns the type of this <tt>ModbusSlaveException</tt>. <br>
	 * Types are defined according to the protocol specification in
	 * <tt>net.wimpi.modbus.Modbus</tt>.
	 * <p>
	 * 
	 * @return the type of this <tt>ModbusSlaveException</tt>.
	 * 
	 * @see net.wimpi.modbus.Modbus
	 */
	public int getType() {
		return m_Type;
	}// getType

	/**
	 * Tests if this <tt>ModbusSlaveException</tt> is of a given type. <br>
	 * Types are defined according to the protocol specification in
	 * <tt>net.wimpi.modbus.Modbus</tt>.
	 * <p>
	 * 
	 * @param TYPE
	 *            the type to test this <tt>ModbusSlaveException</tt> type
	 *            against.
	 * 
	 * @return true if this <tt>ModbusSlaveException</tt> is of the given type,
	 *         false otherwise.
	 * 
	 * @see net.wimpi.modbus.Modbus
	 */
	public boolean isType(int TYPE) {
		return (TYPE == m_Type);
	}// isType

	public String getMessage() {
		return "Error Code = " + m_Type;
	}// getMessage

}// ModbusSlaveException public class ExceptionResponse extends ModbusResponse {

	// instance attributes
	private int m_ExceptionCode = -1;

	/**
	 * Constructs a new <tt>ExceptionResponse</tt> instance.
	 */
	public ExceptionResponse() {
		// exception code, unitid and function code not counted.
		setDataLength(1);
	}// constructor

	/**
	 * Constructs a new <tt>ExceptionResponse</tt> instance with a given
	 * function code. Adds the exception offset automatically.
	 * 
	 * @param fc
	 *            the function code as <tt>int</tt>.
	 */
	public ExceptionResponse(int fc) {
		// unitid and function code not counted.
		setDataLength(1);
		setFunctionCode(fc + Modbus.EXCEPTION_OFFSET);
	}// constructor

	/**
	 * Constructs a new <tt>ExceptionResponse</tt> instance with a given
	 * function code and an exception code. The function code will be
	 * automatically increased with the exception offset.
	 * 
	 * 
	 * @param fc
	 *            the function code as <tt>int</tt>.
	 * @param exc
	 *            the exception code as <tt>int</tt>.
	 */
	public ExceptionResponse(int fc, int exc) {
		// exception code, unitid and function code not counted.
		setDataLength(1);
		setFunctionCode(fc + Modbus.EXCEPTION_OFFSET);
		m_ExceptionCode = exc;
	}// constructor

	/**
	 * Returns the Modbus exception code of this <tt>ExceptionResponse</tt>.
	 * <p>
	 * 
	 * @return the exception code as <tt>int</tt>.
	 */
	public int getExceptionCode() {
		return m_ExceptionCode;
	}// getExceptionCode

	public void writeData(DataOutput dout) throws IOException {
		dout.writeByte(getExceptionCode());
	}// writeData

	public void readData(DataInput din) throws IOException {
		m_ExceptionCode = din.readUnsignedByte();
	}// readData

	public String toString() {
		return "ExceptionResponse - Exception code: " + m_ExceptionCode;
	}

}// ExceptionResponse public abstract class ModbusRequest extends ModbusMessageImpl {

	/**
	 * Returns the <tt>ModbusResponse</tt> that correlates with this
	 * <tt>ModbusRequest</tt>.
	 * <p>
	 * 
	 * @return the corresponding <tt>ModbusResponse</tt>.
	 * 
	 *         public abstract ModbusResponse getResponse();
	 */

	/**
	 * Returns the <tt>ModbusResponse</tt> that represents the answer to this
	 * <tt>ModbusRequest</tt>.
	 * <p>
	 * The implementation should take care about assembling the reply to this
	 * <tt>ModbusRequest</tt>.
	 * <p>
	 * 
	 * @return the corresponding <tt>ModbusResponse</tt>.
	 */
	public abstract ModbusResponse createResponse();

	/**
	 * Factory method for creating exception responses with the given exception
	 * code.
	 * 
	 * @param EXCEPTION_CODE
	 *            the code of the exception.
	 * @return a ModbusResponse instance representing the exception response.
	 */
	public ModbusResponse createExceptionResponse(int EXCEPTION_CODE) {
		ExceptionResponse response = new ExceptionResponse(
				this.getFunctionCode(), EXCEPTION_CODE);
		if (!isHeadless()) {
			response.setTransactionID(this.getTransactionID());
			response.setProtocolID(this.getProtocolID());
			response.setUnitID(this.getUnitID());
		} else {
			response.setHeadless();
		}
		return response;
	}// createExceptionResponse

	/**
	 * Factory method creating the required specialized <tt>ModbusRequest</tt>
	 * instance.
	 * 
	 * @param functionCode
	 *            the function code of the request as <tt>int</tt>.
	 * @return a ModbusRequest instance specific for the given function type.
	 */
	public static ModbusRequest createModbusRequest(int functionCode) {
		ModbusRequest request = null;

		switch (functionCode) {
		case Modbus.READ_MULTIPLE_REGISTERS:
			request = new ReadMultipleRegistersRequest();
			break;
		case Modbus.READ_INPUT_DISCRETES:
			request = new ReadInputDiscretesRequest();
			break;
		case Modbus.READ_INPUT_REGISTERS:
			request = new ReadInputRegistersRequest();
			break;
		case Modbus.READ_COILS:
			request = new ReadCoilsRequest();
			break;
		case Modbus.WRITE_MULTIPLE_REGISTERS:
			request = new WriteMultipleRegistersRequest();
			break;
		case Modbus.WRITE_SINGLE_REGISTER:
			request = new WriteSingleRegisterRequest();
			break;
		case Modbus.WRITE_COIL:
			request = new WriteCoilRequest();
			break;
		case Modbus.WRITE_MULTIPLE_COILS:
			request = new WriteMultipleCoilsRequest();
			break;
		default:
			request = new IllegalFunctionRequest(functionCode);
			break;
		}
		return request;
	}// createModbusRequest

	public abstract int getReference();

}// class ModbusRequest public abstract class ModbusResponse extends ModbusMessageImpl {

	/**
	 * Utility method to set the raw data of the message. Should not be used
	 * except under rare circumstances.
	 * <p>
	 * 
	 * @param msg
	 *            the <tt>byte[]</tt> resembling the raw modbus response
	 *            message.
	 */
	protected void setMessage(byte[] msg) {
		try {
			readData(new DataInputStream(new ByteArrayInputStream(msg)));
		} catch (IOException ex) {

		}
	}// setMessage

	/**
	 * Factory method creating the required specialized <tt>ModbusResponse</tt>
	 * instance.
	 * 
	 * @param functionCode
	 *            the function code of the response as <tt>int</tt>.
	 * @return a ModbusResponse instance specific for the given function code.
	 */
	public static ModbusResponse createModbusResponse(int functionCode) {
		ModbusResponse response = null;

		switch (functionCode) {
		case Modbus.READ_MULTIPLE_REGISTERS:
			response = new ReadMultipleRegistersResponse();
			break;
		case Modbus.READ_INPUT_DISCRETES:
			response = new ReadInputDiscretesResponse();
			break;
		case Modbus.READ_INPUT_REGISTERS:
			response = new ReadInputRegistersResponse();
			break;
		case Modbus.READ_COILS:
			response = new ReadCoilsResponse();
			break;
		case Modbus.WRITE_MULTIPLE_REGISTERS:
			response = new WriteMultipleRegistersResponse();
			break;
		case Modbus.WRITE_SINGLE_REGISTER:
			response = new WriteSingleRegisterResponse();
			break;
		case Modbus.WRITE_COIL:
			response = new WriteCoilResponse();
			break;
		case Modbus.WRITE_MULTIPLE_COILS:
			response = new WriteMultipleCoilsResponse();
			break;
		default:
			response = new ExceptionResponse();
			break;
		}
		return response;
	}// createModbusResponse

}// class ModbusResponse public class TCPMasterConnection {

	// instance attributes
	private Socket m_Socket;
	private int m_Timeout = Modbus.DEFAULT_TIMEOUT;
	private boolean m_Connected;

	private InetAddress m_Address;
	private int m_Port = Modbus.DEFAULT_PORT;

	// private int m_Retries = Modbus.DEFAULT_RETRIES;
	private ModbusTCPTransport m_ModbusTransport;

	/**
	 * Constructs a <tt>TCPMasterConnection</tt> instance with a given
	 * destination address.
	 * 
	 * @param adr
	 *            the destination <tt>InetAddress</tt>.
	 */
	public TCPMasterConnection(InetAddress adr) {
		m_Address = adr;
	}// constructor

	/**
	 * Opens this <tt>TCPMasterConnection</tt>.
	 * 
	 * @throws Exception
	 *             if there is a network failure.
	 */
	public synchronized void connect() throws Exception {
		if (!m_Connected) {
			if (Modbus.debug)
				System.out.println("connect()");
			m_Socket = new Socket();
			java.net.InetSocketAddress sockaddr = new java.net.InetSocketAddress(
					m_Address, m_Port);
			m_Socket.connect(sockaddr, m_Timeout);
			setTimeout(m_Timeout);
			prepareTransport();
			m_Connected = true;
		}
	}// connect

	/**
	 * Closes this <tt>TCPMasterConnection</tt>.
	 */
	public void close() {
		if (m_Connected) {
			try {
				m_ModbusTransport.close();
			} catch (IOException ex) {
				if (Modbus.debug)
					System.out.println("close()");
			}
			m_Connected = false;
		}
	}// close

	/**
	 * Returns the <tt>ModbusTransport</tt> associated with this
	 * <tt>TCPMasterConnection</tt>.
	 * 
	 * @return the connection's <tt>ModbusTransport</tt>.
	 */
	public ModbusTransport getModbusTransport() {
		return m_ModbusTransport;
	}// getModbusTransport

	/**
	 * Prepares the associated <tt>ModbusTransport</tt> of this
	 * <tt>TCPMasterConnection</tt> for use.
	 * 
	 * @throws IOException
	 *             if an I/O related error occurs.
	 */
	private void prepareTransport() throws IOException {
		if (m_ModbusTransport == null) {
			m_ModbusTransport = new ModbusTCPTransport(m_Socket);
		} else {
			m_ModbusTransport.setSocket(m_Socket);
		}
	}// prepareIO

	/**
	 * Returns the timeout for this <tt>TCPMasterConnection</tt>.
	 * 
	 * @return the timeout as <tt>int</tt>.
	 */
	public int getTimeout() {
		return m_Timeout;
	}// getReceiveTimeout

	/**
	 * Sets the timeout for this <tt>TCPMasterConnection</tt>.
	 * 
	 * @param timeout
	 *            the timeout as <tt>int</tt>.
	 */
	public void setTimeout(int timeout) {
		m_Timeout = timeout;
		if (m_Socket != null) {
			try {
				m_Socket.setSoTimeout(m_Timeout);
			} catch (IOException ex) {
				// handle?
			}
		}
	}// setReceiveTimeout

	/**
	 * Returns the destination port of this <tt>TCPMasterConnection</tt>.
	 * 
	 * @return the port number as <tt>int</tt>.
	 */
	public int getPort() {
		return m_Port;
	}// getPort

	/**
	 * Sets the destination port of this <tt>TCPMasterConnection</tt>. The
	 * default is defined as <tt>Modbus.DEFAULT_PORT</tt>.
	 * 
	 * @param port
	 *            the port number as <tt>int</tt>.
	 */
	public void setPort(int port) {
		m_Port = port;
	}// setPort

	/**
	 * Returns the destination <tt>InetAddress</tt> of this
	 * <tt>TCPMasterConnection</tt>.
	 * 
	 * @return the destination address as <tt>InetAddress</tt>.
	 */
	public InetAddress getAddress() {
		return m_Address;
	}// getAddress

	/**
	 * Sets the destination <tt>InetAddress</tt> of this
	 * <tt>TCPMasterConnection</tt>.
	 * 
	 * @param adr
	 *            the destination address as <tt>InetAddress</tt>.
	 */
	public void setAddress(InetAddress adr) {
		m_Address = adr;
	}// setAddress

	/**
	 * Tests if this <tt>TCPMasterConnection</tt> is connected.
	 * 
	 * @return <tt>true</tt> if connected, <tt>false</tt> otherwise.
	 */
	public boolean isConnected() {
		return m_Connected;
	}// isConnected

}// class TCPMasterConnection public class AtomicCounter {

	private int m_Value;

	/**
	 * Constructs a new <tt>AtomicInteger</tt>.
	 */
	public AtomicCounter() {
		m_Value = 0;
	}// constructor

	/**
	 * Constructs a new <tt>AtomicInteger</tt> with a given initial value.
	 * 
	 * @param value
	 *            the initial value.
	 */
	public AtomicCounter(int value) {
		m_Value = value;
	}// constructor

	/**
	 * Increments this <tt>AtomicInteger</tt> by one.
	 * 
	 * @return the resulting value.
	 */
	public synchronized int increment() {
		if (m_Value == Modbus.MAX_TRANSACTION_ID) {
			m_Value = 0;
		}
		return ++m_Value;
	}// increment

	/**
	 * Returns the value of this <tt>AtomicInteger</tt>.
	 * 
	 * @return the actual value.
	 */
	public synchronized int get() {
		return m_Value;
	}// get

}// class AtomicCounter public class Mutex {

	/**
	 * The lock status
	 */
	protected boolean inuse_ = false;

	public void acquire() throws InterruptedException {
		if (Thread.interrupted())
			throw new InterruptedException();
		synchronized (this) {
			try {
				while (inuse_)
					wait();
				inuse_ = true;
			} catch (InterruptedException ex) {
				notify();
				throw ex;
			}
		}
	}// accquire

	public synchronized void release() {
		inuse_ = false;
		notify();
	}// release

	public boolean attempt(long msecs) throws InterruptedException {
		if (Thread.interrupted())
			throw new InterruptedException();
		synchronized (this) {
			if (!inuse_) {
				inuse_ = true;
				return true;
			} else if (msecs <= 0)
				return false;
			else {
				long waitTime = msecs;
				long start = System.currentTimeMillis();
				try {
					for (;;) {
						wait(waitTime);
						if (!inuse_) {
							inuse_ = true;
							return true;
						} else {
							waitTime = msecs
									- (System.currentTimeMillis() - start);
							if (waitTime <= 0)
								return false;
						}
					}
				} catch (InterruptedException ex) {
					notify();
					throw ex;
				}
			}
		}
	}// attempt

}// class Mutex
import net.wimpi.modbus.Modbus;
import net.wimpi.modbus.ModbusException;
import net.wimpi.modbus.ModbusIOException;
import net.wimpi.modbus.ModbusSlaveException;
import net.wimpi.modbus.msg.ExceptionResponse;
import net.wimpi.modbus.msg.ModbusRequest;
import net.wimpi.modbus.msg.ModbusResponse;
import net.wimpi.modbus.net.TCPMasterConnection;
import net.wimpi.modbus.util.AtomicCounter;
import net.wimpi.modbus.util.Mutex;
/***
 * Copyright 2002-2010 jamod development team
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * Original implementation by jamod development team.
 * This file modified by Charles Hache <chache@brood.ca>
 ***/

package net.wimpi.modbus.io;


/**
 * Class implementing the <tt>ModbusTransaction</tt> interface.
 * 
 * @author Dieter Wimberger
 * @version @version@ (@date@)
 */
public class ModbusTCPTransaction implements ModbusTransaction {

	// class attributes
	private static AtomicCounter c_TransactionID = new AtomicCounter(
			Modbus.DEFAULT_TRANSACTION_ID);

	// instance attributes and associations
	private TCPMasterConnection m_Connection;
	private ModbusTransport m_IO;
	private ModbusRequest m_Request;
	private ModbusResponse m_Response;
	private boolean m_ValidityCheck = Modbus.DEFAULT_VALIDITYCHECK;
	private boolean m_Reconnecting = Modbus.DEFAULT_RECONNECTING;
	private int m_Retries = Modbus.DEFAULT_RETRIES;

	private Mutex m_TransactionLock = new Mutex();

	/**
	 * Constructs a new <tt>ModbusTCPTransaction</tt> instance.
	 */
	public ModbusTCPTransaction() {
	}// constructor

	/**
	 * Constructs a new <tt>ModbusTCPTransaction</tt> instance with a given
	 * <tt>ModbusRequest</tt> to be send when the transaction is executed.
	 * <p/>
	 * 
	 * @param request
	 *            a <tt>ModbusRequest</tt> instance.
	 */
	public ModbusTCPTransaction(ModbusRequest request) {
		setRequest(request);
	}// constructor

	/**
	 * Constructs a new <tt>ModbusTCPTransaction</tt> instance with a given
	 * <tt>TCPMasterConnection</tt> to be used for transactions.
	 * <p/>
	 * 
	 * @param con
	 *            a <tt>TCPMasterConnection</tt> instance.
	 */
	public ModbusTCPTransaction(TCPMasterConnection con) {
		setConnection(con);
	}// constructor

	/**
	 * Sets the connection on which this <tt>ModbusTransaction</tt> should be
	 * executed.
	 * <p>
	 * An implementation should be able to handle open and closed connections.
	 * <br>
	 * <p/>
	 * 
	 * @param con
	 *            a <tt>TCPMasterConnection</tt>.
	 */
	public void setConnection(TCPMasterConnection con) {
		m_Connection = con;
		m_IO = con.getModbusTransport();
	}// setConnection

	public void setRequest(ModbusRequest req) {
		m_Request = req;
	}// setRequest

	public ModbusRequest getRequest() {
		return m_Request;
	}// getRequest

	public ModbusResponse getResponse() {
		return m_Response;
	}// getResponse

	public int getTransactionID() {
		return c_TransactionID.get();
	}// getTransactionID

	public void setCheckingValidity(boolean b) {
		m_ValidityCheck = b;
	}// setCheckingValidity

	public boolean isCheckingValidity() {
		return m_ValidityCheck;
	}// isCheckingValidity

	/**
	 * Sets the flag that controls whether a connection is openend and closed
	 * for <b>each</b> execution or not.
	 * <p/>
	 * 
	 * @param b
	 *            true if reconnecting, false otherwise.
	 */
	public void setReconnecting(boolean b) {
		m_Reconnecting = b;
	}// setReconnecting

	/**
	 * Tests if the connection will be openend and closed for <b>each</b>
	 * execution.
	 * <p/>
	 * 
	 * @return true if reconnecting, false otherwise.
	 */
	public boolean isReconnecting() {
		return m_Reconnecting;
	}// isReconnecting

	public int getRetries() {
		return m_Retries;
	}// getRetries

	public void setRetries(int num) {
		m_Retries = num;
	}// setRetries

	public void execute() throws ModbusIOException, ModbusSlaveException,
			ModbusException {