pack/unpack help please

Discussion in 'Perl Misc' started by Dave Saville, Apr 5, 2014.

  1. Dave Saville

    Dave Saville Guest

    I am using perl on a Rasberry pi to read an i2c device using the hipi
    library.

    @temp = $dev->bus_read( MPU6050_TEMP_OUT_H, 2 );

    Returns two bytes as an array of two values. High byte, low byte.

    For example I may get:

    $temp[0] = 244; # 0xFD
    $temp[1] = 224; # 0xE0

    Which is -2848. I (eventually) came up with this

    $temp = unpack 's', pack 'CC', reverse @temp;

    Is there a better method? Also why does

    $temp = unpack 'n', pack 'CC', @temp;

    Not give the same value?

    TIA
    --
    Regards
    Dave Saville
     
    Dave Saville, Apr 5, 2014
    #1
    1. Advertising

  2. Dave Saville

    Dave Saville Guest

    On Sat, 5 Apr 2014 15:14:00 UTC, "Dave Saville" <>
    wrote:

    > $temp = unpack 'n', pack 'CC', @temp;
    >
    > Not give the same value?


    Ah, n is unsigned.

    $temp = unpack 's>', pack 'CC', @temp;

    Does the trick.
    --
    Regards
    Dave Saville
     
    Dave Saville, Apr 5, 2014
    #2
    1. Advertising

  3. "Dave Saville" <> writes:
    > I am using perl on a Rasberry pi to read an i2c device using the hipi
    > library.
    >
    > @temp = $dev->bus_read( MPU6050_TEMP_OUT_H, 2 );
    >
    > Returns two bytes as an array of two values. High byte, low byte.
    >
    > For example I may get:
    >
    > $temp[0] = 244; # 0xFD


    This is 0xf4, not 0xfd.

    > $temp[1] = 224; # 0xE0
    >
    > Which is -2848. I (eventually) came up with this
    >
    > $temp = unpack 's', pack 'CC', reverse @temp;
    >
    > Is there a better method?


    What's you definition of 'better' here? You can generally build the
    number by 'putting the bytes in the right place', ie

    $temp[0] << 8 | $temp[1]

    If you want it to be interpreted as signed, two ways to achieve that
    would be

    ($temp[0] << 8 | $temp[1]) - ($temp[0] & 0x80 && 0x1000)

    and

    use integer;
    ($temp[0] << 8 | $temp[1]) ^ ($temp[0] & 0x80 && HIBITS)

    with HIBITS defined as

    use constant HIBITS => -1 & ~0xffff;

    both are faster (for me) than your approach, OTOH, you'll very likely
    freak out people to whom it never occured that computers actually work
    with binary numbers and that the bit operators are useful.

    sample code:
    -------------
    use Benchmark;

    use constant HIBITS => -1 & ~0xffff;

    @t = (0xf4, 0xe0);

    timethese(-3,
    {
    pack => sub {
    return unpack('s', pack('CC', reverse(@t)));
    },

    calc => sub {
    use integer;
    return ($t[0] << 8 | $t[1]) ^ ($t[0] & 0x80 && HIBITS);
    }});
     
    Rainer Weikusat, Apr 5, 2014
    #3
  4. Rainer Weikusat <> writes:
    > "Dave Saville" <> writes:
    >> I am using perl on a Rasberry pi to read an i2c device using the hipi
    >> library.
    >>
    >> @temp = $dev->bus_read( MPU6050_TEMP_OUT_H, 2 );
    >>
    >> Returns two bytes as an array of two values. High byte, low byte.


    [...]

    > use integer;
    > ($temp[0] << 8 | $temp[1]) ^ ($temp[0] & 0x80 && HIBITS)
    >
    > with HIBITS defined as
    >
    > use constant HIBITS => -1 & ~0xffff;


    The xor is somewhat out-of-place here because there are no overlapping
    1-bits in both numbers. | can be used as well.
     
    Rainer Weikusat, Apr 5, 2014
    #4
  5. Dave Saville

    Dave Saville Guest

    On Sat, 5 Apr 2014 19:25:51 UTC, Rainer Weikusat
    <> wrote:

    > "Dave Saville" <> writes:
    > > I am using perl on a Rasberry pi to read an i2c device using the hipi
    > > library.
    > >
    > > @temp = $dev->bus_read( MPU6050_TEMP_OUT_H, 2 );
    > >
    > > Returns two bytes as an array of two values. High byte, low byte.
    > >
    > > For example I may get:
    > >
    > > $temp[0] = 244; # 0xFD

    >
    > This is 0xf4, not 0xfd.


    Yup - typo and/or brain to keyboard. :)

    >
    > > $temp[1] = 224; # 0xE0
    > >
    > > Which is -2848. I (eventually) came up with this
    > >
    > > $temp = unpack 's', pack 'CC', reverse @temp;
    > >
    > > Is there a better method?

    >
    > What's you definition of 'better' here? You can generally build the
    > number by 'putting the bytes in the right place', ie
    >
    > $temp[0] << 8 | $temp[1]
    >


    That's what I thought at first, but the sign stumped me.

    > If you want it to be interpreted as signed, two ways to achieve that
    > would be
    >
    > ($temp[0] << 8 | $temp[1]) - ($temp[0] & 0x80 && 0x1000)
    >
    > and
    >
    > use integer;
    > ($temp[0] << 8 | $temp[1]) ^ ($temp[0] & 0x80 && HIBITS)
    >
    > with HIBITS defined as
    >
    > use constant HIBITS => -1 & ~0xffff;


    Hmm I see how the second one works but the first doesn't :

    use strict;
    use warnings;

    my @temp;
    $temp[0] = 244; # 0xF4
    $temp[1] = 224; # 0xE0
    printf "%X %X\n", @temp;
    printf "%X\n", $temp[0] & 0x80;
    printf "%X\n", $temp[0] & 0x80 && 0x1000;
    printf "%X\n", ($temp[0] << 8 | $temp[1]) - ($temp[0] & 0x80 &&
    0x1000);
    printf "%d\n", ($temp[0] << 8 | $temp[1]) - ($temp[0] & 0x80 &&
    0x1000);
    use integer;
    use constant HIBITS => -1 & ~0xffff;
    printf "%X\n", HIBITS;
    printf "%X\n", $temp[0] & 0x80;
    printf "%X\n", $temp[0] & 0x80 && HIBITS;
    printf "%X\n", ($temp[0] << 8 | $temp[1]) ^ ($temp[0] & 0x80 &&
    HIBITS);
    printf "%d\n", ($temp[0] << 8 | $temp[1]) ^ ($temp[0] & 0x80 &&
    HIBITS);

    [T:\tmp]try.pl
    F4 E0
    80
    1000
    E4E0
    58592
    FFFF0000
    80
    FFFF0000
    FFFFF4E0
    -2848


    --
    Regards
    Dave Saville
     
    Dave Saville, Apr 6, 2014
    #5
  6. "Dave Saville" <> writes:
    > On Sat, 5 Apr 2014 19:25:51 UTC, Rainer Weikusat
    > <> wrote:
    >> "Dave Saville" <> writes:
    >> > I am using perl on a Rasberry pi to read an i2c device using the hipi
    >> > library.
    >> >
    >> > @temp = $dev->bus_read( MPU6050_TEMP_OUT_H, 2 );
    >> >
    >> > Returns two bytes as an array of two values. High byte, low byte.
    >> >
    >> > For example I may get:
    >> >
    >> > $temp[0] = 244; # 0xFD


    [...]

    >> If you want it to be interpreted as signed, two ways to achieve that
    >> would be
    >>
    >> ($temp[0] << 8 | $temp[1]) - ($temp[0] & 0x80 && 0x1000)


    [...]

    > Hmm I see how the second one works but the first doesn't :


    My bad. The final number in the second term should be 0x10000 (65536),
    not 0x1000 (4096).

    perl -e 'print((0xf4 << 8 | 0xe0) - (0xf4 & 0x80 && 0x10000))'

    Both rely on negative integers being represented as two's complement. In
    this case, a negative n-bit integer is encoded as 'distance' from 2**n,
    ie 0xffff aka 65535 is -1.
     
    Rainer Weikusat, Apr 6, 2014
    #6
  7. Dave Saville

    Dave Saville Guest

    On Sun, 6 Apr 2014 14:36:40 UTC, Rainer Weikusat
    <> wrote:

    > My bad. The final number in the second term should be 0x10000 (65536),
    > not 0x1000 (4096).
    >


    What's a factor of 16 between friends? :)

    > perl -e 'print((0xf4 << 8 | 0xe0) - (0xf4 & 0x80 && 0x10000))'
    >
    > Both rely on negative integers being represented as two's complement. In
    > this case, a negative n-bit integer is encoded as 'distance' from 2**n,
    > ie 0xffff aka 65535 is -1.
    >


    I am happy playing with bits - I just could not see what you were
    trying to do there. Whereas your second method was obvious what it
    did.

    Just for fun I added another I dreamed up to your benchmark

    kalk => sub {
    my $x = $t[0] << 8 | $t[1];
    return $t[0] & 0x80 ? ~(~$x & 0xffff) : $x;

    Which sits between the two.

    Thanks.

    --
    Regards
    Dave Saville
     
    Dave Saville, Apr 6, 2014
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Stacy Mader
    Replies:
    4
    Views:
    840
    Ekkehard Morgenstern
    Nov 22, 2003
  2. tmp123
    Replies:
    5
    Views:
    892
    Tim Roberts
    May 4, 2007
  3. joe shoemaker

    Python pack and unpack question

    joe shoemaker, Jul 15, 2008, in forum: Python
    Replies:
    0
    Views:
    333
    joe shoemaker
    Jul 15, 2008
  4. Kero
    Replies:
    0
    Views:
    220
  5. Bill Atkins
    Replies:
    6
    Views:
    148
    Daniel Berger
    Jun 14, 2004
Loading...

Share This Page