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