Important User InformationImportant User Information
Because of the variety of uses for the products described in this
publication, those responsible for the application and use of this control
equipment must satisfy themselves that all necessary steps have been taken
to assure that each application and use meets all performance and safety
requirements, including any applicable laws, regulations, codes and
standards.
The illustrations, charts, sample programs and layout examples shown in
this guide are intended solely for example. Since there are many variables
and requirements associated with any particular installation, Allen-Bradley
does not assume responsibility or liability (to include intellectual property
liability) for actual use based upon the examples shown in this publication.
Allen-Bradley publication SGI-1.1, “Safety Guidelines For The
Application, Installation and Maintenance of Solid State Control”
(available from your local Allen-Bradley office) describes some important
differences between solid-state equipment and electromechanical devices
that should be taken into consideration when applying products such as
those described in this publication.
Reproduction of the contents of this copyrighted publication, in whole or
in part, without written permission of Allen-Bradley Company, Inc. is
prohibited.
Throughout this manual we make notes to alert you to possible injury to
people or damage to equipment under specific circumstances.
WARNING: Tells readers where people may be hurt if
procedures are not followed properly.
CAUTION: Tells readers where machinery may be damaged
or economic loss can occur if procedures are not followed
properly.
Warnings and Cautions:
identify a possible trouble spot
tell what causes the trouble
give the result of improper action
tell the reader how to avoid trouble
Important: We recommend that you frequently back up your application
programs on an appropriate storage medium to avoid possible data loss.
Page 3
Summary of Changes
Preface
Changes to Software
Use this document with revision 1.2 of the host software package for the
IBM PC I/O Scanner. The host software has been updated to use Microsoft
and Borland compilers.
The new information is marked with a vertical black bar in the margin.
Chapter
How Does the Scanner Relate to 1771-I/O 21
Terms 23
I/O Addressing 25
What the Scanner Does 26
Operating Modes 27
Global
Data Paths 28
Scanner Commands 29
Host Watchdog 210
Scanner Watchdog 210
Chapter
Disk Inventory 41
Installing the Borland Version 43
Installing
Writing Your Program 47
Compiling and Linking the Borland C++ 2.0 Version 412
Compiling and Linking the Borland Turbo C++ 1.0 Version 413
Chapter
Overview 71
Data Structure (Packet) 72
Executing a Management Request 73
Autoconfigure and Link Status Information 715
Configuration
Fault and Fault Dependent Group Information Byte 717
Confirmation Status Codes 719
Print or Display Results 720
Chapter
Overview 81
QBT Data Structure (Packet) 82
Queueing a Block Transfer 84
Time
Polling
Confirmation Status Codes 811
Print or Display Results 812
Unsolicited Block Transfer 813
Block Transfer to PLC5's in Adapter Mode 813
Block Transfer to a 1771-DCM 817
This manual describes the operation and use of the IBM PC I/O Scanner
(cat. no. 6008-SI) with the supplied host software driver. After reading this
manual, you should be able to:
install the scanner board in your computer
write a program that runs on your computer to control the scanner for
your application
diagnose and correct most of the problems that might occur.
This manual begins with an introduction to I/O scanner concepts and
proceeds to detailed instructions on how to install and program your
scanner.
We assume that you have experience in system development and
integration and in writing software for the IBM Personal Computer family
or compatibles. We also assume that you have a working knowledge of the
C programming language, including the concepts of structures and
pointers. Prior knowledge of Allen- Bradley 1771 Series I/O products is
helpful but not essential.
Related Publications
Required Hardware
Use this manual with its companion manual, the I/O Concepts Manual.
Refer to the manuals that accompany the 1771 Series I/O modules and
hardware you intend to use with your system.
You need a computer from the IBM Personal Computer series, such as the
PC/AT or PC/XT, or a compatible such as the Allen-Bradley Industrial
Terminal T50, T60, and T35. The scanner board is installed inside the
computer.
The choice of 1771 Series I/O modules depends on your application.
A printer attached to your computer may be helpful but is not required.
1-1
Page 8
Chapter 1
Using This Manual
Required
Software
Source Code
Conventions
You need the MS–DOS operating system, version 3.0 or higher. If you’re
using the Microsoft C version of the scanner driver software, you’ll need a
Microsoft C compiler, version 5.1 or higher (version 6.0 recommended). If
you’re using the Borland C version of our software, you’ll need a Borland
C compiler, Turbo C++ 1.0 or higher (Borland C++ 2.0 recommended).
Source code for library routines and the interrupt handler is available for a
nominal charge. To obtain source code, you must contact Order Services
and request 6008-SIDC software. They will ship you a license agreement.
Return the signed agreement. A-B source code will be supplied on
3.5-inch and 5.25-inch diskettes.
In this manual, this type is used for special names, such as names of files
and C language identifiers.
The hexidecimal equivalent of selected error codes and commands are
given in the header definition files found in appendix A at the back of this
manual.
Numbers in this document are in decimal unless otherwise noted. Binary
numbers are marked with a trailing (binary), and hexadecimal numbers
with a trailing (hex); for example, 11010(binary) = 26 = 1A(hex).
Bits are numbered so that bit 0 is the low-order bit. For example, bit 4 is
four bits left of bit 0 and has a value of 2
4
=16. Following C conventions,
array subscripts start at 0.
1-2
Page 9
I/O Scanner Concepts
Chapter
2
Chapter
Objectives
How Does the Scanner
Relate to 1771-I/O
This chapter explains basic concepts and provides an overview of the
operation of the IBM PC I/O Scanner. After reading this chapter you
should understand:
how we use certain words with special meanings in this manual
how information moves between your program and the outside world
how your program can issue commands to affect operation of the
scanner
how the safety features, called watchdogs, work
The scanner uses the 1771 Remote I/O protocol to communicate with
Allen–Bradley I/O modules. You don’t have to know the specifics of the
protocol to use the scanner with the I/O modules, but you do need to know
a few terms.
The scanner is an Allen–Bradley card that you install in the host computer
(or host). Typical hosts are the IBM PC/AT class (including the
Allen–Bradley T50, T60, and T35 Industrial Terminals and 6121 Industrial
Computer) and the IBM PC/XT class of machines (including the
Allen–Bradley 6120 Industrial Computer).
IBM PC Hardware
Host
Processor
(i.e. 80286)
IBM PC
1771-I/O Protocol
6008-SI
1771-I/O Hardware
1771-AS
or
1771-ASB
or
1771-DCM
1771-I/O Bus
1771-JAB
Universal I/O
Single
Point
I/O
2-1
Page 10
Chapter 2
I/O Scanner Concepts
I/O modules sit in one or more chassis. An I/O chassis is a housing that
holds one adapter and 1, 2, 4, 8, 12, or 16 I/O modules. The adapter is the
communication interface between the scanner and the chassis. The scanner
communicates with the adapter through shielded two–conductor
twisted–pair cable (the “blue hose”). In turn, the adapter monitors and
controls the I/O modules through the backplane of the chassis. You can
connect up to 16 chassis to the scanner on the blue hose. You can combine
chassis in any way that results in 8 or less rack addresses.
Adapter
Industry
Host
Processor
I/O Chassies can contain 8 bit,
16-bit, or 32-bit discrete I/O
modules. Analog, and/or
intelligent I/O modules.
You address them using 1/2 slot,
1-slot or 2-slot addressing
Bus
I/O Chassis
SI Scanner
Remote I/O Cable
I/O Chassis
Adapter
I/O Chassis
Adapter
2-2
I/O Chassis
Adapter
14652
Page 11
Chapter 2
I/O Scanner Concepts
We can divide I/O, and therefore I/O modules, into discrete and intelligent
modules.
Discrete I/O is characterized by one terminal (or point) per I/O image table
bit. Your program handles discrete I/O through I/O image tables, where
each input or output terminal corresponds to one of the 1024 input and
1024 output image table bits (64 x 16 bits = 1024 bits.)
The input image table is an area of memory that monitors the terminals of
discrete input modules. When an input switch is closed, the corresponding
bit is set (1). The output image table is an area of memory that controls
output terminals of output modules. After a bit is set to 1, the
corresponding switch is closed or the terminal is energized.
A standard–density module is a discrete input or output module that has 4,
6, or typically 8 input or output terminals. A high–density module is a
discrete input or output module that has 16 input or output terminals. A
quad–density module is a discrete input or output module that has 32 input
or output terminals.
Terms
Intelligent I/O is characterized by the transmission of one or more 16–bit
words in a particular format to or from an I/O module. A block transfer
(BT) is the transmission of data to or from an intelligent I/O module. A
BT read or read BT transfers information (typically analog input and status
data) from the module to the host; a BT write or write BT transfers data
(typically analog output and configuration data) from the host to the
module.
You should become familiar with these terms used to describe the I/O
subsystem.
Input image table: An area of memory that monitors input terminals of
input modules. When an input switch is closed, its corresponding input bit
is set. 64 16–bit words (1024 points) are available.
Output image table: An area of memory that controls output switches of
output modules. When a bit is set, its corresponding output is energized.
64 16–bit words (1024 points) are available.
Discrete I/O: I/O characterized by one terminal per image table bit
(terminal and point are the same).
Standard density module: Discrete I/O module having four, six, or
typically eight input or output points.
High density module: Discrete I/O module having 16 input or output
points.
2-3
Page 12
Chapter 2
I/O Scanner Concepts
Quad density module: Discrete I/O module having 32 input or output
points.
I/O chassis: One of four different housings sized to hold either four, eight,
twelve, or sixteen discrete I/O modules.
Slot: Position in an I/O chassis the width of one discrete I/O module.
I/O group: An addressing concept representing 16 input bits (one input
image table word) and
16 output bits (one output image table word).
In hardware, an I/O group can represent one or two slots in an I/O chassis.
It has an address number.
Half–slot addressing: Addressing where an I/O group represents a half of
a slot.
One–slot addressing: Addressing where an I/O group represents one slot.
Two–slot addressing: Addressing where an I/O group represents two
slots.
I/O rack number: An addressing concept representing 8 I/O groups. An
I/O rack number can be distributed over one, two, three, or four I/O
chassis; or two rack numbers can be assigned to one I/O chassis, depending
on chassis size and your application requirements.
Module address: An address that defines the physical location of the
module in the I/O chassis by its I/O rack number and starting slot number.
I/O update: The scanner’s serial scan of all I/O chassis in the I/O
subsystem. This scan is asynchronous to scans between the scanner and
host processor.
Scan list: A list specifying the order in which I/O adapters are to be
scanned. It is specified by the host and sent to the scanner module as a
scanner management command. Although a maximum of 16 I/O adapters
is allowed, the scan list can specify a maximum of 64 I/O adapters. This is
done to allow the scanner to scan adapters more than once during its scan
cycle if more frequent updates are desired.
2-4
Block transfer: The transfer of data to or from an intelligent I/O module
up to 64 words at a time.
Scanner management request: A command from the host to the scanner
used to control and configure the scanner board.
Page 13
Chapter 2
I/O Scanner Concepts
Fault dependent group: A group of I/O adapters treated as a single entity
for the purposes of fault detection. If one of the defined group faults all in
the group are in fault.
I/O Addressing
You assign each adapter an I/O rack number (0 to 7) by setting switches on
the adapter. A rack may be single chassis; or two to four chassis may be
comprised in one rack number; or a single chassis can be addressed as two
racks. It is not necessary to assign rack numbers sequentially: for instance,
you could have a full rack 0, half a rack in rack 3, and a quarter rack in
groups 6–7 of rack 7.
For addressing purposes, each rack is equivalent to a block of 8 I/O groups
in the I/O image table. Groups within a rack are numbered from 0 to 7.
An I/O group is two 16–bit words, one from the output image table and
one from the input image table, with the same address. (Please refer to the
I/O Concepts Manual for more information.) In most applications, only
the input word or only the output word is used in any given I/O group.
Here is an example layout of the output image table:
Group
word #
(hex)rack
00-070xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
08-0F1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
10-172xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
18-1F3xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
20-274xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
28-2F5xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
30-376xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
38-3F7xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
01234567
The word numbers above can be used as subscripts. (We’ll look closely at
that in chapter 6, Discrete I/O.) Each 16–bit word corresponds to 16
discrete I/O terminal positions, terminal 17 octal (15 decimal) to the
high–order bit and terminal 00 to the low–order bit.
Just as each I/O group has an address, so does each adapter. Adapter
addresses are used in the scan list (see, What the Scanner Does, below).
The adapter address is the address of the first I/O group covered by the
adapter, divided by 2. This is numerically the same as (rack x 4) +
(starting group / 2), where the rack and group are both numbered from 0 to
7 as shown above. If you prefer, you can think of 1/4 racks being
numbered from 0 to 3, and then the adapter address is (rack x 4) +
(quarter).
2-5
Page 14
Chapter 2
I/O Scanner Concepts
A slot is a position in an I/O chassis for one I/O module. In one–slot or
single–slot addressing, an I/O group represents a single slot. In two–slot or
double–slot addressing, an I/O group represents two slots.
What
the Scanner Does
The scanner runs asynchronously in relation to the host. When either one
wants to get the other’s attention, it must issue a hardware interrupt.
Information is passed through a global RAM. Both the host and the
scanner have the ability to postpone servicing an interrupt if in the middle
of another interrupt–driven task.
The scanner maintains a scan list, which is a list of adapters to be serviced
by the scanner. A given adapter may appear once, several times, or not at
all in the scan list. (The scan list is empty until you perform
AUTOCONFIGURE at which point AUTOCONFIGURE puts every
adapter in the list once.) The scan list starts as simply the list of adapters,
each occurring once, but your program can issue a scanner command to
alter the scan list.)
An exchange (or an adapter scan) is the scanner’s interchange of
information with one adapter. During an exchange, the scanner may
receive data or status information from the adapter or send data or
commands to the adapter, or both. Both block transfers and discrete I/O
transfers can be done during the same exchange if the adapter’s chassis
contains both kinds of I/O modules.
After servicing each adapter, the scanner looks at its command queue to
see if any commands are waiting. If so, and if the current operating mode
allows, the scanner executes one command. If the scanner has a
confirmation of this command or of a previously executed command, it
puts the confirmation in the global RAM and interrupts the host.
2-6
The scan list is circular: each time the scanner reaches the end of the scan
list it starts again at the beginning. An I/O scan (sometimes called just a
scan) is one complete cycle by the scanner through the scan list, from any
point to the same point.
Every time the host interrupts the scanner, the scanner puts a marker in the
scan list at the point of the adapter most recently scanned. If the scanner
works its way through the scan list to the same point without receiving an
interrupt from the host, the scanner interrupts the host. (If the scan list
contains no adapters, the scanner waits for 5 ms before interrupting the
host.)
Page 15
Chapter 2
I/O Scanner Concepts
Thus you can be certain that the I/O image tables are refreshed once per
scan list. Partial refreshes take place more frequently if your program
executes a lot of block transfers or management requests: whenever the
global ram is transferred the I/O image tables are refreshed as far as the
scanner has got in the scan list since the last interrupt. Your program can
also force a partial refresh: see the update function in chapter 6, Discrete
I/O.
Operating
Modes
Global RAM
The scanner has three modes of operation: program, test, and run modes.
Discrete inputs are read in all three modes.
In program mode no discrete outputs are sent to the adapters, and the
adapters are instructed to hold all discrete outputs reset (zero). The
scanner holds any block transfer requests in its queue without servicing
them.
In test mode the adapters are still instructed to hold discrete outputs
reset, but the scanner sends discrete information to them. Block
transfers can proceed in test mode, but their outputs will be held reset.
In run mode discrete output information is sent to the adapters, and the
adapters are permitted to update the output modules. Block transfers
may be performed.
When your program first starts up scanner operation, the scanner is in
program mode. Your program must issue a command to change to run
mode.
The scanner has a 2048–byte area of RAM that we call a global RAM,
shared by both the IBM PC and the scanner. This is not a true global
RAM, because the host and the scanner can’t access it at the same time.
Instead, the host and the scanner exchange control of the global RAM by
means of interrupts. When the scanner interrupts the host, the scanner is
turning over control of the global RAM to the host. When the host
interrupts the scanner, either the host has the global RAM and wants to
return it or the host doesn’t have the global RAM but wants access to it.
Access to the global RAM is ultimately controlled by hardware and by
scanner firmware. For the host side, we supply an interrupt handler or
interrupt service routine that is automatically invoked whenever the
scanner interrupts the host. Our interrupt service routine copies
information as needed between your program’s data area and the global
RAM.
2-7
Page 16
Chapter 2
I/O Scanner Concepts
Because our interrupt handler takes care of all details of the global RAM,
you don’t have to be concerned with the bits and bytes. You should know
that the global RAM contains two kinds of information:
the I/O image tables are comprised of an output image image table and
an input image table. Every time control of the global RAM is
transferred, the interrupt routine copies new inputs to your program’s
data area from the global RAM and new outputs from your program’s
data area to the global RAM.
a mailbox area is where the host can send commands to the scanner and
the scanner sends back confirmations and data. A list of commands is
given later in this chapter.
Data
Paths
Here is the path followed by a discrete input bit:
An external device causes an input of a discrete input module to turn
“on.”
When next asked by the adapter, the input module reports the new input
information. The adapter updates its internal input image table by
setting the bit corresponding to the particular input point.
When next scanned by the scanner, the adapter reports the new input
information. The scanner updates the input image table in the global
RAM by setting the bit corresponding to the particular input point.
The host interrupt handler reads the input image information in the
global RAM and copies it to a duplicate input image table available to
your program. Your program now knows that an input on a particular
input module is “on.”
The path of an output bit is essentially the reverse of the input path:
Your program sets a bit in its output image table. Your program knows
that this bit maps to an output on a particular output module.
2-8
The scanner interrupts the host, the interrupt handler copies your
program’s output image for that rack to the global RAM.
When the scanner next scans the adapter controlling the particular
output module, it tells the adapter to update its output image table with
the new information.
The adapter tells the discrete output module to update its outputs with
the new information.
Page 17
Chapter 2
I/O Scanner Concepts
The discrete output module turns on the output. Any external device
attached to the output module then activates.
For timing information, please see Timing of Discrete I/O in chapter 6,
Discrete I/O.
Scanner Commands
There are two types of scanner commands, block transfers and
management requests. There are two block transfer commands (BT
commands):
block transfer read
block transfer write
A management request affects the operation of the scanner itself. There
are six management requests:
set mode changes the scanner’s operating mode to program, test, or run
mode
autoconfigure goes on the link to see what devices are attached
scan list changes the order in which adapters are scanned, and their
relative frequency
link status asks the scanner to report all information it has about the
adapters that are connected
setup changes the baud rate and connects or disconnects the line
termination resistor
fault dependent group designates one or more groups of adapters such
that, if one adapter in a group is faulted, the scanner instructs the others
to be faulted also
The control/status and general data areas are used to transfer scanner
management commands to the scanner and provide status information to
the host. In addition, this area of the global RAM is used for block
transfers between the host and intelligent I/O devices in the I/O system.
2-9
Page 18
Chapter 2
I/O Scanner Concepts
Host Watchdog
Scanner W
atchdog
Suppose that your program crashes, either because of logic errors or
because of operator intervention. Or suppose that through logic errors
your program gets into an infinite loop. In these cases the program is no
longer sending meaningful information to the scanner through the interrupt
handler. There is no way for the interrupt service routine (ISR) to
recognize all possible host program failures reliably, so instead a “host
watchdog’’ scheme has been implemented.
In essence, your program must take a particular action every so often (by
default, every second). If the ISR recognizes that the required action has
not been taken recently enough, the ISR infers that your program has failed
and simply stops talking to the scanner. The scanner in turn recognizes this
as a host failure and goes off the link within 50 ms; all the adapters go
inactive and output terminals go to last state or reset as determined by
switches you set on the chassis.
We’ll tell you about the necessary programming steps in chapter 5, Startup,
Status, and Shutdown.
If the host computer doesn’t respond to an interrupt from the scanner
within 100 ms or less, the scanner assumes that the host hardware and
BIOS is no longer active. In this case the scanner goes off the link, and 50
ms later the adapters set the output modules in last state or reset according
to your switch settings. The scanner then goes into its power–up sequence,
waiting for new startup commands from the host.
This scanner watchdog feature lets you end one program run and start
another without cycling host power. Even if your program locks up the
host computer, if you are able to do a soft reset (
Ctrl–Alt–Del) the scanner
is ready and waiting for your program. More importantly, if your program
fails or is interrupted, even by a reboot of the computer, all discrete outputs
are in last state or reset, according to the switches you set on the adapters.
2-10
Page 19
Installation
Chapter
3
Chapter
Objectives
Using the Scanner
with Other Products
This chapter explains how to install the IBM PC I/O Scanner. After
reading this chapter you should be able to:
determine whether you already have hardware or software products
installed that would conflict with the scanner
configure the scanner board for a suitable address in your host’s RAM
install the scanner board in the host
connect the 1771 Series I/O cable to the scanner.
In this manual, we do not explain how to cable and configure 1771 Series
I/O products. For that information, please refer to the manuals that came
with those products.
You need to be aware of possible hardware or software conflicts between
other products and the scanner. In this section we point out the hardware
and software features in the scanner that might lead to conflict with other
products, and where possible we tell you how to avoid those conflicts.
However, there are so many add-ons available that we cannot guarantee
that the scanner works with any particular one.
Hardware Interrupt
On the system board, the scanner can use interrupt request lines IRQ3,
IRQ5, IRQ10, and IRQ12. These interrupt request lines are selected by
positioning the jumper located on the scanner board. Results are
unpredictable if any other devices use these lines. In particular, you can’t
have two IBM I/O scanners operating in the same host, since the host
software cannot direct Allen-Bradley I/O calls to a particular scanner
board.
Allen-Bradley products that use the IRQ3 include the 1784-KTP and the
6121-CBB ‘combo’ card (used with the 6120 and 6121 Industrial
Computers).
3-1
Page 20
Chapter 3
Installation
IBM’s Technical Reference Manuals show line IRQ3 used by the
secondary serial port (COM2 device). If you have 2 serial ports active on
your host computer and you have selected IRQ3, you must disable COM2
before installing the scanner board. (Many multi-junction cards have
jumpers to disable this port; see your manufacturer’s documentation for
details.)
CAUTION: If you have other cards that use the interrupt line
you have selected, (IRQ3, IRQ5, IRQ10, or IRQ12), physically
disconnect them to avoid damaging the 6008-SI or other cards.
To change the interrupt request line setting, complete these steps:
1.Remove the cover from the computer that contains the I/O scanner.
2.Remove the I/O scanner from the computer.
3.Remove the four screws securing the daughterboard to the main
board. Unplug and remove the daughterboard.
4.Locate the double row of stake pins on the main board (see
Figure 3.1). A jumper plug connects 2 pins to select the interrupt
request line.
Figure 3.1
Location
of Interrupt Request Line Jumper Plug
Note: Interrupt line designations are
not actually shown on the board.
11
20
Default setting
IRQ3
35
3-2
Page 21
Chapter 3
Installation
5.To change the setting, pull the jumper off the pins and reposition it on
the pins for the interrupt line you desire. See Table 3.A for interrupt
request line definitions.
Table 3.A
Interrupt
Request Line Definitions
Interrupt Line:Explanation:
IRQ3Default setting. Conflicts with COM2 port on machines so equipped.
Conflicts with the KTP card.
IRQ5This setting conflicts with the hard disk controller when the card is
used in an IBMXT or AT clone. This setting would also conflict with
the LPT2 port on machine so equipped.
IRQ10Not available on IBMXT. Not assigned on 1784T50 or IBMAT, but
may conflict with 3rd party boards.
IRQ12Not available on IBMXT. Not assigned on 1784T50 or IBMAT, but
may conflict with 3rd party boards.
6.Write your application software to use the newly selected interrupt
request line setting.
Software Interrupt
The host receives interrupts from the scanner through the selected line
(IRQ3, IRQ5, IRQ10, or IRQ12). Table 3.B lists the software interrupt
vectors.
Table 3.B
Software
Interrupt Line:Software Interrupt Vector:
IRQ30Bh
IRQ50Dh
IRQ10072h
IRQ12074h
Interrupt V
ectors
Results are unpredictable if you have any other hardware that uses
interrupt IRQ3, IRQ5, IRQ10, or IRQ12 (It is likely that the other software
simply ceases functioning while your scanner 0 interface program is
running, but we cannot guarantee that this is the only result).
The scanner driver routines also use the timer follow–on interrupt, number
1Ch. After its own processing, the scanner code will call any previously
set follow–ons to interrupt 1Ch. If the other software is taking too great a
portion of system resources, your scanner application program may not
operate correctly.
3-3
Page 22
Chapter 3
Installation
Despite IBM recommendations to the contrary, some resident software
uses the system timer hardware interrupt, number 8, rather than the
follow-on described in the preceding paragraph. The scanner may work
erratically or may fail to work at all if such programs are active when a
scanner program is started.
I/O Ports
The scanner does not use any I/O ports.
RAM Address
DIP switches on the scanner board let you configure it to any starting
address in RAM, from 0400(hex) to FC00(hex), in increments of
4000(hex) = 16 K bytes. (The scanner cannot be configured to operate in
extended or expanded memory.) The scanner board occupies 1801(hex)
(6K+1) bytes beginning at the address you select. You are responsible for
selecting an address that starts at a free 6K+1 byte range.
The documentation for each of your add-on boards should tell you which
addresses (if any) it uses in system RAM. In addition, we can tell you
about the following common memory uses:
Enhanced Graphics Adapter memory: C000(hex)-C3FF(hex) for the
BIOS, plus an area that could be as large as A000(hex)-BFFF(hex),
depending on the display mode
hard disk BIOS (on the PC XT, not the PC AT):
C800(hex)-CBFF(hex) for the first controller, CC00(hex)-CFFF(hex)
for the second controller if a second one is installed
cartridge ROM reserved area: E000(hex)-EFFF(hex) on some systems
ROM BIOS: F000(hex)-FFFF(hex)
Use the above information, and documentation from the manufacturers of
your add-on boards, to select an area of memory that is available for the
scanner. During the installation process you’ll set switches according to
the memory area you select.
3-4
Page 23
Chapter 3
Installation
Installation
Procedure
The procedure of installing the scanner board in the host has three main
steps:
1.Set the scanner board switch block for the memory address you
selected earlier.
2.Plug the scanner into a slot in the host computer.
3.Connect the I/O cable to the scanner.
In this section we’ll look at those steps in detail.
Switch Settings
The scanner board has one block of ten DIP switches to be set at
installation time.
Figure 3.2
Switch Location on Scanner Board
Dip
Switches
(Close)
on
(Open)
off
Set switches 710 open for PC/XT (6120)
Set switches 710 closed for PC/AT (T50, 6121, 6122)
(photo shows switches set for PC/AT)
Set switches 1-6 set for RAM address.
(photo shows switches set for RAM address C4000)
3-5
Page 24
Chapter 3
Installation
The factory sets the switches for memory address C000(hex) for an IBM
PC AT or other machine with a 16-bit bus. If you’re running on a PC XT
or another 8-bit bus machine, or if you want to configure the scanner at an
address other than C000(hex), you’ll have to change the switches.
First set switches 7 through 10 to all closed for a PC AT or similar, all open
for a PC XT or similar. The factory setting is all closed, for a PC AT or
other machine with a 16-bit bus.
Next set switches 1 through 6 for the memory address you selected.
Table 3.C shows the correct setting of switches 1 through 6, in that order,
for every hex address below F000, where
O is an open switch and c is a
closed switch:
Table 3.C
Dip
Switch Settings for Memory Address (Switches 1 through 6)
Hex
Address
0400Occ ccc5000ccO cOcA000ccc OcO
0800cOc ccc5400OcO cOcA400Occ OcO
0C00OOc ccc5800cOO cOcA800cOc OcO
1000ccO ccc5C00OOO cOcAC00OOc OcO
1400OcO ccc6000ccc OOcB000ccO OcO
1800cOO ccc6400Occ OOcB400OcO OcO
1C00OOO ccc6800cOc OOcB800cOO OcO
2000ccc Occ6C00OOc OOcBC00OOO OcO
2400Occ Occ7000ccO OOcC000ccc cOO
2800cOc Occ7400OcO OOcC400Occ cOO
2C00OOc Occ7800cOO OOcC800
3000ccO Occ7C00OOO OOcCC00OOc cOO
3400OcO Occ8000ccc ccOD000ccO cOO
3800cOO Occ8400Occ ccOD400OcO cOO
3C00OOO Occ8800cOc ccOD800
4000ccc cOc8C00OOc ccODC00OOO cOO
4400Occ cOc9000ccO ccOE000ccc OOO
4800cOc cOc9400OcO ccOE400Occ OOO
4C00OOc cOc9800cOO ccOE800cOc OOO
1
Not available for the IBM PC XT
2
Recommended for IBM PC AT computers with EGA and VGA graphics
Switch
Setting
Hex
Address
9C00OOO ccOEC00OOc OOO
Switch
Setting
Hex
Address
1
cOc cOO
2
cOO cOO
Switch
Setting
3-6
Page 25
Chapter 3
Installation
Plugging in the Board
The scanner board requires two slots. (Any two adjacent slots will do: the
board doesn’t have to be plugged into any particular slot.) The Installation
and Setup manual from IBM, or the corresponding manual from the maker
of your host computer, explains in detail how to install any add-on board.
(See the Internal Option Installation Instructions section in the IBM
manual.)
Host Bus Speed
The scanner is designed to operate on a standard 6 to 8 Mhz IBM AT bus.
Newer 386 PC compatibles operate their busses at faster rates (11 or 12
Mhz) with no wait states. The scanner will not synchronize properly at
these higher rates and will return a 102 error code at the completion of the
setup command. Most of the faster 386 PC compatibles have a setup
screen that allows you to choose the standard IBM AT bus speed. The
standard bus speed must be chosen in order for the scanner to operate
properly.
Attaching the I/O Cable
The 1771 Series I/O cable (the “blue hose”) terminates in a 15-pin female
D-shell connector, and the scanner has a 15-pin male connector accessible
through the rear cover of the host computer. Connect the cable to the
scanner and your installation is complete.
Table 3.D
I/O Cable Connections
1771
Scanner:Cable:Adapter:
pin 8blueterminal 1
pin 7shieldterminal 2
pin 6clearterminal 3
3-7
Page 26
Chapter 3
Installation
Line Termination
Resistor
1
2
3
4
5
6
7
8
9
10
11
12
Figure 3.3
Connecting
1
2
3
4
5
6
7
8
9
10
11
12
1771 I/O Cable in Parallel
Pin 8
Blue
Shield
White
Pin 1
D-shell
Connector
(back view)
Twinaxial Cable
Blue
Shield
White
1
2
3
4
5
6
7
8
9
10
11
12
1
2
3
4
5
6
7
8
9
10
11
12
Swingarm
1771WB
Swingarm
1771WB
Swingarm
1771WB
Note:
• Use the setup command to disconnect the shunt
line termination resistor in the scanner.
• You can connect a maximum of 16 swingarms.
• Use termination resistor on the last swingarm.
Swingarm
1771WB
14864
3-8
Page 27
Chapter 3
Installation
D-shell
Connector
(back view)
Figure 3.4
Connecting
Pin 1
White
Blue
Twinaxial
Cable
Pin 8
1771 I/O Cable in Series
Blue
Shield
Twinaxial
Cable
White
Swing-ArmSwing-Arm
1771-WB1771-WB
Note:
• Use the setup command to disconnect the shunt
line termination resistor in the scanner.
• You can connect a maximum of 16 swingarms.
• Use termination resistor on the last swingarm.
14865
3-9
Page 28
Chapter
Programming Overview
4
Chapter
Objectives
Disk Inventory
This chapter gives you a general overview of the programming process.
After reading this chapter you should be able to:
identify the purpose of every file on your distribution disk
install the software on your hard disk (if you have one)
recognize the special features of source code for a program that
interfaces with the scanner
select names for your variables that won’t conflict with the names in the
programs we supply
select the necessary options to compile and link a scanner interface
program.
The host software is shipped on a single 720K (3.5”) diskette, for use with
Borland and Microsoft compilers. The disk contains an include file
required with all your programs; run–time libraries in the small, compact,
medium, large, and huge memory models; and source and executable code
for the diagnostic program described in chapter 10, User DiagnosticProgram.
The host software package also includes two 360K 5.25-inch diskettes, one
for use with Borland compilers and the other for use with Microsoft
compilers. The combined contents of these two diskettes is identical to the
contents of the 720K diskette.
Table 4.A lists the contents of the host software package.
Table 4.A
Contents
File:Contents:
H_6008SI.Hinclude file
6008SI?M.LIBrun-time libraries compiled with Microsoft C 6.0A
6008SI?B.LIBrun-time libraries compiled with Borland C++ 2.0
U_D1M.EXEuser diagnostic program (Microsoft C version)
U_D1B.EXEuser diagnostic program (Borland C version)
of Host Software Package
4-1
Page 29
Chapter 4
Programming Overview
Table 4.B lists the rest of the files that make up the source code for the user
diagnostic program:
Table 4.B
Code for the User Diagnostic Program
Source
File:Contents:
U_D1.Cmain program
U_D1.Hinclude file for the U_*.C files
U_BT.Csingle block transfers
U_BTC.Ccontinuous block transfers
U_BTM.Cmultiple block transfers
U_DISC.Cfullscreen discrete I/O
U_GET.Ckeyboard handler
U_GROUP.Csinglegroup discrete I/O
U_MR.Cmanagement requests
U_PICK.Cmain menu
We provide the diagnostic program source files so that you have extended
examples of successful programming for the scanner. You should feel free
to experiment by modifying them, though we cannot support any modified
program versions.
Important: All of the files on the diskettes are Copyright
(C)Allen-Bradley Company and may not be distributed or copied (other
than from the distribution disk to your hard-disk or working diskette)
without our permission.
All of the source files are identical between the two diskettes. The
run-time libraries are different and have different names, as explained
below. The executable programs work the same, but contain different code
because they were compiled with different compilers.
If your system is equipped with a hard disk, please read the installation
hints for the Borland or Microsoft version, below. (We provide hints rather
than firm instructions because your hard disk could be organized in many
ways for system development.)
If your system doesn’t have a hard disk, you can write and run scanner
programs using just floppy drives. Please consult your compiler and linker
manuals for instructions on organizing your floppy disks.
4-2
Page 30
Chapter 4
Programming Overview
Installing the Borland Version
This section provides installation suggestions. Feel free to modify this
procedure according to your own configuration.
Important: We recommend that you make backup copies of the
distribution disks and keep the originals in a safe place, away from your
computer and away from stray magnetic fields.
Please make sure that your compiler is installed according to Borland’s
instructions before you follow the procedure below.
If you have a:Then:
3.5inch floppydisk driveWrite protect the supplied 720K diskette (or your backup copy) by
sliding the write-protect tab so that a hole shows through the
diskette casing. Insert the diskette in the floppydisk drive.
5.25inch floppydisk drive Write protect the supplied 360K diskette labeled `Borland C version'
(or your backup copy) by applying a standard adhesive foil
write-protect tab. Insert the diskette in the floppydisk drive.
In the command examples below, we assume you’re using the a: drive, so
please substitute b: if appropriate. We also assume that your hard disk is
drive c: –– again, please substitute another drive letter if appropriate.
There are two main approaches: either copy the scanner’s include file and
libraries into the directories with the compiler–supplied files, or copy the
scanner files into the work directory where you’ll be developing software.
Method 1: Scanner files in same directories as compiler files
1.Change to the root directory for the compiler. If you used Borland’s
default installation, the command will be one of the following:
for Borland C++ 2.0:cd \borlandc
for Turbo C++ 1.0:cd \tc
The command will be different if you performed an installation to a
directory other than Borland’s default.
If you wish, you can print the source files (approximately 35 pages)
by using this command:
4-4
print examples\u_*.?
Page 32
Chapter 4
Programming Overview
Installing the Microsoft
Version
This section provides installation suggestions. Feel free to modify this
procedure according to your own configuration.
We recommend that you make backup copies of the distribution disks and
keep the originals in a safe place, away from your computer and away
from stray magnetic fields.
Please make sure that your compiler is installed according to Microsoft’s
instructions before you follow the procedure below.
If you have a:Then:
3.5inch floppydisk driveWrite protect the supplied 720K diskette (or your backup copy) by
sliding the write-protect tab so that a hole shows through the
diskette casing. Insert the diskette in your diskette drive.
5.25inch floppydisk drive Write protect the supplied 360K diskette labeled `Microsoft C
version' (or your backup copy) by applying a standard adhesive foil
write-protect tab. Insert the diskette in your diskette drive.
In the command examples below, we assume you’re using the a: drive, so
please substitute b: if appropriate. We also assume that your hard disk is
drive c: –– again, please substitute another drive letter if appropriate.
There are two main approaches: either copy the scanner’s include file and
libraries into the directories with the compiler–supplied files, or copy the
scanner files into the work directory where you’ll be developing software.
Method 1: Scanner files in same directories as compiler files
1.Change to the root directory for the compiler. If you used Microsoft’s
default installation of C 6.00, the command is:
for Microsoft C 6.0:cd \c600
If you have an earlier version of Microsoft C, or installed Microsoft
C 6.0 to a non–default directory, the proper cd command depends on
the directory you chose when you installed the compiler.
If you wish, you can print the source files (approximately 35 pages)
by using this command:
4-6
print examples\u_*.?
Page 34
Chapter 4
Programming Overview
Writing Your Program
In chapters 5 through 9, we’ll explain the details of writing application
programs to communicate with the scanner. But first we’ll give you a
bird’s-eye view.
Header Files
Every source program must contain these two lines:
#include <stdio.h>
#include <H_6008SI.H>
STDIO.H is the standard header file supplied with your compiler.
H_6008SI.H is supplied on your scanner driver disk and defines constants,
variables, and functions that your program needs.
Your program may need other header files in addition to these two. If so,
you can add #include lines before or after the reference to H_6008SI.H.
However, H_6008SI.H must come later in your source file than STDIO.H.
Program Skeleton
Before making reference to any other routines in the scanner driver library,
your program must call either setup_6008 or start_6008 as described in
chapter 5, Startup.
After the last reference to other library routines, but before exiting, you
must call the stop_6008 function; please see the “Shutdown” section of
chapter 5. If your program crashes or exits normally without calling
stop_6008, you may have to reset the host computer (
Ctrl-Alt-Del or
cycle power) to continue operating.
Between the startup and shutdown calls, your program must use the
host_active macro to tell the scanner that your program is still active.
By default, your program must do this at least once a second, but you can
change the interval through programming. For full discussion of safety
issues and programming, please see chapter 5, Host Watchdog.
}
. . .
/* application logic here, including calls to host_active( )
*/
. . .
stop_6008( );
}
printf(“setup failed: command=%s status=%s\n”,
xlat_cmd(status), xlat_conf(pkt.qmr_stat));
if ( status != C_AUTOCONF && status != C_SETUP )
printf(“scanner fatal error %d\n”, fatal_6008(
abort( );
As explained in chapter 5, if setup fails the setup_6008 function returns
the number of the failed command and leaves the specific error status in
the packet. The sample above above uses xlat routines, described in
chapters 7 and 9, to display the meanings of the codes in plain English.
Once the setup procedure has succeeded, the scanner and host are talking
and your program can proceed. Your program must call host_active as
explained above.
4-8
Also, your program should periodically monitor global variable
g_act_scnr to make sure that communications are still active. (Refer to
chapter 5, Scanner Status, for complete information on g_act_scnr and
other scanner monitoring features.)
Page 36
Chapter 4
Programming Overview
Defined Constants
In their appropriate places in this manual we’ll tell you about various
constants defined in the header file H_6008SI.H. There are three
constants that are not used by our routines but are defined for your
convenience, and we’ll list them now:
MAXGROUP is the maximum number of module groups, 64. Groups
in the I/O image tables are therefore numbered from 0 to
MAXGROUP-1.
MAXMOD is the maximum number of modules or slots, 132.
MAXADAPT is not the maximum number of adapters (which is 16) but
the number of possible adapter addresses, 32. (An adapter address is the
same as a quarter-rack address, 8 x rack +group / 2.) For instance, when
specifying fault dependent groups (chapter 7, “Scanner Management”)
you’ll give MAXADAPT group numbers to account for everywhere an
adapter might be addressed.
Defined Type Bool
It’s convenient to think of several variables and function values as
Boolean: that is, their value can be only true or false. We define the type
Bool for such values. Bool is equivalent to int, but use of a specially
defined type provides better program documentation.
We also define the two Bool constants OK and NOT_OK, equivalent to 0
and 1 respectively. This definition reflects the C language convention that
0 indicates no error and a nonzero value indicates an error.
Several library routines return status of OK or NOT_OK, and you can also
use those constants in your program. An example is presented in the user
diagnostic program source code, which we explain next.
Extended Example
Your distribution disk contains a complete sample program that exercises
all aspects of the scanner operation through commands you enter from the
keyboard. (Chapter 10, “User Diagnostic Program,” is a user’s guide for
the U_D1 program.)
Please take a minute to look at the source code for the main module,
U_D1.C. The program includes header files STDIO.H and H_6008SI.H
indirectly, through header file U_D1.H.
4-9
Page 37
Chapter 4
Programming Overview
The main program displays identification on the screen and then calls
options (in the same source file) to read and interpret command line
options.
Next the main program calls init (also in the U_D1.C source file). In turn,
init calls setup_6008 and checks for status. If the setup was unsuccessful,
init displays a message and abort execution rather than returning to main.
If setup succeeded, init returns control to main. The main program then
goes into a loop that monitors the scanner activity code g_act_scnr and
calls pick (in source file U_PICK.C) to get a command from the
keyboard.When you enter a command to quit the program, pick returns a
status of NOT_OK to the main program, which terminates the main
program loop. The main program then calls stop_6008 and exits.
You’ll notice that we declare init and options as Bool type functions:
they’ll be returning a value of OK or NOT_OK. pick is declared Bool (in
the header file U_D1.H.) We also have a Bool variable called status that
we use as an “OK to proceed” sentinel. As soon as status takes on a value
of NOT_OK the remaining code is bypassed until the stop_6008
shutdown call.
You may also notice what looks like a violation of the rule we stated
earlier, that setup_6008 or start_6008 must precede calls to any other
routines in our library, and that no calls can follow stop_6008. Actually,
we oversimplified that rule when we stated it. The true rule is that
setup_6008 or start_6008 must be the first call that interacts with the
scanner and stop_6008 must be the last. But it’s OK to call any of the
following routines before startup or after shutdown: sysdate, systime,sysstamp, pr_array, pr_globl (though some values displayed may not be
meaningful), xlat_cfg, xlat_cmd, xlat_conf, xlat_flt, xlat_opst.
Avoiding Compile Time Name Conflicts
When you write your program, you need to make sure that the variable
names you pick don’t conflict with the variable names in our library or
your compiler’s library. This section and the next tell you how to avoid
conflicts with our names; please consult your compiler manual for hints on
avoiding conflict with its names.
4-10
Page 38
Chapter 4
Programming Overview
File H_6008SI.H defines constants according to a logical pattern. The
first few letters of each constant’s name tells you how it’s used, as follows:
Constant:Definition:
C_scanner commands (listed in chapter 7, Executing a Management Request, and
chapter 8, Queueing a Block Transfer)
CM_
SC_confirmation status values (listed in chapters 7 and 8, Confirmation Status Codes)
SF_fault status bits and values (listed in chapter 7, Autoconfigure and Link Status
SL_link (adapter) configuration status bits and values (listed in chapter 7, Autoconfigure
SO_operating status bits (listed in chapter 5, Scanner Status)
MAX
scanner operating modes (program, test, and run; listed in chapter 7)
Information)
and Link Status Information)
user program limits (listed above, in Defined Constants)
C compilers treat capitals and lower case differently, so it’s OK to select
names that begin with c_, cm_, and so on. But stay away from local or
global variable names beginning with any of the above character sequences
in capitals.
Avoiding Link Time Errors
You eventually link one of our supplied libraries with your program.
Please plan now to avoid naming conflicts. (You need to be concerned
only with the names of your functions and extern variables. Your static,auto, and register variable names can’t conflict with ours.)
Link time name conflicts could show up in two ways. The linker could
refuse to create an executable program. But most likely the link would
proceed with no indication of anything wrong, and your routine would be
linked in and exclude our routine (or the compiler’s library routine) of the
same name. Then your program would crash (or give wrong results) when
one of our routines called your routine instead of the “standard” routine.
Bugs like these can be hard to uncover, so it’s best to avoid them in the
first place. Borland’s TLINK linker offers the /d option to diagnose this
sort of problem. We recommend you use the /d option if you’re using
Borland’s Turbo C++ or Borland C++ to develop your application.
In this manual you’ll see the names of almost all the functions in the
libraries we supply, and naturally you should not use any of those names
for your own code. In addition, the libraries have a few internal support
routines whose names begin with io_ or IO_, and you should avoid those
names also.
4-11
Page 39
Chapter 4
Programming Overview
Names of global variables in our libraries begin with g_. In addition, the
libraries contain a number of undocumented internal global variables
whose names begin with _q.
In summary, you can create conflicts with names in our libraries by naming
functions and extern variables beginning with g_, _q, io_, or IO_. To be
safe, stay away from those names and from the names of functions
documented in this manual.
Compiling and Linking the
Borland C++ 2.0 Version
These notes present a simple way of compiling and linking your
application program with the scanner code. This way may or may not be
the best way for your development. There are many alternatives –
Borland’s Integrated Development Environment, make files and project
files, and so on. You should evaluate the alternatives and decide which
way is most productive for you.
Decide which memory model you will use (small, compact, medium, large,
or huge). Please see the discussion of memory models in your compiler
manual. In the command below, replace %%%% with the first letter of the
memory model, in lower case.
Use this command to compile and link your program in one step:
Important: –lcd upper/lower case is significant in public names; diagnose
duplicate names in libraries.
The options we recommend are listed in Table 4.C.
Table 4.C
Options
for Compile and Link
4-12
Options:Description:
-Nstack checking turned on
-Kdefault 'char' is 'unsigned char'
-wshow warnings at compile time
-mselect memory model
-Oturn off optimization
-dset up for debugging
-vlink with debugging information
We recommend against the –a option (align structure members by word).
Our library routines were compiled without it, and may not be compatible
with code you compile with that option.
Page 40
Chapter 4
Programming Overview
For information on selecting or excluding the 8087 or 80287 math
coprocessor, please see the Borland manual sections on the –f options.
Our libraries are compatible with any –f option because they contain no
floating-point operations.
Example 1: Your program is called APPLIC.C. You have selected the
small (s) memory model. The combined command to compile and link
would be
BCC
–N –K –w –ms –lcd applic.c 6008sisb.lib
Borland C++ will compile applic.c as applic.obj and link it as applic.exe.
Example 2: If your program is in several source modules, you can list
them on the command line. If you have chosen medium model, the
command is
The three source files will be compiled and linked as CONTROL.EXE.
Example 3: You have many source files –– U_D1.C, U_BT.C, and so on
–– to be compiled and linked in a program called U_D1B.EXE. Header
files are not in the same directory as source code, but are in directory
c:\dev\hdr. The following command will compile and link in small model.
Compiling and Linking the
Microsoft C 5.1 or 6.0 Version
These notes present a simple way of compiling and linking your
application program with the scanner code. This way may or may not be
the best way for your development. There are many alternatives –
Microsoft’s Programmer’s Workbench, make files, and so on. You should
evaluate the alternatives and decide which way is most productive for you.
Decide which memory model you will use (small, compact, medium, large,
or huge). Please see the discussion of memory models in your compiler
manual. In the command below, replace %%%% with the first letter of the
memory model, in upper case.
Use this command to compile and link your program in one step:
CL /J /A%%%% /W3 yourprogname.c /link 6008si%%%%m
The options we recommend are listed in Table 4.D.
Table 4.D
Options
for Compile and Link
Options:Description:
/Jdefault 'char' is 'unsigned char'
/Aselect memory model
/W3show warnings at compile time
/linkselect scanner library
/Odturn off optimization
/Ziset up for CodeView debugging
4-14
We recommend against the /Zp option (pack structure members). Our
library routines were compiled without it, and may not be compatible with
code you compile with that option.
For information on selecting or excluding the 8087 or 80287 math
coprocessor, please see the Microsoft manual sections on the /FP options.
Our libraries are compatible with any /FP option because they contain no
floating–point operations.
Example 1: Your program is called APPLIC.C. You have selected the
small (S) memory model. The combined command to compile and link
would be
CL /J /AS /W3 applic.c /link 6008sism
Microsoft C will compile applic.c as applic.obj and link it as applic.exe.
Page 42
Chapter 4
Programming Overview
Example 2: If your program is in several source modules, you can list
them on the command line. If you have chosen medium model, the
command is
CL /J /AM /W3 applic.c /link 6008simm
The three source files will be compiled and linked as CONTROL.EXE.
Example 3: You have many source files –– U_D1.C, U_BT.C, and so on
–– to be compiled and linked in a program called U_D1M.EXE. Header
files are not in the same directory as source code, but are in directory
c:\dev\hdr. The following command will compile and link in small model.
This is quite similar to the command we used to create the U_D1M
program on your distribution disk.
The next few chapters of this manual explain programming features:
Chapter 5, Startup, Status, and Shutdown, explains features that must be
in every scanner interface program, including how to start and stop
scanner operation, status monitoring, and the host watchdog.
Chapter 6, Discrete I/O, explains how to read single-point inputs and
write outputs.
Chapter 7, Scanner Management, explains how to issue management
requests that modify the operation of the scanner.
Chapter 8, Block Transfer, explains how to read data from, and write
data to, intelligent I/O modules.
Chapter 9, General Support Features, explains how to write timing
loops, time-stamp a file or printout, and translate a numeric scanner
command to English.
4-15
Page 43
Chapter 4
Programming Overview
The last two chapters are concerned with diagnostics:
Chapter 10, User Diagnostic Program, tells you how to use the
diagnostic program that we included on your distribution disks.
Chapter 11, Troubleshooting, has some questions and answers to help
you in diagnosing problems.
4-16
Page 44
Chapter
5
Startup, Status, and Shutdown
Chapter
Overview
Objectives
This chapter explains features that must be in every scanner program.
After reading this chapter, you should be able to write code that:
tells the scanner to start operation
lets the scanner know that your program is still active (the host
watchdog)
makes sure that the scanner is still active
checks the current operating status of the scanner
shuts down scanner operation in a way that leaves the scanner ready for
when your program runs again.
Every application begins with a call to setup_6008 or start_6008. Every
application makes one or more calls to host_active to satisfy the host
watchdog. Applications should check global variable g_act_scnr
periodically to make sure that the scanner is still active, though this is not
enforced. If your program finds from g_act_scnr that the scanner is no
longer active, you can call fatal_6008 to find out why. Finally, every
application must call stop_6008 before exiting.
CAUTION: If you are running a real-time control program,
screen dumps
communication with the host computer. Adapters on the I/O
link go to Last State or Reset, depending on their switch
settings. You must restart your system to re-establish
communication.
[Shift-PrtSc] cause the scanner to lose
5-1
Page 45
Chapter 5
Startup, Status, and Shutdown
Startup
In this section we’ll look at two functions that start the scanner and the
host talking to each other: start_6008 and setup_6008. Every application
uses one or the other, but not both. For most applications we recommend
setup_6008, which does more and is easier to use than start_6008.
Common Features
Both routines start the host watchdog, which your program must service
regularly. See chapter 5, ”Host Watchdog”, for more information.
Both routines also load the global variables g_ver_scnr and g_ver_host,
which are strings identifying the release of the scanner firmware and of the
host software driver. The scanner firmware version string g_ver_scnr is
no more than 39 characters long (38 plus the terminating zero byte), and
the host version string is 69 characters long (68 plus the zero byte). Your
program should display these strings so, that in case of trouble, you have
the information to give to A-B Technical Service.
setup_6008
setup_6008 initializes the interrupt handler and the global variables,
establishes communication with the scanner in program mode, and does
the initial baud and resistor setup (if required) and initial autoconfigure.
(For the meaning of autoconfigure, please see that section in chapter 7,
Scanner Management.)
Note: In the management request C_SETUP command, -1 indicates no
change.
Calling sequence:
status = setup_6008(baud, resistor
, ir
q_l, segment, &packet);
Arguments:
baud: an integer representing the baud rate multiplier applied to the
board’s base rate of 57.6 Kbaud. At present only 1 and 2 are legal, for
57.6 and 115.2 Kbaud; or use -1 which means the default, 57.6 Kbaud.
resistor: an integer whose value is 1 if the line termination resistor is
connected and 0 if not; -1 means the default, resistor connected.
irq_l: an integer whose value is 3, 5, 10, or 12, depending on the
hardware interrupt line desired; -1 means the default, IRQ3, is selected.
segment: an unsigned representing the segment or paragraph address
of the global RAM. (Drop the final zero from the actual address to
obtain the paragraph address, which is the argument to this routine.) A
5-2
Page 46
Chapter 5
Startup, Status, and Shutdown
value of 0 for this argument defaults to the factory-selected paragraph
address of C000h. Switches on the board are set to determine the global
RAM’s address in the host’s memory space, as explained in chapter 3,
Installation.
packet: a QMR packet, (see chapter 7, Scanner Management) into
which setup_6008 returns the autoconfigure information, or status in
case of error. Note that the argument is a pointer to the packet.
Returned values:
status: an integer: SC_OK 0(hex) if the setup proceeded without error,
C_AUTOCONF 10(hex) if the initial autoconfigure failed, C_SETUP
13(hex) if the setup call (changing baud rate or resistor) failed; any
other value means that the initial sync with the scanner failed.
If the returned value is SC_OK, your program’s packet contains the
information regularly returned by an autoconfigure.
If the returned value is anything but SC_OK, the specific nature of the
error is in the qmr_stat field of the packet that you passed to
setup_6008. Your program should display status information and abort
immediately.
Here’s the start of a sample program, showing a call to setup_6008 and
associated checks for error:
#include <stdio.h>
#include <h_6008si.h>
void main( )
{
QMR pkt;
int status;
. . .
status = setup_6008(-1, -1, -1, 0xC400, &pkt);
if ( status != OK ) {
The declaration, QMR pkt, is explained in chapter 7, Data Structure.
5-3
Page 47
Chapter 5
Startup, Status, and Shutdown
Look at the call to setup_6008. The first two arguments select the default
baud rate (57.6 Kbaud) and resistor setting (connected). The next two
arguments give the default interrupt request line setting (IRQ3) and the
paragraph address of the scanner, C400 (hex), which corresponds to C400
in the table in chapter 3, Installation. The fifth argument points to the
packet, which contains autoconfigure information if setup was successful
and an error code if it was not.
Next we test the status returned by setup_6008. If it’s not equal to OK (or
SC_OK; the two constants have the same value), we have a problem. In
this case the status is the number of the command that failed, and we
display a message using the translation routines described in chapter 9,
General Support Features, and chapter 7, Scanner Management. If the
status is neither C_AUTOCONF not C_SETUP, the host was unable to
establish communication with the scanner and the fatal_6008 routine gives
a code for the reason. If we couldn’t complete the setup operations, we
abort execution of the program.
NOTE: A common error returned from the fatal_6008 function is error
code 102. This usually means the RAM address set with the dip switches
on the scanner does not agree with the address argument in the setup_6008
function. Code 102 can also mean an addressing conflict with other
hardware in your PC. For most PC’s D800(hex) is usually free. Also
make sure the bus speed of your PC is not running faster than 8 Mhz.
If the setup operation did succeed, the host and the scanner are now talking
and your application program can proceed. In this example, we use
mr_print to display the initial configuration information.
The scanner is in program mode upon startup, and you’ll probably want to
change to run mode. For that procedure, see Set Operating Mode in
chapter 7, Scanner Management.
5-4
Page 48
Chapter 5
Startup, Status, and Shutdown
start_6008
This function does a partial setup. Your program would call this function
rather than setup_6008 only when for some reason you want to
synchronize with the scanner but not set the baud rate and resistor and not
do an initial autoconfigure.
Calling sequence:
status = start_6008(irq_l,segment);
Arguments:
irq_l: same as under setup_6008 above.
segment: same as for setup_6008 above.
Returned values:
status: SC_OK 0(hex) if the sync proceeded without error,
SC_PENDING FF(hex) if the sync timed out, SC_NOT_OK 01(hex) if
the segment argument was illegal, SC_BAD_REQ 10(hex) if the
scanner had already been synchronized earlier in this execution,
SC_BAD_VERSN FE(hex) if the scanner firmware series didn’t match
the host, or a confirmation error status returned from the scanner.
If the returned status is anything but SC_OK, your program should
display the status value and the value of function fatal_6008, then abort
execution.
5-5
Page 49
Chapter 5
Startup, Status, and Shutdown
Host Watchdog
Please refer to the Host Watchdog section in chapter 2, I/O Scanner
Concepts. That section explained the general concepts, this section
explains the specific programming steps.
host_active
This macro sets the host watchdog to a user- specified interval or to the
default.
By default, your program must call the host_active macro at least once a
second (18 units of 55 ms). You can select a different interval in any
host_active call, to be effective for that call only.
Calling sequence:
host_active(interval);
Arguments:
interval: a positive integer specifying the interval, zero to select the
default interval, or a negative value to disable the watchdog. Please see
the discussion below.
Returned values:
none.
g_act_host
When you call host_active, the specified positive number (or 18 if the
actual argument is zero) is placed in the global variable g_act_host.
Then every 55 ms the timer interrupt counts g_act_host down a notch.
When the scanner interrupts the host, the interrupt handler checks
g_act_host and if it’s negative the interrupt handler infers that the host
program is not active. The scanner goes off the link within 50 ms, all
adapters go inactive, and output terminals go to last state or reset. So your
program could bypass the host_active macro and just update g_act_host,
but the macro provides convenient program documentation.
You can disable the host watchdog by a one-time call to host_active with a
negative argument (which stores 0 in g_act_host). This may be
appropriate for strictly monitoring applications, but it’s almost certainly a
bad idea for control applications. You should be aware that disabling the
watchdog overrides the last state or reset switches and effectively sets all
discrete outputs at last state in case of a program failure.
5-6
Page 50
Chapter 5
Startup, Status, and Shutdown
Scanner
Status
This section tells you about three ways your program can monitor the
status of the scanner:
Global variable g_op_stat contains status bits that tell you the current
scanner operating mode and fault conditions. You can use the function
xlat_opst to convert the status bits to English.
Global variable g_act_scnr is positive as long as the scanner is still in
communication with the host.
Function fatal_6008 returns a code to describe the nature of the scanner
shutdown after it is no longer communicating with the host.
g_op_stat
At any time after the initial call to setup_6008 or start_6008, your
program can monitor the unsigned variable g_op_stat. This variable is a
set of bit fields, and you can test for a particular condition by ANDing a
symbolic constant with g_op_stat.
For instance, SO_FAULT is the symbolic name of the bit field that is true
(nonzero) when any adapters are faulted. To find out if any adapters are
faulted, your program would use this statement:
if ( SO_FAULT & g_op_stat )
else
/* one or more adapters are faulted */
/* no adapters are faulted */
5-7
Page 51
Chapter 5
Startup, Status, and Shutdown
Table 5.A lists all of the bit fields in the global variable g_op_stat:
Table 5.A
g_op_stat
Bit Field:Hex Value:Description:
SO_RUN 04 (hex)The scanner is in run mode.
SO_PROGRAM 01 (hex)The scanner is in program mode.
SO_TEST 02 (hex)The scanner is in test mode.
SO_DEBUG 08 (hex)The scanner is in debugging mode (scanner watchdog disabled).
SO_BT_PEND 20 (hex)One or more block transfers are pending in the scanner's queue.
SO_FAULT 40 (hex)One or more adapters are in fault state.
SO_CHG_FLT 80 (hex)The fault state of one or more adapters has changed. (This bit
SO_OIT_ERR 10 (hex)If set, this bit indicates that your program has written one or more
bit field descriptions
For more on the scanner watchdog, see chapter 2., Scanner
Watchdog. For debugging mode, see chapter 7, Setup.
must be reset by your program; the driver never resets it.)
valid module control bytes to the output image table, causing one
or more unsolicited block transfers. (Once set on, this bit remains
on until the user program resets it.) Please see chapter 8,
Unsolicited Block Transfer, for more information.
As mentioned previously, the SO_CHG_FLT and SO_OIT_ERR bits are
set by the driver but can only be reset by your program. Periodically,
probably once per program scan, your program should monitor these bits.
If the fault-change bit, SO_CHG_FLT, is set, your program should then
check SO_FAULT to determine the nature of the change. If the fault bit is
not set, the nature of the fault change was that the last faulted adapter came
back on line. But if the fault bit is set, your program should probably
execute a link status command (see chapter 7, Autoconfigure and LinkStatus Information) to check which adapters are faulted. Here’s some
sample code, to be executed once per program scan:
if ( SO_CHG_FLT & g_op_stat ) {
g_op_stat &= ~SO_CHG_FLT;
if ( SO_FAULT & g_op_stat ) {
mr_wait(C_LINKSTAT, &link_pkt);
/* code to examine adapter status goes here */
}
}
In the first line of this example we test whether the fault state of any
adapters has changed; if so, we reset the fault-change bit. In the third line
we test the fault bit, and if any adapters are faulted we execute a link status
call to find out which ones. After the link status call, you would put code
to test the fault bits for each adapter, as explained in chapter 7,
Autoconfigure and Link Status Information.
For testing and resetting the SO_OIT_ERR bit (output image table
programming error), please see chapter 8, Unsolicited Block Transfer.
5-8
Page 52
Chapter 5
Startup, Status, and Shutdown
xlat_opst
This function translates the operating status bits in g_op_stat to English.
Calling sequence:
explan = xlat_opst( );
Arguments:
None, since the operating status is a global variable.
Returned values:
a character pointer whose object is a string suitable for printing. The
string length does not exceed 80 characters (79 plus the terminating zero
byte).
Note that xlat_opst has an internal string buffer and returns a pointer to
that buffer. Calling xlat_opst destroys the previous contents of the buffer.
This means that you must use the string returned by this routine before you
call the routine again.
Here’s a typical use of this routine:
printf(“status: %s\n”, xlat_opst( ));
5-9
Page 53
Chapter 5
Startup, Status, and Shutdown
g_act_scnr
This sentinel word (type integer) lets your program check periodically that
the scanner is still talking with the host. Here’s how it works.
This word is decremented once every 55ms; on the other hand, the
interrupt handler resets the value to 12 every time an interrupt from the
scanner is processed. Thus g_act_scnr goes negative about 1/3 of a
second (12K x 55ms) after the scanner last talks to the host.
Your program should poll for scanner failure by executing code similar to
the following once per program scan:
The fatal_6008 and stop_6008 functions are explained later in this chapter.
Note that g_act_scnr goes on decrementing even after the scanner stops
talking to the host, so that it flips from negative to positive about half an
hour later.
5-10
Page 54
Chapter 5
Startup, Status, and Shutdown
fatal_6008
This function obtains the scanner shutdown code, if available. Your
program should call this function, and display its result, whenever
g_act_scnr goes negative.
Calling sequence:
code = fatal_6008( );
Arguments:
none.
Returned values:
unsigned: 0 if the scanner is currently active, 1 if the scanner is inactive
but the function can’t obtain the actual code because the host doesn’t
have access to the global RAM (or because the scanner left no shutdown
code), or a value greater than 1 if the error code is obtainable.
If the global variable g_act_scnr is negative, either after a failed
setup_6008 or start_6008 or at any other time during execution,
fatal_6008 may return a meaningful error code. In that case, your
program should display the function value.
You should know about two special values that might be returned by
fatal_6008:
101 means that the interrupt handler let the scanner shut down
because your program hadn’t called host_active recently enough.
For more on this feature, please see chapter 5, ”Host Watchdog”.
102 means that your application program shut down interrupts
properly through the stop_6008 function, as described later in this
chapter. This code usually means that one of the setup parameters
in the SETUP command did not match the physical hardware
setting of the scanner. Recheck the scanner’s memory and
interrupt configuration.
CAUTION: If you ever get an error code other than 0, 101,
and 102 from fatal_6008, please call A-B immediately, because
a hardware or firmware problem with the scanner may have
occurred.
5-11
Page 55
Chapter 5
Startup, Status, and Shutdown
Shutdown
Why is shutdown required?
Your application program must shut down the scanner properly before
exiting back to DOS. There are two reasons to do this:
An orderly shutdown puts all output modules into last state or reset,
according to the switches set on the I/O chassis. This would happen
without an orderly shutdown, but would take about 100ms longer.
When your program issued the original call to setup_6008 or
start_6008, the driver routines altered the DOS interrupt vectors to
point to library routines linked in your executable file. The shutdown
routine resets those interrupt vectors. If your program exits without
resetting the interrupt vectors, and you then try to run a program that
overlays the area pointed to by the altered interrupt vectors, the host
computer may lock up or behave erratically, requiring a hard reset or
cycling power before you can use it again.
stop_6008
This function de-installs the scanner interrupt code. If a setup_6008 or
start_6008 function has once been executed successfully, your program
must call this function before exiting.
Calling sequence:
stop_6008( );
Arguments:
none.
Returned values:
none.
Your program can omit the stop_6008 call only if the initial setup_6008 or
start_6008 call failed. However, an extra stop_6008 call does no harm,
even where it’s not needed.
5-12
Page 56
Discrete I/O
Chapter
6
Chapter
Objectives
Direct Image
T
able Access
This chapter explains how to use the functions contained in the host
software library to do discrete I/O. After reading this chapter, you should
be able to:
examine any discrete inputs
set or clear any discrete outputs
examine any outputs that you set or cleared previously.
You should be able to do all three of these either directly, by subscripting
into the I/O image tables, or indirectly, by using the supplied library
routines.
The output and input image tables are two unsigned integer arrays of 64
words each, named g_oit and g_ipt respectively. You can directly read
either table using C language assignment statements, and you can directly
write to the output image table in the same way. (You can write to the
input image table to use unused input areas for storage. We do this
frequently in programmable controllers. However, with all the memory
available to you for storage in user RAM, we do not recommend using the
input image area for storage.)
The techniques, discussed in this section for accessing discrete I/O, execute
the quickest , but may be a little hard to understand. The techniques
discussed later in this chapter (see ”Library Routines”), sacrifice some
execution speed to gain some clarity. You’ll need to decide which
techniques are best for your application.
WARNING: Whichever technique you use to set outputs, make
sure that you don’t write to the output image table bytes that
correspond to intelligent I/O (block transfer) modules. If you do
write to these bytes, you’ll be unintentionally requesting a block
transfer. For more details, please see chapter 8, ”Unsolicited
Block Transfer”.
6-1
Page 57
Chapter 6
Discrete I/O
Subscript Calculation
The image tables are tables of words, where each 16-bit word corresponds
to the 16 terminals of a module group. Terminal 17 octal (15 decimal)
corresponds to bit 017 (15 decimal) of the word, and so on down to
terminal 0 and bit 0. (16 bits times 64 words gives 1024 output terminals
and 1024 input terminals. Though possible, it is very unlikely that any
given application would use all I/O points.)
To address a particular module group in either the output or the input
image table, the subscript is 8 times the rack plus the group. For instance,
if you wanted to return the 16-bit contents of rack 2, group 7 from the
input image table, you could code it this way:
value = g_ipt[8*2+7];
Single Terminal
To access a single input terminal, you need to shift the word value and
AND a 1 to mask off the other bits. Remember to specify terminal
numbers in decimal, or use a leading zero if you’re specifying terminal
numbers in octal.
Example: to obtain the value of terminal 12 octal (10 decimal) from rack 3,
group 5, either of these statements works:
bit = g_ipt[8*3+5]>>012 & 1; or
bit = (g_ipt[8*3+5]>>10) & 1;
The first statement as coded depends on the C language’s operator priority:
shifts are done before ANDs. You may feel more comfortable adding
parentheses to emphasize the order of operations, as we did in the second
statement.
If you’re simply going to use a terminal value in an if test, you can shift it
as we did above, or you can use a one bit mask like this:
if ( g_ipt[8*3+5] & (1<<012) ) . . .
This doesn’t look much better than the previous construct, but if you define
symbolic constants (as we recommend) the code becomes clearer:
if ( g_ipt[8*SENS_RACK+SENS_GRP] & SENS_MASK ) . . .
. . .
6-2
Page 58
Chapter 6
Discrete I/O
To set a single output terminal, you simply OR a 1 bit in the appropriate
position within the output image table word. Here’s an example, for
terminal 3 of rack 0, group 7:
g_oit[88*0+7] |=1<<3;
The next time the scanner scans that rack, the new value is transferred to
the scanner’s output image table and, the time after that, the value goes on
the I/O link to the module.
To reset (clear) a terminal is a little trickier: you have to AND a mask that
contains 1 bits everywhere except in the bit position of the terminal to be
cleared. The C language operator ~ is made for this kind of operation:
g_oit[8*0+7] &= ~(1<<3);
Access by Byte
If you need to access one slot within a module group, say to reset all eight
terminals in a single operation, you have two ways to do it. You could use
a cast operator to access the image table as an array of 128 character
values, or you could use the masking technique shown above.
Example: to clear slot 12 (the left hand slot of group 6) of rack 2, you can
do either
g_oit[8*2+6] &= 0xFF00; or
*((char *)g_oit + 16*2+12) = 0;
Notice in the first example that the low byte of a constant occurs at the
right, even though the low slot is physically at the left in the chassis. (The
bytes within a word are stored with the low byte at the lower address,
backward from the way the numbers occur in computations.) In the second
example, notice that we have 16 bytes rather than 8 words per rack.
Programming Hint
We suggest that you define constants for the addresses of your I/O
modules. This makes your programs easier to understand, and helps you in
debugging. For example:
Let’s look at this example. We defined the rack and group of the module
that controls an alarm, and the specific terminal (note the leading zero for
octal notation). To turn on an output terminal, we shifted a 1 bit left by the
terminal number and ORed that into the output image table.
By the way, you may be wondering about efficiency. Most C compilers do
all arithmetic on constants at compile time. So at run time there would be
no difference in execution speed between the above statement and
g_oit[40] |= 0x8000;
but the first way is certainly easier to understand and maintain.
Library Routines
We provide you with several library routines and macros to access the I/O
image tables. Execution is not as efficient as with the direct addressing
techniques in the previous section, but the difference should be negligible
in most applications compared to the time for transferring data across the
link.
getbit
Use this routine to get a bit from the input or output image table.
Calling sequence:
value = getbit(inout,
Arguments:
inout: the constant IN (1) for input image or OUT (0) for output
image.
rack: an integer 0 to 7, the logical rack number.
group: an integer 0 to 7, the module group number.
rack, gr
oup, bit
);
6-4
bit: an integer 0 to 15 (octal 0 to 017), the bit or terminal number.
Returned values:
an integer, the value of the bit, 1 or 0.
Example:
sens_bit = getbit(SENS_RACK, SENS_GRP, SENS_BIT);
obtains an on or off value from the sensor, assuming that you have
defined the symbolic constants in your program.
Page 60
Chapter 6
Discrete I/O
getbyte
Use this routine to get an 8-bit byte from the input or output image table.
Calling sequence:
value = getbyte(inout,
rack, gr
oup, hilow
);
Arguments:
inout: the constant IN (1) for input image or OUT (0) for output
image.
rack: an integer 0 to 7, the logical rack number.
group: an integer 0 to 7, the module group number.
hilow: the logical constant HI (1) or LO (0) to select the high or low
byte. The high byte corresponds to slot 1 within a module group
(terminals 017-010), and the low byte to slot 0 (terminals 07-00).
Returned values
a character, the value of the byte.
getword
Use this routine to get a 16-bit word from the input or output image table.
Calling sequence:
value = getword(inout,
rack, gr
oup);
Arguments:
inout: the constant IN (1) for input image or OUT (0) for output
image.
rack: an integer 0 to 7, the logical rack number.
group: an integer 0 to 7, the module group number.
Returned values:
an unsigned integer word, the value in the image table for that module
group.
6-5
Page 61
Chapter 6
Discrete I/O
putbit
Use this routine to write a bit into the output image table.
Calling sequence:
putbit(data,
rack, gr
oup, bit
);
Arguments:
data: an unsigned integer, whose low order bit is to be written to the
output image table.
rack: an integer 0 to 7, the logical rack number.
group: an integer 0 to 7, the module group number.
bit: an integer 0 to 15 (decimal) or 0 to 17 (octal), the bit number.
Returned values:
none
6-6
Page 62
Chapter 6
Discrete I/O
setbit
Use this routine to write a one bit into the output image table.
Calling sequence:
setbit(rack,
gr
oup, bit
);
Arguments:
rack: an integer 0 to 7, the logical rack number.
group: an integer 0 to 7, the module group number.
bit: an integer 0 to 15 (decimal) or 0 to 17 (octal), the bit number.
Returned values:
none.
Example:
setbit(ALARM_RACK, ALARM_GRP, ALARM_TERM);
turns on the alarm if the three constants have been defined with the rack,
group, and terminal (bit) number.
Note: setbit is a macro that compiles into a call on putbit with a
constant data value of 1.
6-7
Page 63
Chapter 6
Discrete I/O
clrbit
Use this routine to write a zero bit into the output image table.
Calling sequence:
clrbit(rack,
gr
oup, bit
);
Arguments:
rack: an integer 0 to 7, the logical rack number.
group: an integer 0 to 7, the module group number.
bit: an integer 0 to 15 (decimal) or 0 to 17 (octal), the bit number.
Returned values:
none.
Note: clrbit is a macro that compiles into a call on putbit with a
constant data value of 0.
putbyte
Use this routine to write an 8-bit byte to the output image table.
Calling sequence:
6-8
putbyte(data,
rack, gr
oup, hilow
);
Arguments:
data: an unsigned integer whose low order byte is written to the output
image table.
rack: an integer 0 to 7, the logical rack number.
group: an integer 0 to 7, the module group number.
hilow: the logical constant HI (1) or LO (0) to select the high or low
byte. The high byte is slot 1 (terminals 17-10) of the module group; the
low byte is slot 0 (terminals 07-00).
Returned values:
none.
Page 64
Chapter 6
Discrete I/O
putword
Use this routine to write a 16-bit word to the output image table.
Calling sequence:
Print
or Display
Image T
able
putword(data,
rack, gr
oup);
Arguments:
data: an unsigned integer to be written to the output image table.
rack: an integer 0 to 7, the logical rack number.
group: an integer 0 to 7, the module group number.
Returned values:
none
This section describes a routine we provide to help you dump the input or
output image table, or any array, to screen, printer, or disk. You can dump
the array by byte (16 per line) or by word (8 per line).
pr_array
Use this routine to format a word or byte array for display.
Calling sequence:
pr_array(fileptr,
header, array, length
);
Arguments:
fileptr:stdout or stderr for output to screen, or a pointer to a file
opened by the user program through fopen.header: a character pointer whose object is a descriptive phrase of a
few characters, such as “IIT”. If the display is to fit on an 80- character
line, the length of the header string must not exceed 34 characters if the
array is word oriented, 26 if byte oriented.
array: the name of a character or unsigned integer array.
length: an integer giving the length of the array. If the array is to be
displayed as words, length should be a positive number. If the array is
to be displayed as single bytes (type chararacter), length should be
minus the number of bytes in the array.
6-9
Page 65
Chapter 6
Discrete I/O
Returned values:
none.
Example: dumps the output image table by words to the screen.
It’s important to bear in mind that when you update your output image
table there is not an immediate effect on the outside world. (Though we
talk about output in this section the same timing applies to input: it takes as
long for a new input value to find its way from the input module to your
program as it does for an output value to follow the reverse path.)
Here is the chain of events for an output:
Your program updates g_oit, your output image table, either directly or
by using a library routine.
Some time later, the scanner interrupts the host.
The host interrupt handler (which runs in background as far as your
program is concerned) copies from the scanner’s input image table to
g_ipt, your input image table, and copies from g_oit to the scanner’s
output image table.
If the interrupt occurred just after you changed the output, the new data
is transferred when the scanner has run through its entire scan list back
to the point of the last interrupt. (The scanner interrupts the host once
per scan list to refresh I/O in both directions.)
6-10
Later the scanner comes to the adapter associated with the changed data,
and sends the new information to the adapter.
Page 66
Chapter 6
Discrete I/O
This sequence of events could take as long as two passes through the scan
list. This worst case scenario happens when you update an output just after
the scanner and the host interrupt handler have refreshed that rack. So it
may take one cycle until the scanner gets the new value, and a second
cycle until it services the adapter and sends the changed output.
How long is a cycle? Multiply 11 milliseconds (7 ms at 115.2 Kbaud) by
the number of adapters in the scan list. Your program has no way to know
where the scanner is in the scan list, or when the refreshes take place, so if
timing is critical you must assume that outputs might not get out to the real
world for as long as two complete scan lists if each adapter occurs only
once. (You can improve the situation by putting a critical adapter at two
different points in the scan list; see the scan list command in chapter 7,
”Scan List”.)
Partial Refresh
You can force a partial refresh sooner than the worst case of two complete
passes through the scan list. This makes the scanner’s latest input
information available to your program and send the scanner new discrete
outputs for those same racks. However, your program has no way to
update specific racks or adapters, or to know which racks have just been
refreshed.
We don’t know of an application that would require such an interim
refresh, but if you decide yours is one here is how to refresh the I/O image
tables early.
Note: It may bear repeating that update merely updates I/O image tables;
it does not assure your program that any I/O has actually occurred.
update
Use this routine to refresh the I/O image tables.
Calling sequence:
status = update( );
Arguments:
none.
Returned value:
OK if the scanner responded before the timeout period specified by
g_timout; NOT_OK if the scanner did not respond.
6-11
Page 67
Chapter 6
Discrete I/O
This routine interrupts the scanner, then waits until the scanner has
interrupted the host at least once. The host’s interrupt handler updates the
global RAM from the user program’s output image tables and the user
input image tables from the global RAM. After the interrupt has been
processed, update returns control to your program.
6-12
Page 68
Scanner Management
Chapter
7
Chapter
Overview
Objectives
This chapter explains how to issue management requests to the scanner.
After reading this chapter, you should be able to:
queue any of the six types of management requests
print or display the results, or write formatted results to a file.
To make this chapter shorter and easier to read, we use the abbreviation
MR for management request.
Here is a summary of the actions involved in completing an MR:
Your program puts the data (for all commands except autoconfigure and
link status) and length of data (for scan list only) into a packet of
specified structure.
Your program calls the mr_wait library routine.
mr_wait copies information to an internal queue and interrupts the
scanner. mr_wait does not return to your program but instead goes into
a wait loop, which ends when the request is done or g_timout units of
time have elapsed.
When the scanner responds (usually a short time later), the interrupt
handler copies the MR information to the global RAM. This happens
essentially in background as far as mr_wait is concerned.
When the scanner comes back a second time with a completion status,
the interrupt handler copies that status (plus the length of data and the
data, for autoconfigure and link status) to your program’s packet.
Again, this is in background as far as mr_wait is concerned.
When mr_wait senses in its loop that the request is complete, it returns
control to your program. If the timeout interval runs out before the
scanner comes back with a confirmation, mr_wait returns to your
program anyway.
7-1
Page 69
Chapter 7
Scanner Management
Data
Structure (Packet)
QMR typedef
When you initiate an MR, you pass a packet to the library routines. The
packet has a defined type of QMR.
This defined type is a structure that contains a field used only by the
library routines, plus the following:
qmr_stat
unsigned integer confirmation status, initially equal to SC_PENDING
and then set to the actual completion status after the scanner has finished
with the MR.
qmr_len
unsigned integer length of data in bytes, which you fill in only when
changing the scan list.
qmr_data
character array of 128 bytes, the data area.
Programmer Alert
Your program can get itself into trouble by misusing packets. Here are the
pitfalls that relate to MRs:
Improper reuse of pointers: If the mr_wait routine decides that the
scanner has not responded in a reasonable time, your program is
generally free to use the packet for a different MR. But suppose that
your program had g_timout set too low so that mr_wait didn’t wait
long enough. (A scan list, the slowest request, can take up to 12 units,
about 2/3 of a second.) Then the confirmation of the first request could
come through and wipe out the information in the second request, which
is waiting for a confirmation from the scanner. The library routines
catch some but not all of these situations, and count up the ones they do
catch in g_pkt_err. Generally, your program should not reuse a packet
that contains a status of SC_PENDING unless absolutely sure that the
scanner never responds to that command.
Invalid pointers: Conforming to established C coding conventions,
library routines that need access to user packets take pointers as their
function arguments. There is no way for a called function to check
whether your program has sent it a valid pointer. Therefore, you are
completely responsible for sending valid pointers to the library routines.
If the pointer arguments don’t point to proper packets, your program can
perform incorrectly or crash, possibly locking up the host computer.
7-2
Page 70
Chapter 7
Scanner Management
Executing
Request
a Management
To start an MR, you store the required fields in the packet and then call the
mr_wait function. mr_wait waits until the request is completed or has
timed out and returns a completion status to your program.
Autoconfigure, setup, scan list, and fault dependent group can be executed
only in program mode. Link status and set mode can be executed in any
mode.
Timeout
The timeout period is the current value of global variable g_timout in 55
millisecond units. (The actual frequency is more nearly 1,193,180 / 64K
Hz, about 18.2065 per second or 54.925 ms each.) If the scanner doesn’t
complete the MR within this time, mr_wait assumes that the scanner never
completes the request.
The default timeout is 18 units, about 1 s. You can change the timeout
interval by storing a new value in g_timout. However, be sure to allow a
large enough interval. Worst-case times for autoconfigure and scan list are
272 ms and 704 ms respectively; for full explanations please see those
sections. Link status, set operating mode, fault dependent group, and setup
are always completed within one time unit, 55 ms.
The actual timeout interval can be as much as one unit less than the value
you store in g_timout. The reason is that the mr_wait routine copies
g_timout to the g_decrem counter, which counts down every 55 ms, and
when g_decrem reaches zero the mr_wait function considers the request
to have timed out. But if the clock tick happens to come right after
g_decrem was set, the effective value of the timeout is almost a full 55 ms
less that the nominal value. The bottom line? In deciding on a timeout (if
you don’t stick with the default value), always allow an extra unit above
the value you calculated.
7-3
Page 71
Chapter 7
Scanner Management
General Form
This section gives details for each of the six types of MR, but first we
present a program skeleton, where command stands for the defined
constant that names the desired command:
QMR mgmt;
unsigned confirm_stat;
. . .
mgmt.qmr_len = . . . /* for scan list only */
mgmt.qmr_data[0] = . . . /* except autoconf & link */status
confirm_stat = mr_wait(command, &mgmt);
if ( !confirm_stat ) {
The mr_print call shown in the program skeleton above displays the
results of the MR on the screen. Such a call would probably be used only
when operator intervention might be appropriate.
7-4
Page 72
Chapter 7
Scanner Management
mr_wait
mr_wait returns a status code, which it also places in the qmr_stat field of
the packet. For a complete list of status codes, please see Confirmation
Status Codes later in this chapter. For now it’s enough to know that
SC_OK (0) means successful completion, SC_PENDING means the
scanner didn’t come back with a confirmation before timeout, and any
other value is an error code returned by the scanner or the library routines.
You can code if tests based on the assumption that a zero status means
success.
Example:
if ( mr_wait(. . .) )
/* request failed */
or
if ( !mr_wait(. . .) )
If you prefer, you can call mr_wait without using its return value, since
the qmr_stat field of the packet contains the same code:
mr_wait(. . ., &pkt);
if ( pkt.qmr_stat )
/* request succeeded */
/* request failed */
7-5
Page 73
Chapter 7
Scanner Management
Set Operating Mode
To change the scanner’s operating mode, you must set the first byte of the
packet’s qmr_data field to one of the three values CM_RUN,CM_TEST,CM_PROGRAM. Then call mr_wait with C_SETMODE as its first
argument.
Calling sequence:
packet.qmr_data[0] = mode;
status = mr_wait(C_SETMODE, &packet);
where
packet is a QMR type packet. Note that the argument to mr_wait is a
pointer to the packet.
mode is either CM_PROGRAM, CM_TEST, or CM_RUN.
Returned values:
status and packet.qmr_stat as explained under General Form, above.
global variable g_op_stat reflects the new scanner operating mode if the
request was successful.
Example: To change to run mode, execute the following code:
QMR mode_pkt;
mode_pkt.qmr_data[0] = CM_RUN;
if ( mr_wait(C_SETMODE, &mode_pkt) ) {
printf(“can’t execute set mode (%s)\n”,
xlat_conf(mode_pkt.qmr_stat));
abort( );
}
. . .
For the xlat_conf function, which translates a confirmation status to
English, see Confirmation Status Codes later in this chapter.
7-6
Page 74
Chapter 7
Scanner Management
Setup
This MR lets you change the baud rate and connect or disconnect the line
termination resistor. It also lets you put the scanner into “debugging
mode,” which disables the scanner watchdog. The scanner must be in
program mode to execute a setup request; otherwise the scanner returns an
error code.
Note: In the SETUP_6008( ) function, -1 indicates default parameters.
The symbolic name of the setup command is C_SETUP. The setup
request takes three bytes of data:
baud rate, 1 for 57.6 Kbaud, 2 for 115.2 Kbaud, or -1 to leave the
present baud rate unchanged.
resistor, 1 to connect, 0 to disconnect, or -1 for no change.
debugging mode, 1 to disable the scanner watchdog and any other value
to enable the watchdog. Debugging mode is discussed below.
WARNING: Debugging mode should be used only when
someone is physically present to monitor the process. If the
host program stops while scanner debugging mode is in effect,
all output modules stay in last state. You should shut off the
host computer’s power switch immediately to terminate the
process.
packet is a QMR type packet. Note that the argument to mr_wait is a
pointer to the packet.
Returned values:
status and packet.qmr_stat as explained under General Form, above.
global variable g_op_stat reflects whether the scanner is in debugging
mode (SO_DEBUG bit).
7-7
Page 75
Chapter 7
Scanner Management
Example: If you want to switch to 115.2 Kbaud without changing the
resistor setting, use this code:
QMR setup_pkt;
setup_pkt.qmr_data[0] = 2; /* baud multiplier */
setup_pkt.qmr_data[1] = -1; /* no change to resistor */
setup_pkt.qmr_data[2] = 0; /* not in debug mode */
mr_wait(C_SETUP, &setup_pkt);
if ( setup_pkt.qmr_stat ) {
setup_pkt.qmr_stat);
}
. . .
printf(“setup call failed (%d)\n”,
abort( );
A note on debugging mode: Normally, the scanner expects the host to
return the global RAM within 50 milliseconds after the scanner interrupts
the host. (This is a comfortable margin: the host interrupt service routine
takes about 0.1 to 2 ms, depending on the host CPU and how much work
the interrupt routine has to do.)
After the 50 ms interval, the scanner watchdog kicks in. What that means
is that the scanner decides that the host hardware or BIOS has died and
therefore the scanner goes off the I/O link. In about another 50 ms the
adapters all go inactive and the modules are in last state or reset according
to the way you set their switches. Normally, this safety precaution is
exactly what you want.
7-8
But if you’re debugging your program you may want to single step through
it, and each step would take longer than the scanner’s 50-ms watchdog
interval. This is the purpose of debugging mode: it turns the scanner
watchdog off.
Make sure to turn debugging mode off (a setup request with any value
other than 1 in the third byte) before your program exits. If your program
ends while the scanner is in debugging mode, you have to cycle power
before the scanner communicates with the host again. (In this case you
should turn off host power anyway, as a safety measure, since otherwise all
output modules are held in last state.)
Page 76
Chapter 7
Scanner Management
Autoconfigure
In doing an autoconfigure, the scanner actually queries each possible
adapter position to determine which addresses have adapters present.
To tell the scanner to do an autoconfigure, you simply issue an mr_wait
function call with C_AUTOCONF as its first argument. The scanner must
be in program mode to do an autoconfigure; otherwise the scanner returns
an error status.
When the scanner does an autoconfigure, it forgets any fault dependent
groups you may have set up. When doing an autoconfigure, the scanner
also puts a new default scan list into effect. The default scan list is simply
a list of all adapters that responded, in rack and group order. (In single slot
addressing, a single adapter with more than eight slots looks like two
adapters to the scanner.)
Calling sequence:
status = mr_wait(C_AUTOCONF, &packet);
where:
packet is a QMR type packet. Note that the argument to mr_wait is a
pointer to the packet.
Returned values:
status and packet.qmr_stat as explained under General Form, above.
packet.qmr_data contains 32 words of configuration information, one
for every possible adapter address, followed by 0 to 16 bytes of the
current scan list; see discussion below.
packet.qmr_len contains the length of data in bytes, which is 64 plus the
length of the new default scan list. In other words, to obtain the length
of the scan list you subtract 64 from packet.qmr_len.
Before we give you further information on interpreting the data returned
by an autoconfigure, you should know that we have provided a routine,
mr_print, to turn all the information into English. For details, please
see ”Print or Display Results” in this chapter.
7-9
Page 77
Chapter 7
Scanner Management
The data returned by a successful autoconfigure can be divided into two
parts:
a fixed length part, 32 pairs of bytes. The first byte of each pair gives
information about the size and type of the adapter, and the second byte
gives fault information. For complete information, please see
”Autoconfigure and Link Status Information” in this chapter.
a variable length part, 0 to 16 bytes long, containing the new default
scan list. Each byte contains an adapter position in the form 4 x rack +
group / 2. The length of the scan list is packet.qmr_len – 2 x 32.
The time required to complete an autoconfigure request depends on the
baud rate and the number of adapters connected, as well as the size of each
adapter. For simplicity, we consider worst case, where each adapter
controls a full rack. In this case, the time to completion is 11 milliseconds
per connected adapter (7 ms at 115.2 Kbaud) plus 6 ms for each of the 32
possible adapter positions where no adapter is connected. Doing the
algebra, we have
T = 5 ms x adapters + 192 (57.6 Kbaud)
T = 1 ms x adapters + 192 (115.2 Kbaud)
Since no more than 16 adapters can be connected at once, worst-case time
for an autoconfigure is 272 ms at 57.6 Kbaud, 208 ms at 115.2 Kbaud. (If
16 adapters are connected, they can’t all be full racks, so this is actually a
longer time than true worst case.)
Link Status
A link status request returns the same information as an autoconfigure, but
link status differs from autoconfigure in three ways:
The scanner can execute a link status request while in any mode, not just
program mode.
The scanner doesn’t actually query possible adapters in doing a link
status. Rather, the scanner copies its internal status tables to the global
RAM.
Fault dependent groups and the current scan list are not changed by a
link status command.
7-10
Page 78
Chapter 7
Scanner Management
To query the scanner about link status, simply issue an mr_wait function
call with C_LINKSTAT as its first argument.
Calling sequence:
status = mr_wait(C_LINKSTAT, &packet);
where:
packet is a QMR type packet. Note that the argument to mr_wait is a
pointer to the packet.
Returned values:
status and packet.qmr_stat as explained under General Form, above.
packet.qmr_data and packet.qmr_len contain exactly the same
information as is returned by an autoconfigure, except that the scan list
and fault dependent groups have not been disturbed. The scan list
length may also be up to 64 bytes long rather than just 16. For complete
information, please see ”Autoconfigure and Link Status Information”
later in this chapter.
Scan List
You can use a scan list request to tell the scanner to give a larger share of
its attention to some adapters at the expense of others. Though there are
only 32 possible adapter addresses, and only 16 of those can be occupied at
a time, the scan list can be up to 64 positions long.
The scan list and fault dependent group requests interact in one way:
Every adapter that is part of a fault dependent group must also be part of
the current scan list. If you try to violate this rule by specifying a new scan
list, one that omits some adapters that are still in fault groups, the scanner
returns an error code and leaves the old scan list in effect. To change the
scan list in that way you must first issue a fault dependent group command
that leaves the “orphan” adapters out of all fault groups.
7-11
Page 79
Chapter 7
Scanner Management
The scan list request is the only MR that requires both data and length of
data to be in the packet before you call mr_wait. The first argument to
mr_wait is C_SCANLIST. The scanner must be in program mode to
execute a scan list request; otherwise the scanner just returns an error code.
packet.qmr_data[length-1] = . . . /* last adapter address */
status = mr_wait(C_SCANLIST, &packet);
where
packet is a QMR type packet. Note that the argument to mr_wait is a
pointer to the packet.
packet.qmr_len, the length of the scan list, may be anything from 0 to
64 inclusive.
packet.qmr_data contains the adapter addresses for the scan list, in the
form 4 x rack + starting group / 2. A given adapter can occur more than
once in the list, or an existing adapter may be omitted from the scan list.
Returned values:
status and packet.qmr_stat as explained under General Form, above.
The time required to complete a scan list command is essentially the
time to scan every adapter once: 11 milliseconds per scan list entry (7
ms/entry at 115.2 Kbaud). Since the scan list can be as long as 64
entries, the worst case time is 704 ms at 57.6 Kbaud, 448 ms at 115.2
Kbaud.
7-12
Page 80
Chapter 7
Scanner Management
Example: Suppose you have two adapters connected, one controlling rack
1 (a full rack) and the other controlling the second half of rack 2. (The
adapter addresses are 4 x 1 + 0 / 2 = 4 and 4 x 2 + 4 / 2 = 10.) Suppose
you want to sample inputs from rack 2 every 5 seconds, but want the most
current information possible from rack 1. You would enter a scan list
request with adapter 2 occurring only once and adapter 1 occurring several
times.
At first glance, you might try a scan list of 64 bytes, with 63 repeats of
adapter 1 and one occurrence of adapter 2. (Since the scan list is processed
repetitively, it doesn’t matter where in the list the one occurrence of rack 2
is placed.) But if you want the most current information possible that may
not be a good idea.
Recall that it takes up to 11 ms at 57.6 Kbaud, or 7 ms at 115.2 Kbaud, to
scan each adapter in the scan list. If you’re operating at 115.2 Kbaud with
a scan list of 64 positions, your inputs are updated only every 64 x 7 = 448
ms. If you want information, say, every 100 ms, then you need a shorter
scan list. 100 / 7 = 14.3, so you want a scan list only 14 or 15 positions
long.
Here is code to create that scan list, using the memset function (provided
with many compilers) to initialize a block of memory:
QMR scan_list;
scan_list.qmr_len = 14; /* length of scan list */
/* 13 occurrences of first adapter */
memset(scan_list.qmr_data, 4, 13);
scan_list.qmr_data[13] = 10; /* second adapter */
mr_wait(C_SCANLIST, scan_list);
if ( scan_list.qmr_stat )
. . .
/* error code here */
Fault Dependant Group
In many applications, adapters are conceptually grouped together such that
if any one of the adapters in a group is faulted, you want all the others to
be faulted too. The fault dependent group (FDG) request implements this
concept.
FDGs are numbered from 0 to 7. When you issue a FDG request, you
specify which adapters should be put in FDGs and which FDGs they
should be put in.
7-13
Page 81
Chapter 7
Scanner Management
In the data array, you must fill the first 32 bytes, one for each possible
adapter position. The subscripting is 4 x rack + group / 2. (In the subscript
calculation, group is the adapter’s starting group number within the rack,
not the FDG number.) For each adapter position, if the adapter doesn’t
exist, or it exists but you don’t want it to be in a fault group, put zero in the
data byte. For each existing adapter that is in the current scan list and that
you want in a fault group, put the fault group number ORed with
SF_IN_FGRP in the data byte.
Note that an adapter is not allowed to be in an FDG unless it is also in the
current scan list. If you want to increase the scan list and put the added
adapters in fault groups, you must issue two commands in that order. If
you try to issue a FDG request that puts unscanned adapters in fault
groups, the scanner returns an error code and does not change the existing
fault groups.
Once you’ve set up the data array, call mr_wait with a first argument of
C_FLT_GRP. The scanner must be in program mode to execute a FDG
request; otherwise the scanner returns an error code.
Calling sequence (example):
packet.qmr_data[...] = 0; /* no fault group */
packet.qmr_data[...] = 1 | SF_IN_FGRP; /* fault group #1 */
packet.qmr_data[...] = 0 | SF_IN_FGRP; /* fault group #0 */
status = mr_wait(C_FLT_GRP, &packet);
. . .
where
packet is a QMR type packet. Note that the argument to mr_wait is a
pointer to the packet.
packet.qmr_data contains the fault group numbers for the 32 possible
adapter addresses, four per rack.
Returned values:
status and packet.qmr_stat as explained under General Form, above.
7-14
Page 82
Chapter 7
Scanner Management
Example: Suppose you have five adapters connected, four for the quarter
racks in rack 6 and one for the first half of rack 0. If you want to link the
four quarter-rack adapters in a fault dependent group, say group 1, and
leave the half-rack adapter out of all FDGs, you can do it this way:
The autoconfigure and link status requests return a complicated data
structure in the qmr_data field of the packet:
The first part is fixed length and contains 32 words (byte pairs), one for
each possible adapter position. Within each byte pair, the first byte
contains configuration information, such as the size and type of the
adapter, and the second byte contains fault status and fault dependent
group information.
The second part is variable length, being the current scan list, 0 to 64
bytes long. The length of the scan list is found by subtracting 64 from
the value in the qmr_len field of the packet. Each byte contains an
adapter address in the form 4 x rack + group / 2.
Here is some quick code to print the current scan list:
int len;
char *scan;
. . .
len = packet.qmr_len - 2*MAXADAPT;
if ( !len )
printf(“scan list has no adapters\n”);
else
printf(“current scan list (%d adapters):\n”, len);
for ( scan=packet.qmr_data+2*MAXADAPT; len--; ++scan )
printf(“rack %d group %d\n”, *scan>>2, (*scan&3)<<1);
Most of this section explains how to extract the configuration and fault
information, working from the packet that was returned by a successful
autoconfigure or link status request.
7-15
Page 83
Chapter 7
Scanner Management
Configuration Information
Byte
You can extract the configuration information byte for any adapter, based
on the rack and starting group of the adapter. Either access an element of
the qmr_data array, like this:
packet.qmr_data[ 8*rack + group ]
or use the cfg_info macro to do the same thing.
cfg_info
This macro obtains the configuration byte for a particular adapter from the
QMR-type packet returned from an autoconfigure or link-status request.
Calling sequence:
status = cfg_info(&packet,
Arguments:
packet: a QMR structure, assumed to contain status SC_OK after an
autoconfigure or link status request. Note that the actual argument is a
pointer to the packet.
rack, gr
oup);
rack: logical rack number, 0 to 7.
group: starting group number, an even number from 0 to 6.
Returned values:
an integer that can then be examined for the status bits described below
(leading characters SL_). If you prefer, you can call the xlat_cfg
function to convert the status bits to an English language string; see
”Print or Display Results” in this chapter.
7-16
Page 84
Chapter 7
Scanner Management
Configuration Information Bit Fields
The fields listed in Table 7.A are defined in the low byte of the word of
information about each adapter, which can be extracted by using the
cfg_info function described above:
Fault and Fault Dependent
Group Information Byte
Table 7.A
Configuration
Bit FieldHex ValueDescription
SL_IN_SCAN 10 (hex)true (1) if the adapter is in the current scan list. If this bit is
SL_EXISTS 08 (hex)true (1) if an adapter is attached (or was attached earlier in the
SL_KNOWN 04 (hex)true (1) if the adapter type, size, and address are valid. If this
SL_SIZE 03 (hex)size of the adapter, measured in 1/4 rack units: values 0 to 3
SL_NODE 40 (hex)true (1) if this is a node adapter.
SL_FAST_NA 80 (hex)true (1) if this is a fast node adapter.
SL_SNGL_PT 20 (hex)true (1) if this is a singlepoint I/O adapter.
Information Bit Field Descriptions
zero, the other bits in the link status word are meaningless.
same execution of the program) and begins at this address. If
this bit is zero, the bit fields listed below are meaningless.
bit is zero, the bit fields listed below are meaningless.
represent 1/4 rack, 1/2 rack, 3/4 rack, and a full rack.
You can test for any of the above conditions by ANDing the information
byte with the bit name.
You can extract the fault information byte for any adapter, based on the
rack and starting group of the adapter. Either access an element of the
qmr_data array, like this:
packet.qmr_data[ 8*rack + group + 1 ];
or use the flt_info macro to do the same thing.
flt_info
Extracts fault information byte. This macro obtains the fault byte for a
particular adapter from the QMR type packet returned from an
autoconfigure or a link status request.
Calling sequence:
status = flt_info(&packet,
rack, gr
oup);
7-17
Page 85
Chapter 7
Scanner Management
Arguments:
same as for cfg_info above.
Returned values:
an integer that can then be examined for the status values described
below (leading characters SF_). You may prefer to call the xlat_flt
function to convert the status bits to an English language string.
Before calling the flt_info function, your program should first examine
the SL_IN_SCAN bit in the configuration byte for the same adapter,
which can be obtained through cfg_info as shown in the sample code
below. If SL_IN_SCAN is false (0), the fault information is
meaningless.
Fault and Fault Dependent Group Bit Fields
The fields listed in Table 7.B are defined in the high byte of information
about each adapter. The fault information byte can be extracted by using
the flt_info function described above.
Table 7.B
and Fault Dependent Group Bit Field Descriptions
Fault
Bit FieldHex ValueDescription
SF_ON_LINE 70 (hex)true (1) if the adapter is on line, false (0) if faulted.
SF_IN_FGRP 08 (hex)true (1) if the adapter is in a fault dependent group.
SF_GRP_NUM 07 (hex)number of the fault group this adapter belongs to (meaningless
if SF_IN_FGRP is zero).
SF_GRP_FLT 80 (hex)true (1) if this adapter has been instructed to go into fault mode
because a member of its fault group is faulted.
You can extract the fault dependent group number (0-7) by ANDing the
fault information byte with the constant SF_GRP_NUM, provided that the
SF_IN_FGRP bit is set.
7-18
Coding Examples
Here’s some sample code to extract the fault dependent group number:
status = flt_info(&pkt, rack, group);
if ( status & SF_IN_FGRP )
fdg_number = status & SF_GRP_NUM;
else
fdg_number = -1; /* no fault dep group */
Page 86
Chapter 7
Scanner Management
This is a partial sample of coding for status of the adapter starting at rack
3, module group 4.
QMR config_pkt;
int status, fault;
if ( mr_wait(C_LINKSTAT, &config_pkt) != SC_OK ) {
}
else {
rack\n”,1+(status&SL_SIZE)):
fault&SF_GRP_NUM);
}
. . .
/*error in MR execution*/
status = cfg_info(&config_pkt, 3, 4);
fault = flt_info(&config_pkt, 3, 4);
if ( status & SL_IN_SCAN ) {
/*the adapter is in the scan list*/
printf(“adapter size: %d/4
if ( ! (fault & SF_ON_LINE) )
printf(“adapter is faulted\n”);
if ( fault & SF_IN_FGRP )
printf(“in fault group %d\n”,
}
Confirmation
Status Codes
Recall that the other bits in a configuration byte have no meaning if the
SL_IN_SCAN bit isn’t set. There are some additional dependencies, too:
you are encouraged to make use of the xlat_cfg and xlat_flt routines
described in later in this chapter in ”Print or Display Results”.
This section lists the confirmation status codes that the scanner may return
when processing an MR. Before the list of codes, we present a routine that
turns a numeric code into an English message.
xlat_conf
Translates a confirmation status. This function converts a confirmation
status value to English.
Calling sequence:
explan = xlat_conf(status);
Arguments:
status: a confirmation status returned in the qbt_stat or qmr_stat field
of a packet after the packet was passed to a library routine.
Returned values:
a character pointer that points to a string suitable for printing. The
string length varies depending on the message, but do not exceed 47
characters (46 plus the terminating zero byte).
7-19
Page 87
Chapter 7
Scanner Management
Table 7.C lists the confirmation status codes for a management request.
Table 7.C
Confirmation
Status CodeHex ValueDescription
SC_PENDING FF (hex)not yet transmitted to the scanner, or transmitted to the
SC_OK 00 (hex)completed successfully.
SC_BAD_CONFIG 16 (hex)the request attempted to specify a scan list that omits some
SC_BAD_LEN 15 (hex)invalid length for a C_SCANLIST command.
SC_BAD_PARAM 11 (hex)invalid parameters to a valid command.
SC_BAD_REQ 10 (hex)invalid command.
SC_PROG_MODE 13 (hex)invalid attempt to issue an autoconfigure or a setup, scan list,
SC_REQ_PEND 12 (hex)invalid attempt to enter a management request while another
SC_NOT_OK 01 (hex)some other error, most likely invalid arguments passed from
Status Code Descriptions
scanner but not yet confirmed back to the host.
adapters that are in fault dependent groups, or to specify a set
of fault dependent groups including some adapters that aren't
in the current scan list.
or fault dependent group command while not in program mode.
one was pending. (This should never happen because the
mr_wait routine doesn't return to your program until the
pending request is finished.)
the user program to the library queue routines.
Print
or Display
Results
This section tells you about three functions that are useful in formatting the
results of an MR for display.
One, mr_print, formats the complete results of any MR, including both
the fixed and variable parts of an autoconfigure or link status. The other
two functions, xlat_cfg and xlat_flt, translate just one byte of data from
the autoconfigure or link status fixed portion.
Note that xlat_cfg and xlat_flt each have an internal string buffer and
return a pointer to that buffer. Calling one of these routines destroys the
previous contents of the buffer for that routine, but leaves the other buffer
unaffected. This means that you must use the string returned by either of
these routines before you call the same routine again.
7-20
Page 88
Chapter 7
Scanner Management
mr_print
Formats an MR queue entry for display. This function translates the
command and status to English for writing to screen or file. If the MR was
for link status or autoconfigure, mr_print also displays expanded
information on all adapters.
Calling sequence:
mr_print(fileptr, command, &qmrptr);
Arguments:
fileptr: stdout or stderr for screen output, or a pointer to a user file
opened with fopen.
command: an integer, the management request. This is one of the six
symbolic constants C_AUTOCONF, C_FLT_GRP, C_LINKSTAT,C_SCANLIST, C _SET_MODE, C_SETUP. (mr_print needs to
know which command you issued because the interpretation of the data
is different for different commands.)
qmrptr: the QMR-type packet that was passed to mr_wait. Note that
the function argument is a pointer to the packet.
Returned values:
none.
mr_print displays as much information as possible in English, rather
than in numeric codes. For instance, if the command was
C_AUTOCONF or C_LINKSTAT, mr_print displays a line of
information about each adapter that is in the scan list, followed by a
display of the scan list showing the order in which adapters are scanned.
For these commands plus C_SCANLIST, mr_print separates adapter
addresses into the form rack/group.
7-21
Page 89
Chapter 7
Scanner Management
xlat_cfg
Translate a configuration byte to English.
Calling sequence:
explan = xlat_cfg(config);
Arguments:
config: a byte from the array returned by an autoconfigure or link status
call, possibly extracted by the cfg_info routine.
Returned values:
a character pointer whose object is a string of 23 characters (22 plus the
terminating zero byte) suitable for printing. This pointer points to an
internal buffer whose contents are destroyed by subsequent calls to
xlat_cfg.
If the SL_IN_SCAN bit is zero, all other fields are meaningless and the
function returns a string containing the message “not in scan list”.
If the SL_IN_SCAN bit is set but the SL_EXISTS it is not, all other
fields are meaningless and the function returns “never responded”.
If the SL_IN_SCAN and SL_EXISTS bits are both set but the
SL_KNOWN bit is not, all other fields are meaningless and the
function returns “responding improperly”. This means that the address,
size, or length information returned by the adapter appears invalid.
If the SL_IN_SCAN, SL_EXISTS, and SL_KNOWN bits are all set,
the other fields are meaningful and the function attempts to interpret
them. The first part of the string contains one of the messages
“1/4_rack”, “half_rack”, “3/4_rack”, or “full_rack” right justified in a
nine character field. Then if one of the adapter type bits is set one of the
three messages “node_adapter”, “fast_node_ad”, and “single_pt_ad”
appears, separated by a space from the size field.
No tabs or newlines are ever included in the returned string.
7-22
Page 90
Chapter 7
Scanner Management
xlat_flt
Translate a fault information byte to English. Note that this function
returns correct information only if the SL_IN_SCAN bit is set in the
configuration byte for the same adapter.
Calling sequence:
explan = xlat_flt(fault);
Arguments:
fault: a byte from the array returned by an autoconfigure or link status
call, possibly extracted by the flt_info routine.
Returned values:
a character pointer whose object is a string of 28 characters (27 plus the
terminating zero byte) suitable for printing. This pointer points to an
internal buffer whose contents are destroyed by subsequent calls to
xlat_flt.
If the SF_ON_LINE field is nonzero, the first seven characters of the
returned string contain “on_line”; otherwise the string begins with
“faulted”. A space follows either message.
If the SF_IN_FGRP bit is set, the SF_GRP_NUM field is extracted
and the next ten characters of the string contain “flt_grp_#n” where n is
the extracted group number; otherwise the next ten characters contain
“no_flt_grp”.
If the SF_GRP_FLT bit is set, the final nine characters contain a space
and “grp_fltd”; otherwise they are blank.
No tabs or newlines are ever included in the returned string.
7-23
Page 91
Block Transfer
Chapter
8
Chapter
Objectives
This chapter explains how to transfer data between intelligent I/O modules
(block transfer modules) and your program’s data area. After reading this
chapter you should be able to:
read a block of data from an intelligent I/O module
write a block of data to an intelligent I/O module
calculate how long it takes any given block transfer to finish
poll for completion of the block transfer
use a library routine to display the results on screen or printer or format
them to a file.
perform block transfers to a PLC5 in adapter mode
perform block transfers to a 1771–DCM.
To make this chapter shorter and easier to read, we use the abbreviation BT
for block transfer.
Overview
Here is a summary of the actions involved in completing a BT:
Your program puts the BT length into a packet of specified structure.
For a write BT, your program also puts the data into the packet.
Your program calls bt_que or another library routine.
The library routine adds your BT to its queue and interrupts the scanner
to alert it that the host has a request. The library routine writes a status
of “not complete” in your packet and returns control to your program
without waiting for a response from the scanner.
A short time later, the scanner responds to the interrupt and the host’s
interrupt handler puts the BT information into the global RAM.
Although this action interrupts your program, you can think of it as
something that takes place in background.
8-1
Page 92
Chapter 8
Block Transfer
Meanwhile, your program is periodically polling for completion of the
BT, either by examining the packet directly or by using the bt_done
macro.
When the BT is complete, or if it is not finished within 4 seconds after it
was queued, the scanner interrupts the host with a confirmation status
and the length of data actually transferred. For a read BT, if the BT was
successful the scanner also passes the data that it read.
The interrupt handler writes the confirmation status, length of data, and
(for a read BT) data to your program’s packet. Again, you can think of
this as taking place in background.
The next time your program polls for completion, it finds that the BT is
finished and can examine the status to determine whether it succeeded.
For a successful read BT, your program can then make use of the data.
QBT
Data Structure (Packet)
In the following sections we’ll be taking a closer look at these steps.
When you initiate a BT, you pass a packet to the library routines. The
packet is a defined type of QBT. You should declare it static unless you
have good reason not to: see the “Programmer Alert” below.
The QBT defined type is a structure that includes the following fields, all
of type unsigned integer, in addition to a field of concern only to the
library routines:
qbt_stat
confirmation status; see ”Confirmation Status Codes” later in this chapter
for a complete list. The library routines initialize this to SC_PENDING,
and change it to the actual confirmation status when a reply is received
from the scanner. Your program can determine whether the BT is done by
testing this field for equality to SC_PENDING or by calling the macro
bt_done. See ”Polling for Completion” later in this chapter.
qbt_len
8-2
length of data in words, up to 64. A value of 0 (zero) is permitted and tells
the module to decide how many words to transfer (never more than 64).
The number of words actually transferred is always left in this field after
the BT has finished or timed out; in case of timeout or other error, this field
is set to zero. After completion, the value is from 0 to 64.
Page 93
Chapter 8
Block Transfer
qbt_data
data area, an array of 64 words. For a write BT, you must place the data in
this area before calling a library routine to queue the BT; and if the length
of data is zero you must be sure to have enough data for the module.
Programmer Alert
Your program can get itself into trouble by misusing packets. Here are the
pitfalls:
Improper declaration of packets: It would be natural for a function to
declare a packet as follows:
QBT packet; /* possibly unsafe */
But this declares the packet on the stack, which may not produce the
desired results. Suppose your program has a declaration like the above
in a function, say x, and calls a library routine to queue a BT. If x then
returns to its calling function, say c, then x (which contains the packet
declaration) is no longer active by the time the scanner comes back with
the confirmation. The interrupt handler still has a record of the absolute
core location of your packet, but that core location is now in use by
some other function’s stack. The library routines can detect some of
these situations, but not all. The running count of occurrences detected
is stored in global variable g_pkt_err.
You have two defenses against this problem. The way requiring less
thought, and providing absolute safety, is simply to declare all QBT
packets static. This ensures that the physical data locations are not used
by any other variables during execution, but may increase program size
unnecessarily. The other technique is to take note of the structure of
your program and locate packet declarations so that each packet is
declared in a function that definitely does not return to its caller before
the scanner has returned a completion status.
Improper reuse of pointers: A second potential problem is closely
related to the preceding one. If your program decides that the scanner
has not responded in a reasonable time, the program is generally free to
use the packet for a different BT. But suppose that your program simply
didn’t wait long enough. Then the confirmation of the first request
could come through and wipe out the information in the second request,
which is waiting for a confirmation from the scanner. Again, the library
routines catch some but not all of these situations, and count up the ones
they do catch in g_pkt_err. Generally, your program should not reuse a
packet that contains a status of SC_PENDING unless absolutely sure
that the scanner is not responding to that command.
8-3
Page 94
Chapter 8
Block Transfer
Invalid pointers: Conforming to established C coding conventions,
library routines that need access to user packets take pointers as their
function arguments. There is no way for a called function to check
whether your program has sent it a valid pointer. Therefore, the
programmer is solely responsible for sending valid pointers to the
library routines. If the pointer arguments don’t point to proper packets,
the program performs incorrectly or crashes, possibly locking up the
host computer.
Queueing
a Block T
ransfer
To start a BT, you store the needed fields (length of data, plus the actual
data for a write BT) in the packet and then call the bt_que routine. If you
prefer, you can use bt_read and bt_write. Those macros compile into
calls on bt_que but let you omit one function argument from your
program.
Once the request has been queued, your program must check periodically
to see whether the request has finished; see ”Polling for Completion” in
this chapter.
8-4
Page 95
Chapter 8
Block Transfer
bt_que
Use this routine to initiate a BT. This routine adds a BT to the pending list
and interrupts the scanner to pass it the command.
Calling sequence:
status = bt_que(command,
addr
ess, &packet);
Arguments:
command: an integer, either C_BT_READ or C_BT_WRITE.
address: an integer, the module or slot address (0–127), formed by
multiplying the rack address (0–7) by 16 and adding the slot address
(0–15). Equivalent arithmetic would be rack times 16, plus group times
2, plus 1 for right–hand slot or 0 for left–hand slots.
packet: a pointer to a QBT structure where you have filled in the
length of data (and the data, for a write BT).
Returned values:
error status, OK if the request was successfully entered in the queue or
NOT_OK if the queue was full or the request was invalid. This is the
status of queuing the request, not of executing it. Your program can
determine the latter status by examining the qbt_stat field in the packet.
Use this routine to initiate a read or write BT. These macros compile as
references to bt_que, but save typing one argument.
Calling sequence:
status = bt_read(address, &packet);
or
status = bt_write(address, &packet);
Arguments:
same as the last two of bt_que above.
Time
to
Completion
Returned values:
same as for bt_que above.
The factors affecting the time to empty the scanner’s BT queue are as
follows. They are roughly in descending order of importance.
The number of BTs queued to the same adapter. (Note: A single
adapter, containing more than eight slots and using single slot
addressing, appears to the scanner as two distinct adapters. In this case,
the lower eight slots belong to the first apparent adapter.)
The number of BTs queued to the same module.
The number of times an adapter appears in the scanner’s scan list.
The length of the scanner’s scan list.
The number of words of BT data to be exchanged.
The baud rate.
8-6
Page 97
Chapter 8
Block Transfer
Timing Formula
In the following formula, we assume that the module is ready to perform a
transfer when asked, as is frequently true. (If a module is not ready to
perform a BT when asked, then the time for it to get ready must be added
to the total time.
T = (Effective Number of Scans) x (Scan List Length) x (Time per Scan)
+ (Number of BTs) x (Time per BT) + ((Number of Words)
x (Time per Word))
where T is the time it takes to complete all block transfers that are queued,
given the constraints of the formula.
Effective Number of Scans: If each adapter is in the scanner’s scan list
only once, and no module has more than one BT queued to it, then the
effective number of scans is the largest number of BTs queued to any one
adapter, plus one. For complete details, see the “Number of Scans” section
below.
Scan List Length: The number of adapters in the scan list.
Time per Scan: The time required to scan an adapter depends on the baud
rate. At 57.6 Kbaud the time is 11 milliseconds. At 115.2 Kbaud the time
is 7 ms.
Number of BTs: The total number of BTs in the scanner’s queue.
Time per BT: At 57.6 Kbaud or 115.2 Kbaud the time is 5.0 ms.
Number of Words: The total number of words of BT data to be
exchanged. This includes all BTs in the queue.
Time per Word: At 57.6 Kbaud this time is 0.3 ms. At 115.2 Kbaud this
time is 0.2 ms.
8-7
Page 98
Chapter 8
Block Transfer
Number of Scans
The total number of scans needed to empty the scanner’s BT queue is
equal to the largest (effective) number of scans needed to service all of the
BTs queued to any single adapter. In other words, determine the effective
number of scans each individual adapter needs, then use the largest one.
The following is a procedure to determine the number of scans any
individual adapter needs. Remember that a single adapter, containing more
than eight slots and using single slot addressing, appears to the scanner as
two distinct adapters.
If none of the BTs are queued to any given module more than once, then
the number of scans is equal to the total number of BTs plus one. For
example, if four BTs are queued to four different modules, then the
number of scans needed to service all of the BTs queued to that adapter
is five. (4 BTs + 1 = 5 scans)
Polling for
Completion
If more than one BT is queued to a given module, then two scans per
BT must be used. If more than one module has multiple queued BTs,
then the number of scans needed is equal to the largest number for any
module. For example, an adapter has five BTs queued to it, two of them
going to one module and three to another. The number of scans to
service that adapter is six. (3 BTs x 2 scans per BT = 6 scans)
At this point, you know the number of scans needed to service each
individual adapter. However, for the calculation of the time to empty the
scanner’s queue, the effective number of scans is required. The effective
number of scans is equal to the number of scans divided by the number of
times the adapter appears in the scanner’s scan list. For example, if the
number of scans to service an adapter’s BTs is 11, and the adapter appears
in the scan list four times, then the effective number of scans to service that
adapter is 2.75. (11 scans / 4 entries = 2.75 effective scans).
The effective number of scans to use to determine the total time to empty
the scanner’s queue is the largest effective number of scans for any
individual adapter.
Once your program has queued a BT, you must check periodically to see
whether the scanner has finished it. (Why? The scanner interrupts the host
to pass back completion status, but this goes on in background as far as
your program is concerned. So the status in the packet seems to change
while your program is executing.)
8-8
There are two ways to poll for completion: by examining the packet and by
using the bt_done macro.
Page 99
Chapter 8
Block Transfer
Packet Check
Your program can periodically check the qbt_stat field of your packet. As
long as the field is equal to SC_PENDING, the scanner still has the BT in
its queue. As soon as the packet status changes to any other value, it is the
actual completion status passed by the scanner.
A list of status values is in ”Confirmation Status Codes” in this chapter,
but for a first approximation all that matters is whether the status is
SC_OK (successful completion) or anything else.
Ordinarily your program would do other things while waiting for the BT to
finish. You could start up other BTs, do discrete I/O, issue management
requests, or a combination of these. But at some point in your program
scan you need to test for completion of this BT: