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