001package jmri.jmrix.powerline.cp290; 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 /** 043 * This ctor interprets the byte array as a sequence of characters to send. 044 * @deprecated 5.13.5, unused, requires further development. 045 * @param a Array of bytes to send 046 * @param l length of expected reply 047 */ 048 @Deprecated( since="5.13.5", forRemoval=true) 049 public SpecificMessage(byte[] a, int l) { 050 super(StringUtil.hexStringFromBytes(a).replaceAll("\\s", ""), l); 051 } 052 053 /** 054 * Find 1st byte that's not 0xFF, or -1 if none 055 * @return -1 or index of first valid byte 056 */ 057 int startIndex() { 058 int len = getNumDataElements(); 059 for (int i = 0; i < len; i++) { 060 if ((getElement(i) & 0xFF) != 0xFF) { 061 return i; 062 } 063 } 064 return -1; 065 } 066 067 /** 068 * Translate packet to text 069 */ 070 @Override 071 public String toMonitorString() { 072 String test = Constants.toMonitorString(this); 073// // check for valid length 074// String val = "???"; 075// int len = getNumDataElements(); 076// boolean goodSync = true; 077// boolean goodCheckSum = true; 078// int sum = 0; 079// String cmd; 080// String stat; 081// String hCode; 082// String bCode; 083// String dev; 084// switch (len) { 085// case 7: 086// for (int i = 0; i < 6; i++) { 087// if ((getElement(i) & 0xFF) != 0xFF) { 088// goodSync = false; 089// } 090// } 091// val = Constants.statusToText(getElement(6)); 092// break; 093// case 12: 094// for (int i = 0; i < 6; i++) { 095// if ((getElement(i) & 0xFF) != 0xFF) { 096// goodSync = false; 097// } 098// } 099// for (int i = 7; i < 12; i++) { 100// sum = (sum + (getElement(i) &0xFF)) & 0xFF; 101// } 102// stat = Constants.statusToText(getElement(6)); 103// cmd = Constants.commandToText(getElement(7) & 0x0F, -1); 104// hCode = Constants.houseCodeToText((getElement(7) >> 4) & 0x0F); 105// dev = Constants.deviceToText(getElement(8), getElement(9)); 106// bCode = Constants.houseCodeToText((getElement(10) >> 4) & 0x0F); 107// if (sum != (getElement(12) & 0xFF)) { 108// goodCheckSum = false; 109// } 110// val = "Cmd Echo: " + cmd + " stat: " + stat + " House: " + hCode + " Device:" + dev + " base: " + bCode; 111// if (!goodSync) { 112// val = val + " BAD SYNC"; 113// } 114// if (!goodCheckSum) { 115// val = val + " BAD CHECKSUM: " + (getElement(11) & 0xFF) + " vs " + sum; 116// } 117// break; 118// case 22: 119// for (int i = 0; i < 16; i++) { 120// if ((getElement(i) & 0xFF) != 0xFF) { 121// goodSync = false; 122// } 123// } 124// for (int i = 17; i < 21; i++) { 125// sum = (sum + (getElement(i) &0xFF)) & 0xFF; 126// } 127// cmd = Constants.commandToText((getElement(17) & 0x0F), ((getElement(17) & 0xF0) >> 4)); 128// hCode = Constants.houseCodeToText((getElement(18) >> 4) & 0x0F); 129// dev = Constants.deviceToText(getElement(19), getElement(20)); 130// if (sum != (getElement(21) & 0xFF)) { 131// goodCheckSum = false; 132// } 133// val = cmd + " House: " + hCode + " Device:" + dev; 134// if (!goodSync) { 135// val = val + " BAD SYNC"; 136// } 137// if (!goodCheckSum) { 138// val = val + " BAD CHECKSUM: " + (getElement(21) & 0xFF) + " vs " + sum; 139// } 140// break; 141// default: 142// val = "UNK " + toString(); 143// break; 144// } 145 return "Send[" + getNumDataElements() + "]: " + test + "\n"; 146 } 147 148 int responseLength = -1; // -1 is an invalid value, indicating it hasn't been set 149 150 @Override 151 public void setResponseLength(int l) { 152 responseLength = l; 153 } 154 155 @Override 156 public int getResponseLength() { 157 return responseLength; 158 } 159 160 // static methods to recognize a message 161 @Override 162 public boolean isPoll() { 163 return getElement(1) == 48; 164 } 165 166 @Override 167 public boolean isXmt() { 168 return getElement(1) == 17; 169 } 170 171 @Override 172 public int getAddr() { 173 return getElement(0); 174 } 175 176 // static methods to return a formatted message 177 static public SerialMessage getPoll(int addr) { 178 // eventually this will have to include logic for reading 179 // various bytes on the card, but our supported 180 // cards don't require that yet 181 // SerialMessage m = new SerialMessage(1); 182 // m.setResponseLength(2); 183 // m.setElement(0, addr); 184 // m.setTimeout(SHORT_TIMEOUT); // minumum reasonable timeout 185 186 // Powerline implementation does not currently poll 187 return null; 188 } 189 190 static public SpecificMessage getAddress(int housecode, int devicecode) { 191 SpecificMessage m = new SpecificMessage(2); 192 m.setElement(0, 0x04); 193 m.setElement(1, (X10Sequence.encode(housecode) << 4) + X10Sequence.encode(devicecode)); 194 return m; 195 } 196 197 static public SpecificMessage getAddressDim(int housecode, int devicecode, int dimcode) { 198 SpecificMessage m = new SpecificMessage(2); 199 if (dimcode > 0) { 200 m.setElement(0, 0x04 | ((dimcode & 0x1f) << 3)); 201 } else { 202 m.setElement(0, 0x04); 203 } 204 m.setElement(1, (X10Sequence.encode(housecode) << 4) + X10Sequence.encode(devicecode)); 205 return m; 206 } 207 208 static public SpecificMessage getFunctionDim(int housecode, int function, int dimcode) { 209 SpecificMessage m = new SpecificMessage(2); 210 if (dimcode > 0) { 211 m.setElement(0, 0x06 | ((dimcode & 0x1f) << 3)); 212 } else { 213 m.setElement(0, 0x06); 214 } 215 m.setElement(1, (X10Sequence.encode(housecode) << 4) + function); 216 return m; 217 } 218 219 static public SpecificMessage getFunction(int housecode, int function) { 220 SpecificMessage m = new SpecificMessage(2); 221 m.setElement(0, 0x06); 222 m.setElement(1, (X10Sequence.encode(housecode) << 4) + function); 223 return m; 224 } 225} 226 227