001package jmri.jmrix.secsi; 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 SECSI Sensor implementation. 011 * <p> 012 * System names are "VSnnnn", where V is the user configurable system prefix, 013 * nnnn is the sensor number without padding. 014 * <p> 015 * Sensors are numbered from 1. 016 * 017 * @author Bob Jacobsen Copyright (C) 2003, 2006, 2007, 2008 018 * @author Dave Duchamp, multi node extensions, 2004 019 */ 020public class SerialSensorManager extends jmri.managers.AbstractSensorManager 021 implements SerialListener { 022 023 /** 024 * Number of sensors per address in the naming scheme. 025 * <p> 026 * The first node address uses sensors from 1 to SENSORSPERNODE-1, the 027 * second from SENSORSPERNODE+1 to SENSORSPERNODE+(SENSORSPERNODE-1), etc. 028 * <p> 029 * Must be more than, and is generally one more than, 030 * {@link SerialNode#MAXSENSORS} 031 * 032 */ 033 static final int SENSORSPERNODE = 1000; 034 035 public SerialSensorManager(SecsiSystemConnectionMemo memo) { 036 super(memo); 037 } 038 039 /** 040 * {@inheritDoc} 041 */ 042 @Override 043 @Nonnull 044 public SecsiSystemConnectionMemo getMemo() { 045 return (SecsiSystemConnectionMemo) memo; 046 } 047 048 /** 049 * {@inheritDoc} 050 * <p> 051 * System name is normalized to ensure uniqueness. 052 * 053 * @throws IllegalArgumentException when SystemName can't be converted 054 */ 055 @Override 056 @Nonnull 057 protected Sensor createNewSensor(@Nonnull String systemName, String userName) throws IllegalArgumentException { 058 Sensor s; 059 // validate the system name, and normalize it 060 String sName = SerialAddress.normalizeSystemName(systemName, getSystemPrefix()); 061 if (sName.isEmpty()) { 062 // system name is not valid 063 throw new IllegalArgumentException("Invalid Secsi Sensor system name - " + // NOI18N 064 systemName); 065 } 066 // does this Sensor already exist 067 s = getBySystemName(sName); 068 if (s != null) { 069 throw new IllegalArgumentException("Secsi Sensor with this name already exists - " + // NOI18N 070 systemName); 071 } 072 // check under alternate name 073 String altName = SerialAddress.convertSystemNameToAlternate(sName, getSystemPrefix()); 074 s = getBySystemName(altName); 075 if (s != null) { 076 throw new IllegalArgumentException("Secsi Sensor with name " + // NOI18N 077 systemName + " already exists as " + altName); 078 } 079 // check bit number 080 int bit = SerialAddress.getBitFromSystemName(sName, getSystemPrefix()); 081 if ((bit <= 0) || (bit >= SENSORSPERNODE)) { 082 throw new IllegalArgumentException("Sensor bit number " + // NOI18N 083 Integer.toString(bit) + " is outside the supported range 1-" + 084 Integer.toString(SENSORSPERNODE - 1)); 085 } 086 // Sensor system name is valid and Sensor doesn't exist, make a new one 087 if (userName == null) { 088 s = new SerialSensor(sName, getMemo()); 089 } else { 090 s = new SerialSensor(sName, userName, getMemo()); 091 } 092 093 // ensure that a corresponding Serial Node exists 094 SerialNode node = SerialAddress.getNodeFromSystemName(sName, getMemo().getTrafficController()); 095 if (node == null) { 096 log.warn("Sensor '{}' refers to an undefined Serial Node.", sName); 097 return s; 098 } 099 // register this sensor with the Serial Node 100 node.registerSensor(s, bit - 1); 101 return s; 102 } 103 104 /** 105 * {@inheritDoc} 106 */ 107 @Override 108 @Nonnull 109 public String validateSystemNameFormat(@Nonnull String systemName, @Nonnull Locale locale) { 110 return SerialAddress.validateSystemNameFormat(systemName, getSystemNamePrefix(), locale); 111 } 112 113 /** 114 * {@inheritDoc} 115 */ 116 @Override 117 public NameValidity validSystemNameFormat(@Nonnull String systemName) { 118 return (SerialAddress.validSystemNameFormat(systemName, typeLetter(), this.getSystemPrefix())); 119 } 120 121 /** 122 * Dummy routine 123 */ 124 @Override 125 public void message(SerialMessage r) { 126 log.warn("unexpected message"); 127 } 128 129 /** 130 * Process a reply to a poll of Sensors of one node. 131 */ 132 @Override 133 public void reply(SerialReply r) { 134 // determine which node 135 log.debug("received node poll reply '{}'", r.toString()); 136 SerialNode node = (SerialNode) getMemo().getTrafficController().getNodeFromAddress(r.getAddr()); 137 if (node != null) { 138 node.markChanges(r); 139 } 140 } 141 142 /** 143 * 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 log.debug("registering node {}", node.getNodeAddress()); 148 // Iterate through the sensors 149 getNamedBeanSet().forEach(sensorInSet -> { 150 String sName = sensorInSet.getSystemName(); 151 log.debug("system name is {}", sName); 152 if (sName.startsWith(getSystemNamePrefix())) { // multichar prefix 153 // This is a Sensor 154 SerialNode tNode = SerialAddress.getNodeFromSystemName(sName, getMemo().getTrafficController()); 155 if (tNode == node) { 156 // This sensor is for this new Serial Node - register it 157 log.debug("register sensor on node {}", node.getNodeAddress()); 158 node.registerSensor(sensorInSet, 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 private final static Logger log = LoggerFactory.getLogger(SerialSensorManager.class); 174 175}