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 + 36; 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 if (Alm.isDs74CapsRpt(l) || Alm.isDs78vCapsRpt(l) ) { 231 switch ((l.getElement(10) & 0x1e) >>1) { 232 case 0: 233 mode = "LN_MSG_ALM_HELPER_DEV_MODE_PS"; // NOI18N 234 be = bs + 3; 235 break; 236 case 1: 237 mode = "LN_MSG_ALM_HELPER_DEV_MODE_SM"; // NOI18N 238 be = bs + 3; 239 break; 240 case 2: 241 mode = "LN_MSG_ALM_HELPER_DEV_MODE_S2"; // NOI18N 242 be = bs + 7; 243 break; 244 case 5: 245 mode = "LN_MSG_ALM_HELPER_DEV_MODE_LT"; // NOI18N 246 be = bs + 7; 247 break; 248 case 6: 249 mode = "LN_MSG_ALM_HELPER_DEV_MODE_S3"; // NOI18N 250 be = bs + 15; 251 break; 252 default: 253 mode = "LN_MSG_ALM_HELPER_DEV_MODE_UNDEF"; // NOI18N 254 be = bs; 255 break; 256 } 257 } else if (Alm.isSe74CapsRpt(l)) { // element 10 observed at 0 258 mode = "LN_MSG_ALM_HELPER_DEV_MODE_UNDEF"; // NOI18N 259 // addressing has already been set above 260 } else if (Alm.isPm74CapsRpt(l)) { // element 10 observed at 0 261 mode = "LN_MSG_ALM_HELPER_DEV_MODE_UNDEF"; // NOI18N 262 // addressing has already been set above 263 } else { 264 be = bs; // only show one address 265 mode = "LN_MSG_ALM_HELPER_DEV_MODE_UNDEF"; // NOI18N 266 } 267 268 mode = Bundle.getMessage(mode); 269 270 if (Alm.isPm74CapsRpt(l)) { 271 return Bundle.getMessage("LN_MSG_DEVICE_NO_ROUTES_CAPABILITIES_REPLY", 272 dev, ser, bs ); 273 } 274 275 return Bundle.getMessage("LN_MSG_DEVICE_ROUTES_CAPABILITIES_REPLY", 276 dev, ser, mode, enable, bs, be, rts, ents ); 277 } 278 279 LocoNetMessage seldev = new LocoNetMessage(new int[] { 280 LnConstants.OPC_IMM_PACKET_2, 0x10, 0x02, 0x0e, 0,0,0,0,0,0,0,0,0,0,0,0 281 }); 282 int sdm[] = {255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0}; 283 if (l.equals(seldev, sdm)) { 284 return Bundle.getMessage("LN_MSG_DEVICE_ROUTES_SELECT_REQUEST", 285 dev, ser, bs, be); 286 } 287 seldev.setElement(0, LnConstants.OPC_ALM_READ); 288 sdm[4] = 0; sdm[5] = 0; sdm[6] = 0; sdm[7] = 0; sdm[8] = 0; 289 if (l.equals(seldev, sdm)) { 290 return Bundle.getMessage("LN_MSG_DEV_ROUTES_SELECT_REPLY", dev, ser, Integer.toString(bs), Integer.toString(be)); 291 } 292 293 if (Alm.isDevBAW(l)) { 294 // change starting turnout address 295 return Bundle.getMessage("LN_MSG_ALM_DEVICE_CHG_SA", dev, ser, Integer.toString(bs)); 296 } 297 298 return EMPTY; 299 } 300 301 private static int getSN(LocoNetMessage l) { 302 return l.getElement(11) + (l.getElement(12)<<7); 303 } 304 305 private static int getBS(LocoNetMessage l) { 306 return l.getElement(13) + (l.getElement(14)<<7) + 1; 307 } 308 309 private static boolean getEnb(LocoNetMessage l) { 310 return (l.getElement(10)& 0x40) == 0x40; 311 } 312 private static DevMode getMode(LocoNetMessage l) { 313 if (l.getElement(9) == LnConstants.RE_IPL_DIGITRAX_HOST_DS74) { 314 switch (l.getElement(10) & 0x1E) { 315 case 0: 316 return DevMode.DS74_SOLE; 317 case 2: 318 return DevMode.DS74_STALL; 319 case 0xA: 320 return DevMode.DS74_LIGHT; 321 default: 322 break; 323 } 324 } else if (l.getElement(9) == LnConstants.RE_IPL_DIGITRAX_HOST_DS78V) { 325 switch (l.getElement(10) & 0xF) { 326 case 4: 327 return DevMode.DS78V_2_POS; 328 case 0xC: 329 return DevMode.DS78V_3_POS; 330 default: 331 break; 332 } 333 } 334 return DevMode.UNKN; 335 } 336 337 private static final String EMPTY = ""; 338 339 private static final LocoNetMessage DESEL = new LocoNetMessage(new int[] { 340 LnConstants.OPC_IMM_PACKET_2, 0x10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3}); 341 342 private static final LocoNetMessage almRouteCapabilitiesQuery = new LocoNetMessage(new int[] { 343 LnConstants.OPC_IMM_PACKET_2, 0x10, 1, 0, 0, 0, 0, 0, 344 0, 0, 0, 0, 0, 0, 0, 0}); 345 346 private static final LocoNetMessage almRouteCapabilitiesQuery2 = new LocoNetMessage(new int[] { 347 LnConstants.OPC_IMM_PACKET_2, 0x10, 1, 0, 0, 0, 15, 0, 348 0, 0, 0, 0, 0, 0, 0, 0}); 349 350 private static final LocoNetMessage cmdStnRoutesCap = new LocoNetMessage(new int[] { 351 LnConstants.OPC_ALM_READ, 0x10, 1, 0, 0x40, 0, 3, 2, 8, 352 0x7F, 0, 0, 0, 0, 0, 0x64}); 353 354 private static final LocoNetMessage cmdStnRoutesCap2 = new LocoNetMessage(new int[] { 355 LnConstants.OPC_ALM_READ, 0x10, 1, 0, 0, 2, 3, 2, 0x10, 356 0x7F, 0, 0, 0, 0, 0, 0x64}); 357 358 private static final LocoNetMessage AlmRoutesDataQuery = new LocoNetMessage(new int[] { 359 LnConstants.OPC_IMM_PACKET_2, 0x10, 1, 2, 0, 0, 0, 0, 360 0, 0, 0, 0, 0, 0, 0, 0}); 361 362 private static final int[] ardqm = new int[] {255, 255, 255, 255, 0, 0, 0, 0, 363 0, 0, 0, 0, 0, 0, 0, 0}; 364 365 private enum DevMode { 366 DS74_SOLE, 367 DS74_STALL, 368 DS74_LIGHT, 369 DS78V_2_POS, 370 DS78V_3_POS, 371 UNKN 372 } 373// private final static Logger log = LoggerFactory.getLogger(Almir.class); 374 375}