001package jmri.jmrix.powerline.cm11; 002 003import jmri.jmrix.powerline.SerialMessage; 004import jmri.jmrix.powerline.X10Sequence; 005import jmri.util.StringUtil; 006 007/** 008 * Contains the data payload of a serial packet. 009 * <p> 010 * The transmission protocol can come in one of several forms: 011 * <ul> 012 * <li>If the interlocked parameter is false (default), the packet is just sent. 013 * If the response length is not zero, a reply of that length is expected. 014 * <li>If the interlocked parameter is true, the transmission will require a CRC 015 * interlock, which will be automatically added. (Design note: this is done to 016 * make sure that the messages remain atomic) 017 * </ul> 018 * 019 * @author Bob Jacobsen Copyright (C) 2001,2003, 2006, 2007, 2008 020 */ 021public class SpecificMessage extends SerialMessage { 022 // is this logically an abstract class? 023 024 public SpecificMessage(int l) { 025 super(l); 026 setResponseLength(0); // only polls require a response 027 setBinary(true); 028 setTimeout(5000); 029 } 030 031 /** 032 * This ctor interprets the String as the exact sequence to send, 033 * byte-for-byte. 034 * 035 * @param m message 036 * @param l response length in bytes 037 */ 038 public SpecificMessage(String m, int l) { 039 super(m, l); 040 } 041 042 boolean interlocked = false; 043 044 @Override 045 public void setInterlocked(boolean v) { 046 interlocked = v; 047 } 048 049 @Override 050 public boolean getInterlocked() { 051 return interlocked; 052 } 053 054 @SuppressWarnings("fallthrough") 055 @Override 056 public String toMonitorString() { 057 // check for valid length 058 int len = getNumDataElements(); 059 StringBuilder text = new StringBuilder(); 060 switch (getElement(0) & 0xFF) { 061 case Constants.MACRO_LOAD: 062 text.append("Macro load reply"); 063 break; 064 case Constants.MACRO_INITIATED: 065 text.append("Macro Poll"); 066 break; 067 case Constants.TIME_REQ_CP11: 068 text.append("Power Fail Poll"); 069 break; 070 case Constants.TIMER_DOWNLOAD: 071 text.append("Set CM11 time"); 072 break; 073 case Constants.EXT_CMD_HEADER: // extended command 074 text.append("Extended Cmd"); 075 if (len == 5) { 076 text.append(" house "); 077 text.append(X10Sequence.houseValueToText(X10Sequence.decode((getElement(1) >> 4) & 0x0F))); 078 text.append(" address device "); 079 text.append(X10Sequence.decode(getElement(2) & 0x0F)); 080 int d = getElement(3) & 0xFF; 081 switch (getElement(4) & 0xFF) { 082 case X10Sequence.EXTCMD_DIM: 083 text.append(" Direct Dim: "); 084 if ((d & 0x3F) <= 0x3E) { 085 text.append(((d & 0x3F) / 0.63) + "%"); 086 } else if (d == 0x3F) { 087 text.append("Full On"); 088 } else { 089 text.append(" data: 0x"); 090 text.append(StringUtil.twoHexFromInt(d)); 091 } 092// switch ((d >> 6) & 0x03) { 093// case 0: 094// text.append(" 3.7 Sec"); 095// break; 096// case 1: 097// text.append(" 30 Sec"); 098// break; 099// case 2: 100// text.append(" 1 Min"); 101// break; 102// case 3: 103// text.append(" 5 Min"); 104// break; 105// } 106 break; 107 default: 108 text.append(" cmd: 0x"); 109 text.append(StringUtil.twoHexFromInt(getElement(4) & 0xFF)); 110 text.append(" data: 0x"); 111 text.append(StringUtil.twoHexFromInt(getElement(3) & 0xFF)); 112 } 113 } else { 114 text.append(" wrong length: " + len); 115 } 116 break; 117 case Constants.POLL_ACK: 118 if (len == 1) { 119 text.append("Poll Ack"); 120 break; 121 } // else fall through 122 case Constants.CHECKSUM_OK: 123 if (len == 1) { 124 text.append("OK for transmission"); 125 break; 126 } // else fall through 127 default: { 128 if (len == 2) { 129 text.append(Constants.formatHeaderByte(getElement(0 & 0xFF))); 130 if ((getElement(0) & 0x02) == 0x02) { 131 text.append(" "); 132 text.append(X10Sequence.formatCommandByte(getElement(1) & 0xFF)); 133 } else { 134 text.append(" "); 135 text.append(X10Sequence.formatAddressByte(getElement(1) & 0xFF)); 136 } 137 } else { 138 text.append("Reply was not expected, len: " + len); 139 text.append(" value: " + Constants.formatHeaderByte(getElement(0 & 0xFF))); 140 } 141 } 142 } 143 return text + "\n"; 144 } 145 146 /** 147 * This ctor interprets the byte array as a sequence of characters to send. 148 * 149 * @param a Array of bytes to send 150 * @param l lenght of expected reply 151 */ 152 @Deprecated( since="5.13.5", forRemoval=true) // deprecated super 153 public SpecificMessage(byte[] a, int l) { 154 super(a, l); 155 } 156 157 int responseLength = -1; // -1 is an invalid value, indicating it hasn't been set 158 159 @Override 160 public void setResponseLength(int l) { 161 responseLength = l; 162 } 163 164 @Override 165 public int getResponseLength() { 166 return responseLength; 167 } 168 169 // static methods to recognize a message 170 @Override 171 public boolean isPoll() { 172 return getElement(1) == 48; 173 } 174 175 @Override 176 public boolean isXmt() { 177 return getElement(1) == 17; 178 } 179 180 @Override 181 public int getAddr() { 182 return getElement(0); 183 } 184 185 // static methods to return a formatted message 186 static public SerialMessage getPoll(int addr) { 187 // eventually this will have to include logic for reading 188 // various bytes on the card, but our supported 189 // cards don't require that yet 190 // SerialMessage m = new SerialMessage(1); 191 // m.setResponseLength(2); 192 // m.setElement(0, addr); 193 // m.setTimeout(SHORT_TIMEOUT); // minumum reasonable timeout 194 195 // Powerline implementation does not currently poll 196 return null; 197 } 198 199 static public SpecificMessage setCM11Time(int housecode) { 200 SpecificMessage msg = new SpecificMessage(7); 201 msg.setElement(0, 0x9B); 202 msg.setElement(5, 0x01); 203 msg.setElement(6, housecode << 4); 204 return msg; 205 } 206 207 static public SpecificMessage getAddress(int housecode, int devicecode) { 208 SpecificMessage m = new SpecificMessage(2); 209 m.setInterlocked(true); 210 m.setElement(0, 0x04); 211 m.setElement(1, (X10Sequence.encode(housecode) << 4) + X10Sequence.encode(devicecode)); 212 return m; 213 } 214 215 static public SpecificMessage getAddressDim(int housecode, int devicecode, int dimcode) { 216 SpecificMessage m = new SpecificMessage(2); 217 m.setInterlocked(true); 218 if (dimcode > 0) { 219 m.setElement(0, 0x04 | ((dimcode & 0x1f) << 3)); 220 } else { 221 m.setElement(0, 0x04); 222 } 223 m.setElement(1, (X10Sequence.encode(housecode) << 4) + X10Sequence.encode(devicecode)); 224 return m; 225 } 226 227 static public SpecificMessage getFunctionDim(int housecode, int function, int dimcode) { 228 SpecificMessage m = new SpecificMessage(2); 229 m.setInterlocked(true); 230 if (dimcode > 0) { 231 m.setElement(0, 0x06 | ((dimcode & 0x1f) << 3)); 232 } else { 233 m.setElement(0, 0x06); 234 } 235 m.setElement(1, (X10Sequence.encode(housecode) << 4) + function); 236 return m; 237 } 238 239 static public SpecificMessage getFunction(int housecode, int function) { 240 SpecificMessage m = new SpecificMessage(2); 241 m.setInterlocked(true); 242 m.setElement(0, 0x06); 243 m.setElement(1, (X10Sequence.encode(housecode) << 4) + function); 244 return m; 245 } 246 247 static public SpecificMessage getExtCmd(int housecode, int devicecode, int function, int dimcode) { 248 SpecificMessage m = new SpecificMessage(5); 249 m.setInterlocked(true); 250 m.setElement(0, 0x07); 251 m.setElement(1, (X10Sequence.encode(housecode) << 4) + X10Sequence.FUNCTION_EXTENDED_CODE); 252 m.setElement(2, X10Sequence.encode(devicecode)); 253 m.setElement(3, dimcode); 254 m.setElement(4, function); 255 return m; 256 } 257} 258 259