001package jmri.jmrix.loconet.streamport; 002 003import jmri.jmrix.loconet.LnPacketizer; 004import jmri.jmrix.loconet.LocoNetSystemConnectionMemo; 005import org.slf4j.Logger; 006import org.slf4j.LoggerFactory; 007 008/** 009 * Converts Stream-based I/O to/from LocoNet messages. The "LocoNetInterface" 010 * side sends/receives LocoNetMessage objects. The connection to a 011 * LnPortController is via a pair of *Streams, which then carry sequences of 012 * characters for transmission. 013 * <p> 014 * Messages come to this via the main GUI thread, and are forwarded back to 015 * listeners in that same thread. Reception and transmission are handled in 016 * dedicated threads by RcvHandler and XmtHandler objects. Those are internal 017 * classes defined here. The thread priorities are: 018 * <ul> 019 * <li> RcvHandler - at highest available priority 020 * <li> XmtHandler - down one, which is assumed to be above the GUI 021 * <li> (everything else) 022 * </ul> 023 * Some of the message formats used in this class are Copyright Digitrax, Inc. 024 * and used with permission as part of the JMRI project. That permission does 025 * not extend to uses in other software products. If you wish to use this code, 026 * algorithm or these message formats outside of JMRI, please contact Digitrax 027 * Inc for separate permission. 028 * 029 * @author Bob Jacobsen Copyright (C) 2001 030 */ 031public class LnStreamPortPacketizer extends LnPacketizer { 032 033 public LnStreamPortPacketizer(LocoNetSystemConnectionMemo m) { 034 super(m); 035 } 036 037 public LnStreamPortController streamController = null; 038 039 @Override 040 public boolean isXmtBusy() { 041 if (streamController == null) { 042 return false; 043 } 044 return true; 045 } 046 047 /** 048 * Make connection to existing LnPortController object. 049 * 050 * @param p Port controller to connect to. Save this for a later disconnect 051 * call 052 */ 053 public void connectPort(LnStreamPortController p) { 054 istream = p.getInputStream(); 055 ostream = p.getOutputStream(); 056 if (controller != null) { 057 log.warn("connectPort: connect called while connected"); 058 } 059 streamController = p; 060 } 061 062 /** 063 * Break connection to existing LnPortController object. Once broken, 064 * attempts to send via "message" member will fail. 065 * 066 * @param p previously connected port 067 */ 068 public void disconnectPort(LnStreamPortController p) { 069 istream = null; 070 ostream = null; 071 if (streamController != p) { 072 log.warn("disconnectPort: disconnect called from non-connected LnStreamPortController"); 073 } 074 streamController = null; 075 } 076 077 /** 078 * Captive class to handle transmission 079 */ 080 class XmtHandler implements Runnable { 081 082 @Override 083 public void run() { 084 085 while (!threadStopRequest) { // loop until asked to stop 086 // any input? 087 try { 088 // get content; blocks until present 089 log.trace("check for input"); // NOI18N 090 091 byte msg[] = xmtList.take(); 092 093 // input - now send 094 try { 095 if (ostream != null) { 096 if (!streamController.okToSend()) { 097 log.debug("LocoNet port not ready to receive"); // NOI18N 098 } 099 log.debug("start write to stream: {}", jmri.util.StringUtil.hexStringFromBytes(msg)); // NOI18N 100 ostream.write(msg); 101 ostream.flush(); 102 log.trace("end write to stream: {}", jmri.util.StringUtil.hexStringFromBytes(msg)); // NOI18N 103 messageTransmitted(msg); 104 } else { 105 // no stream connected 106 log.warn("sendLocoNetMessage: no connection established"); // NOI18N 107 } 108 } catch (java.io.IOException e) { 109 log.warn("sendLocoNetMessage: IOException: {}", e.toString()); // NOI18N 110 } 111 } catch (InterruptedException ie) { 112 return; // ending the thread 113 } 114 } 115 } 116 } 117 118 /** 119 * Invoked at startup to start the threads needed here. 120 */ 121 @Override 122 public void startThreads() { 123 int priority = Thread.currentThread().getPriority(); 124 log.debug("startThreads current priority = {} max available = " + Thread.MAX_PRIORITY + " default = " + Thread.NORM_PRIORITY + " min available = " + Thread.MIN_PRIORITY, priority); // NOI18N 125 126 // make sure that the xmt priority is no lower than the current priority 127 int xmtpriority = (Thread.MAX_PRIORITY - 1 > priority ? Thread.MAX_PRIORITY - 1 : Thread.MAX_PRIORITY); 128 // start the XmtHandler in a thread of its own 129 if (xmtHandler == null) { 130 xmtHandler = new XmtHandler(); 131 } 132 xmtThread = jmri.util.ThreadingUtil.newThread(xmtHandler, "LocoNet transmit handler"); // NOI18N 133 log.debug("Xmt thread starts at priority {}", xmtpriority); // NOI18N 134 xmtThread.setDaemon(true); 135 xmtThread.setPriority(Thread.MAX_PRIORITY - 1); 136 xmtThread.start(); 137 138 // start the RcvHandler in a thread of its own 139 if (rcvHandler == null) { 140 rcvHandler = new RcvHandler(this); 141 } 142 rcvThread = jmri.util.ThreadingUtil.newThread(rcvHandler, "LocoNet receive handler"); // NOI18N 143 rcvThread.setDaemon(true); 144 rcvThread.setPriority(Thread.MAX_PRIORITY); 145 rcvThread.start(); 146 } 147 148 private static final Logger log = LoggerFactory.getLogger(LnStreamPortPacketizer.class); 149 150}