1 package org.lsst.ccs.drivers.ftdi;
2
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.io.OutputStream;
6 import java.net.ServerSocket;
7 import java.net.Socket;
8 import java.util.concurrent.ArrayBlockingQueue;
9 import java.util.logging.Level;
10 import java.util.logging.Logger;
11 import org.lsst.ccs.utilities.conv.Convert;
12
13
14
15
16
17
18
19
20
21
22 public class FtdiServer extends Thread {
23
24
25
26
27
28
29
30
31 final static int
32 SERVER_PORT = 9001,
33 MAGIC_NUMBER = 0x71e5f39c,
34
35 FUNC_EXCEPTION = 0,
36 FUNC_OPEN = 1,
37 FUNC_CLOSE = 2,
38 FUNC_READ = 3,
39 FUNC_WRITE = 4,
40 FUNC_TIMEOUTS = 5,
41 FUNC_BAUDRATE = 6,
42 FUNC_DATACHAR = 7,
43 FUNC_QUEUESTAT = 8,
44 FUNC_MODEMSTAT = 9,
45
46 POSN_MAGIC = 0,
47 POSN_LENGTH = POSN_MAGIC + 4,
48 POSN_FUNCTION = POSN_LENGTH + 2,
49 POSN_CONTEXT = POSN_FUNCTION + 2,
50 POSN_DATA = POSN_CONTEXT + 2,
51 POSN_EXCPTEXT = POSN_DATA,
52 POSN_INDEX = POSN_DATA,
53 POSN_SERIAL = POSN_INDEX + 4,
54 POSN_READLENG = POSN_DATA,
55 POSN_READDATA = POSN_DATA,
56 POSN_WRITEDATA = POSN_DATA,
57 POSN_WRITELENG = POSN_DATA,
58 POSN_RCVETMO = POSN_DATA,
59 POSN_XMITTMO = POSN_RCVETMO + 4,
60 POSN_BAUDRATE = POSN_DATA,
61 POSN_WORDLENG = POSN_DATA,
62 POSN_STOPBITS = POSN_WORDLENG + 4,
63 POSN_PARITY = POSN_STOPBITS + 4,
64 POSN_QUEUESTAT = POSN_DATA,
65 POSN_MODEMSTAT = POSN_DATA;
66
67
68
69
70
71
72
73
74 private final static Logger log = Logger.getLogger("ftdiServer");
75 private Socket cliSock;
76 private InputStream cliIn;
77 private OutputStream cliOut;
78 private FtdiLocal ftdi = new FtdiLocal();
79 private ArrayBlockingQueue<byte[]> readQ = new ArrayBlockingQueue(2);
80
81
82
83
84
85
86
87
88
89 private class Reader extends Thread {
90
91 @Override
92 public void run()
93 {
94 IOException excp = null;
95 while (true) {
96 byte[] rqst;
97 try {
98 rqst = readQ.take();
99 }
100 catch (InterruptedException e) {
101 break;
102 }
103 try {
104 int leng = Convert.bytesToInt(rqst, POSN_READLENG);
105 byte[] data = new byte[leng];
106 int nread = ftdi.read(data);
107 byte[] reply = new byte[POSN_READDATA + nread];
108 System.arraycopy(data, 0, reply, POSN_READDATA, nread);
109 send(rqst, reply);
110 }
111 catch (FtdiException ef) {
112 try {
113 sendException(rqst, ef);
114 }
115 catch (IOException ei) {
116 excp = ei;
117 break;
118 }
119 }
120 catch (IOException ei) {
121 excp = ei;
122 break;
123 }
124 }
125
126 if (excp != null) {
127 if (closeNetSilent()) {
128 log.warning(excp.toString());
129 }
130 try {
131 ftdi.close();
132 }
133 catch (FtdiException e) {
134 }
135 }
136 }
137
138 }
139
140
141
142
143
144
145
146
147
148 public FtdiServer(Socket sock) throws IOException
149 {
150 cliSock = sock;
151 cliIn = sock.getInputStream();
152 cliOut = sock.getOutputStream();
153 }
154
155
156
157
158
159
160
161
162
163 public static void main(String[] args) throws IOException
164 {
165 log.setLevel(Level.INFO);
166 log.info("Started server");
167 ServerSocket sSock = new ServerSocket(SERVER_PORT, 10);
168 while (true) {
169 Socket sock = sSock.accept();
170 FtdiServer srvr = new FtdiServer(sock);
171 srvr.setDaemon(true);
172 srvr.start();
173 }
174 }
175
176
177
178
179
180
181
182
183
184 @Override
185 public void run()
186 {
187 String client = cliSock.getInetAddress().getHostName();
188 int port = cliSock.getPort();
189 log.info("Opened connection to " + client + ":" + port);
190 Reader rdr = new Reader();
191 rdr.setDaemon(true);
192 rdr.start();
193 IOException excp = null;
194 boolean running = true;
195
196 while (running) {
197 byte rqst[] = null;
198 try {
199 byte reply[];
200 rqst = receive();
201 int rLeng = Convert.bytesToShort(rqst, POSN_LENGTH);
202 int func = Convert.bytesToShort(rqst, POSN_FUNCTION);
203
204 switch (func) {
205
206 case FUNC_OPEN:
207 int index = Convert.bytesToInt(rqst, POSN_INDEX);
208 String serial = null;
209 if (rLeng > POSN_SERIAL) {
210 serial = new String(rqst, POSN_SERIAL,
211 rLeng - POSN_SERIAL);
212 }
213 ftdi.open(index, serial);
214 sendAck(rqst);
215 break;
216
217 case FUNC_CLOSE:
218 ftdi.close();
219 closeNet();
220 running = false;
221 break;
222
223 case FUNC_READ:
224 readQ.offer(rqst);
225 break;
226
227 case FUNC_WRITE:
228 int nwrite = ftdi.write(rqst, POSN_WRITEDATA,
229 rLeng - POSN_WRITEDATA);
230 reply = new byte[POSN_WRITELENG + 4];
231 Convert.intToBytes(nwrite, reply, POSN_WRITELENG);
232 send(rqst, reply);
233 break;
234
235 case FUNC_TIMEOUTS:
236 int rcveTmo = Convert.bytesToInt(rqst, POSN_RCVETMO);
237 int xmitTmo = Convert.bytesToInt(rqst, POSN_XMITTMO);
238 ftdi.setTimeouts(rcveTmo, xmitTmo);
239 sendAck(rqst);
240 break;
241
242 case FUNC_BAUDRATE:
243 int baudrate = Convert.bytesToInt(rqst, POSN_BAUDRATE);
244 ftdi.setBaudrate(baudrate);
245 sendAck(rqst);
246 break;
247
248 case FUNC_DATACHAR:
249 int wordleng = Convert.bytesToInt(rqst, POSN_WORDLENG);
250 int stopbits = Convert.bytesToInt(rqst, POSN_STOPBITS);
251 int parity = Convert.bytesToInt(rqst, POSN_PARITY);
252 ftdi.setDataCharacteristics(wordleng, stopbits, parity);
253 sendAck(rqst);
254 break;
255
256 case FUNC_QUEUESTAT:
257 reply = new byte[POSN_QUEUESTAT + 4];
258 Convert.intToBytes(ftdi.getQueueStatus(), reply,
259 POSN_QUEUESTAT);
260 send(rqst, reply);
261 break;
262
263 case FUNC_MODEMSTAT:
264 reply = new byte[POSN_MODEMSTAT + 4];
265 Convert.intToBytes(ftdi.getModemStatus(), reply,
266 POSN_MODEMSTAT);
267 send(rqst, reply);
268 break;
269
270 default:
271 }
272 }
273 catch (FtdiException ef) {
274 try {
275 sendException(rqst, ef);
276 }
277 catch (IOException ei) {
278 excp = ei;
279 running = false;
280 }
281 }
282 catch (IOException ei) {
283 excp = ei;
284 running = false;
285 }
286 }
287
288 if (excp != null) {
289 if (closeNetSilent()) {
290 log.warning(excp.toString());
291 }
292 try {
293 ftdi.close();
294 }
295 catch (FtdiException ef) {
296 }
297 }
298
299 rdr.interrupt();
300 log.info("Closed connection to " + client + ":" + port);
301 }
302
303
304
305
306
307
308
309
310
311 private byte[] receive() throws IOException
312 {
313 byte[] header = new byte[POSN_DATA];
314 int leng = 0, recLeng = header.length;
315 while (leng < recLeng) {
316 int nread = cliIn.read(header, leng, recLeng - leng);
317 if (nread < 0) break;
318 leng += nread;
319 }
320 if (leng < recLeng) {
321 throw new IOException("Client disconnected");
322 }
323 if (Convert.bytesToInt(header, POSN_MAGIC) != MAGIC_NUMBER) {
324 throw new IOException("Invalid magic number");
325 }
326 recLeng = Convert.bytesToShort(header, POSN_LENGTH);
327 byte[] rqst = new byte[recLeng];
328 System.arraycopy(header, 0, rqst, 0, leng);
329 while (leng < recLeng) {
330 int nread = cliIn.read(rqst, leng, recLeng - leng);
331 if (nread < 0) break;
332 leng += nread;
333 }
334 if (leng < recLeng) {
335 throw new IOException("Client disconnected");
336 }
337
338 return rqst;
339 }
340
341
342
343
344
345
346
347
348
349 private void send(byte[] rqst, byte[] reply) throws IOException
350 {
351 Convert.intToBytes(MAGIC_NUMBER, reply, POSN_MAGIC);
352 Convert.shortToBytes((short)reply.length, reply, POSN_LENGTH);
353 System.arraycopy(rqst, POSN_FUNCTION, reply, POSN_FUNCTION, 2);
354 System.arraycopy(rqst, POSN_CONTEXT, reply, POSN_CONTEXT, 2);
355 cliOut.write(reply);
356 }
357
358
359
360
361
362
363
364
365
366 private void sendAck(byte[] rqst) throws IOException
367 {
368 byte[] reply = new byte[POSN_DATA];
369 send(rqst, reply);
370 }
371
372
373
374
375
376
377
378
379
380 private void sendException(byte[] rqst, Exception e) throws IOException
381 {
382 if (rqst == null) return;
383 byte[] text = e.getMessage().getBytes();
384 byte[] reply = new byte[POSN_EXCPTEXT + text.length];
385 System.arraycopy(text, 0, reply, POSN_EXCPTEXT, text.length);
386 Convert.shortToBytes((short)FUNC_EXCEPTION, rqst, POSN_FUNCTION);
387 send(rqst, reply);
388 }
389
390
391
392
393
394
395
396
397
398 private boolean closeNetSilent()
399 {
400 boolean wasOpen = true;
401
402 try {
403 wasOpen = closeNet();
404 }
405 catch (IOException e) {
406 }
407
408 return wasOpen;
409 }
410
411
412
413
414
415
416
417
418
419 private boolean closeNet() throws IOException
420 {
421 boolean wasOpen = false;
422 try {
423 if (cliSock != null) {
424 wasOpen = true;
425 cliSock.close();
426 }
427 }
428 finally {
429 cliSock = null;
430 }
431
432 return wasOpen;
433 }
434
435 }