1

I've following Delphi code reading from socket:

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;
...

Timer tick fo reading data:

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;

I've following C# code:

[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 calc correctly. But I get wrong number for textBox2.Text - random numbers. How I can correctly get this numbers? Thanks in advance.

Scrrenshot of Delphi debugger:

enter image description here

0

1 Answer 1

2

OK, I think I might have deciphered it, but I wouldn't count on it.

You seem to be saying that the C# code displays an unexpected value in textBox2. Looking at the C# code, textBox2 displays data coming from val. And val is assigned like so:

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

Note that output is a C# byte array and so uses zero-based indexing.

In your Delphi code, the matching data structures are:

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;

So, cap consumes the first 9 bytes and then the next 16 are the 4 single precision values. In terms of the C# bytes array:

  • cap is output[0] to output[8],
  • val[0] is output[9] to output[12],
  • val[1] is output[13] to output[16],
  • val[2] is output[17] to output[20],
  • val[3] is output[21] to output[24].

But you are reading output[15] to output[18], and so combine half of val[1] with half of val[2].

In short, you just need to fix up your indexing.


Now, you are making it much more complex that it needs to be. You could do something like this to get hold of all 4 single values:

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

And rather than copying things around byte by byte into CRCc, do this:

Buffer.BlockCopy(BitConverter.GetBytes(req2.Starting), 0, CRCc, 0, 4);
Buffer.BlockCopy(BitConverter.GetBytes(req2.Quantity), 0, CRCc, 4, 2);
Sign up to request clarification or add additional context in comments.

3 Comments

+1 for detective effort considering the lack of clarity in the question.
@Superjet Does this help you out?
Thank you David for help! But now I can't check thi fixs because thisdevice on my work - today is Sunday. Tomorrow I will answer for this.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.