0

各ペイロードバイトのMSBをMSBコレクションバイト(セプテット)に抽出して送信し、受信側でMSBを再注入するバイナリプロトコルがあります。ペイロードは、送信者に応じてn個の4バイトフレームで構成されます(私の場合は6個)。

これらは、ワイヤー上に見られるように、セプテット(最後のバイト)を持つ2つのサンプルフレームです。

0x2E 0x00 0x5F 0x00 0x04
0x79 0x01 0x38 0x22 0x04

これらは同じフレームであり、クライアント側であり、MSBが再注入されています。

0x2E 0x00 0xDF 0x00
0x79 0x01 0xB8 0x22

変換を行うC関数は、このドキュメントの9ページと10ページで定義されています。これらの私のバージョンは、Javaで以下のとおりです。私が抱えている問題は、これがどれも機能しないことであり、その理由について私は混乱しています。ワイヤーから4バイトを渡し、同じバイトをそのまま取得します。私はここで何が悪いのかを理解するのに役立つかもしれません(おそらく私が見ることができない些細なことです)。

private static byte[] vbusExtractSeptett(byte[] data, int offset, int length) {
    byte septett = 0;
    for (int i = 0; i < length; i++) {
        if ((data[offset + i] & 0x80) != 0) {
            data[offset + i] &= 0x7F;
            septett |= 1 << i;
        }
    }

    data[offset + length] = septett;
    return data;
}

private static byte[] vbusInjectSeptett(final byte[] data, int offset, int length) {
    byte septett = data[offset + length];

    for (int i = 0; i < length; i++) {
        if ((septett & (1 << i)) != 0)
            data[offset + i] |= 0x80;
    }

    return data;
}
4

2 に答える 2

1

Java では、バイトはsignedです。すべてのコードを読まずに、それが問題だと思います。

ドキュメント内の C コードは unsigned char math を使用しています。

Java には "unsigned" がないため、すべての計算を short (または int) で行ってからバイトに戻す必要があります。符号ビットをマスクしてください。たとえば、次のようなものです。

byte theResult = theIntIDidtheMathOn & 0xFF;
data[index] = theResult;
于 2012-04-24T03:30:58.490 に答える
0

他の答えは正しいです。Java の符号付きバイトの使用を考慮していません。

これを解決するには、いくつかの可能性があります。

  1. 「& 0xFF」で上記のことを行うことができます
  2. すべてをintとして扱うことができます(以下で行ったように)
  3. ライブラリを使用して支援することができます。いくつかの例としては、JOOU (符号なしタイプの欠如に対応して開始された) またはnettyチャネル バッファ (注: netty はソケットなどのネットワーク IO に焦点を当てていますが、そのチャネル バッファ クラスはバイトストリームおよび符号付き/符号なしの処理に最適です。さまざまな長さのタイプであり、私はあなたが扱っているようなバイナリプロトコルを変換するためにかなり多く使用しました.)

以下に、あなたの質問に対する「解決策」を書きました。

public class SOAnswer
{
    private static void vbusExtractSeptett(int[] data, int offset, int length) {
        int septett = 0;

        for (int i = 0; i < length; i++) {
            if ((data[offset + i] & 0x80) != 0) {
                data[offset + i] &= 0x7F;
                septett |= 1 << i;
            }
        }

        data[offset + length] = septett;
    }

    private static void vbusInjectSeptett(final int[] data, int offset, int length) {
        int septett = data[offset + length];

        for (int i = 0; i < length; i++) {
            if ((septett & (1 << i)) != 0)
                data[offset + i] |= 0x80;
        }

        // clear the septett byte
        data[offset + length] = 0x00;
    }

    private static void printIntArrayAsHEX(int[] array)
    {
        StringBuilder builder = new StringBuilder();

        for ( int a : array )
        {
            String s = Integer.toHexString( a );
            if (s.length() == 1)
                builder.append( "0" );
            builder.append(s + ":");
        }

        builder.substring( 0, builder.lastIndexOf( ":" ) - 1 );

        System.out.println(builder.toString());
    }

    public static void main( String[] args )
    {
        // Create an array long enough for the extracting/injecting
        int[] arr = new int[]{0x2E, 0x00, 0xDF, 0x00, 0x00};
        // see what it looks like
        printIntArrayAsHEX(arr);

        // perform extraction
        vbusExtractSeptett( arr, 0, 4 );
        // see what it looks like
        printIntArrayAsHEX(arr);

        // Perform injection
        vbusInjectSeptett( arr, 0, 4 );
        // see what it looks like
        printIntArrayAsHEX(arr);
    }
}

1 つの推奨事項は、C コードを逐語的に再実装する必要があるかどうかを検討することです (特に、プリミティブ型の配列、配列へのオフセット、および配列の長さを渡す非常に関数的なプログラミング スタイル) )。たぶん、このようなものはもっとオブジェクト指向になるでしょう:

private static int[] vbusExtractSeptettJAVASTYLE(int[] data) {
    int[] extractedData = Arrays.copyOf( data, data.length +1 );

    int septett = 0;

    for (int i = 0; i < data.length; i++) {
        if ((data[i] & 0x80) != 0) {
            extractedData[i] = data[i] &= 0x7F;
            septett |= 1 << i;
        }
    }

    extractedData[extractedData.length-1] = septett;

    return extractedData;
}
于 2012-04-24T04:32:51.547 に答える