从大端数据提取记录 [英] Extracting record from big endian data

查看:121
本文介绍了从大端数据提取记录的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下用于网络协议实现的代码。由于该协议是大端字节序,因此我想使用 Bit_Order 属性和 High_Order_First 值,但似乎我弄错了。

I have the following code for network protocol implementation. As the protocol is big endian, I wanted to use the Bit_Order attribute and High_Order_First value but it seems I made a mistake.

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

什么我忘了还是误会了?

What did I forget or misunderstand ?

更新

实际上,真实记录是

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 长度为16位宽。

如果我删除 Is_Exception 字段并扩展,则这些将正确显示Function_Code 转换为8位。

These ones are displayed correctly if I remove the Is_Exception field and extend Function_Code to 8 bits.

要解码的帧的转储如下:

The dump of the frame to decode is as following:

00000000  00 01 00 00 00 09 11 03  06 02 2b 00 64 00 7f

所以我唯一的问题实际上是提取最后一个字节的第8位。

So my only problem is really to extract the 8th bit of the last byte.

推荐答案

我终于找到了错误。

实际上, Modbus以太网帧定义提到,在例外情况下,返回的代码应为功能代码加128(0x80)(请参阅在Wikipedia上进行解释)。这就是为什么我想通过 Boolean 值来表示它,但我的表示子句是错误的原因。

In fact, the Modbus Ethernet Frame definition mentioned that, in case of exception, the returned code should be the function code plus 128 (0x80) (see explanation on Wikipedia). That's the reason why I wanted to represent it through a Boolean value but my representation clauses were wrong.

正确的子句是这些子句: / p>

The correct clauses are these ones :

   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;
         Is_Exception at 6 range 8 .. 8;
         Function_Code at 6 range 9 .. 15;
      end record;

通过这种方式,可以正确地对Modbus网络协议进行建模(或者至少可以,但是我的代码正在运行)。

This way, the Modbus network protocol is correctly modelled (or not but at least, my code is working).

我真的很感谢 egilhh simonwright 使我发现了问题所在并解释了这些方面背后的语义。

I really thank egilhh and simonwright for making me find what was wrong and explain the semantics behind the aspects.

显然,我不知道是谁奖励的:)

Obviously, I don't know who reward :)

这篇关于从大端数据提取记录的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆