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 Thread sourceThread; 031 032 // streams to share with user class 033 private DataOutputStream pout = null; // this is provided to classes who want to write to us 034 private DataInputStream pin = null; // this is provided to classes who want data from us 035 036 // internal ends of the pipes 037 private DataOutputStream outpipe = null; // feed pin 038 private DataInputStream inpipe = null; // feed pout 039 040 public SimulatorAdapter() { 041 super(new TamsSystemConnectionMemo()); 042 } 043 044 @Override 045 public String openPort(String portName, String appName) { 046 try { 047 PipedOutputStream tempPipeI = new ImmediatePipedOutputStream(); 048 pout = new DataOutputStream(tempPipeI); 049 inpipe = new DataInputStream(new PipedInputStream(tempPipeI)); 050 PipedOutputStream tempPipeO = new ImmediatePipedOutputStream(); 051 outpipe = new DataOutputStream(tempPipeO); 052 pin = new DataInputStream(new PipedInputStream(tempPipeO)); 053 } catch (java.io.IOException e) { 054 log.error("init (pipe): Exception: {}", e.toString()); 055 } 056 opened = true; 057 return null; // indicates OK return 058 } 059 060 /** 061 * Set up all of the other objects to simulate operation with a Tams command 062 * station. 063 */ 064 @Override 065 public void configure() { 066 TamsTrafficController tc = new TamsTrafficController(); 067 tc.connectPort(this); 068 this.getSystemConnectionMemo().setTamsTrafficController(tc); 069 tc.setAdapterMemo(this.getSystemConnectionMemo()); 070 071 this.getSystemConnectionMemo().configureManagers(); 072 //tc.setCabNumber(2); 073 074 // start the simulator 075 sourceThread = new Thread(this); 076 sourceThread.setName("Tams Simulator"); 077 sourceThread.setPriority(Thread.MIN_PRIORITY); 078 sourceThread.start(); 079 //tc.startThreads(); 080 } 081 082 // base class methods for the TamsPortController interface 083 084 @Override 085 public DataInputStream getInputStream() { 086 if (!opened || pin == null) { 087 log.error("getInputStream called before load(), stream not available"); 088 } 089 return pin; 090 } 091 092 @Override 093 public DataOutputStream getOutputStream() { 094 if (!opened || pout == null) { 095 log.error("getOutputStream called before load(), stream not available"); 096 } 097 return pout; 098 } 099 100 @Override 101 public boolean status() { 102 return opened; 103 } 104 105 /** 106 * {@inheritDoc} 107 */ 108 @Override 109 public String[] validBaudRates() { 110 log.debug("validBaudRates should not have been invoked"); 111 return new String[]{}; 112 } 113 114 /** 115 * {@inheritDoc} 116 */ 117 @Override 118 public int[] validBaudNumbers() { 119 return new int[]{}; 120 } 121 122 @Override 123 public String getCurrentBaudRate() { 124 return ""; 125 } 126 127 @Override 128 public String getCurrentPortName(){ 129 return ""; 130 } 131 132 @Override 133 public void run() { // start a new thread 134 // This thread has one task. It repeatedly reads from the input pipe 135 // and writes an appropriate response to the output pipe. This is the heart 136 // of the TAMS command station simulation. 137 // report status? 138 if (log.isInfoEnabled()) { 139 log.info("TAMS Simulator Started"); 140 } 141 while (true) { 142 try { 143 synchronized (this) { 144 wait(50); 145 } 146 } catch (InterruptedException e) { 147 log.debug("interrupted, ending"); 148 return; 149 } 150 TamsMessage m = readMessage(); 151 TamsReply r; 152 if (log.isDebugEnabled()) { 153 StringBuilder buf = new StringBuilder(); 154 if (m != null) { 155 for (int i = 0; i < m.getNumDataElements(); i++) { 156 buf.append(Integer.toHexString(0xFF & m.getElement(i))).append(" "); 157 } 158 } else { 159 buf.append("null message buffer"); 160 } 161 log.debug("Tams Simulator Thread received message: {}", buf ); 162 } 163 if (m != null) { 164 //if(m.isReplyExpected()){ 165 r = generateReply(m); 166 writeReply(r); 167 //} 168 if (log.isDebugEnabled()) { 169 StringBuilder buf = new StringBuilder(); 170 for (int i = 0; i < r.getNumDataElements(); i++) { 171 buf.append(Integer.toHexString(0xFF & r.getElement(i))).append(" "); 172 } 173 log.debug("Tams Simulator Thread sent reply: {}", buf ); 174 } 175 } 176 } 177 } 178 179 // readMessage reads one incoming message from the buffer 180 private TamsMessage readMessage() { 181 TamsMessage msg = null; 182 try { 183 if (inpipe.available() > 0) { 184 msg = loadChars(); 185 } 186 } catch (java.io.IOException e) { 187 188 } 189 return (msg); 190 } 191 192 /** 193 * Get characters from the input source. 194 * 195 * @return filled message 196 * @throws IOException when presented by the input source. 197 */ 198 private TamsMessage loadChars() throws java.io.IOException { 199 int nchars; 200 byte[] rcvBuffer = new byte[32]; 201 202 nchars = inpipe.read(rcvBuffer, 0, 32); 203 //log.debug("new message received"); 204 TamsMessage msg = new TamsMessage(nchars); 205 206 for (int i = 0; i < nchars; i++) { 207 msg.setElement(i, rcvBuffer[i] & 0xFF); 208 } 209 return msg; 210 } 211 212 // generateReply is the heart of the simulation. It translates an 213 // incoming TamsMessage into an outgoing TamsReply. 214 private TamsReply generateReply(TamsMessage m) { 215 TamsReply reply = new TamsReply(); 216 int i = 0; 217 log.debug("Rec {}", m.toString()); 218 if (m.toString().startsWith("xY")) { 219 reply.setElement(i++, 0x00); 220 } else if (m.toString().startsWith("xSR")) { 221 reply.setElement(i++, 0x53); 222 reply.setElement(i++, 0x52); 223 reply.setElement(i++, 0x20); 224 reply.setElement(i++, m.getElement(3)); 225 } else if (m.getElement(0) == 0x99) {// && m.getElement(1)==0x53 && m.getElement(2)=0x52 && m.getElement(3)==0x30){ 226 reply.setElement(i++, 0x55); 227 reply.setElement(i++, 0x55); 228 reply.setElement(i++, 0xAA); 229 reply.setElement(i++, 0xAA); 230 reply.setElement(i++, 0x00); 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 } 289 reply.setElement(i++, 0x0d); 290 reply.setElement(i++, 0x5d); 291 return reply; 292 } 293 294 private void writeReply(TamsReply r) { 295 if (r == null) { 296 return; 297 } 298 for (int i = 0; i < r.getNumDataElements(); i++) { 299 try { 300 outpipe.writeByte((byte) r.getElement(i)); 301 } catch (java.io.IOException ex) { 302 } 303 } 304 try { 305 outpipe.flush(); 306 } catch (java.io.IOException ex) { 307 } 308 } 309 310 private final static Logger log = LoggerFactory 311 .getLogger(SimulatorAdapter.class); 312 313}