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() == 0xE6) && (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() == 0xEE) && (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 default: 206 dev = Bundle.getMessage("LN_MSG_ALM_HELPER_DEVICE_UNKNOWN"); 207 be = bs; 208 rts = 0; 209 ents = 0; 210 } 211 212 int rn = 1 + (l.getElement(4) / 2) + ((l.getElement(5) & 3)<<6); 213 int re = ((l.getElement(4)& 1) == 1)?5:1; 214 if (Alm.isDs7xRQ(l)) { 215 // This code (and associated key/value pair) will require update if 216 // any device is introduced which supports ALM-based routes with anything 217 // other than 16 entries. 218 return Bundle.getMessage("LN_MSG_ALM_SEL_ROUTE_QUERY", rn, re, re+3); 219 } 220 221 if (Alm.isDs74CapsRpt(l) || Alm.isDs78vCapsRpt(l) || 222 Alm.isSe74CapsRpt(l) || Alm.isPm74CapsRpt(l) ) { 223 if (Alm.isDs74CapsRpt(l) || Alm.isDs78vCapsRpt(l) ) { 224 switch ((l.getElement(10) & 0x1e) >>1) { 225 case 0: 226 mode = "LN_MSG_ALM_HELPER_DEV_MODE_PS"; // NOI18N 227 be = bs + 3; 228 break; 229 case 1: 230 mode = "LN_MSG_ALM_HELPER_DEV_MODE_SM"; // NOI18N 231 be = bs + 3; 232 break; 233 case 2: 234 mode = "LN_MSG_ALM_HELPER_DEV_MODE_S2"; // NOI18N 235 be = bs + 7; 236 break; 237 case 5: 238 mode = "LN_MSG_ALM_HELPER_DEV_MODE_LT"; // NOI18N 239 be = bs + 7; 240 break; 241 case 6: 242 mode = "LN_MSG_ALM_HELPER_DEV_MODE_S3"; // NOI18N 243 be = bs + 15; 244 break; 245 default: 246 mode = "LN_MSG_ALM_HELPER_DEV_MODE_UNDEF"; // NOI18N 247 be = bs; 248 break; 249 } 250 } else if (Alm.isSe74CapsRpt(l)) { // element 10 observed at 0 251 mode = "LN_MSG_ALM_HELPER_DEV_MODE_UNDEF"; // NOI18N 252 // addressing has already been set above 253 } else if (Alm.isPm74CapsRpt(l)) { // element 10 observed at 0 254 mode = "LN_MSG_ALM_HELPER_DEV_MODE_UNDEF"; // NOI18N 255 // addressing has already been set above 256 } else { 257 be = bs; // only show one address 258 mode = "LN_MSG_ALM_HELPER_DEV_MODE_UNDEF"; // NOI18N 259 } 260 261 mode = Bundle.getMessage(mode); 262 263 if (Alm.isPm74CapsRpt(l)) { 264 return Bundle.getMessage("LN_MSG_DEVICE_NO_ROUTES_CAPABILITIES_REPLY", 265 dev, ser, bs ); 266 } 267 268 return Bundle.getMessage("LN_MSG_DEVICE_ROUTES_CAPABILITIES_REPLY", 269 dev, ser, mode, enable, bs, be, rts, ents ); 270 } 271 272 LocoNetMessage seldev = new LocoNetMessage(new int[] { 273 0xee, 0x10, 0x02, 0x0e, 0,0,0,0,0,0,0,0,0,0,0,0 274 }); 275 int sdm[] = {255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0}; 276 if (l.equals(seldev, sdm)) { 277 return Bundle.getMessage("LN_MSG_DEVICE_ROUTES_SELECT_REQUEST", 278 dev, ser, bs, be); 279 } 280 seldev.setElement(0, LnConstants.OPC_ALM_READ); 281 sdm[4] = 0; sdm[5] = 0; sdm[6] = 0; sdm[7] = 0; sdm[8] = 0; 282 if (l.equals(seldev, sdm)) { 283 return Bundle.getMessage("LN_MSG_DEV_ROUTES_SELECT_REPLY", dev, ser, Integer.toString(bs), Integer.toString(be)); 284 } 285 286 if (Alm.isDevBAW(l)) { 287 // change starting turnout address 288 return Bundle.getMessage("LN_MSG_ALM_DEVICE_CHG_SA", dev, ser, Integer.toString(bs)); 289 } 290 291 return EMPTY; 292 } 293 294 private static int getSN(LocoNetMessage l) { 295 return l.getElement(11) + (l.getElement(12)<<7); 296 } 297 298 private static int getBS(LocoNetMessage l) { 299 return l.getElement(13) + (l.getElement(14)<<7) + 1; 300 } 301 302 private static boolean getEnb(LocoNetMessage l) { 303 return (l.getElement(10)& 0x40) == 0x40; 304 } 305 private static DevMode getMode(LocoNetMessage l) { 306 if (l.getElement(9) == 0x74) { 307 switch (l.getElement(10) & 0x1E) { 308 case 0: 309 return DevMode.DS74_SOLE; 310 case 2: 311 return DevMode.DS74_STALL; 312 case 0xA: 313 return DevMode.DS74_LIGHT; 314 default: 315 break; 316 } 317 } else if (l.getElement(9) == 0x7c) { 318 switch (l.getElement(10) & 0xF) { 319 case 4: 320 return DevMode.DS78V_2_POS; 321 case 0xC: 322 return DevMode.DS78V_3_POS; 323 default: 324 break; 325 } 326 } 327 return DevMode.UNKN; 328 } 329 330 private static final String EMPTY = ""; 331 332 private static final LocoNetMessage DESEL = new LocoNetMessage(new int[] { 333 0xEE, 0x10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3}); 334 335 private static final LocoNetMessage almRouteCapabilitiesQuery = new LocoNetMessage(new int[] { 336 0xEE, 0x10, 1, 0, 0, 0, 0, 0, 337 0, 0, 0, 0, 0, 0, 0, 0}); 338 339 private static final LocoNetMessage almRouteCapabilitiesQuery2 = new LocoNetMessage(new int[] { 340 0xEE, 0x10, 1, 0, 0, 0, 15, 0, 341 0, 0, 0, 0, 0, 0, 0, 0}); 342 343 private static final LocoNetMessage cmdStnRoutesCap = new LocoNetMessage(new int[] { 344 0xE6, 0x10, 1, 0, 0x40, 0, 3, 2, 8, 345 0x7F, 0, 0, 0, 0, 0, 0x64}); 346 347 private static final LocoNetMessage cmdStnRoutesCap2 = new LocoNetMessage(new int[] { 348 0xE6, 0x10, 1, 0, 0, 2, 3, 2, 0x10, 349 0x7F, 0, 0, 0, 0, 0, 0x64}); 350 351 private static final LocoNetMessage AlmRoutesDataQuery = new LocoNetMessage(new int[] { 352 0xEE, 0x10, 1, 2, 0, 0, 0, 0, 353 0, 0, 0, 0, 0, 0, 0, 0}); 354 355 private static final int[] ardqm = new int[] {255, 255, 255, 255, 0, 0, 0, 0, 356 0, 0, 0, 0, 0, 0, 0, 0}; 357 358 private enum DevMode { 359 DS74_SOLE, 360 DS74_STALL, 361 DS74_LIGHT, 362 DS78V_2_POS, 363 DS78V_3_POS, 364 UNKN 365 } 366// private final static Logger log = LoggerFactory.getLogger(Almir.class); 367 368}