Perl - Пакет сложных 16-битных слов

Мне нужно упаковать сложное сообщение в 16-битное слово, которое определяется так:

  • Part 1: Error State (Least Significant Byte)
    • Bit 0: Error type A (Least Significant Bit)
    • Бит 1: Тип ошибки B
    • Бит 2: Тип ошибки C
    • Бит 3: Тип ошибки D
    • Бит 4: Тип ошибки E
    • Бит 5: Тип ошибки F
    • Бит 6: Тип ошибки G
    • Бит 7: тип ошибки H (старший бит)
  • Part 2: Mode/Status Additional Status is defined like so:
    • Mode: The mode is contained in the least significant 4 bits of the most significant byte. Mode numbers go 0 - 11.
    • Бит 12: Тип состояния A
    • Бит 13: Тип состояния B
    • Бит 14: Тип состояния C
  • Additional Status:
    • Bit 15: Reset on/off

Кажется, я не могу правильно понять команду pack(). Я хочу упаковать: ошибка типа E, режим 7, статус типа B, дополнительный статус включен

my $msg = pack("n",
    pack("C", 0, 0, 0, 0, 1, 0, 0, 0), #error state
    pack("C", 7, 0, 1, 0, 1)
);

документ Perl, http://perldoc.perl.org/functions/pack.html, не говорит о маленьком/старшем порядке, когда дело доходит до упаковки символов.


person rem45acp    schedule 09.06.2014    source источник
comment
Окончание байтов в компьютерной архитектуре определяется тем, в каком порядке байты появляются в числах, состоящих из двух или более байтов. Архитектура называется с прямым порядком байтов, если первый байт, имеющий самый низкий адрес в памяти, является младшим значащим восемью битами большего числа. Восьмибитные числа состоят всего из одного байта, поэтому вопрос о том, какой из них идет первым, неприменим.   -  person Borodin    schedule 09.06.2014


Ответы (2)


Вы можете попробовать использовать vec вместо пакета. Например:

vec($i, 0,1) = 1;               # set bit zero
print unpack('b*', $i), "\n";   # 10000000
vec($i, 1,1) = 1;               # set bit 1 
print unpack('b*', $i), "\n";   # 11000000
vec($i, 4,1) = 1;               # set bit 4
print unpack('b*', $i), "\n";   # 11001000
vec($i, 15,1) = 1;              # set bit 15
print unpack('b*', $i), "\n";   # 1100100000000001
person John C    schedule 09.06.2014

pack производит 1 или более байтов для каждого ввода, поэтому он не может принимать биты. Сначала создайте свое слово, а затем передайте его пакету.

my $word = 0;

$word |= 1 << 0 if $error_type_A;
$word |= 1 << 1 if $error_type_B;
$word |= 1 << 2 if $error_type_C;
$word |= 1 << 3 if $error_type_D;
$word |= 1 << 4 if $error_type_E;
$word |= 1 << 5 if $error_type_F;
$word |= 1 << 6 if $error_type_G;
$word |= 1 << 7 if $error_type_H;

$word |= $mode << 8;

$word |= 1 << 12 if $status_type_A;
$word |= 1 << 13 if $status_type_B;
$word |= 1 << 14 if $status_type_C;

$word |= 1 << 15 if $reset;

pack 'n', $word
person ikegami    schedule 09.06.2014
comment
Можно было бы написать $word |= $error_type_F << 5; вместо $word |= 1 << 5 if $error_type_F;, но последнее позволяет переменной быть любой логической, а не только 0 или 1. - person ikegami; 09.06.2014