そうか、Perl でビットシフトは10進数に変換してから行うのか・・・

とあるバイナリデータがある。
そのデータは、1バイト(8ビット)を2ビットずつに区切って、全部で60個ある装置の状態をヘルスデータとして流してくる。データの大きさは 2ビット x 60装置 = 15バイト。

その 2ビットの内容は、

0(00)...NG
1(01)...WRN(警告)
2(10)...OK

という具合。(カッコ内は 2進数)

その 1バイトの中で、装置番号の若いものが下位ビットにセットされる。
だから、4台の装置の状態が、

No.1 10(OK)
No.2 01(WRN)
No.3 10(OK)
No.4 00(NG)

となっていれば、'10011000'ではなく、下位から順にセットしていき '00100110' となる。16進であれば、0x26 だ。

この情報を装置の番号順に取っていきたい。つまり、15バイトのデータから1バイトずつ抜き出して、さらにその 1バイトの中の下位ビットから 2ビットずつ取っていきたい。

'00100110' というデータであれば、

1.下位 2ビットだけを残す論理積計算をおこなう。
 ('00000011' という 2進数と論理積を取れば、下位 2ビットの情報だけを抜き出せる)
2.論理積の計算後、次の処理のため 2ビット下位にシフト。
 ('00100110'を、2ビット右にシフトして'00001001'に)

この処理を、1バイト分(つまり 4回)繰り返し・・・となる。

$v1 = "\x26\xAA\x26\xAA\x26\xAA\x26\xAA\x26\xAA\x26\xAA\x26\xAA\x00"; # データ 15byte(60装置分)
$v2 = 3; # 00000011

for ($i = 0; $i < 15; $i++) {

# 1byte 抜き出す
if ($v1 !~ /^(.{1})(.*)$/) {
last; # データが無くなれば15byte未満でもループ終了
}

$v3 = $1; # 抜き出した 1byte をセット
$v1 = $2; # 残りは次の処理に使う

$w1 = hex(unpack "H*", $v3); # 10進数に変換

# 抜き出した 1byte の下位から 2bitずつ見ていく
for ($j = 0; $j < 4; $j++) {

$w2 = $w1; # 論理積計算用に退避
$w2 = $w2 & $v2; # 論理積
$w1 = $w1 >> 2; # 右(下位)に 2bit シフト

print "$i.$j $w2\n";

}

}

まあ、こんな感じで。

ポイントは、「シフトする値は、予め10進数に変換しておくこと」だな。
「整数」でないと駄目なので、16進のまま、

$v1 = "\x26";
$v2 = "\x03";

$v1>>2; # 右(下位に 2bit シフト)

$v1 = $v1 & $v2;

なんてやってもまともな結果は出ない。
('00100110'をシフトして'00001001'になってほしいけど、何故か'01001000'になっちゃうんだよな)

そこに気づくのに時間がかかってハマってしまった(^^;
ビット単位でシフトするだけなんだから 16進のままでええやん・・・と思うのだが、俺の知らない問題が色々あるんだろうね。プログラミング言語の実装には。

ちなみに、上位ビットからセットしてくれれば、Perl なら「2進文字列」に unpack して、2文字ずつ頭から抜けばいいだけなので、上の例の処理部を差し替えるなら、

$w1 = unpack("B*", $v3); # 1バイト=8桁の2進数に変換
@w = $w1 =~ /.{2}/g; # 2桁ずつに分解

for ($j = 0; $j < 4; $j++) {

$w[$j] = unpack("C", pack("B8", '000000' . $w[$j])); # 2桁の 2進数を10進変換
print "$i.$j $w[$j]\n";

}

こんな感じで、如何にも Perl っぽくて嬉しい。(いや、ちょっとでも「正規表現」が入ると Perl っぽいやん(笑)2桁ずつに分解してるところだけど(笑))

トラックバック(0)

このブログ記事を参照しているブログ一覧: そうか、Perl でビットシフトは10進数に変換してから行うのか・・・

このブログ記事に対するトラックバックURL: https://blog.netandfield.com/mt/mt-tb.cgi/1988

コメントする

このブログ記事について

このページは、shinodaが2012年2月16日 07:00に書いたブログ記事です。

ひとつ前のブログ記事は「日高屋の「汁なしラーメン」は、まあ、こんなもんかっつう感じ」です。

次のブログ記事は「Apache の起動で libphp5.so のロードエラー」です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。


月別 アーカイブ

電気ウナギ的○○ mobile ver.

携帯版「電気ウナギ的○○」はこちら