001package jmri.jmrix.loconet.pr4;
002
003import jmri.jmrix.loconet.LnCommandStationType;
004import jmri.jmrix.loconet.LnPacketizer;
005import jmri.jmrix.loconet.LocoNetMessage;
006import jmri.jmrix.loconet.LocoNetSystemConnectionMemo;
007import jmri.jmrix.loconet.locobuffer.LocoBufferAdapter;
008import org.slf4j.Logger;
009import org.slf4j.LoggerFactory;
010import purejavacomm.SerialPort;
011import purejavacomm.UnsupportedCommOperationException;
012
013/**
014 * Override {@link jmri.jmrix.loconet.locobuffer.LocoBufferAdapter} so that it refers to the
015 * (switch) settings on the Digitrax PR4.
016 * <p>
017 * Based on PR3Adapter.java
018 *
019 * @author Bob Jacobsen Copyright (C) 2004, 2005, 2006, 2008
020 * @author B. Milhaupt Copyright (C) 2019
021 */
022public class PR4Adapter extends LocoBufferAdapter {
023
024    public PR4Adapter() {
025        super(new PR4SystemConnectionMemo());
026
027        options.remove(option2Name);
028        options.put(option2Name, new Option(Bundle.getMessage("CommandStationTypeLabel"), commandStationOptions(), false));
029
030    }
031
032    /**
033     * Sets up the serial port characteristics.  Always uses flow control, which is
034     * not considered a user-settable option.  Sets the PR4 for the appropriate
035     * operating mode, based on the selected "command station type".
036     *
037     * @param activeSerialPort  the port to be configured
038     */
039    @Override
040    protected void setSerialPort(SerialPort activeSerialPort) throws UnsupportedCommOperationException {
041        // find the baud rate value, configure comm options
042        int baud = currentBaudNumber(mBaudRate);
043        activeSerialPort.setSerialPortParams(baud, SerialPort.DATABITS_8,
044                SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
045
046        // configure flow control to always on
047        int flow = SerialPort.FLOWCONTROL_RTSCTS_OUT;
048        if (getOptionState(option1Name).equals(validOption1[1])) {
049            flow = SerialPort.FLOWCONTROL_NONE;
050        }
051        configureLeadsAndFlowControl(activeSerialPort, flow);
052
053        log.info("PR4 adapter{}{} RTSCTS_OUT=" + SerialPort.FLOWCONTROL_RTSCTS_OUT + " RTSCTS_IN=" + SerialPort.FLOWCONTROL_RTSCTS_IN, activeSerialPort.getFlowControlMode() == SerialPort.FLOWCONTROL_RTSCTS_OUT ? " set hardware flow control, mode=" : " set no flow control, mode=", activeSerialPort.getFlowControlMode());
054    }
055
056    /**
057     * Set up all of the other objects to operate with a PR4 connected to this
058     * port. This overrides the version in loconet.locobuffer, but it has to
059     * duplicate much of the functionality there, so the code is basically
060     * copied.
061     *
062     * Note that the PR4 does not support "LocoNet Data Signal termination" when
063     * in LocoNet interface mode (i.e. MS100 mode).
064     */
065    @Override
066    public void configure() {
067        setCommandStationType(getOptionState(option2Name));
068        setTurnoutHandling(getOptionState(option3Name));
069        if (commandStationType == LnCommandStationType.COMMAND_STATION_PR4_ALONE) {
070            // PR4 standalone case
071            // connect to a packetizing traffic controller
072            // that does echoing
073            //
074            // Note - already created a LocoNetSystemConnectionMemo, so re-use
075            // it when creating a PR2 Packetizer.  (If create a new one, will
076            // end up with two "LocoNet" menus...)
077            jmri.jmrix.loconet.pr2.LnPr2Packetizer packets =
078                    new jmri.jmrix.loconet.pr2.LnPr2Packetizer(this.getSystemConnectionMemo());
079            packets.connectPort(this);
080
081            // set traffic controller and configure command station and mangers
082            this.getSystemConnectionMemo().setLnTrafficController(packets);
083            // do the common manager config
084            this.getSystemConnectionMemo().configureCommandStation(commandStationType,
085                    mTurnoutNoRetry, mTurnoutExtraSpace, mTranspondingAvailable, mInterrogateAtStart, mLoconetProtocolAutoDetect);  // never transponding!
086            this.getSystemConnectionMemo().configureManagersPR2();
087
088            // start operation
089            packets.startThreads();
090
091            // set mode
092            LocoNetMessage msg = new LocoNetMessage(6);
093            msg.setOpCode(0xD3);
094            msg.setElement(1, 0x10);
095            msg.setElement(2, 1);  // set PR2
096            msg.setElement(3, 0);
097            msg.setElement(4, 0);
098            packets.sendLocoNetMessage(msg);
099
100        } else {
101            // MS100 modes - connecting to a separate command station
102            // get transponding option
103            setTranspondingAvailable(getOptionState("TranspondingPresent"));
104            setInterrogateOnStart(getOptionState("InterrogateOnStart"));
105            setLoconetProtocolAutoDetect(getOptionState("LoconetProtocolAutoDetect"));
106            // connect to a packetizing traffic controller
107            LnPacketizer packets = getPacketizer(getOptionState(option4Name));
108            packets.connectPort(this);
109
110            // set traffic controller and configure command station and mangers
111            this.getSystemConnectionMemo().setLnTrafficController(packets);
112            // do the common manager config
113            this.getSystemConnectionMemo().configureCommandStation(commandStationType,
114                    mTurnoutNoRetry, mTurnoutExtraSpace, mTranspondingAvailable, mInterrogateAtStart, mLoconetProtocolAutoDetect);
115
116            this.getSystemConnectionMemo().configureManagersMS100();
117
118            // start operation
119            packets.startThreads();
120
121            // set mode
122            LocoNetMessage msg = new LocoNetMessage(6);
123            msg.setOpCode(0xD3);
124            msg.setElement(1, 0x10);
125            msg.setElement(2, 0);  // set MS100, no power
126            msg.setElement(3, 0);
127            msg.setElement(4, 0);
128            packets.sendLocoNetMessage(msg);
129        }
130    }
131
132    /**
133     * {@inheritDoc}
134     *
135     * @return String[] containing the single valid baud rate, "57,600".
136     */
137    @Override
138    public String[] validBaudRates() {
139        return new String[]{"57,600 baud"}; // NOI18N
140    }
141
142    /**
143     * {@inheritDoc}
144     *
145     * @return int[] containing the single valid baud rate, 57600.
146     */
147    @Override
148    public int[] validBaudNumbers() {
149        return new int[]{57600};
150    }
151
152    @Override
153    public int defaultBaudIndex() {
154        return 0;
155    }
156
157    // Option 1 does flow control, inherited from LocoBufferAdapter
158
159    /**
160     * The PR4 can be used as a "Standalone Programmer", or with various LocoNet
161     * command stations.  The PR4 does not support "LocoNet Data signal termination",
162     * so that is not added as a valid option (as it would be for the PR3).
163     *
164     * @return an array of strings containing the various command station names and
165     *      name(s) of modes without command stations
166     */
167    public String[] commandStationOptions() {
168        String[] retval = new String[commandStationNames.length + 2];
169        retval[0] = LnCommandStationType.COMMAND_STATION_PR4_ALONE.getName();
170        for (int i = 0; i < commandStationNames.length; i++) {
171            retval[i + 1] = commandStationNames[i];
172        }
173        // Add "Standalone LocoNet" option
174        // Note: PR4 does not provide "LocoNet Data Termination" and _requires_
175        // some external source of that feature.
176        retval[retval.length - 1] = LnCommandStationType.COMMAND_STATION_STANDALONE.getName() + " (using external LocoNet Data Termination!)"; // NOI18N
177        return retval;
178    }
179
180    @Override
181    public PR4SystemConnectionMemo getSystemConnectionMemo() {
182        LocoNetSystemConnectionMemo m = super.getSystemConnectionMemo();
183        if (m instanceof PR4SystemConnectionMemo) {
184            return (PR4SystemConnectionMemo) m;
185        }
186        log.error("Cannot cast the system connection memo to a PR4SystemConnection Memo.");
187        return null;
188    }
189
190    private final static Logger log = LoggerFactory.getLogger(PR4Adapter.class);
191}