001package jmri.jmrix.srcp; 002 003import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 004import jmri.DccLocoAddress; 005import jmri.LocoAddress; 006import jmri.SpeedStepMode; 007import jmri.Throttle; 008import jmri.jmrix.AbstractThrottle; 009 010/** 011 * An implementation of DccThrottle with code specific to an SRCP connection. 012 * <p> 013 * Addresses of 99 and below are considered short addresses, and over 100 are 014 * considered long addresses. This is not the NCE system standard, but is used 015 * as an expedient here. 016 * 017 * @author Bob Jacobsen Copyright (C) 2001,2008 018 */ 019public class SRCPThrottle extends AbstractThrottle { 020 021 /** 022 * Constructor. 023 * 024 * @param memo the memo containing the connection 025 * @param address the address to use 026 */ 027 public SRCPThrottle(SRCPBusConnectionMemo memo, DccLocoAddress address) { 028 // default to 128 speed steps with 28 functions and NMRA protocl. 029 this(memo, address, "N", SpeedStepMode.NMRA_DCC_128, 28); 030 } 031 032 public SRCPThrottle(SRCPBusConnectionMemo memo, DccLocoAddress address, 033 String protocol, SpeedStepMode mode, int functions) { 034 super(memo); 035 if (!protocol.equals("N")) { 036 throw new IllegalArgumentException("Protocol " + protocol + " not supported"); 037 } 038 setSpeedStepMode(mode); 039 040 bus = memo.getBus(); 041 042 // cache settings. It would be better to read the 043 // actual state, but I don't know how to do this 044 synchronized(this) { 045 this.speedSetting = 0; 046 } 047 // Functions default to false 048 this.address = address; 049 this.isForward = true; 050 051 // send allocation message 052 String msg = "INIT " + bus + " GL " 053 + (address.getNumber()) 054 + " " + protocol + " " 055 + (address.isLongAddress() ? " 2 " : " 1 ") 056 + maxsteps + " " 057 + functions + "\n"; 058 memo.getTrafficController() 059 .sendSRCPMessage(new SRCPMessage(msg), null); 060 } 061 062 /** 063 * Send the message to set the state of functions F0, F1, F2, F3, F4. 064 */ 065 @Override 066 protected void sendFunctionGroup1() { 067 sendUpdate(); 068 } 069 070 /** 071 * Send the message to set the state of functions F5, F6, F7, F8. 072 */ 073 @Override 074 protected void sendFunctionGroup2() { 075 sendUpdate(); 076 } 077 078 /** 079 * Send the message to set the state of functions F9, F10, F11, F12. 080 */ 081 @Override 082 protected void sendFunctionGroup3() { 083 sendUpdate(); 084 } 085 086 /** 087 * Send the message to set the state of functions F13, F14, F15, F16, F17, 088 * F18, F19, and F20. 089 */ 090 @Override 091 protected void sendFunctionGroup4() { 092 sendUpdate(); 093 } 094 095 /** 096 * Send the message to set the state of functions F21, F22, F23, F24, F25, 097 * F26, F27 and F28. 098 */ 099 @Override 100 protected void sendFunctionGroup5() { 101 sendUpdate(); 102 } 103 104 /** 105 * Set the speed and direction. 106 * <p> 107 * This intentionally skips the emergency stop value of 1. 108 * 109 * @param speed Number from 0 to 1; less than zero is emergency stop 110 */ 111 @SuppressFBWarnings(value = "FE_FLOATING_POINT_EQUALITY") // OK to compare floating point, notify on any change 112 @Override 113 public synchronized void setSpeedSetting(float speed) { 114 float oldSpeed = this.speedSetting; 115 this.speedSetting = speed; 116 sendUpdate(); 117 firePropertyChange(SPEEDSETTING, oldSpeed, this.speedSetting); 118 record(speed); 119 } 120 121 @Override 122 public void setIsForward(boolean forward) { 123 boolean old = isForward; 124 isForward = forward; 125 sendUpdate(); 126 firePropertyChange(Throttle.ISFORWARD, old, isForward); 127 } 128 129 private DccLocoAddress address; 130 private int bus; 131 private int maxsteps; 132 133 /** 134 * Send the complete status 135 */ 136 void sendUpdate() { 137 String msg = "SET " + bus + " GL "; 138 139 int outSpeed; 140 141 synchronized(this) { 142 outSpeed = Math.round(speedSetting * maxsteps); 143 if (speedSetting > 0 && outSpeed == 0) { 144 outSpeed = 1; // ensure non-zero input results in non-zero output 145 } 146 } 147 148 // address 149 msg += (address.getNumber()); 150 151 // direction and speed 152 synchronized(this) { 153 if (speedSetting >= 0) { 154 msg += (isForward ? " 1" : " 0"); 155 } 156 else { 157 msg += " 2"; // handle emergency stop 158 } 159 } 160 msg += " " + outSpeed; 161 msg += " "; 162 msg += maxsteps; 163 164 // now add the functions 165 msg += getFunction(0) ? " 1" : " 0"; 166 msg += getFunction(1) ? " 1" : " 0"; 167 msg += getFunction(2) ? " 1" : " 0"; 168 msg += getFunction(3) ? " 1" : " 0"; 169 msg += getFunction(4) ? " 1" : " 0"; 170 msg += getFunction(5) ? " 1" : " 0"; 171 msg += getFunction(6) ? " 1" : " 0"; 172 msg += getFunction(7) ? " 1" : " 0"; 173 msg += getFunction(8) ? " 1" : " 0"; 174 msg += getFunction(9) ? " 1" : " 0"; 175 msg += getFunction(10) ? " 1" : " 0"; 176 msg += getFunction(11) ? " 1" : " 0"; 177 msg += getFunction(12) ? " 1" : " 0"; 178 msg += getFunction(13) ? " 1" : " 0"; 179 msg += getFunction(14) ? " 1" : " 0"; 180 msg += getFunction(15) ? " 1" : " 0"; 181 msg += getFunction(16) ? " 1" : " 0"; 182 msg += getFunction(17) ? " 1" : " 0"; 183 msg += getFunction(18) ? " 1" : " 0"; 184 msg += getFunction(19) ? " 1" : " 0"; 185 msg += getFunction(20) ? " 1" : " 0"; 186 msg += getFunction(21) ? " 1" : " 0"; 187 msg += getFunction(22) ? " 1" : " 0"; 188 msg += getFunction(23) ? " 1" : " 0"; 189 msg += getFunction(24) ? " 1" : " 0"; 190 msg += getFunction(25) ? " 1" : " 0"; 191 msg += getFunction(26) ? " 1" : " 0"; 192 msg += getFunction(27) ? " 1" : " 0"; 193 msg += getFunction(28) ? " 1" : " 0"; 194 195 // send the result 196 SRCPMessage m = new SRCPMessage(msg + "\n"); 197 198 ((SRCPBusConnectionMemo) adapterMemo).getTrafficController().sendSRCPMessage(m, null); 199 } 200 201 @Override 202 public void setSpeedStepMode(SpeedStepMode Mode) { 203 super.setSpeedStepMode(Mode); 204 switch (Mode) { 205 case NMRA_DCC_14: 206 case NMRA_DCC_27: 207 case NMRA_DCC_28: 208 case NMRA_DCC_128: 209 maxsteps = Mode.numSteps; 210 break; 211 default: 212 maxsteps = 126; 213 break; 214 } 215 } 216 217 @Override 218 public LocoAddress getLocoAddress() { 219 return address; 220 } 221 222 @Override 223 public void throttleDispose() { 224 finishRecord(); 225 } 226 227}