Memory layout of a data structure: Difference between revisions

m
m (→‎{{header|Wren}}: Minor tidy)
 
(47 intermediate revisions by 19 users not shown)
Line 1:
{{task}}{{omit from|BBC BASIC}}
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.
Pin Settings for Plug
Line 5:
__________________________________________
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
Line 35:
24 - XTC External clock
25 -
=={{header|6502 Assembly}}==
<syntaxhighlight lang="6502asm">soft_rs232_lo equ $20 ;%87654321
soft_rs232_hi equ $21 ;%-------9</syntaxhighlight>
 
The values $20 and $21 do not matter; any zero page memory location is acceptable. The comments explain which bit position represents which pin, written in the format one would write a binary literal in the assembler. A "-" means that particular bit is unused.
 
This example non-destructively writes a "1" to pin 3:
<syntaxhighlight lang="6502asm">LDA soft_rs232_lo
ora #%00000100
sta soft_rs232_lo</syntaxhighlight>
 
The common practice is to have "soft" ports in zero page which get written to the memory-mapped location of the actual hardware interface by only a single subroutine that is run at a fixed interval. All other routines only ever update the "soft" port. (Hardware ports such as this example are typically write-only so the only way to non-destructively write to individual bits is through this indirect method.)
=={{header|68000 Assembly}}==
Thanks to the low-level nature of assembly, this task is actually rather straightforward. Using <code>equ</code> directives we can easily abstract the bit numbers with convenient labels without having to remember what they are.
 
<syntaxhighlight lang="68000devpac">BIT_0 equ $1
BIT_1 equ $2
BIT_2 equ $4
BIT_3 equ $8
BIT_4 equ $10
BIT_5 equ $20
BIT_6 equ $40
BIT_7 equ $80
 
BIT_8 equ $100
BIT_9 equ $200
 
RS232_9_TD equ BIT_3
RS232_9_RD equ BIT_2
RS232_9_RTS equ BIT_7
RS232_9_CTS equ BIT_8
RS232_9_DSR equ BIT_6
RS232_9_SG equ BIT_5
RS232_9_CD equ BIT_1</syntaxhighlight>
 
With these aliases defined, we can easily write these constants, or any combination thereof, to the memory-mapped RS232 port.
 
(Disclaimer: I have no idea how this protocol actually works. So there's a good chance that these values should '''not''' be combined this way when working with actual RS232 hardware. But that's not really important to this task. I'm just showing how you can define constants and write them to the port.)
 
<syntaxhighlight lang="68000devpac">rs232_9pin_port equ $A00000
;I chose $A00000 arbitrarily as an example, its actual address depends on the wiring.
 
MOVE.W #RS232_9_CTS,rs232_9pin_port
MOVE.W #RS232_9_CTS|RS232_9_RD|RS232_9_SG,rs232_9pin_port ;bitwise OR can be used at compile time to combine the labels.</syntaxhighlight>
 
 
=={{header|Ada}}==
<langsyntaxhighlight lang="ada">type Bit is mod 2;
type Rs_232_Layout is record
Carrier_Detect : Bit;
Line 60 ⟶ 105:
Clear_To_Send at 0 range 7..7;
Ring_Indicator at 0 range 8..8;
end record;</langsyntaxhighlight>
 
=={{header|ALGOL 68}}==
Line 67 ⟶ 112:
{{works with|ALGOL 68G|Any - tested with release [http://sourceforge.net/projects/algol68/files/algol68g/algol68g-1.18.0/algol68g-1.18.0-9h.tiny.el5.centos.fc11.i386.rpm/download 1.18.0-9h.tiny]}}
{{works with|ELLA ALGOL 68|Any (with appropriate job cards) - tested with release [http://sourceforge.net/projects/algol68/files/algol68toc/algol68toc-1.8.8d/algol68toc-1.8-8d.fc9.i386.rpm/download 1.8-8d]}}
<langsyntaxhighlight lang="algol68">MODE RSTWOTHREETWO = BITS;
INT ofs = bits width - 9;
INT
Line 86 ⟶ 131:
 
rs232 bits := bits pack((FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE));
print(("received data: ",received data ELEM rs232bits, new line))</langsyntaxhighlight>
Output:
<pre>
Line 95 ⟶ 140:
=={{header|C}}/{{header|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.
<langsyntaxhighlight lang="c">struct RS232_data
{
unsigned carrier_detect : 1;
Line 106 ⟶ 151:
unsigned clear_to_send : 1;
unsigned ring_indicator : 1;
};</langsyntaxhighlight>
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.
 
Line 115 ⟶ 160:
Implementation uses tango's BitArray structure.
{{libheader|tango}}
<langsyntaxhighlight Dlang="d">module controlFieldsInStruct;
 
import tango.core.BitArray;
Line 185 ⟶ 230:
 
return 0;
}</langsyntaxhighlight>
 
Output:
Line 193 ⟶ 238:
===Phobos version===
Not tested.
<langsyntaxhighlight lang="d">import std.bitmanip;
 
struct RS232_data {
Line 223 ⟶ 268:
}
 
void main() {}</langsyntaxhighlight>
 
=={{header|Delphi}}==
{{works with|Delphi|6.0}}
{{libheader|SysUtils,StdCtrls}}
The following code examines the memory associated with Delphi "Sets." In the case, the program creates a set associated with the RS232 pin patterns. It then displays the content of memory showing how each item in the set is associated with a single bit in memory.
<syntaxhighlight lang="Delphi">
 
{Enumerate pin assignments}
 
type TRS232Pins = (rpCarrierDetect, rpReceivedData, rpTransmittedData,
rpDataTerminalReady, rpSignalGround, rpDataSetReady,
rpRequestToSend, rpClearToSend, rpRingIndicator);
{Make into a set}
type TPinSet = set of TRS232Pins;
 
var Pins: TPinSet; {Global variable holding a set of pins}
 
procedure ShowMemory(Memo: TMemo; Name: string; SetPins: TPinSet);
{Extract the set data from memory and display it}
var S: string;
var P: PWord;
begin
P:=@Pins;
Pins:=SetPins;
S:=Name;
S:=S+IntToBin(P^, 16, True);
Memo.Lines.Add(S);
end;
 
 
 
procedure ShowPinsMemory(Memo: TMemo);
begin
ShowMemory(Memo,'Empty: ',[]);
ShowMemory(Memo,'Carrier Detect: ',[rpCarrierDetect]);
ShowMemory(Memo,'Received Data: ',[rpReceivedData]);
ShowMemory(Memo,'Transmitted Data: ',[rpTransmittedData]);
ShowMemory(Memo,'Data Terminal Ready:',[rpDataTerminalReady]);
ShowMemory(Memo,'Signal Ground: ',[rpSignalGround]);
ShowMemory(Memo,'Data Set Ready: ',[rpDataSetReady]);
ShowMemory(Memo,'Request To Send: ',[rpRequestToSend]);
ShowMemory(Memo,'Clear To Send: ',[rpClearToSend]);
ShowMemory(Memo,'Ring Indicator: ',[rpRingIndicator]);
end;
 
 
</syntaxhighlight>
{{out}}
<pre>
Empty: 0000000000000000
Carrier Detect: 0000000000000001
Received Data: 0000000000000010
Transmitted Data: 0000000000000100
Data Terminal Ready:0000000000001000
Signal Ground: 0000000000010000
Data Set Ready: 0000000000100000
Request To Send: 0000000001000000
Clear To Send: 0000000010000000
Ring Indicator: 0000000100000000
</pre>
 
 
=={{header|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.
 
<langsyntaxhighlight lang="forth"> : masks ( n -- ) 0 do 1 i lshift constant loop ;
9 masks DCD RxD TxD DTR SG DSR RTS CTS RI</langsyntaxhighlight>
 
Example usage, assuming I/O primitives '''in''' and '''out''':
 
<langsyntaxhighlight lang="forth"> hex
3fd constant com1-ctrl
decimal
Line 257 ⟶ 363:
wait-rx
2/
loop drop ;</langsyntaxhighlight>
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.
 
=={{header|Fortran}}==
===Modern===
F90 introduced the ability to define compound data aggregates, as had been used from the start by COBOL in the 1960s. Thus, one could define <syntaxhighlight lang="fortran"> TYPE RS232PIN9
LOGICAL CARRIER_DETECT !1
LOGICAL RECEIVED_DATA !2
LOGICAL TRANSMITTED_DATA !3
LOGICAL DATA_TERMINAL_READY !4
LOGICAL SIGNAL_GROUND !5
LOGICAL DATA_SET_READY !6
LOGICAL REQUEST_TO_SEND !7
LOGICAL CLEAR_TO_SEND !8
LOGICAL RING_INDICATOR !9
END TYPE RS232PIN9 </syntaxhighlight>
But it would be nearly pointless to do so.
 
Fortran's LOGICAL type is defined to occupy as much space as the default INTEGER type, which is typically thirty-two bits. This was done to simplify questions of storage size for large collections of assorted types of variables in a COMMON storage area. Further, ''true'' and ''false'' may not be signified by 1 and 0 but by -1 and 0, or, something else. Many compilers continue to support the old-style storage size indications that were introduced for binary computers and so would allow LOGICAL*1, but alas, this does not mean one bit, it means one byte. There is no equivalent of a key word PACKED (as in Pascal for example) whereby it might be indicated that a collection of items are to be stored "adjacent" and not aligned to byte or word boundaries. But, without a storage type equivalent to BIT(1) such as pl/i offers, this won't help either. Such packing can make reading or writing to a variable quite difficult - imagine a 32-bit integer variable offset by three bits - which is why some languages offer the keyword ALIGNED.
 
However, all is not quite lost. Given that one can access the special storage word containing the status of the nine-pin socket, presumably returning what can be regarded as a thirty-two bit integer (to accommodate a 25-pin socket), then, given certain knowledge of the ordering of the pins versus the bits of the integer (are bits counted from left-to-right or right-to-left, starting at one or at zero?), and certain knowledge that the nine bits are at the high-order end of the word or at the low-order end of the word (the IBM 1130's card reader placed the image of a column of a card, twelve bits, at the high-order end of its sixteen-bit word), it would be merely a matter of tedium to unpack those bits with suitable expressions and place the appropriate values into the components of a variable of type RS232PIN9. Such variables can then be juggled in the usual way, for instance using NAMELIST style I/O whereby the values are presented along with the names of the variables holding them. For output, this could be achieved with suitable FORMAT statements.
 
There may be available library functions IAND(i,j) and IOR(i,j) for dealing with integer variables, otherwise it becomes a matter of integer arithmetic. Unpacking or re-packing a data structure (say, as found in a disc file record) is straightforward but tedious, and, aside from the sizes and types of the components one must have definite knowledge of the endianness of the data as in the aggregate (read from disc) compared to the endianness of the cpu running your procedure. Easiest is of course to have the same style cpu for both.
 
===Older style===
Without the ability to create data aggregates via TYPE statements, whereby a single variable might sprawl across memory as above, one instead prepared a collection of variables, usually with some systematic name convention linking the names of the parts. These variables would be anywhere in memory and so had no particular memory layout in themselves. However, when stored as a record in a disc file a data structure is created with a definite layout, and this is manifest in the READ and WRITE statements involved. Suppose the statement was <code>WRITE (F,REC = n) THIS,M,NAME</code> meaning that the n'th record of file unit F was to be written. The types of the variables would be known, and their sizes also. Say <code>REAL*8 THIS</code>, <code>INTEGER*1 M</code>, and <code>CHARACTER*28 NAME</code>. Such a record could be read (or written) by <code>READ (F,REC = n) STUFF</code> given a declaration <code>CHARACTER*37 STUFF</code> (counting on fingers as necessary) and the various parts of the data aggregate could be indexed within STUFF. However, the interpretation of the interior bytes of multi-byte items such as integer and floating-point variables is complicated by the endianness of the processor, a confounding nuisance.
 
It is further possible to declare that STUFF is to occupy the same storage as the named variables. If the declaration was <code>CHARACTER*1 STUFF(37)</code>, then <code>EQUIVALENCE (STUFF(1),THIS),(STUFF(9),M),(STUFF(10),NAME)</code> would mean that STUFF occupied the same storage as those variables, or rather, that the variables occupied the same storage as STUFF - indeed, they could overlay each other, which would be unlikely to be helpful. This could mean that a floating-point or integer variable was ''not'' aligned to a word boundary with the consequent penalty in access, for instance by having THIS start with STUFF(2) because M was put first. Some systems may not allow byte-based addressing, only word-based so complications can arise. But this demonstrates precise knowledge of the memory layout of a data structure. The more modern compilers that allow the TYPE declaration typically do not allow the appearance of such variables in EQUIVALENCE statements, to prevent access to the memory layout of such data structures. Others allow a new version of EQUIVALENCE (which the moderns deprecate) via the MAP statement, but this is not standard Fortran.
 
As before stated, there is no BIT facility, so packing is to byte boundaries. But, if one is determined to store thousands of records with minimal storage use, it may seem worth the effort to engage in the arithmetic to pack the likes of say three bits, followed by the thirty-two bits of a floating-point value, and so on, into a sequence of bytes which then would be written. In such a situation it may even be worth packing only a portion of the floating-point variable, if reduced precision is acceptable and one is certain of the usage of the bits within such a number. However, given the difficulty of access to the parts of such a packed aggregate, it is usually better to leave the byte/word packing and unpacking to the I/O system as via <code>WRITE (F,REC = n) THIS,M,NAME</code> and then manipulate the variables as their conveniently-aligned in-memory forms as ordinary variables, only repacking to the data structure form with a subsequent WRITE statement.
 
The INTEGER*''n'' opportunity is not fully flexible in that powers of two are usually the only options so that a value that might fit into INTEGER*3 will have to go into INTEGER*4. In any case this style is not helpful for decimal machines or binary computers whose word size is not a power of two. It is possible to break away from a byte base, especially when there are many variables with small ranges to represent. Suppose that V3 only has values 0, 1, 2; V5 has only 0, 1, 2, 3, 4; V4 only 0, 1, 2, 3; and V2 only 0, 1. Then a set of values could be encoded as a single decimal number: say 1230 for the four variables in that order, which would fit into a two byte integer instead of four one byte integers. That is merely changing base 256 to base 10, notionally, but a better packing is possible, Consider <code>V = V3 + 3*(V5 + 5*(V4 + 4*(V2)))</code> whose maximum value would be 2 + 3*(4 + 5*(3 + 4*1)) = 119, which will fit into one byte. If there were many such variables, then their packed values might require larger integers for even greater sharing. Variables with fractional values can be treated in a similar way, cautiously...
 
With careful planning, such a compound value may even have helpful numerical properties, of service for (some) multi-key sorts. In the example, V2 is the high-order value so if a desired sort key happened to include V2, V4, V5, V3 then a four-variable comparison could be done in just one test. Unless the value overflows into the sign bit. This may not be a problem if the sorted order is merely to facilitate a binary search that will use the same ordering, but there can still be surprises. The B6700 used a 48-bit word and its compiler did not offer the then-unknown CHARACTER type. One might store six eight-bit characters in a word without worrying over the ordering that will result - the B6700 had no integer representation as such, using floating-point numbers with no fractional part, so the numerical values resulting from character codes would be quite odd. However, it also worked in base eight and although forty-eight is divisible by three, the requirement for the sign of the exponent and the sign of the value uses only two bits. Thus, one bit, the topmost, did not participate in arithmetic operations and as a result, arithmetic could not distinguish between characters in the high end of a word that differed in their highest bit. Even .EQ. would fail and the compiler offered a special substitute, .IS. to test for equality. Other languages that offered character manipulation (such as the extensions to Algol) used entirely different methods that avoided this problem.
 
In a similar way, text content may employ only a limited character set so perhaps five bits per symbol would suffice, or some other packing scheme might suggest itself. There is also a whole world of compression algorithms. The end result is that a data structure manifesting as records in a disc file may be difficult to unpack into a convenient internal form even given a careful description of the layout.
 
=={{header|Free Pascal}}==
The FPC (Free Pascal compiler) carefully defines the internal memory structure of data type in its “Programmer’s guide”.
<syntaxhighlight lang="pascal">program rs232(input, output, stdErr);
type
{$packEnum 2}{$scopedEnums off}
pin = (carrierDetect, receivedData, transmittedData, dataTerminalReady,
signalGround, dataSetReady, requestToSend, clearToSend, ringIndicator);
{$packSet 2}
pins = set of pin;
var
signal: pins;
// for demonstration purposes, in order to reveal the memory layout
signalMemoryStructure: word absolute signal;
{$if sizeOf(signal) <> sizeOf(word)} // just as safe-guard
{$fatal signal size}
{$endIf}
begin
signal := [];
include(signal, signalGround); // equivalent to signal := signal + [signalGround];
// for demonstration purposes: obviously we know this is always `true`
if signalGround in signal then
begin
writeLn(binStr(signalMemoryStructure, bitSizeOf(signal)));
end;
end.</syntaxhighlight>
{{Out}}
<pre>0000000000010000</pre>
 
=={{header|FreeBASIC}}==
<syntaxhighlight lang="freebasic">' FB 1.05.0 Win64
 
' using bit fields
Type RS232_Pin9
carrierDetect : 1 As UByte
receivedData : 1 As UByte
transmittedData : 1 As UByte
dataTerminalReady : 1 As UByte
signalGround : 1 As UByte
dataSetReady : 1 As UByte
requestToSend : 1 As UByte
clearToSend : 1 As UByte
ringIndicator : 1 As UByte
End Type
 
Print SizeOf(RS232_Pin9) '' 2 bytes
Sleep</syntaxhighlight>
 
=={{header|Go}}==
Go does not have named bits as part of the type system. Instead, constants are typically defined as shown. For a word of bits with special meanings like this, a type would be defined though, as shown. Static typing rules then control assignments and comparisons at the word level. At the bit level, it helps to follow naming conventions so that, say, using a 9-pin constant on a 25-pin word would be an obvious error in the source code.
<langsyntaxhighlight lang="go">package main
 
import "fmt"
Line 269 ⟶ 457:
 
const (
CD9 CD9 rs232p9 = 1 << iota // Carrier detect
RD9 RD9 // Received data
TD9 TD9 // Transmitted data
DTR9 DTR9 // Data terminal ready
SG9 SG9 // signal ground
DSR9 DSR9 // Data set ready
RTS9 RTS9 // Request to send
CTS9 CTS9 // Clear to send
RI9 RI9 // Ring indicator
)
 
func main() {
// set some nonsense bits just for example
var p rs232p9 := RI9 | TD9 | CD9
fmt.Printf("Type=%T value=%#04x\n", p, p)
}</langsyntaxhighlight>
{{out}}
Output:
<pre>
Type=main.rs232p9 value=0x0105
0105
</pre>
 
=={{header|J}}==
J does not support "structures", nor "fields in a structure". Instead, J supports arrays. And, of course, J could have labels corresponding to the elements of an array representing the state (voltage, current, logical bit value, whatever) of each pin of a 9-pin RS-232 plug:
<syntaxhighlight lang="j">default=: 0#~#|:'labels comments'=:|:(4 ({.@;:@{. ; }.)]);._2 {{)n
<lang j>labels=: <;._2]0 :0
CD Carrier detect
RD Received data
TD Transmitted data
Line 302 ⟶ 489:
CTS Clear to send
RI Ring indicator
}}
)</lang>
 
indices=: labels (i. ;: ::]) ]
ndx=: [ {~ [ indices ]
asgn=: {{ y (x indices m)} x }}</syntaxhighlight>
 
Example use:
 
<syntaxhighlight lang="j"> example=: default NB. new instance
example ndx 'RI CTS'
0 0
example=: example 'RI RTS TD' asgn 1 2 3
example ndx 'RI CTS'
1 0</syntaxhighlight>
 
=={{header|Java}}==
<syntaxhighlight lang="java">
public final class MemoryLayoutOfDataStructure {
 
public static void main(String[] aArgs) {
RS232Pins9 plug = new RS232Pins9();
System.out.println(plug.getPin("receivedData"));
plug.setPin(2, Status.ON);
System.out.println(plug.getPin("receivedData"));
plug.setPin("signalGround", Status.ON);
plug.displayPinStatus();
}
}
 
enum Status { OFF, ON }
final class RS232Pins9 {
public Status getPin(int aPinNumber) {
for ( Pin pin : Pin.values() ) {
if ( pin.pinNumber == aPinNumber ) {
return pin.status;
}
}
throw new IllegalArgumentException("Unknown pin number: " + aPinNumber);
}
public Status getPin(String aName) {
for ( Pin pin : Pin.values() ) {
if ( pin.name() == aName ) {
return pin.status;
}
}
throw new IllegalArgumentException("Unknown pin name: " + aName);
}
public void setPin(int aPinNumber, Status aStatus) {
for ( Pin pin : Pin.values() ) {
if ( pin.pinNumber == aPinNumber ) {
pin.status = aStatus;
}
}
}
public void setPin(String aName, Status aStatus) {
for ( Pin pin : Pin.values() ) {
if ( pin.name() == aName ) {
pin.status = aStatus;
}
}
}
public void displayPinStatus() {
for ( Pin pin : Pin.values() ) {
System.out.println(String.format("%-29s%s", pin.name() + " has status ", pin.status));
}
}
private enum Pin {
carrierDetect(1, Status.OFF), receivedData(2, Status.OFF), transmittedData(3, Status.OFF),
dataTerminalReady(4, Status.OFF), signalGround(5, Status.OFF), dataSetReady(6, Status.OFF),
requestToSend(7, Status.OFF), clearToSend(8, Status.OFF), ringIndicator(9, Status.OFF);
private Pin(int aPinNumber, Status aStatus) {
pinNumber = aPinNumber;
status = aStatus;
}
private int pinNumber;
private Status status;
}
 
}
</syntaxhighlight>
{{ out }}
<pre>
OFF
ON
carrierDetect has status OFF
receivedData has status ON
transmittedData has status OFF
dataTerminalReady has status OFF
signalGround has status ON
dataSetReady has status OFF
requestToSend has status OFF
clearToSend has status OFF
ringIndicator has status OFF
</pre>
 
=={{header|Julia}}==
If the nine-pin version of the serial port is as specified above:
<pre>1 2 3 4 5
6 7 8 9
9 pin
PG Protective ground
TD Transmitted data 3
RD Received data 2
RTS Request to send 7
CTS Clear to send 8
DSR Data set ready 6
SG Signal ground 5
CD Carrier detect 1
+ voltage (testing)
</pre>
We can then make the following code for a new serial port type:
<syntaxhighlight lang="julia">
mutable struct NinePinSerialPort
pins::BitArray
function NinePinSerialPort()
this = new()
this.pins = BitArray(9)
end
end
 
const CD = 1
const RD = 2
const TD = 3
const SG = 5
const DSR = 6
const RTS = 7
const CTS = 8
 
# Here we test the type's code.
port = NinePinSerialPort()
println("Port is now at defaults, which are $port")
port[CTS] = true
println("CD pin of port, which is pin $CD, is now $(port[CD])")
println("CTS pin of port, which is pin $CTS, is now $(port[CTS])")
println("port is now: $port")
</syntaxhighlight>
{{output}}
<pre>
Port is now at defaults, which are Bool[false, false, false, false, false, false, false, false, false]
CD pin of port, which is pin 1, is now false
CTS pin of port, which is pin 8, is now true
port is now: Bool[false, false, false, false, false, false, false, true, false]
</pre>
 
=={{header|Kotlin}}==
If it were only desired to access pin settings by position (albeit starting from pin 0 rather than pin 1), then a java.util.BitSet could be used to model this task.
 
However, if access by both position and name is required, then a data class with 9 named boolean properties would be more suitable. This automatically generates functions called component1, component2 etc. to get the pin values by pin number. However, a function needs to be written manually to set pin values by pin number:
<syntaxhighlight lang="scala">// version 1.0.6
 
const val OFF = false
const val ON = true
 
fun toOnOff(b: Boolean) = if (b) "ON" else "OFF"
 
data class Rs232Pins9(
var carrierDetect : Boolean = OFF,
var receivedData : Boolean = OFF,
var transmittedData : Boolean = OFF,
var dataTerminalReady : Boolean = OFF,
var signalGround : Boolean = OFF,
var dataSetReady : Boolean = OFF,
var requestToSend : Boolean = OFF,
var clearToSend : Boolean = OFF,
var ringIndicator : Boolean = OFF
) {
fun setPin(n: Int, v: Boolean) {
when (n) {
1 -> carrierDetect = v
2 -> receivedData = v
3 -> transmittedData = v
4 -> dataTerminalReady = v
5 -> signalGround = v
6 -> dataSetReady = v
7 -> requestToSend = v
8 -> clearToSend = v
9 -> ringIndicator = v
}
}
}
 
fun main(args: Array<String>) {
val plug = Rs232Pins9(carrierDetect = ON, receivedData = ON) // set first two pins, say
println(toOnOff(plug.component2())) // print value of pin 2 by number
plug.transmittedData = ON // set pin 3 by name
plug.setPin(4, ON) // set pin 4 by number
println(toOnOff(plug.component3())) // print value of pin 3 by number
println(toOnOff(plug.dataTerminalReady)) // print value of pin 4 by name
println(toOnOff(plug.ringIndicator)) // print value of pin 9 by name
}</syntaxhighlight>
 
{{out}}
<pre>
ON
ON
ON
OFF
</pre>
 
=={{header|MATLAB}} / {{header|Octave}}==
Defining structs in MATLAB is kind of bulky, making a class definition might be cleaner for this purpose. If you need to enumerate each pin rather than set the state of the pin using the name of the pin, you can use struct2cell() on the rs232 struct, which will return a cell array whose entries are the value of each of the structs fields in the order in which they were defined.
 
<langsyntaxhighlight MATLABlang="matlab">>> rs232 = struct('carrier_detect', logical(1),...
'received_data' , logical(1), ...
'transmitted_data', logical(1),...
Line 341 ⟶ 737:
[1]
[1]
[1]</langsyntaxhighlight>
 
=={{header|Mercury}}==
Line 351 ⟶ 747:
 
=== rs232.m ===
<syntaxhighlight lang="mercury">
<lang Mercury>
:- module rs232.
 
Line 422 ⟶ 818:
 
:- end_module rs232.
</syntaxhighlight>
</lang>
 
=== rs232_main.m ===
<syntaxhighlight lang="mercury">:- module rs232_main.
<lang Mercury>
:- module rs232_main.
 
:- interface.
Line 449 ⟶ 844:
 
write_string("Com1 DTR is ", !IO),
( if rs232_is_set(Com1, data_terminal_ready) ->then
write_string("set.", !IO), nl(!IO)
else
; write_string("clear.", !IO), nl(!IO) ),
write_string("clear.", !IO), nl(!IO)
),
 
write_string("Com2 DSR is ", !IO),
( if rs232_is_clear(Com2, data_set_ready) ->then
write_string("clear.", !IO), nl(!IO)
else
; write_string("set.", !IO), nl(!IO) ).
write_string("set.", !IO), nl(!IO)
).
 
:- end_module rs232_main.
</syntaxhighlight>
</lang>
 
==== Usage and output ====
Line 468 ⟶ 867:
''Com1 DTR is set.''
''Com2 DSR is clear.''
 
=={{header|Nim}}==
<syntaxhighlight lang="nim">type
rs232Data = enum
carrierDetect,
receivedData,
transmittedData,
dataTerminalReady,
signalGround,
dataSetReady,
requestToSend,
clearToSend,
ringIndicator
 
# Bit vector of 9 bits
var bv = {carrierDetect, signalGround, ringIndicator}
echo cast[uint16](bv) # Conversion of bitvector to 2 bytes for writing
 
let readValue: uint16 = 123
bv = cast[set[rs232Data]](readValue) # Conversion of a read value to bitvector
echo bv</syntaxhighlight>
Output:
<pre>273
{carrierDetect, receivedData, dataTerminalReady, signalGround, dataSetReady, requestToSend}</pre>
 
=={{header|OCaml}}==
'''Library:''' [http://code.google.com/p/ocaml-extlib/ extlib]
<langsyntaxhighlight lang="ocaml">open ExtLib
class rs232_data = object
val d = BitSet.create 9
Line 495 ⟶ 918:
method set_ring_indicator b = (if b then BitSet.set else BitSet.unset) d 8
end
;;</langsyntaxhighlight>
 
=={{header|Pascal}}==
Pascal itself does not define, how data types have to be stored in memory.
{{works with|Free_Pascal}}
It is up to the processor (i. e. compiler) to choose appropriate mechanism.
<lang pascal>program memoryLayout;
The [[#Free Pascal|FPC]] (Free Pascal compiler) does predictably define how it stores data.
 
type
T_RS232 = (
carrier_detect,
received_data,
transmitted_data,
data_terminal_ready,
signal_ground,
data_set_ready,
request_to_send,
clear_to_send,
ring_indicator
);
 
var
Signal: bitpacked array[T_RS232] of boolean;
 
begin
Signal[signal_ground] := true;
end.</lang>
 
=={{header|Perl}}==
<langsyntaxhighlight lang="perl">use Bit::Vector::Minimal qw();
my $vec = Bit::Vector::Minimal->new(size => 24);
 
Line 551 ⟶ 955:
 
$vec->set($rs232{'RD Received data'}, 1);
$vec->get($rs232{'TC Transmit clock'});</langsyntaxhighlight>
=={{header|Perl 6}}==
The following is specced to work, but implementation of shaped arrays is not quite complete.
<lang perl6>enum T_RS232 <
carrier_detect
received_data
transmitted_data
data_terminal_ready
signal_ground
data_set_ready
request_to_send
clear_to_send
ring_indicator
>;
 
=={{header|Phix}}==
my bit @signal[T_RS232];
Phix does not support bit-fields directly. The nearest/sanest thing to do probably goes something like this (completely untested)
 
<!--<syntaxhighlight lang="phix">-->
@signal[signal_ground] = 1;</lang>
<span style="color: #008080;">constant</span> <span style="color: #000000;">CD</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">RD</span><span style="color: #0000FF;">=</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">TD</span><span style="color: #0000FF;">=</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">DTR</span><span style="color: #0000FF;">=</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">...</span>
In the absence of shaped arrays, you can do the usual bit-twiddling tricks on a native integer of sufficient size. (Such an integer could presumably be mapped directly to a device register.)
<span style="color: #004080;">atom</span> <span style="color: #000000;">addr</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">allocate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- or wherever
<lang perl6>$signal +|= 1 +< signal_ground;</lang>
--read</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">bits</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">int_to_bits</span><span style="color: #0000FF;">(</span><span style="color: #000000;">peek2u</span><span style="color: #0000FF;">(</span><span style="color: #000000;">addr</span><span style="color: #0000FF;">),</span><span style="color: #000000;">16</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">dtr</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">bits</span><span style="color: #0000FF;">[</span><span style="color: #000000;">DTR</span><span style="color: #0000FF;">]</span>
<span style="color: #000080;font-style:italic;">--write</span>
<span style="color: #000000;">bits</span><span style="color: #0000FF;">[</span><span style="color: #000000;">DTR</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
<span style="color: #7060A8;">poke2</span><span style="color: #0000FF;">(</span><span style="color: #000000;">addr</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">bits_to_int</span><span style="color: #0000FF;">(</span><span style="color: #000000;">bits</span><span style="color: #0000FF;">))</span>
<!--</syntaxhighlight>-->
 
Naturally, you would be well advised to sequester such grubby details away in a small and separate unit/source code file (eg RS232.e) with a domain specific public API that does not leak implementation details (eg keep those constants private). There are 1/2/4/8 byte variants of peek and poke, and int-to-bits can extract anything from 1 to 53 bits on a 32-bit runtime, or up to 64 on a 64-bit runtime.
Alternatively you could use bit-masks, or it may be possible to enhance builtins/cffi.e to manage bit-fields, then again the above C entry does not exactly inspire confidence.
 
=={{header|PicoLisp}}==
Line 578 ⟶ 980:
'[http://software-lab.de/doc/refX.html#x| x|]',
or tested with '[http://software-lab.de/doc/refB.html#bit? bit?]'.
<langsyntaxhighlight PicoLisplang="picolisp"># Define bit constants
(for (N . Mask) '(CD RD TD DTR SG DSR RTS CTS RI)
(def Mask (>> (- 1 N) 1)) )
Line 584 ⟶ 986:
# Test if Clear to send
(when (bit? CTS Data)
... )</langsyntaxhighlight>
 
=={{header|PL/I}}==
<syntaxhighlight lang="pl/i">
<lang PL/I>
declare 1 RS232_layout,
2 Carrier_Detect Bit(1),
Line 598 ⟶ 1,000:
2 Clear_To_Send Bit(1),
2 Ring_Indicator Bit(1);
</syntaxhighlight>
</lang>
 
=={{header|Python}}==
The ctypes module allows for the creation of Structures that can map between the structures of C and python datatypes. Within Structures, [http://docs.python.org/library/ctypes.html#bit-fields-in-structures-and-unions bit fields] can be created.
 
<langsyntaxhighlight lang="python">from ctypes import Structure, c_int
 
rs232_9pin = "_0 CD RD TD DTR SG DSR RTS CTS RI".split()
Line 615 ⟶ 1,017:
class RS232_25pin(Structure):
_fields_ = [(__, c_int, 1) for __ in rs232_25pin]</langsyntaxhighlight>
 
=={{header|Racket}}==
 
<langsyntaxhighlight lang="racket">
#lang racket
 
Line 634 ⟶ 1,036:
((ctype-scheme->c _rs232) '(SG TD RI)) ; -> 276
((ctype-c->scheme _rs232) 276) ; -> '(TD SG RI)
</syntaxhighlight>
</lang>
 
=={{header|Raku}}==
(formerly Perl 6)
The following is specced to work, but implementation of shaped arrays is not quite complete.
<syntaxhighlight lang="raku" line>enum T_RS232 <
carrier_detect
received_data
transmitted_data
data_terminal_ready
signal_ground
data_set_ready
request_to_send
clear_to_send
ring_indicator
>;
 
my bit @signal[T_RS232];
 
@signal[signal_ground] = 1;</syntaxhighlight>
In the absence of shaped arrays, you can do the usual bit-twiddling tricks on a native integer of sufficient size. (Such an integer could presumably be mapped directly to a device register.)
<syntaxhighlight lang="raku" line>$signal +|= 1 +< signal_ground;</syntaxhighlight>
Using a native int is likelier to work on a big-endian machine in any case. Another almost-there solution is the mapping of C representational types into Raku for native interfaces, but it does not yet support bit fields.
 
=={{header|REXX}}==
===version 1===
<langsyntaxhighlight lang="rexx">/* REXX ***************************************************************
* Decode Memory structure of RS-232 Plug Definition
* Not sure if I understood it completely :-) Open for corrections
Line 757 ⟶ 1,181:
res=res||bs
End
Return res</langsyntaxhighlight>
Output EBCDIC:
<pre>
Line 800 ⟶ 1,224:
===version 2===
Checks could be added to verify the number of pins selected, and also verify if the data (pin readings) specified is valid.
<langsyntaxhighlight lang="rexx">/*REXX pgmprogram displays which pins are active of a 9 or 24 pin RS-232 plug. */
call rs_232 24, 127 /*the value for an RS-232 24 pin plug.*/
call rs_232 24, '020304x' /*value for" " " " " " " an RS-232 24" pin plug*/
call rs_232 9, '10100000b' /*value for" " " " " an RS-232 9 pin plug" " */
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
/*──────────────────────────────────RS_232 subroutine───────────────────*/
rs_232: arg pins,x; parse arg pins,ox /*xX is uppercased when using ARG. */
@. = '??? unassigned bitpin' /*assignedassign a default for all bitsthe pins. */
@.24.1 = 'PG protective ground'
@.24.2 = 'TD transmitted data' ; @.9.3 = @.24.2
@.24.3 = 'RD received data' ; @.9.2 = @.24.3
@.24.4 = 'RTS request to send' ; @.9.7 = @.24.4
@.24.5 = 'CTS clear to send' ; @.9.8 = @.24.5
@.24.6 = 'DSR data set ready' ; @.9.6 = @.24.6
@.24.7 = 'SG signal ground' ; @.9.5 = @.24.7
@.24.8 = 'CD carrier detect' ; @.9.1 = @.24.8
@.24.9 = '+ positive voltage'
@.24.10 = '- negative voltage'
@.24.12 = 'SCD secondary CD'
@.24.13 = 'SCS secondary CTS'
@.24.14 = 'STD secondary td'
@.24.15 = 'TC transmit clock'
@.24.16 = 'SRD secondary RD'
@.24.17 = 'RC receiver clock'
@.24.19 = 'SRS secondary RTS'
@.24.20 = 'DTR data terminal ready' ; @.9.4 = @.24.20
@.24.21 = 'SQD signal quality detector'
@.24.22 = 'RI ring indicator' ; @.9.9 = @.24.22
@.24.23 = 'DRS data rate select'
@.24.24 = 'XTC external clock'
 
select
when right(x,1)=='B' then bits= strip(x,'T',"B") select
when right(x, 1)=='XB' then bits=x2b( strip(x, 'T', "XB"))
otherwise when right(x, 1)=='X' then bits=x2b( d2xstrip(x, 'T', "X"))
otherwise bits=x2b( d2x(x) )
end /*select*/
bits=right(bits,pins,0) /*right justifyend the pin readings./*select*/
say
say; say '───────── For a' pins "pin RS─232 plug, with a reading of: " ox
bits=right(bits, pins, 0) /*right justify pin readings (values). */
say
say do'───────── For a' j=1 for pins; "pin z=substr(bitsRS─232 plug,j,1); with a reading of: if" z==0 then iterateox
say
say right(j,5) 'pin is "on": ' @.pins.j
do j=1 for pins; z=substr(bits, j, 1); if z==0 then iterate
end /*j*/
say right(j, 5) 'pin is "on": ' @.pins.j
return</lang>
end /*j*/
'''output''' when using the internal input:
return</syntaxhighlight>
<pre style="overflow:scroll">
'''output''' &nbsp; when using the default (internal) inputs:
<pre>
───────── For a 24 pin RS─232 plug, with a reading of: 127
 
18 pin is "on": B18??? unassigned bit 18pin
19 pin is "on": SRS secondary RTS
20 pin is "on": DTR data terminal ready
Line 869 ⟶ 1,295:
=={{header|Ruby}}==
Uses the [http://redshift.sourceforge.net/bit-struct/ BitStruct] module, which is handy but awkward to instantiate objects.
<langsyntaxhighlight lang="ruby">require 'bit-struct'
 
class RS232_9 < BitStruct
Line 898 ⟶ 1,324:
puts sample2.inspect_detailed
 
puts "CD is #{sample2.cd == 1 ? 'on' : 'off'}"</langsyntaxhighlight>
 
<pre>num = 37
Line 922 ⟶ 1,348:
Ring indicator = 0
CD is on</pre>
 
=={{header|Scala}}==
<syntaxhighlight lang="scala">object Rs232Pins9 extends App {
 
val (off: Boolean, on: Boolean) = (false, true)
val plug = new Rs232Pins9(carrierDetect = on, receivedData = on) // set first two pins, say
 
def toOnOff(b: Boolean) = if (b) "on" else "off"
 
class Rs232Pins9(
var carrierDetect: Boolean = off,
var receivedData: Boolean = off,
var transmittedData: Boolean = off,
var dataTerminalReady: Boolean = off,
var signalGround: Boolean = off,
var dataSetReady: Boolean = off,
var requestToSend: Boolean = off,
var clearToSend: Boolean = off,
var ringIndicator: Boolean = off
) {
def setPin(n: Int, v: Boolean) {
(n) match {
case 1 => carrierDetect = v
case 2 => receivedData = v
case 3 => transmittedData = v
case 4 => dataTerminalReady = v
case 5 => signalGround = v
case 6 => dataSetReady = v
case 7 => requestToSend = v
case 8 => clearToSend = v
case 9 => ringIndicator = v
}
}
}
 
// println(toOnOff(plug.component2())) // print value of pin 2 by number
plug.transmittedData = on // set pin 3 by name
plug.setPin(4, on) // set pin 4 by number
// println(toOnOff(plug.component3())) // print value of pin 3 by number
println(toOnOff(plug.dataTerminalReady)) // print value of pin 4 by name
println(toOnOff(plug.ringIndicator)) // print value of pin 9 by name
}</syntaxhighlight>
 
=={{header|Tcl}}==
This Tcl implementation represents the fields as bits in an integer. It provides two functions to get from symbolic pin names to the integer, and vice versa.
<langsyntaxhighlight lang="tcl">set rs232_bits {CD RD TD DTR SG DSR RTS CTS RI}
 
proc rs232_encode args {
Line 953 ⟶ 1,421:
catch $test res
if {$res ne $expected} {puts "$test -> $res, expected $expected"}
}</langsyntaxhighlight>
 
=={{header|Wren}}==
{{libheader|Wren-seq}}
{{libheader|Wren-fmt}}
In Wren instances of user defined data structures ('classes') are always allocated on the heap and (AFAIK) their fields are laid out contiguously and require 8 bytes each. Nums, Bools and Nulls are stored directly and fields of other types store a pointer to their actual storage location.
 
It is not possible to vary this memory layout though, if lack of memory is a problem, one may be able to use bit arithmetic to pack more values into a Num.
 
As far as this task is concerned, below is a possible implementation for a 9-pin RS-232 plug which allows access by pin name or number and provides a comprehensive print out of the current pin state.
<syntaxhighlight lang="wren">import "./seq" for Lst
import "./fmt" for Fmt
 
var ON = true
var OFF = false
 
// Converts "ON"/"OFF" string to true/false.
var AsBool = Fn.new { |s| s == "ON" }
 
class RS232_9 {
static names { ["CD", "RD", "TD", "DTR", "SG", "DSR", "RTS", "CTS", "RI"] }
 
construct new() { _settings = [OFF] * 9 } // all pins OFF
 
// get pin setting as an ON/OFF string by pin name or number; returns null if invalid
[p] {
if (p is String) {
var ix = Lst.indexOf(RS232_9.names, p)
return (ix >= 0 && ix < 9) ? (_settings[ix] ? "ON" : "OFF") : null
}
if (p is Num) {
return (p.isInteger && p >= 1 && p <= 9) ? (_settings[p-1] ? "ON" : "OFF") : null
}
return null
}
 
// set pin by pin name or number; does nothing if invalid
[p] = (v) {
if (v.type == String && (v == "ON" || v == "OFF")) v = AsBool.call(v)
if (v.type != Bool) return
if (p is String) {
var ix = Lst.indexOf(RS232_9.names, p)
if (ix >= 0 && ix < 9) _settings[ix] = v
}
if (p is Num && p.isInteger && p >= 1 && p <= 9) _settings[p-1] = v
}
 
// prints all pin settings
toString { (1..9).map { |i| "%(i) %(Fmt.s(-3, RS232_9.names[i-1])) = %(this[i])" }.join("\n") }
}
 
var plug = RS232_9.new()
plug["CD"] = ON // set pin 1 by name
plug[3] = ON // set pin 3 by number
plug["DSR"] = "ON" // set pin 6 by name and using a string
System.print(plug) // print the state of the pins</syntaxhighlight>
 
{{out}}
<pre>
1 CD = ON
2 RD = OFF
3 TD = ON
4 DTR = OFF
5 SG = OFF
6 DSR = ON
7 RTS = OFF
8 CTS = OFF
9 RI = OFF
</pre>
 
=={{header|XPL0}}==
<syntaxhighlight lang "XPL0">
Assuming RS-232 pin 1 is connected to bit 0 of an I/O port et cetera, the
bits can be assigned names, such as these:
 
def CD=1<<0, RD=1<<1, TD=1<<2, DTR=1<<3, DSR=1<<4, RTS=1<<5, CTS=1<<6, RI=1<<7;
def RS232=$10;
 
The 'port' command can then be used to access these pin signals by name like this:
port(RS232):= TD ! RTS;
if port(RS232) & RD then ...
 
Note: The 'port' command is implemented in the Intel x86 versions but not
in the Raspberry Pi or Windows (EXPL32) versions.
]</syntaxhighlight>
 
=={{header|Z80 Assembly}}==
{{trans|6502 Assembly}}
 
<syntaxhighlight lang="z80">softRS232_LO equ &C000 ;%87654321 (each bit represents the state of a numbered pin)
softRS232_HI equ &C001 ;%-------9
 
ld hl,softRS232_LO ;memory location of soft RS232 port
ld c,&00 ;&00 = the port that the RS232 is connected to.
;This is just an example, the actual port number depends on where the hardware is connected.
 
outi ;send the value contained in softRS232_LO thru port &00
outi ;send the value contained in softRS232_HI thru port &00</syntaxhighlight>
 
 
 
{{omit from|ACL2}}
{{omit from|AWK}}
{{omit from|Batch File|No memory management or data structures.}}
{{omit from|BBC BASIC}}
{{omit from|Clojure}}
{{omit from|E}}
Line 970 ⟶ 1,538:
{{omit from|PARI/GP}}
{{omit from|PlainTeX}}
{{omit from|Processing}}
{{omit from|PureBasic}} <!-- Does not have bit-sized data types. -->
{{omit from|TI-83 BASIC}} {{omit from|TI-89 BASIC}} <!-- Does not have user-defined data structures. -->
9,476

edits