#### Do you have a question? Post it now! No Registration Necessary.  Now with pictures!

•  Subject
• Author
• Posted on
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

wrote:

Ah, n is unsigned.

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

Does the trick.
--
Regards
Dave Saville

This is 0xf4, not 0xfd.

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);
}});

[...]

The xor is somewhat out-of-place here because there are no overlapping
1-bits in both numbers. | can be used as well.

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

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

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

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

[...]

[...]

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.

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

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

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