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