Perl: How do I extract certain bits from a byte and then covert these bits to a hex value?
Asked Answered
C

2

7

I need to extract certain bits of a byte and covert the extract bits back to a hex value.

Example (the value of the byte is 0xD2) :

76543210 bit position
11010010 is 0xD2
  • Bit 0-3 defines the channel which is 0010b is 0x2
  • Bit 4-5 defines the controller which is 01b is 0x1
  • Bit 6-7 defines the port which is 11b is 0x3

I somehow need to get from the byte is 0xD2 to channel is 0x2, controller is 0x1, port is 0x3

I googled allot and found the functions pack/unpack, vec and sprintf. But I'm scratching by head how to use the functions to achieve this. Any idea how to achieve this in Perl ?

Crumley answered 24/11, 2012 at 16:39 Comment(0)
F
8

What's the initial format?

my $chr = chr(0b11010010);  # A character  e.g. from read()
my $bin = '11010010';       # Binary
my $hex = 'D2';             # Hexadecimal
my $num = 0b11010010;       # A number.
my $num = 0xD2;             # A number.

You want to start by converting it to a number

my $num = ord($chr);
my $num = unpack('C', $chr);  # Alternative
my $num = oct("0b$bin");
my $num = hex($hex);

Then you use shifts and masks.

my $channel    = ($num >> 0) & 0xF;   # Or just: $num & 0xF
my $controller = ($num >> 4) & 0x3;
my $port       = ($num >> 6) & 0x3;   # Or just: $num >> 6

(You could use 0b1111, 0b11 and 0b11 for the masks. Most people work in hex.)

Or let vec figure out the masks for you.

my $channel    = vec $num, 0, 4;
my $controller = vec $num, 4, 2;
my $port       = vec $num, 6, 2;

Here's an example for $controller:

  11010010
      >> 4
  --------
      11010010
&       11
  --------
        01

(Some zeroes omitted for clarity.)

Frostbitten answered 24/11, 2012 at 16:52 Comment(3)
Yes, the initial format is the hex value from the byte so in above example 0xD2 not what I previously indicated.Crumley
I'm glad that I could help to improve this answer. :)Mezzorelievo
After reading : devshed.com/c/a/Perl/More-Perl-Bits The coin dropped :-)Crumley
M
2

vec is a good choice. I think this is pretty straightforward:

#!/usr/bin/env perl

use strict;
use warnings;
use feature 'say';

my @channels    = map "channel_$_"      => 0 .. 15;
my @controllers = map "controller_$_"   => 0 .. 3;
my @ports       = map "port_$_"         => 0 .. 3;

my $bits        = 0b11010010;
my $channel     = vec $bits, 0, 4;
my $controller  = vec $bits, 4, 2;
my $port        = vec $bits, 6, 2;

say "channel    : $channels[$channel]";
say "controller : $controllers[$controller]";
say "port       : $ports[$port]";

Output:

channel    : channel_2
controller : controller_1
port       : port_3
Mezzorelievo answered 24/11, 2012 at 16:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.