2017-04-12 3 views
0

これまでシリアルポートからの着信データを処理するコードを書いています。データは固定フォーマットです。 このコードをjava(android)に移行します。しかし、私は多くの障害を見ます。パックされたC構造体と関数をjavaに移植できますか?

実際のコードはより複雑ですが、私はここに簡略化されたバージョンがあります:

#define byte unsigned char 
#define word unsigned short 

#pragma pack(1); 
struct addr_t 
{ 
    byte foo; 
    word bar; 
}; 
#pragma pack(); 


bool RxData(byte val) 
{ 
    static byte buffer[20]; 
    static int idx = 0; 

    buffer[idx++] = val; 

    return (idx == sizeof(addr_t)); 
} 

Rxデータ機能は、バイトが受信されるたびに呼び出されます。データの完全なチャンクが入っている場合、trueを返します。

障害物のいくつか:

使用されるデータ型は、Javaには使用できません。他のスレッドでは、より大きなデータ型を使用することをお勧めしますが、この場合、これは実行可能な解決策ではありません。

この場合、構造体のサイズは正確に3バイトです。 #pragmaステートメントが重要な理由です。さもなければ、Cコンパイラはメモリ使用のためにそれを「最適化」し、その結果として異なるサイズにすることができる。

Javaにはsizeof関数がありません。この種の状況では、代替手段が見つかりませんでした。

私は 'sizeof'を3の固定値に置き換えることができますが、それは非常に悪い練習IMOになります。

Javaでこのようなコードを書くことは可能でしょうか?または、Android StudioにネイティブのCソースを追加することをお勧めしますか?

+1

'native'とJNIを使​​用できませんか?過度のものかもしれないが、見る価値があるかもしれない。少なくともあなたはCコードをそのまま保ちます。それ以外の場合は、Javaで 'byte [3]'を使用します。そしてきちんと言葉にされた質問。 downvoteについてはわからない。ところで、 'unsigned short'のサイズはプラットフォームによって異なります。 – Bathsheba

+0

Javaプリミティブデータ型は、プラットフォームに依存してはならない固定サイズなので、値をハードコーディングしても問題にはなりません。単純に、ByteInputStreamを使用して適切なバイト数をフィールドに読み込むdeserialize関数を記述することができます。 –

+0

'RxData()'を20回以上呼び出すと、バッファオーバーフローが発生します。 –

答えて

0

あなたのCコードにも問題があります。技術的には、あなたはcharshortの大きさが分かりません。おそらくuint8_tuint16_tがそれぞれ必要です。また、私はどのようにポータブルパッキングがわからない。

Javaでは、クラスが必要です。クラスは、それを初期化するために必要なバイト数を示します。

class Addr 
{ 
    private byte foo; 
    private short bar; 
    public final static int bufferBytes = 3; 

    public int getUnsignedFoo() 
    { 
     return (int)foo & 0xff; 
    } 
    public int getUnsignedBar() 
    { 
     return (int)bar & 0xffff; 
    } 
} 

おそらく標準ライブラリに適切なクラスが存在するかもしれませんが、おそらくバッファのクラスです。

class Buffer 
{ 
    private final static int maxSize = 20; 

    private byte[] bytes = new byte[maxSize]; 
    private int idx = 0; 
    private bool rxData(byte b) 
    { 
     bytes[idx++] = b; 
     return idx == Addr.bufferBytes; 
    } 
} 

は、あなたのプロトコルのあなたの仕様が言う必要があるので、これは実際にそれを行うには良い方法である、3のhardcodednessについての質問に答えるために「fooの1バイト、バー用の2つのバイト」ではありません「 char型とshort型のC構造体をパックしました "。バッファをdeserialiseする一つの方法は、このようなものです:それは何な限り、ご使用のプラットフォームに依存しているため

public class Addr 
{ 
    // All the stuff from above 
    public Addr(byte[] buffer) 
    { 
     foo = buffer[0]; 
     bar = someFunctionThatGetsTheEndiannessRight(buffer[1], buffer[2]); 
    } 
} 

TIは、バーが意図的に曖昧に計算されている方法を残しています。例えばビットシフトで簡単に行うことができます。

(((short)buffer[1] & 0xff) << 8) | ((short)buffer[2] & 0xff) 

しかし、より良いオプションがあります。たとえば、エンディアン発行に対処するための機械を持つjava.nio.ByteBufferを使用できます。

+0

ありがとうございます。これはきちんとした解決策のようです。私はまだ3の固定値が嫌いですが、別の方法がないかもしれません。私のCコードでは、次のステップはaddr_t * ptr =(addr_t *)バッファのようなものになります。そうすれば、それぞれのメンバーを別々に割り当てる必要なしに、自動的に処理される便利な構造になります。 – Hneel

+0

私はそれが次のステップかもしれないと思っていましたが、それを行うにはかなり悪い方法です。あなたのマシンのエンディアンはプロトコルと同じであると信じています。 – JeremyP

関連する問題