Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convention for handling foreign binary data

Tags:

ada

I'm a C programmer and started learning Ada a few weeks ago. I have been puzzled by how Ada handles foreign binary data, such as when decoding a communications packet stored in a serial input buffer.

In C, I would define a packed structure to reflect the layout of the packet, and then cast the pointer-to-buffer to pointer-to-structure to access the individual elements in the communications data. What is the typical way to do such decoding in Ada?

I have tried to replicate the same method for C in Ada with the following

-- Fundamental types for fields in the packet

type Station_Addr_Type is mod 2**8;

type Func_Code_Type is (FUNC1, FUNC2);
for Func_Code_Type use
   (
    FUNC1 => 1,
    FUNC2 => 2
   );
type Packet is
    record
       Station_Addr : Station_Addr_Type;
       Func_Code : Func_Code_Type;
    end record;


-- attempts to reflect packet binary layout

for Packet use
    record at mod 1;
       Station_Addr at 0 range 0 .. 7;
       Func_Code at 1 range 0 .. 7;
    end record;

I then defined the array for the communications receive buffer that accepts foreign binary data (possibly from a different architecture):

type Communication_Data is mod 2**8;
for Communication_Data'Size use 8;

type Communication_Buffer is array (Natural range <>) of Communication_Data;

Buffer : Communication_Buffer (0 .. 20);

Then a procedure that decodes such communications

procedure Decode_Packet (Packet_Provided : in Packet);
-- non-working sample
declare
begin

  -- Attempts to sanity-check packet by object casting
  Decode_Packet (Packet (Buffer));
  ---------------^----
  Error: invalid conversion, not compatible with type "Communication_Buffer"

exception
  when others => 
     raise Decode_Failure;
end;

However, the compiler forbids such casting with error as shown. Thanks for reading this far. My question is,

Regarding the correct way of decoding foreign binary data, am I "in the ball park", or is there a better way of doing this?

like image 812
John Doe Avatar asked Jul 10 '21 04:07

John Doe


1 Answers

  1. If you sure that the data has a right alignment, you can map a Packet object to space allocated by Communication_Data:
Buffer : Communication_Buffer (0 .. 20);
Pkg    : Packet;
pragma Import (Ada, Pkg);
for Pkg'Address use Buffer (0)'Address;

The same with aspect syntax:

Buffer : Communication_Buffer (0 .. 20);
Pkg    : Packet
 with Import, Address => Buffer (0)'Address;
  1. Another way is to use Ada.Unchecked_Conversion, but you should be sure that Buffer and Packet have the same size:
subtype Packet_Buffer is Communication_Buffer (1 .. 2);

function To_Packet is new Ada.Unchecked_Conversion
  (Packet_Buffer, Packet);

Pkg : Packet := To_Packet (Buffer (0 .. 1));

PS. If you want an endianness independent code you may also need a Scalar_Storage_Order (GNAT implementation defined) aspect.

PS. I recommend also take a look at "Safe Communication" chapter of Safe and Secure Software booklet.

like image 134
Maxim Reznik Avatar answered Sep 17 '22 22:09

Maxim Reznik