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