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