001package jmri.jmrix.ieee802154; 002 003/** 004 * Contains the data payload of a serial reply packet. Note that it's _only_ the 005 * payload. 006 * 007 * @author Bob Jacobsen Copyright (C) 2002, 2006, 2007, 2008 Converted to 008 * multiple connection 009 * @author kcameron Copyright (C) 2011 Modified for IEEE 802.15.4 connection 010 * @author Paul Bender Copyright (C) 2013 011 */ 012public class IEEE802154Reply extends jmri.jmrix.AbstractMRReply { 013 014 // create a new one 015 public IEEE802154Reply() { 016 super(); 017 setBinary(true); 018 } 019 020 public IEEE802154Reply(String s) { 021 super(s); 022 setBinary(true); 023 } 024 025 public IEEE802154Reply(IEEE802154Reply l) { 026 super(l); 027 setBinary(true); 028 } 029 030 /* 031 * @return the destination address associated with the reply (need for 032 * matching to a node ). The type and position of the sender 033 * address is indicated in the control byte. 034 */ 035 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "PZLA_PREFER_ZERO_LENGTH_ARRAYS", 036 justification = "Would take significant rework") 037 public byte[] getDestinationAddress() { 038 int destinationMode = getDestinationAddressMode(); 039 //int sourceMode = getSourceAddressMode(); // not used 040 int offset = 4; // position of first byte of destination address if 041 // it is present. 042 int length = 0; // minimum destination address length. 043 // both address may be either 0, 2, or 8 bytes, depending on 044 // the addressing mode used. destination mode determins the 045 // source address offset. 046 switch (destinationMode) { 047 case 0x00: 048 return null; // no destination address. 049 case 0x01: 050 return null; // this value is reserved. 051 case 0x10: 052 length += 2; // 16 bit address 053 break; 054 case 0x11: 055 length += 8; // 64 bit address 056 break; 057 default: 058 return null; // this should never actually happen. 059 } 060 061 if (!isIntraPanFrame()) { 062 // this is an interpan frame. pan addresses 063 // are included if both address fields 064 // are present. 065 if (destinationMode != 0) { 066 offset += 2; 067 } 068 } 069 070 byte address[] = new byte[length]; 071 for (int i = 0; i < length; i++) { 072 address[i] = (byte) (0xff & getElement(i + offset)); 073 } 074 return address; 075 } 076 077 /* 078 * @return the sender address associated with the reply (need for 079 * matching to a node ). The type and position of the sender 080 * address is indicated in the control byte. 081 */ 082 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "PZLA_PREFER_ZERO_LENGTH_ARRAYS", 083 justification = "Would take significant rework") 084 public byte[] getSourceAddr() { 085 int destinationMode = getDestinationAddressMode(); 086 int sourceMode = getSourceAddressMode(); 087 int offset = 4; // position of first byte of source address if 088 // no destination address is present. 089 int length = 0; // minimum source address length. 090 // both address may be either 0, 2, or 8 bytes, depending on 091 // the addressing mode used. destination mode determins the 092 // source address offset. 093 switch (destinationMode) { 094 case 0x00: 095 break; // no destination address. 096 case 0x01: 097 break; // this value is reserved. 098 case 0x10: 099 offset += 2; // 16 bit address 100 break; 101 case 0x11: 102 offset += 8; // 64 bit address 103 break; 104 default: 105 return null; // this should never actually happen. 106 } 107 switch (sourceMode) { 108 case 0x00: 109 return null; // no source address. 110 case 0x01: 111 return null; // this value is reserved. 112 case 0x10: 113 length += 2; // 16 bit address 114 break; 115 case 0x11: 116 length += 8; // 64 bit address 117 break; 118 default: 119 return null; // this should never actually happen. 120 } 121 122 if (!isIntraPanFrame()) { 123 // this is an interpan frame. pan addresses 124 // are included if both address fields 125 // are present. 126 if (destinationMode != 0 && sourceMode != 0) { 127 offset += 4; 128 } 129 } 130 131 byte address[] = new byte[length]; 132 for (int i = 0; i < length; i++) { 133 address[i] = (byte) (0xff & getElement(i + offset)); 134 } 135 return address; 136 } 137 138 /* 139 * @return the payload associated with the reply. The position 140 * of the data is determined from the control byte. 141 */ 142 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "PZLA_PREFER_ZERO_LENGTH_ARRAYS", 143 justification = "Would take significant rework") 144 public byte[] getPayload() { 145 int destinationMode = getDestinationAddressMode(); 146 int sourceMode = getSourceAddressMode(); 147 int offset = 4; // position of first byte of source address if 148 // no destination address is present. 149 // both address may be either 0, 2, or 8 bytes, depending on 150 // the addressing mode used. destination mode determins the 151 // source address offset. 152 switch (destinationMode) { 153 case 0x00: 154 break; // no destination address. 155 case 0x01: 156 break; // this value is reserved. 157 case 0x10: 158 offset += 2; // 16 bit address 159 break; 160 case 0x11: 161 offset += 8; // 64 bit address 162 break; 163 default: 164 return null; // this should never actually happen. 165 } 166 switch (sourceMode) { 167 case 0x00: 168 break; // no source address. 169 case 0x01: 170 break; // this value is reserved. 171 case 0x10: 172 offset += 2; // 16 bit address 173 break; 174 case 0x11: 175 offset += 8; // 64 bit address 176 break; 177 default: 178 return null; // this should never actually happen. 179 } 180 181 if (!isIntraPanFrame()) { 182 // this is an interpan frame. pan addresses 183 // are included if both address fields 184 // are present. 185 if (destinationMode != 0 && sourceMode != 0) { 186 offset += 4; 187 } 188 } 189 190 int length = getLength() - (offset + 2); // the payload starts after 191 // the address and ends 192 // at the 2 byte checksum. 193 194 byte address[] = new byte[length]; 195 for (int i = 0; i < length; i++) { 196 address[i] = (byte) (0xff & getElement(i + offset)); 197 } 198 return address; 199 } 200 201 /* 202 * @return length of reply. length is the first byte after 203 * the start byte. We are not storing the start byte. 204 * <p> 205 * NOTE: this does not work correctly for packets received from 206 * an XBee Node. These devices do not provide raw packet 207 * information. 208 */ 209 public int getLength() { 210 return getElement(0); 211 } 212 213 /* 214 * @return control information from the reply. This is the 3rd and 4th 215 * byte after the start byte. 216 * Format of the frame control field (FCF) 217 * according to IEEE 802.15.4 MAC standard 218 * 219 * bits 0-2 frame type 220 * 3 security enabled 221 * 4 frame pending 222 * 5 acknowledge request 223 * 6 intra pan 224 * 7-9 reserved 225 * 10-11 destination addressing mode 226 * 12-13 reserved 227 * 14-15 source addressing mode 228 * 229 */ 230 public int getFrameControl() { 231 return (getElement(1) << 8) + getElement(2); 232 } 233 234 // return the destination address mode (bits 10 and 11) of the frame 235 // control field. 236 public int getDestinationAddressMode() { 237 return ((getFrameControl() & 0x0C00) >> 10); 238 } 239 240 // return the source address mode (bits 14 and 15) of the frame 241 // control field. 242 public int getSourceAddressMode() { 243 return ((getFrameControl() & 0xC000) >> 14); 244 } 245 246 // return whether or not the intrapan frame bit (bit 6) is set in 247 // the frame control field. 248 public boolean isIntraPanFrame() { 249 return ((getFrameControl() & 0x0020) != 0); 250 } 251 252 /* 253 * @return the sequence number of the reply. This is the 4th byte 254 * after the start byte. 255 */ 256 public byte getSequenceByte() { 257 return (byte) getElement(3); 258 } 259 260 @Override 261 protected int skipPrefix(int index) { 262 // doesn't have to do anything 263 return index; 264 } 265 266 /** 267 * check whether the message has a valid parity IEEE 802.15.4 messages have 268 * a two byte parity. 269 * @return true if parity valid 270 */ 271 public boolean checkParity() { 272 int len = getNumDataElements(); 273 int chksum = 0x0000; /* the seed */ 274 275 int loop; 276 277 for (loop = 0; loop < len - 1; loop = loop + 2) { // calculate contents for data part 278 chksum ^= (getElement(loop) << 8); 279 chksum ^= getElement(loop + 1); 280 } 281 return ((chksum & 0xFFFF) == ((getElement(len - 2) << 8) + getElement(len - 1))); 282 } 283 284}