Reputation: 71
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
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
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
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