Memory layout of a data structure

It is often useful to control the memory layout of fields in a data structure to match an interface control definition, or to interface with hardware. Define a data structure matching the RS-232 Plug Definition. Use the 9-pin definition for brevity.

Task
Memory layout of a data structure
You are encouraged to solve this task according to the task description, using any language you may know.
Pin Settings for Plug
(Reverse order for socket.)
__________________________________________
1  2  3  4  5  6  7  8  9  10 11 12 13
14 15 16 17 18 19 20 21 22 23 24 25
_________________
1  2  3  4  5
6  7  8  9
25 pin                        9 pin
1 - PG   Protective ground
2 - TD   Transmitted data     3
3 - RD   Received data        2
4 - RTS  Request to send      7
5 - CTS  Clear to send        8
6 - DSR  Data set ready       6
7 - SG   Signal ground        5
8 - CD   Carrier detect       1
9 - + voltage (testing)
10 - - voltage (testing)
11 -
12 - SCD  Secondary CD
13 - SCS  Secondary CTS
14 - STD  Secondary TD
15 - TC   Transmit clock
16 - SRD  Secondary RD
17 - RC   Receiver clock
18 -
19 - SRS  Secondary RTS            
20 - DTR  Data terminal ready      4
21 - SQD  Signal quality detector
22 - RI   Ring indicator           9
23 - DRS  Data rate select
24 - XTC  External clock
25 -

Ada

type Bit is mod 2;
type Rs_232_Layout is record
   Carrier_Detect      : Bit;
   Received_Data       : Bit;
   Transmitted_Data    : Bit;
   Data_Terminal_ready : Bit;
   Signal_Ground       : Bit;
   Data_Set_Ready      : Bit;
   Request_To_Send     : Bit;
   Clear_To_Send       : Bit;
   Ring_Indicator      : Bit;
end record;

for Rs_232_Layout use record
   Carrier_Detect      at 0 range 0..0;
   Received_Data       at 0 range 1..1;
   Transmitted_Data    at 0 range 2..2;
   Data_Terminal_Ready at 0 range 3..3;
   Signal_Ground       at 0 range 4..4;
   Data_Set_Ready      at 0 range 5..5;
   Request_To_Send     at 0 range 6..6;
   Clear_To_Send       at 0 range 7..7;
   Ring_Indicator      at 0 range 8..8;
end record;

C/C++

Note: The order of the fields is implementation-defined (i.e. the first bit might be the least-significant one or the most-significant one). On GCC and MSVC++, the first bit is the least-significant one.

struct RS232_data
{
  unsigned carrier_detect        : 1;
  unsigned received_data         : 1;
  unsigned transmitted_data      : 1;
  unsigned data_terminal_ready   : 1;
  unsigned signal_ground         : 1;
  unsigned data_set_ready        : 1;
  unsigned request_to_send       : 1;
  unsigned clear_to_send         : 1;
  unsigned ring_indicator        : 1;
};

The ":1" gives the number of allocated bits. For unused bits (e.g. pin 11 in the 25-pin version above) the field name can be omitted.

Forth

Low level hardware control is a typical use of Forth. None of this is standard, however, since hardware I/O mechanisms differ on different systems. Forth does not have a structure mechanism, much less bitfields. These would be represented instead via bitmask constants if doing real serial port control.

: masks ( n -- ) 0 do 1 i lshift constant loop ;

9 masks DCD RxD TxD DTR SG DSR RTS CTS RI

Example usage, assuming I/O primitives in and out:

hex
3fd constant com1-ctrl
decimal

: wait-ready
  begin
    com1-ctrl in
    CTS and
  until ;
: wait-rx
  begin
    com1-ctrl in
    CTS and 0=
  until ;

: send-byte ( b -- )   \ send assuming N81 (no parity, 8 bits data, 1 bit frame)
  255 and
  9 0 do
    RTS com1-ctrl out
    wait-ready
    dup 1 and if TxD else 0 then com1-ctrl out
    wait-rx
    2/
  loop drop ;
  

Of course, this is a very simplified view of the full RS-232 protocol. Also, although this represents the order of the pins in a D-9 connector, this would not necessarily be the same as the order of the bits in a control register.

OCaml

<ocaml>open ExtLib class rs232_data = object

 val d = BitSet.create 9
 method carrier_detect      = BitSet.is_set d 0
 method received_data       = BitSet.is_set d 1
 method transmitted_data    = BitSet.is_set d 2
 method data_terminal_ready = BitSet.is_set d 3
 method signal_ground       = BitSet.is_set d 4
 method data_set_ready      = BitSet.is_set d 5
 method request_to_send     = BitSet.is_set d 6
 method clear_to_send       = BitSet.is_set d 7
 method ring_indicator      = BitSet.is_set d 8
 method set_carrier_detect      b = (if b then BitSet.set else BitSet.unset) d 0
 method set_received_data       b = (if b then BitSet.set else BitSet.unset) d 1
 method set_transmitted_data    b = (if b then BitSet.set else BitSet.unset) d 2
 method set_data_terminal_ready b = (if b then BitSet.set else BitSet.unset) d 3
 method set_signal_ground       b = (if b then BitSet.set else BitSet.unset) d 4
 method set_data_set_ready      b = (if b then BitSet.set else BitSet.unset) d 5
 method set_request_to_send     b = (if b then BitSet.set else BitSet.unset) d 6
 method set_clear_to_send       b = (if b then BitSet.set else BitSet.unset) d 7
 method set_ring_indicator      b = (if b then BitSet.set else BitSet.unset) d 8

end

</ocaml>

Perl

use Bit::Vector::Minimal qw();
my $vec = Bit::Vector::Minimal->new(size => 24);

my %rs232 = reverse (
     1 => 'PG   Protective ground',
     2 => 'TD   Transmitted data',
     3 => 'RD   Received data',
     4 => 'RTS  Request to send',
     5 => 'CTS  Clear to send',
     6 => 'DSR  Data set ready',
     7 => 'SG   Signal ground',
     8 => 'CD   Carrier detect',
     9 => '+ voltage (testing)',
    10 => '- voltage (testing)',
    12 => 'SCD  Secondary CD',
    13 => 'SCS  Secondary CTS',
    14 => 'STD  Secondary TD',
    15 => 'TC   Transmit clock',
    16 => 'SRD  Secondary RD',
    17 => 'RC   Receiver clock',
    19 => 'SRS  Secondary RTS',
    20 => 'DTR  Data terminal ready',
    21 => 'SQD  Signal quality detector',
    22 => 'RI   Ring indicator',
    23 => 'DRS  Data rate select',
    24 => 'XTC  External clock',
);

$vec->set($rs232{'RD   Received data'}, 1);
$vec->get($rs232{'TC   Transmit clock'});

Python

This task cannot really be done efficiently in Python, as there is no type analogous to bit fields. The code below merely defines a dictionary with the pin names corresponding to entries in the dictionary.

<python># Controlling Fields in a Structure in Python

rs232 = { "PG Protective ground":1, "TD Transmitted data":2, "RD Received data":3, "RTS Request to send":4, "CTS Clear to send":5, "DSR Data set ready":6, "SG Signal ground":7, "CD Carrier detect":8, "+ voltage (testing)":9, "- voltage (testing)":10, "SCD Secondary CD":12, "SCS Secondary CTS":13, "STD Secondary TD":14, "TC Transmit clock":15, "SRD Secondary RD":16, "RC Receiver clock":17, "SRS Secondary RTS":19, "DTR Data terminal ready":20, "SQD Signal quality detector":21, "RI Ring indicator":22, "DRS Data rate select":23, "XTC External clock":24 }


rs232["RD Received data"] = 1 print rs232["TC Transmit clock"]</python>