Dreanaught
Dreanaught

Reputation: 71

convert fixed size array to record of same size

This might be a nobrainer but as a novice i can not get my head around it.

I have a function returning a fixed size array. I am trying to convert this array into a record of the same size

The function signature is like this:

type Control is new UInt8_Array (1 .. 2);
function readControl (Command : Control) return Control;

I am trying to get the two bytes (UInt8) into the record Contro_Status_Bytes with the following definition:

 type Control_Status_MSB is
  record
     RES_UP     : Boolean;
     QMAX_UP    : Boolean;
     BCA        : Boolean;
     CCA        : Boolean;
     CALMODE    : Boolean;
     SS         : Boolean;
     WDRESET    : Boolean;
     SHUTDOWNEN : Boolean;
  end record;

for Control_Status_MSB use
  record
     RES_UP     at 0 range 0 .. 0;
     QMAX_UP    at 0 range 1 .. 1;
     BCA        at 0 range 2 .. 2;
     CCA        at 0 range 3 .. 3;
     CALMODE    at 0 range 4 .. 4;
     SS         at 0 range 5 .. 5;
     WDRESET    at 0 range 6 .. 6;
     SHUTDOWNEN at 0 range 7 .. 7;
  end record;


type Control_Status_LSB is
  record
     VOK       : Boolean;
     RUP_DIS   : Boolean;
     LDMD      : Boolean;
     SLEEP     : Boolean;
     HIBERNATE : Boolean;
     INITCOMP  : Boolean;
  end record;

for Control_Status_LSB use
  record
     VOK at 0 range 1 .. 1;
  end record;

type Control_Status_Bytes is
  record
     HighByte : Control_Status_MSB;
     LowByte  : Control_Status_LSB;
  end record;

I think it must be possible to convert the array to the record and vice versa without an unchecked conversion. But currently i am missing something.

Update: This might be an valid answer/way to do that i came up after reading @Simons answer.

function readControl (Command : Control) return Control_Status_Bytes is
  CSB : Control_Status_Bytes;
begin
  -- do stuff return UInt8_Array of size 2 as response
  CSB.HighByte := response'First;
  CSB.LowByte  := response'Last;
  return CSB;
end readControl;

Upvotes: 1

Views: 80

Answers (3)

Dreanaught
Dreanaught

Reputation: 71

The hint from @Simon Wright pointed me in the right direction.

This is what is use now and it works:

function convert (ResponseArray : Control) return Control_Status_Bytes is
   Result : Control_Status_Bytes with
     Import, Convention => Ada, Address => ResponseArray'Address;
begin
   return Result;
end convert;

Upvotes: 1

Simon Wright
Simon Wright

Reputation: 25501

It has to depend on what happens inside readControl, but couldn't you make it return the type you want directly?

function readControl (Command : Control) return Control_Status_Bytes;

(I expect that Command actually has some structure too?).

By the way, you only define the position of one component (VOK) in Control_Status_LSB, which leaves the rest up to the compiler.

Upvotes: 1

user1818839
user1818839

Reputation:

Unchecked conversion is the usual way.

But for I/O ports and peripheral registers in MCUs (Atmel AVR, MSP430 etc) which can be addressed either as numbers, or arrays of booleans (or potentially, records) there's a hack ...

   p1in                   : constant unsigned_8;     --  Port 1 Input 
   Pragma Volatile(p1in);
   Pragma Import(Ada, p1in);      -- see ARM C.6 (13)
   For p1in'Address use   16#20#;

   p1in_bits              : constant Byte;           --  Port 1 Input  Bits
   Pragma Volatile(p1in_bits);
   Pragma Import(Ada, p1in_bits);
   For p1in_bits'Address use   16#20#;

This maps the inputs from I/O port 1 to the same address, viewed either as an 8 bit Unsigned or as a Byte (an array of 8 booleans).

The equivalent in your case would be something like

For Control_Status_Record'Address use Control_Status_Array`Address;

Note you probably need to attach "pragma volatile" to both views, as here, so that changes to one view aren't lost because the other view is cached in a register.

All in all, I recommend Unchecked_Conversion over this approach. It's designed for the job and avoids messing with Volatile.

Upvotes: 3

Related Questions