我有以下用于网络协议(protocol)实现的代码。由于协议(protocol)是大端的,我想使用 Bit_Order 属性和 High_Order_First 值,但似乎我犯了一个错误。
With Ada.Unchecked_Conversion;
with Ada.Text_IO; use Ada.Text_IO;
with System; use System;
procedure Bit_Extraction is
type Byte is range 0 .. (2**8)-1 with Size => 8;
type Command is (Read_Coils,
Read_Discrete_Inputs
) with Size => 7;
for Command use (Read_Coils => 1,
Read_Discrete_Inputs => 4);
type has_exception is new Boolean with Size => 1;
type Frame is record
Function_Code : Command;
Is_Exception : has_exception := False;
end record
with Pack => True,
Size => 8;
for Frame use
record
Function_Code at 0 range 0 .. 6;
Is_Exception at 0 range 7 .. 7;
end record;
for Frame'Bit_Order use High_Order_First;
for Frame'Scalar_Storage_Order use High_Order_First;
function To_Frame is new Ada.Unchecked_Conversion (Byte, Frame);
my_frame : Frame;
begin
my_frame := To_Frame (Byte'(16#32#)); -- Big endian version of 16#4#
Put_Line (Command'Image (my_frame.Function_Code)
& " "
& has_exception'Image (my_frame.Is_Exception));
end Bit_Extraction;
编译没问题,但结果是
raised CONSTRAINT_ERROR : bit_extraction.adb:39 invalid data
我忘记或误解了什么?
更新
真正的记录其实是
type Frame is record
Transaction_Id : Transaction_Identifier;
Protocol_Id : Word := 0;
Frame_Length : Length;
Unit_Id : Unit_Identifier;
Function_Code : Command;
Is_Exception : Boolean := False;
end record with Size => 8 * 8, Pack => True;
for Frame use
record
Transaction_Id at 0 range 0 .. 15;
Protocol_Id at 2 range 0 .. 15;
Frame_Length at 4 range 0 .. 15;
Unit_id at 6 range 0 .. 7;
Function_Code at 7 range 0 .. 6;
Is_Exception at 7 range 7 .. 7;
end record;
其中 Transaction_Identifier、Word 和 Length 为 16 位宽。
如果我删除 Is_Exception 字段并将 Function_Code 扩展为 8 位,这些将正确显示。
要解码的帧的转储如下:
00000000 00 01 00 00 00 09 11 03 06 02 2b 00 64 00 7f
所以我唯一的问题是提取最后一个字节的第 8 位。
最佳答案
所以,
for Frame use
record
Transaction_Id at 0 range 0 .. 15;
Protocol_Id at 2 range 0 .. 15;
Frame_Length at 4 range 0 .. 15;
Unit_id at 6 range 0 .. 7;
Function_Code at 7 range 0 .. 6;
Is_Exception at 7 range 7 .. 7;
end record;
看来您希望 Is_Exception 成为最后一个字节的 LSB?
与
for Frame'Bit_Order use System.High_Order_First;
LSB 将是第 7 位,(另外,
16#32#
永远不会是 -- Big endian version of 16#4#
,位模式不匹配)指定所有字段相对于它们所在的单词而不是字节可能更直观和清晰:
Unit_ID at 6 range 0..7;
Function_Code at 6 range 8 .. 14;
Is_Exception at 6 range 15 .. 15;
给定
Command
的定义上面,最后一个字节的合法值将是:顺便提一句,
通过将您的更新应用到您的原始程序,并添加/更改以下内容,您的程序对我有用
添加
with Interfaces;
添加
type Byte_Array is array(1..8) of Byte with Pack;
改变,因为我们不知道定义
Transaction_ID : Interfaces.Unsigned_16;
Protocol_ID : Interfaces.Unsigned_16;
Frame_Length : Interfaces.Unsigned_16;
Unit_ID : Interfaces.Unsigned_8;
改变
function To_Frame is new Ada.Unchecked_Conversion (Byte_Array, Frame);
改变
my_frame := To_Frame (Byte_Array'(00, 01, 00, 00, 00, 09, 16#11#, 16#9#));
关于ada - 从大端数据中提取记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56656184/