001package jmri.jmrix.ieee802154.xbee; 002 003import com.digi.xbee.api.connection.ConnectionType; 004import com.digi.xbee.api.connection.IConnectionInterface; 005 006import java.util.Arrays; 007 008import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 009 010import jmri.jmrix.AbstractSerialPortController.SerialPortDataListener; 011 012import org.slf4j.Logger; 013import org.slf4j.LoggerFactory; 014 015/** 016 * Provide access to IEEE802.15.4 devices via a serial com port. 017 * 018 * @author Paul Bender Copyright (C) 2013,2023 019 */ 020public class XBeeAdapter extends jmri.jmrix.ieee802154.serialdriver.SerialDriverAdapter implements IConnectionInterface, SerialPortDataListener { 021 022 private boolean iConnectionOpened = false; 023 024 public XBeeAdapter() { 025 super(new XBeeConnectionMemo()); 026 } 027 028 @Override 029 public String openPort(String portName, String appName) { 030 // get and open the primary port 031 currentSerialPort = activatePort(portName,log); 032 // try to set it for serial 033 setSerialPort(); 034 035 // report status 036 reportPortStatus(log,portName); 037 opened = true; 038 return null; // normal operation 039 } 040 041 /** 042 * Local method to do specific port configuration 043 */ 044 @Override 045 protected void setSerialPort() { 046 log.debug("setSerialPort() called."); 047 // find the baud rate value, configure comm options 048 int baud = currentBaudNumber(mBaudRate); 049 setBaudRate(currentSerialPort,baud); 050 configureLeads(currentSerialPort,true,true); 051 052 // The following are required for the XBee API's input thread. 053 setDataListener(currentSerialPort,this); 054 } 055 056 /** 057 * Set up all of the other objects to operate connected to this port. 058 */ 059 @Override 060 public void configure() { 061 log.debug("configure() called."); 062 XBeeTrafficController tc = new XBeeTrafficController(); 063 064 // connect to the traffic controller 065 this.getSystemConnectionMemo().setTrafficController(tc); 066 tc.setAdapterMemo(this.getSystemConnectionMemo()); 067 tc.connectPort(this); 068 this.getSystemConnectionMemo().configureManagers(); 069 } 070 071 /** 072 * {@inheritDoc} 073 */ 074 @Override 075 public String[] validBaudRates() { 076 return Arrays.copyOf(validSpeeds, validSpeeds.length); 077 } 078 079 /** 080 * {@inheritDoc} 081 */ 082 @Override 083 public int[] validBaudNumbers() { 084 return Arrays.copyOf(validSpeedValues, validSpeedValues.length); 085 } 086 087 @Override 088 public XBeeConnectionMemo getSystemConnectionMemo() { 089 jmri.jmrix.ieee802154.IEEE802154SystemConnectionMemo m = super.getSystemConnectionMemo(); 090 if (m instanceof XBeeConnectionMemo ) { 091 return (XBeeConnectionMemo) m; 092 } else { 093 throw new java.lang.IllegalArgumentException("System Connection Memo associated with this connection is not the right type."); 094 } 095 } 096 097 private final String[] validSpeeds = new String[]{Bundle.getMessage("Baud1200"), 098 Bundle.getMessage("Baud2400"), Bundle.getMessage("Baud4800"), 099 Bundle.getMessage("Baud9600"), Bundle.getMessage("Baud19200"), 100 Bundle.getMessage("Baud38400"), Bundle.getMessage("Baud57600"), 101 Bundle.getMessage("Baud115200")}; 102 private final int[] validSpeedValues = new int[]{1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200}; 103 104 @Override 105 public int defaultBaudIndex() { 106 return 0; 107 } 108 109 // methods for IConnectionInterface 110 111 @Override 112 public void close() { 113 closeSerialPort(currentSerialPort); 114 iConnectionOpened = false; 115 } 116 117 @Override 118 public int readData(byte[] b) throws java.io.IOException { 119 log.debug("read data called with {}", b); 120 return getInputStream().read(b); 121 } 122 123 @Override 124 public int readData(byte[] b,int off, int len) throws java.io.IOException { 125 log.debug("read data called with {} {} {}", b, off, len); 126 return getInputStream().read(b,off,len); 127 } 128 129 @Override 130 public void writeData(byte[] b) throws java.io.IOException { 131 log.debug("write data called with {}", b); 132 getOutputStream().write(b); 133 } 134 135 @Override 136 public void writeData(byte[] b,int off, int len) throws java.io.IOException { 137 log.debug("write data called with {} {} {}", b, off, len); 138 getOutputStream().write(b,off,len); 139 } 140 141 @Override 142 public boolean isOpen(){ 143 log.debug("isOpen called"); 144 return ( iConnectionOpened ); 145 } 146 147 @Override 148 public void open(){ 149 log.debug("open called"); 150 iConnectionOpened = true; 151 // don't do anything here. We handle the details of open through the 152 // openPort call, which is called from the JMRI infrastructure. 153 } 154 155 @Override 156 public ConnectionType getConnectionType() { 157 return ConnectionType.UNKNOWN; 158 } 159 160 // SerialPortEventListener methods 161 @Override 162 public int getListeningEvents() { 163 return SerialPort.LISTENING_EVENT_DATA_AVAILABLE; 164 } 165 166 @SuppressFBWarnings(value = {"NN_NAKED_NOTIFY"}, justification="The notify call is notifying the receive thread that data is available due to an event.") 167 @Override 168 public void serialEvent(SerialPortEvent serialPortEvent) { 169 if (serialPortEvent.getEventType() != SerialPort.LISTENING_EVENT_DATA_AVAILABLE) 170 return; 171 synchronized (this) { 172 this.notifyAll(); 173 } 174 } 175 176 private final static Logger log = LoggerFactory.getLogger(XBeeAdapter.class); 177 178}