001package jmri.jmrix.lenz; 002 003import jmri.Manager.NameValidity; 004import org.slf4j.Logger; 005import org.slf4j.LoggerFactory; 006 007import javax.annotation.Nonnull; 008 009/** 010 * Utility Class supporting parsing and testing of addresses for Lenz XpressNet 011 * <p> 012 * Two address format are supported: 013 * <ul> 014 * <li> 015 * Xtxxxx where: t is the type code, 'T' for turnouts, 'S' for sensors, 016 * and 'L' for lights xxxx is a int for the hardware address (1-1024) 017 * examples: XT2 (address 2), XS1003 (address 1003), XL134 (address 134) 018 * </li> 019 * <li> 020 * XSmm:pp where mm is the module address (1-128) and pp is the contact pin number (1-8). 021 * </li> 022 * </ul> 023 * 024 * @author Dave Duchamp, Copyright (C) 2004 - 2006 025 * @author Bob Coleman Copyright (C) 2007, 2008, 2009 026 * @author Egbert Broerse (C) 2017 Based on Acela example, modified for XpressNet. 027 */ 028public class XNetAddress { 029 030 public XNetAddress() { 031 } 032 033 static final int MINSENSORADDRESS = 1; 034 static final int MAXSENSORADDRESS = 1024; // same for outputs 035 036 /** 037 * Public static method to parse a Lenz XpressNet system name. 038 * Note: Bits are numbered from 1. 039 * 040 * @param systemName system name to parse. 041 * @param prefix system prefix. 042 * @return the hardware address number, return -1 if an error is found 043 */ 044 public static int getBitFromSystemName(String systemName, String prefix) { 045 // validate the system Name leader characters 046 if (!systemName.startsWith(prefix)) { 047 // here if an invalid XpressNet system name 048 log.error("invalid character in header field of XpressNet system name: {} wants prefix {}", 049 systemName, prefix); 050 return (-1); 051 } 052 // name must be in the Xtnnnnn or XSmm:pp format (X is user 053 // configurable) 054 int num; 055 try { 056 String curAddress = systemName.substring(prefix.length() + 1); 057 if( ( systemName.charAt(prefix.length())=='S' || 058 systemName.charAt(prefix.length())=='s' ) && 059 curAddress.contains(":")) { 060 // Address format passed is in the form of encoderAddress:input or T:turnout address 061 int seperator = curAddress.indexOf(":"); 062 int encoderAddress = Integer.parseInt(curAddress.substring(0, seperator)); 063 int input = Integer.parseInt(curAddress.substring(seperator + 1)); 064 num = ((encoderAddress - 1) * 8) + input; 065 } else { 066 num = Integer.parseInt(curAddress); 067 } 068 } catch (NumberFormatException e) { 069 log.warn("invalid character in number field of system name: {}", systemName); 070 return (-1); 071 } 072 if ((num >= MINSENSORADDRESS) && (num <= MAXSENSORADDRESS)) { 073 return (num); 074 } 075 log.warn("XpressNet hardware address out of range in system name {}", systemName); 076 return (-1); 077 } 078 079 /** 080 * Public static method to validate system name format. 081 * Logging of handled cases no higher than WARN. 082 * 083 * @param systemName system name. 084 * @param type bean type, S for Sensor, T for Turnout, L for Light. 085 * @param prefix system prefix. 086 * @return VALID if system name has a valid format, else return INVALID 087 */ 088 public static NameValidity validSystemNameFormat(@Nonnull String systemName, char type, String prefix) { 089 // validate the system Name leader characters 090 if (!(systemName.startsWith(prefix + type))) { 091 // here if an illegal format 092 log.error("invalid character in header field of system name: {} wants prefix {} type {}", 093 systemName, prefix, type); 094 return NameValidity.INVALID; 095 } 096 if (getBitFromSystemName(systemName, prefix) > 0) { 097 return NameValidity.VALID; 098 } else { 099 return NameValidity.INVALID; 100 } 101 } 102 103 /** 104 * Public static method to check the user name for a valid system name. 105 * 106 * @param systemName system name to check. 107 * @param prefix system prefix. 108 * @return "" (null string) if the system name is not valid or does not exist 109 */ 110 public static String getUserNameFromSystemName(String systemName, String prefix) { 111 // check for a valid system name 112 if ((systemName.length() < (prefix.length() + 2)) || (!systemName.startsWith(prefix))) { 113 // not a valid system name for XNet 114 return (""); 115 } 116 // check for a sensor 117 if (systemName.charAt(prefix.length() + 1) == 'S') { 118 jmri.Sensor s; 119 s = jmri.InstanceManager.sensorManagerInstance().getBySystemName(systemName); 120 if (s != null) { 121 return s.getUserName(); 122 } else { 123 return (""); 124 } 125 } // check for a turnout 126 else if (systemName.charAt(prefix.length() + 1) == 'T') { 127 jmri.Turnout t; 128 t = jmri.InstanceManager.turnoutManagerInstance().getBySystemName(systemName); 129 if (t != null) { 130 return t.getUserName(); 131 } else { 132 return (""); 133 } 134 } // check for a light 135 else if (systemName.charAt(prefix.length() + 1) == 'L') { 136 jmri.Light lgt; 137 lgt = jmri.InstanceManager.lightManagerInstance().getBySystemName(systemName); 138 if (lgt != null) { 139 return lgt.getUserName(); 140 } else { 141 return (""); 142 } 143 } 144 145 // not any known sensor, light, or turnout 146 return (""); 147 } 148 149 private static final Logger log = LoggerFactory.getLogger(XNetAddress.class); 150 151}