Search code examples
indydelphi-10.1-berlin

Unexpected results converting TIdBytes to Integer using BytesToInt64()


I am reading UDP packets using the TIdUDPServer.OnUDPRead event. Embedded in each packet is an 8-byte QUint64, which represents a radio frequency. I am trying to read that frequency.

All attempts using BytesToInt64() are resulting in erroneous results. I have verified the data is correct by reading the hex values with Wireshark and using a web-based hex-to-decimal converter.

I know the frequency in the packet data starts at position 23 and is 8 bytes long.

procedure TWSJTxUDPClient.IdUDPServer1UDPRead(AThread:  TIdUDPListenerThread;
  const AData: TIdBytes; ABinding: TIdSocketHandle);
var
  FreqInt: Int64;

begin
  FreqInt := BytesToInt64(AData,23);
  LabelFreq.Caption := IntToStr(FreqInt);
end;

Here is the data on the wire in hex notation, starting at position 23:

00 00 00 00 00 6b f0 d0

Which represents a freq of 7074000 hz.

My code above is resulting in a freq value of 58811137507983360.

I have also confirmed the hex data by reading each byte with the Ord() function on a string representing the frequency.

FreqStr := BytesToString(Adata,23,8);
Int8 := Ord(FreqStr[8]);

Int8 is now = 208 - the correct value for 0xd0. Did same for bytes 5, 6, & 7. Confirmed.

So I know I am missing something basic.


Solution

  • You are not taking endian into account.

    Decimal 7074000 is hex 0x6BF0D0. Decimal 58811137507983360 is hex 0xD0F06B00000000. See the similarity? Their bytes are in opposite order.

    The bytes in your packet are in network byte order (big endian) but your machine uses little endian instead. You need to swap the bytes of the Int64. You can use Indy's GStack.NetworkToHost() method for that:

    procedure TWSJTxUDPClient.IdUDPServer1UDPRead(AThread: TIdUDPListenerThread; const AData: TIdBytes; ABinding: TIdSocketHandle);
    var
      FreqInt: Int64;
    begin
      FreqInt := BytesToInt64(AData, 23);
      FreqInt := Int64(GStack.NetworkToHost(UInt64(FreqInt)));
      LabelFreq.Caption := IntToStr(FreqInt);
    end;