Package net.wimpi.modbus.io

Source Code of net.wimpi.modbus.io.ModbusRTUTransport

//License
/***
* Java Modbus Library (jamod)
* Copyright (c) 2002-2004, jamod development team
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS
* IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
***/
package net.wimpi.modbus.io;

import net.wimpi.modbus.Modbus;
import net.wimpi.modbus.ModbusIOException;
import net.wimpi.modbus.msg.ModbusMessage;
import net.wimpi.modbus.msg.ModbusRequest;
import net.wimpi.modbus.msg.ModbusResponse;
import net.wimpi.modbus.util.ModbusUtil;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
* Class that implements the ModbusRTU transport
* flavor.
*
* @author John Charlton
* @author Dieter Wimberger
*
* @version 1.2rc1 (09/11/2004)
*/
public class ModbusRTUTransport
    extends ModbusSerialTransport {

  private InputStream m_InputStream;    //wrap into filter input
  private OutputStream m_OutputStream;      //wrap into filter output

  private byte[] m_InBuffer;
  private BytesInputStream m_ByteIn;         //to read message from
  private BytesOutputStream m_ByteInOut;     //to buffer message to
  private BytesOutputStream m_ByteOut;      //write frames
  private byte[] lastRequest = null;

  public void writeMessage(ModbusMessage msg) throws ModbusIOException {
    try {
      int len;
      synchronized (m_ByteOut) {
        // first clear any input from the receive buffer to prepare
        // for the reply since RTU doesn't have message delimiters
        clearInput();
        //write message to byte out
        m_ByteOut.reset();
        msg.setHeadless();
        msg.writeTo(m_ByteOut);
        len = m_ByteOut.size();
        int[] crc = ModbusUtil.calculateCRC(m_ByteOut.getBuffer(), 0, len);
        m_ByteOut.writeByte(crc[0]);
        m_ByteOut.writeByte(crc[1]);
        //write message
        len = m_ByteOut.size();
        byte buf[] = m_ByteOut.getBuffer();
        m_OutputStream.write(buf, 0, len);     //PDU + CRC
        m_OutputStream.flush();
        if(Modbus.debug) System.out.println("Sent: " + ModbusUtil.toHex(buf, 0, len));
        // clears out the echoed message
        // for RS485
        if (m_Echo) {
          readEcho(len);
        }
        lastRequest = new byte[len];
        System.arraycopy(buf, 0, lastRequest, 0, len);
      }

    } catch (Exception ex) {
      throw new ModbusIOException("I/O failed to write");
    }

  }//writeMessage

  //This is required for the slave that is not supported
  public ModbusRequest readRequest() throws ModbusIOException {
    throw new RuntimeException("Operation not supported.");
  } //readRequest

  /**
   * Clear the input if characters are found in the input stream.
   *
   * @throws ModbusIOException
   */
  public void clearInput() throws IOException {
    if (m_InputStream.available() > 0) {
      int len = m_InputStream.available();
      byte buf[] = new byte[len];
      m_InputStream.read(buf, 0, len);
      if(Modbus.debug) System.out.println("Clear input: " +
                  ModbusUtil.toHex(buf, 0, len));
    }
  }//cleanInput

  public ModbusResponse readResponse()
      throws ModbusIOException {

    boolean done = false;
    ModbusResponse response = null;
    int dlength = 0;

    try {
      do {
        //1. read to function code, create request and read function specific bytes
        synchronized (m_ByteIn) {
          int uid = m_InputStream.read();
          if (uid != -1) {
            int fc = m_InputStream.read();
            m_ByteInOut.reset();
            m_ByteInOut.writeByte(uid);
            m_ByteInOut.writeByte(fc);

            //create response to acquire length of message
            response = ModbusResponse.createModbusResponse(fc);
            response.setHeadless();

            // With Modbus RTU, there is no end frame.  Either we assume
            // the message is complete as is or we must do function
            // specific processing to know the correct length.  To avoid
            // moving frame timing to the serial input functions, we set the
            // timeout and to message specific parsing to read a response.
            getResponse(fc, m_ByteInOut);
            dlength = m_ByteInOut.size() - 2; // less the crc
            if (Modbus.debug) System.out.println("Response: " +
               ModbusUtil.toHex(m_ByteInOut.getBuffer(), 0, dlength + 2));

            m_ByteIn.reset(m_InBuffer, dlength);

            //check CRC
            int[] crc = ModbusUtil.calculateCRC(m_InBuffer, 0, dlength); //does not include CRC
            if (ModbusUtil.unsignedByteToInt(m_InBuffer[dlength]) != crc[0]
                && ModbusUtil.unsignedByteToInt(m_InBuffer[dlength + 1]) != crc[1]) {
              throw new IOException("CRC Error in received frame: " + dlength + " bytes: " + ModbusUtil.toHex(m_ByteIn.getBuffer(), 0, dlength));
            }
          } else {
            throw new IOException("Error reading response");
          }

          //read response
          m_ByteIn.reset(m_InBuffer, dlength);
          if (response != null) {
            response.readFrom(m_ByteIn);
          }
          done = true;
        }//synchronized
      } while (!done);
      return response;
    } catch (Exception ex) {
      System.err.println("Last request: " + ModbusUtil.toHex(lastRequest));
      System.err.println(ex.getMessage());
      throw new ModbusIOException("I/O exception - failed to read");
    }
  }//readResponse

  /**
   * Prepares the input and output streams of this
   * <tt>ModbusRTUTransport</tt> instance.
   *
   * @param in the input stream to be read from.
   * @param out the output stream to write to.
   * @throws IOException if an I\O error occurs.
   */
  public void prepareStreams(InputStream in, OutputStream out)
      throws IOException {
    m_InputStream = in;   //new RTUInputStream(in);
    m_OutputStream = out;

    m_ByteOut = new BytesOutputStream(Modbus.MAX_MESSAGE_LENGTH);
    m_InBuffer = new byte[Modbus.MAX_MESSAGE_LENGTH];
    m_ByteIn = new BytesInputStream(m_InBuffer);
    m_ByteInOut = new BytesOutputStream(m_InBuffer);
  } //prepareStreams

  public void close() throws IOException {
    m_InputStream.close();
    m_OutputStream.close();
  }//close

  private void getResponse(int fn, BytesOutputStream out)
    throws IOException {
    int bc = -1, bc2 = -1, bcw = -1;
    int inpBytes = 0;
    byte inpBuf[] = new byte[256];

    try {
      switch (fn) {
        case 0x01:
        case 0x02:
        case 0x03:
        case 0x04:
        case 0x0C:
        case 0x11// report slave ID version and run/stop state
        case 0x14// read log entry (60000 memory reference)
        case 0x15// write log entry (60000 memory reference)
        case 0x17:
          // read the byte count;
          bc = m_InputStream.read();
          out.write(bc);
          // now get the specified number of bytes and the 2 CRC bytes
          setReceiveThreshold(bc+2);
          inpBytes = m_InputStream.read(inpBuf, 0, bc+2);
          out.write(inpBuf, 0, inpBytes);
          m_CommPort.disableReceiveThreshold();
          if (inpBytes != bc+2) {
            System.out.println("Error: looking for " + (bc+2) +
                               " bytes, received " + inpBytes);
          }
          break;
        case 0x05:
        case 0x06:
        case 0x0B:
        case 0x0F:
        case 0x10:
          // read status: only the CRC remains after address and function code
          setReceiveThreshold(6);
          inpBytes = m_InputStream.read(inpBuf, 0, 6);
          out.write(inpBuf, 0, inpBytes);
          m_CommPort.disableReceiveThreshold();
          break;
        case 0x07:
        case 0x08:
          // read status: only the CRC remains after address and function code
          setReceiveThreshold(3);
          inpBytes = m_InputStream.read(inpBuf, 0, 3);
          out.write(inpBuf, 0, inpBytes);
          m_CommPort.disableReceiveThreshold();
          break;
        case 0x16:
          // eight bytes in addition to the address and function codes
          setReceiveThreshold(8);
          inpBytes = m_InputStream.read(inpBuf, 0, 8);
          out.write(inpBuf, 0, inpBytes);
          m_CommPort.disableReceiveThreshold();
          break;
        case 0x18:
          // read the byte count word
          bc = m_InputStream.read();
          out.write(bc);
          bc2 = m_InputStream.read();
          out.write(bc2);
          bcw = ModbusUtil.makeWord(bc, bc2);
          // now get the specified number of bytes and the 2 CRC bytes
          setReceiveThreshold(bcw+2);
          inpBytes = m_InputStream.read(inpBuf, 0, bcw + 2);
          out.write(inpBuf, 0, inpBytes);
          m_CommPort.disableReceiveThreshold();
          break;
      }
    } catch (IOException e) {
      m_CommPort.disableReceiveThreshold();
      throw new IOException("getResponse serial port exception");
    }
  }//getResponse
 
} //ModbusRTUTransport
TOP

Related Classes of net.wimpi.modbus.io.ModbusRTUTransport

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.