001package jmri.jmrix.maple; 002 003import java.util.Locale; 004import javax.annotation.Nonnull; 005import jmri.JmriException; 006import jmri.Sensor; 007import org.slf4j.Logger; 008import org.slf4j.LoggerFactory; 009 010/** 011 * Manage the specific Sensor implementation. 012 * <p> 013 * System names are "KSnnnn", where K is the user configurable system prefix, 014 * nnnn is the sensor number without padding. 015 * <p> 016 * Sensors are numbered from 1. 017 * <p> 018 * This is a SerialListener to handle the replies to poll messages. Those are 019 * forwarded to the specific SerialNode object corresponding to their origin for 020 * processing of the data. 021 * 022 * @author Bob Jacobsen Copyright (C) 2003, 2007, 2008 023 * @author Dave Duchamp, multi node extensions, 2004 024 */ 025public class SerialSensorManager extends jmri.managers.AbstractSensorManager 026 implements SerialListener { 027 028 /** 029 * Number of sensors per UA in the naming scheme. 030 * <p> 031 * The first UA (node address) uses sensors from 1 to SENSORSPERUA-1, the 032 * second from SENSORSPERUA+1 to SENSORSPERUA+(SENSORSPERUA-1), etc. 033 * <p> 034 * Must be more than, and is generally one more than, 035 * {@link SerialNode#MAXSENSORS} 036 */ 037 static final int SENSORSPERUA = 1000; 038 039 public SerialSensorManager(MapleSystemConnectionMemo memo) { 040 super(memo); 041 } 042 043 /** 044 * {@inheritDoc} 045 */ 046 @Override 047 @Nonnull 048 public MapleSystemConnectionMemo getMemo() { 049 return (MapleSystemConnectionMemo) memo; 050 } 051 052 /** 053 * {@inheritDoc} 054 * <p> 055 * System name is normalized to ensure uniqueness. 056 * 057 * @throws IllegalArgumentException when SystemName can't be converted 058 */ 059 @Override 060 @Nonnull 061 protected Sensor createNewSensor(@Nonnull String systemName, String userName) throws IllegalArgumentException { 062 Sensor s; 063 // validate the system name, and normalize it 064 String sName = SerialAddress.normalizeSystemName(systemName, getSystemPrefix()); 065 if (sName.isEmpty()) { 066 // system name is not valid 067 throw new IllegalArgumentException("Invalid Maple Sensor system name - " + // NOI18N 068 systemName); 069 } 070 // does this Sensor already exist 071 s = getBySystemName(sName); 072 if (s != null) { 073 throw new IllegalArgumentException("Maple Sensor with this name already exists - " + // NOI18N 074 systemName); 075 } 076 // check bit number 077 int bit = SerialAddress.getBitFromSystemName(sName, getSystemPrefix()); 078 if ((bit <= 0) || (bit > 1000)) { 079 log.warn("Sensor bit number '{}' is outside the supported range, 1-1000", Integer.toString(bit)); 080 throw new IllegalArgumentException("Sensor bit number " + // NOI18N 081 Integer.toString(bit) + " is outside the supported range 1-1000"); 082 } 083 // Sensor system name is valid and Sensor doesn't exist, make a new one 084 if (userName == null) { 085 s = new SerialSensor(sName); // prefix not passed 086 } else { 087 s = new SerialSensor(sName, userName); // prefix not passed 088 } 089 // check configured 090 if (!SerialAddress.validSystemNameConfig(sName, 'S', getMemo())) { 091 log.warn("Sensor system Name '{}' does not address configured hardware.", sName); 092 javax.swing.JOptionPane.showMessageDialog(null, "WARNING - The Sensor just added, " 093 + sName + ", refers to an unconfigured input bit.", "Configuration Warning", 094 javax.swing.JOptionPane.INFORMATION_MESSAGE, null); 095 } 096 // register this sensor 097 getMemo().getTrafficController().inputBits().registerSensor(s, bit - 1); 098 return s; 099 } 100 101 /** 102 * {@inheritDoc} 103 */ 104 @Override 105 @Nonnull 106 public String validateSystemNameFormat(@Nonnull String name, @Nonnull Locale locale) { 107 return SerialAddress.validateSystemNameFormat(name, this, locale); 108 } 109 110 /** 111 * {@inheritDoc} 112 */ 113 @Override 114 public NameValidity validSystemNameFormat(@Nonnull String systemName) { 115 return (SerialAddress.validSystemNameFormat(systemName, typeLetter(), getSystemPrefix())); 116 } 117 118 /** 119 * {@inheritDoc} 120 */ 121 @Override 122 public String getEntryToolTip() { 123 return Bundle.getMessage("AddInputEntryToolTip"); 124 } 125 126 /** 127 * Dummy routine. 128 * @param r unused. 129 */ 130 @Override 131 public void message(SerialMessage r) { 132 log.warn("unexpected message"); 133 } 134 135 /** 136 * Process a reply to a poll of Sensors of one panel node. 137 * {@inheritDoc} 138 */ 139 @Override 140 public void reply(SerialReply r) { 141 getMemo().getTrafficController().inputBits().markChanges(r); 142 } 143 144 /** 145 * Method to register any orphan Sensors when a new Serial Node is created. 146 * @param node node to register. 147 */ 148 public void registerSensorsForNode(SerialNode node) { 149 // get list containing all Sensors 150 for (Sensor s : getNamedBeanSet()) { 151 String sName = s.getSystemName(); 152 log.debug("system name is {}", sName); 153 if (sName.startsWith(getSystemNamePrefix())) { 154 // This is a valid Sensor - make sure it is registered 155 getMemo().getTrafficController().inputBits().registerSensor(s, 156 (SerialAddress.getBitFromSystemName(sName, getSystemPrefix()) - 1)); 157 } 158 } 159 } 160 161 @Override 162 public boolean allowMultipleAdditions(@Nonnull String systemName) { 163 return true; 164 } 165 166 @Override 167 @Nonnull 168 public String createSystemName(@Nonnull String curAddress, @Nonnull String prefix) throws JmriException { 169 if (curAddress.contains(":")) { 170 //Address format passed is in the form of sysNode:address or T:turnout address 171 int seperator = curAddress.indexOf(":"); 172 try { 173 sysNode = Integer.parseInt(curAddress.substring(0, seperator)); 174 address = Integer.parseInt(curAddress.substring(seperator + 1)); 175 } catch (NumberFormatException ex) { 176 throw new JmriException("Unable to convert "+curAddress+" into the cab and address format of nn:xx"); 177 } 178 iName = (sysNode * 1000) + address; 179 } else { 180 //Entered in using the old format 181 try { 182 iName = Integer.parseInt(curAddress); 183 } catch (NumberFormatException ex) { 184 throw new JmriException("Hardware Address passed "+curAddress+" should be a number or the cab and address format of nn:xx"); 185 } 186 } 187 return prefix + typeLetter() + iName; 188 } 189 190 private int sysNode = 0; 191 private int address = 0; 192 private int iName = 0; 193 194 private final static Logger log = LoggerFactory.getLogger(SerialSensorManager.class); 195 196}