001package jmri.jmrix.grapevine; 002 003import java.util.Locale; 004 005import javax.annotation.Nonnull; 006 007import jmri.JmriException; 008import jmri.Sensor; 009import org.slf4j.Logger; 010import org.slf4j.LoggerFactory; 011 012/** 013 * Manage the system-specific Sensor implementation. 014 * <p> 015 * System names are "GSnnnn", where G is the (multichar) system connection prefix, 016 * nnnn is the sensor number without padding. 017 * <p> 018 * Sensors are numbered from 1. 019 * 020 * @author Bob Jacobsen Copyright (C) 2003, 2006, 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 address in the naming scheme. 028 * <p> 029 * The first node address uses sensors from 1 to SENSORSPERNODE-1, the 030 * second from SENSORSPERNODE+1 to SENSORSPERNODE+(SENSORSPERNODE-1), etc. 031 * <p> 032 * Must be more than, and is generally one more than, 033 * {@link SerialNode#MAXSENSORS} 034 */ 035 static final int SENSORSPERNODE = 1000; 036 037 public SerialSensorManager(GrapevineSystemConnectionMemo memo) { 038 super(memo); 039 } 040 041 /** 042 * {@inheritDoc} 043 */ 044 @Override 045 @Nonnull 046 public GrapevineSystemConnectionMemo getMemo() { 047 return (GrapevineSystemConnectionMemo) memo; 048 } 049 050 /** 051 * {@inheritDoc} 052 * <p> 053 * System name is normalized to ensure uniqueness. 054 * @throws IllegalArgumentException when SystemName can't be converted 055 */ 056 @Override 057 @Nonnull 058 protected Sensor createNewSensor(@Nonnull String systemName, String userName) throws IllegalArgumentException { 059 String prefix = getSystemPrefix(); 060 log.debug("createNewSensor {} {}", systemName, userName); 061 Sensor s; 062 // validate the system name, and normalize it 063 String sName = SerialAddress.normalizeSystemName(systemName, prefix); 064 if (sName.isEmpty()) { 065 // system name is not valid 066 throw new IllegalArgumentException("Invalid Grapevine Sensor system name - " + // NOI18N 067 systemName); 068 } 069 // does this Sensor already exist 070 s = getBySystemName(sName); 071 if (s != null) { 072 throw new IllegalArgumentException("Grapevine Sensor with this name already exists - " + // NOI18N 073 systemName); 074 } 075 // check under alternate name 076 String altName = SerialAddress.convertSystemNameToAlternate(sName, prefix); 077 s = getBySystemName(altName); 078 if (s != null) { 079 throw new IllegalArgumentException("Grapevine Sensor with name " + // NOI18N 080 systemName + " already exists as " + altName); 081 } 082 // check bit number 083 int bit = SerialAddress.getBitFromSystemName(sName, prefix); 084 if ((bit <= 0) || (bit >= SENSORSPERNODE)) { 085 throw new IllegalArgumentException("Sensor bit number " + // NOI18N 086 Integer.toString(bit) + " is outside the supported range 1-" + 087 Integer.toString(SENSORSPERNODE - 1)); 088 } 089 // Sensor system name is valid and Sensor doesn't exist, make a new one 090 if (userName == null) { 091 s = new SerialSensor(sName, getMemo()); 092 } else { 093 s = new SerialSensor(sName, userName, getMemo()); 094 } 095 096 // ensure that a corresponding Serial Node exists 097 SerialNode node = SerialAddress.getNodeFromSystemName(sName, getMemo().getTrafficController()); 098 if (node == null) { 099 log.warn("Sensor {} refers to an undefined Serial Node.", sName); 100 return s; 101 } 102 // register this sensor with the Serial Node 103 node.registerSensor(s, bit); 104 log.debug("registered {} in node {}", s.getSystemName(), node); 105 return s; 106 } 107 108 /** {@inheritDoc} */ 109 @Override 110 @Nonnull 111 public String createSystemName(@Nonnull String curAddress, @Nonnull String prefix) throws jmri.JmriException { 112 String tmpSName = prefix + "S" + curAddress; 113 // first, check validity 114 try { 115 validSystemNameFormat(tmpSName); 116 } catch (IllegalArgumentException e) { 117 throw new JmriException(e.toString()); 118 } 119 log.debug("createSystemName {}", tmpSName); 120 return tmpSName; 121 } 122 123 /** 124 * {@inheritDoc} 125 */ 126 @Override 127 @Nonnull 128 public String validateSystemNameFormat(@Nonnull String name, @Nonnull Locale locale) { 129 return SerialAddress.validateSystemNameFormat(name, this, locale); 130 } 131 132 /** 133 * {@inheritDoc} 134 */ 135 @Override 136 public NameValidity validSystemNameFormat(@Nonnull String systemName) { 137 return SerialAddress.validSystemNameFormat(systemName, typeLetter(), getSystemPrefix()); 138 } 139 140 /** 141 * {@inheritDoc} 142 */ 143 @Override 144 public String getEntryToolTip() { 145 return Bundle.getMessage("AddInputEntryToolTip"); 146 } 147 148 /** 149 * Dummy routine. 150 */ 151 @Override 152 public void message(SerialMessage r) { 153 } 154 155 /** 156 * Process a reply to a poll of Sensors of one node. 157 */ 158 @Override 159 public void reply(SerialReply r) { 160 // determine which node 161 SerialNode node = (SerialNode) getMemo().getTrafficController().getNodeFromAddress(r.getAddr()); 162 if (node != null) { 163 node.markChanges(r); 164 } 165 log.debug("node {} marked as changed by SerialSensorManager", r.getAddr()); 166 } 167 168 /** 169 * Register any orphan Sensors when a new Serial Node is created. 170 * @param node node to register sensors for. 171 */ 172 public void registerSensorsForNode(SerialNode node) { 173 // Iterate through list containing names of all Sensors 174 SerialNode tNode; 175 for (Sensor s : getNamedBeanSet()) { 176 String sName = s.getSystemName(); 177 log.debug("System Name is {}", sName); 178 if (sName.startsWith(getSystemNamePrefix())) { // multichar prefix 179 // This is a Sensor 180 tNode = SerialAddress.getNodeFromSystemName(sName, getMemo().getTrafficController()); 181 if (tNode == node) { 182 // This sensor is for this new Serial Node - register it 183 node.registerSensor(s, SerialAddress.getBitFromSystemName(sName, getSystemPrefix())); 184 } 185 } 186 } 187 } 188 189 private final static Logger log = LoggerFactory.getLogger(SerialSensorManager.class); 190 191}