1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package motej;
17
18 import java.io.IOException;
19 import java.util.concurrent.ConcurrentLinkedQueue;
20
21 import javax.bluetooth.L2CAPConnection;
22 import javax.microedition.io.Connector;
23
24 import motej.request.MoteRequest;
25 import motej.request.PlayerLedRequest;
26 import motej.request.RumbleRequest;
27
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30
31
32
33
34
35
36 class OutgoingThread extends Thread {
37
38 private static final long THREAD_SLEEP = 10l;
39
40 private Logger log = LoggerFactory.getLogger(OutgoingThread.class);
41
42 private volatile boolean active;
43
44 private L2CAPConnection outgoing;
45
46 private volatile ConcurrentLinkedQueue<MoteRequest> requestQueue;
47
48 private byte ledByte;
49
50 private long rumbleMillis = Long.MIN_VALUE;
51
52 private Mote source;
53
54 protected OutgoingThread(Mote source, String btaddress) throws IOException, InterruptedException {
55 super("out:" + btaddress);
56
57 this.source = source;
58
59 String l2cap = "btl2cap://"
60 + btaddress
61 + ":11;authenticate=false;encrypt=false;master=false";
62
63 if (log.isDebugEnabled()) {
64 log.debug("Opening outgoing connection to " + l2cap);
65 }
66
67 outgoing = (L2CAPConnection) Connector.open(l2cap, Connector.WRITE, true);
68
69 if (log.isDebugEnabled()) {
70 log.debug("Outgoing connection is " + outgoing.toString());
71 }
72
73 requestQueue = new ConcurrentLinkedQueue<MoteRequest>();
74 Thread.sleep(THREAD_SLEEP);
75 active = true;
76 }
77
78 public void disconnect() {
79 active = false;
80 }
81
82 public void run() {
83 while (active || !requestQueue.isEmpty()) {
84 try {
85 if (rumbleMillis > 0) {
86 rumbleMillis -= THREAD_SLEEP;
87 }
88 if (rumbleMillis == 0) {
89 rumbleMillis = Long.MIN_VALUE;
90 outgoing.send(RumbleRequest.getStopRumbleBytes(ledByte));
91 Thread.sleep(THREAD_SLEEP);
92 continue;
93 }
94 if (!requestQueue.isEmpty()) {
95 MoteRequest request = requestQueue.poll();
96 if (request instanceof PlayerLedRequest) {
97 ledByte = ((PlayerLedRequest) request).getLedByte();
98 }
99 if (request instanceof RumbleRequest) {
100 ((RumbleRequest)request).setLedByte(ledByte);
101 rumbleMillis = ((RumbleRequest) request).getMillis();
102 }
103
104 if (log.isTraceEnabled()) {
105 byte[] buf = request.getBytes();
106 StringBuffer sb = new StringBuffer();
107 log.trace("sending:");
108 for (int i = 0; i < buf.length; i++) {
109 String hex = Integer.toHexString(buf[i] & 0xff);
110 sb.append(hex.length() == 1 ? "0x0" : "0x").append(hex).append(" ");
111 if ((i + 1) % 8 == 0) {
112 log.trace(sb.toString());
113 sb.delete(0, sb.length());
114 }
115 }
116 if (sb.length() > 0) {
117 log.trace(sb.toString());
118 }
119 }
120
121 outgoing.send(request.getBytes());
122 }
123 Thread.sleep(THREAD_SLEEP);
124 } catch (InterruptedException ex) {
125 ex.printStackTrace();
126 } catch (IOException ex) {
127 log.error("connection closed?", ex);
128 active = false;
129 source.fireMoteDisconnectedEvent();
130 }
131 }
132 try {
133 outgoing.close();
134 } catch (IOException ex) {
135 log.error(ex.getMessage(), ex);
136 }
137 }
138
139 public void sendRequest(MoteRequest request) {
140 requestQueue.add(request);
141 }
142
143 }