001package jmri.jmrix.loconet.alm.almi; 002 003import jmri.jmrix.loconet.LnConstants; 004import jmri.jmrix.loconet.LocoNetMessage; 005import jmri.jmrix.loconet.alm.Alm; 006 007//import org.slf4j.Logger; 008//import org.slf4j.LoggerFactory; 009 010/** 011 * ALM Interpretation for Routes 012 * 013 * @author Bob Milhaupt Copyright (C) 2022 014 */ 015public class Almir { 016 private Almir () { 017 throw new IllegalStateException("Utility class"); // NOI18N 018 } 019 020 static String interpretAlmRoutes(LocoNetMessage l) { 021 if ((l.getElement(2) != 1) && (l.getElement(2) != 2)) { 022 return EMPTY; 023 } 024 if (l.getNumDataElements() != 0x10) { 025 return EMPTY; 026 } 027 if (l.equals(DESEL)) { 028 return Bundle.getMessage("MSG_LN_ALM_DEVICE_DESEL"); 029 } 030 031 String ret; 032 ret = cardq(l); 033 if (ret.length() > 1) { 034 return ret; 035 } 036 String key = EMPTY; 037 if ((l.getOpCode() == LnConstants.OPC_ALM_READ) && (l.getElement(3) == 0x02)) { 038 if (l.getElement(2) == 1) { 039 key = "LN_MSG_ALM_ROUTE_CMD_STN_REPORT"; // NOI18N 040 } else if (l.getElement(2) != 2) { 041 return EMPTY; 042 } else { 043 key = "LN_MSG_ALM_ROUTE_DEV_REPORT"; // NOI18N 044 } 045 } else if ((l.getOpCode() == LnConstants.OPC_IMM_PACKET_2) && (l.getElement(3) == 3)) { 046 if (l.getElement(2) == 1) { 047 key = "LN_MSG_ALM_ROUTE_CMD_STN_WRITE"; // NOI18N 048 } else if (l.getElement(2) != 2) { 049 return EMPTY; 050 } else { 051 key = "LN_MSG_ALM_ROUTE_DEV_WRITE"; // NOI18N 052 } 053 } 054 if (key.length() > 1) { 055 return Bundle.getMessage(key, 056 1 + (((l.getElement(4) + l.getElement(5)*128)/2) & 0x7f), 057 1 + ((l.getElement(4) & 0x1)<< 2), 058 4 + ((l.getElement(4) & 0x1)<< 2), 059 1 + (((l.getElement(4) + l.getElement(5)*128)/4) & 0x3F), 060 1 + ((l.getElement(4) & 0x3) << 2), 061 4 + ((l.getElement(4) & 0x3) << 2), 062 getTurnoutNum(l, 0), getTurnoutStat(l, 0), 063 getTurnoutNum(l, 1), getTurnoutStat(l, 1), 064 getTurnoutNum(l, 2), getTurnoutStat(l, 2), 065 getTurnoutNum(l, 3), getTurnoutStat(l, 3)); 066 } 067 068 ret = checkarcq(l); 069 if (ret.length() > 1) { 070 return ret; 071 } 072 073 ret = checkCsrc1(l); 074 if (ret.length()>1) { 075 return ret; 076 } 077 078 ret = checkCsrc2(l); 079 if (ret.length()>1) { 080 return ret; 081 } 082 083 ret = dealWithAlmStyle2(l); 084 if (ret.length() > 1) { 085 return ret; 086 } 087 088 return EMPTY; 089 } 090 091 private static String checkarcq(LocoNetMessage l) { 092 if ((l.equals(almRouteCapabilitiesQuery)) || (l.equals(almRouteCapabilitiesQuery2))) { 093 return Bundle.getMessage("LN_MSG_ALM_RTS_CAP_Q"); 094 } 095 return EMPTY; 096 } 097 098 private static String cardq(LocoNetMessage l) { 099 if (l.equals(AlmRoutesDataQuery, ardqm)) { 100 return Bundle.getMessage("LN_MSG_CMD_STN_ROUTE_QUERY", 101 getRouteNum(l), 102 getTurnoutGroup(l), 103 (getTurnoutGroup(l) + 3), 104 getAltRouteNum(l), 105 getAltTurnoutGroup(l), 106 (getAltTurnoutGroup(l) + 3)); 107 } 108 return EMPTY; 109 } 110 111 private static int getTurnoutGroup(LocoNetMessage l) { 112 return 1 + ((l.getElement(4) & 0x1)<< 2); 113 } 114 115 private static int getAltTurnoutGroup(LocoNetMessage l) { 116 return 1 + ((l.getElement(4) & 0x3) << 2); 117 } 118 119 private static int getRouteNum(LocoNetMessage l) { 120 return 1 + (((l.getElement(4) + l.getElement(5)*128)/2) & 0x7f); 121 } 122 123 private static int getAltRouteNum(LocoNetMessage l) { 124 return 1 + (((l.getElement(4) + l.getElement(5)*128)/4) & 0x3F); 125 } 126 127 private static String checkCsrc1 (LocoNetMessage l) { 128 if (l.equals(cmdStnRoutesCap)) { 129 return Bundle.getMessage("LN_MSG_ALM_RTS_CAP_R"); 130 } 131 return EMPTY; 132 } 133 134 private static String checkCsrc2 (LocoNetMessage l) { 135 if (l.equals(cmdStnRoutesCap2)) { 136 return Bundle.getMessage("LN_MSG_ALM_RTS_CAP_R2"); 137 } 138 return EMPTY; 139 } 140 141 private static String getTurnoutNum(LocoNetMessage l, int num) { 142 if ((l.getElement(7+(num*2)) == 0x7f) && (l.getElement(8+(num*2)) == 0x7f)) { 143 return Bundle.getMessage("LN_ROUTE_UNUSED_ENTRY_HELPER"); 144 } 145 if ((num < 0) || (num > 3)) { 146 throw new java.lang.IllegalArgumentException(); 147 } 148 int val = 1 + l.getElement(7+(num*2)) + ((l.getElement(8+(num*2)) & 15)<<7); 149 return Integer.toString(val); 150 } 151 152 private static String getTurnoutStat(LocoNetMessage l, int num) { 153 if ((l.getElement(7+(num*2)) == 0x7f) && (l.getElement(8+(num*2)) == 0x7f)) { 154 return ""; 155 } 156 if ((num <0) || (num > 3)) { 157 throw new java.lang.IllegalArgumentException(); 158 } 159 boolean isClosed; 160 isClosed = (l.getElement(8 + (num*2)) & 0x20) == 0x20; 161 return isClosed ? Bundle.getMessage("LN_SW_CLOSED") 162 :Bundle.getMessage("LN_SW_THROWN"); 163 } 164 165 private static String dealWithAlmStyle2(LocoNetMessage l) { 166 int sn = getSN(l); 167 String ser = Integer.toHexString(sn); 168 int bs = getBS(l); // starting address 169 int be; // ending address 170 String enable; 171 boolean enb = getEnb(l); 172 enable = (enb ? Bundle.getMessage("LN_MSG_HELPER_DISABLED") 173 : Bundle.getMessage("LN_MSG_HELPER_ENABLED")); 174 DevMode mod = getMode(l); 175 String mode; 176 String dev; 177 int rts; // number of routes 178 int ents; // number of entries in routes 179 switch (l.getElement(9)) { 180 case LnConstants.RE_IPL_DIGITRAX_HOST_DS74: 181 dev = "DS74"; //NOI18N 182 rts = 8; 183 ents = 8; 184 be = ((mod == DevMode.DS74_LIGHT)?(bs + 7):(bs + 3)); 185 break; 186 case LnConstants.RE_IPL_DIGITRAX_HOST_DS78V: 187 dev = "DS78V"; //NOI18N 188 rts = 16; 189 ents = 8; 190 be = ((mod == DevMode.DS78V_3_POS)?(bs + 15):(bs + 7)); 191 break; 192 case LnConstants.RE_IPL_DIGITRAX_HOST_SE74: 193 dev = "SE74"; //NOI18N 194 rts = 64; 195 ents = 16; 196 be = bs + 35; 197 break; 198 case LnConstants.RE_IPL_DIGITRAX_HOST_PM74: 199 dev = "PM74"; //NOI18N 200 rts = 0; 201 ents = 0; 202 be = bs + 7; 203 break; 204 205 case LnConstants.RE_IPL_DIGITRAX_HOST_BDL716: 206 dev = "BDL716"; //NOI18N 207 rts = 0; 208 ents = 0; 209 be = bs + 15; 210 break; 211 212 default: 213 dev = Bundle.getMessage("LN_MSG_ALM_HELPER_DEVICE_UNKNOWN"); 214 be = bs; 215 rts = 0; 216 ents = 0; 217 } 218 219 int rn = 1 + (l.getElement(4) / 2) + ((l.getElement(5) & 3)<<6); 220 int re = ((l.getElement(4)& 1) == 1)?5:1; 221 if (Alm.isDs7xRQ(l)) { 222 // This code (and associated key/value pair) will require update if 223 // any device is introduced which supports ALM-based routes with anything 224 // other than 16 entries. 225 return Bundle.getMessage("LN_MSG_ALM_SEL_ROUTE_QUERY", rn, re, re+3); 226 } 227 228 if (Alm.isDs74CapsRpt(l) || Alm.isDs78vCapsRpt(l) || 229 Alm.isSe74CapsRpt(l) || Alm.isPm74CapsRpt(l) || 230 Alm.isBdl716CapsRpt(l)) { 231 if (Alm.isDs74CapsRpt(l) || Alm.isDs78vCapsRpt(l) ) { 232 switch ((l.getElement(10) & 0x1e) >>1) { 233 case 0: 234 mode = "LN_MSG_ALM_HELPER_DEV_MODE_PS"; // NOI18N 235 be = bs + 3; 236 break; 237 case 1: 238 mode = "LN_MSG_ALM_HELPER_DEV_MODE_SM"; // NOI18N 239 be = bs + 3; 240 break; 241 case 2: 242 mode = "LN_MSG_ALM_HELPER_DEV_MODE_S2"; // NOI18N 243 be = bs + 7; 244 break; 245 case 5: 246 mode = "LN_MSG_ALM_HELPER_DEV_MODE_LT"; // NOI18N 247 be = bs + 7; 248 break; 249 case 6: 250 mode = "LN_MSG_ALM_HELPER_DEV_MODE_S3"; // NOI18N 251 be = bs + 15; 252 break; 253 default: 254 mode = "LN_MSG_ALM_HELPER_DEV_MODE_UNDEF"; // NOI18N 255 be = bs; 256 break; 257 } 258 } else if (Alm.isSe74CapsRpt(l)) { 259 if (((l.getElement(10) & 0x3e) >>1) == 0x10) { 260 mode = "LN_MSG_ALM_HELPER_DEV_MODE_ASPECT"; 261 be = bs + 3; 262 } else if (((l.getElement(10) & 0x3E) >>1) == 0x00) { 263 mode = "LN_MSG_ALM_HELPER_DEV_MODE_SIG"; // NOI18N 264 // addressing has already been set above 265 } else { 266 mode = "LN_MSG_ALM_HELPER_DEV_MODE_UNDEF"; 267 // assume addressing has already been set above 268 } // NOI18N 269 } else if (Alm.isPm74CapsRpt(l)) { // element 10 observed at 0 270 mode = "LN_MSG_ALM_HELPER_DEV_MODE_UNDEF"; // NOI18N 271 // addressing has already been set above 272 } else if (Alm.isBdl716CapsRpt(l)) { 273 mode = "LN_MSG_ALM_HELPER_DEV_MODE_NOT_APPLICABLE"; // NOI18N 274 275 // addressing has already been set above 276 } else { 277 be = bs; // only show one address 278 mode = "LN_MSG_ALM_HELPER_DEV_MODE_UNDEF"; // NOI18N 279 } 280 281 mode = Bundle.getMessage(mode); 282 283 if ((Alm.isPm74CapsRpt(l)) || (Alm.isBdl716CapsRpt(l))) { 284 return Bundle.getMessage("LN_MSG_DEVICE_NO_ROUTES_CAPABILITIES_REPLY", 285 dev, ser, bs ); 286 } 287 288 return Bundle.getMessage("LN_MSG_DEVICE_ROUTES_CAPABILITIES_REPLY", 289 dev, ser, mode, enable, bs, be, rts, ents ); 290 } 291 292 LocoNetMessage seldev = new LocoNetMessage(new int[] { 293 LnConstants.OPC_IMM_PACKET_2, 0x10, 0x02, 0x0e, 0,0,0,0,0,0,0,0,0,0,0,0 294 }); 295 int sdm[] = {255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0}; 296 if (l.equals(seldev, sdm)) { 297 return Bundle.getMessage("LN_MSG_DEVICE_ROUTES_SELECT_REQUEST", 298 dev, ser, bs, be); 299 } 300 seldev.setElement(0, LnConstants.OPC_ALM_READ); 301 sdm[4] = 0; sdm[5] = 0; sdm[6] = 0; sdm[7] = 0; sdm[8] = 0; 302 if (l.equals(seldev, sdm)) { 303 return Bundle.getMessage("LN_MSG_DEV_ROUTES_SELECT_REPLY", dev, ser, Integer.toString(bs), Integer.toString(be)); 304 } 305 306 if (Alm.isDevBAW(l)) { 307 // change starting turnout address 308 return Bundle.getMessage("LN_MSG_ALM_DEVICE_CHG_SA", dev, ser, Integer.toString(bs)); 309 } 310 311 return EMPTY; 312 } 313 314 private static int getSN(LocoNetMessage l) { 315 return l.getElement(11) + (l.getElement(12)<<7); 316 } 317 318 private static int getBS(LocoNetMessage l) { 319 return l.getElement(13) + (l.getElement(14)<<7) + 1; 320 } 321 322 private static boolean getEnb(LocoNetMessage l) { 323 return (l.getElement(10)& 0x40) == 0x40; 324 } 325 private static DevMode getMode(LocoNetMessage l) { 326 if (l.getElement(9) == LnConstants.RE_IPL_DIGITRAX_HOST_DS74) { 327 switch (l.getElement(10) & 0x1E) { 328 case 0: 329 return DevMode.DS74_SOLE; 330 case 2: 331 return DevMode.DS74_STALL; 332 case 0xA: 333 return DevMode.DS74_LIGHT; 334 default: 335 break; 336 } 337 } else if (l.getElement(9) == LnConstants.RE_IPL_DIGITRAX_HOST_DS78V) { 338 switch (l.getElement(10) & 0xF) { 339 case 4: 340 return DevMode.DS78V_2_POS; 341 case 0xC: 342 return DevMode.DS78V_3_POS; 343 default: 344 break; 345 } 346 } 347 return DevMode.UNKN; 348 } 349 350 private static final String EMPTY = ""; 351 352 private static final LocoNetMessage DESEL = new LocoNetMessage(new int[] { 353 LnConstants.OPC_IMM_PACKET_2, 0x10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3}); 354 355 private static final LocoNetMessage almRouteCapabilitiesQuery = new LocoNetMessage(new int[] { 356 LnConstants.OPC_IMM_PACKET_2, 0x10, 1, 0, 0, 0, 0, 0, 357 0, 0, 0, 0, 0, 0, 0, 0}); 358 359 private static final LocoNetMessage almRouteCapabilitiesQuery2 = new LocoNetMessage(new int[] { 360 LnConstants.OPC_IMM_PACKET_2, 0x10, 1, 0, 0, 0, 15, 0, 361 0, 0, 0, 0, 0, 0, 0, 0}); 362 363 private static final LocoNetMessage cmdStnRoutesCap = new LocoNetMessage(new int[] { 364 LnConstants.OPC_ALM_READ, 0x10, 1, 0, 0x40, 0, 3, 2, 8, 365 0x7F, 0, 0, 0, 0, 0, 0x64}); 366 367 private static final LocoNetMessage cmdStnRoutesCap2 = new LocoNetMessage(new int[] { 368 LnConstants.OPC_ALM_READ, 0x10, 1, 0, 0, 2, 3, 2, 0x10, 369 0x7F, 0, 0, 0, 0, 0, 0x64}); 370 371 private static final LocoNetMessage AlmRoutesDataQuery = new LocoNetMessage(new int[] { 372 LnConstants.OPC_IMM_PACKET_2, 0x10, 1, 2, 0, 0, 0, 0, 373 0, 0, 0, 0, 0, 0, 0, 0}); 374 375 private static final int[] ardqm = new int[] {255, 255, 255, 255, 0, 0, 0, 0, 376 0, 0, 0, 0, 0, 0, 0, 0}; 377 378 private enum DevMode { 379 DS74_SOLE, 380 DS74_STALL, 381 DS74_LIGHT, 382 DS78V_2_POS, 383 DS78V_3_POS, 384 UNKN 385 } 386// private static final Logger log = LoggerFactory.getLogger(Almir.class); 387 388}