View Javadoc

1   /*
2    * Copyright 2007-2008 Volker Fritzsch
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License. 
15   */
16  package motej;
17  
18  import java.io.IOException;
19  import java.util.HashSet;
20  import java.util.Set;
21  
22  import javax.bluetooth.BluetoothStateException;
23  import javax.bluetooth.DeviceClass;
24  import javax.bluetooth.DiscoveryAgent;
25  import javax.bluetooth.DiscoveryListener;
26  import javax.bluetooth.LocalDevice;
27  import javax.bluetooth.RemoteDevice;
28  import javax.bluetooth.ServiceRecord;
29  import javax.swing.event.EventListenerList;
30  
31  import org.slf4j.Logger;
32  import org.slf4j.LoggerFactory;
33  
34  import com.intel.bluetooth.BlueCoveConfigProperties;
35  
36  /**
37   * 
38   * <p>
39   * @author Volker Fritzsch
40   * @author Christoph Krichenbauer
41   */
42  public class MoteFinder {
43  	
44  	// initialization on demand holder idiom
45  	private static class SingletonHolder {
46  		
47  		private static final MoteFinder INSTANCE = new MoteFinder();
48  		
49  	}
50  	
51  	/**
52  	 * Returns the <code>WiimoteFinder</code> instance.
53  	 * 
54  	 * @return WiimoteFinder
55  	 */
56  	public static MoteFinder getMoteFinder() {
57  		try {
58  			// disable PSM minimum flag because the wiimote has a PSM below 0x1001
59  			System.setProperty(BlueCoveConfigProperties.PROPERTY_JSR_82_PSM_MINIMUM_OFF, "true");
60  
61  			SingletonHolder.INSTANCE.localDevice = LocalDevice.getLocalDevice();
62  			SingletonHolder.INSTANCE.discoveryAgent = SingletonHolder.INSTANCE.localDevice.getDiscoveryAgent();
63  			return SingletonHolder.INSTANCE;
64  		} catch (BluetoothStateException ex) {
65  			throw new RuntimeException(ex);
66  		}
67  	}
68  
69  	private Logger log = LoggerFactory.getLogger(MoteFinder.class);
70  	
71  	private EventListenerList listenerList = new EventListenerList();
72  	
73  	private DiscoveryAgent discoveryAgent;
74  	
75  	private Set<String> bluetoothAddressCache = new HashSet<String>();
76  	
77  	private Set<DiscoveryListener> discoveryListeners;
78  	
79  	public void addDiscoveryListener(DiscoveryListener listener) {
80  		if (discoveryListeners == null) {
81  			discoveryListeners = new HashSet<DiscoveryListener>();
82  		}
83  		
84  		discoveryListeners.add(listener);
85  	}
86  	
87  	public void removeDiscoveryListener(DiscoveryListener listener) {
88  		if (discoveryListeners != null) {
89  			discoveryListeners.remove(listener);
90  		}
91  	}
92  
93  	protected final DiscoveryListener listener = new DiscoveryListener() {
94  		
95  		public void deviceDiscovered(final RemoteDevice device, DeviceClass clazz) {
96  			if (log.isInfoEnabled()) {
97  				try {
98  					log.info("found device: " + device.getFriendlyName(true)
99  							+ " - " + device.getBluetoothAddress() + " - "
100 							+ clazz.getMajorDeviceClass() + ":"
101 							+ clazz.getMinorDeviceClass() + " - "
102 							+ clazz.getServiceClasses());
103 				} catch (IOException ex) {
104 					log.error(ex.getMessage(), ex);
105 					throw new RuntimeException(ex);
106 				}
107 			}
108 
109 			try {
110 				if (!device.getFriendlyName(true).startsWith("Nintendo")) { //("Nintendo RVL-CNT-01") != 0) {
111 					return;
112 				}
113 			} catch (IOException ex) {
114 				log.error(ex.getMessage(), ex);
115 				throw new RuntimeException(ex);
116 			}
117 
118 			final String address = device.getBluetoothAddress();
119 			
120 			// is this already registered?
121 			if (!bluetoothAddressCache.contains(address)) {
122 				Thread connectThread = new Thread("connect: " + address) {
123 					public void run() {
124 						Mote mote = new Mote(address);
125 						fireMoteFound(mote);
126 						bluetoothAddressCache.add(address);
127 					};
128 				};
129 				connectThread.start();
130 				
131 				for (DiscoveryListener delegate : discoveryListeners) {
132 					delegate.deviceDiscovered(device, clazz);
133 				}
134 			}
135 		}
136 
137 		public void inquiryCompleted(int discType) {
138 			if (discType == DiscoveryListener.INQUIRY_COMPLETED) {
139 				if (log.isInfoEnabled()) {
140 					log.info("inquiry completed");
141 				}
142 			}
143 
144 			if (discType == DiscoveryListener.INQUIRY_TERMINATED) {
145 				if (log.isInfoEnabled()) {
146 					log.info("inquiry terminated");
147 				}
148 			}
149 			
150 			if (discType == DiscoveryListener.INQUIRY_ERROR) {
151 				if (log.isInfoEnabled()) {
152 					log.info("inquiry error");
153 				}
154 			}
155 			
156 			for (DiscoveryListener delegate : discoveryListeners) {
157 				delegate.inquiryCompleted(discType);
158 			}
159 		}
160 
161 		public void servicesDiscovered(int transID, ServiceRecord[] servRecord) {
162 			// internally unused
163 			
164 			for (DiscoveryListener delegate : discoveryListeners) {
165 				delegate.servicesDiscovered(transID, servRecord);
166 			}
167 		}
168 
169 		public void serviceSearchCompleted(int transID, int respCode) {
170 			// internally unused
171 			
172 			for (DiscoveryListener delegate : discoveryListeners) {
173 				delegate.serviceSearchCompleted(transID, respCode);
174 			}
175 		}
176 	};
177 
178 	private LocalDevice localDevice;
179 
180 	private MoteFinder() {};
181 
182 	public void addMoteFinderListener(MoteFinderListener listener) {
183 		listenerList.add(MoteFinderListener.class, listener);
184 	}
185 	
186 	protected void fireMoteFound(Mote mote) {
187 		MoteFinderListener[] listeners = listenerList.getListeners(MoteFinderListener.class);
188 		for (MoteFinderListener l : listeners) {
189 			l.moteFound(mote);
190 		}
191 	}
192 
193 	public void removeMoteFinderListener(MoteFinderListener listener) {
194 		listenerList.remove(MoteFinderListener.class, listener);
195 	}
196 	
197 	public void startDiscovery() {
198 		try {
199 			discoveryAgent.startInquiry(DiscoveryAgent.GIAC, listener);
200 		} catch (BluetoothStateException ex) {
201 			throw new RuntimeException(ex);
202 		}
203 	}
204 	
205 	public void stopDiscovery() {
206 		discoveryAgent.cancelInquiry(listener);
207 	}
208 
209 }