/
SerialDriverAdapter.java
335 lines (302 loc) · 14.2 KB
/
SerialDriverAdapter.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
package jmri.jmrix.rfid.serialdriver;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import jmri.jmrix.rfid.RfidPortController;
import jmri.jmrix.rfid.RfidProtocol;
import jmri.jmrix.rfid.RfidSystemConnectionMemo;
import jmri.jmrix.rfid.RfidTrafficController;
import jmri.jmrix.rfid.generic.standalone.StandaloneReporterManager;
import jmri.jmrix.rfid.generic.standalone.StandaloneSensorManager;
import jmri.jmrix.rfid.generic.standalone.StandaloneTrafficController;
import jmri.jmrix.rfid.merg.concentrator.ConcentratorReporterManager;
import jmri.jmrix.rfid.merg.concentrator.ConcentratorSensorManager;
import jmri.jmrix.rfid.merg.concentrator.ConcentratorTrafficController;
import jmri.jmrix.rfid.protocol.coreid.CoreIdRfidProtocol;
import jmri.jmrix.rfid.protocol.em18.Em18RfidProtocol;
import jmri.jmrix.rfid.protocol.olimex.OlimexRfid1356mifareProtocol;
import jmri.jmrix.rfid.protocol.olimex.OlimexRfidProtocol;
import jmri.jmrix.rfid.protocol.parallax.ParallaxRfidProtocol;
import jmri.jmrix.rfid.protocol.seeedstudio.SeeedStudioRfidProtocol;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import purejavacomm.CommPortIdentifier;
import purejavacomm.NoSuchPortException;
import purejavacomm.PortInUseException;
import purejavacomm.SerialPort;
import purejavacomm.UnsupportedCommOperationException;
/**
* Provide access to RFID devices via a serial comm port.
* Derived from the Oaktree code.
*
* @author Bob Jacobsen Copyright (C) 2006, 2007, 2008
* @author Matthew Harris Copyright (C) 2011
* @author Oscar A. Pruitt Copyright (C) 2015
* @author B. Milhaupt Copyright (C) 2017
* @since 2.11.4
*/
public class SerialDriverAdapter extends RfidPortController implements jmri.jmrix.SerialPortAdapter {
SerialPort activeSerialPort = null;
public SerialDriverAdapter() {
super(new RfidSystemConnectionMemo());
option1Name = "Adapter"; // NOI18N
option2Name = "Concentrator-Range"; // NOI18N
option3Name = "Protocol"; // NOI18N
option4Name = "Device"; // NOI18N
options.put(option1Name, new Option(Bundle.getMessage("ConnectionAdapter"), new String[]{"Generic Stand-alone", "MERG Concentrator"}, false)); // NOI18N
options.put(option2Name, new Option(Bundle.getMessage("ConnectionConcentratorRange"), new String[]{"A-H", "I-P"}, false)); // NOI18N
options.put(option3Name, new Option(Bundle.getMessage("ConnectionProtocol"), new String[]{"CORE-ID", "Olimex", "Parallax", "SeeedStudio", "EM-18"}, false)); // NOI18N
options.put(option4Name, new Option(Bundle.getMessage("ConnectionDeviceType"), new String[]{"MOD-RFID125", "MOD-RFID1356MIFARE"}, false)); // NOI18N
this.manufacturerName = jmri.jmrix.rfid.RfidConnectionTypeList.RFID;
}
@Override
public String openPort(String portName, String appName) {
try {
// get and open the primary port
CommPortIdentifier portID = CommPortIdentifier.getPortIdentifier(portName);
try {
activeSerialPort = (SerialPort) portID.open(appName, 2000); // name of program, msec to wait
} catch (PortInUseException p) {
return handlePortBusy(p, portName, log);
}
// try to set it for serial
try {
setSerialPort();
} catch (UnsupportedCommOperationException e) {
log.error("Cannot set serial parameters on port {}: {}", portName, e.getMessage()); // NOI18N
return "Cannot set serial parameters on port " + portName + ": " + e.getMessage(); // NOI18N
}
// set framing (end) character
try {
log.debug("Serial framing was observed as: {} {}", activeSerialPort.isReceiveFramingEnabled(), // NOI18N
activeSerialPort.getReceiveFramingByte()); // NOI18N
} catch (Exception ef) {
log.debug("failed to set serial framing: {}", ef); // NOI18N
}
// set timeout; framing should work before this anyway
try {
activeSerialPort.enableReceiveTimeout(10);
log.debug("Serial timeout was observed as: {} {}", activeSerialPort.getReceiveTimeout(), // NOI18N
activeSerialPort.isReceiveTimeoutEnabled()); // NOI18N
} catch (UnsupportedCommOperationException et) {
log.info("failed to set serial timeout: {}", et); // NOI18N
}
// get and save stream
serialStream = activeSerialPort.getInputStream();
// purge contents, if any
purgeStream(serialStream);
// report status?
if (log.isInfoEnabled()) {
// report now
log.info(portName + " port opened at " // NOI18N
+ activeSerialPort.getBaudRate() + " baud with" // NOI18N
+ " DTR: " + activeSerialPort.isDTR() // NOI18N
+ " RTS: " + activeSerialPort.isRTS() // NOI18N
+ " DSR: " + activeSerialPort.isDSR() // NOI18N
+ " CTS: " + activeSerialPort.isCTS() // NOI18N
+ " CD: " + activeSerialPort.isCD() // NOI18N
);
}
if (log.isDebugEnabled()) {
// report additional status
log.debug(" port flow control shows {}", // NOI18N
(activeSerialPort.getFlowControlMode() == SerialPort.FLOWCONTROL_RTSCTS_OUT ? "hardware flow control" : "no flow control")); // NOI18N
// log events
setPortEventLogging(activeSerialPort);
}
opened = true;
} catch (NoSuchPortException p) {
return handlePortNotFound(p, portName, log);
} catch (IOException ex) {
log.error("Unexpected exception while opening port {}", portName, ex);
return "Unexpected error while opening port " + portName + ": " + ex; // NOI18N
}
return null; // normal operation
}
/**
* Can the port accept additional characters?
*
* @return always true
*/
public boolean okToSend() {
return true;
}
/**
* Set up all of the other objects to operate connected to this port
*/
@Override
public void configure() {
RfidTrafficController control;
RfidProtocol protocol;
// set up the system connection first
String opt1 = getOptionState(option1Name);
switch (opt1) {
case "Generic Stand-alone": // NOI18N
// create a Generic Stand-alone port controller
log.debug("Create Generic Standalone SpecificTrafficController"); // NOI18N
control = new StandaloneTrafficController(this.getSystemConnectionMemo());
this.getSystemConnectionMemo().configureManagers(
new StandaloneSensorManager(control, this.getSystemPrefix()),
new StandaloneReporterManager(control, this.getSystemPrefix()));
break;
case "MERG Concentrator": // NOI18N
// create a MERG Concentrator port controller
log.debug("Create MERG Concentrator SpecificTrafficController"); // NOI18N
control = new ConcentratorTrafficController(this.getSystemConnectionMemo(), getOptionState(option2Name));
this.getSystemConnectionMemo().configureManagers(
new ConcentratorSensorManager(control, this.getSystemPrefix()),
new ConcentratorReporterManager(control, this.getSystemPrefix()));
break;
default:
// no connection at all - warn
log.warn("adapter option {} defaults to Generic Stand-alone", opt1); // NOI18N
// create a Generic Stand-alone port controller
control = new StandaloneTrafficController(this.getSystemConnectionMemo());
this.getSystemConnectionMemo().configureManagers(
new StandaloneSensorManager(control, this.getSystemPrefix()),
new StandaloneReporterManager(control, this.getSystemPrefix()));
break;
}
// Now do the protocol
String opt3 = getOptionState(option3Name);
String opt4 = getOptionState(option4Name);
if (opt1.equals("MERG Concentrator")) { // NOI18N
// MERG Concentrator only supports CORE-ID
log.info("set protocol to CORE-ID"); // NOI18N
String opt2 = getOptionState(option2Name);
switch (opt2) {
case "A-H": // NOI18N
log.info("set concentrator range to 'A-H' at position 1"); // NOI18N
protocol = new CoreIdRfidProtocol('A', 'H', 1);
break;
case "I-P": // NOI18N
log.info("set concentrator range to 'I-P' at position 1"); // NOI18N
protocol = new CoreIdRfidProtocol('I', 'P', 1);
break;
default:
// unrecognised concentrator range - warn
log.warn("concentrator range '{}' not supported - default to no concentrator", opt2); // NOI18N
protocol = new CoreIdRfidProtocol();
break;
}
} else {
switch (opt3) {
case "CORE-ID": // NOI18N
log.info("set protocol to CORE-ID"); // NOI18N
protocol = new CoreIdRfidProtocol();
break;
case "Olimex": // NOI18N
if (opt4.equals("MOD-RFID1356MIFARE")) { // NOI18N
log.info("set protocol for Olimex MOD-RFID1356MIFARE"); // NOI18N
protocol = new OlimexRfid1356mifareProtocol();
} else {
log.info("set protocol for Olimex MOD-RFID125"); // NOI18N
protocol = new OlimexRfidProtocol();
}
break;
case "Parallax": // NOI18N
log.info("set protocol to Parallax"); // NOI18N
protocol = new ParallaxRfidProtocol();
break;
case "SeeedStudio": // NOI18N
log.info("set protocol to SeeedStudio"); // NOI18N
protocol = new SeeedStudioRfidProtocol();
break;
case "EM-18": // NOI18N
log.info("set protocol to EM-18"); // NOI18N
protocol = new Em18RfidProtocol();
break;
default:
// no protocol at all - warn
log.warn("protocol option {} defaults to CORE-ID", opt3);
// create a coreid protocol
protocol = new CoreIdRfidProtocol();
break;
}
}
this.getSystemConnectionMemo().setProtocol(protocol);
// connect to the traffic controller
this.getSystemConnectionMemo().setRfidTrafficController(control);
control.setAdapterMemo(this.getSystemConnectionMemo());
control.connectPort(this);
control.sendInitString();
}
// base class methods for the RfidPortController interface
@Override
public DataInputStream getInputStream() {
if (!opened) {
log.error("getInputStream called before load(), stream not available");
return null;
}
return new DataInputStream(serialStream);
}
@Override
public DataOutputStream getOutputStream() {
if (!opened) {
log.error("getOutputStream called before load(), stream not available");
}
try {
return new DataOutputStream(activeSerialPort.getOutputStream());
} catch (java.io.IOException e) {
log.error("getOutputStream exception: {}", e.getMessage());
}
return null;
}
@Override
public boolean status() {
return opened;
}
/**
* Local method to do specific port configuration
*
* @throws UnsupportedCommOperationException if unable to configure port
*/
protected void setSerialPort() throws UnsupportedCommOperationException {
// find the baud rate value, configure comm options
int baud = 9600; // default, but also defaulted in the initial value of selectedSpeed
// the Parallax reader uses 2400 baud, so set that here
if (getOptionState(option3Name).equals("Parallax")) {
log.debug("Set baud rate to 2400 for Parallax reader");
baud = 2400;
}
// check for specific port type
activeSerialPort.setSerialPortParams(baud, SerialPort.DATABITS_8,
SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
// find and configure flow control
int flow = SerialPort.FLOWCONTROL_NONE; // default
if (getOptionState(option1Name).equals("MERG Concentrator")) {
// Set Hardware Flow Control for Concentrator
log.debug("Set hardware flow control for Concentrator");
flow = SerialPort.FLOWCONTROL_RTSCTS_OUT;
}
configureLeadsAndFlowControl(activeSerialPort, flow);
}
@Override
public String[] validBaudRates() {
return Arrays.copyOf(validSpeeds, validSpeeds.length);
}
@Override
public int[] validBaudNumber() {
return Arrays.copyOf(validSpeedValues, validSpeedValues.length);
}
/**
* Set the baud rate.
*
* @param rate the baud rate to set
*/
@Override
public void configureBaudRate(String rate) {
log.debug("configureBaudRate: {}", rate);
selectedSpeed = rate;
super.configureBaudRate(rate);
}
protected String[] validSpeeds = new String[]{Bundle.getMessage("BaudAutomatic")};
protected int[] validSpeedValues = new int[]{9600};
protected String selectedSpeed = validSpeeds[0];
// private control members
private boolean opened = false;
InputStream serialStream = null;
private static final Logger log = LoggerFactory.getLogger(SerialDriverAdapter.class);
}