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