001package jmri.jmrit.logix; 002 003import java.awt.event.ActionEvent; 004import java.text.NumberFormat; 005import java.util.ArrayList; 006import java.util.List; 007import java.util.ListIterator; 008 009import javax.annotation.CheckForNull; 010import javax.annotation.Nonnull; 011 012import javax.swing.Box; 013import javax.swing.BoxLayout; 014import javax.swing.ButtonGroup; 015import javax.swing.JButton; 016import javax.swing.JCheckBox; 017import javax.swing.JLabel; 018import javax.swing.JMenuBar; 019import javax.swing.JPanel; 020import javax.swing.JRadioButton; 021import javax.swing.JSpinner; 022import javax.swing.JTextField; 023import javax.swing.SpinnerNumberModel; 024 025import jmri.JmriException; 026import jmri.SpeedStepMode; 027import jmri.jmrit.logix.ThrottleSetting.Command; 028import jmri.jmrit.logix.ThrottleSetting.ValueType; 029import jmri.util.swing.JmriJOptionPane; 030 031/** 032 * Frame for defining and launching an entry/exit warrant. An NX warrant is a 033 * warrant that can be defined on the run without a pre-recorded learn mode 034 * session using a set script for ramping startup and stop throttle settings. 035 * <p> 036 * The route can be defined in a form or by mouse clicking on the OBlock 037 * IndicatorTrack icons. 038 * <br> 039 * <hr> 040 * This file is part of JMRI. 041 * <p> 042 * JMRI is free software; you can redistribute it and/or modify it under the 043 * terms of version 2 of the GNU General Public License as published by the Free 044 * Software Foundation. See the "COPYING" file for a copy of this license. 045 * <p> 046 * JMRI is distributed in the hope that it will be useful, but WITHOUT ANY 047 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 048 * A PARTICULAR PURPOSE. See the GNU General Public License for more details. 049 * 050 * @author Pete Cressman Copyright (C) 2009, 2010, 2015 051 */ 052public class NXFrame extends WarrantRoute { 053 054 private float _maxThrottle = 0.0f; 055 private float _startDist; // mm start distance to portal 056 private float _stopDist; // mm stop distance from portal 057 058 private final JTextField _maxThrottleBox = new JTextField(6); 059 private final JTextField _maxSpeedBox = new JTextField(6); 060 private final JLabel _maxSpeedBoxLabel = new JLabel(Bundle.getMessage("scaleSpeed")); 061 062 private final JTextField _originDist = new JTextField(6); 063 private DisplayButton _originUnits; 064 private final JTextField _destDist = new JTextField(6); 065 private DisplayButton _destUnits; 066 private final JSpinner _timeIncre = new JSpinner(new SpinnerNumberModel(750, 200, 9000, 1)); 067 private final JTextField _rampIncre = new JTextField(6); 068 private final JRadioButton _forward = new JRadioButton(); 069 private final JRadioButton _reverse = new JRadioButton(); 070 private final JCheckBox _noRamp = new JCheckBox(); 071 private final JCheckBox _noSound = new JCheckBox(); 072 private final JCheckBox _stageEStop = new JCheckBox(); 073 private final JCheckBox _shareRouteBox = new JCheckBox(); 074 private final JCheckBox _haltStartBox = new JCheckBox(); 075 private final JCheckBox _addTracker = new JCheckBox(); 076 private final JRadioButton _runAuto = new JRadioButton(Bundle.getMessage("RunAuto")); 077 private final JRadioButton _runManual = new JRadioButton(Bundle.getMessage("RunManual")); 078 079 private JPanel _routePanel = new JPanel(); 080 private JPanel _autoRunPanel; 081 private final JPanel __trainHolder = new JPanel(); 082 private JPanel _switchPanel; 083 private JPanel _trainPanel; 084 085 protected NXFrame() { 086 super(); 087 init(); 088 } 089 090 private void init() { 091 log.debug("newInstance"); 092 makeMenus(); 093 094 _routePanel = new JPanel(); 095 _routePanel.setLayout(new BoxLayout(_routePanel, BoxLayout.PAGE_AXIS)); 096 _routePanel.add(Box.createVerticalGlue()); 097 _routePanel.add(makeBlockPanels(true)); 098 099 _forward.setSelected(true); 100 _speedUtil.setIsForward(true); 101 _stageEStop.setSelected(false); 102 _haltStartBox.setSelected(false); 103 _runAuto.setSelected(true); 104 105 _autoRunPanel = makeAutoRunPanel(); 106 _switchPanel = makeSwitchPanel(); 107 _maxSpeedBox.setEnabled(false); 108 109 JPanel mainPanel = new JPanel(); 110 mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.PAGE_AXIS)); 111 mainPanel.add(_routePanel); 112 getContentPane().add(mainPanel); 113 114 if (_maxThrottle <= 0.1f) { 115 _maxThrottle = WarrantPreferences.getDefault().getThrottleScale()*100; 116 } 117 _maxThrottleBox.setText(NumberFormat.getNumberInstance().format(_maxThrottle)); 118 maxThrottleEventAction(); 119 120 addWindowListener(new java.awt.event.WindowAdapter() { 121 @Override 122 public void windowClosing(java.awt.event.WindowEvent e) { 123 WarrantTableAction.getDefault().closeNXFrame(); 124 } 125 }); 126 setAlwaysOnTop(true); 127 setVisible(true); 128 pack(); 129 } 130 131 protected boolean isRouteSeaching() { 132 return _routePanel.isVisible(); 133 } 134 135 private void setPanel() { 136 __trainHolder.add(_trainPanel); 137 } 138 private void setPanel(JPanel p) { 139 JPanel con = (JPanel)getContentPane().getComponent(0); 140 con.removeAll(); 141 con.add(p); 142 con.add(_switchPanel); 143 pack(); 144 } 145 146 private JPanel makeSwitchPanel() { 147 ButtonGroup bg = new ButtonGroup(); 148 bg.add(_runAuto); 149 bg.add(_runManual); 150 _runAuto.addActionListener((ActionEvent event) -> { 151 setPanel(); 152 setPanel(_autoRunPanel); 153 }); 154 _runManual.addActionListener((ActionEvent event) -> { 155 setPanel(_trainPanel); 156 _stageEStop.setSelected(false); 157 _shareRouteBox.setSelected(false); 158 _haltStartBox.setSelected(false); 159 _addTracker.setSelected(false); 160 }); 161 JPanel pp = new JPanel(); 162 pp.setLayout(new BoxLayout(pp, BoxLayout.LINE_AXIS)); 163 pp.add(Box.createHorizontalGlue()); 164 pp.add(_runAuto); 165 pp.add(Box.createHorizontalStrut(STRUT_SIZE)); 166 pp.add(_runManual); 167 pp.add(Box.createHorizontalGlue()); 168 169 JPanel p = new JPanel(); 170 p.add(Box.createGlue()); 171 JButton button = new JButton(Bundle.getMessage("ButtonRoute")); 172 button.addActionListener((ActionEvent e) -> { 173 clearTempWarrant(); 174 JPanel con = (JPanel)getContentPane().getComponent(0); 175 con.removeAll(); 176 con.add(_routePanel); 177 pack(); 178 }); 179 p.add(button); 180 p.add(Box.createHorizontalStrut(2 * STRUT_SIZE)); 181 button = new JButton(Bundle.getMessage("ButtonRunNX")); 182 button.addActionListener((ActionEvent e) -> { 183 clearTempWarrant(); 184 makeAndRunWarrant(); 185 }); 186 p.add(button); 187 p.add(Box.createHorizontalStrut(2 * STRUT_SIZE)); 188 button = new JButton(Bundle.getMessage("ButtonCancel")); 189 button.addActionListener((ActionEvent e) -> WarrantTableAction.getDefault().closeNXFrame()); 190 p.add(button); 191 p.add(Box.createGlue()); 192 193 JPanel panel = new JPanel(); 194 panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS)); 195 panel.add(pp); 196 panel.add(p); 197 return panel; 198 } 199 200 @Override 201 protected void maxThrottleEventAction() { 202 NumberFormat formatter = NumberFormat.getNumberInstance(); 203 float num; 204 try { 205 num = formatter.parse(_maxThrottleBox.getText()).floatValue(); 206 num = Math.min(100.0f, Math.max(num, 0.f)); 207 _maxThrottleBox.setText(formatter.format(num)); 208 } catch (java.text.ParseException pe) { 209 _maxThrottleBox.setText(null); 210 _maxSpeedBox.setText(null); 211 return; 212 } 213 float speed = _speedUtil.getTrackSpeed(num/100); // returns mm/ms (meters/sec) 214 switch(_displayPref) { 215 case MPH: 216 // Convert meters/sec to scale miles/hr 217 _maxSpeedBox.setText(formatter.format(speed * _scale * 2.2369363f)); 218 break; 219 case KPH: 220 // Convert meters/sec to scale kilometers/hr 221 _maxSpeedBox.setText(formatter.format(speed * _scale * 3.6f)); 222 break; 223 case MMPS: 224 // Convert meters/sec to millimeters/sec 225 _maxSpeedBox.setText(formatter.format(speed * 1000)); // mm/sec 226 break; 227 case INPS: 228 default: 229 // Convert meters/sec to inchec/sec 230 _maxSpeedBox.setText(formatter.format(speed * 39.37f)); // in/sec 231 } 232 } 233 234 private void unitsEventAction(@Nonnull JButton button, JTextField field) { 235 try { 236 getDistance(_originDist, _orders.get(0)); 237 getDistance(_destDist, _orders.get(_orders.size()-1)); 238 } catch (JmriException je) { 239 JmriJOptionPane.showMessageDialog(this, je.getMessage(), 240 Bundle.getMessage("WarningTitle"), JmriJOptionPane.WARNING_MESSAGE); 241 return; 242 } 243 if (button.getText().equals(Display.IN.toString())) { 244 _units = Display.CM; 245 } else { 246 _units = Display.IN; 247 } 248 setFieldText(_originUnits, _originDist); 249 setFieldText(_destUnits, _destDist); 250 } 251 // convert to units change 252 private void setFieldText(@Nonnull JButton button, @Nonnull JTextField field) { 253 NumberFormat formatter = NumberFormat.getNumberInstance(); 254 formatter.setMaximumFractionDigits(2); 255 float num = 0; 256 try { 257 num = formatter.parse(field.getText()).floatValue(); 258 } catch (java.text.ParseException pe) { 259 // errors reported later 260 } 261 if (_units.equals(Display.IN)) { 262 num *= 0.393701f; 263 } else { 264 num *= 2.54f; 265 } 266 button.setText(_units.toString()); 267 field.setText(formatter.format(num)); 268 } 269 270 private JPanel makeAutoRunPanel() { 271 JPanel p1 = new JPanel(); 272 p1.setLayout(new BoxLayout(p1, BoxLayout.PAGE_AXIS)); 273 274 DisplayButton speedUnitsButton = new DisplayButton(_displayPref); 275 _originUnits = new DisplayButton(_units); 276 _destUnits = new DisplayButton(_units); 277 278 _maxThrottleBox.addActionListener((ActionEvent evt)-> maxThrottleEventAction()); 279 280 _maxSpeedBox.addActionListener((ActionEvent evt)-> { 281 NumberFormat formatter = NumberFormat.getNumberInstance(); 282 formatter.setMaximumFractionDigits(2); 283 float num; 284 try { 285 num = formatter.parse(_maxSpeedBox.getText()).floatValue(); 286 } catch (java.text.ParseException pe) { 287 _maxSpeedBox.setText(""); 288 return; 289 } 290 if (num < 0) { 291 _maxSpeedBox.setText(formatter.format(0)); 292 _maxThrottleBox.setText(formatter.format(0)); 293 return; 294 } 295 // maxSpeed is speed at full throttle in mm/sec 296 float maxSpeed = _speedUtil.getTrackSpeed(1); // mm/ms, i.e. m/s 297 // maximum number is maxSpeed when converted to selected units 298 float maxNum; 299 // convert to display units. Note real world speed is converted to scaled world speed 300 // display label changes "Scale speed" to "Track Speed" accordingly 301 switch (_displayPref) { 302 case MPH: 303 maxNum = maxSpeed * 2.2369363f *_scale; // convert meters/sec to miles/hr 304 break; 305 case KPH: 306 maxNum = maxSpeed * 3.6f * _scale; // convert meters/sec to to kilometers/hr 307 break; 308 case MMPS: 309 maxNum = maxSpeed * 1000; // convert meters/sec to milimeters/sec 310 break; 311 default: 312 maxNum = maxSpeed * 39.37f; // convert meters/sec to inches/sec 313 break; 314 } 315 if (num > maxNum) { 316 String name = _speedUtil.getRosterId(); 317 if (name == null || name.charAt(0) == '$') { 318 name = getTrainName(); 319 if (name == null || name.isEmpty()) { 320 name = Bundle.getMessage("Unknown"); 321 } 322 } 323 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("maxSpeedLimit", 324 name, formatter.format(maxNum), speedUnitsButton.getText()), 325 Bundle.getMessage("MessageTitle"), JmriJOptionPane.INFORMATION_MESSAGE); 326 _maxSpeedBox.setText(formatter.format(maxNum)); 327 _maxThrottleBox.setText(formatter.format(100)); 328 return; 329 } 330 // convert to display num in selected units to track speed in meters/sec (mm/ms) 331 // reciprocal of above 332 switch (_displayPref) { 333 case MPH: 334 num = num * 0.44704f / _scale; // convert scale miles/hr to mm/msec 335 break; 336 case KPH: 337 num = num * 0.277778f / _scale; // convert scale kilometers/hr to mm/msec 338 break; 339 case MMPS: 340 num /= 1000; // convert mm/sec to mm/msec 341 break; 342 default: 343 num /= 39.37f; // convert inches/sec to mm/msec 344 break; 345 } 346 // get throttla setting and display as percent full throttle. 347 float throttle = _speedUtil.getThrottleSettingForSpeed(num)*100; 348 _maxThrottleBox.setText(formatter.format(throttle)); 349 }); 350 351 // User makes a choice for their desired units (_displayPref) to show max speed 352 speedUnitsButton.addActionListener((ActionEvent evt)-> { 353 NumberFormat formatter = NumberFormat.getNumberInstance(); 354 float num; 355 try { 356 num = formatter.parse(_maxSpeedBox.getText()).floatValue(); 357 } catch (java.text.ParseException pe) { 358 _maxSpeedBox.setText(null); 359 return; 360 } 361 // display preference for units cycles through 4 choices 362 // convert old choice to new 363 switch (_displayPref) { 364 case MPH: 365 _displayPref = Display.KPH; 366 _maxSpeedBox.setText(formatter.format(num * 1.60934f)); // miles/hr to km/hr 367 break; 368 case KPH: 369 _displayPref = Display.MMPS; 370 _maxSpeedBox.setText(formatter.format(num * 0277.778f / _scale)); // scale km/hr to mm/sec 371 _maxSpeedBoxLabel.setText(Bundle.getMessage("trackSpeed")); 372 break; 373 case MMPS: 374 _displayPref = Display.INPS; 375 _maxSpeedBox.setText(formatter.format(num * 0.03937f)); // mm/sec to in/sec 376 break; 377 default: 378 _displayPref = Display.MPH; 379 _maxSpeedBox.setText(formatter.format(num * 0.056818f * _scale)); // inches/sec to scale miles/hr 380 _maxSpeedBoxLabel.setText(Bundle.getMessage("scaleSpeed")); 381 break; 382 } 383 // display label changes "Scale speed" to "Track Speed" accordingly 384 speedUnitsButton.setDisplayPref(_displayPref); 385 }); 386 387 p1.add(makeTextAndButtonPanel(_maxThrottleBox, new JLabel(Bundle.getMessage("percent")), 388 new JLabel(Bundle.getMessage("MaxSpeed")), "ToolTipPercentThrottle")); 389 p1.add(makeTextAndButtonPanel(_maxSpeedBox, speedUnitsButton, 390 _maxSpeedBoxLabel, "ToolTipScaleSpeed")); 391 392 _originUnits.addActionListener((ActionEvent evt)-> 393 unitsEventAction(_originUnits, _originDist)); 394 _destUnits.addActionListener((ActionEvent evt)-> 395 unitsEventAction(_destUnits, _destDist)); 396 397 p1.add(makeTextAndButtonPanel(_originDist, _originUnits, 398 new JLabel(Bundle.getMessage("startDistance")), "ToolTipStartDistance")); 399 p1.add(makeTextAndButtonPanel(_destDist, _destUnits, 400 new JLabel(Bundle.getMessage("stopDistance")), "ToolTipStopDistance")); 401 p1.add(WarrantPreferencesPanel.timeIncrementPanel(false, _timeIncre)); 402 p1.add(WarrantPreferencesPanel.throttleIncrementPanel(false, _rampIncre)); 403 _rampIncre.addActionListener((ActionEvent e)->{ 404 String text = _rampIncre.getText(); 405 boolean showdialog; 406 try { 407 float incr = NumberFormat.getNumberInstance().parse(text).floatValue(); 408 showdialog = (incr < 0.5f || incr > 25f); 409 } catch (java.text.ParseException pe) { 410 showdialog = true; 411 } 412 if (showdialog) { 413 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("rampIncrWarning", text), 414 Bundle.getMessage("WarningTitle"), JmriJOptionPane.WARNING_MESSAGE); 415 } 416 }); 417 ButtonGroup bg = new ButtonGroup(); 418 bg.add(_forward); 419 bg.add(_reverse); 420 JPanel pp = new JPanel(); 421 pp.setLayout(new BoxLayout(pp, BoxLayout.LINE_AXIS)); 422 pp.add(Box.createHorizontalGlue()); 423 pp.add(makeTextBoxPanel(false, _forward, "forward", null)); 424 pp.add(makeTextBoxPanel(false, _reverse, "reverse", null)); 425 pp.add(Box.createHorizontalGlue()); 426 p1.add(pp); 427 428 __trainHolder.setLayout(new BoxLayout(__trainHolder, BoxLayout.PAGE_AXIS)); 429 _trainPanel = makeTrainIdPanel(null); 430 __trainHolder.add(_trainPanel); 431 432 JPanel p2 = new JPanel(); 433 p2.setLayout(new BoxLayout(p2, BoxLayout.PAGE_AXIS)); 434 p2.add(__trainHolder); 435 p2.add(makeTextBoxPanel(_noRamp, "NoRamping", "ToolTipNoRamping")); 436 p2.add(makeTextBoxPanel(_noSound, "NoSound", "ToolTipNoSound")); 437 p2.add(makeTextBoxPanel(_stageEStop, "StageEStop", null)); 438 p2.add(makeTextBoxPanel(_haltStartBox, "HaltAtStart", null)); 439 p2.add(makeTextBoxPanel(_shareRouteBox, "ShareRoute", "ToolTipShareRoute")); 440 p2.add(makeTextBoxPanel(_addTracker, "AddTracker", "ToolTipAddTracker")); 441 442 443 JPanel autoRunPanel = new JPanel(); 444 autoRunPanel.setLayout(new BoxLayout(autoRunPanel, BoxLayout.PAGE_AXIS)); 445 JPanel ppp = new JPanel(); 446 ppp.setLayout(new BoxLayout(ppp, BoxLayout.LINE_AXIS)); 447 ppp.add(Box.createHorizontalStrut(STRUT_SIZE)); 448 ppp.add(p1); 449 ppp.add(Box.createHorizontalGlue()); 450 ppp.add(p2); 451 ppp.add(Box.createHorizontalStrut(STRUT_SIZE)); 452 autoRunPanel.add(ppp); 453 454 _forward.addActionListener((ActionEvent evt)-> maxThrottleEventAction()); 455 _reverse.addActionListener((ActionEvent evt)-> maxThrottleEventAction()); 456 457 return autoRunPanel; 458 } 459 460 private void updateAutoRunPanel() { 461 _startDist = getPathLength(_orders.get(0)) * 0.4f; 462 _stopDist = getPathLength(_orders.get(_orders.size()-1)) * 0.6f; 463 NumberFormat formatter = NumberFormat.getNumberInstance(); 464 if (_units.equals(Display.IN)) { 465 // convert millimeters to inches 466 _originDist.setText(formatter.format(_startDist * 0.0393701)); 467 _destDist.setText(formatter.format(_stopDist * 0.0393701)); 468 } else { 469 // convert millimeters to centimeters 470 _originDist.setText(formatter.format(_startDist / 10)); 471 _destDist.setText(formatter.format(_stopDist / 10)); 472 } 473 _autoRunPanel.repaint(); 474 } 475 476 private void makeMenus() { 477 setTitle(Bundle.getMessage("AutoWarrant")); 478 JMenuBar menuBar = new JMenuBar(); 479 setJMenuBar(menuBar); 480 addHelpMenu("package.jmri.jmrit.logix.NXWarrant", true); 481 } 482 483 @Override 484 public void propertyChange(java.beans.PropertyChangeEvent e) { 485 String property = e.getPropertyName(); 486 log.trace("propertyChange \"{}\" old= {} new= {} source= {}",property, 487 e.getOldValue(), e.getNewValue(), e.getSource().getClass().getName()); 488 if (property.equals("DnDrop")) { 489 doAction(e.getSource()); 490 } 491 } 492 493 /** 494 * Called by {@link jmri.jmrit.logix.RouteFinder#run()}. If all goes well, 495 * WarrantTableFrame.runTrain(warrant) will run the warrant 496 * 497 * @param orders list of block orders 498 */ 499 @Override 500 protected void selectedRoute(ArrayList<BlockOrder> orders) { 501 JPanel con = (JPanel)getContentPane().getComponent(0); 502 con.removeAll(); 503 if (_runAuto.isSelected()) { 504 con.add(_autoRunPanel); 505 } else { 506 con.add(_trainPanel); 507 } 508 con.add(_switchPanel); 509 updateAutoRunPanel(); 510 pack(); 511 } 512 513 private void makeAndRunWarrant() { 514 String msg = getBoxData(); 515 if (msg == null) { 516 msg = checkLocoAddress(); 517 } 518 if (msg != null) { 519 JmriJOptionPane.showMessageDialog(this, msg, 520 Bundle.getMessage("WarningTitle"), JmriJOptionPane.WARNING_MESSAGE); 521 return; 522 } 523 // There is a dccAddress so a throttle can be acquired 524 String s = ("" + Math.random()).substring(2); 525 Warrant warrant = new Warrant("IW" + s, "NX(" + getAddress() + ")"); 526 warrant.setBlockOrders(_orders); 527 warrant.setTrainName(getTrainName()); 528 warrant.setNoRamp(_noRamp.isSelected()); 529 _speedUtil.setIsForward(_forward.isSelected()); 530 warrant.setSpeedUtil(_speedUtil); // transfer SpeedUtil to warrant 531 log.debug("Warrant {}. Route and loco set.", warrant.getDisplayName()); 532 int mode; 533 if (!_runManual.isSelected()) { 534 mode = Warrant.MODE_RUN; 535 warrant.setShareRoute(_shareRouteBox.isSelected()); 536 warrant.setAddTracker(_addTracker.isSelected()); 537 warrant.setHaltStart(_haltStartBox.isSelected()); 538 msg = makeCommands(warrant); 539 } else { 540 mode = Warrant.MODE_MANUAL; 541 } 542 if (msg == null) { 543 WarrantTableFrame tableFrame = WarrantTableFrame.getDefault(); 544 tableFrame.setVisible(true); 545 warrant.setNXWarrant(true); 546 tableFrame.getModel().addNXWarrant(warrant); //need to catch propertyChange at start 547 log.debug("NXWarrant added to table"); 548 msg = tableFrame.runTrain(warrant, mode); 549 if (msg != null) { 550 log.debug("WarrantTableFrame run warrant. msg= {} Remove warrant {}",msg,warrant.getDisplayName()); 551 tableFrame.getModel().removeWarrant(warrant, false); 552 } 553 } 554 if (msg != null) { 555 JmriJOptionPane.showMessageDialog(this, msg, 556 Bundle.getMessage("WarningTitle"), JmriJOptionPane.WARNING_MESSAGE); 557 } else { 558 WarrantTableAction.getDefault().closeNXFrame(); 559 } 560 } 561 562 // for testing 563 protected void setMaxSpeed(float s) { 564 _maxThrottle = s; 565 _maxThrottleBox.setText(NumberFormat.getNumberInstance().format(s)); 566 } 567 568 private String getBoxData() { 569 String text = null; 570 float maxSpeed; 571 NumberFormat formatter = NumberFormat.getNumberInstance(); 572 try { 573 text = _maxThrottleBox.getText(); 574 maxSpeed = formatter.parse(text).floatValue(); 575 } catch (java.text.ParseException pe) { 576 if (text==null) { 577 text = "\"\""; 578 } 579 return Bundle.getMessage("badSpeed100", text); 580 } 581 582 try { 583 _startDist = getDistance(_originDist, _orders.get(0)); 584 if (_startDist < 2) { 585 _startDist = 2; // leave block by at least 2 millimeters - cannot be 0 586 } 587 } catch (JmriException je) { 588 return je.getMessage(); 589 } 590 591 try { 592 _stopDist = getDistance(_destDist, _orders.get(_orders.size()-1)); 593 if (_stopDist < 2) { 594 _stopDist = 2; // enter block by at least 2 millimeters - cannot be 0 595 } 596 } catch (JmriException je) { 597 return je.getMessage(); 598 } 599 600 if (maxSpeed > 100f || maxSpeed < 0.001f) { 601 return Bundle.getMessage("badSpeed100", maxSpeed); 602 } 603 _maxThrottle = maxSpeed / 100; 604 605 String msg = setAddress(); 606 if (msg != null) { 607 return msg; 608 } 609 610 int time = (Integer)_timeIncre.getValue(); 611 _speedUtil.setRampTimeIncrement(time); 612 613 try { 614 text = _rampIncre.getText(); 615 float incre = NumberFormat.getNumberInstance().parse(text).floatValue(); 616 if (incre < 0.5f || incre > 25f) { 617 return Bundle.getMessage("rampIncrWarning", text); 618 } else { 619 _speedUtil.setRampThrottleIncrement(incre/100); 620 } 621 } catch (java.text.ParseException pe) { 622 return Bundle.getMessage("MustBeFloat", text); 623 } 624 return null; 625 } 626 627 private float getDistance(@Nonnull JTextField field, @Nonnull BlockOrder bo) throws JmriException { 628 NumberFormat formatter = NumberFormat.getNumberInstance(); 629 float distance; 630 String text = field.getText(); 631 try { 632 distance = formatter.parse(text).floatValue(); 633 } catch (java.text.ParseException pe) { 634 throw new JmriException(Bundle.getMessage("MustBeFloat", text)); 635 } 636 float pathLen = getPathLength(bo); 637 if (pathLen <= 0) { 638 throw new JmriException(Bundle.getMessage("zeroPathLength", 639 bo.getPathName(), bo.getBlock().getDisplayName())); 640 } 641 if (_units.equals(Display.IN)){ 642 distance *= 25.4f; // convert inches to millimeters 643 if (distance > pathLen) { 644 field.setText(formatter.format(pathLen*0.03937008f)); 645 throw new JmriException(Bundle.getMessage( 646 "BadLengthIn", bo.getPathName(), bo.getBlock().getDisplayName(), pathLen*0.03937008f, text)); 647 } else if (distance < 0) { 648 field.setText("0"); 649 throw new JmriException(Bundle.getMessage( 650 "BadLengthIn", bo.getPathName(), bo.getBlock().getDisplayName(), pathLen*0.03937008f, text)); 651 } 652 } else { 653 distance *= 10f; // convert centimeters to millimeters 654 if (distance > pathLen) { 655 field.setText(formatter.format(pathLen*0.1f)); 656 throw new JmriException(Bundle.getMessage( 657 "BadLengthCm", bo.getPathName(), bo.getBlock().getDisplayName(), pathLen*0.1f, text)); 658 } else if (distance < 0) { 659 field.setText("0"); 660 throw new JmriException(Bundle.getMessage( 661 "BadLengthCm", bo.getPathName(), bo.getBlock().getDisplayName(), pathLen*0.1f, text)); 662 } 663 } 664 return distance; 665 } 666 667 private float getPathLength(@Nonnull BlockOrder bo) { 668 float len = bo.getPathLength(); 669 if (len <= 0) { 670 len = bo.getPathLength(); 671 if ( len <= 0) { 672 String sLen = JmriJOptionPane.showInputDialog(this, 673 Bundle.getMessage("zeroPathLength", bo.getPathName(), bo.getBlock().getDisplayName()) 674 + Bundle.getMessage("getPathLength", bo.getPathName(), bo.getBlock().getDisplayName()), 675 Bundle.getMessage("WarningTitle"), JmriJOptionPane.WARNING_MESSAGE); 676 try { 677 len = NumberFormat.getNumberInstance().parse(sLen).floatValue(); 678 } catch (java.text.ParseException | java.lang.NullPointerException pe) { 679 len = 0.0f; 680 } 681 bo.setPathLength(len); 682 } 683 } 684 return len; 685 } 686 687 /** 688 * Return length of warrant route in mm. 689 * @throws JmriException when a Path Length is < or equals 0 690 */ 691 private float getTotalLength() throws JmriException { 692 List<BlockOrder> orders = getOrders(); 693 float totalLen = _startDist; 694 for (int i = 1; i < orders.size() - 1; i++) { 695 BlockOrder bo = orders.get(i); 696 float pathLen = getPathLength(bo); 697 if (pathLen <= 0) { 698 throw new JmriException(Bundle.getMessage("zeroPathLength", 699 bo.getPathName(), bo.getBlock().getDisplayName())); 700 } 701 totalLen += pathLen; 702 } 703 totalLen += _stopDist; 704 return totalLen; 705 } 706 707 @CheckForNull 708 private String makeCommands(@Nonnull Warrant w) { 709 710 int nextIdx = 0; // block index - increment after getting a block order 711 List<BlockOrder> orders = getOrders(); 712 BlockOrder bo = orders.get(nextIdx++); 713 String blockName = bo.getBlock().getDisplayName(); 714 715 int cmdNum; 716 w.addThrottleCommand(new ThrottleSetting(0, Command.FKEY, 0, 717 ValueType.VAL_ON, SpeedStepMode.UNKNOWN, 0, "", blockName)); 718 if (_forward.isSelected()) { 719 w.addThrottleCommand(new ThrottleSetting(100, Command.FORWARD, -1, 720 ValueType.VAL_TRUE, SpeedStepMode.UNKNOWN, 0, "", blockName)); 721 if (!_noSound.isSelected()) { 722 w.addThrottleCommand(new ThrottleSetting(1000, Command.FKEY, 2, 723 ValueType.VAL_ON, SpeedStepMode.UNKNOWN, 0, "", blockName)); 724 w.addThrottleCommand(new ThrottleSetting(2500, Command.FKEY, 2, 725 ValueType.VAL_OFF, SpeedStepMode.UNKNOWN, 0, "", blockName)); 726 w.addThrottleCommand(new ThrottleSetting(1000, Command.FKEY, 2, 727 ValueType.VAL_ON, SpeedStepMode.UNKNOWN, 0, "", blockName)); 728 w.addThrottleCommand(new ThrottleSetting(2500, Command.FKEY, 2, 729 ValueType.VAL_OFF, SpeedStepMode.UNKNOWN, 0, "", blockName)); 730 cmdNum = 7; 731 } else { 732 cmdNum = 3; 733 } 734 } else { 735 w.addThrottleCommand(new ThrottleSetting(100, Command.FORWARD, -1, 736 ValueType.VAL_FALSE, SpeedStepMode.UNKNOWN, 0, "", blockName)); 737 if (!_noSound.isSelected()) { 738 w.addThrottleCommand(new ThrottleSetting(1000, Command.FKEY, 3, 739 ValueType.VAL_ON, SpeedStepMode.UNKNOWN, 0, "", blockName)); 740 w.addThrottleCommand(new ThrottleSetting(500, Command.FKEY, 3, 741 ValueType.VAL_OFF, SpeedStepMode.UNKNOWN, 0, "", blockName)); 742 w.addThrottleCommand(new ThrottleSetting(500, Command.FKEY, 3, 743 ValueType.VAL_ON, SpeedStepMode.UNKNOWN, 0, "", blockName)); 744 w.addThrottleCommand(new ThrottleSetting(500, Command.FKEY, 3, 745 ValueType.VAL_OFF, SpeedStepMode.UNKNOWN, 0, "", blockName)); 746 cmdNum = 6; 747 } else { 748 cmdNum = 2; 749 } 750 } 751 752 float totalLen; 753 try { 754 totalLen = getTotalLength(); 755 } catch (JmriException je) { 756 return je.getMessage(); 757 } 758 759 RampData upRamp = _speedUtil.getRampForSpeedChange(0f, _maxThrottle); 760 RampData downRamp = _speedUtil.getRampForSpeedChange(_maxThrottle, 0f); 761 float upRampLength = upRamp.getRampLength(); 762 float dnRampLength = downRamp.getRampLength(); 763 int timeInterval = downRamp.getRampTimeIncrement(); 764 float intervalDist = totalLen - (upRampLength + dnRampLength); 765 while (intervalDist < 0) { 766 log.debug("Route length= {}, upRampLength= {}, dnRampLength= {}, intervalDist= {}, _maxThrottle= {}", 767 totalLen, upRampLength, dnRampLength, intervalDist, _maxThrottle); 768 ListIterator<Float> downIter = downRamp.speedIterator(false); 769 float prevSetting = downIter.previous(); // top value is _maxThrottle 770 if (downIter.hasPrevious()) { // if none, empty ramp 771 prevSetting = downIter.previous(); 772 _maxThrottle = prevSetting; // last throttle increment 773 } else { 774 _maxThrottle = _speedUtil.getThrottleSettingForSpeed(totalLen/(timeInterval*2)); 775 } 776 upRamp = _speedUtil.getRampForSpeedChange(0f, _maxThrottle); 777 downRamp = _speedUtil.getRampForSpeedChange(_maxThrottle, 0f); 778 upRampLength = upRamp.getRampLength(); 779 dnRampLength = downRamp.getRampLength(); 780 intervalDist = totalLen - (upRampLength + dnRampLength); 781 } 782 if (upRampLength < 1) { 783 upRamp = _speedUtil.getRampForSpeedChange(0f, _speedUtil.getRampThrottleIncrement()); 784 } 785 if (dnRampLength < 1) { 786 downRamp = _speedUtil.getRampForSpeedChange(0f, _speedUtil.getRampThrottleIncrement()); 787 } 788 log.debug("Route length= {}, upRampLength= {}, dnRampLength= {}, intervalDist= {}, _maxThrottle= {}", 789 totalLen, upRampLength, dnRampLength, intervalDist, _maxThrottle); 790 791 float blockLen = _startDist; // length of path in current block 792 float sumBlkLen = 0; // sum of path lengths at NOOP 793 794 // start train 795 int speedTime = 0; // ms time to complete speed step from last block 796 int noopTime = 0; // ms time for entry into next block 797 ListIterator<Float> iter = upRamp.speedIterator(true); 798 float curThrottle = 0; // throttle setting 799 float prevThrottle = 0; 800 float curDistance = 0; // current distance traveled up to issuing next command 801 float blkDistance = 0; // distance traveled in current block up to issuing next command 802 float dist = 0f; // increment to accumulate curDistance and blkDistance 803 804 log.debug("Start in block \"{}\" startDist= {} stopDist= {}", blockName, _startDist, _stopDist); 805 806 while (iter.hasNext()) { // ramp up loop 807 808 while (iter.hasNext()) { 809 // interval distance up to speed change 810 dist = _speedUtil.getDistanceOfSpeedChange(prevThrottle, curThrottle, speedTime); 811 if (blkDistance + dist >= blockLen) { 812 break; // cannot finish upRamp within this block 813 } 814 blkDistance += dist; 815 curDistance += dist; 816 float nextThrottle = iter.next(); 817 w.addThrottleCommand(new ThrottleSetting(speedTime, Command.SPEED, -1, ValueType.VAL_FLOAT, 818 SpeedStepMode.UNKNOWN, nextThrottle, "", blockName, _speedUtil.getTrackSpeed(curThrottle))); 819 if (log.isDebugEnabled()) { 820 log.debug("cmd#{}. UpRamp block \"{}\" set speed {} after {}ms " + 821 "dist= {} from {} to {}, blkDist= {} curDist= {}", 822 cmdNum++, blockName, nextThrottle, speedTime, 823 dist, prevThrottle, curThrottle, blkDistance, curDistance); 824 } 825 prevThrottle = curThrottle; 826 curThrottle = nextThrottle; 827 speedTime = timeInterval; 828 } // end of upRamp within a block 829 830 if (blkDistance >= blockLen) { 831 // Possible case where initial blkDistance can exceed the length of a block that was just entered. 832 // Skip over block and move to next block and adjust the distance times into that block 833 noopTime = _speedUtil.getTimeForDistance(curThrottle, blockLen); // noop distance to run through block 834 speedTime = _speedUtil.getTimeForDistance(curThrottle, blkDistance - blockLen); 835 } else { 836 // typical case where next speed change broke out of above loop. (blkDistance + dist >= blockLen) 837 noopTime = _speedUtil.getTimeForDistance(curThrottle, (blockLen - blkDistance)); // time to next block 838 speedTime = timeInterval - noopTime; // time to next speed change 839 } 840 841 if (log.isDebugEnabled()) { 842 log.debug("Leave block \"{}\" curThrottle= {}, blockLen= {} blkDist= {}, " + 843 "noopTime= {} 'speedTime'= {}, curDist= {}", 844 blockName, curThrottle, blockLen, blkDistance, noopTime, speedTime, curDistance); 845 } 846 if (!iter.hasNext()) { 847 break; 848 } 849 850 if (nextIdx < orders.size()) { 851 if (noopTime > timeInterval) { 852 speedTime = 0; 853 } else { 854 speedTime = timeInterval - noopTime; 855 } 856 dist = _speedUtil.getDistanceOfSpeedChange(prevThrottle, curThrottle, noopTime); 857 blkDistance += dist; 858 curDistance += dist; 859 sumBlkLen += blockLen; 860 bo = orders.get(nextIdx++); 861 blockLen = getPathLength(bo); 862 if (blockLen <= 0) { 863 return Bundle.getMessage("zeroPathLength", bo.getPathName(), bo.getBlock().getDisplayName()); 864 } 865 blockName = bo.getBlock().getDisplayName(); 866 w.addThrottleCommand(new ThrottleSetting(noopTime, Command.NOOP, -1, ValueType.VAL_NOOP, 867 SpeedStepMode.UNKNOWN, 0, "", blockName, _speedUtil.getTrackSpeed(curThrottle))); 868 if (log.isDebugEnabled()) { 869 log.debug("cmd#{}. Enter RampUp block \"{}\" noopTime= {}" 870 + ", dist= {} blockLen= {}, blkDist= {}, sumBlkLen= {}, curDist= {}", 871 cmdNum++, blockName, noopTime, dist, blockLen, blkDistance, sumBlkLen, curDistance); 872 } 873 blkDistance = 0; 874 curDistance = sumBlkLen; 875 } 876 } // end of upRamp loop 877 878 if (blkDistance < 0.01) { // no increase of speed in this block 879 dist = _speedUtil.getDistanceOfSpeedChange(prevThrottle, curThrottle, speedTime); 880 log.debug("No speed increase in block \"{}\" speedTime= {} dist= {}" 881 + ", blkDist= {}, curDist= {} upRampLength={}", 882 blockName, speedTime, dist, blkDistance, curDistance, upRampLength); 883 blkDistance += dist; 884 curDistance += dist; // curDistance ought to equal upRampLength 885 } 886 log.debug("Ramp Up done in block \"{}\" speedTime= {} dist= {}" 887 + ", blkDist= {}, curDist= {} upRampLength= {} diff= {}", 888 blockName, speedTime, dist, blkDistance, curDistance, upRampLength, upRampLength - curDistance); 889 blkDistance += (upRampLength - curDistance); // adjustment for getDistanceOfSpeedChange calculation variances 890 curDistance = upRampLength; 891 if (log.isDebugEnabled()) { 892 log.debug("Ramp Up done in block \"{}\" timeInterval= {} dist= {}" 893 + ", blkDist= {}, curDist= {} upRampLength= {}", 894 blockName, noopTime, dist, blkDistance, curDistance, upRampLength); 895 } 896 prevThrottle = curThrottle; // travel at curThrottle (max speed) for a period of time 897 898 if ( log.isDebugEnabled() && Math.abs(curThrottle - _maxThrottle) > 0.001) { 899 log.error("curThrottle = {} _maxThrottle = {} prevThrottle= {}", curThrottle, _maxThrottle, prevThrottle); 900 } 901 902 // (sumBlkLen + blockLen) is total distance traveled to end of current block 903 if (totalLen - sumBlkLen - blockLen > dnRampLength) { 904 if (!iter.hasNext()) { // upRamp done. At maxThrottle for remainder of block 905 if (nextIdx < orders.size()) { // not the last block 906 dist = _speedUtil.getDistanceOfSpeedChange(prevThrottle, curThrottle, noopTime); 907 blkDistance += dist; 908 curDistance += dist; 909 sumBlkLen += blockLen; 910 bo = orders.get(nextIdx++); 911 blockLen = getPathLength(bo); 912 if (blockLen <= 0) { 913 return Bundle.getMessage("zeroPathLength", bo.getPathName(), bo.getBlock().getDisplayName()); 914 } 915 blockName = bo.getBlock().getDisplayName(); 916 w.addThrottleCommand(new ThrottleSetting(noopTime, Command.NOOP, -1, ValueType.VAL_NOOP, 917 SpeedStepMode.UNKNOWN, 0, "", blockName, _speedUtil.getTrackSpeed(curThrottle))); 918 if (log.isDebugEnabled()) { 919 log.debug("cmd#{}. Enter RampUp block \"{}\" noopTime= {}" 920 + ", dist= {} blockLen= {}, blkDist= {}, sumBlkLen= {}, curDist= {}", 921 cmdNum++, blockName, noopTime, 922 dist, blockLen, blkDistance, sumBlkLen, curDistance); 923 } 924 curDistance = sumBlkLen; 925 blkDistance = 0; 926 } else { 927 if (log.isDebugEnabled()) { 928 log.debug("Ramp Up done at last block \"{}\" curThrottle={}, blkDist={}, curDist={}", 929 blockName, curThrottle, blkDistance, curDistance); 930 } 931 } // left block where up ramp finished 932 933 // run through mid route at max speed 934 while (nextIdx < orders.size() && totalLen - sumBlkLen - blockLen > dnRampLength) { 935 // constant speed, get time to next block 936 noopTime = _speedUtil.getTimeForDistance(curThrottle, blockLen); // time to next block 937 sumBlkLen += blockLen; 938 curDistance += blockLen; 939 if (log.isDebugEnabled()) { 940 log.debug("Leave MidRoute block \"{}\" noopTime= {} blockLen= {}, sumBlkLen= {}, curDist={}", 941 blockName, noopTime, blockLen, sumBlkLen, curDistance); 942 } 943 bo = orders.get(nextIdx++); 944 blockLen = getPathLength(bo); 945 if (blockLen <= 0) { 946 return Bundle.getMessage("zeroPathLength", bo.getPathName(), bo.getBlock().getDisplayName()); 947 } 948 blockName = bo.getBlock().getDisplayName(); 949 if (nextIdx == orders.size()) { 950 blockLen = _stopDist; 951 } 952 w.addThrottleCommand(new ThrottleSetting(noopTime, Command.NOOP, -1, ValueType.VAL_NOOP, 953 SpeedStepMode.UNKNOWN, 0, "", blockName, _speedUtil.getTrackSpeed(curThrottle))); 954 if (log.isDebugEnabled()) { 955 log.debug("cmd#{}. Enter MidRoute block \"{}\" noopTime= {}," 956 + "blockLen= {}, sumBlkLen= {}, curDist={}", 957 cmdNum++, blockName, noopTime, blockLen, sumBlkLen, curDistance); 958 } 959 } 960 } 961 blkDistance = 0; 962 dist = totalLen - sumBlkLen - dnRampLength; 963 } else { // up ramp and down ramp in the same block 964 dist = totalLen - dnRampLength - upRampLength; 965 } 966 967 speedTime =_speedUtil.getTimeForDistance(curThrottle, dist); 968 blkDistance += dist; 969 curDistance += dist; 970 971 float diff = totalLen - dnRampLength - curDistance; 972 if (log.isDebugEnabled()) { 973 log.debug("Begin Ramp Down in block \"{}\" speedTime= {} dist= {}" 974 + ", blkDist= {}, curDist= {} dnRampLength= {} diff= {}", 975 blockName, speedTime, dist, blkDistance, curDistance, dnRampLength, diff); 976 } 977 blkDistance += diff; // adjustment for getDistanceOfSpeedChange calculation variances 978 curDistance = totalLen - dnRampLength; 979 980 // Ramp down. 981 if (log.isDebugEnabled()) { 982 log.debug("Begin Ramp Down at block \"{}\" blockLen={}," 983 + " at blkDistance= {} curDist= {} sumBlkLen= {} curThrottle= {}", 984 blockName, blockLen, blkDistance, curDistance, sumBlkLen, curThrottle); 985 } 986 987 iter = downRamp.speedIterator(false); 988 iter.previous(); // discard, equals curThrottle 989 990 float nextThrottle = iter.previous(); 991 w.addThrottleCommand(new ThrottleSetting(speedTime, Command.SPEED, -1, ValueType.VAL_FLOAT, 992 SpeedStepMode.UNKNOWN, nextThrottle, "", blockName, _speedUtil.getTrackSpeed(curThrottle))); 993 if (log.isDebugEnabled()) { 994 log.debug("cmd#{}. DownRamp block \"{}\" set speed {} after {}ms " 995 + "dist= {} from {} to {}, blkDist= {} curDist={}", 996 cmdNum++, blockName, nextThrottle, speedTime, 997 dist, prevThrottle, curThrottle, blkDistance, curDistance); 998 } 999 prevThrottle = curThrottle; 1000 curThrottle = nextThrottle; 1001 speedTime = timeInterval; 1002 1003 while (iter.hasPrevious()) { 1004 if ( nextIdx == orders.size() /* at last block */ && _stageEStop.isSelected() ) { 1005 w.addThrottleCommand(new ThrottleSetting(50, Command.SPEED, -1, ValueType.VAL_FLOAT, 1006 SpeedStepMode.UNKNOWN, -0.5f, "", blockName, _speedUtil.getTrackSpeed(curThrottle))); 1007 log.debug("cmd#{}. At block \"{}\" EStop set speed= {}", cmdNum++, blockName, -0.5); 1008 break; 1009 } 1010 1011 nextThrottle = curThrottle; 1012 while (iter.hasPrevious()) { 1013 dist = _speedUtil.getDistanceOfSpeedChange(prevThrottle, curThrottle, speedTime); 1014 if (blkDistance + dist >= blockLen) { 1015 break; 1016 } 1017 nextThrottle = iter.previous(); 1018 1019 if (!iter.hasPrevious() && nextIdx != orders.size()) { 1020 // nextThrottle is last speed setting. Make sure speed 0 is set in last block 1021 log.debug("BEFORE last block! Set speed {} in block \"{}\" after {}ms!" 1022 + "dist= {}, blkDist= {} curDist={}, blockLen= {}", 1023 nextThrottle, blockName, speedTime, dist, blkDistance, curDistance, blockLen); 1024 iter.next(); // Back up. 1025 noopTime = speedTime; 1026 speedTime = -1; 1027 break; 1028 } 1029 // interval distance up to speed change 1030 blkDistance += dist; 1031 curDistance += dist; 1032 w.addThrottleCommand(new ThrottleSetting(speedTime, Command.SPEED, -1, ValueType.VAL_FLOAT, 1033 SpeedStepMode.UNKNOWN, nextThrottle, "", blockName, _speedUtil.getTrackSpeed(curThrottle))); 1034 if (log.isDebugEnabled()) { 1035 log.debug("cmd#{}. DownRamp block \"{}\" set speed {} after {}ms" 1036 + " dist= {} from {} to {}, blkDist= {} curDist={}", 1037 cmdNum++, blockName, nextThrottle, speedTime, 1038 dist, prevThrottle, curThrottle, blkDistance, curDistance); 1039 } 1040 prevThrottle = curThrottle; 1041 curThrottle = nextThrottle; 1042 speedTime = timeInterval; 1043 } 1044 1045 if (!iter.hasPrevious()) { 1046 break; 1047 } 1048 1049 if (speedTime < 0) { 1050 speedTime = 0; 1051 } else { 1052 if (blkDistance >= blockLen) { 1053 // Possible case where blkDistance can exceed the length of a block that was just entered. 1054 // Skip over block and move to next block and adjust the distance times into that block 1055 noopTime = _speedUtil.getTimeForDistance(curThrottle, blockLen); // noop distance to run through block 1056 speedTime = _speedUtil.getTimeForDistance(curThrottle, blkDistance - blockLen); 1057 } else { 1058 // typical case where next speed change broke out of above loop. (blkDistance + dist >= blockLen) 1059 noopTime = _speedUtil.getTimeForDistance(curThrottle, (blockLen - blkDistance)); // time to next block 1060 speedTime = timeInterval - noopTime; // time to next speed change 1061 } 1062 } 1063 1064 if (log.isDebugEnabled()) { 1065 log.debug("Leave block \"{}\" curThrottle= {}, blockLen= {}" 1066 + " BlkDist= {}, noopTime= {} 'speedTime'= {}, curDist= {}", 1067 blockName, curThrottle, blockLen, blkDistance, noopTime, speedTime, curDistance); 1068 } 1069 1070 if (nextIdx < orders.size()) { 1071 if (noopTime > timeInterval) { 1072 speedTime = 0; 1073 } else { 1074 speedTime = timeInterval - noopTime; 1075 } 1076 dist = _speedUtil.getDistanceOfSpeedChange(prevThrottle, curThrottle, noopTime); 1077 blkDistance += dist; 1078 curDistance += dist; 1079 sumBlkLen += blockLen; 1080 bo = orders.get(nextIdx++); 1081 if (nextIdx == orders.size()) { 1082 blockLen = _stopDist; 1083 } else { 1084 blockLen = getPathLength(bo); 1085 } 1086 if (blockLen <= 0) { 1087 return Bundle.getMessage("zeroPathLength", bo.getPathName(), bo.getBlock().getDisplayName()); 1088 } 1089 blockName = bo.getBlock().getDisplayName(); 1090 w.addThrottleCommand(new ThrottleSetting(noopTime, Command.NOOP, -1, ValueType.VAL_NOOP, 1091 SpeedStepMode.UNKNOWN, 0, "", blockName, _speedUtil.getTrackSpeed(curThrottle))); 1092 if (log.isDebugEnabled()) { 1093 log.debug("cmd#{}. Enter RampDown block \"{}\" noopTime= {}," 1094 + " dist= {} blockLen= {}, blkDist= {}, sumBlkLen= {}, curDist= {}", 1095 cmdNum++, blockName, noopTime, dist, blockLen, blkDistance, sumBlkLen, curDistance); 1096 } 1097 blkDistance = 0; 1098 curDistance = sumBlkLen; 1099 if (nextIdx == orders.size()) { 1100 dist = _speedUtil.getDistanceOfSpeedChange(prevThrottle, curThrottle, speedTime); 1101 if (dist > blockLen) { 1102 speedTime = 0; 1103 } 1104 } 1105 } else if (iter.hasPrevious()) { // Should not happen. Error in distance calculation 1106 _stageEStop.setSelected(true); 1107 log.error("cmd#{}. ERROR speed in block \"{}\" set speed {} " 1108 + "after {}ms dist= {} from {} to {}, blkDist= {} curDist={}", 1109 cmdNum++, blockName, nextThrottle, 1110 speedTime, dist, prevThrottle, curThrottle, blkDistance, curDistance); 1111 } 1112 } 1113 1114 // Ramp down finished 1115 if (log.isDebugEnabled()) { 1116 sumBlkLen += _stopDist; 1117 curDistance += _speedUtil.getDistanceOfSpeedChange(prevThrottle, curThrottle, speedTime); 1118 log.debug("Ramp down done at block \"{}\", blockLen= {}, " 1119 + "BlkDist= {}, curDist= {}, sumBlkLen= {}, totalLen= {},", 1120 blockName, blockLen, blkDistance, curDistance, sumBlkLen, totalLen); 1121 } 1122 if (!_noSound.isSelected()) { 1123 w.addThrottleCommand(new ThrottleSetting(500, Command.FKEY, 1, 1124 ValueType.VAL_OFF, SpeedStepMode.UNKNOWN, 0, "", blockName)); 1125 w.addThrottleCommand(new ThrottleSetting(1000, Command.FKEY, 2, 1126 ValueType.VAL_ON, SpeedStepMode.UNKNOWN, 0, "", blockName)); 1127 w.addThrottleCommand(new ThrottleSetting(2000, Command.FKEY, 2, 1128 ValueType.VAL_OFF, SpeedStepMode.UNKNOWN, 0, "", blockName)); 1129 } 1130 w.addThrottleCommand(new ThrottleSetting(500, Command.FKEY, 0, 1131 ValueType.VAL_OFF, SpeedStepMode.UNKNOWN, 0, "", blockName)); 1132 return null; 1133 } 1134 1135 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(NXFrame.class); 1136 1137}