picrate 0.9.0-java → 1.0.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.mvn/extensions.xml +1 -1
- data/README.md +2 -2
- data/Rakefile +9 -9
- data/docs/_config.yml +1 -1
- data/docs/_posts/2018-06-26-auto_install_picrate.md +4 -4
- data/docs/index.html +0 -4
- data/lib/picrate.rb +1 -0
- data/lib/picrate/app.rb +0 -1
- data/lib/picrate/runner.rb +15 -8
- data/lib/picrate/version.rb +2 -1
- data/library/color_group/color_group.rb +1 -1
- data/library/video_event/video_event.rb +2 -1
- data/pom.rb +3 -3
- data/pom.xml +3 -3
- data/src/main/java/monkstone/MathToolModule.java +253 -203
- data/src/main/java/monkstone/videoevent/CaptureEvent.java +27 -0
- data/src/main/java/monkstone/videoevent/{VideoInterface.java → MovieEvent.java} +14 -24
- data/src/main/java/processing/net/Client.java +673 -685
- data/src/main/java/processing/net/Server.java +329 -326
- data/test/color_group_test.rb +1 -2
- data/test/deglut_spec_test.rb +0 -2
- data/test/helper_methods_test.rb +1 -2
- data/test/math_tool_test.rb +0 -2
- data/test/respond_to_test.rb +1 -2
- data/test/test_helper.rb +2 -0
- data/test/vecmath_spec_test.rb +0 -2
- data/vendors/Rakefile +4 -5
- metadata +6 -5
@@ -0,0 +1,27 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2015-19 Martin Prout
|
3
|
+
*
|
4
|
+
* This library is free software; you can redistribute it and/or
|
5
|
+
* modify it under the terms of the GNU Lesser General Public
|
6
|
+
* License as published by the Free Software Foundation; either
|
7
|
+
* version 2.1 of the License, or (at your option) any later version.
|
8
|
+
*
|
9
|
+
* http://creativecommons.org/licenses/LGPL/2.1/
|
10
|
+
*
|
11
|
+
* This library is distributed in the hope that it will be useful,
|
12
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14
|
+
* Lesser General Public License for more details.
|
15
|
+
*
|
16
|
+
* You should have received a copy of the GNU Lesser General Public
|
17
|
+
* License along with this library; if not, write to the Free Software
|
18
|
+
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
19
|
+
*/
|
20
|
+
|
21
|
+
package monkstone.videoevent;
|
22
|
+
import processing.video.Capture;
|
23
|
+
|
24
|
+
@FunctionalInterface
|
25
|
+
public interface CaptureEvent{
|
26
|
+
public void captureEvent(Capture capture);
|
27
|
+
}
|
@@ -1,42 +1,32 @@
|
|
1
|
-
/*
|
2
|
-
* Copyright (c)
|
3
|
-
*
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2015-19 Martin Prout
|
3
|
+
*
|
4
4
|
* This library is free software; you can redistribute it and/or
|
5
|
-
* modify it under the terms of the GNU General Public
|
5
|
+
* modify it under the terms of the GNU Lesser General Public
|
6
6
|
* License as published by the Free Software Foundation; either
|
7
|
-
* version
|
8
|
-
*
|
7
|
+
* version 2.1 of the License, or (at your option) any later version.
|
8
|
+
*
|
9
9
|
* http://creativecommons.org/licenses/LGPL/2.1/
|
10
|
-
*
|
10
|
+
*
|
11
11
|
* This library is distributed in the hope that it will be useful,
|
12
12
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
13
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14
14
|
* Lesser General Public License for more details.
|
15
|
-
*
|
16
|
-
* You should have received a copy of the GNU General Public
|
15
|
+
*
|
16
|
+
* You should have received a copy of the GNU Lesser General Public
|
17
17
|
* License along with this library; if not, write to the Free Software
|
18
18
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
19
19
|
*/
|
20
20
|
|
21
21
|
package monkstone.videoevent;
|
22
22
|
import processing.video.Movie;
|
23
|
-
|
23
|
+
|
24
24
|
/**
|
25
25
|
* This interface makes it easier/possible to use the reflection methods
|
26
|
-
* from Movie and Capture classes in Processing::App in
|
27
|
-
*
|
26
|
+
* from Movie and Capture classes in Processing::App in JRubyArt
|
27
|
+
* @author Martin Prout
|
28
28
|
*/
|
29
|
-
|
30
|
-
|
31
|
-
* Used to implement reflection method in PApplet
|
32
|
-
* @see processing.video.Movie
|
33
|
-
* @param movie Movie
|
34
|
-
*/
|
29
|
+
@FunctionalInterface
|
30
|
+
public interface MovieEvent {
|
35
31
|
public void movieEvent(Movie movie);
|
36
|
-
/**
|
37
|
-
* Used to implement reflection method in PApplet
|
38
|
-
* @see processing.video.Capture
|
39
|
-
* @param capture Capture
|
40
|
-
*/
|
41
|
-
public void captureEvent(Capture capture);
|
42
32
|
}
|
@@ -1,6 +1,6 @@
|
|
1
1
|
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
2
2
|
|
3
|
-
|
3
|
+
/*
|
4
4
|
Client - basic network client implementation
|
5
5
|
Part of the Processing project - http://processing.org
|
6
6
|
|
@@ -21,736 +21,724 @@
|
|
21
21
|
Public License along with this library; if not, write to the
|
22
22
|
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
23
23
|
Boston, MA 02111-1307 USA
|
24
|
-
|
24
|
+
*/
|
25
|
+
|
25
26
|
package processing.net;
|
27
|
+
import processing.core.*;
|
26
28
|
|
27
|
-
import java.io
|
28
|
-
import java.
|
29
|
-
import java.
|
30
|
-
import java.lang.reflect.InvocationTargetException;
|
31
|
-
import java.lang.reflect.Method;
|
32
|
-
import java.net.Socket;
|
33
|
-
import java.net.SocketException;
|
34
|
-
import processing.core.PApplet;
|
29
|
+
import java.io.*;
|
30
|
+
import java.lang.reflect.*;
|
31
|
+
import java.net.*;
|
35
32
|
|
36
33
|
/**
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
*
|
34
|
+
* ( begin auto-generated from Client.xml )
|
35
|
+
*
|
36
|
+
* A client connects to a server and sends data back and forth. If anything
|
37
|
+
* goes wrong with the connection, for example the host is not there or is
|
38
|
+
* listening on a different port, an exception is thrown.
|
39
|
+
*
|
40
|
+
* ( end auto-generated )
|
45
41
|
* @webref net
|
46
|
-
* @brief The client class is used to create client Objects which connect to a
|
47
|
-
* server to exchange data.
|
42
|
+
* @brief The client class is used to create client Objects which connect to a server to exchange data.
|
48
43
|
* @instanceName client any variable of type Client
|
49
44
|
* @usage Application
|
50
45
|
* @see_external LIB_net/clientEvent
|
51
46
|
*/
|
52
47
|
public class Client implements Runnable {
|
53
48
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
49
|
+
protected static final int MAX_BUFFER_SIZE = 1 << 27; // 128 MB
|
50
|
+
|
51
|
+
PApplet parent;
|
52
|
+
Method clientEventMethod;
|
53
|
+
Method disconnectEventMethod;
|
54
|
+
|
55
|
+
volatile Thread thread;
|
56
|
+
Socket socket;
|
57
|
+
int port;
|
58
|
+
String host;
|
59
|
+
|
60
|
+
public InputStream input;
|
61
|
+
public OutputStream output;
|
62
|
+
|
63
|
+
final Object bufferLock = new Object[0];
|
64
|
+
|
65
|
+
byte buffer[] = new byte[32768];
|
66
|
+
int bufferIndex;
|
67
|
+
int bufferLast;
|
68
|
+
|
69
|
+
boolean disposeRegistered = false;
|
70
|
+
|
71
|
+
|
72
|
+
/**
|
73
|
+
* @param parent typically use "this"
|
74
|
+
* @param host address of the server
|
75
|
+
* @param port port to read/write from on the server
|
76
|
+
*/
|
77
|
+
public Client(PApplet parent, String host, int port) {
|
78
|
+
this.parent = parent;
|
79
|
+
this.host = host;
|
80
|
+
this.port = port;
|
81
|
+
|
82
|
+
try {
|
83
|
+
socket = new Socket(this.host, this.port);
|
84
|
+
input = socket.getInputStream();
|
85
|
+
output = socket.getOutputStream();
|
86
|
+
|
87
|
+
thread = new Thread(this);
|
88
|
+
thread.start();
|
89
|
+
|
90
|
+
parent.registerMethod("dispose", this);
|
91
|
+
disposeRegistered = true;
|
92
|
+
|
93
|
+
// reflection to check whether host sketch has a call for
|
94
|
+
// public void clientEvent(processing.net.Client)
|
95
|
+
// which would be called each time an event comes in
|
96
|
+
try {
|
97
|
+
clientEventMethod =
|
98
|
+
parent.getClass().getMethod("clientEvent", Client.class);
|
99
|
+
} catch (Exception e) {
|
100
|
+
// no such method, or an error.. which is fine, just ignore
|
101
|
+
}
|
102
|
+
// do the same for disconnectEvent(Client c);
|
103
|
+
try {
|
104
|
+
disconnectEventMethod =
|
105
|
+
parent.getClass().getMethod("disconnectEvent", Client.class);
|
106
|
+
} catch (Exception e) {
|
107
|
+
// no such method, or an error.. which is fine, just ignore
|
108
|
+
}
|
109
|
+
|
110
|
+
} catch (IOException e) {
|
111
|
+
e.printStackTrace();
|
112
|
+
dispose();
|
117
113
|
}
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
// do the same for disconnectEvent(Client c);
|
144
|
-
try {
|
145
|
-
disconnectEventMethod
|
146
|
-
= parent.getClass().getMethod("disconnectEvent", Client.class);
|
147
|
-
} catch (NoSuchMethodException | SecurityException e) {
|
148
|
-
// no such method, or an error.. which is fine, just ignore
|
149
|
-
}
|
114
|
+
}
|
115
|
+
|
116
|
+
|
117
|
+
/**
|
118
|
+
* @param socket any object of type Socket
|
119
|
+
* @throws IOException
|
120
|
+
*/
|
121
|
+
public Client(PApplet parent, Socket socket) throws IOException {
|
122
|
+
this.parent = parent;
|
123
|
+
this.socket = socket;
|
124
|
+
|
125
|
+
input = socket.getInputStream();
|
126
|
+
output = socket.getOutputStream();
|
127
|
+
|
128
|
+
thread = new Thread(this);
|
129
|
+
thread.start();
|
130
|
+
|
131
|
+
// reflection to check whether host sketch has a call for
|
132
|
+
// public void clientEvent(processing.net.Client)
|
133
|
+
// which would be called each time an event comes in
|
134
|
+
try {
|
135
|
+
clientEventMethod =
|
136
|
+
parent.getClass().getMethod("clientEvent", Client.class);
|
137
|
+
} catch (Exception e) {
|
138
|
+
// no such method, or an error.. which is fine, just ignore
|
150
139
|
}
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
*
|
158
|
-
* ( end auto-generated )
|
159
|
-
*
|
160
|
-
* @webref client:client
|
161
|
-
* @brief Disconnects from the server
|
162
|
-
* @usage application
|
163
|
-
*/
|
164
|
-
public void stop() {
|
165
|
-
if (disconnectEventMethod != null && thread != null) {
|
166
|
-
try {
|
167
|
-
disconnectEventMethod.invoke(parent, this);
|
168
|
-
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
|
169
|
-
Throwable cause = e;
|
170
|
-
// unwrap the exception if it came from the user code
|
171
|
-
if (e instanceof InvocationTargetException && e.getCause() != null) {
|
172
|
-
cause = e.getCause();
|
173
|
-
}
|
174
|
-
disconnectEventMethod = null;
|
175
|
-
}
|
176
|
-
}
|
177
|
-
if (disposeRegistered) {
|
178
|
-
parent.unregisterMethod("dispose", this);
|
179
|
-
disposeRegistered = false;
|
180
|
-
}
|
181
|
-
dispose();
|
140
|
+
// do the same for disconnectEvent(Client c);
|
141
|
+
try {
|
142
|
+
disconnectEventMethod =
|
143
|
+
parent.getClass().getMethod("disconnectEvent", Client.class);
|
144
|
+
} catch (Exception e) {
|
145
|
+
// no such method, or an error.. which is fine, just ignore
|
182
146
|
}
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
}
|
207
|
-
|
208
|
-
try {
|
209
|
-
if (socket != null) {
|
210
|
-
socket.close();
|
211
|
-
socket = null;
|
212
|
-
}
|
213
|
-
} catch (IOException e) {
|
147
|
+
}
|
148
|
+
|
149
|
+
|
150
|
+
/**
|
151
|
+
* ( begin auto-generated from Client_stop.xml )
|
152
|
+
*
|
153
|
+
* Disconnects from the server. Use to shut the connection when you're
|
154
|
+
* finished with the Client.
|
155
|
+
*
|
156
|
+
* ( end auto-generated )
|
157
|
+
* @webref client:client
|
158
|
+
* @brief Disconnects from the server
|
159
|
+
* @usage application
|
160
|
+
*/
|
161
|
+
public void stop() {
|
162
|
+
if (disconnectEventMethod != null && thread != null){
|
163
|
+
try {
|
164
|
+
disconnectEventMethod.invoke(parent, this);
|
165
|
+
} catch (Exception e) {
|
166
|
+
Throwable cause = e;
|
167
|
+
// unwrap the exception if it came from the user code
|
168
|
+
if (e instanceof InvocationTargetException && e.getCause() != null) {
|
169
|
+
cause = e.getCause();
|
214
170
|
}
|
171
|
+
cause.printStackTrace();
|
172
|
+
disconnectEventMethod = null;
|
173
|
+
}
|
215
174
|
}
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
byte[] readBuffer;
|
220
|
-
{ // make the read buffer same size as socket receive buffer so that
|
221
|
-
// we don't waste cycles calling listeners when there is more data waiting
|
222
|
-
int readBufferSize = 1 << 16; // 64 KB (default socket receive buffer size)
|
223
|
-
try {
|
224
|
-
readBufferSize = socket.getReceiveBufferSize();
|
225
|
-
} catch (SocketException ignore) {
|
226
|
-
}
|
227
|
-
readBuffer = new byte[readBufferSize];
|
228
|
-
}
|
229
|
-
while (Thread.currentThread() == thread) {
|
230
|
-
try {
|
231
|
-
while (input != null) {
|
232
|
-
int readCount;
|
233
|
-
|
234
|
-
// try to read a byte using a blocking read.
|
235
|
-
// An exception will occur when the sketch is exits.
|
236
|
-
try {
|
237
|
-
readCount = input.read(readBuffer, 0, readBuffer.length);
|
238
|
-
} catch (SocketException e) {
|
239
|
-
System.err.println("Client SocketException: " + e.getMessage());
|
240
|
-
// the socket had a problem reading so don't try to read from it again.
|
241
|
-
stop();
|
242
|
-
return;
|
243
|
-
}
|
244
|
-
|
245
|
-
// read returns -1 if end-of-stream occurs (for example if the host disappears)
|
246
|
-
if (readCount == -1) {
|
247
|
-
System.err.println("Client got end-of-stream.");
|
248
|
-
stop();
|
249
|
-
return;
|
250
|
-
}
|
251
|
-
|
252
|
-
synchronized (bufferLock) {
|
253
|
-
int freeBack = buffer.length - bufferLast;
|
254
|
-
if (readCount > freeBack) {
|
255
|
-
// not enough space at the back
|
256
|
-
int bufferLength = bufferLast - bufferIndex;
|
257
|
-
byte[] targetBuffer = buffer;
|
258
|
-
if (bufferLength + readCount > buffer.length) {
|
259
|
-
// can't fit even after compacting, resize the buffer
|
260
|
-
// find the next power of two which can fit everything in
|
261
|
-
int newSize = Integer.highestOneBit(bufferLength + readCount - 1) << 1;
|
262
|
-
if (newSize > MAX_BUFFER_SIZE) {
|
263
|
-
// buffer is full because client is not reading (fast enough)
|
264
|
-
System.err.println("Client: can't receive more data, buffer is full. "
|
265
|
-
+ "Make sure you read the data from the client.");
|
266
|
-
stop();
|
267
|
-
return;
|
268
|
-
}
|
269
|
-
targetBuffer = new byte[newSize];
|
270
|
-
}
|
271
|
-
// compact the buffer (either in-place or into the new bigger buffer)
|
272
|
-
System.arraycopy(buffer, bufferIndex, targetBuffer, 0, bufferLength);
|
273
|
-
bufferLast -= bufferIndex;
|
274
|
-
bufferIndex = 0;
|
275
|
-
buffer = targetBuffer;
|
276
|
-
}
|
277
|
-
// copy all newly read bytes into the buffer
|
278
|
-
System.arraycopy(readBuffer, 0, buffer, bufferLast, readCount);
|
279
|
-
bufferLast += readCount;
|
280
|
-
}
|
281
|
-
|
282
|
-
// now post an event
|
283
|
-
if (clientEventMethod != null) {
|
284
|
-
try {
|
285
|
-
clientEventMethod.invoke(parent, this);
|
286
|
-
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
|
287
|
-
System.err.println("error, disabling clientEvent() for " + host);
|
288
|
-
Throwable cause = e;
|
289
|
-
// unwrap the exception if it came from the user code
|
290
|
-
if (e instanceof InvocationTargetException && e.getCause() != null) {
|
291
|
-
cause = e.getCause();
|
292
|
-
}
|
293
|
-
clientEventMethod = null;
|
294
|
-
}
|
295
|
-
}
|
296
|
-
}
|
297
|
-
} catch (IOException e) {
|
298
|
-
//errorMessage("run", e);
|
299
|
-
|
300
|
-
}
|
301
|
-
}
|
175
|
+
if (disposeRegistered) {
|
176
|
+
parent.unregisterMethod("dispose", this);
|
177
|
+
disposeRegistered = false;
|
302
178
|
}
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
179
|
+
dispose();
|
180
|
+
}
|
181
|
+
|
182
|
+
|
183
|
+
/**
|
184
|
+
* Disconnect from the server: internal use only.
|
185
|
+
* <P>
|
186
|
+
* This should only be called by the internal functions in PApplet,
|
187
|
+
* use stop() instead from within your own applets.
|
188
|
+
*/
|
189
|
+
public void dispose() {
|
190
|
+
thread = null;
|
191
|
+
try {
|
192
|
+
if (input != null) {
|
193
|
+
input.close();
|
194
|
+
input = null;
|
195
|
+
}
|
196
|
+
} catch (Exception e) {
|
197
|
+
e.printStackTrace();
|
318
198
|
}
|
319
199
|
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
* @return
|
328
|
-
* @webref client:client
|
329
|
-
* @usage application
|
330
|
-
* @brief Returns the IP address of the machine as a String
|
331
|
-
*/
|
332
|
-
public String ip() {
|
333
|
-
if (socket != null) {
|
334
|
-
return socket.getInetAddress().getHostAddress();
|
335
|
-
}
|
336
|
-
return null;
|
200
|
+
try {
|
201
|
+
if (output != null) {
|
202
|
+
output.close();
|
203
|
+
output = null;
|
204
|
+
}
|
205
|
+
} catch (Exception e) {
|
206
|
+
e.printStackTrace();
|
337
207
|
}
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
* @webref client:client
|
347
|
-
* @usage application
|
348
|
-
* @brief Returns the number of bytes in the buffer waiting to be read
|
349
|
-
*/
|
350
|
-
public int available() {
|
351
|
-
synchronized (bufferLock) {
|
352
|
-
return (bufferLast - bufferIndex);
|
353
|
-
}
|
208
|
+
|
209
|
+
try {
|
210
|
+
if (socket != null) {
|
211
|
+
socket.close();
|
212
|
+
socket = null;
|
213
|
+
}
|
214
|
+
} catch (Exception e) {
|
215
|
+
e.printStackTrace();
|
354
216
|
}
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
synchronized (bufferLock) {
|
369
|
-
bufferLast = 0;
|
370
|
-
bufferIndex = 0;
|
371
|
-
}
|
217
|
+
}
|
218
|
+
|
219
|
+
|
220
|
+
@Override
|
221
|
+
public void run() {
|
222
|
+
byte[] readBuffer;
|
223
|
+
{ // make the read buffer same size as socket receive buffer so that
|
224
|
+
// we don't waste cycles calling listeners when there is more data waiting
|
225
|
+
int readBufferSize = 1 << 16; // 64 KB (default socket receive buffer size)
|
226
|
+
try {
|
227
|
+
readBufferSize = socket.getReceiveBufferSize();
|
228
|
+
} catch (SocketException ignore) { }
|
229
|
+
readBuffer = new byte[readBufferSize];
|
372
230
|
}
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
231
|
+
while (Thread.currentThread() == thread) {
|
232
|
+
try {
|
233
|
+
while (input != null) {
|
234
|
+
int readCount;
|
235
|
+
|
236
|
+
// try to read a byte using a blocking read.
|
237
|
+
// An exception will occur when the sketch is exits.
|
238
|
+
try {
|
239
|
+
readCount = input.read(readBuffer, 0, readBuffer.length);
|
240
|
+
} catch (SocketException e) {
|
241
|
+
System.err.println("Client SocketException: " + e.getMessage());
|
242
|
+
// the socket had a problem reading so don't try to read from it again.
|
243
|
+
stop();
|
244
|
+
return;
|
245
|
+
}
|
246
|
+
|
247
|
+
// read returns -1 if end-of-stream occurs (for example if the host disappears)
|
248
|
+
if (readCount == -1) {
|
249
|
+
System.err.println("Client got end-of-stream.");
|
250
|
+
stop();
|
251
|
+
return;
|
252
|
+
}
|
253
|
+
|
254
|
+
synchronized (bufferLock) {
|
255
|
+
int freeBack = buffer.length - bufferLast;
|
256
|
+
if (readCount > freeBack) {
|
257
|
+
// not enough space at the back
|
258
|
+
int bufferLength = bufferLast - bufferIndex;
|
259
|
+
byte[] targetBuffer = buffer;
|
260
|
+
if (bufferLength + readCount > buffer.length) {
|
261
|
+
// can't fit even after compacting, resize the buffer
|
262
|
+
// find the next power of two which can fit everything in
|
263
|
+
int newSize = Integer.highestOneBit(bufferLength + readCount - 1) << 1;
|
264
|
+
if (newSize > MAX_BUFFER_SIZE) {
|
265
|
+
// buffer is full because client is not reading (fast enough)
|
266
|
+
System.err.println("Client: can't receive more data, buffer is full. " +
|
267
|
+
"Make sure you read the data from the client.");
|
268
|
+
stop();
|
269
|
+
return;
|
270
|
+
}
|
271
|
+
targetBuffer = new byte[newSize];
|
272
|
+
}
|
273
|
+
// compact the buffer (either in-place or into the new bigger buffer)
|
274
|
+
System.arraycopy(buffer, bufferIndex, targetBuffer, 0, bufferLength);
|
275
|
+
bufferLast -= bufferIndex;
|
276
|
+
bufferIndex = 0;
|
277
|
+
buffer = targetBuffer;
|
391
278
|
}
|
279
|
+
// copy all newly read bytes into the buffer
|
280
|
+
System.arraycopy(readBuffer, 0, buffer, bufferLast, readCount);
|
281
|
+
bufferLast += readCount;
|
282
|
+
}
|
392
283
|
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
284
|
+
// now post an event
|
285
|
+
if (clientEventMethod != null) {
|
286
|
+
try {
|
287
|
+
clientEventMethod.invoke(parent, this);
|
288
|
+
} catch (Exception e) {
|
289
|
+
System.err.println("error, disabling clientEvent() for " + host);
|
290
|
+
Throwable cause = e;
|
291
|
+
// unwrap the exception if it came from the user code
|
292
|
+
if (e instanceof InvocationTargetException && e.getCause() != null) {
|
293
|
+
cause = e.getCause();
|
294
|
+
}
|
295
|
+
cause.printStackTrace();
|
296
|
+
clientEventMethod = null;
|
397
297
|
}
|
398
|
-
|
298
|
+
}
|
399
299
|
}
|
300
|
+
} catch (IOException e) {
|
301
|
+
//errorMessage("run", e);
|
302
|
+
e.printStackTrace();
|
303
|
+
}
|
400
304
|
}
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
305
|
+
}
|
306
|
+
|
307
|
+
|
308
|
+
/**
|
309
|
+
* ( begin auto-generated from Client_active.xml )
|
310
|
+
*
|
311
|
+
* Returns true if this client is still active and hasn't run
|
312
|
+
* into any trouble.
|
313
|
+
*
|
314
|
+
* ( end auto-generated )
|
315
|
+
* @webref client:client
|
316
|
+
* @brief Returns true if this client is still active
|
317
|
+
* @usage application
|
318
|
+
*/
|
319
|
+
public boolean active() {
|
320
|
+
return (thread != null);
|
321
|
+
}
|
322
|
+
|
323
|
+
|
324
|
+
/**
|
325
|
+
* ( begin auto-generated from Client_ip.xml )
|
326
|
+
*
|
327
|
+
* Returns the IP address of the computer to which the Client is attached.
|
328
|
+
*
|
329
|
+
* ( end auto-generated )
|
330
|
+
* @webref client:client
|
331
|
+
* @usage application
|
332
|
+
* @brief Returns the IP address of the machine as a String
|
333
|
+
*/
|
334
|
+
public String ip() {
|
335
|
+
if (socket != null){
|
336
|
+
return socket.getInetAddress().getHostAddress();
|
420
337
|
}
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
* @return
|
440
|
-
* @webref client:client
|
441
|
-
* @usage application
|
442
|
-
* @brief Reads everything in the buffer
|
443
|
-
*/
|
444
|
-
public byte[] readBytes() {
|
445
|
-
synchronized (bufferLock) {
|
446
|
-
if (bufferIndex == bufferLast) {
|
447
|
-
return null;
|
448
|
-
}
|
449
|
-
|
450
|
-
int length = bufferLast - bufferIndex;
|
451
|
-
byte outgoing[] = new byte[length];
|
452
|
-
System.arraycopy(buffer, bufferIndex, outgoing, 0, length);
|
453
|
-
|
454
|
-
bufferIndex = 0; // rewind
|
455
|
-
bufferLast = 0;
|
456
|
-
return outgoing;
|
457
|
-
}
|
338
|
+
return null;
|
339
|
+
}
|
340
|
+
|
341
|
+
|
342
|
+
/**
|
343
|
+
* ( begin auto-generated from Client_available.xml )
|
344
|
+
*
|
345
|
+
* Returns the number of bytes available. When any client has bytes
|
346
|
+
* available from the server, it returns the number of bytes.
|
347
|
+
*
|
348
|
+
* ( end auto-generated )
|
349
|
+
* @webref client:client
|
350
|
+
* @usage application
|
351
|
+
* @brief Returns the number of bytes in the buffer waiting to be read
|
352
|
+
*/
|
353
|
+
public int available() {
|
354
|
+
synchronized (bufferLock) {
|
355
|
+
return (bufferLast - bufferIndex);
|
458
356
|
}
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
int length = bufferLast - bufferIndex;
|
477
|
-
if (length > max) {
|
478
|
-
length = max;
|
479
|
-
}
|
480
|
-
byte outgoing[] = new byte[length];
|
481
|
-
System.arraycopy(buffer, bufferIndex, outgoing, 0, length);
|
482
|
-
|
483
|
-
bufferIndex += length;
|
484
|
-
if (bufferIndex == bufferLast) {
|
485
|
-
bufferIndex = 0; // rewind
|
486
|
-
bufferLast = 0;
|
487
|
-
}
|
488
|
-
|
489
|
-
return outgoing;
|
490
|
-
}
|
357
|
+
}
|
358
|
+
|
359
|
+
|
360
|
+
/**
|
361
|
+
* ( begin auto-generated from Client_clear.xml )
|
362
|
+
*
|
363
|
+
* Empty the buffer, removes all the data stored there.
|
364
|
+
*
|
365
|
+
* ( end auto-generated )
|
366
|
+
* @webref client:client
|
367
|
+
* @usage application
|
368
|
+
* @brief Clears the buffer
|
369
|
+
*/
|
370
|
+
public void clear() {
|
371
|
+
synchronized (bufferLock) {
|
372
|
+
bufferLast = 0;
|
373
|
+
bufferIndex = 0;
|
491
374
|
}
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
bufferIndex += length;
|
518
|
-
if (bufferIndex == bufferLast) {
|
519
|
-
bufferIndex = 0; // rewind
|
520
|
-
bufferLast = 0;
|
521
|
-
}
|
522
|
-
return length;
|
523
|
-
}
|
375
|
+
}
|
376
|
+
|
377
|
+
|
378
|
+
/**
|
379
|
+
* ( begin auto-generated from Client_read.xml )
|
380
|
+
*
|
381
|
+
* Returns a number between 0 and 255 for the next byte that's waiting in
|
382
|
+
* the buffer. Returns -1 if there is no byte, although this should be
|
383
|
+
* avoided by first cheacking <b>available()</b> to see if any data is available.
|
384
|
+
*
|
385
|
+
* ( end auto-generated )
|
386
|
+
* @webref client:client
|
387
|
+
* @usage application
|
388
|
+
* @brief Returns a value from the buffer
|
389
|
+
*/
|
390
|
+
public int read() {
|
391
|
+
synchronized (bufferLock) {
|
392
|
+
if (bufferIndex == bufferLast) return -1;
|
393
|
+
|
394
|
+
int outgoing = buffer[bufferIndex++] & 0xff;
|
395
|
+
if (bufferIndex == bufferLast) { // rewind
|
396
|
+
bufferIndex = 0;
|
397
|
+
bufferLast = 0;
|
398
|
+
}
|
399
|
+
return outgoing;
|
524
400
|
}
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
* @webref client:client
|
544
|
-
* @usage application
|
545
|
-
* @brief Reads from the buffer of bytes up to and including a particular
|
546
|
-
* character
|
547
|
-
* @param interesting character designated to mark the end of the data
|
548
|
-
*/
|
549
|
-
public byte[] readBytesUntil(int interesting) {
|
550
|
-
byte what = (byte) interesting;
|
551
|
-
|
552
|
-
synchronized (bufferLock) {
|
553
|
-
if (bufferIndex == bufferLast) {
|
554
|
-
return null;
|
555
|
-
}
|
556
|
-
|
557
|
-
int found = -1;
|
558
|
-
for (int k = bufferIndex; k < bufferLast; k++) {
|
559
|
-
if (buffer[k] == what) {
|
560
|
-
found = k;
|
561
|
-
break;
|
562
|
-
}
|
563
|
-
}
|
564
|
-
if (found == -1) {
|
565
|
-
return null;
|
566
|
-
}
|
567
|
-
|
568
|
-
int length = found - bufferIndex + 1;
|
569
|
-
byte outgoing[] = new byte[length];
|
570
|
-
System.arraycopy(buffer, bufferIndex, outgoing, 0, length);
|
571
|
-
|
572
|
-
bufferIndex += length;
|
573
|
-
if (bufferIndex == bufferLast) {
|
574
|
-
bufferIndex = 0; // rewind
|
575
|
-
bufferLast = 0;
|
576
|
-
}
|
577
|
-
return outgoing;
|
578
|
-
}
|
401
|
+
}
|
402
|
+
|
403
|
+
|
404
|
+
/**
|
405
|
+
* ( begin auto-generated from Client_readChar.xml )
|
406
|
+
*
|
407
|
+
* Returns the next byte in the buffer as a char. Returns -1 or 0xffff if
|
408
|
+
* nothing is there.
|
409
|
+
*
|
410
|
+
* ( end auto-generated )
|
411
|
+
* @webref client:client
|
412
|
+
* @usage application
|
413
|
+
* @brief Returns the next byte in the buffer as a char
|
414
|
+
*/
|
415
|
+
public char readChar() {
|
416
|
+
synchronized (bufferLock) {
|
417
|
+
if (bufferIndex == bufferLast) return (char) (-1);
|
418
|
+
return (char) read();
|
579
419
|
}
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
System.err.println("readBytesUntil() byte buffer is"
|
617
|
-
+ " too small for the " + length
|
618
|
-
+ " bytes up to and including char " + interesting);
|
619
|
-
return -1;
|
620
|
-
}
|
621
|
-
//byte outgoing[] = new byte[length];
|
622
|
-
System.arraycopy(buffer, bufferIndex, byteBuffer, 0, length);
|
623
|
-
|
624
|
-
bufferIndex += length;
|
625
|
-
if (bufferIndex == bufferLast) {
|
626
|
-
bufferIndex = 0; // rewind
|
627
|
-
bufferLast = 0;
|
628
|
-
}
|
629
|
-
return length;
|
630
|
-
}
|
420
|
+
}
|
421
|
+
|
422
|
+
|
423
|
+
/**
|
424
|
+
* ( begin auto-generated from Client_readBytes.xml )
|
425
|
+
*
|
426
|
+
* Reads a group of bytes from the buffer. The version with no parameters
|
427
|
+
* returns a byte array of all data in the buffer. This is not efficient,
|
428
|
+
* but is easy to use. The version with the <b>byteBuffer</b> parameter is
|
429
|
+
* more memory and time efficient. It grabs the data in the buffer and puts
|
430
|
+
* it into the byte array passed in and returns an int value for the number
|
431
|
+
* of bytes read. If more bytes are available than can fit into the
|
432
|
+
* <b>byteBuffer</b>, only those that fit are read.
|
433
|
+
*
|
434
|
+
* ( end auto-generated )
|
435
|
+
* <h3>Advanced</h3>
|
436
|
+
* Return a byte array of anything that's in the serial buffer.
|
437
|
+
* Not particularly memory/speed efficient, because it creates
|
438
|
+
* a byte array on each read, but it's easier to use than
|
439
|
+
* readBytes(byte b[]) (see below).
|
440
|
+
*
|
441
|
+
* @webref client:client
|
442
|
+
* @usage application
|
443
|
+
* @brief Reads everything in the buffer
|
444
|
+
*/
|
445
|
+
public byte[] readBytes() {
|
446
|
+
synchronized (bufferLock) {
|
447
|
+
if (bufferIndex == bufferLast) return null;
|
448
|
+
|
449
|
+
int length = bufferLast - bufferIndex;
|
450
|
+
byte outgoing[] = new byte[length];
|
451
|
+
System.arraycopy(buffer, bufferIndex, outgoing, 0, length);
|
452
|
+
|
453
|
+
bufferIndex = 0; // rewind
|
454
|
+
bufferLast = 0;
|
455
|
+
return outgoing;
|
631
456
|
}
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
457
|
+
}
|
458
|
+
|
459
|
+
|
460
|
+
/**
|
461
|
+
* <h3>Advanced</h3>
|
462
|
+
* Return a byte array of anything that's in the serial buffer
|
463
|
+
* up to the specified maximum number of bytes.
|
464
|
+
* Not particularly memory/speed efficient, because it creates
|
465
|
+
* a byte array on each read, but it's easier to use than
|
466
|
+
* readBytes(byte b[]) (see below).
|
467
|
+
*
|
468
|
+
* @param max the maximum number of bytes to read
|
469
|
+
*/
|
470
|
+
public byte[] readBytes(int max) {
|
471
|
+
synchronized (bufferLock) {
|
472
|
+
if (bufferIndex == bufferLast) return null;
|
473
|
+
|
474
|
+
int length = bufferLast - bufferIndex;
|
475
|
+
if (length > max) length = max;
|
476
|
+
byte outgoing[] = new byte[length];
|
477
|
+
System.arraycopy(buffer, bufferIndex, outgoing, 0, length);
|
478
|
+
|
479
|
+
bufferIndex += length;
|
480
|
+
if (bufferIndex == bufferLast) {
|
481
|
+
bufferIndex = 0; // rewind
|
482
|
+
bufferLast = 0;
|
483
|
+
}
|
484
|
+
|
485
|
+
return outgoing;
|
654
486
|
}
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
487
|
+
}
|
488
|
+
|
489
|
+
|
490
|
+
/**
|
491
|
+
* <h3>Advanced</h3>
|
492
|
+
* Grab whatever is in the serial buffer, and stuff it into a
|
493
|
+
* byte buffer passed in by the user. This is more memory/time
|
494
|
+
* efficient than readBytes() returning a byte[] array.
|
495
|
+
*
|
496
|
+
* Returns an int for how many bytes were read. If more bytes
|
497
|
+
* are available than can fit into the byte array, only those
|
498
|
+
* that will fit are read.
|
499
|
+
*
|
500
|
+
* @param bytebuffer passed in byte array to be altered
|
501
|
+
*/
|
502
|
+
public int readBytes(byte bytebuffer[]) {
|
503
|
+
synchronized (bufferLock) {
|
504
|
+
if (bufferIndex == bufferLast) return 0;
|
505
|
+
|
506
|
+
int length = bufferLast - bufferIndex;
|
507
|
+
if (length > bytebuffer.length) length = bytebuffer.length;
|
508
|
+
System.arraycopy(buffer, bufferIndex, bytebuffer, 0, length);
|
509
|
+
|
510
|
+
bufferIndex += length;
|
511
|
+
if (bufferIndex == bufferLast) {
|
512
|
+
bufferIndex = 0; // rewind
|
513
|
+
bufferLast = 0;
|
514
|
+
}
|
515
|
+
return length;
|
516
|
+
}
|
517
|
+
}
|
518
|
+
|
519
|
+
|
520
|
+
/**
|
521
|
+
* ( begin auto-generated from Client_readBytesUntil.xml )
|
522
|
+
*
|
523
|
+
* Reads from the port into a buffer of bytes up to and including a
|
524
|
+
* particular character. If the character isn't in the buffer, 'null' is
|
525
|
+
* returned. The version with no <b>byteBuffer</b> parameter returns a byte
|
526
|
+
* array of all data up to and including the <b>interesting</b> byte. This
|
527
|
+
* is not efficient, but is easy to use. The version with the
|
528
|
+
* <b>byteBuffer</b> parameter is more memory and time efficient. It grabs
|
529
|
+
* the data in the buffer and puts it into the byte array passed in and
|
530
|
+
* returns an int value for the number of bytes read. If the byte buffer is
|
531
|
+
* not large enough, -1 is returned and an error is printed to the message
|
532
|
+
* area. If nothing is in the buffer, 0 is returned.
|
533
|
+
*
|
534
|
+
* ( end auto-generated )
|
535
|
+
* @webref client:client
|
536
|
+
* @usage application
|
537
|
+
* @brief Reads from the buffer of bytes up to and including a particular character
|
538
|
+
* @param interesting character designated to mark the end of the data
|
539
|
+
*/
|
540
|
+
public byte[] readBytesUntil(int interesting) {
|
541
|
+
byte what = (byte)interesting;
|
542
|
+
|
543
|
+
synchronized (bufferLock) {
|
544
|
+
if (bufferIndex == bufferLast) return null;
|
545
|
+
|
546
|
+
int found = -1;
|
547
|
+
for (int k = bufferIndex; k < bufferLast; k++) {
|
548
|
+
if (buffer[k] == what) {
|
549
|
+
found = k;
|
550
|
+
break;
|
679
551
|
}
|
680
|
-
|
552
|
+
}
|
553
|
+
if (found == -1) return null;
|
554
|
+
|
555
|
+
int length = found - bufferIndex + 1;
|
556
|
+
byte outgoing[] = new byte[length];
|
557
|
+
System.arraycopy(buffer, bufferIndex, outgoing, 0, length);
|
558
|
+
|
559
|
+
bufferIndex += length;
|
560
|
+
if (bufferIndex == bufferLast) {
|
561
|
+
bufferIndex = 0; // rewind
|
562
|
+
bufferLast = 0;
|
563
|
+
}
|
564
|
+
return outgoing;
|
681
565
|
}
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
566
|
+
}
|
567
|
+
|
568
|
+
|
569
|
+
/**
|
570
|
+
* <h3>Advanced</h3>
|
571
|
+
* Reads from the serial port into a buffer of bytes until a
|
572
|
+
* particular character. If the character isn't in the serial
|
573
|
+
* buffer, then 'null' is returned.
|
574
|
+
*
|
575
|
+
* If outgoing[] is not big enough, then -1 is returned,
|
576
|
+
* and an error message is printed on the console.
|
577
|
+
* If nothing is in the buffer, zero is returned.
|
578
|
+
* If 'interesting' byte is not in the buffer, then 0 is returned.
|
579
|
+
*
|
580
|
+
* @param byteBuffer passed in byte array to be altered
|
581
|
+
*/
|
582
|
+
public int readBytesUntil(int interesting, byte byteBuffer[]) {
|
583
|
+
byte what = (byte)interesting;
|
584
|
+
|
585
|
+
synchronized (bufferLock) {
|
586
|
+
if (bufferIndex == bufferLast) return 0;
|
587
|
+
|
588
|
+
int found = -1;
|
589
|
+
for (int k = bufferIndex; k < bufferLast; k++) {
|
590
|
+
if (buffer[k] == what) {
|
591
|
+
found = k;
|
592
|
+
break;
|
706
593
|
}
|
594
|
+
}
|
595
|
+
if (found == -1) return 0;
|
596
|
+
|
597
|
+
int length = found - bufferIndex + 1;
|
598
|
+
if (length > byteBuffer.length) {
|
599
|
+
System.err.println("readBytesUntil() byte buffer is" +
|
600
|
+
" too small for the " + length +
|
601
|
+
" bytes up to and including char " + interesting);
|
602
|
+
return -1;
|
603
|
+
}
|
604
|
+
//byte outgoing[] = new byte[length];
|
605
|
+
System.arraycopy(buffer, bufferIndex, byteBuffer, 0, length);
|
606
|
+
|
607
|
+
bufferIndex += length;
|
608
|
+
if (bufferIndex == bufferLast) {
|
609
|
+
bufferIndex = 0; // rewind
|
610
|
+
bufferLast = 0;
|
611
|
+
}
|
612
|
+
return length;
|
707
613
|
}
|
614
|
+
}
|
615
|
+
|
616
|
+
|
617
|
+
/**
|
618
|
+
* ( begin auto-generated from Client_readString.xml )
|
619
|
+
*
|
620
|
+
* Returns the all the data from the buffer as a String. This method
|
621
|
+
* assumes the incoming characters are ASCII. If you want to transfer
|
622
|
+
* Unicode data, first convert the String to a byte stream in the
|
623
|
+
* representation of your choice (i.e. UTF8 or two-byte Unicode data), and
|
624
|
+
* send it as a byte array.
|
625
|
+
*
|
626
|
+
* ( end auto-generated )
|
627
|
+
* @webref client:client
|
628
|
+
* @usage application
|
629
|
+
* @brief Returns the buffer as a String
|
630
|
+
*/
|
631
|
+
public String readString() {
|
632
|
+
byte b[] = readBytes();
|
633
|
+
if (b == null) return null;
|
634
|
+
return new String(b);
|
635
|
+
}
|
636
|
+
|
637
|
+
|
638
|
+
/**
|
639
|
+
* ( begin auto-generated from Client_readStringUntil.xml )
|
640
|
+
*
|
641
|
+
* Combination of <b>readBytesUntil()</b> and <b>readString()</b>. Returns
|
642
|
+
* <b>null</b> if it doesn't find what you're looking for.
|
643
|
+
*
|
644
|
+
* ( end auto-generated )
|
645
|
+
* <h3>Advanced</h3>
|
646
|
+
* <p/>
|
647
|
+
* If you want to move Unicode data, you can first convert the
|
648
|
+
* String to a byte stream in the representation of your choice
|
649
|
+
* (i.e. UTF8 or two-byte Unicode data), and send it as a byte array.
|
650
|
+
*
|
651
|
+
* @webref client:client
|
652
|
+
* @usage application
|
653
|
+
* @brief Returns the buffer as a String up to and including a particular character
|
654
|
+
* @param interesting character designated to mark the end of the data
|
655
|
+
*/
|
656
|
+
public String readStringUntil(int interesting) {
|
657
|
+
byte b[] = readBytesUntil(interesting);
|
658
|
+
if (b == null) return null;
|
659
|
+
return new String(b);
|
660
|
+
}
|
661
|
+
|
662
|
+
|
663
|
+
/**
|
664
|
+
* ( begin auto-generated from Client_write.xml )
|
665
|
+
*
|
666
|
+
* Writes data to a server specified when constructing the client.
|
667
|
+
*
|
668
|
+
* ( end auto-generated )
|
669
|
+
* @webref client:client
|
670
|
+
* @usage application
|
671
|
+
* @brief Writes bytes, chars, ints, bytes[], Strings
|
672
|
+
* @param data data to write
|
673
|
+
*/
|
674
|
+
public void write(int data) { // will also cover char
|
675
|
+
try {
|
676
|
+
output.write(data & 0xff); // for good measure do the &
|
677
|
+
output.flush(); // hmm, not sure if a good idea
|
678
|
+
|
679
|
+
} catch (Exception e) { // null pointer or serial port dead
|
680
|
+
//errorMessage("write", e);
|
681
|
+
//e.printStackTrace();
|
682
|
+
//dispose();
|
683
|
+
//disconnect(e);
|
684
|
+
e.printStackTrace();
|
685
|
+
stop();
|
686
|
+
}
|
687
|
+
}
|
708
688
|
|
709
|
-
public void write(byte data[]) {
|
710
|
-
try {
|
711
|
-
output.write(data);
|
712
|
-
output.flush(); // hmm, not sure if a good idea
|
713
689
|
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
690
|
+
public void write(byte data[]) {
|
691
|
+
try {
|
692
|
+
output.write(data);
|
693
|
+
output.flush(); // hmm, not sure if a good idea
|
718
694
|
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
* string. (Meaning that internally it uses String.getBytes)
|
726
|
-
*
|
727
|
-
* If you want to move Unicode data, you can first convert the String to a
|
728
|
-
* byte stream in the representation of your choice (i.e. UTF8 or two-byte
|
729
|
-
* Unicode data), and send it as a byte array.
|
730
|
-
*
|
731
|
-
* @param data
|
732
|
-
*/
|
733
|
-
public void write(String data) {
|
734
|
-
write(data.getBytes());
|
695
|
+
} catch (Exception e) { // null pointer or serial port dead
|
696
|
+
//errorMessage("write", e);
|
697
|
+
//e.printStackTrace();
|
698
|
+
//disconnect(e);
|
699
|
+
e.printStackTrace();
|
700
|
+
stop();
|
735
701
|
}
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
702
|
+
}
|
703
|
+
|
704
|
+
|
705
|
+
/**
|
706
|
+
* <h3>Advanced</h3>
|
707
|
+
* Write a String to the output. Note that this doesn't account
|
708
|
+
* for Unicode (two bytes per char), nor will it send UTF8
|
709
|
+
* characters.. It assumes that you mean to send a byte buffer
|
710
|
+
* (most often the case for networking and serial i/o) and
|
711
|
+
* will only use the bottom 8 bits of each char in the string.
|
712
|
+
* (Meaning that internally it uses String.getBytes)
|
713
|
+
*
|
714
|
+
* If you want to move Unicode data, you can first convert the
|
715
|
+
* String to a byte stream in the representation of your choice
|
716
|
+
* (i.e. UTF8 or two-byte Unicode data), and send it as a byte array.
|
717
|
+
*/
|
718
|
+
public void write(String data) {
|
719
|
+
write(data.getBytes());
|
720
|
+
}
|
721
|
+
|
722
|
+
|
723
|
+
/**
|
724
|
+
* Handle disconnect due to an Exception being thrown.
|
725
|
+
*/
|
726
|
+
/*
|
741
727
|
protected void disconnect(Exception e) {
|
742
728
|
dispose();
|
743
729
|
if (e != null) {
|
744
730
|
e.printStackTrace();
|
745
731
|
}
|
746
732
|
}
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
733
|
+
*/
|
734
|
+
|
735
|
+
|
736
|
+
/**
|
737
|
+
* General error reporting, all corralled here just in case
|
738
|
+
* I think of something slightly more intelligent to do.
|
739
|
+
*/
|
740
|
+
//public void errorMessage(String where, Exception e) {
|
741
|
+
//parent.die("Error inside Client." + where + "()", e);
|
742
|
+
//e.printStackTrace(System.err);
|
743
|
+
//}
|
756
744
|
}
|