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

Quick Search    Search Deep

Source code: com/synchrona/jred/IrLMP.java


1   /*
2   **************************************************************************
3   ** $Header: /cvsroot/jred/jred/src/com/synchrona/jred/IrLMP.java,v 1.5 2000/07/30 20:18:12 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;
19  
20  import com.synchrona.jred.iIrLMPService;
21  import com.synchrona.jred.IrIAS;
22  import com.synchrona.jred.IrLMPConnection;
23  import com.synchrona.jred.irlap.ConnectionInformation;
24  import com.synchrona.jred.irlap.DiscoveryInformation;
25  import com.synchrona.jred.irlap.iIrLAPListener;
26  import com.synchrona.jred.irlap.IrLAPContext;
27  import com.synchrona.util.Assert;
28  import com.synchrona.util.Log;
29  import com.synchrona.util.Utilities;
30  import java.awt.event.ActionEvent;
31  import java.awt.event.ActionListener;
32  import java.util.Vector;
33  import javax.swing.Timer;
34  
35  /**
36  ** Implement link management as defined in the IrLMP specification.
37  */
38  public class IrLMP implements iIrLAPListener {
39  
40    public static final int    DEFAULT_AUTO_DISCOVERY_INTERVAL  = 300;
41    public static final String AUTO_DISCOVERY_PROPERTY          = "IrLMP.autoDiscovery";
42    public static final String AUTO_DISCOVERY_INTERVAL_PROPERTY = "IrLMP.autoDiscoveryInterval";
43  
44    private static final byte OPCODE_CONNECT_REQUEST = (byte) 0x01;
45    private static final byte OPCODE_CONNECT_CONFIRM = (byte) 0x81;
46  
47    private int          _autoDiscoveryInterval;
48    private Timer        _autoDiscoveryTimer;
49    private byte         _irlapConnection;
50    private IrLAPContext _irlap;
51    private boolean      _doAutoDiscovery;
52    private Log          _log;
53    private Vector       _services;
54  
55    //----------------------------------------------------------------
56    // User-level methods.
57    //----------------------------------------------------------------
58  
59    /**
60    ** 
61    */
62    public IrLMP(Log log) throws Exception{
63      Assert.fail(  log != null, "Log must not be null.");
64  
65      _log      = log;
66      _services = new Vector(10);
67  
68      // IAS is required, and serves at LSAP=0 per the IrLMP spec.
69      IrIAS ias = IrIAS.getInstance();
70      ias.setLog(_log);
71      _services.add(0, ias);
72  
73      configureAutoDiscovery();
74    }
75  
76    /**
77    ** IrLMP allows multiple service providers (IrOBEX, IrCOMM, etc.) to
78    ** listen to a single IrDA port, although only one service is 
79    ** active at a time. This method allows a new service to let IrLMP
80    ** know that it's available.
81    ** <B>This method is broken. It only adds IrOBEX, and does so at
82    ** LSAP 5. This will change when IrIAS is augmented.</B>
83    */
84    public void addService(iIrLMPService service) {
85      for ( int i = 1; i < _services.capacity(); i++ ) {
86        _services.add(service);
87      }
88    }
89  
90    /**
91    ** Instructs IrLMP to enter a discovery sequence, by which other
92    ** IrDA hosts can be found.
93    */
94    public void discover() throws Exception {
95      Assert.fail(_irlap != null, "No IrLAP instance.");
96  
97      if ( _irlap.isMediaBusy() ) {
98        _log.debug("IrLMP", "The IrLAP layer is busy now.");
99      } else {
100       _irlap.startDiscovery();
101     }
102   }
103 
104   /**
105   ** Request a connection with a service on another IrDA host.
106   ** If the request is granted, IrLMP invokes the connect()
107   ** method of the IrLMPService that requested the connection.
108   ** This method cannot be used unless a Host has identified
109   ** itself to us in response to a discovery sequence initiated
110   ** by us, or as a result of our identification to the Host
111   ** during a discovery sequence initiated by the Host.
112   public Connection requestConnection(Host host, int sourceLSAP, int destination LSAP) {
113     return new Connection(this, sourceLSAP, destinationLSAP);
114   }
115   */
116 
117   /**
118   ** If you want IrLMP to be able to initiate things like discovery,
119   ** it needs to hold a reference to an IrLAP instance.
120   */
121   public void setIrLAPContext(IrLAPContext irlap) {
122     _irlap = irlap;
123   }
124 
125   /**
126   ** An IrLMP service (IrOBEX, for instance) has agreed to a connect request
127   ** from a host.
128   */
129   public void connectConfirm(byte destination, byte source, byte [] userData) {
130     _log.debug("IrLMP", "entered connectConfirm");
131     _log.debug("IrLMP", "destination:     " + destination);
132     _log.debug("IrLMP", "source:          " + source);
133 
134     if ( null == _irlap ) {
135       _log.error("IrLMP", "IrLAP is null");
136       return;
137     }
138 
139     byte [] confirmMsg    = new byte[255];
140     int     confirmLength = 0;
141 
142     confirmMsg[confirmLength++] = (byte) (0x80 | destination);
143     confirmMsg[confirmLength++] = source;
144     confirmMsg[confirmLength++] = OPCODE_CONNECT_CONFIRM;
145     confirmMsg[confirmLength++] = (byte) 0x00; // optional 0x00
146 
147     if ( null != userData ) {
148       _log.debug("IrLMP", "userData.length: " + userData.length);
149       for ( int i = 0; i < userData.length; i++ ) {
150         confirmMsg[confirmLength++] = userData[i];
151       }
152     }
153 
154         try {
155       _log.debug("IrLMP", "_irlapConnection: " + _irlapConnection);
156       _log.debug("IrLMP", "confirmLength: "    + confirmLength);
157       _irlap.sendData(_irlapConnection, confirmMsg, 0, confirmLength);
158     } catch ( Exception e ) {
159       _log.debug("IrLMP", "(connectConfirm) " + e);
160     }
161   }
162 
163   //-------------------------------------------------------------
164   // Implement iIrLAPListener
165   //-------------------------------------------------------------
166 
167   /**
168   ** The IrLAP layer has made a connection with another IrLAP layer.
169   */
170   public void connectIndication(IrLAPContext context, ConnectionInformation info) {
171     _log.debug("IrLMP", "connectIndication");
172 
173     try {
174       _irlapConnection  = (byte) info.getConnection();
175       int remoteAddress = info.getRemoteAddress();
176 
177       _log.debug("IrLMP", "_irlapConnection:" + _irlapConnection);
178       _log.debug("IrLMP", "remoteAddress:"    + remoteAddress);
179 
180       context.connectResponse(remoteAddress, _irlapConnection, info.getCommParameters());
181     } catch ( Exception e ) {
182       _log.error("IrLMP", e.toString());
183     }            
184   }
185 
186   /**
187   ** A host has sent data.
188   */
189     public void dataIndication(IrLAPContext context, ConnectionInformation info, byte [] data) {
190      _log.debug("IrLMP", "(dataIndication) data length: " + data.length);
191 
192     // high bit of first byte is set if this is a command
193         boolean isCommand = (0 != (0x80 & data[0]));
194 
195     // destination (us) is the lower 7 bits of the first byte
196         byte destination = (byte) (0x7F & data[0]);
197 
198     // source (them) is the lower 7 bits of the second byte
199         byte source = (byte) (0x7F & data[1]);
200 
201     // opcode is the third byte
202         byte opcode = data[2];
203 
204         _log.debug("IrLMP", "isCommand:   " + isCommand);
205         _log.debug("IrLMP", "destination: " + Utilities.byteToString(destination));
206         _log.debug("IrLMP", "source:      " + Utilities.byteToString(source));
207         _log.debug("IrLMP", "opcode:      " + Utilities.byteToString(opcode));
208 
209     //Assert.fail(destination >= 0,
210     //  "Destination must be >= zero: " + destination);
211     //Assert.fail(destination < (_services.size() - 1),
212     //  "Destination exceeds number of registered services: " + destination);
213 
214     _log.debug("IrLMP", "retrieving service " + destination);
215     iIrLMPService service = (iIrLMPService) _services.get(destination);
216     if ( null == service ) {
217       _log.error("IrLMP", "Destination service is null: " + destination);
218     }
219 
220     _log.debug("IrLMP", "creating IrLMPConnection");
221     IrLMPConnection irlmpConn = new IrLMPConnection(this, destination, source, info);
222 
223     if ( isCommand ) {
224       _log.debug("IrLMP", "processing command");
225 
226       // the high bit of the 2nd (source) byte tells us if this is
227       // a message confirming a connect request
228       boolean isConfirm = (0 != (0x80 & data[2]));
229 
230       // we don't use the parameters right now.
231       byte parameters = data[3];
232 
233       // this is for debugging
234       String message    = "(unknown)";
235 
236       switch ( opcode ) {
237         case OPCODE_CONNECT_REQUEST:
238           message = (isConfirm ? "Connect Confirmation" : "Connect");
239 
240           // frame length - dest - source - opcode - reserved byte
241           byte [] userData = null;
242           if ( data.length > 4 ) {
243             userData = new byte[data.length - 4];
244             for ( int i = 0; i < userData.length; i++ ) {
245               userData[i] = data[i + 4];
246             }
247           }
248           _log.debug("IrLMP", "invoking service's connectRequest()");
249           service.connectRequest(this, destination, source, userData);
250         break;
251         case 2:
252           message = "Disconnect";
253         break;
254         case 3:
255           message = (isConfirm ? "Access Mode (confirm)" : "Access Mode");
256         break;
257       }
258     } else {
259       try {
260         _log.debug("IrLMP", "invoking service's serviceRequest()");
261         service.serviceRequest(this, irlmpConn, data, 0, data.length);
262       } catch ( Exception e ) {
263         _log.error("IrLMP", "Caught this " + e);
264       }
265     }
266   }
267 
268   /**
269   ** A host has been discovered.
270   */
271     public void discoveryIndication(IrLAPContext context, DiscoveryInformation discoveryInfo) {
272     _log.debug("IrLMP", "Host discovered: " + discoveryInfo);
273   }
274 
275   protected void sendData(int destination, int source, byte[] data, int offset, int length)
276   throws Exception {
277     _log.debug("IrLMP", "(sendData) destination: " + destination + " source: " + source);
278     send(destination, source, data, offset, length);
279   }
280 
281   /**
282   ** Send data to a host to whom we are connected.
283   */
284   public void send(int destination, int source, byte[] data, int offset, int length)
285   throws Exception {
286     _log.debug("IrLMP", "(send) destination: " + destination + " source: " + source);
287     Assert.fail(null != _irlap, "IrLAP is null.");
288 
289     try {
290       byte [] frame = new byte[2 + length];
291       frame[0]      = (byte) destination;
292       frame[1]      = (byte) source;
293       for ( int i = 0; i < length; i++ ) {
294         frame[i + 2] = data[offset + i];
295       }
296 
297       _irlap.sendData(_irlapConnection, frame, 0, frame.length);
298     } catch ( Exception e ) {
299       _log.debug("IrLMP ", e.toString());
300     }
301   }
302 
303   /**
304   ** @param doAutoDiscovery Autodiscovery is enabled if this value is <CODE>true</CODE>.
305   */
306   public void setAutoDiscovery(boolean doAutoDiscovery) {
307     _doAutoDiscovery = doAutoDiscovery;
308 
309     if ( !_doAutoDiscovery && (null != _autoDiscoveryTimer) ) {
310       _autoDiscoveryTimer.stop();
311     } else {
312       _autoDiscoveryTimer.start();
313     }
314   }
315 
316   /**
317   ** Find out if IrLMP needs to automatically discover other hosts.
318   */
319   private void configureAutoDiscovery() {
320     _doAutoDiscovery = Boolean.getBoolean(AUTO_DISCOVERY_PROPERTY);    
321     _log.debug("IrLMP", "_doAutoDiscovery: " + _doAutoDiscovery);
322 
323     Integer interval = Integer.getInteger(AUTO_DISCOVERY_INTERVAL_PROPERTY);
324     if ( null != interval ) {
325       _autoDiscoveryInterval = interval.intValue();
326     } else {
327       _log.debug("IrLMP", "autoDiscoveryInterval was undefined, using default (300s)");
328       _autoDiscoveryInterval = DEFAULT_AUTO_DISCOVERY_INTERVAL;
329     }
330     _log.debug("IrLMP", "_autoDiscoveryInterval: " + _autoDiscoveryInterval);
331 
332     if ( _doAutoDiscovery ) {
333       _log.debug("IrLMP", "creating autoDiscoveryTimer");
334 
335       _autoDiscoveryTimer = new Timer(_autoDiscoveryInterval * 1000, new ActionListener() {
336         public void actionPerformed(ActionEvent event) {
337           _log.debug("IrLMP", "autoDiscoveryTimer fired");
338           try {
339             discover();
340           } catch ( Exception e ) {
341             _log.error("IrLMP", e.toString());
342           }
343         }
344       });
345       _autoDiscoveryTimer.start();
346     }
347   }
348 }