/*** * 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. ***/ package net.wimpi.modbus.io; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import gnu.io.CommPort; import gnu.io.UnsupportedCommOperationException; 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; /** * Abstract base class for serial <tt>ModbusTransport</tt> * implementations. * * @author Dieter Wimberger * @author John Charlton * * @version @version@ (@date@) */ abstract public class ModbusSerialTransport implements ModbusTransport { private static final Logger logger = LoggerFactory.getLogger(ModbusSerialTransport.class); protected CommPort m_CommPort; protected boolean m_Echo = false; // require RS-485 echo processing /** * <code>prepareStreams</code> prepares the input and output streams of this * <tt>ModbusSerialTransport</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. */ abstract public void prepareStreams(InputStream in, OutputStream out) throws IOException; /** * <code>readResponse</code> reads a response message from the slave * responding to a master writeMessage request. * * @return a <code>ModbusResponse</code> value * @exception ModbusIOException if an error occurs */ @Override abstract public ModbusResponse readResponse() throws ModbusIOException; /** * The <code>readRequest</code> method listens continuously on the serial * input stream for master request messages and replies if the request slave * ID matches its own set in ModbusCoupler.getUnitID(). * * @return a <code>ModbusRequest</code> value * @exception ModbusIOException if an error occurs */ @Override abstract public ModbusRequest readRequest() throws ModbusIOException; /** * The <code>writeMessage</code> method writes a modbus serial message to * its serial output stream to a specified slave unit ID. * * @param msg a <code>ModbusMessage</code> value * @exception ModbusIOException if an error occurs */ @Override abstract public void writeMessage(ModbusMessage msg) throws ModbusIOException; /** * The <code>close</code> method closes the serial input/output streams. * * @exception IOException if an error occurs */ @Override public void close() throws IOException { if (m_CommPort != null) { m_CommPort.close(); } } /** * <code>setCommPort</code> sets the comm port member and prepares the input * and output streams to be used for reading from and writing to. * * @param cp the comm port to read from/write to. * @throws IOException if an I/O related error occurs. */ public void setCommPort(CommPort cp) throws IOException { // Close existing port, if any close(); m_CommPort = cp; if (cp != null) { prepareStreams(cp.getInputStream(), cp.getOutputStream()); } } /** * <code>isEcho</code> method returns the output echo state. * * @return a <code>boolean</code> value */ public boolean isEcho() { return m_Echo; }// isEcho /** * <code>setEcho</code> method sets the output echo state. * * @param b a <code>boolean</code> value */ public void setEcho(boolean b) { this.m_Echo = b; }// setEcho /** * Describe <code>setReceiveThreshold</code> method here. * * @param th an <code>int</code> value */ public void setReceiveThreshold(int th) { try { m_CommPort.enableReceiveThreshold(th); /* chars */ } catch (UnsupportedCommOperationException e) { logger.error("Failed to setReceiveThreshold: {}", e.getMessage()); } } /** * Describe <code>setReceiveTimeout</code> method here. * * @param ms an <code>int</code> value */ public void setReceiveTimeout(int ms) { try { m_CommPort.enableReceiveTimeout(ms); /* milliseconds */ } catch (UnsupportedCommOperationException e) { logger.error("Failed to setReceiveTimeout: {}", e.getMessage()); } } /** * Reads the own message echo produced in RS485 Echo Mode * within the given time frame. * * @param len is the length of the echo to read. Timeout will occur if the * echo is not received in the time specified in the SerialConnection. * * @throws IOException if a I/O error occurred. */ public void readEcho(int len) throws IOException { byte echoBuf[] = new byte[len]; setReceiveThreshold(len); int echoLen = m_CommPort.getInputStream().read(echoBuf, 0, len); logger.debug("Echo: {}", ModbusUtil.toHex(echoBuf, 0, echoLen)); m_CommPort.disableReceiveThreshold(); if (echoLen != len) { final String errMsg = "Echo not received"; logger.error("Transmit {}", errMsg); throw new IOException(errMsg); } }// readEcho }// interface ModbusSerialTransport