001package jmri.jmrix; 002 003import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 004import org.slf4j.Logger; 005import org.slf4j.LoggerFactory; 006 007/** 008 * Abstract Traffic Controller base class for those implementations that track a 009 * set of nodes. 010 * <p> 011 * The nodes are descendents of {@link jmri.jmrix.AbstractNode}. Provides node 012 * management services, but no additional protocol. 013 * 014 * @author Bob Jacobsen Copyright (C) 2008 015 */ 016public abstract class AbstractMRNodeTrafficController extends AbstractMRTrafficController { 017 018 /** 019 * Create a new unnamed MRNodeTrafficController instance. 020 */ 021 public AbstractMRNodeTrafficController() { 022 } 023 024 /** 025 * Initialize based on number of first and last nodes. 026 * @param minNode lowest node number, usually 0 027 * @param maxNode highest node number 028 */ 029 protected void init(int minNode, int maxNode) { 030 this.minNode = minNode; 031 this.maxNode = maxNode; 032 033 nodeArray = new AbstractNode[this.maxNode + 1]; // numbering from 0 034 mustInit = new boolean[this.maxNode + 1]; 035 036 // initialize content 037 for (int i = 0; i <= this.maxNode; i++) { 038 mustInit[i] = true; 039 } 040 } 041 042 protected int minNode = -1; 043 protected int maxNode = -1; 044 045 /** 046 * Total number of SerialNodes registered with this TrafficController. 047 * Incremented as Serial Nodes are created and registered. 048 * Corresponds to the next available address in {@link #nodeArray}. 049 */ 050 protected volatile int numNodes = 0; 051 protected AbstractNode[] nodeArray; 052 private boolean[] mustInit; 053 054 /** 055 * Does a given node need to have initialization data sent? 056 * 057 * @param i the node address (number) 058 * @return true if initialization data is required 059 */ 060 protected boolean getMustInit(int i) { 061 return mustInit[i]; 062 } 063 064 /** 065 * Mark whether a given node needs to have initialization data sent. 066 * 067 * @param i the node index 068 * @param v true if set to require sending initialization data 069 */ 070 protected void setMustInit(int i, boolean v) { 071 mustInit[i] = v; 072 } 073 074 protected void setMustInit(AbstractNode node, boolean v) { 075 for (int i = 0; i < numNodes; i++) { 076 if (nodeArray[i] == node) { 077 // found node - set up for initialization 078 mustInit[i] = v; 079 return; 080 } 081 } 082 } 083 084 /** 085 * Get the total number of currently registered nodes. 086 * 087 * @return the number of registerd nodes on this connection 088 */ 089 public int getNumNodes() { 090 return numNodes; 091 } 092 093 /** 094 * Register a Serial node on this TrafficController. 095 * 096 * @param node the node object to register 097 */ 098 @SuppressFBWarnings(value = "VO_VOLATILE_INCREMENT", justification = "Method itself is synchronized to protect numNodes") 099 public void registerNode(AbstractNode node) { 100 synchronized (this) { 101 // no validity checking because at this point the node may not be fully defined 102 nodeArray[numNodes] = node; 103 mustInit[numNodes] = true; 104 numNodes++; 105 } 106 } 107 108 /** 109 * Get the Serial node for a given index as registered with this 110 * TrafficController. 111 * 112 * @param index the index number of the node. To cycle through all nodes, 113 * begin with index=0, and increment your index at each call. 114 * @return the node at index, 'null' when index exceeds the number of defined nodes 115 */ 116 public synchronized AbstractNode getNode(int index) { 117 if (index >= numNodes) { 118 return null; 119 } 120 return nodeArray[index]; 121 } 122 123 /** 124 * Identify a SerialNode from its node address. 125 * 126 * @param addr the node address, numbered from 0 127 * @return the node at node address, 'null' if a SerialNode with the 128 * specified address was not found 129 */ 130 synchronized public AbstractNode getNodeFromAddress(int addr) { 131 for (int i = 0; i < numNodes; i++) { 132 if (getNode(i).getNodeAddress() == addr) { 133 return (getNode(i)); 134 } 135 } 136 return (null); 137 } 138 139 /** 140 * Working variable for keeping track of the active node, if any. 141 */ 142 protected int curSerialNodeIndex = 0; 143 144 /** 145 * Delete a SerialNode by node address. 146 * 147 * @param nodeAddress address number for the node to be deleted 148 */ 149 @SuppressFBWarnings(value = "VO_VOLATILE_INCREMENT", justification = "Method itself is synchronized to protect numNodes") 150 public synchronized void deleteNode(int nodeAddress) { 151 // find the serial node 152 int index = 0; 153 for (int i = 0; i < numNodes; i++) { 154 if (nodeArray[i].getNodeAddress() == nodeAddress) { 155 index = i; 156 } 157 } 158 if (index == curSerialNodeIndex) { 159 log.warn("Deleting the serial node active in the polling loop"); 160 // just a warning, unlikely event and probably OK in any case. 161 } 162 // delete the node from the node list 163 numNodes--; 164 if (index < numNodes) { 165 // did not delete the last node, shift 166 for (int j = index; j < numNodes; j++) { 167 nodeArray[j] = nodeArray[j + 1]; 168 } 169 } 170 nodeArray[numNodes] = null; 171 } 172 173 private final static Logger log = LoggerFactory.getLogger(AbstractMRNodeTrafficController.class); 174 175}