001package jmri.jmrix.oaktree; 002 003import java.util.Locale; 004import javax.annotation.Nonnull; 005import jmri.Sensor; 006import org.slf4j.Logger; 007import org.slf4j.LoggerFactory; 008 009/** 010 * Manage the system-specific Sensor implementation. 011 * <p> 012 * System names are "OSnnn", where O is the user configurable system prefix, 013 * nnn is the sensor number without padding. 014 * <p> 015 * Sensors are numbered from 1. 016 * 017 * @author Bob Jacobsen Copyright (C) 2003, 2006 018 * @author Dave Duchamp, multi node extensions, 2004 019 */ 020public class SerialSensorManager extends jmri.managers.AbstractSensorManager 021 implements SerialListener { 022 023 public SerialSensorManager() { 024 this(jmri.InstanceManager.getDefault(OakTreeSystemConnectionMemo.class)); 025 } 026 027 public SerialSensorManager(OakTreeSystemConnectionMemo memo) { 028 super(memo); 029 } 030 031 /** 032 * Number of sensors per address in the naming scheme. 033 * <p> 034 * The first node address uses sensors from 1 to SENSORSPERNODE-1, the 035 * second from SENSORSPERNODE+1 to SENSORSPERNODE+(SENSORSPERNODE-1), etc. 036 * <p> 037 * Must be more than, and is generally one more than, 038 * {@link SerialNode#MAXSENSORS} 039 */ 040 static final int SENSORSPERNODE = 1000; 041 042 /** 043 * {@inheritDoc} 044 */ 045 @Override 046 @Nonnull 047 public OakTreeSystemConnectionMemo getMemo() { 048 return (OakTreeSystemConnectionMemo) memo; 049 } 050 051 /** 052 * {@inheritDoc} 053 * <p> 054 * System name is normalized to ensure uniqueness. 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 Oaktree 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("Oaktree Sensor with this name already exists - " + // NOI18N 072 systemName); 073 } 074 // check under alternate name 075 String altName = SerialAddress.convertSystemNameToAlternate(sName, getSystemPrefix()); 076 s = getBySystemName(altName); 077 if (s != null) { 078 throw new IllegalArgumentException("Grapevine Sensor with name " + // NOI18N 079 systemName + " already exists as " + altName); 080 } 081 // check bit number 082 int bit = SerialAddress.getBitFromSystemName(sName, getSystemPrefix()); 083 if ((bit <= 0) || (bit >= SENSORSPERNODE)) { 084 throw new IllegalArgumentException("Sensor bit number " + // NOI18N 085 Integer.toString(bit) + " is outside the supported range 1-" + 086 Integer.toString(SENSORSPERNODE - 1)); 087 } 088 // Sensor system name is valid and Sensor doesn't exist, make a new one 089 if (userName == null) { 090 s = new SerialSensor(sName); 091 } else { 092 s = new SerialSensor(sName, userName); 093 } 094 095 // ensure that a corresponding Serial Node exists 096 SerialNode node = SerialAddress.getNodeFromSystemName(sName, getMemo().getTrafficController()); 097 if (node == null) { 098 log.warn("Sensor {} refers to an undefined Serial Node.", sName); 099 return s; 100 } 101 // register this sensor with the Serial Node 102 node.registerSensor(s, bit - 1); 103 return s; 104 } 105 106 /** 107 * {@inheritDoc} 108 */ 109 @Override 110 @Nonnull 111 public String validateSystemNameFormat(@Nonnull String systemName, @Nonnull Locale locale) { 112 return SerialAddress.validateSystemNameFormat(systemName, getSystemNamePrefix(), locale); 113 } 114 115 /** 116 * {@inheritDoc} 117 */ 118 @Override 119 public NameValidity validSystemNameFormat(@Nonnull String systemName) { 120 return (SerialAddress.validSystemNameFormat(systemName, typeLetter(), getSystemPrefix())); 121 } 122 123 /** 124 * Dummy routine 125 */ 126 @Override 127 public void message(SerialMessage r) { 128 log.warn("unexpected message"); 129 } 130 131 /** 132 * Process a reply to a poll of Sensors of one node 133 */ 134 @Override 135 public void reply(SerialReply r) { 136 // determine which node 137 SerialNode node = (SerialNode) getMemo().getTrafficController().getNodeFromAddress(r.getAddr()); 138 if (node != null) { 139 node.markChanges(r); 140 } 141 } 142 143 /** 144 * Method to register any orphan Sensors when a new Serial Node is created. 145 * @param node node to register. 146 */ 147 public void registerSensorsForNode(SerialNode node) { 148 // Iterate through the sensors 149 SerialNode tNode; 150 for (Sensor s : getNamedBeanSet()) { 151 String sName = s.getSystemName(); 152 log.debug("system name is {}", sName); 153 if (sName.startsWith(getSystemNamePrefix())) { // multichar prefix 154 // This is a Sensor 155 tNode = SerialAddress.getNodeFromSystemName(sName, getMemo().getTrafficController()); 156 if (tNode == node) { 157 // This sensor is for this new Serial Node - register it 158 node.registerSensor(s, 159 (SerialAddress.getBitFromSystemName(sName, getSystemPrefix()) - 1)); 160 } 161 } 162 } 163 } 164 165 /** 166 * {@inheritDoc} 167 */ 168 @Override 169 public String getEntryToolTip() { 170 return Bundle.getMessage("AddInputEntryToolTip"); 171 } 172 173 @Override 174 public boolean allowMultipleAdditions(@Nonnull String systemName) { 175 return true; 176 } 177 178 private final static Logger log = LoggerFactory.getLogger(SerialSensorManager.class); 179 180}