001package jmri.jmrix.dccpp;
002
003import java.io.DataInputStream;
004import java.io.DataOutputStream;
005import org.slf4j.Logger;
006import org.slf4j.LoggerFactory;
007import purejavacomm.SerialPort;
008
009/**
010 * Abstract base for classes representing a DCC++ communications port.
011 * Based on XNetSerialPortController by Bob Jacobsen and Paul Bender.
012 *
013 * @author Bob Jacobsen Copyright (C) 2001, 2008
014 * @author Paul Bender Copyright (C) 2004,2010
015 * @author Mark Underwood Copyright (C) 2015
016 */
017public abstract class DCCppSerialPortController extends jmri.jmrix.AbstractSerialPortController implements DCCppPortController {
018
019    protected SerialPort activeSerialPort = null;
020
021    private boolean outputBufferEmpty = true;
022
023    public DCCppSerialPortController() {
024        super(new DCCppSystemConnectionMemo());
025        //option2Name = "Buffer";
026        //options.put(option2Name, new Option("Check Buffer : ", validOption2));
027    }
028
029    // base class. Implementations will provide InputStream and OutputStream
030    // objects to XNetTrafficController classes, who in turn will deal in messages.    
031    // returns the InputStream from the port
032    @Override
033    public abstract DataInputStream getInputStream();
034
035    // returns the outputStream to the port
036    @Override
037    public abstract DataOutputStream getOutputStream();
038
039    /**
040     * Check that this object is ready to operate. This is a question of
041     * configuration, not transient hardware status.
042     */
043    @Override
044    public abstract boolean status();
045
046    /**
047     * Can the port accept additional characters? The state of CTS determines
048     * this, as there seems to be no way to check the number of queued bytes and
049     * buffer length. This might go false for short intervals, but it might also
050     * stick off if something goes wrong.
051     */
052    @Override
053    public boolean okToSend() {
054        if ((activeSerialPort.getFlowControlMode() & SerialPort.FLOWCONTROL_RTSCTS_OUT) == SerialPort.FLOWCONTROL_RTSCTS_OUT) {
055            if (checkBuffer) {
056                log.debug("CTS: {} Buffer Empty: {}", activeSerialPort.isCTS(), outputBufferEmpty);
057                return (activeSerialPort.isCTS() && outputBufferEmpty);
058            } else {
059                log.debug("CTS: {}", activeSerialPort.isCTS());
060                return (activeSerialPort.isCTS());
061            }
062        } else {
063            if (checkBuffer) {
064                log.debug("Buffer Empty: {}", outputBufferEmpty);
065                return (outputBufferEmpty);
066            } else {
067                log.debug("No Flow Control or Buffer Check");
068                return (true);
069            }
070        }
071    }
072    
073    /**
074     * Say if the output buffer is empty or full.
075     * This should only be set to false by external processes.
076     */
077    @Override
078    synchronized public void setOutputBufferEmpty(boolean s) {
079        outputBufferEmpty = s;
080    }
081    
082    
083    /* Option 2 is not currently used with RxTx 2.0.  In the past, it
084       was used for the "check buffer status when sending" If this is still set
085       in a configuration file, we need to handle it, but we are not writing it
086       to new configuration files. */
087    /*public String getCurrentOption2Setting() {
088      if(getOptionState(option2Name)==null) return("no");
089     else return getOptionState(option2Name);
090     }*/
091
092    protected String[] validOption2 = new String[]{"yes", "no"};
093    private boolean checkBuffer = false;
094
095    /**
096     * Allow derived classes to set the private checkBuffer value.
097     * @param b Buffer to be held and used from now on.
098     */
099    protected void setCheckBuffer(boolean b) {
100        checkBuffer = b;
101    }
102    
103    @Override
104    public DCCppSystemConnectionMemo getSystemConnectionMemo() {
105        return (DCCppSystemConnectionMemo) super.getSystemConnectionMemo();
106    }
107
108    private final static Logger log = LoggerFactory.getLogger(DCCppSerialPortController.class);
109
110}