2016-10-12 8 views
2

私はC#プログラミングの新機能があり、通常はPLCプログラミングとHMI/SCADAシステム開発を扱います。最後の1つはC/VBSスクリプティングのみです。C#オブジェクト型からバイト[]への変換、TCP経由での送信、および二重への変換

最近私のプロジェクトの1つでは、LabVIEWで最初に開発されたSCADAシステムをSiemens WinCCアプリケーションにアップグレード/移行しました。 LabVIEWプロジェクトでは、バイト配列を受け取っていたC#アプリケーション(TCPクライアント)を実行している別のPCにTCPソケットを介してタグ値(タグ名と一緒にバンドルされ、文字列に変換された二重の値)値を倍にする

LabVIEW TCP Server Example

し、別のPC上で実行されているTCPクライアントのコードの一部。

TcpClient     _client; 
NetworkStream    _stream = null; 
byte[]      _data = new byte[8192]; 

{...} 
try 
{ 
    _client  = new TcpClient(properties.IpAddress, properties.Port); 
} 
{...} 
    try 
    { 
     _stream  = _client.GetStream(); 
{...} 
     int NumBytesInRecvBuffer = _stream.Read(_data, 0, 8192); 

{...} 
      if(_data[3] == paramCount) 
      { 
       for(int i = 0; i < paramCount; i++) 
       { 
        double Value = MakeDouble(_data, 4+(i*8)); 
        fmacsParams[i].NumericalValue = Value; 
       } 
      } 
    } 

MakeDouble()は、TCPクライアントで機能します。

private unsafe double MakeDouble(byte[] data, int StartIndex) 
{ 
    double result; 
    byte* b = (byte*)&result; 
    b[0] = data[StartIndex + 7]; 
    b[1] = data[StartIndex + 6]; 
    b[2] = data[StartIndex + 5]; 
    b[3] = data[StartIndex + 4]; 
    b[4] = data[StartIndex + 3]; 
    b[5] = data[StartIndex + 2]; 
    b[6] = data[StartIndex + 1]; 
    b[7] = data[StartIndex + 0]; 
    return(result);   
} 

私はその後、倍増すると、配列をバイトに変換され

object ft107Flow = oType.InvokeMember("GetValue", System.Reflection.BindingFlags.InvokeMethod, null, wincc, new object[] { "FT107_Flow" }); 

オブジェクト

としてTCPリスナーであるC#で簡単なアプリケーションを開発するために管理し、WinCCランタイムからタグの値を読み取ります。最後に、配列内のすべてのバイトが関数SwapBytes()でスワップされ、データ配列に配置され、TCP上でバイト配列として送信されます。

{...} 
const int paramCount = 30; 
double[] WinCC_Tags = new double[paramCount]; 

WinCC_Tags[0] = Convert.ToDouble(ft107Flow); 
{...} 
byte[] data = new byte[4 + paramCount * 8]; 
Array.Clear(data, 0, data.Length); 

byte[] UnswappedByte; 
byte[] SwappedByte; 

data[3] = paramCount; 

for (int i = 0; i < paramCount; i++) 
{ 
    int j; 

    UnswappedByte = BitConverter.GetBytes(WinCC_Tags[i]); 
    SwappedByte = SwapBytes(UnswappedByte, 0); 

    j = (4 + i * 8); 

    data[j] = SwappedByte[0]; 
    data[j + 1] = SwappedByte[1]; 
    data[j + 2] = SwappedByte[2]; 
    data[j + 3] = SwappedByte[3]; 
    data[j + 4] = SwappedByte[4]; 
    data[j + 5] = SwappedByte[5]; 
    data[j + 6] = SwappedByte[6]; 
    data[j + 7] = SwappedByte[7]; 
} 

私が今直面している問題は、クライアントが受け取ったこれらの値が同じではないということです。この倍精度または三重変換(オブジェクト - >倍精度、倍精度 - >バイト配列、バイト配列 - >倍精度)のために精度が失われたようです。

たとえば、WinCCランタイムでは、タグ値は15.3となります。 doubleに変換すると、15.300000190734863になります。次に、data[12..19] = {0x40, 0x2e, 0x99, 0x99, 0xA0, 0x00, 0x00, 0x00}。次のように

クライアントによって受信されたデータが見える:

_data[12..19] = {0x40, 0x2e, 0x99, 0x99, 0xA0, 0x00, 0x00, 0x00}

Value = 15.001172065734863

変換が等しくないした後、同じデータ(バイト配列)は、クライアント、しかし値によって受信されるようですWinCCランタイムの値に設定します。

TCPクライアントが変換後にMakeDouble()機能を使用し、TCPクライアントコードに触れずに(修正不可能に)適切なデータを受信できるように、TCPリスナー側を変更する方法があるかどうか確認してください。

+0

簡易:バイト[]データ=新しいバイト[] {0x40の、0x2e、0x99、0x99、0xA0を、0x00に、0x00に、0x00を}。 double number = BitConverter.ToDouble(data.Reverse()。ToArray()、0);私は15.300を得る。 – jdweng

+0

彼のMake 'MakeDouble()'関数はうまく動いています –

答えて

1

自分でバイトを交換する代わりに、 thisパッケージを使用することをおすすめします。それは、あなたが私はC#は危険なコードやポインタを処理する方法とスーパー慣れていないんだけど、私はCの観点からこれを答えていた場合、この

using (MemoryStream stream = new MemoryStream()) 
using (BeBinaryReader BeReader = new BeBinaryReader(stream)) 
{ 
    stream.Position = 3; 
    if(BeReader.ReadByte() == paramCount) 
    for (int i = 0; i < paramCount; i++) 
    { 
     double Value = BeReader.ReadDouble(); 
     fmacsParams[i].NumericalValue = Value; 
    } 
} 
+0

私はTCPクライアントコードを変更することができません。 – matmix1

+0

しかし、あなたのデータを読み書きするためには、BigEdian BinaryReader/Writerを使うことができます。 –

+0

関数MakeDouble()の中に何があるかを証明する方法はありませんか?精度を失うような方法でバイト配列をdoubleに変換します。その結果、わずかに異なる値を返しますか? – matmix1

0

ようにそれを使用することができ、それBigEdian BinaryReader /ライター

です6番目のバイトが何かで上書きされているように見えます。

15.300000190734863と15.0011720657349差が {$ 00、$ 00、$ 00、0xA0を、0x99、0x99、0x2e、0x40の}と{$ 00、$ 00、$ 00、0xA0を、0x99、0x00の、0x2e、0x40のあります}。

次のコードを試してみ

private double MakeDouble(byte[] data, int StartIndex) 
    { 
     double result; 
     byte[] b = new byte[8]; 
     b[0] = data[StartIndex + 7]; 
     b[1] = data[StartIndex + 6]; 
     b[2] = data[StartIndex + 5]; 
     b[3] = data[StartIndex + 4]; 
     b[4] = data[StartIndex + 3]; 
     b[5] = data[StartIndex + 2]; 
     b[6] = data[StartIndex + 1]; 
     b[7] = data[StartIndex + 0]; 
     result = BitConverter.ToDouble(b, 0); 
     return (result); 
    } 
+0

同じコードが2つの異なるPCの同じソフトウェアによってコンパイルされると、実際には異なる結果が生じることはありますか? – matmix1

+0

コンパイラやCLRのバージョンや設定が異なると、一般的に(C#ではなく)、さまざまな出力が得られます。 Cコードでは、オプティマイザは、最適化されていない方法でコンパイルされたときに期待どおりに実行されても、コードが適切なコーディング標準に準拠していないと、予期せず実行する可能性があります。私はこれを例として言及しています。 2つの質問: a)上記のコードを実行しようとしましたか? b)1台のマシンでビルドしてもう1台のビルドを実行しましたか? – bizziedog

関連する問題