001package jmri.jmrix.lenz; 002 003import org.slf4j.Logger; 004import org.slf4j.LoggerFactory; 005 006/** 007 * Defines the standard/common routines used in multiple classes related to the 008 * a Lenz Command Station, on an XpressNet network. 009 * 010 * @author Bob Jacobsen Copyright (C) 2001 Portions by Paul Bender Copyright (C) 2003 011 */ 012public class LenzCommandStation implements jmri.CommandStation { 013 014 /* The First group of routines is for obtaining the Software and 015 hardware version of the Command station */ 016 017 /** 018 * We need to add a few data members for saving the version information we 019 * get from the layout. 020 */ 021 private int cmdStationType = -1; 022 private float cmdStationSoftwareVersion = -1; 023 private int cmdStationSoftwareVersionBCD = -1; 024 025 /** 026 * Return the CS Type. 027 * @return CS type. 028 */ 029 public int getCommandStationType() { 030 return cmdStationType; 031 } 032 033 /** 034 * Set the CS Type. 035 * @param t CS type. 036 */ 037 public void setCommandStationType(int t) { 038 cmdStationType = t; 039 } 040 041 /** 042 * Set the CS Type based on an XpressNet Message. 043 * @param l XNetReply containing the CS type. 044 */ 045 public void setCommandStationType(XNetReply l) { 046 if (l.getElement(0) == XNetConstants.CS_SERVICE_MODE_RESPONSE) { 047 // This is the Command Station Software Version Response 048 if (l.getElement(1) == XNetConstants.CS_SOFTWARE_VERSION) { 049 cmdStationType = l.getElement(3); 050 } 051 } 052 } 053 054 /** 055 * Get the CS Software Version. 056 * @return software version. 057 */ 058 public float getCommandStationSoftwareVersion() { 059 return cmdStationSoftwareVersion; 060 } 061 062 /** 063 * Get the CS Software Version in BCD (for use in comparisons). 064 * @return software version. 065 */ 066 public float getCommandStationSoftwareVersionBCD() { 067 return cmdStationSoftwareVersionBCD; 068 } 069 070 /** 071 * Set the CS Software Version. 072 * @param v software version. 073 */ 074 public void setCommandStationSoftwareVersion(float v) { 075 cmdStationSoftwareVersion = v; 076 } 077 078 /** 079 * Set the CS Software Version based on an XpressNet Message. 080 * @param l reply containing CS version. 081 */ 082 public void setCommandStationSoftwareVersion(XNetReply l) { 083 if (l.getElement(0) == XNetConstants.CS_SERVICE_MODE_RESPONSE) { 084 // This is the Command Station Software Version Response 085 if (l.getElement(1) == XNetConstants.CS_SOFTWARE_VERSION) { 086 try { 087 cmdStationSoftwareVersion = (l.getElementBCD(2).floatValue()) / 10; 088 } catch (java.lang.NumberFormatException nfe) { 089 // the number was not in BCD format as expected. 090 // the upper nibble is the major version and the lower 091 // nibble is the minor version. 092 cmdStationSoftwareVersion = ((l.getElement(2) & 0xf0) >> 4) + (l.getElement(2) & 0x0f) / 100.0f; 093 } 094 cmdStationSoftwareVersionBCD = l.getElement(2); 095 } 096 } 097 } 098 099 /** 100 * Provide the version string returned during the initial check. 101 * @return human readable version string. 102 */ 103 public String getVersionString() { 104 return Bundle.getMessage("CSVersionString", getCommandStationType(),getCommandStationSoftwareVersionBCD()); 105 } 106 107 /** 108 * XpressNet command station does provide Ops Mode. 109 * 110 * @return true if CS type 1 or 2, else false. 111 */ 112 public boolean isOpsModePossible() { 113 return cmdStationType != 0x01 && cmdStationType != 0x02; 114 } 115 116 // A few utility functions 117 118 /** 119 * Get the Lower byte of a locomotive address from the decimal locomotive 120 * address. 121 * @param address loco address. 122 * @return low address byte including DCC offset. 123 */ 124 public static int getDCCAddressLow(int address) { 125 /* For addresses below 100, we just return the address, otherwise, 126 we need to return the upper byte of the address after we add the 127 offset 0xC000. The first address used for addresses over 99 is 0xC064*/ 128 if (address < 100) { 129 return (address); 130 } else { 131 int temp = address + 0xC000; 132 temp = temp & 0x00FF; 133 return temp; 134 } 135 } 136 137 /** 138 * Get the Upper byte of a locomotive address from the decimal locomotive 139 * address. 140 * @param address loco address. 141 * @return upper byte after DCC offset. 142 */ 143 public static int getDCCAddressHigh(int address) { 144 /* this isn't actually the high byte, For addresses below 100, we 145 just return 0, otherwise, we need to return the upper byte of the 146 address after we add the offset 0xC000 The first address used for 147 addresses over 99 is 0xC064*/ 148 if (address < 100) { 149 return (0x00); 150 } else { 151 int temp = address + 0xC000; 152 temp = temp & 0xFF00; 153 temp = temp / 256; 154 return temp; 155 } 156 } 157 158 /** 159 * We need to calculate the locomotive address when doing the translations 160 * back to text. XpressNet Messages will have these as two elements, which 161 * need to get translated back into a single address by reversing the 162 * formulas used to calculate them in the first place. 163 * 164 * @param AH the high order byte of the address 165 * @param AL the low order byte of the address 166 * @return the address as an integer. 167 */ 168 static public int calcLocoAddress(int AH, int AL) { 169 if (AH == 0x00) { 170 /* if AH is 0, this is a short address */ 171 return (AL); 172 } else { 173 /* This must be a long address */ 174 int address; 175 address = ((AH * 256) & 0xFF00); 176 address += (AL & 0xFF); 177 address -= 0xC000; 178 return (address); 179 } 180 } 181 182 /* To Implement the CommandStation Interface, we have to define the 183 sendPacket function */ 184 185 /** 186 * Send a specific packet to the rails. 187 * 188 * @param packet Byte array representing the packet, including the 189 * error-correction byte. Must not be null. 190 * @param repeats Number of times to repeat the transmission. 191 */ 192 @Override 193 public boolean sendPacket(byte[] packet, int repeats) { 194 195 if (_tc == null) { 196 log.error("Send Packet Called without setting traffic controller"); 197 return false; 198 } 199 200 XNetMessage msg = XNetMessage.getNMRAXNetMsg(packet); 201 for (int i = 0; i < repeats; i++) { 202 _tc.sendXNetMessage(msg, null); 203 } 204 return true; 205 } 206 207 /* 208 * For the command station interface, we need to set the traffic 209 * controller. 210 */ 211 public void setTrafficController(XNetTrafficController tc) { 212 _tc = tc; 213 } 214 215 private XNetTrafficController _tc = null; 216 217 public void setSystemConnectionMemo(XNetSystemConnectionMemo memo) { 218 adaptermemo = memo; 219 } 220 221 XNetSystemConnectionMemo adaptermemo; 222 223 @Override 224 public String getUserName() { 225 if (adaptermemo == null) { 226 return Bundle.getMessage("MenuXpressNet"); 227 } 228 return adaptermemo.getUserName(); 229 } 230 231 @Override 232 public String getSystemPrefix() { 233 if (adaptermemo == null) { 234 return "X"; 235 } 236 return adaptermemo.getSystemPrefix(); 237 } 238 239 /* 240 * Register for logging. 241 */ 242 private static final Logger log = LoggerFactory.getLogger(LenzCommandStation.class); 243 244}