Perl pack()发送消息?

rem*_*acp 5 perl message cpu-word pack

背景

我有一个设备连接到我的机器上的串行端口是面向消息的,其中每个传入的命令消息恰好是8个16位字.首先接收每​​个字的最高有效字节,然后接收最低有效字节.每个标题字是命令标识符(范围从0到255).格式定义如下:

XXXX    Header Word (Placeholder for 16-bit Hexadecimal value)
XXXX    Data Word
XXXX    Data Word
XXXX    Data Word
XXXX    Data Word
XXXX    Data Word
XXXX    Data Word
XXXX    Checksum Word (Result of Exclusive OR on header word and all six data words)
Run Code Online (Sandbox Code Playgroud)

我需要发送的命令的格式,标头0x5D,定义如下:

Word 1: Header = 005Dh
Word 2: Mode (values can be 2, 3, 6, 8, 9)
Words 3-7: Not significant
Word 8: 16 bit checksum 
Run Code Online (Sandbox Code Playgroud)

问题(全部相关)

我从其他源代码中得到了这个示例,显然正确地发送了这条消息,但我不确定发生了什么,即使在读取包上的perldoc之后也是如此.

pack("v"x8, 0x00, 0x5D, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x5D);
Run Code Online (Sandbox Code Playgroud)
  1. "v"表示小端,但我找不到跟随它的x8的任何引用.
  2. 并且根据消息的格式,0x5D值不应该在"v"x8之后,而不是在0x00之后?
  3. 该消息应该有8个16位字,那么为什么有16而不是8?有些是0x00,而不是0x0?这有什么区别吗?

ike*_*ami 5

pack "v"x8(结果pack "vvvvvvvv",可以写成pack "v8"简称)包含8个16位数字,但你通过了16个.

如果你已经有16个字节,你想要

pack 'C16', 0x00, 0x5D, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x5D
Run Code Online (Sandbox Code Playgroud)

但我希望你有8个16位字,所以你可以使用

pack 'n8', 0x005D, 0x0009, 0x0000, 0x0000, 0x0000, 0x0000, 0x0009, 0x005D
Run Code Online (Sandbox Code Playgroud)

注意使用n而不是v获得所需的字节顺序.

pack 'v', 0x1234      => "\x34\x12"   Most significant byte last
pack 'n', 0x1234      => "\x12\x34"   Most significant byte first
Run Code Online (Sandbox Code Playgroud)

证明两种方法都是等价的:

my $method1 =  pack 'C16',
    0x00, 0x5D, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x5D;

my $method2 = pack 'n8',
    0x005D, 0x0009, 0x0000, 0x0000, 0x0000, 0x0000, 0x0009, 0x005D;

print($method1 eq $method2 ? "yes" : "no", "\n");  # yes
Run Code Online (Sandbox Code Playgroud)