001package jmri.jmrix.direct; 002 003import java.io.DataInputStream; 004import java.io.IOException; 005import java.io.OutputStream; 006import jmri.jmrix.AbstractSerialPortController; 007import org.slf4j.Logger; 008import org.slf4j.LoggerFactory; 009 010/** 011 * Converts Stream-based I/O to/from NMRA packets and controls sending to the 012 * direct interface. 013 * <p> 014 * This is much simpler than many other "TrafficHandler" classes, because 015 * <ul> 016 * <li>It's not handling mode information, or even any information back from the 017 * device; it's just sending. 018 * <li>It can work with the direct packets. 019 * </ul> 020 * This actually bears more similarity to a pure implementation of the 021 * CommandStation interface, which is where the real guts of it is. In 022 * particular, note that transmission is not a threaded operation. 023 * 024 * @author Bob Jacobsen Copyright (C) 2001 025 */ 026public class TrafficController implements jmri.CommandStation { 027 028 /** 029 * Create a new Direct TrafficController instance. 030 * @param memo system connection. 031 */ 032 public TrafficController(DirectSystemConnectionMemo memo) { 033 super(); 034 _memo = memo; 035 } 036 037 /** 038 * Send a specific packet to the rails. 039 * 040 * @param packet Byte array representing the packet, including the 041 * error-correction byte. Must not be null. 042 * @param repeats Number of times to repeat the transmission, but is ignored 043 * in the current implementation 044 */ 045 @Override 046 public boolean sendPacket(byte[] packet, int repeats) { 047 048 if (repeats != 1) { 049 log.warn("Only single transmissions currently available"); 050 } 051 052 // convert packet (in byte form) into bits 053 int[] msgAsInt = MakePacket.createStream(packet); 054 055 if (msgAsInt[0] == 0) { 056 // failed to make packet 057 log.error("Failed to convert packet to transmitable form: {}", java.util.Arrays.toString(packet)); 058 return false; 059 } 060 061 // have to recopy & reformat, as there's only a byte write in Java 1 062 // note that msgAsInt has 0th byte containing length still 063 byte[] msg = new byte[msgAsInt[0]]; 064 for (int i = 0; i < msg.length; i++) { 065 msg[i] = (byte) (msgAsInt[i + 1] & 0xFF); 066 } 067 068 // and stream the resulting byte array 069 try { 070 if (ostream != null) { 071 if (log.isDebugEnabled()) { 072 StringBuilder f = new StringBuilder(); 073 for (int i = 0; i < msg.length; i++) { 074 f.append(Integer.toHexString(0xFF & msg[i])).append(" "); 075 } 076 log.debug("write message: {}", f); 077 } 078 ostream.write(msg); 079 } else { 080 // no stream connected 081 log.warn("sendMessage: no connection established"); 082 } 083 } catch (IOException e) { 084 log.warn("sendMessage: Exception: {}", e.getMessage()); 085 } 086 return true; 087 } 088 089 // methods to connect/disconnect to a source of data in an AbstractSerialPortController 090 private DirectSystemConnectionMemo _memo = null; 091 private AbstractSerialPortController controller = null; 092 093 public boolean status() { 094 return (ostream != null && istream != null); 095 } 096 097 /** 098 * Make connection to existing PortController object. 099 * 100 * @param p the controller to connect to 101 */ 102 public void connectPort(AbstractSerialPortController p) { 103 istream = p.getInputStream(); 104 ostream = p.getOutputStream(); 105 if (controller != null) { 106 log.warn("connectPort: connect called while connected"); 107 } else { 108 log.debug("connectPort invoked"); 109 } 110 controller = p; 111 } 112 113 /** 114 * Break connection to existing PortController object. Once broken, attempts 115 * to send via "message" member will fail. 116 * 117 * @param p the controller to disconnect from 118 */ 119 public void disconnectPort(AbstractSerialPortController p) { 120 istream = null; 121 ostream = null; 122 if (controller != p) { 123 log.warn("disconnectPort: disconnect called from non-connected AbstractPortController"); 124 } 125 controller = null; 126 } 127 128 // data members to hold the streams 129 protected DataInputStream istream = null; 130 protected OutputStream ostream = null; 131 132 @Override 133 public String getUserName() { 134 return _memo.getUserName(); 135 } 136 137 @Override 138 public String getSystemPrefix() { 139 return _memo.getSystemPrefix(); 140 } 141 142 private final static Logger log = LoggerFactory.getLogger(TrafficController.class); 143 144}