1

私はソケットからのDelphiコードの読み取りをフォローしています:

type
   RegbusReq2=packed record 
     Funct:char;             
     Device:char;            
     Device1:char;
     Starting:integer;       
     Quantity:smallint;      
     _CRC:Word;              
     stroka:char;            
   end;

   type                         
     crcReg=packed record
     buf:array[0..2] of byte;
     value:array[0..5] of byte;
   end;

   type                          
   myRB=record                       
   case byte of
    0:(data:RegbusReq2);
    1:(Buff:crcReg);
   end;

   type
   outVal=packed record
    cap:array[0..8] of byte;
    val:array[0..3] of single;
   end;

   type
   outValBuff=record
   case byte of
    0:(val:outVal);
    1:(Buff:array [1..25] of byte);
   end;


var
  Form1: TForm1;
  hCommFile:THandle;  
  typeCon:byte;       
  cs1: TClientSocket;
...

データを読み取るためのタイマーティック:

Procedure TForm1.Timer1Timer(Sender: TObject);
var
  DataReq:myRB;
  output:outValbuff;
  Wr,Rd:Cardinal;
  i:integer;
  st:string;
begin
    //çàïîëíåíèå çàïðîñà
  DataReq.data.Funct:=chr(63);    //êîìàíäà "?"
  DataReq.data.Device:=chr(48);     //íîìåð ïðèáîðà ñò
  DataReq.data.Device1:=chr(49);    //íîìåð ïðèáîðà ìëàäøèé
  DataReq.data.Starting:=2088;     //àäðåñ â äåñ ôîðì
  DataReq.data.Quantity:=16;       //ðàçìåð äàííûõ
  DataReq.data._CRC:=CRC2(@DataReq.Buff.value,6);      //ÊÑ
  DataReq.data.stroka:=chr(13);             //ïåðåâîä ñòðîêè

PurgeComm(hCommFile,PURGE_RXCLEAR or PURGE_TXCLEAR);
if typecon=1 then begin   //COM-ïîðò
 WriteFile(hCommFile,DataReq.data,SizeOf(DataReq.data),Wr,nil);
 ReadFile(hCommFile,Output.buff,SizeOf(Output.Buff),Rd,nil);
end;
if typecon=2 then begin    //ethernet
  cs1.Active:=true;
  cs1.Socket.SendBuf(DataReq.data,SizeOf(DataReq.data));
  cs1.Socket.ReceiveBuf(output.buff,SizeOf(Output.Buff));
  cs1.Active:=false;
 end;

 for i:=1 to 25 do
 st:=st + '_' + inttostr(output.buff[i]);
 memo1.Lines.Add(st);

 edit1.Text:=FloatToStr(Round(output.val.val[0]
 *exp(2*ln(10)))/(exp(2*ln(10))));
 edit2.Text:=FloatToStr(Round(output.val.val[1]
 *exp(2*ln(10)))/(exp(2*ln(10))));
 edit3.Text:=FloatToStr(Round(output.val.val[2]
 *exp(2*ln(10)))/(exp(2*ln(10))));
 edit4.Text:=FloatToStr(Round(output.val.val[3]
 *exp(2*ln(10)))/(exp(2*ln(10))));

end;

私はC#コードに従っています:

[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]        
        public struct RegBusRec
        {
            public char Funct;
            public char Device;
            public char Device1;
            public int Starting;
            public short Quantity;
            public ushort _CRC;
            public char Message;
        }
...
private void timer1_Tick(object sender, EventArgs e)
        {
            byte[] CRCc = new byte[6];
            byte[] tmp;
            byte[] output = new byte[25];
            RegBusRec req2 = new RegBusRec();
            Crc16 crc16 = new Crc16();
            req2.Funct = '?';
            req2.Device = '0';
            req2.Device1 = '1';
            req2.Starting = 2088;
            req2.Quantity = 16;
            req2.Message = '\r';
            tmp = BitConverter.GetBytes(req2.Starting);
            CRCc[0] = tmp[0];
            CRCc[1] = tmp[1];
            CRCc[2] = tmp[2];
            CRCc[3] = tmp[3];
            tmp = BitConverter.GetBytes(req2.Quantity);
            CRCc[4] = tmp[0];
            CRCc[5] = tmp[1];
            req2._CRC = crc16.ComputeChecksum(CRCc);
            textBox6.Text += Environment.NewLine;
            textBox6.Text += "CRC: " + req2._CRC;
            cl.Client.Send(StructureToByteArray(req2));
            cl.Client.Receive(output);
            byte[] val = new byte[4];
            val[0] = output[15];
            val[1] = output[16];
            val[2] = output[17];
            val[3] = output[18];
            textBox6.Text += Environment.NewLine;
            textBox6.Text += "Query: ";
            for (int i = 0; i < StructureToByteArray(req2).Length; i++)
            {
                textBox6.Text += StructureToByteArray(req2)[i] + "_";
            }
            textBox2.Text = BitConverter.ToSingle(val,0).ToString();
            textBox6.Text += Environment.NewLine;
            textBox6.Text += "Data: ";
            for (int i = 0; i < output.Length; i++)
            {
                textBox6.Text += output[i] + "_";
            }
        }
...
static byte[] StructureToByteArray(object obj)
        {

            int len = Marshal.SizeOf(obj);
            byte[] arr = new byte[len];
            IntPtr ptr = Marshal.AllocHGlobal(len);
            Marshal.StructureToPtr(obj, ptr, true);
            Marshal.Copy(ptr, arr, 0, len);
            Marshal.FreeHGlobal(ptr);
            return arr;
        }

CRCは正しく計算されます。しかし、textBox2.Textの番号が間違っています-乱数。この番号を正しく取得するにはどうすればよいですか?前もって感謝します。

DelphiデバッガーのScrrenshot:

ここに画像の説明を入力してください

4

1 に答える 1

2

OK、私はそれを解読したかもしれないと思いますが、私はそれを当てにしません。

C#コードが。に予期しない値を表示しているとおっしゃっているようですtextBox2。C#コードを見ると、textBox2からのデータが表示されますval。そしてval、そのように割り当てられます:

val[0] = output[15];
val[1] = output[16];
val[2] = output[17];
val[3] = output[18];

outputこれはC#バイト配列であるため、ゼロベースのインデックスを使用することに注意してください。

Delphiコードでは、一致するデータ構造は次のとおりです。

outVal=packed record
  cap:array[0..8] of byte;
  val:array[0..3] of single;
end;

outValBuff=record
  case byte of
  0:(val:outVal);
  1:(Buff:array [1..25] of byte);
end;

したがって、cap最初の9バイトを消費し、次の16バイトは4つの単精度値です。C#バイト配列に関して:

  • capoutput[0]することですoutput[8]
  • val[0]output[9]することですoutput[12]
  • val[1]output[13]することですoutput[16]
  • val[2]output[17]することですoutput[20]
  • val[3]output[21]することですoutput[24]

しかし、あなたはに読んoutput[15]でいるので、の半分との半分をoutput[18]組み合わせます。val[1]val[2]

つまり、インデックスを修正する必要があります。


今、あなたはそれを必要以上に複雑にしています。次のようなことを実行して、4つの単一の値すべてを取得できます。

single[] val = new single[4];
int byteIndex = 9;
for (int i=0; i<4; i++)
{
    val[i] = BitConverter.ToSingle(val, byteIndex);
    byteIndex += 4;
}

そして、バイトごとに物事をにコピーするのではなくCRCc、これを行います:

Buffer.BlockCopy(BitConverter.GetBytes(req2.Starting), 0, CRCc, 0, 4);
Buffer.BlockCopy(BitConverter.GetBytes(req2.Quantity), 0, CRCc, 4, 2);
于 2012-05-12T13:53:39.170 に答える