001package jmri.jmrix.can.cbus.node; 002 003import java.beans.PropertyChangeListener; 004import java.util.concurrent.CopyOnWriteArraySet; 005// import javax.annotation.Nonnull; 006 007import javax.annotation.CheckForNull; 008 009import jmri.jmrix.can.CanSystemConnectionMemo; 010import jmri.jmrix.can.TrafficController; 011import jmri.jmrix.can.cbus.CbusSend; 012 013import org.slf4j.Logger; 014import org.slf4j.LoggerFactory; 015 016/** 017 * Class to represent a node. 018 * 019 * @author Steve Young Copyright (C) 2019 020 */ 021public class CbusBasicNode { 022 protected CanSystemConnectionMemo _memo; 023 private int _nodeNumber; 024 025 private int _canId; 026 private boolean _inSetupMode; 027 private boolean _inlearnMode; 028 private boolean _inFLiMMode; 029 030 public CbusSend send; 031 032 // data members to hold contact with the property listeners 033 protected final CopyOnWriteArraySet<PropertyChangeListener> _listeners; 034 035 /** 036 * Create a new CbusBasicNodeWithChangeListener. 037 * 038 * @param connmemo The CAN Connection to use 039 * @param nodenumber The Node Number 040 */ 041 public CbusBasicNode ( @CheckForNull CanSystemConnectionMemo connmemo, int nodenumber ){ 042 _memo = connmemo; 043 _nodeNumber = nodenumber; 044 _canId = 1; 045 _inSetupMode = false; 046 _inlearnMode = false; 047 _inFLiMMode = true; 048 049 send = new CbusSend(_memo); 050 _listeners = new CopyOnWriteArraySet<>(); 051 } 052 053 /** 054 * Register for notification if any of the properties change. 055 * 056 * @param l The Listener to attach to Node 057 */ 058 public void addPropertyChangeListener(PropertyChangeListener l) { 059 // add only if not already registered 060 if (!_listeners.contains(l)) { 061 _listeners.add(l); 062 // log.info("Added listener {}, new size is {}", l,_listeners.size()); 063 } 064 } 065 066 /** 067 * Remove notification listener. 068 * @param l Listener to remove 069 */ 070 public void removePropertyChangeListener(PropertyChangeListener l) { 071 if (_listeners.contains(l)) { 072 _listeners.remove(l); 073 // log.info("Removed listener {}, new size is {}", l,_listeners.size()); 074 } 075 } 076 077 /** 078 * Trigger the notification of Node PropertyChangeListeners. 079 * 080 * Properties include 081 * PARAMETER, 082 * BACKUPS, 083 * SINGLENVUPDATE ( newValue NV index (0 is NV1, 5 is NV6) ) 084 * ALLNVUPDATE 085 * SINGLEEVUPDATE ( newValue event row ) 086 * ALLEVUPDATE 087 * DELETEEVCOMPLETE ( newValue Error String else empty String ) 088 * ADDEVCOMPLETE ( newValue Error String else null ) 089 * ADDALLEVCOMPLETE ( Event Teach Loop Completed, newValue error count ) 090 * TEACHNVCOMPLETE ( newValue error count ) 091 * NAMECHANGE 092 * 093 * @param property Node property 094 * @param oldValue Old Value 095 * @param newValue New Value 096 */ 097 protected void notifyPropertyChangeListener(String property, Object oldValue, Object newValue) { 098 if ((oldValue != null && oldValue.equals(newValue)) || (newValue != null && newValue.equals(oldValue))) { 099 log.error("notifyPropertyChangeListener without change"); 100 return; 101 } 102 _listeners.forEach((listener) -> { 103 listener.propertyChange(new java.beans.PropertyChangeEvent(this, property, oldValue, newValue)); 104 }); 105 } 106 107 /** 108 * Returns Node Number. 109 * 110 * @return Node Number,1-65535 111 */ 112 public int getNodeNumber() { 113 return _nodeNumber; 114 } 115 116 /** 117 * Set Node Number. 118 * @param newnumber Node Number, should be 1-65535 119 */ 120 public void setNodeNumber ( int newnumber ) { 121 _nodeNumber = newnumber; 122 notifyPropertyChangeListener("PARAMETER", null, null); 123 } 124 125 /** 126 * Set Node CAN ID. 127 * @param newcanid CAN ID of the node 128 */ 129 public final void setCanId ( int newcanid ) { 130 _canId = newcanid; 131 notifyPropertyChangeListener("CANID", null, _canId); 132 } 133 134 /** 135 * Set CAN ID by System Connection. 136 * <p> 137 * Leaves unchanged if no System Connection or Traffic Controller. 138 * @param memo System Connection of the Node. 139 */ 140 public final void setCanId( CanSystemConnectionMemo memo ) { 141 if ( memo != null ) { 142 TrafficController tc = memo.getTrafficController(); 143 if ( tc != null ) { 144 setCanId(tc.getCanid()); 145 } 146 } 147 } 148 149 /** 150 * Get the Node CAN ID. 151 * min 1 , ( max 128? ) 152 * @return CAN ID of the node, default 1. 153 */ 154 public int getNodeCanId() { 155 return _canId; 156 } 157 158 /** 159 * Set flag for this Node in Setup Mode. 160 * <p> 161 * Does NOT send instruction to actual node 162 * 163 * @param setup use true if in Setup, else false 164 */ 165 public void setNodeInSetupMode( boolean setup ) { 166 _inSetupMode = setup; 167 notifyPropertyChangeListener("PARAMETER", null, null); 168 } 169 170 /** 171 * Get if this Node is in Setup Mode. 172 * 173 * @return true if in Setup, else false 174 */ 175 public boolean getNodeInSetupMode() { 176 return _inSetupMode; 177 } 178 179 /** 180 * Set if the Node is in Learn Mode. 181 * Used to track node status, does NOT update Physical Node 182 * 183 * @param inlearnmode set true if in Learn else false 184 */ 185 public void setNodeInLearnMode( boolean inlearnmode) { 186 boolean oldLearnmode = _inlearnMode; 187 _inlearnMode = inlearnmode; 188 if (oldLearnmode != _inlearnMode) { 189 notifyPropertyChangeListener("LEARNMODE",oldLearnmode,_inlearnMode); 190 } 191 } 192 193 /** 194 * Get if the Node is in Learn Mode. 195 * <p> 196 * Defaults to false if unset 197 * 198 * @return true if in Learn else false 199 */ 200 public boolean getNodeInLearnMode() { 201 return _inlearnMode; 202 } 203 204 /** 205 * Set if the Node is in FLiM Mode. 206 * <p> 207 * Defaults to true if unset 208 * 209 * @param inFlimMode set true if in FlIM else false 210 */ 211 public void setNodeInFLiMMode( boolean inFlimMode ) { 212 _inFLiMMode = inFlimMode; 213 } 214 215 /** 216 * Get if the Node is in FLiM Mode. 217 * <p> 218 * Defaults to true if unset 219 * 220 * @return true if in FlIM else false 221 */ 222 public boolean getNodeInFLiMMode() { 223 return _inFLiMMode; 224 } 225 226 public CanSystemConnectionMemo getMemo() { 227 return _memo; 228 } 229 230 private static final Logger log = LoggerFactory.getLogger(CbusBasicNode.class); 231 232}