001package jmri.jmrix; 002 003import java.io.DataInputStream; 004import java.io.DataOutputStream; 005import java.util.Enumeration; 006import java.util.Vector; 007 008import jmri.SystemConnectionMemo; 009 010/** 011 * Provide an abstract base for *PortController classes. 012 * <p> 013 * The intent is to hide, to the extent possible, all the references to the 014 * actual serial library in use within this class. Subclasses then 015 * rely on methods here to maniplate the content of the 016 * protected currentSerialPort variable/ 017 * 018 * @see jmri.jmrix.SerialPortAdapter 019 * 020 * @author Bob Jacobsen Copyright (C) 2001, 2002, 2023 021 */ 022abstract public class AbstractSerialPortController extends AbstractPortController implements SerialPortAdapter { 023 024 protected AbstractSerialPortController(SystemConnectionMemo connectionMemo) { 025 super(connectionMemo); 026 } 027 028 protected com.fazecast.jSerialComm.SerialPort currentSerialPort = null; 029 030 /** 031 * Standard error handling for purejavacomm port-busy case. 032 * 033 * @param p the exception being handled, if additional information 034 * from it is desired 035 * @param portName name of the port being accessed 036 * @param log where to log a status message 037 * @return Localized message, in case separate presentation to user is 038 * desired 039 */ 040 //@Deprecated(forRemoval=true) // with PureJavaComm 041 @Override 042 public String handlePortBusy(purejavacomm.PortInUseException p, String portName, org.slf4j.Logger log) { 043 log.error("{} port is in use: {}", portName, p.getMessage()); 044 /*JmriJOptionPane.showMessageDialog(null, "Port is in use", 045 "Error", JmriJOptionPane.ERROR_MESSAGE);*/ 046 ConnectionStatus.instance().setConnectionState(this.getSystemPrefix(), portName, ConnectionStatus.CONNECTION_DOWN); 047 return Bundle.getMessage("SerialPortInUse", portName); 048 } 049 050 /** 051 * Specific error handling for purejavacomm port-not-found case. 052 * @param p no such port exception. 053 * @param portName port name. 054 * @param log system log. 055 * @return human readable string with error detail. 056 */ 057 //@Deprecated(forRemoval=true) // with PureJavaComm 058 public String handlePortNotFound(purejavacomm.NoSuchPortException p, String portName, org.slf4j.Logger log) { 059 log.error("Serial port {} not found", portName); 060 ConnectionStatus.instance().setConnectionState(this.getSystemPrefix(), portName, ConnectionStatus.CONNECTION_DOWN); 061 return Bundle.getMessage("SerialPortNotFound", portName); 062 } 063 064 /** 065 * Standard error handling for the general port-not-found case. 066 * @param portName port name. 067 * @param log system log, passed so logging comes from bottom level class 068 * @param ex Underlying Exception that caused this failure 069 * @return human readable string with error detail. 070 */ 071 final public String handlePortNotFound(String portName, org.slf4j.Logger log, Exception ex) { 072 log.error("Serial port {} not found: {}", portName, ex.getMessage()); 073 ConnectionStatus.instance().setConnectionState(this.getSystemPrefix(), portName, ConnectionStatus.CONNECTION_DOWN); 074 return Bundle.getMessage("SerialPortNotFound", portName); 075 } 076 077 /** 078 * {@inheritDoc} 079 */ 080 @Override 081 public void connect() throws java.io.IOException { 082 openPort(mPort, "JMRI app"); 083 } 084 085 /** 086 * Do the formal opening of the port, 087 * set the port for blocking reads without timeout, 088 * set the port to 8 data bits, 1 stop bit, no parity 089 * and purge the port's input stream. 090 * <p> 091 * Does not do the rest of the setup implied in the {@link #openPort} method. 092 * This is usually followed by calls to 093 * {@link #setBaudRate}, {@link #configureLeads} and {@link #setFlowControl}. 094 * 095 * @param portName local system name for the desired port 096 * @param log Logger to use for errors, passed so that errors are logged from low-level class 097 * @return the serial port object for later use 098 */ 099 final protected com.fazecast.jSerialComm.SerialPort activatePort(String portName, org.slf4j.Logger log) { 100 return this.activatePort(portName, log, 1, Parity.NONE); 101 } 102 103 /** 104 * Do the formal opening of the port, 105 * set the port for blocking reads without timeout, 106 * set the port to 8 data bits, the indicated number of stop bits, no parity, 107 * and purge the port's input stream. 108 * <p> 109 * Does not do the rest of the setup implied in the {@link #openPort} method. 110 * This is usually followed by calls to 111 * {@link #setBaudRate}, {@link #configureLeads} and {@link #setFlowControl}. 112 * 113 * @param portName local system name for the desired port 114 * @param log Logger to use for errors, passed so that errors are logged from low-level class' 115 * @param stop_bits The number of stop bits, either 1 or 2 116 * @return the serial port object for later use 117 */ 118 final protected com.fazecast.jSerialComm.SerialPort activatePort(String portName, org.slf4j.Logger log, int stop_bits) { 119 return this.activatePort(portName, log, stop_bits, Parity.NONE); 120 } 121 122 /** 123 * Do the formal opening of the port, 124 * set the port for blocking reads without timeout, 125 * set the port to 8 data bits, the indicated number of stop bits and parity, 126 * and purge the port's input stream. 127 * <p> 128 * Does not do the rest of the setup implied in the {@link #openPort} method. 129 * This is usually followed by calls to 130 * {@link #setBaudRate}, {@link #configureLeads} and {@link #setFlowControl}. 131 * 132 * @param portName local system name for the desired port 133 * @param log Logger to use for errors, passed so that errors are logged from low-level class' 134 * @param stop_bits The number of stop bits, either 1 or 2 135 * @param parity one of the defined parity contants 136 * @return the serial port object for later use 137 */ 138 139 final protected com.fazecast.jSerialComm.SerialPort activatePort(String portName, org.slf4j.Logger log, int stop_bits, Parity parity) { 140 com.fazecast.jSerialComm.SerialPort serialPort; 141 142 // convert the 1 or 2 stop_bits argument to the proper jSerialComm code value 143 int stop_bits_code; 144 switch (stop_bits) { 145 case 1: 146 stop_bits_code = com.fazecast.jSerialComm.SerialPort.ONE_STOP_BIT; 147 break; 148 case 2: 149 stop_bits_code = com.fazecast.jSerialComm.SerialPort.TWO_STOP_BITS; 150 break; 151 default: 152 throw new IllegalArgumentException("Incorrect stop_bits argument: "+stop_bits); 153 } 154 155 try { 156 serialPort = com.fazecast.jSerialComm.SerialPort.getCommPort(portName); 157 serialPort.openPort(); 158 serialPort.setComPortTimeouts(com.fazecast.jSerialComm.SerialPort.TIMEOUT_READ_BLOCKING, 0, 0); 159 serialPort.setNumDataBits(8); 160 serialPort.setNumStopBits(stop_bits_code); 161 serialPort.setParity(parity.getValue()); 162 purgeStream(serialPort.getInputStream()); 163 } catch (java.io.IOException | com.fazecast.jSerialComm.SerialPortInvalidPortException ex) { 164 // IOException includes 165 // com.fazecast.jSerialComm.SerialPortIOException 166 handlePortNotFound(portName, log, ex); 167 return null; 168 } 169 return serialPort; 170 } 171 172 /** 173 * {@inheritDoc} 174 */ 175 @Override 176 public void setPort(String port) { 177 log.debug("Setting port to {}", port); 178 mPort = port; 179 } 180 protected String mPort = null; 181 182 /** 183 * {@inheritDoc} 184 * 185 * Overridden in simulator adapter classes to return ""; 186 */ 187 @Override 188 public String getCurrentPortName() { 189 if (mPort == null) { 190 if (getPortNames() == null) { 191 // this shouldn't happen in normal operation 192 // but in the tests this can happen if the receive thread has been interrupted 193 log.error("Port names returned as null"); 194 return null; 195 } 196 if (getPortNames().size() <= 0) { 197 log.error("No usable ports returned"); 198 return null; 199 } 200 return null; 201 // return (String)getPortNames().elementAt(0); 202 } 203 return mPort; 204 } 205 206 /** 207 * Provide the actual serial port names. 208 * As a public static method, this can be accessed outside the jmri.jmrix 209 * package to get the list of names for e.g. context reports. 210 * 211 * @return the port names in the form they can later be used to open the port 212 */ 213// @SuppressWarnings("UseOfObsoleteCollectionType") // historical interface 214 public static Vector<String> getActualPortNames() { 215 // first, check that the comm package can be opened and ports seen 216 var portNameVector = new Vector<String>(); 217 218 com.fazecast.jSerialComm.SerialPort[] portIDs = com.fazecast.jSerialComm.SerialPort.getCommPorts(); 219 // find the names of suitable ports 220 for (com.fazecast.jSerialComm.SerialPort portID : portIDs) { 221 portNameVector.addElement(portID.getSystemPortName()); 222 } 223 return portNameVector; 224 } 225 226 /** 227 * Set the control leads and flow control for purejavacomm. This handles any necessary 228 * ordering. 229 * 230 * @param serialPort Port to be updated 231 * @param flow flow control mode from (@link purejavacomm.SerialPort} 232 * @param rts set RTS active if true 233 * @param dtr set DTR active if true 234 */ 235 //@Deprecated(forRemoval=true) // Removed with PureJavaComm 236 protected void configureLeadsAndFlowControl(purejavacomm.SerialPort serialPort, int flow, boolean rts, boolean dtr) { 237 // (Jan 2018) PJC seems to mix termios and ioctl access, so it's not clear 238 // what's preserved and what's not. Experimentally, it seems necessary 239 // to write the control leads, set flow control, and then write the control 240 // leads again. 241 serialPort.setRTS(rts); 242 serialPort.setDTR(dtr); 243 244 try { 245 if (flow != purejavacomm.SerialPort.FLOWCONTROL_NONE) { 246 serialPort.setFlowControlMode(flow); 247 } 248 } catch (purejavacomm.UnsupportedCommOperationException e) { 249 log.warn("Could not set flow control, ignoring"); 250 } 251 if (flow!=purejavacomm.SerialPort.FLOWCONTROL_RTSCTS_OUT) serialPort.setRTS(rts); // not connected in some serial ports and adapters 252 serialPort.setDTR(dtr); 253 } 254 255 /** 256 * Set the baud rate on the port 257 * 258 * @param serialPort Port to be updated 259 * @param baud baud rate to be set 260 */ 261 final protected void setBaudRate(com.fazecast.jSerialComm.SerialPort serialPort, int baud) { 262 serialPort.setBaudRate(baud); 263 } 264 265 /** 266 * Set the control leads. 267 * 268 * @param serialPort Port to be updated 269 * @param rts set RTS active if true 270 * @param dtr set DTR active if true 271 */ 272 final protected void configureLeads(com.fazecast.jSerialComm.SerialPort serialPort, boolean rts, boolean dtr) { 273 if (rts) { 274 serialPort.setRTS(); 275 } else { 276 serialPort.clearRTS(); 277 } 278 if (dtr) { 279 serialPort.setDTR(); 280 } else { 281 serialPort.clearDTR(); 282 } 283 284 } 285 286 /** 287 * Configure the port's parity 288 * 289 * @param serialPort Port to be updated 290 * @param parity the desired parity as one of the define static final constants 291 */ 292 final protected void setParity(com.fazecast.jSerialComm.SerialPort serialPort, Parity parity) { 293 serialPort.setParity(parity.getValue()); // constants are defined with values for the specific port class 294 } 295 296 /** 297 * Enumerate the possible flow control choices 298 */ 299 public enum FlowControl { 300 NONE, 301 RTSCTS, 302 XONXOFF 303 } 304 305 /** 306 * Enumerate the possible parity choices 307 */ 308 public enum Parity { 309 NONE(com.fazecast.jSerialComm.SerialPort.NO_PARITY), 310 EVEN(com.fazecast.jSerialComm.SerialPort.EVEN_PARITY), 311 ODD(com.fazecast.jSerialComm.SerialPort.ODD_PARITY); 312 313 private final int value; 314 315 Parity(int value) { 316 this.value = value; 317 } 318 319 public int getValue() { 320 return value; 321 } 322 } 323 324 /** 325 * Configure the flow control settings. Keep this in synch with the 326 * FlowControl enum. 327 * 328 * @param serialPort Port to be updated 329 * @param flow set which kind of flow control to use 330 */ 331 final protected void setFlowControl(com.fazecast.jSerialComm.SerialPort serialPort, FlowControl flow) { 332 lastFlowControl = flow; 333 334 boolean result = true; 335 336 if (null == flow) { 337 log.error("Invalid null FlowControl enum member"); 338 } else switch (flow) { 339 case RTSCTS: 340 result = serialPort.setFlowControl(com.fazecast.jSerialComm.SerialPort.FLOW_CONTROL_RTS_ENABLED 341 | com.fazecast.jSerialComm.SerialPort.FLOW_CONTROL_CTS_ENABLED ); 342 break; 343 case XONXOFF: 344 result = serialPort.setFlowControl(com.fazecast.jSerialComm.SerialPort.FLOW_CONTROL_XONXOFF_IN_ENABLED 345 | com.fazecast.jSerialComm.SerialPort.FLOW_CONTROL_XONXOFF_OUT_ENABLED); 346 break; 347 case NONE: 348 result = serialPort.setFlowControl(com.fazecast.jSerialComm.SerialPort.FLOW_CONTROL_DISABLED); 349 break; 350 default: 351 log.error("Invalid FlowControl enum member: {}", flow); 352 break; 353 } 354 355 if (!result) log.error("Port did not accept flow control setting {}", flow); 356 } 357 358 private FlowControl lastFlowControl = FlowControl.NONE; 359 /** 360 * get the flow control mode back from the actual port. 361 * @param serialPort Port to be examined 362 * @return flow control setting observed in the port 363 */ 364 final protected FlowControl getFlowControl(com.fazecast.jSerialComm.SerialPort serialPort) { 365 // do a cross-check, just in case there's an issue 366 int nowFlow = serialPort.getFlowControlSettings(); 367 368 switch (lastFlowControl) { 369 370 case NONE: 371 if (nowFlow != com.fazecast.jSerialComm.SerialPort.FLOW_CONTROL_DISABLED) 372 log.error("Expected flow {} but found {}", lastFlowControl, nowFlow); 373 break; 374 case RTSCTS: 375 if (nowFlow != (com.fazecast.jSerialComm.SerialPort.FLOW_CONTROL_RTS_ENABLED 376 | com.fazecast.jSerialComm.SerialPort.FLOW_CONTROL_CTS_ENABLED)) 377 log.error("Expected flow {} but found {}", lastFlowControl, nowFlow); 378 break; 379 case XONXOFF: 380 if (nowFlow != (com.fazecast.jSerialComm.SerialPort.FLOW_CONTROL_XONXOFF_IN_ENABLED 381 | com.fazecast.jSerialComm.SerialPort.FLOW_CONTROL_XONXOFF_OUT_ENABLED)) 382 log.error("Expected flow {} but found {}", lastFlowControl, nowFlow); 383 break; 384 default: 385 log.warn("Unexpected FlowControl mode: {}", lastFlowControl); 386 } 387 388 return lastFlowControl; 389 } 390 391 /** 392 * Add a data listener to the specified port 393 * @param serialPort Port to be updated 394 * @param serialPortDataListener the listener to add 395 */ 396 final protected void setDataListener(com.fazecast.jSerialComm.SerialPort serialPort,com.fazecast.jSerialComm.SerialPortDataListener serialPortDataListener){ 397 currentSerialPort.addDataListener(serialPortDataListener); 398 } 399 400 /** 401 * Cleanly close the specified port 402 * @param serialPort Port to be closed 403 */ 404 final protected void closeSerialPort(com.fazecast.jSerialComm.SerialPort serialPort){ 405 serialPort.closePort(); 406 } 407 408 /** 409 * Set the flow control for purejavacomm, while also setting RTS and DTR to active. 410 * 411 * @param serialPort Port to be updated 412 * @param flow flow control mode from (@link purejavacomm.SerialPort} 413 */ 414 //@Deprecated(forRemoval=true) // with PureJavaComm 415 final protected void configureLeadsAndFlowControl(purejavacomm.SerialPort serialPort, int flow) { 416 configureLeadsAndFlowControl(serialPort, flow, true, true); 417 } 418 419 /** 420 * Report the connection status. 421 * Typically used after the connection is complete 422 * @param log The low-level logger to get this reported against the right class 423 * @param portName low-level name of selected port 424 */ 425 final protected void reportPortStatus(org.slf4j.Logger log, String portName) { 426 if (log.isInfoEnabled()) { 427 log.info("Port {} {} opened at {} baud, sees DTR: {} RTS: {} DSR: {} CTS: {} DCD: {} flow: {}", 428 portName, currentSerialPort.getDescriptivePortName(), 429 currentSerialPort.getBaudRate(), currentSerialPort.getDTR(), 430 currentSerialPort.getRTS(), currentSerialPort.getDSR(), currentSerialPort.getCTS(), 431 currentSerialPort.getDCD(), getFlowControl(currentSerialPort)); 432 } 433 if (log.isDebugEnabled()) { 434 String stopBits; 435 switch (currentSerialPort.getNumStopBits()) { 436 case com.fazecast.jSerialComm.SerialPort.TWO_STOP_BITS: 437 stopBits = "2"; 438 break; 439 case com.fazecast.jSerialComm.SerialPort.ONE_STOP_BIT: 440 stopBits = "1"; 441 break; 442 default: 443 stopBits = "unknown"; 444 break; 445 } 446 log.debug(" {} data bits, {} stop bits", 447 currentSerialPort.getNumDataBits(), stopBits); 448 } 449 450 } 451 452 453 // When PureJavaComm is removed, set this to 'final' to find 454 // identical implementations in the subclasses - but note simulators are now overriding 455 @Override 456 public DataInputStream getInputStream() { 457 if (!opened) { 458 log.error("getInputStream called before open, stream not available"); 459 return null; 460 } 461 return new DataInputStream(currentSerialPort.getInputStream()); 462 } 463 464 // When PureJavaComm is removed, set this to 'final' to find 465 // identical implementations in the subclasses - but note simulators are now overriding 466 @Override 467 public DataOutputStream getOutputStream() { 468 if (!opened) { 469 log.error("getOutputStream called before open, stream not available"); 470 } 471 472 return new DataOutputStream(currentSerialPort.getOutputStream()); 473 } 474 475 476 /** 477 * {@inheritDoc} 478 */ 479 @Override 480 final public void configureBaudRate(String rate) { 481 mBaudRate = rate; 482 } 483 484 /** 485 * {@inheritDoc} 486 */ 487 @Override 488 final public void configureBaudRateFromNumber(String indexString) { 489 int baudNum; 490 int index = 0; 491 final String[] rates = validBaudRates(); 492 final int[] numbers = validBaudNumbers(); 493 if ((numbers == null) || (numbers.length == 0)) { // simulators return null TODO for SpotBugs make that into an empty array 494 mBaudRate = null; 495 log.debug("no serial port speed values received (OK for simulator)"); 496 return; 497 } 498 if (numbers.length != rates.length) { 499 mBaudRate = null; 500 log.error("arrays wrong length in currentBaudNumber: {}, {}", numbers.length, rates.length); 501 return; 502 } 503 if (indexString.isEmpty()) { 504 mBaudRate = null; // represents "(none)" 505 log.debug("empty baud rate received"); 506 return; 507 } 508 try { 509 // since 4.16 first try to convert loaded value directly to integer 510 baudNum = Integer.parseInt(indexString); // new storage format, will throw ex on old format 511 log.debug("new profile format port speed value"); 512 } catch (NumberFormatException ex) { 513 // old pre 4.15.8 format is i18n string including thousand separator and whatever suffix like "18,600 bps (J1)" 514 log.warn("old profile format port speed value converted"); 515 // filter only numerical characters from indexString 516 StringBuilder baudNumber = new StringBuilder(); 517 boolean digitSeen = false; 518 for (int n = 0; n < indexString.length(); n++) { 519 if (Character.isDigit(indexString.charAt(n))) { 520 digitSeen = true; 521 baudNumber.append(indexString.charAt(n)); 522 } else if ((indexString.charAt(n) == ' ') && digitSeen) { 523 break; // break on first space char encountered after at least 1 digit was found 524 } 525 } 526 if (baudNumber.toString().equals("")) { // no number found in indexString e.g. "(automatic)" 527 baudNum = 0; 528 } else { 529 try { 530 baudNum = Integer.parseInt(baudNumber.toString()); 531 } catch (NumberFormatException e2) { 532 mBaudRate = null; // represents "(none)" 533 log.error("error in filtering old profile format port speed value"); 534 return; 535 } 536 log.debug("old format baud number: {}", indexString); 537 } 538 } 539 // fetch baud rate description from validBaudRates[] array copy and set 540 for (int i = 0; i < numbers.length; i++) { 541 if (numbers[i] == baudNum) { 542 index = i; 543 log.debug("found new format baud value at index {}", i); 544 break; 545 } 546 } 547 mBaudRate = validBaudRates()[index]; 548 log.debug("mBaudRate set to: {}", mBaudRate); 549 } 550 551 /** 552 * {@inheritDoc} 553 * Invalid indexes are ignored. 554 */ 555 @Override 556 final public void configureBaudRateFromIndex(int index) { 557 if (validBaudRates().length > index && index > -1 ) { 558 mBaudRate = validBaudRates()[index]; 559 log.debug("mBaudRate set by index to: {}", mBaudRate); 560 } else { 561 // expected for simulators extending serialPortAdapter, mBaudRate already null 562 log.debug("no baud rate index {} in array size {}", index, validBaudRates().length); 563 } 564 } 565 566 protected String mBaudRate = null; 567 568 @Override 569 public int defaultBaudIndex() { 570 return -1; 571 } 572 573 /** 574 * {@inheritDoc} 575 */ 576 @Override 577 public String getCurrentBaudRate() { 578 if (mBaudRate == null) { 579 return ""; 580 } 581 return mBaudRate; 582 } 583 584 /** 585 * {@inheritDoc} 586 */ 587 @Override 588 final public String getCurrentBaudNumber() { 589 int[] numbers = validBaudNumbers(); 590 String[] rates = validBaudRates(); 591 if (numbers == null || rates == null || numbers.length != rates.length) { // entries in arrays should correspond 592 return ""; 593 } 594 String baudNumString = ""; 595 // first try to find the configured baud rate value 596 if (mBaudRate != null) { 597 for (int i = 0; i < numbers.length; i++) { 598 if (rates[i].equals(mBaudRate)) { 599 baudNumString = Integer.toString(numbers[i]); 600 break; 601 } 602 } 603 } else if (defaultBaudIndex() > -1) { 604 // use default 605 baudNumString = Integer.toString(numbers[defaultBaudIndex()]); 606 log.debug("using default port speed {}", baudNumString); 607 } 608 log.debug("mBaudRate = {}, matched to string {}", mBaudRate, baudNumString); 609 return baudNumString; 610 } 611 612 @Override 613 final public int getCurrentBaudIndex() { 614 if (mBaudRate != null) { 615 String[] rates = validBaudRates(); 616 // find the configured baud rate value 617 for (int i = 0; i < rates.length; i++) { 618 if (rates[i].equals(mBaudRate)) { 619 return i; 620 } 621 } 622 } 623 return defaultBaudIndex(); // default index or -1 if port speed not supported 624 } 625 626 /** 627 * {@inheritDoc} 628 */ 629 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "PZLA_PREFER_ZERO_LENGTH_ARRAYS", 630 justification = "null signals incorrect implementation of portcontroller") 631 @Override 632 public String[] validBaudRates() { 633 log.error("default validBaudRates implementation should not be used", new Exception()); 634 return null; 635 } 636 637 /** 638 * {@inheritDoc} 639 */ 640 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "PZLA_PREFER_ZERO_LENGTH_ARRAYS", 641 justification = "null signals incorrect implementation of portcontroller") 642 @Override 643 public int[] validBaudNumbers() { 644 log.error("default validBaudNumbers implementation should not be used", new Exception()); 645 return null; 646 } 647 648 /** 649 * Convert a baud rate I18N String to an int number, e.g. "9,600 baud" to 9600. 650 * <p> 651 * Uses the validBaudNumbers() and validBaudRates() methods to do this. 652 * 653 * @param currentBaudRate a rate from validBaudRates() 654 * @return baudrate as integer if available and matching first digits in currentBaudRate, 655 * 0 if baudrate not supported by this adapter, 656 * -1 if no match (configuration system should prevent this) 657 */ 658 final public int currentBaudNumber(String currentBaudRate) { 659 String[] rates = validBaudRates(); 660 int[] numbers = validBaudNumbers(); 661 662 // return if arrays invalid 663 if (numbers == null) { 664 log.error("numbers array null in currentBaudNumber()"); 665 return -1; 666 } 667 if (rates == null) { 668 log.error("rates array null in currentBaudNumber()"); 669 return -1; 670 } 671 if (numbers.length != rates.length) { 672 log.error("arrays are of different length in currentBaudNumber: {} vs {}", numbers.length, rates.length); 673 return -1; 674 } 675 if (numbers.length < 1) { 676 log.warn("baudrate is not supported by adapter"); 677 return 0; 678 } 679 // find the baud rate value 680 for (int i = 0; i < numbers.length; i++) { 681 if (rates[i].equals(currentBaudRate)) { 682 return numbers[i]; 683 } 684 } 685 686 // no match 687 log.error("no match to ({}) in currentBaudNumber", currentBaudRate); 688 return -1; 689 } 690 691 /** 692 * Set event logging. 693 * @param port Serial port to configure 694 */ 695 //@Deprecated(forRemoval=true) // with PureJavaComm 696 protected void setPortEventLogging(purejavacomm.SerialPort port) { 697 // arrange to notify later 698 try { 699 port.addEventListener(new purejavacomm.SerialPortEventListener() { 700 @Override 701 public void serialEvent(purejavacomm.SerialPortEvent e) { 702 int type = e.getEventType(); 703 switch (type) { 704 case purejavacomm.SerialPortEvent.DATA_AVAILABLE: 705 log.info("SerialEvent: DATA_AVAILABLE is {}", e.getNewValue()); // NOI18N 706 return; 707 case purejavacomm.SerialPortEvent.OUTPUT_BUFFER_EMPTY: 708 log.info("SerialEvent: OUTPUT_BUFFER_EMPTY is {}", e.getNewValue()); // NOI18N 709 return; 710 case purejavacomm.SerialPortEvent.CTS: 711 log.info("SerialEvent: CTS is {}", e.getNewValue()); // NOI18N 712 return; 713 case purejavacomm.SerialPortEvent.DSR: 714 log.info("SerialEvent: DSR is {}", e.getNewValue()); // NOI18N 715 return; 716 case purejavacomm.SerialPortEvent.RI: 717 log.info("SerialEvent: RI is {}", e.getNewValue()); // NOI18N 718 return; 719 case purejavacomm.SerialPortEvent.CD: 720 log.info("SerialEvent: CD is {}", e.getNewValue()); // NOI18N 721 return; 722 case purejavacomm.SerialPortEvent.OE: 723 log.info("SerialEvent: OE (overrun error) is {}", e.getNewValue()); // NOI18N 724 return; 725 case purejavacomm.SerialPortEvent.PE: 726 log.info("SerialEvent: PE (parity error) is {}", e.getNewValue()); // NOI18N 727 return; 728 case purejavacomm.SerialPortEvent.FE: 729 log.info("SerialEvent: FE (framing error) is {}", e.getNewValue()); // NOI18N 730 return; 731 case purejavacomm.SerialPortEvent.BI: 732 log.info("SerialEvent: BI (break interrupt) is {}", e.getNewValue()); // NOI18N 733 return; 734 default: 735 log.info("SerialEvent of unknown type: {} value: {}", type, e.getNewValue()); // NOI18N 736 } 737 } 738 } 739 ); 740 } catch (java.util.TooManyListenersException ex) { 741 log.warn("cannot set listener for SerialPortEvents; was one already set?"); 742 } 743 744 try { 745 port.notifyOnFramingError(true); 746 } catch (Exception e) { 747 log.debug("Could not notifyOnFramingError", e); // NOI18N 748 } 749 750 try { 751 port.notifyOnBreakInterrupt(true); 752 } catch (Exception e) { 753 log.debug("Could not notifyOnBreakInterrupt", e); // NOI18N 754 } 755 756 try { 757 port.notifyOnParityError(true); 758 } catch (Exception e) { 759 log.debug("Could not notifyOnParityError", e); // NOI18N 760 } 761 762 try { 763 port.notifyOnOverrunError(true); 764 } catch (Exception e) { 765 log.debug("Could not notifyOnOverrunError", e); // NOI18N 766 } 767 768 port.notifyOnCarrierDetect(true); 769 port.notifyOnCTS(true); 770 port.notifyOnDSR(true); 771 } 772 773 /** 774 * {@inheritDoc} 775 * Each serial port adapter should handle this and it should be abstract. 776 */ 777 @Override 778 protected void closeConnection(){} 779 780 /** 781 * Re-setup the connection. 782 * Called when the physical connection has reconnected and can be linked to 783 * this connection. 784 * Each port adapter should handle this and it should be abstract. 785 */ 786 @Override 787 protected void resetupConnection(){} 788 789 /** 790 * {@inheritDoc} 791 * Attempts a re-connection to the serial port from the main reconnect 792 * thread. 793 */ 794 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings( value="SLF4J_FORMAT_SHOULD_BE_CONST", 795 justification="I18N of Info Message") 796 //@Deprecated(forRemoval=true) // with purejavacomm 797 @Override 798 protected void reconnectFromLoop(int retryNum){ 799 try { 800 log.info("Retrying Connection attempt {} for {}", retryNum,mPort); 801 Enumeration<purejavacomm.CommPortIdentifier> portIDs = purejavacomm.CommPortIdentifier.getPortIdentifiers(); 802 while (portIDs.hasMoreElements()) { 803 purejavacomm.CommPortIdentifier id = portIDs.nextElement(); 804 // filter out line printers 805 if (id.getPortType() != purejavacomm.CommPortIdentifier.PORT_PARALLEL) // accumulate the names in a vector 806 { 807 if (id.getName().equals(mPort)) { 808 log.info(Bundle.getMessage("ReconnectPortReAppear", mPort)); 809 openPort(mPort, "jmri"); 810 } 811 } 812 } 813 if (retryNum % 10==0) { 814 log.info(Bundle.getMessage("ReconnectSerialTip")); 815 } 816 } catch (RuntimeException e) { 817 log.warn(Bundle.getMessage("ReconnectFail",(mPort == null ? "null" : mPort))); 818 819 } 820 } 821 822 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(AbstractSerialPortController.class); 823 824}