1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package motej;
17
18 import javax.swing.event.EventListenerList;
19
20 import motej.event.AccelerometerEvent;
21 import motej.event.AccelerometerListener;
22 import motej.event.CoreButtonEvent;
23 import motej.event.CoreButtonListener;
24 import motej.event.DataEvent;
25 import motej.event.DataListener;
26 import motej.event.ExtensionEvent;
27 import motej.event.ExtensionListener;
28 import motej.event.IrCameraEvent;
29 import motej.event.IrCameraListener;
30 import motej.event.MoteDisconnectedEvent;
31 import motej.event.MoteDisconnectedListener;
32 import motej.event.StatusInformationListener;
33 import motej.request.CalibrationDataRequest;
34 import motej.request.PlayerLedRequest;
35 import motej.request.RawByteRequest;
36 import motej.request.ReadRegisterRequest;
37 import motej.request.ReportModeRequest;
38 import motej.request.RumbleRequest;
39 import motej.request.StatusInformationRequest;
40 import motej.request.WriteRegisterRequest;
41
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45
46
47
48
49
50 public class Mote {
51
52 private Logger log = LoggerFactory.getLogger(Mote.class);
53
54 private OutgoingThread outgoing;
55
56 private IncomingThread incoming;
57
58 private ExtensionProvider extensionProvider = new ExtensionProvider();
59
60 private Extension currentExtension;
61
62 private StatusInformationReport statusInformationReport;
63
64 private CalibrationDataReport calibrationDataReport;
65
66 private EventListenerList listenerList = new EventListenerList();
67
68 private String bluetoothAddress;
69
70 public Mote(String bluetoothAddress) {
71 try {
72 this.bluetoothAddress = bluetoothAddress;
73
74
75 addMoteDisconnectedListener(new MoteDisconnectedListener<Mote>(){
76 public void moteDisconnected(MoteDisconnectedEvent<Mote> evt) {
77
78
79 disconnect();
80 }
81 });
82
83 outgoing = new OutgoingThread(this, bluetoothAddress);
84 incoming = new IncomingThread(this, bluetoothAddress);
85
86 incoming.start();
87 outgoing.start();
88
89 outgoing.sendRequest(new StatusInformationRequest());
90 outgoing.sendRequest(new CalibrationDataRequest());
91 } catch (Exception ex) {
92 throw new RuntimeException(ex.fillInStackTrace());
93 }
94 }
95
96 public void addAccelerometerListener(AccelerometerListener<Mote> listener) {
97 listenerList.add(AccelerometerListener.class, listener);
98 }
99
100 public void addCoreButtonListener(CoreButtonListener listener) {
101 listenerList.add(CoreButtonListener.class, listener);
102 }
103
104 public void addDataListener(DataListener listener) {
105 listenerList.add(DataListener.class, listener);
106 }
107
108 public void addExtensionListener(ExtensionListener listener) {
109 listenerList.add(ExtensionListener.class, listener);
110 }
111
112 public void addIrCameraListener(IrCameraListener listener) {
113 listenerList.add(IrCameraListener.class, listener);
114 }
115
116 public void addMoteDisconnectedListener(MoteDisconnectedListener<Mote> listener) {
117 listenerList.add(MoteDisconnectedListener.class, listener);
118 }
119
120 public void addStatusInformationListener(StatusInformationListener listener) {
121 listenerList.add(StatusInformationListener.class, listener);
122 }
123
124 public void disableIrCamera() {
125
126 outgoing.sendRequest(new RawByteRequest(new byte[] { 82, 19, 0 }));
127
128
129 outgoing.sendRequest(new RawByteRequest(new byte[] { 82, 26, 0 }));
130 }
131
132 public void disconnect() {
133 if (log.isInfoEnabled()) {
134 log.info("Disconnecting mote " + bluetoothAddress);
135 }
136 if (outgoing != null) {
137 outgoing.disconnect();
138 try {
139 outgoing.join(5000l);
140 } catch (InterruptedException ex) {
141 log.error(ex.getMessage(), ex);
142 }
143 }
144 if (incoming != null) {
145 incoming.disconnect();
146 try {
147 incoming.join(5000l);
148 } catch (InterruptedException ex) {
149 log.error(ex.getMessage(), ex);
150 }
151 }
152 }
153
154
155
156
157 public void enableIrCamera() {
158 enableIrCamera(IrCameraMode.BASIC, IrCameraSensitivity.WII_LEVEL_3);
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 public void enableIrCamera(IrCameraMode mode, IrCameraSensitivity sensitivity) {
186
187 outgoing.sendRequest(new RawByteRequest(new byte[] { 82, 0x13, 0x06 }));
188
189
190 outgoing.sendRequest(new RawByteRequest(new byte[] { 82, 0x1a, 0x06 }));
191
192
193 outgoing.sendRequest(new WriteRegisterRequest(new byte[] { (byte) 0xb0,
194 0x00, 0x30 }, new byte[] { 0x01 }));
195
196
197 outgoing.sendRequest(new WriteRegisterRequest(new byte[] { (byte) 0xb0,
198 0x00, 0x00 }, sensitivity.block1()));
199
200
201 outgoing.sendRequest(new WriteRegisterRequest(new byte[] { (byte) 0xb0,
202 0x00, 0x1a }, sensitivity.block2()));
203
204
205 outgoing.sendRequest(new WriteRegisterRequest(new byte[] { (byte) 0xb0,
206 0x00, 0x33 }, new byte[] { mode.modeAsByte() }));
207
208
209 outgoing.sendRequest(new WriteRegisterRequest(new byte[] { (byte) 0xb0,
210 0x00, 0x30 }, new byte[] { 0x08 }));
211 }
212
213 @Override
214 public boolean equals(Object obj) {
215 if (!(obj instanceof Mote))
216 return false;
217
218 return hashCode() == obj.hashCode();
219 }
220
221 @SuppressWarnings("unchecked")
222 protected void fireMoteDisconnectedEvent() {
223 MoteDisconnectedListener<Mote>[] listeners = listenerList.getListeners(MoteDisconnectedListener.class);
224 MoteDisconnectedEvent<Mote> evt = new MoteDisconnectedEvent<Mote>(this);
225 for (MoteDisconnectedListener<Mote> l : listeners) {
226 l.moteDisconnected(evt);
227 }
228 }
229
230 @SuppressWarnings("unchecked")
231 protected void fireAccelerometerEvent(int x, int y, int z) {
232 AccelerometerListener<Mote>[] listeners = listenerList.getListeners(AccelerometerListener.class);
233 AccelerometerEvent<Mote> evt = new AccelerometerEvent<Mote>(this, x, y, z);
234 for (AccelerometerListener<Mote> l : listeners) {
235 l.accelerometerChanged(evt);
236 }
237 }
238
239 protected void fireCoreButtonEvent(int modifiers) {
240 CoreButtonListener[] listeners = listenerList.getListeners(CoreButtonListener.class);
241 CoreButtonEvent evt = new CoreButtonEvent(this, modifiers);
242 for (CoreButtonListener l : listeners) {
243 l.buttonPressed(evt);
244 }
245 }
246
247 protected void fireExtensionConnectedEvent() {
248 ExtensionListener[] listeners = listenerList.getListeners(ExtensionListener.class);
249 ExtensionEvent evt = new ExtensionEvent(this, currentExtension);
250 for (ExtensionListener l : listeners) {
251 l.extensionConnected(evt);
252 }
253 }
254
255 protected void fireExtensionDisconnectedEvent() {
256 ExtensionListener[] listeners = listenerList.getListeners(ExtensionListener.class);
257 ExtensionEvent evt = new ExtensionEvent(this);
258 for (ExtensionListener l : listeners) {
259 l.extensionDisconnected(evt);
260 }
261 }
262
263 protected void fireIrCameraEvent(IrCameraMode mode, IrPoint p0, IrPoint p1, IrPoint p2, IrPoint p3) {
264 IrCameraListener[] listeners = listenerList.getListeners(IrCameraListener.class);
265 IrCameraEvent evt = new IrCameraEvent(this, mode, p0, p1, p2, p3);
266 for (IrCameraListener l : listeners) {
267 l.irImageChanged(evt);
268 }
269 }
270
271 protected void fireReadDataEvent(byte[] address, byte[] payload, int error) {
272 if (calibrationDataReport == null && error == 0 && address[0] == 0x00 && address[1] == 0x20) {
273
274 if (log.isDebugEnabled()) {
275 log.debug("Received Calibration Data Report.");
276 }
277 CalibrationDataReport report = new CalibrationDataReport(payload[0] & 0xff, payload[1] & 0xff, payload[2] & 0xff,
278 payload[4] & 0xff, payload[5] & 0xff, payload[6] & 0xff);
279 calibrationDataReport = report;
280 }
281
282 if (currentExtension == null && error == 0 && address[0] == 0x00 && (address[1] & 0xff) == 0xfe && payload.length == 2) {
283
284 if (log.isDebugEnabled()) {
285 String id0 = Integer.toHexString(payload[0] & 0xff);
286 String id1 = Integer.toHexString(payload[1] & 0xff);
287 log.debug("Received Extension ID: " + (id0.length() == 1 ? "0x0" + id0 : "0x" + id0) + " " + (id1.length() == 1 ? "0x0" + id1 : "0x" + id1));
288 }
289
290 if ((payload[0] & 0xff) == 0xff
291 && (payload[1] & 0xff) == 0xff) {
292 log.debug("Connection not completed, re-requesting extension id.");
293 outgoing.sendRequest(new ReadRegisterRequest(new byte[] { (byte) 0xa4, 0x00, (byte) 0xfe }, new byte[] { 0x00, 0x02 }));
294 } else {
295
296 currentExtension = extensionProvider.getExtension(payload);
297 if (log.isInfoEnabled()) {
298 log.info("Found extension: " + currentExtension == null ? "null" : currentExtension.toString());
299 }
300 if (currentExtension != null) {
301 currentExtension.setMote(this);
302 currentExtension.initialize();
303 incoming.setExtension(currentExtension);
304 fireExtensionConnectedEvent();
305 }
306 }
307 }
308
309 DataListener[] listeners = listenerList.getListeners(DataListener.class);
310 DataEvent evt = new DataEvent(address, payload, error);
311 for (DataListener l : listeners) {
312 l.dataRead(evt);
313 }
314 }
315
316 protected void fireStatusInformationChangedEvent(StatusInformationReport report) {
317
318
319 boolean extensionChanged;
320 if (statusInformationReport == null) {
321 extensionChanged = report.isExtensionControllerConnected();
322 } else {
323 extensionChanged = statusInformationReport.isExtensionControllerConnected() != report.isExtensionControllerConnected();
324 }
325
326 statusInformationReport = report;
327 StatusInformationListener[] listeners = listenerList.getListeners(StatusInformationListener.class);
328 for (StatusInformationListener l : listeners) {
329 l.statusInformationReceived(report);
330 }
331
332 if (extensionChanged) {
333 if (!report.isExtensionControllerConnected()) {
334 currentExtension = null;
335 fireExtensionDisconnectedEvent();
336 } else {
337
338 outgoing.sendRequest(new WriteRegisterRequest(new byte[] { (byte) 0xa4, 0x00, 0x40 }, new byte[] { 0x00 }));
339
340
341 outgoing.sendRequest(new ReadRegisterRequest(new byte[] { (byte) 0xa4, 0x00, (byte) 0xfe }, new byte[] { 0x00, 0x02 }));
342 }
343 }
344 }
345
346 public String getBluetoothAddress() {
347 return bluetoothAddress;
348 }
349
350 public CalibrationDataReport getCalibrationDataReport() {
351 return calibrationDataReport;
352 }
353
354 public StatusInformationReport getStatusInformationReport() {
355 return statusInformationReport;
356 }
357
358 @Override
359 public int hashCode() {
360 return bluetoothAddress.hashCode();
361 }
362
363 public void removeAccelerometerListener(AccelerometerListener<Mote> listener) {
364 listenerList.remove(AccelerometerListener.class, listener);
365 }
366
367 public void removeCoreButtonListener(CoreButtonListener listener) {
368 listenerList.remove(CoreButtonListener.class, listener);
369 }
370
371 public void removeDataListener(DataListener listener) {
372 listenerList.remove(DataListener.class, listener);
373 }
374
375 public void removeExtensionListener(ExtensionListener listener) {
376 listenerList.remove(ExtensionListener.class, listener);
377 }
378
379 public void removeIrCameraListener(IrCameraListener listener) {
380 listenerList.remove(IrCameraListener.class, listener);
381 }
382
383 public void remoteMoteDisconnectedListener(MoteDisconnectedListener<Mote> listener) {
384 listenerList.remove(MoteDisconnectedListener.class, listener);
385 }
386
387 public void removeStatusInformationListener(StatusInformationListener listener) {
388 listenerList.remove(StatusInformationListener.class, listener);
389 }
390
391 public void requestStatusInformation() {
392 outgoing.sendRequest(new StatusInformationRequest());
393 }
394
395 public void rumble(long millis) {
396 outgoing.sendRequest(new RumbleRequest(millis));
397 }
398
399 public void setPlayerLeds(boolean[] leds) {
400 outgoing.sendRequest(new PlayerLedRequest(leds));
401 }
402
403 public void setReportMode(byte mode) {
404 outgoing.sendRequest(new ReportModeRequest(mode));
405 }
406
407 public void setReportMode(byte mode, boolean continuous) {
408 outgoing.sendRequest(new ReportModeRequest(mode, continuous));
409 }
410
411 public void readRegisters(byte[] offset, byte[] size) {
412 outgoing.sendRequest(new ReadRegisterRequest(offset, size));
413 }
414
415 public void writeRegisters(byte[] offset, byte[] payload) {
416 outgoing.sendRequest(new WriteRegisterRequest(offset, payload));
417 }
418
419 @SuppressWarnings("unchecked")
420 public <T extends Extension> T getExtension() {
421 return (T) currentExtension;
422 }
423
424 @Override
425 public String toString() {
426 return "Mote[" + bluetoothAddress + "]";
427 }
428 }