001package jmri.jmrix.tams.simulator; 002 003import java.io.DataInputStream; 004import java.io.DataOutputStream; 005import java.io.IOException; 006import java.io.PipedInputStream; 007import java.io.PipedOutputStream; 008 009import jmri.jmrix.tams.TamsMessage; 010import jmri.jmrix.tams.TamsPortController; 011import jmri.jmrix.tams.TamsReply; 012import jmri.jmrix.tams.TamsSystemConnectionMemo; 013import jmri.jmrix.tams.TamsTrafficController; 014import jmri.util.ImmediatePipedOutputStream; 015import org.slf4j.Logger; 016import org.slf4j.LoggerFactory; 017 018/** 019 * Tams simulator. 020 * Derived from MRC Simulator 021 * 022 * @author Bob Jacobsen Copyright (C) 2001, 2002 023 * @author Paul Bender, Copyright (C) 2009 024 * @author Daniel Boudreau Copyright (C) 2010 025 * 026 */ 027public class SimulatorAdapter extends TamsPortController implements Runnable { 028 029 // private control members 030 private boolean opened = false; 031 private Thread sourceThread; 032 033 // streams to share with user class 034 private DataOutputStream pout = null; // this is provided to classes who want to write to us 035 private DataInputStream pin = null; // this is provided to classes who want data from us 036 037 // internal ends of the pipes 038 private DataOutputStream outpipe = null; // feed pin 039 private DataInputStream inpipe = null; // feed pout 040 041 public SimulatorAdapter() { 042 super(new TamsSystemConnectionMemo()); 043 } 044 045 @Override 046 public String openPort(String portName, String appName) { 047 try { 048 PipedOutputStream tempPipeI = new ImmediatePipedOutputStream(); 049 pout = new DataOutputStream(tempPipeI); 050 inpipe = new DataInputStream(new PipedInputStream(tempPipeI)); 051 PipedOutputStream tempPipeO = new ImmediatePipedOutputStream(); 052 outpipe = new DataOutputStream(tempPipeO); 053 pin = new DataInputStream(new PipedInputStream(tempPipeO)); 054 } catch (java.io.IOException e) { 055 log.error("init (pipe): Exception: {}", e.toString()); 056 } 057 opened = true; 058 return null; // indicates OK return 059 } 060 061 /** 062 * Set up all of the other objects to simulate operation with a Tams command 063 * station. 064 */ 065 @Override 066 public void configure() { 067 TamsTrafficController tc = new TamsTrafficController(); 068 tc.connectPort(this); 069 this.getSystemConnectionMemo().setTamsTrafficController(tc); 070 tc.setAdapterMemo(this.getSystemConnectionMemo()); 071 072 this.getSystemConnectionMemo().configureManagers(); 073 //tc.setCabNumber(2); 074 075 // start the simulator 076 sourceThread = new Thread(this); 077 sourceThread.setName("Tams Simulator"); 078 sourceThread.setPriority(Thread.MIN_PRIORITY); 079 sourceThread.start(); 080 //tc.startThreads(); 081 } 082 083 // base class methods for the TamsPortController interface 084 085 @Override 086 public DataInputStream getInputStream() { 087 if (!opened || pin == null) { 088 log.error("getInputStream called before load(), stream not available"); 089 } 090 return pin; 091 } 092 093 @Override 094 public DataOutputStream getOutputStream() { 095 if (!opened || pout == null) { 096 log.error("getOutputStream called before load(), stream not available"); 097 } 098 return pout; 099 } 100 101 @Override 102 public boolean status() { 103 return opened; 104 } 105 106 /** 107 * {@inheritDoc} 108 */ 109 @Override 110 public String[] validBaudRates() { 111 log.debug("validBaudRates should not have been invoked"); 112 return new String[]{}; 113 } 114 115 /** 116 * {@inheritDoc} 117 */ 118 @Override 119 public int[] validBaudNumbers() { 120 return new int[]{}; 121 } 122 123 @Override 124 public String getCurrentBaudRate() { 125 return ""; 126 } 127 128 @Override 129 public String getCurrentPortName(){ 130 return ""; 131 } 132 133 @Override 134 public void run() { // start a new thread 135 // This thread has one task. It repeatedly reads from the input pipe 136 // and writes an appropriate response to the output pipe. This is the heart 137 // of the TAMS command station simulation. 138 // report status? 139 if (log.isInfoEnabled()) { 140 log.info("TAMS Simulator Started"); 141 } 142 while (true) { 143 try { 144 synchronized (this) { 145 wait(50); 146 } 147 } catch (InterruptedException e) { 148 log.debug("interrupted, ending"); 149 return; 150 } 151 TamsMessage m = readMessage(); 152 TamsReply r; 153 if (log.isDebugEnabled()) { 154 StringBuilder buf = new StringBuilder(); 155 if (m != null) { 156 for (int i = 0; i < m.getNumDataElements(); i++) { 157 buf.append(Integer.toHexString(0xFF & m.getElement(i))).append(" "); 158 } 159 } else { 160 buf.append("null message buffer"); 161 } 162 log.debug("Tams Simulator Thread received message: {}", buf ); 163 } 164 if (m != null) { 165 //if(m.isReplyExpected()){ 166 r = generateReply(m); 167 writeReply(r); 168 //} 169 if (log.isDebugEnabled()) { 170 StringBuilder buf = new StringBuilder(); 171 for (int i = 0; i < r.getNumDataElements(); i++) { 172 buf.append(Integer.toHexString(0xFF & r.getElement(i))).append(" "); 173 } 174 log.debug("Tams Simulator Thread sent reply: {}", buf ); 175 } 176 } 177 } 178 } 179 180 // readMessage reads one incoming message from the buffer 181 private TamsMessage readMessage() { 182 TamsMessage msg = null; 183 try { 184 if (inpipe.available() > 0) { 185 msg = loadChars(); 186 } 187 } catch (java.io.IOException e) { 188 189 } 190 return (msg); 191 } 192 193 /** 194 * Get characters from the input source. 195 * 196 * @return filled message 197 * @throws IOException when presented by the input source. 198 */ 199 private TamsMessage loadChars() throws java.io.IOException { 200 int nchars; 201 byte[] rcvBuffer = new byte[32]; 202 203 nchars = inpipe.read(rcvBuffer, 0, 32); 204 //log.debug("new message received"); 205 TamsMessage msg = new TamsMessage(nchars); 206 207 for (int i = 0; i < nchars; i++) { 208 msg.setElement(i, rcvBuffer[i] & 0xFF); 209 } 210 return msg; 211 } 212 213 // generateReply is the heart of the simulation. It translates an 214 // incoming TamsMessage into an outgoing TamsReply. 215 private TamsReply generateReply(TamsMessage m) { 216 TamsReply reply = new TamsReply(); 217 int i = 0; 218 log.debug("Rec {}", m.toString()); 219 if (m.toString().startsWith("xY")) { 220 reply.setElement(i++, 0x00); 221 } else if (m.toString().startsWith("xSR")) { 222 reply.setElement(i++, 0x53); 223 reply.setElement(i++, 0x52); 224 reply.setElement(i++, 0x20); 225 reply.setElement(i++, m.getElement(3)); 226 } else if (m.getElement(0) == 0x99) {// && m.getElement(1)==0x53 && m.getElement(2)=0x52 && m.getElement(3)==0x30){ 227 reply.setElement(i++, 0x55); 228 reply.setElement(i++, 0x55); 229 reply.setElement(i++, 0xAA); 230 reply.setElement(i++, 0xAA); 231 reply.setElement(i++, 0x00); 232 reply.setElement(i++, 0x00); 233 reply.setElement(i++, 0x00); 234 reply.setElement(i++, 0x00); 235 reply.setElement(i++, 0x00); 236 reply.setElement(i++, 0x00); 237 reply.setElement(i++, 0x00); 238 reply.setElement(i++, 0x00); 239 reply.setElement(i++, 0x00); 240 reply.setElement(i++, 0x00); 241 reply.setElement(i++, 0x00); 242 reply.setElement(i++, 0x00); 243 reply.setElement(i++, 0x00); 244 reply.setElement(i++, 0x00); 245 reply.setElement(i++, 0x00); 246 reply.setElement(i++, 0x00); 247 reply.setElement(i++, 0x00); 248 reply.setElement(i++, 0x00); 249 reply.setElement(i++, 0x00); 250 reply.setElement(i++, 0x00); 251 reply.setElement(i++, 0x00); 252 reply.setElement(i++, 0x00); 253 reply.setElement(i++, 0x00); 254 reply.setElement(i++, 0x00); 255 reply.setElement(i++, 0x00); 256 reply.setElement(i++, 0x00); 257 reply.setElement(i++, 0x00); 258 reply.setElement(i++, 0x00); 259 reply.setElement(i++, 0x00); 260 reply.setElement(i++, 0x00); 261 reply.setElement(i++, 0x00); 262 reply.setElement(i++, 0x00); 263 reply.setElement(i++, 0x00); 264 reply.setElement(i++, 0x00); 265 reply.setElement(i++, 0x00); 266 reply.setElement(i++, 0x00); 267 reply.setElement(i++, 0x00); 268 reply.setElement(i++, 0x00); 269 reply.setElement(i++, 0x00); 270 reply.setElement(i++, 0x00); 271 reply.setElement(i++, 0x00); 272 reply.setElement(i++, 0x00); 273 reply.setElement(i++, 0x00); 274 reply.setElement(i++, 0x00); 275 reply.setElement(i++, 0x00); 276 reply.setElement(i++, 0x00); 277 reply.setElement(i++, 0x00); 278 reply.setElement(i++, 0x00); 279 reply.setElement(i++, 0x00); 280 reply.setElement(i++, 0x00); 281 reply.setElement(i++, 0x00); 282 reply.setElement(i++, 0x00); 283 reply.setElement(i++, 0x00); 284 reply.setElement(i++, 0x00); 285 reply.setElement(i++, 0x00); 286 reply.setElement(i++, 0x00); 287 reply.setElement(i++, 0x00); 288 reply.setElement(i++, 0x00); 289 } 290 reply.setElement(i++, 0x0d); 291 reply.setElement(i++, 0x5d); 292 return reply; 293 } 294 295 private void writeReply(TamsReply r) { 296 if (r == null) { 297 return; 298 } 299 for (int i = 0; i < r.getNumDataElements(); i++) { 300 try { 301 outpipe.writeByte((byte) r.getElement(i)); 302 } catch (java.io.IOException ex) { 303 } 304 } 305 try { 306 outpipe.flush(); 307 } catch (java.io.IOException ex) { 308 } 309 } 310 311 private final static Logger log = LoggerFactory 312 .getLogger(SimulatorAdapter.class); 313 314}