001package jmri.jmrix.roco.z21; 002 003import jmri.SpeedStepMode; 004import jmri.jmrix.lenz.XNetConstants; 005import jmri.jmrix.lenz.XNetMessage; 006 007/** 008 * Represents a single command or response on the XpressNet. 009 * <p> 010 * Content is represented with ints to avoid the problems with sign-extension 011 * that bytes have, and because a Java char is actually a variable number of 012 * bytes in Unicode. 013 * 014 * @author Bob Jacobsen Copyright (C) 2002 015 * @author Paul Bender Copyright (C) 2003-2010 016 */ 017public class Z21XNetMessage extends jmri.jmrix.lenz.XNetMessage { 018 019 /** 020 * Constructor, just pass on to the superclass. 021 * @param len message length. 022 */ 023 public Z21XNetMessage(int len) { 024 super(len); 025 } 026 027 /** 028 * Constructor from a Z21Message. 029 * @param m the Z21Message. 030 */ 031 public Z21XNetMessage(Z21Message m) { 032 super(m.getLength()-4); 033 for(int i = 4; i< m.getLength() ; i++ ){ 034 this.setElement(i-4,m.getElement(i)); 035 } 036 } 037 038 /** 039 * Create a new object, that is a copy of an existing message. 040 * 041 * @param message an existing Z21XpressNet message 042 */ 043 public Z21XNetMessage(Z21XNetMessage message) { 044 super(message); 045 } 046 047 /** 048 * Create an Z21XNetMessage from an Z21XNetReply. 049 * @param message the existing Z21XNetReply. 050 */ 051 public Z21XNetMessage(Z21XNetReply message) { 052 super(message); 053 } 054 055 /** 056 * Create an XNetMessage from a String containing bytes. 057 * @param s byte string. 058 */ 059 public Z21XNetMessage(String s) { 060 super(s); 061 } 062 063 @Override 064 public String toMonitorString() { 065 switch(getElement(0)) { 066 case Z21Constants.LAN_X_SET_TURNOUT: { 067 int address = (getElement(1) << 8) + getElement(2) + 1; 068 int element = getElement(3); 069 boolean queue = (element & 0x20) == 0x20; 070 String active = ((element & 0x08) == 0x08)? "activate":"deactivate"; 071 return Bundle.getMessage("Z21LAN_X_SET_TURNOUT", address, active, element & 0x01, queue); 072 } 073 case Z21Constants.LAN_X_GET_TURNOUT_INFO: { 074 int address = (getElement(1) << 8) + getElement(2) + 1; 075 return Bundle.getMessage("Z21LAN_X_GET_TURNOUT_INFO", address); 076 } 077 default: 078 return super.toMonitorString(); 079 } 080 } 081 082 /** 083 * Create messages of a particular form. 084 * @param cv CV index 085 * @return message to send. 086 */ 087 public static Z21XNetMessage getZ21ReadDirectCVMsg(int cv) { 088 Z21XNetMessage m = new Z21XNetMessage(5); 089 m.setNeededMode(jmri.jmrix.AbstractMRTrafficController.PROGRAMINGMODE); 090 m.setTimeout(XNetProgrammingTimeout); 091 m.setElement(0, Z21Constants.LAN_X_CV_READ_XHEADER); 092 m.setElement(1, Z21Constants.LAN_X_CV_READ_DB0); 093 m.setElement(2, ((0xff00 & (cv - 1)) >> 8)); 094 m.setElement(3, (0xff & (cv - 1))); 095 m.setParity(); // Set the parity bit 096 return m; 097 } 098 099 public static Z21XNetMessage getZ21WriteDirectCVMsg(int cv, int val) { 100 Z21XNetMessage m = new Z21XNetMessage(6); 101 m.setNeededMode(jmri.jmrix.AbstractMRTrafficController.PROGRAMINGMODE); 102 m.setTimeout(XNetProgrammingTimeout); 103 m.setElement(0, Z21Constants.LAN_X_CV_WRITE_XHEADER); 104 m.setElement(1, Z21Constants.LAN_X_CV_WRITE_DB0); 105 m.setElement(2, (0xff00 & (cv - 1)) >> 8); 106 m.setElement(3, (0xff & (cv - 1))); 107 m.setElement(4, val); 108 m.setParity(); // Set the parity bit 109 return m; 110 } 111 112 /** 113 * Given a locomotive address, request its status. 114 * 115 * @param address is the locomotive address 116 * @return message to send. 117 */ 118 public static Z21XNetMessage getZ21LocomotiveInfoRequestMsg(int address) { 119 Z21XNetMessage msg = new Z21XNetMessage(5); 120 msg.setElement(0, XNetConstants.LOCO_STATUS_REQ); 121 msg.setElement(1, Z21Constants.LAN_X_LOCO_INFO_REQUEST_Z21); 122 msg.setElement(2, jmri.jmrix.lenz.LenzCommandStation.getDCCAddressHigh(address)); 123 msg.setElement(3, jmri.jmrix.lenz.LenzCommandStation.getDCCAddressLow(address)); 124 msg.setParity(); 125 return (msg); 126 } 127 128 /** 129 * Given a locomotive address, a function number, and its value, 130 * generate a message to change the state. 131 * 132 * @param address is the locomotive address 133 * @param functionno is the function to change 134 * @param state is boolean representing whether the function is to be on or off 135 * @return message to send. 136 */ 137 public static Z21XNetMessage getZ21LocomotiveFunctionOperationMsg(int address, int functionno, boolean state) { 138 Z21XNetMessage msg = new Z21XNetMessage(6); 139 int functionbyte = functionno; 140 msg.setElement(0, XNetConstants.LOCO_OPER_REQ); 141 msg.setElement(1, Z21Constants.LAN_X_SET_LOCO_FUNCTION); 142 msg.setElement(2, jmri.jmrix.lenz.LenzCommandStation.getDCCAddressHigh(address)); 143 msg.setElement(3, jmri.jmrix.lenz.LenzCommandStation.getDCCAddressLow(address)); 144 if(state) { 145 //This function is on 146 functionbyte = functionbyte & 0x3F; // clear the 2 most significant bits. 147 functionbyte = functionbyte | 0x40; // set the 2 msb to 01. 148 } else { 149 //This function is off. 150 functionbyte = functionbyte & 0x3F; // clear the 2 most significant bits. 151 } 152 msg.setElement(4, functionbyte); 153 msg.setParity(); 154 msg.setBroadcastReply(); 155 return (msg); 156 } 157 158 /** 159 * Generate a Z21 message to change the speed/direction of a locomotive. 160 * 161 * @param address the locomotive address 162 * @param speedMode the speedstep mode see @jmri.DccThrottle 163 * for possible values. 164 * @param speed a normalized speed value (a floating point number between 0 165 * and 1). A negative value indicates emergency stop. 166 * @param isForward true for forward, false for reverse. 167 * @return message to send. 168 */ 169 public static XNetMessage getZ21LanXSetLocoDriveMsg(int address, SpeedStepMode speedMode, float speed, boolean isForward) { 170 XNetMessage msg = XNetMessage.getSpeedAndDirectionMsg(address, 171 speedMode,speed,isForward); 172 msg.setBroadcastReply(); 173 return (msg); 174 } 175 176 177 /** 178 * Given a turnout address, generate a message to request the state. 179 * 180 * @param address the turnout address 181 * @return message to send. 182 */ 183 public static Z21XNetMessage getZ21TurnoutInfoRequestMessage(int address ) { 184 // refer to section 5.1 of the z21 lan protocol manual. 185 Z21XNetMessage msg = new Z21XNetMessage(4); 186 msg.setElement(0,Z21Constants.LAN_X_GET_TURNOUT_INFO); 187 // compared to Lenz devices, the addresses on the Z21 is one below 188 // the numerical value. We will correct it here so higher level 189 // code doesn't see the difference. 190 msg.setElement(1,((address-1) &0xff00)>>8); 191 msg.setElement(2,((address-1) & 0x00ff)); 192 msg.setParity(); 193 return(msg); 194 } 195 196 /** 197 * Given a turnout address and whether or not it is thrown, generate 198 * a message to operate the turnout. 199 * 200 * @param address is the turnout address 201 * @param thrown boolean value representing whether the turnout is thrown. 202 * @param active boolean value representing whether the output is being set 203 * to active. 204 * @param queue boolean value representing whehter or not the message is 205 * added to the queue. 206 * @return message to send. 207 */ 208 public static Z21XNetMessage getZ21SetTurnoutRequestMessage(int address, boolean thrown, boolean active, boolean queue) { 209 // refer to section 5.2 of the z21 lan protocol manual. 210 Z21XNetMessage msg = new Z21XNetMessage(5); 211 msg.setElement(0,Z21Constants.LAN_X_SET_TURNOUT); 212 // compared to Lenz devices, the addresses on the Z21 is one below 213 // the numerical value. We will correct it here so higher level 214 // code doesn't see the difference. 215 msg.setElement(1,((address-1) &0xff00)>>8); 216 msg.setElement(2,((address-1) & 0x00ff)); 217 int element3=0x80; 218 if(active) { 219 element3 |= 0x08; 220 } 221 if(thrown) { 222 element3 |= 0x01; 223 } 224 if(queue) { 225 element3 |= 0x20; 226 } 227 228 msg.setElement(3,element3); 229 msg.setParity(); 230 msg.setBroadcastReply(); 231 return(msg); 232 } 233 234}