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    /**
052     * Get a locale friendly Step Mode Description.
053     * For just "128" use name()
054     * @return e.g. "128 SS"
055     */
056    @Override
057    public String toString() {
058        return description;
059    }
060
061    /**
062     * Convert a human-readable string to a DCC speed step mode.
063     *
064     * @param name string version of speed step mode; example "128"
065     * @return matching SpeedStepMode
066     * @throws IllegalArgumentException if name does not correspond to a valid speed step mode.
067     */
068    static public SpeedStepMode getByName(String name) {
069        for (SpeedStepMode s : SpeedStepMode.values()) {
070            if (s.name.equals(name)) {
071                return s;
072            }
073        }
074        throw new IllegalArgumentException("Invalid speed step mode: " + name);
075    }
076
077    /**
078     * Convert a localized name string to a DCC speed step mode.
079     *
080     * @param name localized string version of speed step mode; example "128"
081     * @return matching SpeedStepMode
082     * @throws IllegalArgumentException if name does not correspond to a valid speed step mode.
083     */
084    static public SpeedStepMode getByDescription(String name) {
085        for (SpeedStepMode s : SpeedStepMode.values()) {
086            if (s.description.equals(name)) {
087                return s;
088            }
089        }
090        throw new IllegalArgumentException("Invalid speed step mode: " + name);
091    }
092
093    static public EnumSet<SpeedStepMode> getCompatibleModes(
094            EnumSet<SpeedStepMode> command_station_modes,
095            EnumSet<SpeedStepMode> decoder_modes) {
096        EnumSet<SpeedStepMode> result = command_station_modes.clone();
097        result.retainAll(decoder_modes);
098        return result;
099    }
100
101    static public SpeedStepMode bestCompatibleMode(
102            EnumSet<SpeedStepMode> command_station_modes,
103            EnumSet<SpeedStepMode> decoder_modes) {
104        EnumSet<SpeedStepMode> result = getCompatibleModes(command_station_modes, decoder_modes);
105        return bestMode(result);
106    }
107
108    static public SpeedStepMode bestMode(EnumSet<SpeedStepMode> modes) {
109        if(modes.contains(NMRA_DCC_128)) {
110            return NMRA_DCC_128;
111        } else if(modes.contains(TMCC_32)) {
112            return TMCC_32;
113        } else if(modes.contains(NMRA_DCC_28)) {
114            return NMRA_DCC_28;
115        } else if(modes.contains(MOTOROLA_28)) {
116            return MOTOROLA_28;
117        } else if(modes.contains(NMRA_DCC_27)) {
118            return NMRA_DCC_27;
119        } else if(modes.contains(NMRA_DCC_14)) {
120            return NMRA_DCC_14;
121        }
122        return UNKNOWN;
123    }
124
125    static public EnumSet<SpeedStepMode> getCompatibleModesForProtocol(LocoAddress.Protocol protocol) {
126        switch (protocol) {
127            case DCC:
128            case DCC_LONG:
129            case DCC_SHORT:
130                return EnumSet.of(
131                        // NMRA Speed step modes.
132                        SpeedStepMode.NMRA_DCC_128,
133                        SpeedStepMode.NMRA_DCC_28,
134                        SpeedStepMode.NMRA_DCC_27,
135                        SpeedStepMode.NMRA_DCC_14,
136                        // Incremental speed step mode, used by LENZ XPA
137                        // XpressNet Phone Adapter.
138                        SpeedStepMode.INCREMENTAL,
139                        // TMCC mode, since some NMRA decoder models are used
140                        // for TMCC locomotives.
141                        SpeedStepMode.TMCC_32);
142            case MFX:
143                return EnumSet.of(
144                        // NMRA Speed step modes.
145                        SpeedStepMode.NMRA_DCC_128,
146                        SpeedStepMode.NMRA_DCC_28,
147                        SpeedStepMode.NMRA_DCC_27,
148                        SpeedStepMode.NMRA_DCC_14,
149                        // Incremental speed step mode, used by LENZ XPA
150                        // XpressNet Phone Adapter.
151                        SpeedStepMode.INCREMENTAL,
152                        // MFX decoders also support Motorola speed step mode.
153                        SpeedStepMode.MOTOROLA_28);
154            case MOTOROLA:
155                return EnumSet.of(SpeedStepMode.MOTOROLA_28);
156            case SELECTRIX:
157            case M4:
158            case OPENLCB:
159            case LGB:
160                // No compatible speed step modes for these protocols.
161                // NOTE: these protocols only appear to be used in conjunction
162                // with ECOS.
163                break;
164            default:
165                // Unhandled case; no compatible speed step mode.
166                break;
167        }
168        return EnumSet.noneOf(SpeedStepMode.class);
169    }
170}