Search code examples
perlendianness

How do I convert little Endian to Big Endian using a Perl Script?


I am using the Perl Win32::SerialPort module. In this paticular module I sent over data using the input command. The data that I sent over to a embedded system were scalar data (numbers) using the transmit_char function (if it were C it would be integers, but since its a scripting language I am not sure what the internal format is in perl. My guess is that perl always stores all numbers as 32 bit floating points, which are adjusted by the module when transmitting).

Then after sending the data I receive data using the input command. The data that I recieve is probably in binary form, but perl doesn't know how to interpret it. I use the unpack function like this

my $binData = $PortObj->input;
my $hexData = unpack("H*",$binData);

Suppose I transmit 0x4294 over the serial cable, which is a command on the embedded system that I am communicating with, I expect a response of 0x5245. Now the problem is with the endianess: when I unpack I get 0x4552, which is wrong. Is there a way to correct that by adjusting the binary data. I also tried h*, which gives me 0x5425, which is also not correct.

Note: the data I receive is sent over Byte at a time and the LSB is sent first


Solution

  • Endianess applies to the ordering of bytes of an integer (primarily). You need to know the size of the integer.

    Example for 32-bit unsigned:

    my $bytes = pack('H*', '1122334455667788');
    my @n = unpack('N*', $bytes);
    # @n = ( 0x11223344, 0x55667788 );
    
    my $bytes = pack('H*', '4433221188776655');
    my @n = unpack('V*', $bytes);
    # @n = ( 0x11223344, 0x55667788 );
    

    See pack. Note the "<" and ">" modifiers to control the endianess where of instructions where the default endianess is not the one you want.

    Note: If you're reading from the file, you already have bytes. Don't create bytes using pack 'H*'.

    Note: If you're reading from the file, don't forget to binmode the handle.


    Regarding the example the OP added to his post:

    To get 0x5245 from "\x45\x52", use unpack("v", $two_bytes).