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 * with edits/additions by 021 * @author Timothy Jump Copyright (C) 2025 022 */ 023@javax.annotation.concurrent.Immutable 024public enum SpeedStepMode { 025 // NOTE: keep these up to date with xml/schema/locomotive-config.xsd 026 UNKNOWN("unknown", 1, 0.0f, "SpeedStepUnknown"), 027 // NMRA DCC standard speed step modes. 028 NMRA_DCC_128("128", 126, "SpeedStep128"), // Remember there are only 126 non-stop values in 128 speed. 029 NMRA_DCC_28("28", 28, "SpeedStep28"), 030 NMRA_DCC_27("27", 27, "SpeedStep27"), 031 NMRA_DCC_14("14", 14, "SpeedStep14"), 032 // Non-DCC speed step modes. 033 MOTOROLA_28("motorola_28", 28, "SpeedStep28Motorola"), // Motorola 28 speed step mode. 034 TMCC1_32("tmcc1_32", 32, "SpeedStep32TMCC1"), // Lionel TMCC 1, 32 speed step mode. 035 TMCC2_32("tmcc2_32", 32, "SpeedStep32TMCC2"), // Lionel TMCC 2 Legacy, 32 speed step mode. 036 TMCC1_100("tmcc1_100", 100, "SpeedStep100TMCC1"), // Lionel TMCC 1, 100 "relative" speed step mode. 037 TMCC2_200("tmcc2_200", 200, "SpeedStep200TMCC2"), // Lionel TMCC 2 Legacy, 200 speed step mode. 038 TMCC1TR_32("tmcc1tr_32", 32, "SpeedStep32TMCC1TR"), // Lionel TMCC 1 TR, 32 speed step mode. 039 TMCC2TR_32("tmcc2tr_32", 32, "SpeedStep32TMCC2TR"), // Lionel TMCC 2 Legacy TR, 32 speed step mode. 040 TMCC1TR_100("tmcc1tr_100", 100, "SpeedStep100TMCC1TR"), // Lionel TMCC 1 TR, 100 "relative" speed step mode. 041 TMCC2TR_200("tmcc2tr_200", 200, "SpeedStep200TMCC2TR"), // Lionel TMCC 2 Legacy TR, 200 speed step mode. 042 INCREMENTAL("incremental", 1, 1.0f, "SpeedStepIncremental"); 043 044 SpeedStepMode(String name, int numSteps, String description) { 045 this(name, numSteps, 1.0f / numSteps, description); 046 } 047 048 SpeedStepMode(String name, int numSteps, float increment, String description) { 049 this.name = name; 050 this.numSteps = numSteps; 051 this.increment = increment; 052 this.description = Bundle.getMessage(description); 053 } 054 055 public final String name; 056 057 /** 058 * The Number of steps, e.g. 126 for DCC 128 059 */ 060 public final int numSteps; 061 062 /** 063 * The increment between steps, e.g. 1 / 126 for DCC 128 064 */ 065 public final float increment; 066 public final String description; 067 068 /** 069 * Get a locale friendly Step Mode Description. 070 * For just "128" use name() 071 * @return e.g. "128 SS" 072 */ 073 @Override 074 public String toString() { 075 return description; 076 } 077 078 /** 079 * Convert a human-readable string to a DCC speed step mode. 080 * 081 * @param name 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 getByName(String name) { 086 for (SpeedStepMode s : SpeedStepMode.values()) { 087 if (s.name.equals(name)) { 088 return s; 089 } 090 } 091 throw new IllegalArgumentException("Invalid speed step mode: " + name); 092 } 093 094 /** 095 * Convert a localized name string to a DCC speed step mode. 096 * 097 * @param name localized string version of speed step mode; example "128" 098 * @return matching SpeedStepMode 099 * @throws IllegalArgumentException if name does not correspond to a valid speed step mode. 100 */ 101 static public SpeedStepMode getByDescription(String name) { 102 for (SpeedStepMode s : SpeedStepMode.values()) { 103 if (s.description.equals(name)) { 104 return s; 105 } 106 } 107 throw new IllegalArgumentException("Invalid speed step mode: " + name); 108 } 109 110 static public EnumSet<SpeedStepMode> getCompatibleModes( 111 EnumSet<SpeedStepMode> command_station_modes, 112 EnumSet<SpeedStepMode> decoder_modes) { 113 EnumSet<SpeedStepMode> result = command_station_modes.clone(); 114 result.retainAll(decoder_modes); 115 return result; 116 } 117 118 static public SpeedStepMode bestCompatibleMode( 119 EnumSet<SpeedStepMode> command_station_modes, 120 EnumSet<SpeedStepMode> decoder_modes) { 121 EnumSet<SpeedStepMode> result = getCompatibleModes(command_station_modes, decoder_modes); 122 return bestMode(result); 123 } 124 125 static public SpeedStepMode bestMode(EnumSet<SpeedStepMode> modes) { 126 if(modes.contains(NMRA_DCC_128)) { 127 return NMRA_DCC_128; 128 } else if(modes.contains(TMCC1_32)) { 129 return TMCC1_32; 130 } else if(modes.contains(NMRA_DCC_28)) { 131 return NMRA_DCC_28; 132 } else if(modes.contains(MOTOROLA_28)) { 133 return MOTOROLA_28; 134 } else if(modes.contains(NMRA_DCC_27)) { 135 return NMRA_DCC_27; 136 } else if(modes.contains(NMRA_DCC_14)) { 137 return NMRA_DCC_14; 138 } 139 return UNKNOWN; 140 } 141 142 static public EnumSet<SpeedStepMode> getCompatibleModesForProtocol(LocoAddress.Protocol protocol) { 143 switch (protocol) { 144 case DCC: 145 case DCC_LONG: 146 case DCC_SHORT: 147 return EnumSet.of( 148 // NMRA Speed step modes. 149 SpeedStepMode.NMRA_DCC_128, 150 SpeedStepMode.NMRA_DCC_28, 151 SpeedStepMode.NMRA_DCC_27, 152 SpeedStepMode.NMRA_DCC_14, 153 // Incremental speed step mode, used by LENZ XPA 154 // XpressNet Phone Adapter. 155 SpeedStepMode.INCREMENTAL, 156 // TMCC1 mode, since some NMRA decoder models are used 157 // for TMCC1 locomotives. 158 SpeedStepMode.TMCC1_32); 159 case MFX: 160 return EnumSet.of( 161 // NMRA Speed step modes. 162 SpeedStepMode.NMRA_DCC_128, 163 SpeedStepMode.NMRA_DCC_28, 164 SpeedStepMode.NMRA_DCC_27, 165 SpeedStepMode.NMRA_DCC_14, 166 // Incremental speed step mode, used by LENZ XPA 167 // XpressNet Phone Adapter. 168 SpeedStepMode.INCREMENTAL, 169 // MFX decoders also support Motorola speed step mode. 170 SpeedStepMode.MOTOROLA_28); 171 case MOTOROLA: 172 return EnumSet.of(SpeedStepMode.MOTOROLA_28); 173 case SELECTRIX: 174 case M4: 175 case OPENLCB: 176 case LGB: 177 // No compatible speed step modes for these protocols. 178 // NOTE: these protocols only appear to be used in conjunction 179 // with ECOS. 180 break; 181 default: 182 // Unhandled case; no compatible speed step mode. 183 break; 184 } 185 return EnumSet.noneOf(SpeedStepMode.class); 186 } 187}