001package jmri.jmrix.loconet;
002
003import java.io.IOException;
004
005import jmri.InstanceManager;
006import jmri.ShutDownManager;
007import jmri.ShutDownTask;
008import jmri.implementation.AbstractShutDownTask;
009
010import org.slf4j.Logger;
011import org.slf4j.LoggerFactory;
012
013/**
014 * Base for classes representing a LocoNet communications port.
015 *
016 * @author Kevin Dickerson Copyright (C) 2011
017 * @author Bob Jacobsen    Copyright (C) 2023
018 */
019public abstract class LnNetworkPortController extends jmri.jmrix.AbstractNetworkPortController {
020
021    /**
022     * Base class. Implementations will provide InputStream and OutputStream
023     * objects to LnTrafficController classes, who in turn will deal in messages.
024     *
025     * @param connectionMemo associated memo for this connection
026     */
027    protected LnNetworkPortController(LocoNetSystemConnectionMemo connectionMemo) {
028        super(connectionMemo);
029        setManufacturer(LnConnectionTypeList.DIGITRAX);
030    }
031
032    protected LnCommandStationType commandStationType = null;
033
034    protected boolean mTurnoutNoRetry = false;
035    protected boolean mTurnoutExtraSpace = false;
036    protected boolean mInterrogateAtStart = true;
037
038    protected boolean mTranspondingAvailable = false;
039
040    protected boolean mLoconetProtocolAutoDetect = false;
041
042    protected LnCommandStationType[] commandStationTypes = {
043        LnCommandStationType.COMMAND_STATION_DCS100,
044        LnCommandStationType.COMMAND_STATION_DCS240,
045        LnCommandStationType.COMMAND_STATION_DCS210,
046        LnCommandStationType.COMMAND_STATION_DCS200,
047        LnCommandStationType.COMMAND_STATION_DCS050,
048        LnCommandStationType.COMMAND_STATION_DCS051,
049        LnCommandStationType.COMMAND_STATION_DCS052,
050        LnCommandStationType.COMMAND_STATION_DB150,
051        LnCommandStationType.COMMAND_STATION_IBX_TYPE_1,
052        LnCommandStationType.COMMAND_STATION_IBX_TYPE_2,
053        LnCommandStationType.COMMAND_STATION_LBPS,
054        LnCommandStationType.COMMAND_STATION_MM,
055        LnCommandStationType.COMMAND_STATION_DCS210PLUS,
056        LnCommandStationType.COMMAND_STATION_DCS240PLUS};
057
058    protected String[] commandStationNames;
059
060    {
061        commandStationNames = new String[commandStationTypes.length];
062        int i = 0;
063        for (LnCommandStationType type : commandStationTypes) {
064            commandStationNames[i++] = type.getName();
065        }
066    }
067
068    /**
069     * While opening, also register a ShutDown item that
070     * makes sure the socket is cleanly closed.
071     */
072    @Override
073    public void connect() throws IOException {
074        super.connect();
075        
076        ShutDownTask shutDownTask = new AbstractShutDownTask("Writing Blocks") {
077            @Override
078            public void run() {
079                log.info("Closing LocoNet network connection");
080                try {
081                    socketConn.close();
082                } catch (IOException ex) {
083                    log.error("Exception closing LocoNet network connection", ex);
084                }
085            }
086        };
087        InstanceManager.getDefault(ShutDownManager.class).register(shutDownTask);
088    }
089    
090    // There are also "PR3 standalone programmer" and "Stand-alone LocoNet"
091    // in pr3/PR3Adapter
092    /**
093     * Set config info from a name, which needs to be one of the valid ones.
094     *
095     * @param name the name of the command station
096     */
097    public void setCommandStationType(String name) {
098        try {
099            setCommandStationType(LnCommandStationType.getByName(name));
100        } catch (IllegalArgumentException e) {
101            // not a valid command station type, force
102            log.error("Invalid command station name: \"{}\", defaulting to {}", name, commandStationTypes[0]);
103            setCommandStationType(commandStationTypes[0]);
104        }
105    }
106
107    /**
108     * Set configcommand station type.
109     *
110     * @param value command station type enum
111     */
112    public void setCommandStationType(LnCommandStationType value) {
113        if (value == null) {
114            return;  // can happen while switching protocols
115        }
116        log.debug("setCommandStationType: {}", value);
117        commandStationType = value;
118    }
119
120    @Override
121    public LocoNetSystemConnectionMemo getSystemConnectionMemo() {
122        return (LocoNetSystemConnectionMemo) super.getSystemConnectionMemo();
123    }
124
125    public void setTurnoutHandling(String value) {
126        if (value.equals("One Only") || value.equals(Bundle.getMessage("HandleOneOnly"))
127                || value.equals("Both") || value.equals(Bundle.getMessage("HandleBoth"))) {
128            mTurnoutNoRetry = true;
129        }
130        log.debug("turnout no retry: {}", mTurnoutNoRetry); // NOI18N
131        if (value.equals("Spread") || value.equals(Bundle.getMessage("HandleSpread"))
132                || value.equals("Both") || value.equals(Bundle.getMessage("HandleBoth"))) {
133            mTurnoutExtraSpace = true;
134        }
135        log.debug("turnout extra space: {}", mTurnoutExtraSpace); // NOI18N
136    }
137
138    /**
139     * Set whether transponding is available.
140     *
141     * @param value either yes or no
142     */
143    public void setTranspondingAvailable(String value) {
144        // default (most common state) is off, so just check for Yes
145        mTranspondingAvailable = (value.equals("Yes") || value.equals(Bundle.getMessage("ButtonYes")));
146        log.debug("transponding available: {}", mTranspondingAvailable); // NOI18N
147    }
148
149    /**
150     * Set whether to use XP slots if available or not.
151     *
152     * @param value either Bundle.getMessage("LoconetProtocolAutoDetect") or no
153     */
154    public void setLoconetProtocolAutoDetect(String value) {
155        // default (most common state) is off, so just check for Yes
156        mLoconetProtocolAutoDetect = (value.equals("Yes") || value.equals(Bundle.getMessage("LoconetProtocolAutoDetect")));
157        log.debug("Loconet XPSlots: {}", mLoconetProtocolAutoDetect); // NOI18N
158     }
159    /**
160     * Set whether to interrogate at startup
161     *
162     * @param value either yes or no
163     */
164    public void setInterrogateOnStart(String value) {
165        // default (most common state) is on, so just check for No
166        mInterrogateAtStart = !(value.equals("No") || value.equals(Bundle.getMessage("ButtonNo")));
167        log.debug("Interrogate at StartUp: {}", mInterrogateAtStart); // NOI18N
168    }
169
170    /**
171     * Set the third port option. Only to be used after construction, but before
172     * the openPort call.
173     */
174    @Override
175    public void configureOption3(String value) {
176        super.configureOption3(value);
177        log.debug("configureOption3: {}", value);
178        setTurnoutHandling(value);
179    }
180
181    private final static Logger log = LoggerFactory.getLogger(LnNetworkPortController.class);
182
183}