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