Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

Pack or unpack dropping a nibble

by smknjoe (Beadle)
on Mar 19, 2018 at 17:01 UTC ( [id://1211249]=perlquestion: print w/replies, xml ) Need Help??

smknjoe has asked for the wisdom of the Perl Monks concerning the following question:

Hi all other monks,

I'm trying to write a hex to binary converter and found what I thought were the needed code nuggets towards the bottom of "perldoc perlpacktut" documentation in the Intel Hex section. It seemed fairly straightforward, but I found that when processing bytes of data that the upper nibble is being dropped during the conversion. The discovery only came by reverse-conversion of the binary output string. The data length is reported as being correct; the first data line has 16 bytes, and the second contains 14 bytes - note this format has 4 bytes of info at the beginning of the line and a checksum byte at the end.

Here is my test code:

#!/usr/bin/env perl use strict; use warnings; use utf8; #===================================================================== +========== # Set to "1" for additional debugging print statements. #===================================================================== +========== my $debug= 1; #===================================================================== +========== # Standard input while loop #===================================================================== +========== my $line; # Retrieve a line while ($line = <DATA>) { # chomp line chomp $line; # Does line begin with ":"? if (($line !~ /^\:/) || ($line =~ /^\$/)) { print "INVALID LINE, SKIPPING : $line\n" if $debug; next } else { # convert line to hex (and strip off ":") my $hexrec = pack( 'H*', substr( $line, 1 ) ); # calculate checksum, if error, die. my $chksum = unpack( "%C*", $hexrec ); print "checksum = $chksum\n" if $debug; die unless unpack( "%8C*", $hexrec ) == 0; # # process the line. get bytecount, address, record type, and d +ata # my( $bytecount, $address, $recordtype, $data ) = unpack( "C n +C X4 C x3 /a", $hexrec ); # note: no reason to print data, since it results in special, +unprintable chars printf ("bytecount = %d, address = %d, recordtype = %d\n", $by +tecount, $address, $recordtype) if $debug; # # terminator line # if ($recordtype == 1) { print "Conversion complete\n"; exit; } # # real data line # elsif ($recordtype == 0) { my $binarycount = $bytecount*8; my $datlength = length($data); print "Data length (should match bytecount) = $datlength\n +"; # convert to binary my $binaryval = unpack("B$binarycount", pack("H$bytecount" +, $data)); print "binary = $binaryval\n" if $debug; } } } # end of while __DATA__ :1004D0000A95E1F7E0E0F8E000E40BBF00E81791CF :0E04E0001D930A95E1F74CCE00E10883FDCE96 :00000001FF __END__

The results of running the Perl code is this:

checksum = 2816 bytecount = 16, address = 1232, recordtype = 0 Data length (should match bytecount) = 16 binary = 1010010100010111000000001000000000000100101111110000100001110 +001 checksum = 2304 + bytecount = 14, address = 1248, recordtype = 0 + Data length (should match bytecount) = 14 + binary = 11010011101001010001011101011110000000011000001111011110 + checksum = 256 + bytecount = 0, address = 0, recordtype = 1 + Conversion complete

If someone can shed some light on this and help me to understand pack/unpack a tiny bit better, it would be much appreciated.

Thanks,

Joe

Replies are listed 'Best First'.
Re: Pack or unpack dropping a nibble
by Eily (Monsignor) on Mar 19, 2018 at 18:16 UTC

    Hi. Please read this node on how to write a question that is likely to get answers. Here not only your example wasn't really short, but you explained nothing of what your program does, and how you conclude from your output that there is something wrong with what you do (or that a nibble is lost). This means that to understand the issue, you have to read and understand the code.

    My advice: when in doubt, don't print, dump! (or possibly Data::Dumper with the useqq option). With use Data::Dump "pp"; and print pp($data)."\n"; you get: pack("H*","0a95e1f7e0e0f8e000e40bbf00e81791") and pack("H*","1d930a95e1f74cce00e10883fdce"). That's why I love debugging with Data::Dump it won't let an invisible char stay invisible (eg, it won't let you confuse \r\n with \n) and in this case it even detects that this is binary data and writes it as a pack call for you.

    Now, your issue is here: my $binaryval = unpack("B$binarycount", pack("H$bytecount", $data));
    The first mistake is that H is a nibble, so H$bytecount will display as many nibbles as their are bytes, that's only half the data.
    But the main issue is that $data is binary data, and pack "H" will convert an hexadecimal string representation of binary data. (Like "1004D00" from your input). So your binary data is interpreted as a string, which is only supposed to contain 0-9 and a-f.

    Now what you probably meant was: my $binaryval = unpack("B*", $data);.

    Edit: too slow :). But the advice on Data::Dump still holds.

Re: Pack or unpack dropping a nibble
by smknjoe (Beadle) on Mar 19, 2018 at 18:06 UTC

    All,

    Nevermind, as I solved it on my own. The line where I convert it to binary also contained another pack command to convert to hex. Well, the $data variable already contains hex-formatted data, so it wasn't necessary.

    Cutting and pasting someone else's code never works, if you don't know what it is doing in the first place....

    Joe

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1211249]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (9)
As of 2024-03-28 09:39 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found