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