Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2015-10

Byte order modification in fpc on ARM?

8 messages · 5 people ·

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Bo Berglund

I am making a control program for a data collection system using FPC + Lazarus on a Raspberry Pi2 platform. I will use a number of Delphi units, which implement the communications and data handling needs in a way that works fine on a Windows platform.

While looking over existing code I see that there are instructions to modify received data from the instrument by reversing the byte order. The reason for that was that the instrument is based on a Motorola controller and it uses the opposite byte order as in the Intel CPU:s on the PC. Since download is of binary data areas in the instrument the byte order change was necessary for all multi-byte data like word and integers as well as real (floating point 32 bit values).

Now I wonder if it will be necessary also on an ARM platform like the RPi2?
Is there a function or such to interrogate the byte order of the platform FPC runs on? So that I could add a test at the start of download to check if swapping is needed?

Or is the ARM used on RPi2 working with the same byte order as the Motorola MC68HC11 MCU is?
In that case I must switch out the swapping...

Bo Berglund Developer in Sweden
Michael Van Canneyt
to Bo Berglund
Bo Berglund wrote 18 lines
I am making a control program for a data collection system using FPC + Lazarus on a Raspberry Pi2 platform. I will use a number of Delphi units, which implement the communications and data handling needs in a way that works fine on a Windows platform. While looking over existing code I see that there are instructions to modify received data from the instrument by reversing the byte order. The reason for that was that the instrument is based on a Motorola controller and it uses the opposite byte order as in the Intel CPU:s on the PC. Since download is of binary data areas in the instrument the byte order change was necessary for all multi-byte data like word and integers as well as real (floating point 32 bit values). Now I wonder if it will be necessary also on an ARM platform like the RPi2? Is there a function or such to interrogate the byte order of the platform FPC runs on? So that I could add a test at the start of download to check if swapping is needed?
There are compiler defines defines that give you the endianness.
{$IFDEF ENDIAN_BIG}
{$IFDEF ENDIAN_LITTLE}
And
{$IFDEF FPC_LITTLE_ENDIAN}
{$IFDEF FPC_BIG_ENDIAN}

Then there are BeToN, LeTon and and other functions that force a certain endianness or convert from a certain endianness to native endianness.

Michael.

Karoly Balogh (Charlie/SGR
to Bo Berglund: I am making a control program for a data collection system using FPC + Lazarus on a…

Hi,

Bo Berglund wrote 15 lines
I am making a control program for a data collection system using FPC + Lazarus on a Raspberry Pi2 platform. I will use a number of Delphi units, which implement the communications and data handling needs in a way that works fine on a Windows platform. While looking over existing code I see that there are instructions to modify received data from the instrument by reversing the byte order. The reason for that was that the instrument is based on a Motorola controller and it uses the opposite byte order as in the Intel CPU:s on the PC. Since download is of binary data areas in the instrument the byte order change was necessary for all multi-byte data like word and integers as well as real (floating point 32 bit values). Now I wonder if it will be necessary also on an ARM platform like the RPi2?

Yes.

Is there a function or such to interrogate the byte order of the platform FPC runs on? So that I could add a test at the start of download to check if swapping is needed?

There are compile time defines. ENDIAN_LITTLE and ENDIAN_BIG. As documented here:
http://www.freepascal.org/docs-html/prog/progap7.html

But the Raspberry Pi2's ARM is little endian, just like the x86 processors in a PC. It's also pretty easy to write a test function, which determines it runtime:

function islittleendian: boolean;
var
  x: longint;
begin
  x:=1;
  islittleendian:=pbyte(@x)^ = 1;
end;

This will return true on little endian processors, and false on big endians. Should return true on RPi2 and x86 PCs.

Or is the ARM used on RPi2 working with the same byte order as the Motorola MC68HC11 MCU is?

No, the MC68HC11 is big endian (according to the Internet, I have no direct experience with that platform).

BTW, big endian is also known as "network byte order" so you could look at sockets unit, which has network-to-host and host-to-network byte order which will just "always work" so compile to a no-op on big endian platforms, while doing the right conversion on little endian ones.

Charlie

Karoly Balogh (Charlie/SGR
to Jonas Maebe: Bo Berglund wrote on Mon, 19 Oct 2015: Use the…

Hi,

Jonas Maebe wrote 8 lines
Bo Berglund wrote on Mon, 19 Oct 2015: > Is there a function or such to interrogate the byte order of the > platform FPC runs on? So that I could add a test at the start of > download to check if swapping is needed? Use the http://www.freepascal.org/docs-html/rtl/system/ntobe.html function and you don't have to care about what your host platform uses.

Right, we have them in the system unit as well, no need for the sockets unit. Silly me.

Charlie

Bo Berglund
to Michael Van Canneyt: There are compiler defines defines that give you the endianness. {$IFDEF ENDIAN_BIG}…
Michael Van Canneyt wrote 7 lines
There are compiler defines that give you the endianness. {$IFDEF ENDIAN_BIG} {$IFDEF ENDIAN_LITTLE} And {$IFDEF FPC_LITTLE_ENDIAN} {$IFDEF FPC_BIG_ENDIAN}

Good, that would probably be what I need. Thanks!
Example:

procedure Swap4 (var Source);
{Swap the byte order of a 4-byte variable so it matches the PC i86}
type
    Reverse = packed record
      B1 : Byte;
      I2 : Word;
      B4 : Byte;
    end;
var
    Bsw : Byte;
begin
  {$IFDEF FPC_BIG_ENDIAN}
    Bsw :=  Reverse(Source).B1;
    Reverse(Source).B1 := Reverse(Source).B4;
    Reverse(Source).B4 := Bsw;
    Reverse(Source).I2 := Swap(Reverse(Source).I2);
  {$ENDIF}
end;

Then all functions calling these functions could stay as they are and it will work on both the PC and Raspberry Pi2.

Just have to make sure I don't have the endians reversed...

Bo Berglund Developer in Sweden
Sven Barth
to Bo Berglund
"Bo Berglund" wrote 39 lines
On Mon, 19 Oct 2015 15:30:36 +0200 (CEST), Michael Van Canneyt wrote: >There are compiler defines that give you the endianness. >{$IFDEF ENDIAN_BIG} >{$IFDEF ENDIAN_LITTLE} > >And >{$IFDEF FPC_LITTLE_ENDIAN} >{$IFDEF FPC_BIG_ENDIAN} Good, that would probably be what I need. Thanks! Example: procedure Swap4 (var Source); {Swap the byte order of a 4-byte variable so it matches the PC i86} type Reverse = packed record B1 : Byte; I2 : Word; B4 : Byte; end; var Bsw : Byte; begin {$IFDEF FPC_BIG_ENDIAN} Bsw := Reverse(Source).B1; Reverse(Source).B1 := Reverse(Source).B4; Reverse(Source).B4 := Bsw; Reverse(Source).I2 := Swap(Reverse(Source).I2); {$ENDIF} end; Then all functions calling these functions could stay as they are and it will work on both the PC and Raspberry Pi2. Just have to make sure I don't have the endians reversed...

You don't need to implement this yourself. Just use NToBe when transmitting to the Motorola unit and BeToN when receiving from it. Both functions provide overloads for the usual sizes (see the documentation link provided by Jonas).

Regards,
Sven

Bo Berglund
to Jonas Maebe: Bo Berglund wrote on Mon, 19 Oct 2015: Use the…
Jonas Maebe wrote 10 lines
Bo Berglund wrote on Mon, 19 Oct 2015: > Is there a function or such to interrogate the byte order of the > platform FPC runs on? So that I could add a test at the start of > download to check if swapping is needed? Use the http://www.freepascal.org/docs-html/rtl/system/ntobe.html function and you don't have to care about what your host platform uses.

This sounds OK were it not for the fact that it has overloaded implementations for:
Smallint, Word, LongInt, DWord, Int64, QWord.

I need to convert not only integer types but also single precision floats. These are the main part of the data.

But I have found that I can make an endian test like this:

function PCEndian: boolean;
var
  sTest: string
  fTest: single;
begin
  sTest := #0#0#$20#$40;
  Move(sTest[1], fTest, 4);
  Result := Abs(fTest - 2.5) < 0.01;
end;

Single precision value with hex representation 40200000 is 1.1569E-41 on a PC but 00002040 is exactly 2.5.

Bo Berglund Developer in Sweden