001package jmri.jmrix.ieee802154.xbee; 002 003import java.util.Locale; 004import javax.annotation.Nonnull; 005import jmri.JmriException; 006import jmri.NamedBean; 007import jmri.Turnout; 008import jmri.managers.AbstractTurnoutManager; 009import org.slf4j.Logger; 010import org.slf4j.LoggerFactory; 011 012/** 013 * Implement turnout manager for XBee connections 014 * 015 * @author Paul Bender Copyright (C) 2014 016 */ 017public class XBeeTurnoutManager extends AbstractTurnoutManager { 018 019 protected XBeeTrafficController tc = null; 020 021 public XBeeTurnoutManager(XBeeConnectionMemo memo) { 022 super(memo); 023 tc = (XBeeTrafficController) memo.getTrafficController(); 024 } 025 026 /** 027 * {@inheritDoc} 028 */ 029 @Override 030 @Nonnull 031 public XBeeConnectionMemo getMemo() { 032 return (XBeeConnectionMemo) memo; 033 } 034 035 // for now, set this to false. Multiple additions currently works 036 // partially, but not for all possible cases. 037 @Override 038 public boolean allowMultipleAdditions(@Nonnull String systemName) { 039 return false; 040 } 041 042 /** 043 * {@inheritDoc} 044 */ 045 @Nonnull 046 @Override 047 protected Turnout createNewTurnout(@Nonnull String systemName, String userName) throws IllegalArgumentException { 048 XBeeNode curNode; 049 String name = addressFromSystemName(systemName); 050 if ((curNode = (XBeeNode) tc.getNodeFromName(name)) == null) { 051 if ((curNode = (XBeeNode) tc.getNodeFromAddress(name)) == null) { 052 try { 053 curNode = (XBeeNode) tc.getNodeFromAddress(Integer.parseInt(name)); 054 } catch (java.lang.NumberFormatException nfe) { 055 // if there was a number format exception, we couldn't 056 // find the node. 057 log.debug("failed to create turnout {}", systemName); 058 throw new IllegalArgumentException("Cannot find Node, check Turnout System Name " + systemName); 059 } 060 } 061 } 062 int pin = pinFromSystemName(systemName); 063 int pin2 = pin2FromSystemName(systemName); 064 if (!curNode.getPinAssigned(pin) 065 && (pin2 == -1 || !curNode.getPinAssigned(pin2))) { 066 log.debug("Adding turnout to pin {}", pin); 067 curNode.setPinBean(pin, new XBeeTurnout(systemName, userName, tc)); 068 if (pin2 != -1) { 069 curNode.setPinBean(pin2, curNode.getPinBean(pin)); 070 } 071 return (XBeeTurnout) curNode.getPinBean(pin); 072 } else { 073 log.debug("failed to create turnout {}", systemName); 074 throw new IllegalArgumentException("Cannot create Turnout " + systemName + ", check pins."); 075 } 076 } 077 078 @Override 079 public String createSystemName(@Nonnull String curAddress, @Nonnull String prefix) throws JmriException { 080 return prefix + typeLetter() + curAddress; 081 } 082 083 /** 084 * {@inheritDoc} 085 */ 086 @Override 087 @Nonnull 088 public String validateSystemNameFormat(@Nonnull String name, @Nonnull Locale locale) { 089 super.validateSystemNameFormat(name, locale); 090 int pin = pinFromSystemName(name); 091 int pin2 = pin2FromSystemName(name); 092 if (pin < 0 || pin > 7) { 093 throw new NamedBean.BadSystemNameException( 094 Bundle.getMessage(Locale.ENGLISH, "SystemNameInvalidPin", name), 095 Bundle.getMessage(locale, "SystemNameInvalidPin", name)); 096 } 097 if (pin2 != -1 && (pin2 < 0 || pin2 > 7)) { 098 throw new NamedBean.BadSystemNameException( 099 Bundle.getMessage(Locale.ENGLISH, "SystemNameInvalidPin", name), 100 Bundle.getMessage(locale, "SystemNameInvalidPin", name)); 101 } 102 return name; 103 } 104 105 /** 106 * {@inheritDoc} 107 */ 108 @Override 109 public NameValidity validSystemNameFormat(@Nonnull String systemName) { 110 if (tc.getNodeFromName(addressFromSystemName(systemName)) == null 111 && tc.getNodeFromAddress(addressFromSystemName(systemName)) == null) { 112 try { 113 if (tc.getNodeFromAddress(Integer.parseInt(addressFromSystemName(systemName))) == null) { 114 return NameValidity.INVALID; 115 } else { 116 return (pinFromSystemName(systemName) >= 0 117 && pinFromSystemName(systemName) <= 7 118 && (pin2FromSystemName(systemName) == -1 119 || (pin2FromSystemName(systemName) >= 0 120 && pin2FromSystemName(systemName) <= 7))) ? NameValidity.VALID : NameValidity.INVALID; 121 } 122 } catch (java.lang.NumberFormatException nfe) { 123 // if there was a number format exception, we couldn't 124 // find the node. 125 log.error("Unable to convert {} into the Xbee node and pin format of nn:xx", systemName); 126 return NameValidity.INVALID; 127 } 128 129 } else { 130 return (pinFromSystemName(systemName) >= 0 131 && pinFromSystemName(systemName) <= 7 132 && (pin2FromSystemName(systemName) == -1 133 || (pin2FromSystemName(systemName) >= 0 134 && pin2FromSystemName(systemName) <= 7))) ? NameValidity.VALID : NameValidity.INVALID; 135 } 136 } 137 138 private String addressFromSystemName(@Nonnull String systemName) { 139 String encoderAddress; 140 141 if (systemName.contains(":")) { 142 //Address format passed is in the form of encoderAddress:input or S:turnout address 143 int seperator = systemName.indexOf(":"); 144 encoderAddress = systemName.substring(getSystemPrefix().length() + 1, seperator); 145 } else { 146 encoderAddress = systemName.substring(getSystemPrefix().length() + 1, systemName.length() - 1); 147 } 148 log.debug("Converted {} to hardware address {}", systemName, encoderAddress); 149 return encoderAddress; 150 } 151 152 private int pinFromSystemName(@Nonnull String systemName) { 153 int input = 0; 154 int iName = 0; 155 156 if (systemName.contains(":")) { 157 //Address format passed is in the form of encoderAddress:input or T:turnout address 158 int seperator = systemName.indexOf(":"); 159 int seperator2 = systemName.indexOf(":", seperator + 1); 160 int len = systemName.length(); 161 try { 162 if ((seperator2 >= 0) && (seperator2 <= len)) { 163 input = Integer.parseInt(systemName.substring(seperator + 1, seperator2)); 164 } else { 165 input = Integer.parseInt(systemName.substring(seperator + 1, len)); 166 } 167 } catch (NumberFormatException ex) { 168 log.debug("Unable to convert {} into the XBee node and pin format of nn:xx", systemName); 169 return -1; 170 } 171 } else { 172 try { 173 iName = Integer.parseInt(systemName.substring(getSystemPrefix().length() + 1)); 174 input = iName % 10; 175 } catch (NumberFormatException ex) { 176 log.debug("Unable to convert {} system name to a number", systemName); 177 return -1; 178 } 179 } 180 log.debug("Converted {} to pin number {}", systemName, input); 181 return input; 182 } 183 184 private int pin2FromSystemName(@Nonnull String systemName) { 185 int input = 0; 186 187 if (systemName.contains(":")) { 188 //Address format passed is in the form of encoderAddress:input or T:turnout address 189 int seperator = systemName.indexOf(":"); 190 int seperator2 = systemName.indexOf(":", seperator + 1); 191 try { 192 input = Integer.parseInt(systemName.substring(seperator2 + 1)); 193 } catch (NumberFormatException ex) { 194 log.debug("Unable to convert {} into the cab and input format of nn:xx", systemName); 195 return -1; 196 } 197 } else { 198 // no ":" means only one pin. 199 input = -1; 200 } 201 log.debug("Converted {} to pin number {}", systemName, input); 202 return input; 203 } 204 205 @Override 206 public void deregister(@Nonnull jmri.Turnout t) { 207 super.deregister(t); 208 // remove the specified turnout from the associated XBee pin. 209 String systemName = t.getSystemName(); 210 String name = addressFromSystemName(systemName); 211 int pin = pinFromSystemName(systemName); 212 XBeeNode curNode; 213 if ((curNode = (XBeeNode) tc.getNodeFromName(name)) == null) { 214 if ((curNode = (XBeeNode) tc.getNodeFromAddress(name)) == null) { 215 try { 216 curNode = (XBeeNode) tc.getNodeFromAddress(Integer.parseInt(name)); 217 } catch (java.lang.NumberFormatException nfe) { 218 // if there was a number format exception, we couldn't find the node. 219 curNode = null; 220 } 221 } 222 } 223 if (curNode != null) { 224 if (curNode.removePinBean(pin, t)) { 225 log.debug("Removing turnout from pin {}", pin); 226 } else { 227 log.debug("Failed to removing turnout from pin {}", pin); 228 } 229 } 230 } 231 232 /** 233 * {@inheritDoc} 234 */ 235 @Override 236 public String getEntryToolTip() { 237 return Bundle.getMessage("AddTurnoutEntryToolTip"); 238 } 239 240 private final static Logger log = LoggerFactory.getLogger(XBeeTurnoutManager.class); 241 242}