1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 package net.sf.bluecove.awt;
26
27 import java.io.File;
28 import java.io.FileOutputStream;
29 import java.io.IOException;
30 import java.text.SimpleDateFormat;
31 import java.util.Date;
32
33 import javax.bluetooth.L2CAPConnection;
34 import javax.microedition.io.Connection;
35 import javax.microedition.io.Connector;
36 import javax.microedition.io.StreamConnection;
37
38 import org.bluecove.tester.log.Logger;
39 import org.bluecove.tester.util.IOUtils;
40 import org.bluecove.tester.util.RuntimeDetect;
41 import org.bluecove.tester.util.StringUtils;
42 import org.bluecove.tester.util.TimeUtils;
43
44 import net.sf.bluecove.ConnectionHolder;
45 import net.sf.bluecove.ConnectionHolderL2CAP;
46 import net.sf.bluecove.ConnectionHolderStream;
47 import net.sf.bluecove.util.BluetoothTypesInfo;
48
49
50
51
52
53 public class ClientConnectionThread extends Thread {
54
55 Object threadLocalBluetoothStack;
56
57 private static int connectionCount = 0;
58
59 private String serverURL;
60
61 private ConnectionHolder c;
62
63 private boolean stoped = false;
64
65 boolean isRunning = false;
66
67 boolean isConnecting = false;
68
69 long receivedCount = 0;
70
71 long reportedSize = 0;
72
73 long receivedPacketsCount = 0;
74
75 boolean rfcomm;
76
77 public static final int interpretDataChar = 0;
78
79 public static final int interpretDataCharArray = 1;
80
81 public static final int interpretDataStats = 2;
82
83 public static final int interpretDataStatsArray = 3;
84
85 public static final int interpretIgnore = 4;
86
87 int interpretData = interpretDataChar;
88
89 long reported = 0;
90
91 String logPrefix = "";
92
93 private StringBuffer dataBuf = new StringBuffer();
94
95 private boolean binaryData = false;
96
97 private FileOutputStream fileOut;
98
99 ClientConnectionThread(String serverURL) {
100 super("ClientConnectionThread" + (++connectionCount));
101 this.serverURL = serverURL;
102 }
103
104 String getLocalBluetoothId() {
105 if (threadLocalBluetoothStack == null) {
106 return "";
107 } else {
108 return threadLocalBluetoothStack.toString();
109 }
110 }
111
112 public void run() {
113 try {
114 rfcomm = BluetoothTypesInfo.isRFCOMM(serverURL);
115 if (!rfcomm && !BluetoothTypesInfo.isL2CAP(serverURL)) {
116 Logger.error(logPrefix + "unsupported connection type " + serverURL);
117 return;
118 }
119 RuntimeDetect.cldcStub.setThreadLocalBluetoothStack(threadLocalBluetoothStack);
120 Connection conn = null;
121 try {
122 isConnecting = true;
123 Logger.debug(logPrefix + "Connecting:" + serverURL + " ...");
124 conn = Connector.open(serverURL);
125 } catch (IOException e) {
126 Logger.error(logPrefix + "Connection error", e);
127 return;
128 } finally {
129 isConnecting = false;
130 }
131 Logger.info(logPrefix + "Connected");
132 if (rfcomm) {
133 ConnectionHolderStream cs = new ConnectionHolderStream((StreamConnection) conn);
134 c = cs;
135 cs.is = cs.conn.openInputStream();
136 cs.os = cs.conn.openOutputStream();
137 isRunning = true;
138 while (!stoped) {
139 if (interpretData == interpretIgnore) {
140 Thread.sleep(777);
141 } else if ((interpretData == interpretDataCharArray) || (interpretData == interpretDataStatsArray)) {
142 byte b[] = new byte[0xFF];
143 int readLen = cs.is.read(b);
144 if (readLen == -1) {
145 Logger.debug(logPrefix + "EOF recived");
146 break;
147 }
148 receivedCount += readLen;
149 for (int k = 0; k < readLen; k++) {
150 printdataReceivedRFCOMM(b[k]);
151 }
152 } else {
153 int data = cs.is.read();
154 if (data == -1) {
155 Logger.debug(logPrefix + "EOF recived");
156 break;
157 }
158 receivedCount++;
159 printdataReceivedRFCOMM(data);
160 }
161 }
162 if (dataBuf.length() > 0) {
163 Logger.debug(logPrefix + "cc:" + StringUtils.toBinaryText(dataBuf));
164 }
165 } else {
166 ConnectionHolderL2CAP lc = new ConnectionHolderL2CAP((L2CAPConnection) conn);
167 isRunning = true;
168 c = lc;
169 while (!stoped) {
170 if (interpretData == interpretIgnore) {
171 Thread.sleep(777);
172 } else {
173 if ((interpretData != interpretDataCharArray) || (interpretData != interpretDataStatsArray)) {
174 while ((!lc.channel.ready()) && (!stoped)) {
175 Thread.sleep(100);
176 }
177 }
178 if (stoped) {
179 break;
180 }
181 int receiveMTU = lc.channel.getReceiveMTU();
182 byte[] data = new byte[receiveMTU];
183 int length = lc.channel.receive(data);
184 receivedCount += length;
185 receivedPacketsCount++;
186 printdataReceivedL2CAP(data, length);
187 }
188 }
189 }
190 } catch (IOException e) {
191 if (!stoped) {
192 Logger.error(logPrefix + "Communication error", e);
193 } else {
194 Logger.debug(logPrefix + "communication stopped", e);
195 }
196 } catch (Throwable e) {
197 Logger.error(logPrefix + "Error", e);
198 } finally {
199 isRunning = false;
200 if (c != null) {
201 c.shutdown();
202 }
203 closeFile();
204 }
205 }
206
207 private void printdataReceivedRFCOMM(int data) {
208 switch (interpretData) {
209 case interpretDataChar:
210 case interpretDataCharArray:
211 char c = (char) data;
212 if ((!binaryData) && (c < ' ')) {
213 binaryData = true;
214 }
215 dataBuf.append(c);
216 if (((!binaryData) && (c == '\n')) || (dataBuf.length() > 32)) {
217 Logger.debug("cc:" + StringUtils.toBinaryText(dataBuf));
218 dataBuf = new StringBuffer();
219 }
220 break;
221 case interpretDataStatsArray:
222 case interpretDataStats:
223 long now = System.currentTimeMillis();
224 if (now - reported > 5 * 1000) {
225 int size = (int) (receivedCount - reportedSize);
226 reportedSize = receivedCount;
227 Logger.debug(logPrefix + "Received " + receivedCount + " bytes " + TimeUtils.bps(size, reported));
228 reported = now;
229 }
230 break;
231 }
232 synchronized (this) {
233 if (fileOut != null) {
234 try {
235 fileOut.write((char) data);
236 } catch (IOException e) {
237 Logger.debug(logPrefix + "file write error", e);
238 closeFile();
239 }
240 }
241 }
242 }
243
244 private void printdataReceivedL2CAP(byte[] data, int length) {
245 switch (interpretData) {
246 case interpretDataCharArray:
247 case interpretDataChar:
248 int messageLength = length;
249 if ((length > 0) && (data[length - 1] == '\n')) {
250 messageLength = length - 1;
251 }
252 StringBuffer buf = new StringBuffer();
253 buf.append(logPrefix).append("cc:");
254 if (messageLength != 0) {
255 buf.append(StringUtils.toBinaryText(new StringBuffer(new String(data, 0, messageLength))));
256 }
257 buf.append(" (").append(length).append(")");
258 Logger.debug(buf.toString());
259 break;
260 case interpretDataStatsArray:
261 case interpretDataStats:
262 long now = System.currentTimeMillis();
263 if (now - reported > 5 * 1000) {
264 int size = (int) (receivedCount - reportedSize);
265 reportedSize = receivedCount;
266 Logger.debug(logPrefix + "Received " + receivedPacketsCount + " packet(s), " + receivedCount
267 + " bytes " + TimeUtils.bps(size, reported));
268 reported = now;
269 }
270 break;
271 }
272 synchronized (this) {
273 if (fileOut != null) {
274 try {
275 fileOut.write(data, 0, length);
276 } catch (IOException e) {
277 Logger.debug(logPrefix + "file write error", e);
278 closeFile();
279 }
280 }
281 }
282 }
283
284 public void shutdown() {
285 stoped = true;
286 if (c != null) {
287 c.shutdown();
288 }
289 c = null;
290 closeFile();
291 }
292
293 private synchronized void closeFile() {
294 if (fileOut != null) {
295 try {
296 fileOut.flush();
297 } catch (IOException ignore) {
298 }
299 IOUtils.closeQuietly(fileOut);
300 fileOut = null;
301 }
302 }
303
304 public void updateDataReceiveType(int type, boolean saveToFile) {
305 interpretData = type;
306
307 if ((!saveToFile) && (fileOut != null)) {
308 closeFile();
309 } else if ((saveToFile) && (fileOut == null)) {
310 SimpleDateFormat fmt = new SimpleDateFormat("MM-dd_HH-mm-ss");
311 File file = new File("data-" + BluetoothTypesInfo.extractBluetoothAddress(serverURL)
312 + fmt.format(new Date()) + ".bin");
313 try {
314 fileOut = new FileOutputStream(file);
315 Logger.info(logPrefix + "saving data to file " + file.getAbsolutePath());
316 } catch (IOException e) {
317 }
318 }
319 }
320
321 public void send(final byte data[]) {
322 Thread t = new Thread("ClientConnectionSendThread" + (++connectionCount)) {
323 public void run() {
324 try {
325 if (rfcomm) {
326 ((ConnectionHolderStream) c).os.write(data);
327 } else {
328 ((ConnectionHolderL2CAP) c).channel.send(data);
329 }
330 Logger.debug(logPrefix + "data " + data.length + " sent");
331 } catch (IOException e) {
332 Logger.error(logPrefix + "Communication error", e);
333 }
334 }
335 };
336 t.setDaemon(true);
337 t.start();
338 }
339 }