001package jmri.jmrix.loconet; 002 003import java.util.ArrayList; 004import java.util.Vector; 005import java.util.concurrent.LinkedTransferQueue; 006import javax.annotation.Nonnull; 007 008import org.slf4j.Logger; 009import org.slf4j.LoggerFactory; 010 011/** 012 * Abstract base class for implementations of LocoNetInterface. 013 * <p> 014 * This provides just the basic interface and some statistics support. 015 * 016 * @author Bob Jacobsen Copyright (C) 2001 017 */ 018public abstract class LnTrafficController implements LocoNetInterface { 019 020 /** 021 * Reference to the system connection memo. 022 */ 023 LocoNetSystemConnectionMemo memo = null; 024 025 /** 026 * Configuration option: Notify listeners on adding message to transmit queue, 027 * don't notify them on receiving an echo 028 */ 029 protected boolean mLoconetUpdateSlotOnMessageCreation = false; 030 031 /** 032 * Constructor without reference to a LocoNetSystemConnectionMemo. 033 */ 034 public LnTrafficController() { 035 super(); 036 } 037 038 /** 039 * Constructor. Gets a reference to the LocoNetSystemConnectionMemo. 040 * 041 * @param memo connection's memo 042 */ 043 public LnTrafficController(LocoNetSystemConnectionMemo memo) { 044 super(); 045 this.memo = memo; 046 } 047 048 /** 049 * Set configuration option: Notify listeners on adding message to transmit queue, 050 * don't notify them on reading back the echo 051 * 052 * @param value true for notify on adding to queue 053 */ 054 public void setLoconetUpdateSlotOnMessageCreation(boolean value) { 055 mLoconetUpdateSlotOnMessageCreation = value; 056 } 057 058 /** 059 * Get configuration option: Notify listeners on adding message to transmit queue, 060 * don't notify them on reading back the echo 061 */ 062 public boolean getLoconetUpdateSlotOnMessageCreation() { 063 return mLoconetUpdateSlotOnMessageCreation; 064 } 065 066 /** 067 * Synchronized list to remember outbound packets 068 */ 069 protected LinkedTransferQueue<LocoNetMessage> sentList = new LinkedTransferQueue<>(); 070 071 public LinkedTransferQueue<LocoNetMessage> getSentList() { 072 return sentList; 073 } 074 075 /** 076 * {@inheritDoc} 077 */ 078 @Override 079 public void setSystemConnectionMemo(LocoNetSystemConnectionMemo m) { 080 log.debug("LnTrafficController set memo to {}", m.getUserName()); 081 memo = m; 082 } 083 084 /** 085 * {@inheritDoc} 086 */ 087 @Override 088 public LocoNetSystemConnectionMemo getSystemConnectionMemo() { 089 log.debug("getSystemConnectionMemo {} called in LnTC", memo.getUserName()); 090 return memo; 091 } 092 093 /** 094 * {@inheritDoc} 095 */ 096 @Override 097 abstract public boolean status(); 098 099 /** 100 * Forward a preformatted LocoNetMessage to the actual interface. 101 * <p> 102 * Implementations should update the transmit count statistic. 103 * 104 * @param m Message to send; will be updated with CRC 105 * @param requestIgnoreEcho If true: Notify listeners on enqueing message, ignore echo from line. 106 * Only in effect if preference "LoconetUpdateSlotOnMessageCreation" is set. 107 */ 108 @Override 109 abstract public void sendLocoNetMessage(LocoNetMessage m, boolean requestIgnoreEcho); 110 111 /** 112 * Forward a preformatted LocoNetMessage to the actual interface. 113 * <p> 114 * Implementations should update the transmit count statistic. 115 * 116 * @param m message to send; will be updated with CRC 117 */ 118 @Override 119 public void sendLocoNetMessage(LocoNetMessage m) { 120 sendLocoNetMessage(m, false); 121 } 122 123 // The methods to implement adding and removing listeners 124 125 // relies on Vector being a synchronized class 126 protected Vector<LocoNetListener> listeners = new Vector<LocoNetListener>(); 127 128 @Override 129 public synchronized void addLocoNetListener(int mask, @Nonnull LocoNetListener l) { 130 java.util.Objects.requireNonNull(l); 131 if (!listeners.contains(l)) { 132 listeners.addElement(l); 133 } 134 } 135 136 @Override 137 public synchronized void removeLocoNetListener(int mask, @Nonnull LocoNetListener l) { 138 java.util.Objects.requireNonNull(l); 139 if (listeners.contains(l)) { 140 listeners.removeElement(l); 141 } 142 } 143 144 /** 145 * Forward a LocoNetMessage to all registered listeners. 146 * <p> 147 * Needs to have public access, as 148 * {@link jmri.jmrix.loconet.loconetovertcp.LnOverTcpPacketizer} and 149 * {@link jmri.jmrix.loconet.Intellibox.IBLnPacketizer} invoke it, but don't 150 * inherit from it. 151 * 152 * @param m message to forward. Listeners should not modify it! 153 */ 154 public void notify(LocoNetMessage m) { 155 // record statistics 156 receivedMsgCount++; 157 receivedByteCount += m.getNumDataElements(); 158 159 // make a copy of the listener vector for notifications; synchronized not needed once copied 160 ArrayList<LocoNetListener> v; 161 synchronized (this) { 162 v = new ArrayList<LocoNetListener>(listeners); 163 } 164 165 // forward to all listeners 166 log.debug("notify of incoming LocoNet packet: {}", m); 167 for (LocoNetListener client : v) { 168 log.trace(" notify {} of incoming LocoNet packet: {}", client, m); 169 client.message(m); 170 } 171 } 172 173 /** 174 * Is there a backlog of information for the outbound link? This includes 175 * both in the program (e.g. the outbound queue) and in the Command Station 176 * interface (e.g. flow control from the port). 177 * 178 * @return true if busy, false if nothing waiting to send 179 */ 180 abstract public boolean isXmtBusy(); 181 182 /** 183 * Reset statistics (received message count, transmitted message count, 184 * received byte count). 185 */ 186 public void resetStatistics() { 187 receivedMsgCount = 0; 188 transmittedMsgCount = 0; 189 receivedByteCount = 0; 190 } 191 192 /** 193 * Clean up any resources, particularly threads. 194 * <p> 195 * The object can't be used after this. 196 */ 197 public void dispose() {} 198 199 /** 200 * Monitor the number of LocoNet messages received across the interface. 201 * This includes the messages this client has sent. 202 * 203 * @return the number of messages received 204 */ 205 public int getReceivedMsgCount() { 206 return receivedMsgCount; 207 } 208 protected int receivedMsgCount = 0; 209 210 /** 211 * Monitor the number of bytes in LocoNet messages received across the 212 * interface. This includes the bytes in messages this client has sent. 213 * 214 * @return the number of bytes received 215 */ 216 public int getReceivedByteCount() { 217 return receivedByteCount; 218 } 219 protected int receivedByteCount = 0; 220 221 /** 222 * Monitor the number of LocoNet messages transmitted across the interface. 223 * 224 * @return the number of messages transmitted 225 */ 226 public int getTransmittedMsgCount() { 227 return transmittedMsgCount; 228 } 229 protected int transmittedMsgCount = 0; 230 231 private static final Logger log = LoggerFactory.getLogger(LnTrafficController.class); 232 233}