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