001package jmri.jmrit.ussctc; 002 003import java.util.*; 004import jmri.*; 005/** 006 * Drive the code line communications on a USS CTC panel. 007 * <p> 008 * Primary interactions are with a group of {@link Station} objects 009 * that make up the panel. Can also work with external 010 * hardware via Turnout/Sensor interfaces. 011 * 012 * @author Bob Jacobsen Copyright (C) 2007, 2017 013 */ 014public class CodeLine { 015 016 /** 017 * Create and configure 018 * 019 * @param startIndicateTO Name for turnout that starts indication operations on the layout 020 * @param startSendTO Name for turnout that starts send operations on the layout 021 * @param output1TO Turnout name for 1st channel of code information 022 * @param output2TO Turnout name for 2nd channel of code information 023 * @param output3TO Turnout name for 3rd channel of code information 024 * @param output4TO Turnout name for 4th channel of code information 025 */ 026 public CodeLine(String startIndicateTO, String startSendTO, String output1TO, String output2TO, String output3TO, String output4TO) { 027 NamedBeanHandleManager hm = InstanceManager.getDefault(NamedBeanHandleManager.class); 028 TurnoutManager tm = InstanceManager.getDefault(TurnoutManager.class); 029 030 logMemory = InstanceManager.getDefault(MemoryManager.class).provideMemory( 031 Constants.commonNamePrefix+"CODELINE"+Constants.commonNameSuffix+"LOG"); // NOI18N 032 log.debug("log memory name is {}", logMemory.getSystemName()); // NOI18N 033 034 hStartIndicateTO = hm.getNamedBeanHandle(startIndicateTO, tm.provideTurnout(startIndicateTO)); 035 hStartSendTO = hm.getNamedBeanHandle(startSendTO, tm.provideTurnout(startSendTO)); 036 037 hOutput1TO = hm.getNamedBeanHandle(output1TO, tm.provideTurnout(output1TO)); 038 hOutput2TO = hm.getNamedBeanHandle(output2TO, tm.provideTurnout(output2TO)); 039 hOutput3TO = hm.getNamedBeanHandle(output3TO, tm.provideTurnout(output3TO)); 040 hOutput4TO = hm.getNamedBeanHandle(output4TO, tm.provideTurnout(output4TO)); 041 } 042 043 final Memory logMemory; 044 045 final NamedBeanHandle<Turnout> hStartIndicateTO; 046 final NamedBeanHandle<Turnout> hStartSendTO; 047 048 final NamedBeanHandle<Turnout> hOutput1TO; 049 final NamedBeanHandle<Turnout> hOutput2TO; 050 final NamedBeanHandle<Turnout> hOutput3TO; 051 final NamedBeanHandle<Turnout> hOutput4TO; 052 053 public static int START_PULSE_LENGTH = 500; // mSec 054 public static int CODE_SEND_DELAY = 2500; // mSec 055 public static int INTER_INDICATION_DELAY = 500; // mSec 056 057 volatile Deque<Station<?,?>> codeQueue = new ArrayDeque<>(); 058 volatile Deque<Station<?,?>> indicationQueue = new ArrayDeque<>(); 059 060 volatile boolean active = false; 061 062 synchronized void endAndCheckNext() { 063 if (!active) log.error("endAndCheckNext with active false"); 064 log.debug("active set false"); 065 active = false; 066 checkForWork(); 067 } 068 069 synchronized void checkForWork() { 070 log.debug("checkForWork with active == {}", active); 071 if (active) return; 072 log.debug("active set true"); 073 active = true; 074 075 // indications have priority over code sends 076 final Station<?,?> indicatorStation = indicationQueue.pollFirst(); 077 if (indicatorStation != null) { 078 // go inactive for just a bit before starting indication cycles 079 jmri.util.ThreadingUtil.runOnGUIDelayed( ()->{ 080 startSendIndication(indicatorStation); 081 }, INTER_INDICATION_DELAY); 082 return; 083 } 084 Station<?,?> codeStation = codeQueue.pollFirst(); 085 if (codeStation != null) { 086 startSendCode(codeStation); 087 return; 088 } 089 log.debug("active set false"); 090 active = false; 091 logMemory.setValue(""); 092 log.debug("CodeLine goes inactive"); // NOI18N 093 } 094 095 /** 096 * Request processing of an indication from the field 097 * @param station Station being addressed. 098 */ 099 synchronized void requestSendCode(Station<?,?> station) { 100 log.debug("requestSendCode queued from Station {}", station.getName()); 101 // remove if present 102 while (codeQueue.contains(station)) { 103 codeQueue.remove(station); 104 log.debug(" removed previous request"); 105 } 106 codeQueue.addLast(station); 107 checkForWork(); 108 } 109 110 void startSendCode(Station<?,?> station) { 111 final Station<?,?> s = station; 112 log.debug("CodeLine startSendCode - Tell hardware to start sending code"); // NOI18N 113 logMemory.setValue("Sending Code: Station "+station.getName()); // NOI18N 114 startSendExternalCodeLine(); 115 116 // Wait time for sequence complete, then proceed to end of code send 117 // ToDo: Allow an input to end this too 118 jmri.util.ThreadingUtil.runOnGUIDelayed( ()->{ 119 s.codeValueDelivered(); 120 // and see if anything else needs to be done 121 log.debug("end of codeValueDelivered"); // NOI18N 122 endAndCheckNext(); 123 }, CODE_SEND_DELAY); 124 } 125 126 void startSendExternalCodeLine() { 127 hStartSendTO.getBean().setCommandedState(Turnout.THROWN); 128 jmri.util.TimerUtil.schedule(new TimerTask() { 129 @Override 130 public void run() { 131 hStartSendTO.getBean().setCommandedState(Turnout.CLOSED); 132 } 133 }, START_PULSE_LENGTH); 134 } 135 136 @Override 137 public String toString() { 138 return "Codeline "+active; 139 } 140 /** 141 * Request processing of an indication from the field. 142 * @param station Station being addressed. 143 */ 144 synchronized void requestIndicationStart(Station<?,?> station) { 145 log.debug("requestIndicationStart queued from Station {}", station.getName()); 146 // remove if present 147 while (indicationQueue.contains(station)) { 148 indicationQueue.remove(station); 149 log.debug(" removed previous request"); 150 } 151 indicationQueue.addLast(station); 152 checkForWork(); 153 } 154 155 void startSendIndication(Station<?,?> station) { 156 final Station<?,?> s = station; 157 log.debug("CodeLine startSendIndication - process indication from field"); 158 159 // light code light and gather values 160 station.indicationStart(); 161 162 log.debug("Tell hardware to start sending indication"); 163 logMemory.setValue("Receiving Indication: Station "+station.getName()); // NOI18N 164 startIndicationExternalCodeLine(); 165 166 // Wait time for sequence complete, then proceed to end of indication send 167 // ToDo: Allow an input to end this too 168 jmri.util.ThreadingUtil.runOnGUIDelayed( ()->{ 169 log.debug("hardware delay done, receiving indication"); 170 s.indicationComplete(); 171 log.debug("end of indicationComplete"); 172 // and see if anything else needs to be done 173 endAndCheckNext(); 174 }, CODE_SEND_DELAY); 175 } 176 177 void startIndicationExternalCodeLine() { 178 hStartIndicateTO.getBean().setCommandedState(Turnout.THROWN); 179 jmri.util.TimerUtil.schedule(new TimerTask() { 180 @Override 181 public void run() { 182 hStartIndicateTO.getBean().setCommandedState(Turnout.CLOSED); 183 } 184 }, START_PULSE_LENGTH); 185 } 186 187 188 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CodeLine.class); 189}