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}