Real-Time between DOS, UNIX, and MVS
As business needs change and evolve, so do the computing
to support them. At our site, we needed to automatically
as they were received via a conveyor system. The problem
the verification had to be performed against a completely
platform: the mainframe. By combining DOS, UNIX and
MVS, we were able
to build a solution.
The application I will discuss here involves weighing
our receivables as they arrive in their fixed-size vendor
Our vendors provide our merchandise in fixed-size boxes
that fit directly
into the racks in our warehouse. To eliminate the need
for our receiving
clerks to open up each box and count each piece, boxes
weighed and scanned once placed on a conveyor belt
(think of this
as the checkout counter process at the supermarket,
but without the
checkout clerk). Since we know the individual weight
of each piece
from our inventory file and we know the tare weight
of the box, we
can calculate the number of pieces in each box from
the total weight.
Once the weight and barcode of each box is collected,
it is transmitted
as an ASCII data string to a DOS-based PC running a
supplied by the scale manufacturer. As the program receives
data string from the scale and scanner it passes it
to a host system.
Then it waits for a response back from the host system.
Once the response
is received, the program then passes that response back
to the scale
system, then waits for the next box. The response that
is passed back
to the scale system is an alpha code indicating one
of three directions
the box will take as it travels down the conveyor belt:
(1) the staging
area where the box will be put away in the warehouse;
(2) the quality
control lane, should the merchandise need visual checking;
the reject lane, should there be something physically
wrong with the
The scale was designed with a DOS "controller"
PC so as to
be generic and thus provide connection with virtually
any host. In
our case, the host is an IBM mainframe ES9121 model
621 running the
MVS/ESA operating system. Our enterprise databases are
Storage Access Method) datasets used by IBM'S CICS (Customer
Control System) command-level programs. This created
problem, since the character set on the mainframe is
Binary-Coded Decimal Interchange Code), as opposed to
ASCII on the
DOS scale PC, and the mainframe is synchronous while
the PC is asynchronous.
In addition, physically connecting the two systems involves
Cluster Controller on the mainframe versus a serial
port on the PC
(see the sidebar "IBM Mainframe Hardware").
Our solution was
to place a SCO UNIX box between the IBM mainframe and
the DOS scale
PC. The SCO box performs the handshaking between the
two systems as
follows: When the ASCII data stream is sent by the DOS
PC, it is first
received by the SCO box. It is then automatically converted
and sent to the mainframe via emulation software. When
responds back, it's the SCO box that receives the response
then forwards it on to the DOS PC, (see Figure 1). In
one sense we
have two hosts doing the work here, but that is all
to the DOS-based scale PC. It couldn't care less --
as long as
it gets a response back from the message it originally
DOS PC Connection
The DOS connection involves an AT-Class PC running MS-DOS
and a proprietary
software program provided by the scale manufacturer.
The PC contains
a multi-port serial card providing four RS-422 serial
As with other system parameters, the individual port
setups for characteristics
such as line speed and protocol are configured and controlled
the scale's proprietary software program. As far as
the physical port
connections are concerned, the first port connects to
a laser barcode
reader, the second port connects to the actual weighing
third port connects to a TTY line on the SCO UNIX box,
and the fourth
port is currently unused. Of interest here is the connection
SCO UNIX box. As barcodes and weights are received from
and two, a data record is formatted and sent out the
port to the SCO
box. We ran that serial line through an RS-422 to RS-232
since our multi-port adapter on the SCO box was RS-232.
is a proprietary software program, all installation,
and setup was performed by the scale manufacturer.
The base UNIX system involves an Austin 486/50 tower
PC with 16Mb
of RAM and twin 500Mb hard disks, an internal tape backup
modem for dial-in support, and an 8-port Megaport multi-serial
adapter. The system runs SCO UNIX System V/386 release
system. To make the connection to the IBM mainframe,
the Cleo 3270LINKix kit, from Cleo Communications of
Ann Arbor, MI.
The kit contains the hardware and software necessary
(except the cable)
for connecting into the IBM.
The Cleo hardware is an ICOT ShortCUT board that installs
in an open
slot in the UNIX system. We used the default settings
I/O address, shared-memory address, and DMA channels
without a problem.
However, each of these settings can be easily reconfigured
switches on the board should we need to change them.
The cable was
a simple twisted pair wire with RJ-11 (telephone style)
on each side. We used a balum on each end to convert
the cable back
to the standard coax BNC-Style connector. One end plugged
BNC connector on the ICOT board and the other plugged
into a BNC connector
port on the IBM 3174 cluster controller. At this point
it was necessary
to get an IBM systems programmer involved to configure
the IBM 3174
port as a "Distributed Function Terminal (DFT)"
the sidebar "IBM Mainframe Hardware"). The
Cleo 3270 software
provides five 3270 terminal sessions over one physical
The Cleo software was easily installed using SCO's sysadmsh
software install option. (sysadmsh actually calls
custom to do the install). Installing was as easy as
the screen prompts from the Cleo install script and
typing in the
default hardware settings mentioned above. Once the
was relinked and the mainframe activated its line, the
box appeared as a remote 3174 Terminal Cluster Controller
We knew we had succeeded when we typed com3270 from
terminal and got the IBM terminal screen!
Making It Work
Once we got all the hardware and system software installed
three platforms we began work on the application, which
centered on a C program that ran on the SCO box. This
written in house and performed the handshaking between
the DOS scale
PC and the IBM mainframe. The program reads data from
the serial line
that is connected to the DOS PC, sends that data to
the IBM mainframe,
waits for a response from the mainframe, and then sends
back to the DOS PC. Some interesting programming issues
in this application, and the program was compiled so
that we could
take advantage of curses the terminal screen handling
provided by SCO. These routines are listed in detail
in the SCO
Programmers Guide and contain a wealth of tools that
screen handling capabilities to any program. Refer to
Figure 2 for
syntax on using curses.
The first programming issue was keyboard polling. As
continuously looped, monitoring the data from the DOS-based
needed a way to cleanly stop the program. In DOS you
can simply call
the kbhit() function to check the status of the keyboard.
If the function returns a true value, it means a key
You can then use the getch() function to fetch the keystroke
(see Listing 1). Unfortunately, the kbhit() function
available in UNIX; however, the same result can be achieved
the powerful UNIX file handling controls. Since the
is a special file (/dev/TTY), we can open it up with
delay" flag. We then perform a read on this file.
Instead of waiting
until data is available, the "no delay" flag
the file, and if there's data, get it; if there's not
any data, don't
wait, continue on." In this way we can monitor
the user's keyboard
and exit the program (or perform any other action) should
a key be
pressed. To achieve exactly what we want, we must set
of the user's terminal. Listing 2 shows the coding fragment.
is an explanation of the code statements:
1. Include termio.h for the necessary
2. Define two structures of type termio.
3. Close the user's terminal keyboard. "0"
represents the file descriptor for the user's terminal.
4. Open the user's terminal with the "no delay"
and "read/write" parameters.
5. Use the I/O control function to read the current
settings into the temporary structure. "0"
open file descriptor for the user's terminal. TCGETA
the control function that gets the parameters; ttyOParms
the address of the receiving data structure.
6. Assign the new structure from the temporary structure.
7. Clear the ICANON and ECHO flags
in c_lflag so the input characters are not assembled
lines before they are read, and there is no character
8. Set the minimum characters to read to 1.
The read will be satisfied after reading a single character.
9. Set the time to 0. Time here is really
irrelevant since we are only reading a single character
VMIN and VTIME must be set if the ICANON flag
is cleared. Otherwise, you may get strange results.
10. Use the I/O control function to reset the user's
terminal keyboard. "0" represents the open
for the user's keyboard: TCSETA selects the control
function to reset the parameters according to the values
11. wgetch is the curses function
to fetch a keystroke if one exists in the user's terminal
buffer. The function returns immediately, regardless
of the result.
The second programming issue was CPU overhead in reading
from the DOS PC. In keyboard polling we want to read
a single character
at a time; however, when reading the data from the DOS
PC, it would
be more efficient to read a block of data at a time
-- in other
words, only satisfy the read request once the entire
message is present.
We can do this with "canonical" processing.
processing, the input characters are assembled into
lines before they
are read. That is, they are terminated with an ASCII
Setting up the TTY line for the DOS PC in canonical
mode also requires
the use of the I/O control function (ioctl). Listing
this code fragment. The following is an explanation
of the code statements:
1. Include termio.h for the necessary definitions.
2. Define structure of type termio.
3. RdChars will be the number of characters
read from port. ImbsPort is the file descriptor for
4. This structure is the buffer where the read characters
5. Open the TTY line connected to the DOS PC with
"no delay, read/write".
6. Use the I/O control function (ioctl) to
get the current setting of the port. ImbsPort represents
open file descriptor for the TTY line connected to the
DOS PC. TCGETA
selects the control function that gets the parameters.
is the address of the receiving data structure.
Four fields in the termio structure are
used to setup line and protocol settings: c_ifflag describes
the basic terminal input control, c_oflag specifies
system treatment of output; c_cflag describes the hardware
control of the terminal; and c_lflag is used by the
discipline to control terminal functions.
7. The line is a local connection with no modem control.
8. Set the character size to 7.
9. Set the stop bits to 2.
10. Turn on canonical processing -- that is, wait
until an ASCII LF character is sent before reading the
port. The message
from the DOS PC terminates each time with the ASCII
This is its "end of transmission" character.
11. Turn off character echo on the TTY line.
12. Do not even echo the new-line character. The
new-line character gets echoed even if echo is turned
therefore, this statement was necessary.
13. Disable start/stop output control because the
DOS PC controlls the data flow.
14. Set the baud rate to 9600.
15. Enable even parity checking.
16. Now use the I/O control function (ioctl)
to reset the TTY line with the new settings. ImbsPort
open file descriptor; TCSETAF is the command to reset
TTY line. TCSETAF is different from TCSETA in that
it first waits for any output on the line to drain,
then it flushes
the TTY line input queue, then it sets the values. We
use it to flush
any garbage characters that might exist on the line.
17. Initialize RdChars to zero.
18. Read a block of data. The read request will be
satisfied when an ASCII LF character is received. ImbsPort
is the open file descriptor of the TTY line connected
to the DOS PC:
&Imbs is the address of the data structure where
will be placed; and sizeof(Imbs) is the size of the
The final programming issue had to do with communication
the mainframe. Once we received the data from the DOS
PC, we had to
forward it on to the mainframe for validation against
databases. This is where the Cleo 3270 product came
into play. In
addition to providing 3270 terminal emulation to the
also provides a way of communicating through what is
know as HLLAPI.
(High Level Language Application Programmer Interface).
an interface used in applications to communicate with
through the 3270 emulation program. In other words,
programs can be
written to automate tasks such as logging on and running
usually require human intervention. Anything that can
be done from
the users 3270 keyboard can be automated through HLLAPI.
an entire article could be dedicated just to the subject
I will discuss only the basics here.
HLLAPI works by first running the 3270 emulation program
(in our case,
we start it running in the background, since we designed
not to need human intervention) and then executing the
HLLAPI communicates with the mainframe by processing
requests made in the application. These functions are
part of the
development kit that comes with the product. In addition,
is compiled and linked with a special include file and
following steps are performed when the application makes
to a HLLAPI function:
1. The application calls a HLLAPI function, passing
it the appropriate parameters.
2. The HLLAPI function is part of the library and
it's the library that interprets and sends the request
to the 3270
3. The 3270 emulation program performs the necessary
mainframe communications, processes the request, and
sends back a
return code indicating the results of that request to
4. The library then sends the return code back to
Refer to Figure 2 for the syntax in compiling and linking
a HLLAPI program.
One other point to mention concerns "presentation
The application program and the mainframe communicate
referred to as the 3270 presentation space, or terminal
is actually a screen buffer of the session to which
the program is
attached. Using the Model 2 (24x80) screen mode, for
example, we have
a presentation space of 24 rows and 80 characters across,
characters. Simply put, we have a single dimension array
of 1920 characters
each time we receive a mainframe screen. HLLAPI functions
act on this
array -- for example, searching for a specific piece
of text. This
is how a communication dialog is formed between the
Our mainframe, like most, uses an online programming
CICS (Customer Information Control System). CICS, in
the COBOL programming language, is the standard way
we write 3270
terminal screen programs for accessing our mainframe
we already had this efficient method for performing
I/O, there was no need to reinvent the wheel. We decided
to take the
following approach: write a CICS program to handle the
I/O, and write a UNIX HLLAPI program to control the
The CICS programming part was handle by the mainframe
staff. The CICS program contains a field on its screen
the data record from UNIX and a field to display the
return code from
the mainframe I/O request. Each time we send data, we
check the return
code field and act accordingly. While the HLLAPI program
developed, the CICS program was also being developed
and tested on
a standalone 3270 terminal. The programmer manually
entered the data
and checked the return code field, as would be done
by the HLLAPI application.
There are three items basic to calling any HLLAPI function.
is to include the structures and function constants
in the source
module(s). The second is to set up the four standard
any HLLAPI function (there are three integers and one
The last is to call the HLLAPI function (refer to Listing
are dozens of HLLAPI functions available for use; however,
relative functions used in the program are discussed
The following are line-by-line explanations of the numbered
of code in Figure 2:
1. Includes the basic structure and function constants.
2. This is the function code of the HLLAPI function
being called. Function codes are constants defined in
3. This is a string of text used for control information
needed by the function; or it can be an empty string
in which the
HLLAPI function will return some data.
4. Usually used to specify the length of HDataString.
It may also be used for return data.
5. Usually contains the return code from the function.
This return codes indicates whether the function was
not. This field can also indicate the screen position
of the cursor.
6. This is the syntax of the HLLAPI function
call. Notice we use "call by reference" when
HLength, and HRetCode arguments to the function.
Having explained the mechanics, I would now like to
put it all together
with the code example in Listing 4. Lines 1 through
18 contain the
main code, lines 19 through 56 contain the functions
called by the
The following are line-by-line explanations of the statements
in Listing 4.
For the sake of simplicity, no return codes are checked
example. In the real world, we would check the return
from the HLLAPI functions and act accordingly. For example,
1 and 2, if host session A was not available, we would
not be able
to log into the mainframe and might display an error
exit the program. We must first log into the mainframe.
Line 1 checks the availability of host session A.
Line 2 connects to host session A.
Lines 3 through 13 use the WaitForMsg() and ReplyWithMsg()
functions to send and wait for text from the mainframe.
The text exists
in the presentation space (terminal screen). The @E
in the character strings is a macro substitution by
HLLAPI to send
the enter key. If the Enter key was not sent, the screen
change. Remember, it's just as if someone was typing
at the keyboard.
The @C in line 12 is the macro substitution for the
Lines 14 through 17 are a basic loop that reads data
from the DOS
PC (explained earlier) and then uses the ReplyWithMsg()
function to send the data to the mainframe. Line 15
does the keyboard
polling explained earlier. Here is where we would want
to check the
keyboard, and if it was pressed, respond accordingly.
uses DiscHostSessA() to disconnect from the
host session. The following lines are the functions
that were called
Lines 19 through 26 constitute the CheckHostSessA()
which returns a TRUE value if host session A is available.
are configured in the 3270 software setup program.)
contains the desired session ID.
Lines 27 through 34 comprise the ConnHostSessA() function.
We must call this function to actually connect to host
A TRUE value is returned if we actually connected.
Lines 35 through 45 present the WaitForMsg() function,
uses two HLLAPI functions. First we copy the presentation
we can access the screen buffer array (Lines 37 through
we search the presentation space looking for the desired
at array element 0 (the beginning of the array). To
more efficient, you would probably code it in some sort
of loop. If
you don't get the text, continue to loop, reading the
space and searching. After a fixed period of time, or
number of loops,
Lines 46 through 56 show the ReplyWithMsg() function,
also uses two HLLAPI functions to send data to the mainframe.
48 through 51 actually send the "message"
(including the Enter
or Clear key, as in our example) and then lines 52 through
a HLLAPI wait function. The wait is important, because
after we send
the Enter, Clear, or some other action key to the host,
we must wait
until the host screen refreshes before continuing. 3270
are half-duplex and when an action key (Enter, Clear,
etc.) is pressed, the terminal keyboard locks until
the screen refreshes.
Lines 57 through 64 show the DiscHostSess() function
disconnects the mainframe session.
A few years ago I remember reading articles that said
the big mainframes
were going away. In fact, one article even said the
dead. People are now finding that the mainframe has
matured over the
past few decades into a machine that already offers
needed for today's transaction-based and client-server
As more and more 'open system' technologies interconnect
mainframe, applications like the one discussed in this
become more and more common.
3270LINKix 3270 User's Guide and HLLAPI Programmer's
Guide. Ann Arbor, MI: Cleo Communications, 1991.
Martin, James. Data Communication Technology.
Englewood Cliffs, NJ: Pretice Hall, 1988. ISBN: 0-13-196643-X.
About the Author
Colt Johnson earned a BS in Mathematics from Liberty
He is currently doing Systems Programming for J. Crew
in Lynchburg, VA in the areas of MVS/ESA, UNIX, and
MS-DOS. Over the
past 13 years he has done extensive systems work in
the areas of PCs,
telecommunications, UNIX, IBM Mainframe, and C programming,
as cross-platform system integration. He can be reached