我将数据从我的Java应用程序通过USB连接推送到另一端的Arduino。
Arduino只能在其末端缓冲64字节的数据,所以我必须限制每个字节中发送的字节数量#gulp'从我的Java应用程序(多余的字节将丢失)。当Arduino代码准备接收更多字节时,它将发送一个简单的ping线。
所以,我在类BufferedOutputStream
中扩展了ArduinoBufferedOutputStream
,这实际上是输出流的一部分。从Java应用程序的不同部分,将任意数量的字节写入流(使用write(byte b)
),并且流是flush
。{/ p>
我需要(我猜)是覆盖BufferedOutputStream
的flush方法,以便在从Arduino接收ping之前它不会发送超过64个字节,此时流应该发送64个字节(或更少)。
static class ArduinoBufferedOutputStream extends BufferedOutputStream {
public static final int WIRE_CAPACITY = 25;
private byte[] waiting = new byte[0];
private int onWire = 0;
public ArduinoBufferedOutputStream(final OutputStream wrapped) throws IOException {
super(wrapped, 500);
}
public void ping() {
this.onWire = 0;
this.flush();
}
@Override
public void flush() throws IOException {
if (this.onWire >= WIRE_CAPACITY) {
return; // we're exceeding capacity, don't to anything before the next ping
}
if (this.count > WIRE_CAPACITY) {
this.waiting = new byte[this.count - WIRE_CAPACITY];
System.arraycopy(this.buf, WIRE_CAPACITY, waiting, 0, this.count - WIRE_CAPACITY);
this.buf = Arrays.copyOfRange(this.buf, 0, WIRE_CAPACITY);
this.count = WIRE_CAPACITY;
} else {
this.waiting = new byte[0];
}
onWire += this.count;
super.flush();
if (this.waiting.length > 0) {
System.arraycopy(this.waiting, 0, this.buf, 0, Math.min(this.waiting.length, WIRE_CAPACITY));
this.count = Math.min(this.waiting.length, WIRE_CAPACITY);
}
}
}
但是,这不能正常工作。如果缓冲区包含超过WIRE_CAPACITY
个字节,则会丢失字节,如以下测试用例所示:
@Test
public void testStream() throws IOException {
final ArduinoBufferedOutputStream stream = new ArduinoDisplayOutputStream.ArduinoBufferedOutputStream(System.out);
stream.write("This is a very, very long string, which must be made even longer to demonstrate the problem".getBytes());
stream.flush();
stream.ping();
stream.ping();
stream.ping();
stream.ping();
stream.ping();
stream.ping();
stream.ping();
stream.ping();
stream.ping();
}
打印以下字符串:This is a very, very long string, which must be ma
,而我显然希望打印整个字符串。
有谁能看到我在这里做错了什么? 或者甚至更好,是否有人知道现有的库可以满足我的需求?
答案 0 :(得分:2)
我确实没有任何使用Arduino的经验,但我在处理Java Output / InputStreams方面有很多经验。拿一块盐,因为我无法在真正的Arduino设备上进行实际测试,但如果我在你的情况下,这就是我要做的。
我怀疑你对stream.write("This is a very, very long string, which must be made even longer to demonstrate the problem".getBytes());
的调用实际上是在缓冲整个字符串。当您随后调用stream.flush()
时,所有字符串数据都会立即“写入”Arduino设备。我怀疑这是因为你正在调用大小为500字节的BufferedOutputStream
超级构造函数。首先,我尝试将其减少到64字节。但是,我怀疑这可能无法解决问题,因为BufferedOutputStream
无法知道何时致电ping
。
我认为您要覆盖write
和flush
。根据Java规范,flush
背后的想法是flush
应该强制将任何未写入的缓冲字节写入底层流:
http://docs.oracle.com/javase/7/docs/api/java/io/OutputStream.html#flush()
我也可能只是扩展普通OutputStream
并自己做任何缓冲。我会覆盖write
方法,一次缓冲多达64字节的数据。如果64字节空间不足,请在填充的64字节缓冲区上调用super.write()
,然后在缓冲/写入更多数据之前调用super.flush()
然后调用ping()
。在while循环中重复此过程,直到缓冲区有足够的空间来容纳输入数据的剩余部分。然后重写flush
以写入任何未完全填充底层64字节缓冲区的数据(因此实际上并未通过之前调用super.write()
写入)。
这样,如果您对过多数据调用write
,您的类将写入基础流,直到最多保留64个字节,随后对flush
的调用将确保最后几个字节实际上写入Arduino。在一天结束时,您还可以获得完全符合Java的OutputStream
实现,这也很不错。
修改强> 的
我使用64字节只是因为你声明你的Arduino一次可以处理那么多。当然,如果有必要,可以减少这个,为了方便,我只是使用“64”。
答案 1 :(得分:1)
您的flush()
在每次通话中写入WIRE_CAPACITY
=最多25个字节。你调用它两次,总输出是50字节(假设cp1252编码)。我认为没有错。
也许您应该在flush()
内拨打ping()
?那么你的测试基本上就会成为:
@Test
public void testStream() throws IOException {
final ArduinoDisplayOutputStream.ArduinoBufferedOutputStream stream = new ArduinoDisplayOutputStream.ArduinoBufferedOutputStream(System.out);
stream.write("This is a very, very long string, which must be made even longer to demonstrate the problem".getBytes());
stream.flush();
stream.ping();
stream.ping();
... // as many ping()s as written bytes / WIRE_CAPACITY
}
答案 2 :(得分:0)
好吧,我想我最终做对了。延长BufferedOutputStream
是一个死胡同。相反,我使用一个单独的缓冲区,如@ ben-lawry建议的那样。通过使用ConcurrentLinkedQueue
作为缓冲区,我可以轻松地在每个WIRE CAPACITY
上轮询flush()
个字节数。
人们可能会说,效率不是很高,但与Arduino处理相比,Java方面的工作仍然会很快。
这是我得到的:
static class ArduinoBufferedOutputStream extends OutputStream {
public static final int WIRE_CAPACITY = 25;
private final ConcurrentLinkedQueue<Byte> buffer = new ConcurrentLinkedQueue<Byte>();
private int onWire = 0;
private OutputStream wrapped;
public ArduinoBufferedOutputStream(final OutputStream wrapped) throws IOException {
super();
this.wrapped = wrapped;
}
@Override
public void write(int i) throws IOException {
this.buffer.add((byte) i);
}
@Override
public void write(byte[] bytes) throws IOException {
for (byte aByte : bytes) {
this.buffer.add(aByte);
}
}
@Override
public void write(byte[] bytes, int off, int len) throws IOException {
for (int i = off; i < len; i++) {
this.buffer.add(bytes[i]);
}
}
public void ping() throws IOException {
synchronized (this.buffer) {
this.onWire = 0;
}
this.flush();
}
@Override
public void flush() throws IOException {
synchronized (this.buffer) {
for (; this.onWire < WIRE_CAPACITY && buffer.size() > 0; this.onWire++) {
wrapped.write(buffer.poll());
}
}
}
}
谢谢,@ gpeche和@ ben-lawry - 这肯定有助于更多地关注这个问题。