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.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   * <p>
34   * @author <a href="mailto:vfritzsch@users.sourceforge.net">Volker Fritzsch</a>
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 	}