2

Java アプリケーションから USB 接続を介して、反対側の Arduino にデータをプッシュしています。

Arduino は最後に 64 バイトのデータしかバッファリングできないため、Java アプリからの「一口」ごとに送信されるバイト数を制限する必要があります (余分なバイトは失われます)。Arduino コードは、より多くのバイトを受信する準備ができると、単純な ping をワイヤに送信します。

そのため、実際の出力ストリームをラップBufferedOutputStreamする classを拡張しました。ArduinoBufferedOutputStreamJava アプリのさまざまな部分から、任意のバイト数が ( を使用してwrite(byte b)) ストリームに書き込まれ、ストリームはときどきflush編集されます。

私が必要なのは(私が推測する) BufferedOutputStreams 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、明らかに文字列全体を出力したいのですが。

ここで私が間違っていることを誰かが見ることができますか? またはさらに良いことに、私が望むことを行う既存のライブラリを知っている人はいますか?

4

3 に答える 3

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デバイスに一度に「書き込まれ」ます。これが疑われる理由はBufferedOutputStream、500バイトのサイズのスーパーコンストラクターを呼び出しているためです。まず、それを64バイトに減らしてみます。ただし、BufferedOutputStreamいつ呼び出すかわからないため、これでも問題が解決しない可能性がありますping

writeとの両方をオーバーライドしたいと思うでしょうflushflushJava仕様によると、背後にある考え方はflush、書き込まれていないバッファリングされたバイトを強制的に基になるストリームに書き込むことになっているということです。

http://docs.oracle.com/javase/7/docs/api/java/io/OutputStream.html#flush()

また、おそらくプレーンオレOutputStreamを拡張して、自分でバッファリングを行うでしょう。メソッドをオーバーライドして、一度にwrite最大64バイトのデータをバッファリングします。64バイトでは十分なスペースがない場合はsuper.write()、いっぱいになった64バイトのバッファーを呼び出しsuper.flush()てから呼び出してからping()、データをバッファリング/書き込みする前に呼び出します。入力データの残りを保持するのに十分なスペースがバッファにあるまで、このプロセスをwhileループで繰り返します。次に、オーバーライドflushして、基になる64バイトのバッファーを完全に満たしていない(したがって、以前のへの呼び出しによって実際に書き込まれなかったsuper.write())データを書き込みます。

このように、writeあまりにも多くのデータを呼び出すと、クラスは最大64バイトが残るまで基になるストリームに書き込み、その後の呼び出しでflush最後の数バイトが実際にArduinoに書き込まれるようにします。結局のところ、完全にJavaに準拠しOutputStreamた実装も得られます。これも素晴らしいことです。

編集

Arduinoが一度に最大64バイトを処理できるとあなたが言ったという理由だけで、私は64バイトを使用しています。もちろん、これは必要に応じて減らすことができます。私は便宜上「64」を使用しています。

于 2012-11-05T22:12:42.860 に答える
1

書き込み= 各flush()呼び出しWIRE_CAPACITYで最大 25 バイト。2 回呼び出すと、合計出力は 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
}
于 2012-11-05T22:15:35.100 に答える
0

わかりました、やっとそれが正しかったと思います。延長BufferedOutputStreamは行き止まりでした。代わりに、@ben-lawry が提案したように、別のバッファーを使用します。そして、そのバッファとして a を使用することで、各 のバイト数をConcurrentLinkedQueue簡単にポーリングできます。WIRE CAPACITYflush()

それほど効率的ではないと言う人もいるかもしれませんが、Java 側で行われている処理は、Arduino の処理に比べれば依然として高速です。

これが私が得たものです:

   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 に感謝します。この問題にさらに目を向けるのに役立ちました。

于 2012-11-05T23:52:49.370 に答える