001package jmri.jmrix.sprog; 002 003import javax.annotation.Nonnull; 004 005import jmri.DccLocoAddress; 006import jmri.LocoAddress; 007import jmri.SpeedStepMode; 008import jmri.jmrix.AbstractThrottle; 009 010/** 011 * An implementation of DccThrottle with code specific to a SPROG Command 012 * Station connection. 013 * <p> 014 * Updated by Andrew Crosland February 2012 to enable 28 step speed packets 015 * 016 * @author Andrew Crosland Copyright (C) 2006, 2012 017 */ 018public class SprogCSThrottle extends AbstractThrottle { 019 020 /** 021 * Constructor. 022 * @param memo system connection. 023 * @param address Loco Address. 024 */ 025 public SprogCSThrottle(@Nonnull SprogSystemConnectionMemo memo, LocoAddress address) { 026 super(memo, SprogConstants.MAX_FUNCTIONS); 027 028 if (address instanceof DccLocoAddress) { 029 this.address = ((DccLocoAddress) address); 030 } 031 else { 032 log.error("{} is not a DccLocoAddress",address); 033 } 034 035 // cache settings. 036 synchronized(this) { 037 this.speedSetting = 0; 038 } 039 // Functions default to false 040 this.isForward = true; 041 this.speedStepMode = SpeedStepMode.NMRA_DCC_128; 042 043 044 //@TODO - this needs a little work. Current implementation looks like it 045 //should support other modes, but doesn't in practice. 046 //@see AbstractThrottleManager.supportedSpeedModes() 047 // Find our command station 048 if ( memo.get(jmri.CommandStation.class) != null) { 049 commandStation = (SprogCommandStation) memo.get(jmri.CommandStation.class); 050 } else { 051 commandStation = (SprogCommandStation) jmri.InstanceManager.getNullableDefault(jmri.CommandStation.class); 052 } 053 054 } 055 056 private final SprogCommandStation commandStation; 057 058 DccLocoAddress address; 059 060 @Override 061 public LocoAddress getLocoAddress() { 062 return address; 063 } 064 065 /** 066 * Send the message to set the state of functions F0, F1, F2, F3, F4 by 067 * adding it to the S queue 068 */ 069 @Override 070 protected void sendFunctionGroup1() { 071 commandStation.function0Through4Packet(address, 072 getFunction(0), getFunctionMomentary(0), 073 getFunction(1), getFunctionMomentary(1), 074 getFunction(2), getFunctionMomentary(2), 075 getFunction(3), getFunctionMomentary(3), 076 getFunction(4), getFunctionMomentary(4)); 077 078 } 079 080 /** 081 * Send the message to set the state of functions F5, F6, F7, F8 by# adding 082 * it to the S queue 083 */ 084 @Override 085 protected void sendFunctionGroup2() { 086 commandStation.function5Through8Packet(address, 087 getFunction(5), getFunctionMomentary(5), 088 getFunction(6), getFunctionMomentary(6), 089 getFunction(7), getFunctionMomentary(7), 090 getFunction(8), getFunctionMomentary(8)); 091 } 092 093 /** 094 * Send the message to set the state of functions F9, F10, F11, F12 by 095 * adding it to the S queue 096 */ 097 @Override 098 protected void sendFunctionGroup3() { 099 commandStation.function9Through12Packet(address, 100 getFunction(9), getFunctionMomentary(9), 101 getFunction(10), getFunctionMomentary(10), 102 getFunction(11), getFunctionMomentary(11), 103 getFunction(12), getFunctionMomentary(12)); 104 } 105 106 /** 107 * Send the message to set the state of functions F13 - F20 108 * adding it to the S queue 109 */ 110 @Override 111 protected void sendFunctionGroup4() { 112 commandStation.function13Through20Packet(address, 113 getFunction(13), getFunctionMomentary(13), 114 getFunction(14), getFunctionMomentary(14), 115 getFunction(15), getFunctionMomentary(15), 116 getFunction(16), getFunctionMomentary(16), 117 getFunction(17), getFunctionMomentary(17), 118 getFunction(18), getFunctionMomentary(18), 119 getFunction(19), getFunctionMomentary(19), 120 getFunction(20), getFunctionMomentary(20)); 121 } 122 123 /** 124 * Send the message to set the state of functions F21 - F28 125 * adding it to the S queue 126 */ 127 @Override 128 protected void sendFunctionGroup5() { 129 commandStation.function21Through28Packet(address, 130 getFunction(21), getFunctionMomentary(21), 131 getFunction(22), getFunctionMomentary(22), 132 getFunction(23), getFunctionMomentary(23), 133 getFunction(24), getFunctionMomentary(24), 134 getFunction(25), getFunctionMomentary(25), 135 getFunction(26), getFunctionMomentary(26), 136 getFunction(27), getFunctionMomentary(27), 137 getFunction(28), getFunctionMomentary(28)); 138 } 139 140 /** 141 * Send the message to set the state of functions F29 - F36 142 * adding it to the S queue 143 */ 144 @Override 145 protected void sendFunctionGroup6() { 146 commandStation.function29Through36Packet(address, 147 getFunctionNoWarn(29), getFunctionMomentaryNoWarn(29), 148 getFunctionNoWarn(30), getFunctionMomentaryNoWarn(30), 149 getFunctionNoWarn(31), getFunctionMomentaryNoWarn(32), 150 getFunctionNoWarn(32), getFunctionMomentaryNoWarn(32), 151 getFunctionNoWarn(33), getFunctionMomentaryNoWarn(33), 152 getFunctionNoWarn(34), getFunctionMomentaryNoWarn(34), 153 getFunctionNoWarn(35), getFunctionMomentaryNoWarn(35), 154 getFunctionNoWarn(36), getFunctionMomentaryNoWarn(36)); 155 } 156 157 /** 158 * Send the message to set the state of functions F37 - F44 159 * adding it to the S queue 160 */ 161 @Override 162 protected void sendFunctionGroup7() { 163 commandStation.function37Through44Packet(address, 164 getFunctionNoWarn(37), getFunctionMomentaryNoWarn(37), 165 getFunctionNoWarn(38), getFunctionMomentaryNoWarn(38), 166 getFunctionNoWarn(39), getFunctionMomentaryNoWarn(39), 167 getFunctionNoWarn(40), getFunctionMomentaryNoWarn(40), 168 getFunctionNoWarn(41), getFunctionMomentaryNoWarn(41), 169 getFunctionNoWarn(42), getFunctionMomentaryNoWarn(42), 170 getFunctionNoWarn(43), getFunctionMomentaryNoWarn(43), 171 getFunctionNoWarn(44), getFunctionMomentaryNoWarn(44)); 172 } 173 174 /** 175 * Send the message to set the state of functions F45 - F52 176 * adding it to the S queue 177 */ 178 @Override 179 protected void sendFunctionGroup8() { 180 commandStation.function45Through52Packet(address, 181 getFunctionNoWarn(45), getFunctionMomentaryNoWarn(45), 182 getFunctionNoWarn(46), getFunctionMomentaryNoWarn(46), 183 getFunctionNoWarn(47), getFunctionMomentaryNoWarn(47), 184 getFunctionNoWarn(48), getFunctionMomentaryNoWarn(48), 185 getFunctionNoWarn(49), getFunctionMomentaryNoWarn(49), 186 getFunctionNoWarn(50), getFunctionMomentaryNoWarn(50), 187 getFunctionNoWarn(51), getFunctionMomentaryNoWarn(51), 188 getFunctionNoWarn(52), getFunctionMomentaryNoWarn(52)); 189 } 190 191 /** 192 * Send the message to set the state of functions F53 - F60 193 * adding it to the S queue 194 */ 195 @Override 196 protected void sendFunctionGroup9() { 197 commandStation.function53Through60Packet(address, 198 getFunctionNoWarn(53), getFunctionMomentaryNoWarn(53), 199 getFunctionNoWarn(54), getFunctionMomentaryNoWarn(54), 200 getFunctionNoWarn(55), getFunctionMomentaryNoWarn(55), 201 getFunctionNoWarn(56), getFunctionMomentaryNoWarn(56), 202 getFunctionNoWarn(57), getFunctionMomentaryNoWarn(57), 203 getFunctionNoWarn(58), getFunctionMomentaryNoWarn(58), 204 getFunctionNoWarn(59), getFunctionMomentaryNoWarn(59), 205 getFunctionNoWarn(60), getFunctionMomentaryNoWarn(60)); 206 } 207 208 /** 209 * Send the message to set the state of functions F61 - F68 210 * adding it to the S queue 211 */ 212 @Override 213 protected void sendFunctionGroup10() { 214 commandStation.function61Through68Packet(address, 215 getFunctionNoWarn(61), getFunctionMomentaryNoWarn(61), 216 getFunctionNoWarn(62), getFunctionMomentaryNoWarn(62), 217 getFunctionNoWarn(63), getFunctionMomentaryNoWarn(63), 218 getFunctionNoWarn(64), getFunctionMomentaryNoWarn(64), 219 getFunctionNoWarn(65), getFunctionMomentaryNoWarn(65), 220 getFunctionNoWarn(66), getFunctionMomentaryNoWarn(66), 221 getFunctionNoWarn(67), getFunctionMomentaryNoWarn(67), 222 getFunctionNoWarn(68), getFunctionMomentaryNoWarn(68)); 223 } 224 225 /** 226 * Set the speed and direction. 227 * <p> 228 * This intentionally skips the emergency stop value of 1 in 128 step mode 229 * and the stop and estop values 1-3 in 28 step mode. 230 * 231 * @param speed Number from 0 to 1; less than zero is emergency stop 232 */ 233 @Override 234 public synchronized void setSpeedSetting(float speed) { 235 SpeedStepMode mode = getSpeedStepMode(); 236 if (mode == SpeedStepMode.NMRA_DCC_28) { 237 // 28 step mode speed commands are 238 // stop, estop, stop, estop, 4, 5, ..., 31 239 float oldSpeed = this.speedSetting; 240 this.speedSetting = speed; 241 int value = Math.round((31 - 3) * speed); // -3 for rescale to avoid estopx2 and stop 242 if (this.speedSetting > 0 && value == 0) { 243 value = 1; // ensure non-zero input results in non-zero output 244 } 245 if (value > 0) { 246 value = value + 3; // skip estopx2 and stop 247 } 248 if (value > 31) { 249 value = 31; // max possible speed 250 } 251 if (value < 0) { 252 value = 1; // emergency stop 253 } 254 commandStation.setSpeed(SpeedStepMode.NMRA_DCC_28, address, value, isForward); 255 firePropertyChange(SPEEDSETTING, oldSpeed, this.speedSetting); 256 } else { 257 // 128 step mode speed commands are 258 // stop, estop, 2, 3, ..., 127 259 float oldSpeed = this.speedSetting; 260 this.speedSetting = speed; 261 int value = Math.round((127 - 1) * speed); // -1 for rescale to avoid estop 262 if (this.speedSetting > 0 && value == 0) { 263 value = 1; // ensure non-zero input results in non-zero output 264 } 265 if (value > 0) { 266 value = value + 1; // skip estop 267 } 268 if (value > 127) { 269 value = 127; // max possible speed 270 } 271 if (value < 0) { 272 value = 1; // emergency stop 273 } 274 commandStation.setSpeed(SpeedStepMode.NMRA_DCC_128, address, value, isForward); 275 firePropertyChange(SPEEDSETTING, oldSpeed, this.speedSetting); 276 } 277 record(speed); 278 } 279 280 @Override 281 public void setIsForward(boolean forward) { 282 boolean old = isForward; 283 isForward = forward; 284 synchronized(this) { 285 setSpeedSetting(speedSetting); // Update the speed setting 286 } 287 firePropertyChange(ISFORWARD, old, isForward); 288 } 289 290 @Override 291 public void throttleDispose() { 292 active = false; 293 commandStation.release(address); 294 finishRecord(); 295 } 296 297 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(SprogCSThrottle.class); 298 299}