001package jmri.jmrix.xpa; 002 003import java.util.Arrays; 004import org.slf4j.Logger; 005import org.slf4j.LoggerFactory; 006 007/** 008 * Encodes a message to an XpressNet command station via an XPA and a modem. 009 * 010 * @author Paul Bender Copyright (C) 2004 011 */ 012public class XpaMessage implements jmri.jmrix.Message { 013 014 public final static int MAX_SIZE = 64; 015 016 private int _nDataChars = 0; 017 private byte[] _dataChars = null; 018 019 // create a new one 020 public XpaMessage(int i) { 021 if (i < 1) { 022 log.error("invalid length in call to ctor"); 023 } 024 _nDataChars = i; 025 _dataChars = new byte[i]; 026 } 027 028 // create a new one, given a string containing the message. 029 public XpaMessage(String s) { 030 if (s.length() < 1) { 031 log.error("zero length string in call to ctor"); 032 } 033 _nDataChars = s.length(); 034 _dataChars = s.getBytes(); 035 } 036 037 // create a new one with default MAX_SIZE 038 public XpaMessage() { 039 this(MAX_SIZE); 040 } 041 042 // copy one 043 public XpaMessage(XpaMessage m) { 044 if (m == null) { 045 log.error("copy ctor of null message"); 046 return; 047 } 048 _nDataChars = m._nDataChars; 049 _dataChars = new byte[_nDataChars]; 050 System.arraycopy(m._dataChars, 0, _dataChars, 0, _nDataChars); 051 } 052 053 // compare two XpaMessages. 054 @Override 055 public boolean equals(Object m) { 056 if (m != null && m instanceof XpaMessage 057 && ((XpaMessage) m).getNumDataElements() == this.getNumDataElements()) { 058 return Arrays.equals(((XpaMessage) m)._dataChars, _dataChars); 059 } 060 return false; 061 } 062 063 @Override 064 public int hashCode() { 065 int hash = 5; 066 hash = 79 * hash + this._nDataChars; 067 hash = 79 * hash + Arrays.hashCode(this._dataChars); 068 return hash; 069 } 070 071 // accessors to the bulk data 072 @Override 073 public int getNumDataElements() { 074 return _nDataChars; 075 } 076 077 @Override 078 public int getElement(int n) { 079 return _dataChars[n]; 080 } 081 082 @Override 083 public void setElement(int n, int v) { 084 _dataChars[n] = (byte) (v & 0x7F); 085 } 086 087 // display format 088 @Override 089 public String toString() { 090 StringBuilder s = new StringBuilder(); 091 for (int i = 0; i < _nDataChars; i++) { 092 s.append((char) _dataChars[i]); 093 } 094 return s.toString(); 095 } 096 097 // static methods to return a formatted message 098 static XpaMessage getDefaultInitMsg() { 099 return new XpaMessage("ATX0E0;"); 100 } 101 102 103 /* Get a message which sends an Estop or Everything off command 104 to the layout. This will toggle the Estop commands. 105 XPA settings can change the behavior of this command. It may 106 only work with a single locomotive, or it may kill the entire 107 layout. 108 */ 109 static XpaMessage getEStopMsg() { 110 return new XpaMessage("ATDT0;"); 111 } 112 113 // Locomotive Messages 114 115 /* 116 Get a message which sends an "Idle" (zero speed) command 117 to a specific locomotive on the layout. 118 */ 119 static XpaMessage getIdleMsg(int address) { 120 return new XpaMessage("ATDT#" + address + "*5;"); 121 } 122 123 /** 124 * Get a message for an "Increase Speed" command 125 * to a specific locomotive on the layout. To make 126 * calculations easy, this uses a single speed step increase. 127 * 128 * @param address throttle loco address for message 129 * @param steps amount of speed steps to change to increase 130 * @return message for the requested change 131 */ 132 static XpaMessage getIncSpeedMsg(int address, int steps) { 133 StringBuilder buf = new StringBuilder("ATDT#" + address + "*"); 134 String message; 135 for (int i = 0; i < steps; i++) { 136 buf.append("3"); 137 } 138 message = buf.toString() + ";"; 139 return new XpaMessage(message); 140 } 141 142 /** 143 * Get a message for a "Decrease Speed" command 144 * to a specific locomotive on the layout. To make 145 * calculations easy, this uses a single speed step decrease. 146 * 147 * @param address throttle loco address for message 148 * @param steps amount of speed steps to change to decrease 149 * @return message for the requested change 150 */ 151 static XpaMessage getDecSpeedMsg(int address, int steps) { 152 StringBuilder buf = new StringBuilder("ATDT#" + address + "*"); 153 String Message; 154 for (int i = 0; i < steps; i++) { 155 buf.append("1"); 156 } 157 Message = buf.toString() + ";"; 158 return new XpaMessage(Message); 159 } 160 161 /* 162 Get a message for a "Direction Forward" command 163 to a specific locomotive on the layout. 164 */ 165 static XpaMessage getDirForwardMsg(int address) { 166 return new XpaMessage("ATDT#" + address + "*52;"); 167 } 168 169 /* 170 Get a message for a "Direction Reverse" command 171 to a specific locomotive on the layout. 172 */ 173 static XpaMessage getDirReverseMsg(int address) { 174 return new XpaMessage("ATDT#" + address + "*58;"); 175 } 176 177 /* 178 Get a message which sends a "Toggle Function" command 179 to a specific locomotive on the layout. 180 */ 181 static XpaMessage getFunctionMsg(int address, int function) { 182 return new XpaMessage("ATDT#" + address + "**" + function + ";"); 183 } 184 185 // Switch Commands 186 187 /* 188 Get a message for a "Switch Position Normal" command 189 to a specific accessory decoder on the layout. 190 */ 191 static XpaMessage getSwitchNormalMsg(int address) { 192 return new XpaMessage("ATDT#" + address + "#3;"); 193 } 194 195 /* 196 Get a message for a "Switch Position Reverse" command 197 to a specific accessory decoder on the layout. 198 */ 199 static XpaMessage getSwitchReverseMsg(int address) { 200 return new XpaMessage("ATDT#" + address + "#1;"); 201 } 202 203 // Xpa Device Settings 204 /* Get a message for setting a Device value */ 205 public static XpaMessage getDeviceSettingMsg(int setting) { 206 return new XpaMessage("ATDT*" + setting + "*"); 207 } 208 209 private final static Logger log = LoggerFactory.getLogger(XpaMessage.class 210 .getName()); 211 212}