Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/synchrona/jred/irlap/IrLAPFramer.java


1   /*
2   **************************************************************************
3   ** $Header: /cvsroot/jred/jred/src/com/synchrona/jred/irlap/IrLAPFramer.java,v 1.1.1.1 2000/07/05 04:41:52 mpatters Exp $
4   **
5   ** Copyright (C) 2000 Synchrona, Inc. All rights reserved.
6   **
7   ** This file is part of JRed, a 100% Java implementation of the IrDA
8   ** infrared communications protocols.
9   **
10  ** This file may be distributed under the terms of the Synchrona Public
11  ** License as defined by Synchrona, Inc. and appearing in the file
12  ** LICENSE included in the packaging of this file. The Synchrona Public
13  ** License is based on the Q Public License as defined by Troll Tech AS
14  ** of Norway; it differs only in its use of the courts of Florida, USA
15  ** rather than those of Oslo, Norway.
16  **************************************************************************
17  */
18  package com.synchrona.jred.irlap;
19  
20  import com.synchrona.util.Log;
21  import java.io.DataInputStream;
22  import java.io.DataOutputStream;
23  import javax.comm.SerialPort;
24  
25  public class IrLAPFramer implements Runnable {
26    private static final byte COMMAND_DISCONNECT          = (byte) 0x43;
27    private static final byte BROADCAST_ADDRESS           = (byte) 0xFE;
28    private static final int  COMM_PARAMETER_ARRAY_LENGTH = 21;
29    private static final byte FINAL_SLOT                  = (byte) 0xFF;
30    private static final byte INFORMATION_FORMAT          = (byte) 0x00;
31    private static final byte IRLAP_VERSION               = (byte) 0x00;
32    private static final byte MASK_CR_BIT                 = (byte) 0x01;
33    private static final byte MASK_NR_BITS                = (byte) 0xE0;
34    private static final byte MASK_NS_BITS                = (byte) 0x0E;
35    private static final byte MASK_PF_BIT                 = (byte) 0x10;
36    private static final byte MASK_SUPERVISORY_CONTROLS   = (byte) 0x0F;
37    private static final byte RR_CONTROL                  = (byte) 0x01;
38    private static final byte SNRM_COMMAND                = (byte) 0x83;
39    private static final byte SUPERVISORY_FORMAT          = (byte) 0x01;
40    private static final byte UA_RESPONSE                 = (byte) 0x63;
41    private static final byte UNNUMBERED_FORMAT           = (byte) 0x03;
42    private static final byte XID_COMMAND                 = (byte) 0x2F;
43    private static final byte XID_FORMAT                  = (byte) 0x01;
44    private static final byte XID_RESPONSE                = (byte) 0xAF;
45  
46    private byte []              m_ayCommParameters;
47    private byte []              m_ayOutputFrame;
48    private boolean              m_bDoLogging;
49    private iIrLAPFramerListener m_listener;
50    private Log                  m_log;
51    private SerialPort           m_port;
52    private iFrameWrapper        m_wrapper;
53  
54    public IrLAPFramer(Log log, SerialPort port) throws Exception {
55      m_ayCommParameters = new byte[COMM_PARAMETER_ARRAY_LENGTH];
56      m_ayOutputFrame    = new byte[AsyncFrameWrapper.MAX_FRAME_LENGTH];
57      m_bDoLogging       = false;
58      m_listener         = null;
59      m_log              = log;
60      m_port             = port;
61  
62      // default IrLAP serial parameters
63      m_port.setSerialPortParams(Integer.getInteger("portSpeed", 9600).intValue(),
64                                 SerialPort.DATABITS_8,
65                                 SerialPort.STOPBITS_1,
66                                 SerialPort.PARITY_NONE);
67      // readFrame() needs to block while data is unavailable
68      m_port.disableReceiveThreshold();
69      m_port.disableReceiveTimeout();
70  
71      m_port.setRTS(true);
72      m_port.setDTR(false);
73  
74      m_wrapper = new AsyncFrameWrapper(log,
75                                        new DataInputStream(port.getInputStream()),
76                                        new DataOutputStream(port.getOutputStream()));
77  
78    }
79  
80    public void addIrLAPFramerListener(iIrLAPFramerListener listener) throws Exception {
81      if ( null != m_listener ) {
82        throw new Exception("This IrLAPFramer already has a listener.");
83      } else {
84        m_listener = listener;
85      }
86    }
87  
88    public void initialize() {
89      m_port.setRTS(true);
90      m_port.setDTR(false);
91    }
92  
93    public void run() {
94      boolean bContinue = true;
95      byte [] ayFrame   = new byte[AsyncFrameWrapper.MAX_FRAME_LENGTH];
96  
97      while ( bContinue ) {
98        try {
99          int nBytesRead = readFrame(ayFrame);
100         if ( nBytesRead > 0 ) {
101           dispatchFrame(ayFrame, nBytesRead);
102         }
103       } catch ( Exception e ) {
104         System.err.println(e);
105         e.printStackTrace(System.err);
106       }
107     }
108   }
109 
110   public void sendI(byte yConnection, int nNr, int nNs, boolean bFinal, byte [] ayData, int nOffset, int nLength) throws Exception {
111     m_log.debug("IrLAPFramer", "sendI Nr=" + nNr + " Ns=" + nNs);
112     int nPosition = 0;
113 
114     m_ayOutputFrame[nPosition++] = (byte) (yConnection << 1);
115     m_ayOutputFrame[nPosition++] = (byte) ((nNr << 5 ) | (bFinal ? 0x10 : 0x00) | (nNs << 1));
116     for ( int i = 0; i < nLength; i++ ) {
117       m_ayOutputFrame[nPosition++] = ayData[nOffset + i];
118     }
119     
120     m_wrapper.send(m_ayOutputFrame, 0, nPosition);
121   }
122 
123   public void sendRR(byte yConnection, int nNr, boolean bCommand, boolean bFinal) throws Exception {
124     m_log.debug("IrLAPFramer", "sendRR");
125     int nPosition = 0;
126 
127     m_ayOutputFrame[nPosition++] = (byte) ((yConnection << 1) | ( bCommand ? 0x01 : 0x00 ));
128     m_ayOutputFrame[nPosition++] = (byte) ((nNr << 5 ) | (bFinal ? 0x10 : 0x00) | RR_CONTROL);
129 
130     m_wrapper.send(m_ayOutputFrame, 0, nPosition);
131   }
132 
133   public void sendSNRM(int nSource, int nDestination, byte yConnection) throws Exception {
134     m_log.debug("IrLAPFramer", "sendSNRM");
135     int nPosition = 0;
136 
137     m_ayOutputFrame[nPosition++] = (byte) (BROADCAST_ADDRESS | MASK_CR_BIT);
138     m_ayOutputFrame[nPosition++] = (byte) (SNRM_COMMAND | MASK_PF_BIT);
139 
140     nPosition = intToBytes(m_ayOutputFrame, nPosition, nSource);
141     nPosition = intToBytes(m_ayOutputFrame, nPosition, nDestination);
142 
143     m_ayOutputFrame[nPosition++] = (byte) ((yConnection << 1) & 0xFE);
144 
145     m_ayOutputFrame[nPosition++] = (byte) 0x01; // (1) baud rate
146     m_ayOutputFrame[nPosition++] = (byte) 0x01; // data is 1 byte in length
147     m_ayOutputFrame[nPosition++] = (byte) 0x02; // 9600 bps
148 
149     m_ayOutputFrame[nPosition++] = (byte) 0x82; // (2) max turnaround time
150     m_ayOutputFrame[nPosition++] = (byte) 0x01; // data is 1 byte in length
151     m_ayOutputFrame[nPosition++] = (byte) 0x01; // data is 1 byte in length
152 
153     m_ayOutputFrame[nPosition++] = (byte) 0x83; // (3) data size
154     m_ayOutputFrame[nPosition++] = (byte) 0x01; // data is 1 byte in length
155     m_ayOutputFrame[nPosition++] = (byte) 0x01; // 500ms
156 
157     m_ayOutputFrame[nPosition++] = (byte) 0x84; // (4) window size
158     m_ayOutputFrame[nPosition++] = (byte) 0x01; // data is 1 byte in length
159     m_ayOutputFrame[nPosition++] = (byte) 0x01; // stop-and-wait; 1 frame/window
160 
161     m_ayOutputFrame[nPosition++] = (byte) 0x85; // (5) additional BOF's
162     m_ayOutputFrame[nPosition++] = (byte) 0x01; // data is 1 byte in length
163     m_ayOutputFrame[nPosition++] = (byte) 0x01; // 48 BOF's @ 115200
164 
165     m_ayOutputFrame[nPosition++] = (byte) 0x86; // (6) min turnaround time
166     m_ayOutputFrame[nPosition++] = (byte) 0x01; // data is 1 byte in length
167     m_ayOutputFrame[nPosition++] = (byte) 0x01; // 3 seconds
168 
169     m_ayOutputFrame[nPosition++] = (byte) 0x08; // (7) link disconnect time
170     m_ayOutputFrame[nPosition++] = (byte) 0x01; // data is 1 byte in length
171     m_ayOutputFrame[nPosition++] = (byte) 0x80; // 40 seconds
172 
173     m_wrapper.send(m_ayOutputFrame, 0, nPosition);
174   }
175 
176   public void sendUA(int nSource, int nDestination, byte yConnection, boolean bSendParameters) throws Exception {
177     m_log.debug("IrLAPFramer", "sendUA");
178 
179     int nPosition = 0;
180 
181     m_ayOutputFrame[nPosition++] = (byte) ((yConnection << 1) & 0xFE);
182     m_ayOutputFrame[nPosition++] = (byte) (UA_RESPONSE | MASK_PF_BIT);
183 
184     nPosition = intToBytes(m_ayOutputFrame, nPosition, nSource);
185     nPosition = intToBytes(m_ayOutputFrame, nPosition, nDestination);
186 
187     if ( bSendParameters ) {
188       for ( int i =0; i < m_ayCommParameters.length; i++ ) {
189         m_ayOutputFrame[nPosition++] = m_ayCommParameters[i];
190       }
191     }
192 
193     m_wrapper.send(m_ayOutputFrame, 0, nPosition);
194   }
195 
196   public void sendXID(int nSource, int nDestination, boolean bCommand, byte ySlot, byte [] ayDiscoveryInfo) throws Exception {
197     m_log.debug("IrLAPFramer", "sendXID");
198     int nPosition = 0;
199     
200     if ( bCommand ) {
201       m_ayOutputFrame[nPosition++] = (byte) (BROADCAST_ADDRESS | MASK_CR_BIT);
202       m_ayOutputFrame[nPosition++] = (byte) (XID_COMMAND | MASK_PF_BIT);
203     } else {
204       m_ayOutputFrame[nPosition++] = BROADCAST_ADDRESS;
205       m_ayOutputFrame[nPosition++] = (byte) (XID_RESPONSE | MASK_PF_BIT);
206     }
207     m_ayOutputFrame[nPosition++] = XID_FORMAT;
208   
209     m_ayOutputFrame[nPosition++] = (byte) ((nSource & 0xFF000000) >>> 24);
210     m_ayOutputFrame[nPosition++] = (byte) ((nSource & 0x00FF0000) >>> 16);
211     m_ayOutputFrame[nPosition++] = (byte) ((nSource & 0x0000FF00) >>> 8);
212     m_ayOutputFrame[nPosition++] = (byte) ((nSource & 0x000000FF));
213   
214     m_ayOutputFrame[nPosition++] = (byte) ((nDestination & 0xFF000000) >>> 24);
215     m_ayOutputFrame[nPosition++] = (byte) ((nDestination & 0x00FF0000) >>> 16);
216     m_ayOutputFrame[nPosition++] = (byte) ((nDestination & 0x0000FF00) >>> 8);
217     m_ayOutputFrame[nPosition++] = (byte) ((nDestination & 0x000000FF));
218   
219     // Flag field tells how many slots per discovery; 0x01 means 6 and
220     // is what PalmOS devices do.
221     m_ayOutputFrame[nPosition++] = (byte) 0x01;
222     m_ayOutputFrame[nPosition++] = ySlot;
223     m_ayOutputFrame[nPosition++] = IRLAP_VERSION;
224   
225     m_log.debug("IrLAPFramer", "FINAL_SLOT " + FINAL_SLOT + " ySlot " + ySlot + " disco length " + ayDiscoveryInfo.length);
226 
227     // Plug in discovery hints
228     if ( FINAL_SLOT == ySlot ) {
229       for ( int i = 0; i < ayDiscoveryInfo.length; i++ ) {
230         m_ayOutputFrame[nPosition++] = ayDiscoveryInfo[i];
231       }
232     }
233   
234     m_wrapper.send(m_ayOutputFrame, 0, nPosition);
235   }
236 
237   public void setConnectionParameters(byte [] ayParameters) throws Exception {
238     m_log.debug("IrLAPFramer", "[setConnectionParameters] do nothing for now");
239 
240     int i = 0;
241 
242     m_ayCommParameters[i++] = (byte) 0x01; // (1) baud rate
243     m_ayCommParameters[i++] = (byte) 0x01; // data is 1 byte in length
244     m_ayCommParameters[i++] = (byte) 0x02; // 9600 bps
245 
246     m_ayCommParameters[i++] = (byte) 0x82; // (2) max turnaround time
247     m_ayCommParameters[i++] = (byte) 0x01; // data is 1 byte in length
248     m_ayCommParameters[i++] = (byte) 0x01; // data is 1 byte in length
249 
250     m_ayCommParameters[i++] = (byte) 0x83; // (3) data size
251     m_ayCommParameters[i++] = (byte) 0x01; // data is 1 byte in length
252     m_ayCommParameters[i++] = (byte) 0x01; // 500ms
253 
254     m_ayCommParameters[i++] = (byte) 0x84; // (4) window size
255     m_ayCommParameters[i++] = (byte) 0x01; // data is 1 byte in length
256     m_ayCommParameters[i++] = (byte) 0x01; // stop-and-wait; 1 frame/window
257 
258     m_ayCommParameters[i++] = (byte) 0x85; // (5) additional BOF's
259     m_ayCommParameters[i++] = (byte) 0x01; // data is 1 byte in length
260     m_ayCommParameters[i++] = (byte) 0x01; // 48 BOF's @ 115200
261 
262     m_ayCommParameters[i++] = (byte) 0x86; // (6) min turnaround time
263     m_ayCommParameters[i++] = (byte) 0x01; // data is 1 byte in length
264     m_ayCommParameters[i++] = (byte) 0x01; // 3 seconds
265 
266     m_ayCommParameters[i++] = (byte) 0x08; // (7) link disconnect time
267     m_ayCommParameters[i++] = (byte) 0x01; // data is 1 byte in length
268     m_ayCommParameters[i++] = (byte) 0x80; // 40 seconds
269   }
270 
271   //---------------------------------------------------------------
272   // End public methods
273   //---------------------------------------------------------------
274 
275   private int bytesToInt(byte [] ayBytes, int nOffset) {
276     return   ((ayBytes[nOffset    ] << 24) & 0xFF000000)
277            | ((ayBytes[nOffset + 1] << 16) & 0x00FF0000)
278            | ((ayBytes[nOffset + 2] << 8)  & 0x0000FF00)
279            | ( ayBytes[nOffset + 3]        & 0x000000FF);
280   }
281 
282   private void dispatchFrame(byte [] ayFrame, int nLength) throws Exception {
283     // 0 bit of address field indicates whether this frame is a
284     // command (bit 0 = 1) or a response (bit 0 = 0)
285     byte    yConnection = (byte) (ayFrame[0] >> 1);
286     boolean bCommand    = ((ayFrame[0] & MASK_CR_BIT) != 0) ? true : false;
287     boolean bPoll       = ((ayFrame[1] & MASK_PF_BIT) != 0) ? true : false;
288     byte    yControl    = ayFrame[1];
289     
290     if ( UNNUMBERED_FORMAT == (yControl & UNNUMBERED_FORMAT) ) {
291       switch ( yControl & ~MASK_PF_BIT ) {
292         case SNRM_COMMAND:
293           dispatchSNRM(ayFrame, bCommand, nLength);
294         break;
295         case XID_COMMAND: // fall through
296         case XID_RESPONSE:
297           dispatchXID(ayFrame, bCommand, nLength);
298         break;
299         case COMMAND_DISCONNECT:
300           dispatchDISC(yConnection, bCommand, bPoll, ayFrame, nLength);
301         break;
302         default:
303           m_log.debug("IrLAPFramer", "Unimplemented control: " + (yControl & ~MASK_PF_BIT));
304         break;
305       }
306     } else if ( SUPERVISORY_FORMAT == (yControl & SUPERVISORY_FORMAT) ) {
307       int  nNr         = (yControl & MASK_NR_BITS) >> 5;
308 
309       switch ( yControl & MASK_SUPERVISORY_CONTROLS ) {
310         case RR_CONTROL:
311           dispatchRR(yConnection, nNr, bCommand, bPoll);
312         break;
313         default:
314           m_log.debug("IrLAPFramer", "Unimplemented supervisory control: " + (yControl & MASK_SUPERVISORY_CONTROLS));
315         break;
316       }
317     } else if ( INFORMATION_FORMAT == (yControl & INFORMATION_FORMAT) ) {
318       int  nNr         = (yControl & MASK_NR_BITS) >> 5;
319       int  nNs         = (yControl & MASK_NS_BITS) >> 1;
320 
321       dispatchInformation(yConnection, bCommand, bPoll, nNs, nNr, ayFrame, nLength);
322     }
323   }
324 
325   private void dispatchDISC(byte yConnection, boolean bCommand, boolean bPoll, byte [] ayFrame, int nLength) throws Exception {
326     m_log.debug("IrLAPFramer", "dispatchDISC");
327 
328     if ( m_listener != null ) {
329       m_listener.handleDisconnect(yConnection, bCommand, bPoll);
330     }
331   }
332 
333   private void dispatchInformation(byte yConnection, boolean bCommand, boolean bPoll, int nNs, int nNr, byte [] ayFrame, int nLength) throws Exception {
334     m_log.debug("IrLAPFramer", "dispatchInformation");
335 
336     if ( m_listener != null ) {
337       byte [] ayData = new byte[nLength - 2];
338       for ( int nSource = 2, nDestination = 0; nSource < nLength; nSource++, nDestination++ ) {
339         ayData[nDestination] = ayFrame[nSource];
340       }
341 
342       m_listener.handleData(yConnection, bCommand, nNs, nNr, bPoll, ayData);
343     }
344   }
345 
346   private void dispatchRR(byte yConnection, int nNr, boolean bCommand, boolean bPoll) throws Exception {
347     m_log.debug("IrLAPFramer", "dispatchRR");
348 
349     if ( null != m_listener ) {
350       m_listener.handleRR(yConnection, nNr, bCommand, bPoll);
351     }
352   }
353 
354   private void dispatchSNRM(byte [] ayFrame, boolean bCommand, int nLength) throws Exception {
355     m_log.debug("IrLAPFramer", "dispatchSNRM");
356 
357     if ( null != m_listener ) {
358       int     nSource      = bytesToInt(ayFrame, 2);
359       int     nDestination = bytesToInt(ayFrame, 6);
360       byte    yConnection  = (byte) (ayFrame[10] >>> 1);
361       byte [] ayParameters = new byte[nLength - 11];
362 
363       for ( int i = 0, j = 11; j < nLength; i++, j++ ) {
364         ayParameters[i] = ayFrame[j];
365       }
366 
367       m_listener.handleSNRM(nSource, nDestination, yConnection, ayParameters);
368     }
369   }
370 
371   private void dispatchXID(byte [] ayFrame, boolean bCommand, int nLength) throws Exception {
372     if ( (nLength < 14) || (ayFrame.length < 14) ) {
373       throw new Exception("XID frames must be at least 14 bytes long. (length=" + nLength + ",array length=" + ayFrame.length);
374     }
375 
376     int i = 3; // skip past address, XID command, and format
377     
378 /*
379     if ( ayFrame[i++] != XID_FORMAT ) {
380       //throw new Exception("XID format identifier is supposed to be " + XID_FORMAT + ".");
381       m_log.debug("dispatchXID", "XID format identifier is supposed to be " + XID_FORMAT + ".");
382     }
383 */
384 
385     int nSource = bytesToInt(ayFrame, i);
386     i += 4;
387     m_log.debug("dispatchXID", "source: " + nSource);
388 
389     int nDestination = bytesToInt(ayFrame, i);
390     i += 4;
391     m_log.debug("dispatchXID", "destination: " + nDestination);
392 
393     // TBD: Decode flags. These are okay for PalmOS.
394     byte    yFlags    = ayFrame[i++];
395     byte    yNumSlots = 6;
396     byte    ySlot     = ayFrame[i++];
397     byte    yVersion  = ayFrame[i++];
398     byte [] ayHints   = null;
399 
400     if ( FINAL_SLOT == ySlot ) {
401       m_log.debug("IrLAPFramer", "nLength " + nLength + " i " + i);
402       int nHintLength = nLength - i;
403       if ( nHintLength > 0 ) {
404         ayHints = new byte[nLength - i];
405         for ( int j = 0; j < ayHints.length; j++, i++ ) {
406           ayHints[j] = ayFrame[i];
407         }
408       }
409     }
410 
411     if ( null != m_listener ) {
412       m_listener.handleXID(nSource, nDestination, yNumSlots, ySlot, bCommand, ayHints);
413     }
414   }
415 
416   /**
417    * Write an integer in network order to the given array of bytes at
418    * the given offset.
419    * @return Returns the offset plus the size of an integer (4 bytes)
420    */
421   private int intToBytes(byte [] ayBytes, int nOffset, int nValue) throws Exception {
422     if ( nOffset < 0 ) {
423       throw new Exception("Negative offset.");
424     }
425     if ( (ayBytes.length - nOffset) < 4 ) {
426       throw new Exception("Writing values at this offset would overflow the array bounds.");
427     }
428 
429     ayBytes[nOffset++] = (byte) ((nValue & 0xFF000000) >>> 24);
430     ayBytes[nOffset++] = (byte) ((nValue & 0x00FF0000) >>> 16);
431     ayBytes[nOffset++] = (byte) ((nValue & 0x0000FF00) >>> 8);
432     ayBytes[nOffset++] = (byte) ((nValue & 0x000000FF));
433     
434     return nOffset;
435   }
436 
437   private int readFrame(byte [] ayFrame) throws Exception {
438     int nBytesRead = m_wrapper.receive(ayFrame, 0, ayFrame.length);
439     return nBytesRead;
440   }
441 }