001package jmri;
002
003import java.util.EnumSet;
004
005/**
006 * DCC Speed Step Mode.
007 *
008 * <hr>
009 * This file is part of JMRI.
010 * <p>
011 * JMRI is free software; you can redistribute it and/or modify it under the
012 * terms of version 2 of the GNU General Public License as published by the Free
013 * Software Foundation. See the "COPYING" file for a copy of this license.
014 * <p>
015 * JMRI is distributed in the hope that it will be useful, but WITHOUT ANY
016 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
017 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
018 *
019 * @author Austin Hendrix Copyright (C) 2019
020 */
021@javax.annotation.concurrent.Immutable
022public enum SpeedStepMode {
023    // NOTE: keep these up to date with xml/schema/locomotive-config.xsd
024    UNKNOWN("unknown", 1, 0.0f, "SpeedStepUnknown"),
025    // NMRA DCC standard speed step modes.
026    NMRA_DCC_128("128", 126, "SpeedStep128"), // Remember there are only 126 non-stop values in 128 speed.
027    NMRA_DCC_28("28", 28, "SpeedStep28"),
028    NMRA_DCC_27("27", 27, "SpeedStep27"),
029    NMRA_DCC_14("14", 14, "SpeedStep14"),
030    // Non-DCC speed step modes.
031    MOTOROLA_28("motorola_28", 28, "SpeedStep28Motorola"), // Motorola 28 speed step mode.
032    TMCC_32("tmcc_32", 32, "SpeedStep32TMCC"), // Lionel TMCC 32 speed step mode.
033    INCREMENTAL("incremental", 1, 1.0f, "SpeedStepIncremental");
034
035    SpeedStepMode(String name, int numSteps, String description) {
036        this(name, numSteps, 1.0f / numSteps, description);
037    }
038
039    SpeedStepMode(String name, int numSteps, float increment, String description) {
040        this.name = name;
041        this.numSteps = numSteps;
042        this.increment = increment;
043        this.description = Bundle.getMessage(description);
044    }
045
046    public final String name;
047    public final int numSteps;
048    public final float increment;
049    public final String description;
050
051    @Override
052    public String toString() {
053        return description;
054    }
055
056    /**
057     * Convert a human-readable string to a DCC speed step mode.
058     *
059     * @param name string version of speed step mode; example "128"
060     * @return matching SpeedStepMode
061     * @throws IllegalArgumentException if name does not correspond to a valid speed step mode.
062     */
063    static public SpeedStepMode getByName(String name) {
064        for (SpeedStepMode s : SpeedStepMode.values()) {
065            if (s.name.equals(name)) {
066                return s;
067            }
068        }
069        throw new IllegalArgumentException("Invalid speed step mode: " + name);
070    }
071
072    /**
073     * Convert a localized name string to a DCC speed step mode.
074     *
075     * @param name localized string version of speed step mode; example "128"
076     * @return matching SpeedStepMode
077     * @throws IllegalArgumentException if name does not correspond to a valid speed step mode.
078     */
079    static public SpeedStepMode getByDescription(String name) {
080        for (SpeedStepMode s : SpeedStepMode.values()) {
081            if (s.description.equals(name)) {
082                return s;
083            }
084        }
085        throw new IllegalArgumentException("Invalid speed step mode: " + name);
086    }
087
088    static public EnumSet<SpeedStepMode> getCompatibleModes(
089            EnumSet<SpeedStepMode> command_station_modes,
090            EnumSet<SpeedStepMode> decoder_modes) {
091        EnumSet<SpeedStepMode> result = command_station_modes.clone();
092        result.retainAll(decoder_modes);
093        return result;
094    }
095
096    static public SpeedStepMode bestCompatibleMode(
097            EnumSet<SpeedStepMode> command_station_modes,
098            EnumSet<SpeedStepMode> decoder_modes) {
099        EnumSet<SpeedStepMode> result = getCompatibleModes(command_station_modes, decoder_modes);
100        return bestMode(result);
101    }
102
103    static public SpeedStepMode bestMode(EnumSet<SpeedStepMode> modes) {
104        if(modes.contains(NMRA_DCC_128)) {
105            return NMRA_DCC_128;
106        } else if(modes.contains(TMCC_32)) {
107            return TMCC_32;
108        } else if(modes.contains(NMRA_DCC_28)) {
109            return NMRA_DCC_28;
110        } else if(modes.contains(MOTOROLA_28)) {
111            return MOTOROLA_28;
112        } else if(modes.contains(NMRA_DCC_27)) {
113            return NMRA_DCC_27;
114        } else if(modes.contains(NMRA_DCC_14)) {
115            return NMRA_DCC_14;
116        }
117        return UNKNOWN;
118    }
119
120    static public EnumSet<SpeedStepMode> getCompatibleModesForProtocol(LocoAddress.Protocol protocol) {
121        switch (protocol) {
122            case DCC:
123            case DCC_LONG:
124            case DCC_SHORT:
125                return EnumSet.of(
126                        // NMRA Speed step modes.
127                        SpeedStepMode.NMRA_DCC_128,
128                        SpeedStepMode.NMRA_DCC_28,
129                        SpeedStepMode.NMRA_DCC_27,
130                        SpeedStepMode.NMRA_DCC_14,
131                        // Incremental speed step mode, used by LENZ XPA
132                        // XpressNet Phone Adapter.
133                        SpeedStepMode.INCREMENTAL,
134                        // TMCC mode, since some NMRA decoder models are used
135                        // for TMCC locomotives.
136                        SpeedStepMode.TMCC_32);
137            case MFX:
138                return EnumSet.of(
139                        // NMRA Speed step modes.
140                        SpeedStepMode.NMRA_DCC_128,
141                        SpeedStepMode.NMRA_DCC_28,
142                        SpeedStepMode.NMRA_DCC_27,
143                        SpeedStepMode.NMRA_DCC_14,
144                        // Incremental speed step mode, used by LENZ XPA
145                        // XpressNet Phone Adapter.
146                        SpeedStepMode.INCREMENTAL,
147                        // MFX decoders also support Motorola speed step mode.
148                        SpeedStepMode.MOTOROLA_28);
149            case MOTOROLA:
150                return EnumSet.of(SpeedStepMode.MOTOROLA_28);
151            case SELECTRIX:
152            case M4:
153            case OPENLCB:
154            case LGB:
155                // No compatible speed step modes for these protocols.
156                // NOTE: these protocols only appear to be used in conjunction
157                // with ECOS.
158                break;
159            default:
160                // Unhandled case; no compatible speed step mode.
161                break;
162        }
163        return EnumSet.noneOf(SpeedStepMode.class);
164    }
165}