Sign in Join

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

Mailing lists / fpc-pascal / 2016-06

Delphi-FPC portable code for endian conversion

4 messages · 2 people · –

Reply by email Subscribe to this list Your subscription

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

Bo Berglund

I have a class file implementing interfaces for talking to an embedded system and I intend to use this class for both Delphi (on Windows) and FPC (on ARM Linux)
One part of this class deals with transfers of binary data to/from the embedded system, which is based on a Motorola MCU and is BigEndian. When the class is compiled on Windows it needs to swap 2- and 4-byte values to correct for endian differences between Intel and Motorola CPU:s.
I have a working code to do this on Windows, but on FPC I would like to use the BEToN() and NToBE functions to convert 16 bit words, 32 bit integers and 32 bit floats (single prec) as needed. I.e. if running in Delphi on Windows use the Swap and Swap4 functions but if running on FPC use the BEToN and NToBE.
I think I have understood that these functions will convert only if the current system is using a different endian than specified by the call.

I have tried to figure out a set of {$IFDEF } statements but so far with no success.

Bo Berglund Developer in Sweden
Sven Barth
to Bo Berglund
"Bo Berglund" wrote 17 lines
I have a class file implementing interfaces for talking to an embedded system and I intend to use this class for both Delphi (on Windows) and FPC (on ARM Linux) One part of this class deals with transfers of binary data to/from the embedded system, which is based on a Motorola MCU and is BigEndian. When the class is compiled on Windows it needs to swap 2- and 4-byte values to correct for endian differences between Intel and Motorola CPU:s. I have a working code to do this on Windows, but on FPC I would like to use the BEToN() and NToBE functions to convert 16 bit words, 32 bit integers and 32 bit floats (single prec) as needed. I.e. if running in Delphi on Windows use the Swap and Swap4 functions but if running on FPC use the BEToN and NToBE. I think I have understood that these functions will convert only if the current system is using a different endian than specified by the call.

FPC's NToBE and BEToN routines indeed only convert if necessary. I don't know about the Delphi's Swap routines, bit alone from the name I'd say that they swap unconditionally (though considering that Delphi runs only on little endian CPUs that provably won't matter).

I have tried to figure out a set of {$IFDEF } statements but so far with no success.

I'd say that "ifdef fpc" should do the job.

Regards,
Sven

Bo Berglund
to Sven Barth
Sven Barth wrote 10 lines
FPC's NToBE and BEToN routines indeed only convert if necessary. I don't know about the Delphi's Swap routines, but alone from the name I'd say that they swap unconditionally (though considering that Delphi runs only on little endian CPUs that provably won't matter). > I have tried to figure out a set of {$IFDEF } statements but so far > with no success. I'd say that "ifdef fpc" should do the job.

Yes, but then I would also need to use the NToBE and BEToN functions in the FPC code block and my existing code in the D2007 code in order for it to work when I run on FPC but in Linux on x86...

Meanwhile I realized I could do as follows instead:

interface
  ...
var
  IsLittleEndian: boolean;
implementation
var
  _Tmp: array[0..1] of byte;
  _Tst: word;
  ...
procedure Swap4 (var Source);
{Swap the byte order of a 4-byte variable}
type
  Reverse = packed record
    B1 : Byte;
    I2 : Word;
    B4 : Byte;
  end;
var
  Bsw : Byte;
begin
  Bsw :=  Reverse(Source).B1;
  Reverse(Source).B1 := Reverse(Source).B4;
  Reverse(Source).B4 := Bsw;
  Reverse(Source).I2 := Swap(Reverse(Source).I2);
end;

....

initialization
  _Tmp[0] := 57;
  _Tmp[1] := 48;
  Move(_Tmp[0], _Tst, 2);
  IsLittleEndian := (_Tst = 12345);
end.

Then in each endian conversion function I could do as the following example:

procedure FileDirRecEndianConv(var FR: TSSFileDirRec);
begin
  if IsLittleEndian then
  begin
    Swap4(FR.FileLen);
    FR.StartBlock := Swap(FR.StartBlock);
    FR.CmdNum := Swap(FR.CmdNum);
    FR.Meascount := Swap(FR.Meascount);
    Swap4(FR.Xloc);
    Swap4(FR.Yloc);
    Swap4(FR.Zloc);
    Swap4(FR.ScaleFactor);
    Swap4(FR.P_X);
    Swap4(FR.P_Y);
    Swap4(FR.P_Z);
    Swap4(FR.InfiniteX);
    Swap4(FR.InfiniteY);
    Swap4(FR.InfiniteZ);
  end;
end;

What this does is that it checks system endian on program startup (once) and then uses this flag all through to either convert or not. Still with my own Swap4() procedure and the built in Swap() function.

Bo Berglund Developer in Sweden
Sven Barth
to Bo Berglund
"Bo Berglund" wrote 6 lines
On Sat, 4 Jun 2016 00:05:21 +0200, Sven Barth wrote: >FPC's NToBE and BEToN routines indeed only convert if necessary. I don't >know about the Delphi's Swap routines, but alone from the name I'd say

that

Show quoted text 11 lines
>they swap unconditionally (though considering that Delphi runs only on >little endian CPUs that provably won't matter). > >> I have tried to figure out a set of {$IFDEF } statements but so far >> with no success. > >I'd say that "ifdef fpc" should do the job. > Yes, but then I would also need to use the NToBE and BEToN functions in the FPC code block and my existing code in the D2007 code in order for it to work when I run on FPC but in Linux on x86...

[snip]

What this does is that it checks system endian on program startup (once) and then uses this flag all through to either convert or not. Still with my own Swap4() procedure and the built in Swap() function.

FPC has the defines ENDIAN_LITTLE and ENDIAN_BIG (for Delphi you can implicitly assume that it's little endian, maybe simply define ENDIAN_LITTLE if FPC is not set). It's better to enable/disable the swapping code at compile time so that there is no branch in those routines.

Regards
Sven