# Introduction

## PURPOSE

This document gives an overview of the basic operation of the PAWS
panel, matrix and PSIC software. It also provides a brief description of
the major routines and the most important data structures used in the
PAWS software. Along with the description of the data structure, some
information on how it is used in the system is provided. This document
also provides an overview of the messages used by the PAWS software.
Understanding the data structures and their use is crucial to trouble
shooting and modifying the PAWS software.

This document also covers the operation of the program PDS, the tool
used to inspect the PAWS data structures.

The final section gives instructions on updating the PAWS panel, matrix,
and PSIC code.

##  GENERAL OPERATION

The Paging and Area Warning System (PAWS) is a message driven paging
system. The main point of control for the system is the paging panel.
The central switch, also known as the matrix, handles tray operations
and audio routing based on messages that originate from the panels.

The Paging and Area Warning System offers a certain amount of
redundancy. Each PAWS has two matrices. Some areas will have speakers
driven from both central switches. Each panel is connected to both
matrices.

To simplify the system software, the matrix will not initiate any
actions, all actions performed by the matrix are the result of the
matrix processing a received message.

Likewise, the panels do not initiate any actions on their own accord.
All panel actions result from messages or panel operator inputs.

###  PANEL OPERATION

The panel software is event driven. The events that the panel software
reacts to are received messages, timers and operator actions. The event
processing is implemented by a polling loop. Serial transmission, serial
reception and the basic system timer are implemented as interrupt
handlers.

The first block of panel code initializes the microcontroller and some
of the indicators. After the microcontroller is initialized, the code
checks to see if the EEPROM in the CPU needs to be updated. Due to
certain hardware constraints, the interrupt handlers can not be run from
the XICOR EEPROM that serves as the main memory device. These routines
have to be placed in the CPU EEPROM for execution. If changes between
the CPU EEPROM and the XICOR EEPROM are detected, the new interrupt
handler code is moved into the CPU EEPROM.

After any required CPU EEPROM programming, the CPU\'s real time
interrupt is enabled. The code then initializes the panel data
structures, followed by hardware initialization. The last action before
enabling the CPU interrupt is to set up a series of tables based on the
panel type which is determined by reading two input lines that come from
the front panel of the panel chassis.

Before the software enters the main polling loop, it calls a routine to
beep. This is to draw the operator\'s attention to the panel so he can
see that the panel was reset. (There are several events that can cause
the panel to reset. These will be covered later.) In addition to
notifying the operator, the panel calls a routine to send a reset
message to the system console so that the system operators are also
aware of the panel reset. The last thing done before entering the main
polling loop is to select the test tone output. This tone appears as the
audio output of the panel. If no output were selected, the matrix would
receive random noise from the panel.

The first task of the main loop is to call a routine that resets the
CPU\'s watchdog timer. The watchdog timer will generate an interrupt if
a certain period of time passes without the timer being reset. This
feature is used to reset the panel in the event that a software bug
causes the panel to stop executing the main loop.

The next task is to fill the large buffers. The panel uses a dual UART
for communications between the panel and the matrix. The panel software
uses a pair of buffers for received data. When a byte is received, the
interrupt handler will place the byte in a small circular buffer. The
code in the main loop moves any data that is in the small circular
buffer into a large buffer. This double buffering of the received data
is forced by hardware constraints.

Because code can not be executed out of the XICOR EEPROM while it is in
a programming cycle, some code must execute from the CPU\'s EEPROM. The
XICOR programming cycle takes 10 milliseconds. Any code that can not be
disabled for 10 milliseconds must be placed in the CPU\'s EEPROM. In the
case of the panel, the real time interrupt and the UART interrupt must
be placed in the CPU\'s EEPROM. This also requires that the interrupt
table itself must be placed in the CPU\'s EEPROM, as reading the XICOR
during a programming cycle will corrupt the contents of the XICOR.

The CPU\'s EEPROM is very small, so the size of the interrupt handlers
must be minimized.

Due to addressing limitations of the microcontroller, the size of the
UART receive buffer had to be limited to 256 bytes, otherwise the size
of the UART receive interrupt handler would have exceeded the allowable
size.

While the 256 byte buffer is more than large enough to hold all bytes
received while the XICOR is in a programming cycle, during a download,
where the panel receives a new mapping from the panel buttons to trays
required, it will receive up to 128 messages that require the XICOR to
be programmed. This causes the received messages to back up in the
buffer as the messages are received faster than they can be programmed
into the XICOR. Eventually the received bytes overflow the small buffer
and configuration information is lost.

In order to prevent this from happening, the panel will drain the small
buffer, moving the received data to a large buffer, before it executes
any code that may require a XICOR programming cycle.

Before the main loop tries to assemble a message received from the A
side matrix, it will move the bytes in the side A small buffer to the
side A large buffer and the bytes in the side B small buffer to the side
B large buffer. This insures that the small buffers will not overflow
while any received message is being processed. After the two small
buffers have been drained, the main loop calls a routine that attempts
to assemble a message from the A side matrix.

After attempting A side message assembly, the main loop will once again
drain the two small buffers before calling the code to assemble a side B
message.

After assembling and processing any waiting messages, the code calls a
routine to see if any timers have expired. Many operations the panel
performs have time limits to keep the panel code from hanging. Any time
one of these operations is started, a timer is started as well.

After processing any expired timers, the main loop checks the download
flag. This flag is set whenever the panel receives a download lock
command. During downloads, configuration information is sent to the
panel, which programs it into the XICOR EEPROM. During a download, the
panel disables any operator input. When the code sees the download flag
set, it skips the code that would normally check for changes in zone
selections, microphone state and area warning changes.

If the panel is not locked due to a download lock, the code calls DO_ZS
to handle any changes in zone selections. It then calls MK_CK to see if
there are any changes in microphone state. (Keyed or Unkeyed.)

The main loop code then checks a flag to see if the code is running on
an admin panel. On the admin panel, there are three sources for audio,
the normal microphone, a gooseneck microphone that is controlled by a
foot switch, and an aux audio input for playing prerecorded messages. If
the code is running on an admin panel, the main loop code checks for
changes in the gooseneck microphone state. (The aux audio input is
controlled by an actuator/indicator on the front panel.)

The final action is a call to AW_CK. This routine handles changes in the
area warning state of the system. (As an example, someone could activate
a local area warning pull station while a download is occurring. The
area warning map would be sent to the panel, which would store it in
RAM, and when the download was complete, the panel would run AW_CK, and
pick up the stored map.)

#### Microcontroller Initialization

The first thing done for microcontroller initialization is to set up the
stack pointer so that subroutines can be called. Next we clear the block
protect flags. This allows us to program the CPU EEPROM. Clearing the
block protect flags must be accomplished within the first 64 cycles
after coming out of reset. If this operation is delayed, the CPU
hardware will lock out clearing the block protect register.

Next the option register is set to enable slow clock resets, and the
watchdog period is set to 1 second.

The microcontroller has circuitry to detect the fact that the clock
input to the chip is lower in frequency that a certain minimum. If this
condition is detected, the microcontroller will go through a reset.

The watchdog timer is a timer that counts up with each clock. When it
reaches overflow, a reset is generated. There is a programmable
prescaler that drives the watchdog timer counter. We set the prescaler
for divide by 64, which yields a watchdog timer period of a little over
a second.

After setting the options register, the code sets the chip select
register. The microcontroller is capable of generating several chip
select signals for external chips. We select two I/O chip select lines
to be active low during the address valid phase of bus cycles. The
general select line is also programmed as active low, and is mapped to
the lower 32K of the memory map. This line is used to select a 32K RAM
chip on the panel card.

The clock stretch register is set to add 3 extra cycles for bus accesses
via the first I/O chip select. The second I/O chip select has one extra
cycle added. The general chip select and the program chip select do not
have any additional wait states added.

The chip select control register is programmed to enable both I/O chip
selects as active low. The PROG chip select is enabled, and mapped to
the upper 32K of the memory map. This line is used as the chip enable
for a 32K XICOR EEPROM on the panel card.

After setting up the chip select registers, the code will record the
contents of the RST variable. This value is used to indicate the reason
the CPU reset. The value is placed in a CPU register by the code that is
run by the reset vector. This value is moved into a RAM location after
the chip select lines have been set up. This location can be read using
the PDS program to determine the reason for the last reset the panel
experienced. This is only a single location, so information is only
recorded for the last reset. Information about prior resets are lost.

Next the code sets the lower nybble of port A as input. The upper nybble
is set to outputs. Bit 0 of port A is used to sense the keyboard encoder
data available line. The zone select switches on the front of a panel
are connected to a keyboard encoder chip that handles scanning and
debouncing. When it has a valid key press, it signals it by driving its
data available line.

The microphone PTT line is connected to Bit 1 of port A. This line is
used to sense the position of the microphone Push To Talk line. Debounce
of this signal is handled by a 14490 chip that sits between the
microcontroller and the microphone PTT switch.

Bit 2 of port A is used to sense the position the area warning key
switch. This switch is only present on Area Warning panels. This key
switch is used to enter and exit area warning mode. When an Area Warning
panel is in area warning mode, all pages are processed at a higher
priority. This signal is debounced by the 14490 chip.

Before the area warning tone can be activated from an area warning
panel, the panel must be placed in the area warning mode by turning the
area warning key to the on position. This will clear all selected zones.
The operator must then select the zones of interest.

When the panel is in the area warning mode, pages will have a higher
priority than when the panel is not in the area warning mode. This
allows the area warning panel to override other pages that may be going
to the affected zones.

The area warning tone can be turned off any time the microphone is not
keyed by depressing the guarded area warning active button.

After you turn the area warning tone off, the volume of pages to
selected zones will return to normal, but the priority of such pages
remains high.

The area warning tone is also turned off if you exit the area warning
mode by turning the area warning key to off.

Zone selections are not affected by exiting the area warning mode.

Bit 3 of port A is used to sense the position of the foot switch. This
switch is only present on Administrative panels, where it used as a PTT
switch for the gooseneck mike. This signal is debounced by the 14490
chip. (An administrative panel has two microphones, the normal front
panel microphone and a gooseneck microphone activated by a foot switch
to allow hands free operation.)

Bit 4 of port A is used to drive the reset line on the LED driver chips.
Driving this pin low will force all the actuator/indicator lamps off.
This happens once during the reset code, right after setting the port A
pin directions, then the line is left high to allow individual control
of the actuator/indicator lamps.

Port D is used to drive several special indicators, which vary with the
panel type. It is set to be an output port.

Pin 2 of port D is used to drive the Weather Warning Active lamp on
Emergency Warning panels.

On the right side of the Emergency Warning panels, near the middle of
the panel is the weather warning button. An emergency panel has a
feature not found on other panels. It is capable of activating a weather
warning tone.

With one or more zones selected, you initiate a weather warning by
pressing the weather warning button. It will illuminate and at the same
time, a weather tone will be audible in the selected zone or zones.

With no operator intervention, the tone will terminate after two
seconds, and the trays will be released two seconds later. (Four seconds
after the weather warning button was pressed.)

The reason for the delay in the tray release is to give the panel
operator time to initiate a voice page after the weather warning tone
completes.

Normally the panel operator will press the weather warning button, and
wait for the weather warning indicator to go off, then key the
microphone and issue the verbal warning.

It is possible to terminate the weather warning tone early by depressing
the microphone push to talk button before the weather warning indicator
goes off. If this is done, the weather warning tone will be terminated
as soon as the ready indicator comes on.

When an Emergency Warning panel operator is ready to make a weather
announcement, he will activate the weather warning tone by pressing the
weather warning button. This causes the panel to request the matrix to
route the weather warning tone generated on the matrix secondary card to
the trays selected on the Emergency Warning panel. This tone is two
seconds in duration. When the weather warning tone is activated, the
Weather Warning lamp comes on. After two seconds, the Weather Warning
lamp goes off, which indicates to the operator that he can proceed with
the weather announcement.

Pin 2 of Port D drives the Area Warning Active lamp on Area Warning
panels.

On Area Warning panels, this lamp indicates that some trays in the
system are in area warning mode. Area warning mode can be initiated from
and area warning panel or from a local area warning pull station. When
the system enters area warning mode, the matrix broadcasts a map of
trays that are in area warning mode to all the panels. The panel will
store this map and see if any zones on that panel contain any of the
affected trays. If any trays on the panel are affected by the area
warning, the affected zones will blink, and the Area Warning lamp will
also blink. If no zones contains any of the affected trays, the zones
will not blink, and the Area Warning indicator will not blink. On an
Area Warning panel that initiates an area warning, this lamp will
illuminate and not flash.

On Administrative panels, this line drives the Aux Audio Input Active
lamp.

When the Aux Audio input is used as the source for a page, This lamp
will illuminate. It serves the same purpose as the microphone keyed
indicator, except for the Aux Audio input.

A page can also be performed using the auxiliary audio input. An audio
source must be connected to the auxiliary input on the rear panel. To
initiate a page using the auxiliary audio input, press the aux input
enable actuator/indicator, which is located on the left side of the
panel near the center.

The aux input enable actuator/indicator should illuminate. The balance
of the page is identical to using the normal panel microphone with it\'s
push to talk switch.

Pressing the aux input enable actuator/indicator while it is illuminated
will terminate the auxiliary audio page.

Pin 2 of Port D is not connected on Operational panels.

Pin 3 of port D is used to drive the Area Warning Active lamp on
Operational panels, Emergency Warning panels, and Administrative panels.

On these panels, this lamp indicates that some trays in the system are
in area warning mode. Area warning mode can be initiated from and area
warning panel or from a local area warning pull station. When the system
enters area warning mode, the matrix broadcasts a map of trays that are
in area warning mode to all the panels. The panel will store this map
and see if any zones on that panel contain any of the affected trays. If
any trays on the panel are affected by the area warning, the affected
zones will blink, and the Area Warning lamp will also blink. If no zones
contain any of the affected trays, the zones will not blink, and the
Area Warning indicator will not blink.

Pin 3 of port D is used to drive the Local Area Warning Active lamp on
Area Warning panels.

When a local area warning pull station is activated, the matrix will
broadcast a message indicating that the system is in local area warning
mode. It then broadcasts a map of all the zones that are in area
warning. Most panels will ignore the local area warning on and off
messages, but the Area Warning panels have a special indicator not
present on other panel types, the Local Area Warning Active indicator.
On the Area Warning panels, this lamp is controlled by the local area
warning on and off messages.

Unlike most other panels, area warning panels can differentiate between
a local area warning and an area warning initiated by an area warning
panel. In the case of an area warning panel initiated area warning, the
area warning active indicator will be lit. In the case of a local area
warning, the local area warning tone active indicator will be lit, along
with the area warning active indicator.

Pin 4 of port D drives the audio warning device on all panels.

This device is used to emit a beep to draw the operator\'s attention
whenever a condition occurs that the operator needs to be aware of.

Each panel is equipped with an audible alarm which notifies the operator
of important changes and helps differentiate errors. The operator has
two methods of control over this alarm. A switch can be used to enable
and disable the alarm. In addition, there is a shutter assembly on the
front of the alarm which can be rotated to adjust the volume level of
the alarm.

It is strongly advised that the alarm be left enabled at all times.
Often the only indication the panel operator will receive that something
has gone wrong with a zone selection or page operation is a short beep.

In addition to indicating the difference between success and partial
success on these operations, the audible alarm is used to signal the
operator that an asynchronous event has occurred.

#####  Asynchronous Events

Several things can happen to the system that may interrupt or prevent
certain page operations. These do not occur as a result of any action on
the panel operator\'s part. These are referred to as asynchronous
events. Many of these events are signaled to the operator.

The asynchronous events that the operator is notified of are:

1.  Cutoff

2.  Area Warning transitions.

3.  Resets

4.  Downloads

###### Cutoff

One of the asynchronous events that can occur is a cutoff. This happens
when a page is in progress and a higher priority page request is
received by the central switch. In this event, the conflicting tray will
be taken away from the panel that is currently using it for a page, and
will be given to the panel requesting the higher priority page. (More
than one tray may be taken away. It is possible that ALL trays will be
lost.)

When this occurs, the central switch sends a message to the panel that
lost the tray or trays, telling it that it has lost one or more trays.
The panel will notify the operator by turning the busy/cutoff lamp on,
and beeping to draw the operator\'s attention to the panel.

When this happens, the panel operator knows that the page was
interrupted and she should attempt the page again later.

######  Area Warning Transitions

Because activation of area warning mode may make trays unavailable to
the rest of the system, all panel operators are notified when the system
enters or leaves the area warning mode.

There are two ways the system can be placed in the area warning mode.

Area warning panel operators can make area warning requests of the
central switch. This is the highest priority operation that can be
initiated on the system, and any required trays will be given to the
requesting area warning panel.

Certain areas of KSC have local alarm pull stations that can be operated
by personnel in the area. These activate warbler alarms and beacons in
the affected areas. In this case, the trays are still available for use,
but should be reserved for important traffic such as evacuation
instructions.

In both cases, all panels will be notified of transitions into and out
of area warning mode.

When the system enters the area warning mode, the central switch sends a
message to each panel, indicating which trays are affected by the area
warning. The panel will start blinking the area warning lamp on the
panel. It will also blink any zone that contains an affected tray. Since
this can happen at any time, the panel also beeps to attract the
operator\'s attention.

When the area warning is terminated, the central switch will send a
message to each panel indicating that the area warning is over. The
panel will turn the area warning lamp off, the zones will stop blinking,
and the panel beeps to draw the operator\'s attention to the change.

It is possible for there to be more than one area warning active at a
time. Each time an area warning is initiated or terminated, a new list
of area warning trays is sent to each panel. When the panel receives a
new area warning tray map, it starts blinking the affected zones, and
beeps to draw the operators attention to the change in the panel\'s
state.

If a panel does not have any zones that contain any of the area warning
trays, the panel will still beep when it receives a new map, but none of
the zones will blink, and the area warning lamp will not blink.

#######  Area Warning Panel Initiated Area Warning

When an area warning is performed from an area warning panel, several
things happen in the affected areas. As long as area warning mode is
active, the affected trays will produce higher audio levels. Voice pages
can be alternated with an area warning tone. In addition, some areas
will have local beacons activated.

####### Pull Station Initiated Area Warning

When a pull station is activated, the central switch will detect the
activation and notify the panels. Local beacons are not controlled by
the PAWS, it only notifies panel operators that area warning has been
activated. In general, there is no way to tell which of the two area

warnings is occurring from any given panel. (Area Warning panels can
tell these apart.)

####### Resets

The panels can be reset for a number of reasons. They are:

1.  Power on.

2.  Software faults.

3.  Remote command.

Any time a panel is reset, it sends a reset notification to the system
consoles and beeps to let the operator know that something happened. (It
is likely the operator needs to reselect zones.)

When the panel is reset, all zones will be deselected. All information
about any zones affected by area warnings will be lost. (Tray
assignments and priority for all zones is retained as this information
is stored in EEPROM, a nonvolatile memory, in the panel.)

######## Power On

Every time a panel is powered on, it goes through a power on reset. The
will beep when it comes out of reset.

######## Software Faults

A variety of software faults can cause a panel reset. This insures that
if a software bug locks up the panel, it will be reset, allowing a rapid
recovery. After coming out of reset, it will beep.

######## Remote Command

The panel can be reset by sending a command from the system consoles.
The panel will perform a jump to start when it receives this command. As
it comes up, it will beep.

####### Downloads

As mentioned earlier, when the system console needs to download a new
configuration to a panel, it will lock the panel. When the panel is
locked, it beeps to draw the operator\'s attention. If the system
console fails to unlock the panel within 10 seconds, the panel will beep
and unlock itself. There is no beep when the system console unlocks the
panel is less than 10 seconds.

Pin 5 of port D is used to drive the Alarm Enabled lamp on all panels
except the Operational panel. On most panels, enable/disable of the
audio alarm is under software control. On the operational panel it is
controlled by a mechanical switch on the front panel. This is why the
Operational panel does not have an alarm enabled lamp, this is indicated
by the position of the alarm enable switch.

After port D is set to output, all lines are driven low to turn all the
lamps off.

Port G is used to drive several special indicators. It is set to be an
output port.

Pin 0 of port G drives the Mike Keyed lamp on all panels.

When you press the microphone Push To Talk (PTT) button, the panel will
light the mic button and send a page request to the central switches,
asking that the microphone audio be routed to all trays associated with
any selected zone.

After making the announcement, release the PTT button. The panel will
turn off the mic lamp and send a message to each central switch
releasing the trays so that others may use them.

Pin 1 of port G drives the Lamp Test indicator on all panels except the
Operational panel. Operational panels do not have a lamp test button,
and can not perform a lamp test.

A lamp test can be performed by briefly pressing the lamp test button.
Zone selections are not affected by a lamp test. If a zone was selected
before a lamp test, it will be selected when the lamp test completes.

Lamp tests are performed in two parts. During the first phase, the zone
select lamps are tested. During the second phase the rest of the lamps
are tested.

In the first phase of a lamp test, all zone select buttons are lit for a
few seconds. During this time, the rest of the panel lights (with the
exception of the power lamp) will be off.

After the zone select buttons have been lit, they are turned off, and
all the other lamps on the panel are turned on for a few seconds. During
this period, the audible alarm is also activated.

After both phases of the lamp test are completed, all zone select
buttons are restored to the state they were in before the lamp test. The
lamp test indicator will be off.

Pin 2 of port G drives the Busy/Cutoff on all panels.

One of the possible results when attempting a page is a busy. This
occurs when one or more of the requested trays was being used by another
panel for a page. This is referred to as a busy failure. In this case,
the page was not heard anywhere. When this happens, the Busy/Cutoff
indicator will illuminate and the panel will beep. The Busy/Cutoff lamp
will go off when the page attempt is terminated. (When the microphone
PTT is release.)

One of the asynchronous events that can occur is a cutoff. This happens
when a page is in progress and a higher priority page request is
received by the central switch. In this event, the conflicting tray will
be taken away from the panel that is currently using it for a page, and
will be given to the panel requesting the higher priority page. (More
than one tray may be taken away. It is possible that ALL trays will be
lost.)

When this occurs, the central switch sends a message to the panel that
lost the tray or trays, telling it that it has lost one or more trays.
The panel will notify the operator by turning the busy/cutoff lamp on,
and beeping to draw the operator\'s attention to the panel.

When this happens, the panel operator knows that the page was
interrupted and she should attempt the page again later.

The Busy/Cutoff lamp will go off when the page is terminated. (The
microphone PTT is released.)

Pin 3 of port G drives the voice ready lamp on all panels.

The voice ready lamp is the main page request indicator. When a page is
attempted, the operator should watch the voice ready lamp to see what
happens.

If the ready lamp turns on and the panel does not beep, all trays
associated with that page are passing audio from the page.

If the panel beeps but turns the ready lamp on, at least one tray is
passing audio, and at least one tray failed the test and is not passing
audio. This action indicates that the page was heard in only some of the
requested zones. This will be referred to as a partial failure.

If the panel beeps and the ready lamp remains off , this indicates that
the page was not heard anywhere.

#### CPU EEPROM Checks

The main memory device in the panel is a 32K XICOR EEPROM. This contains
the configuration information, as well as containing the majority of the
code. Due to the nature of the XICOR EEPROM, you can not perform any
reads from the XICOR while it is in a programming cycle. The programming
cycle can take as long as 10 milliseconds. During this period, the CPU
must be running code that resides somewhere besides the XICOR chip. Any
operation that can not be suspended for 10 milliseconds needs to reside
in a different location.

In our case, this turns out to be the interrupt handlers, the interrupt
vector table and the code that is used to program the XICOR.

The microcontroller used in PAWS has a small amount of EEPROM built into
it. In order to allow the system to program configuration information
into the XICOR, certain code had to be moved to the CPU EEPROM. The code
that resides in the CPU EEPROM consists of the code to program the
XICOR, the DUART interrupt handlers, the real time clock interrupt code,
and the interrupt vector table.

Since the vector table resides at the top of the memory map, all of the
indicated code must reside there. Since the XICOR chip is also mapped to
the top of the memory map, the code can be assembled to reside at the
top of the memory map. Only one block of memory can actually reside in
the top block of the memory map, the CPU EEPROM or the XICOR EEPROM.
Since the CPU EEPROM is an image of the XICOR EEPROM, the system will
run with either block mapped to the top.

When one block is mapped to the top block, the other block is no longer
accessible to the controller.

It was desired that from a maintenance standpoint, no special operations
would be required when upgrading the code in any of the PAWS units. This
required a rather involved method of updating the CPU EEPROM code.

If the new code in the XICOR has any changes to the interrupt handlers,
the vector table or the code that programs the XICOR, it will not appear
in the CPU\'s memory map as the CPU EEPROM is mapped to this region.

Some method had to be found that would allow the CPU to detect the fact
that the code in the top of the XICOR did not match what was programmed
into the CPU EEPROM. The method used is fairly simple. All of the code
that ends up in the CPU EEPROM is contained in a single file, uart.asm.
We run the CRC of the source file uart.asm, and this CRC is recorded in
two locations in the XICOR EEPROM. One of these locations is at the top
of the XICOR and the other is much lower.

If the contents of uart.asm changes, then the new CRC is recorded in the
two locations in the XICOR EEPROM. Since the CPU EEPROM is mapped to the
highest block, the top CRC will be the one programmed into the CPU
EEPROM while the lower one will be the new CRC in the XICOR. If these
two don\'t match, then the code in the CPU EEPROM needs to be updated.

#### CPU EEPROM Programming

At this point, things get a little tricky. The contents of the top of
the XICOR EEPROM need to be copied into the CPU EEPROM, but you can\'t
see the contents of the top of the XICOR as it is masked by the CPU
EEPROM.

There is a register that controls where the CPU EEPROM appears in the
memory map. In order to copy the top of the XICOR contents to the CPU
EEPROM, we have to move the CPU EEPROM lower in the memory map. After
the CPU EEPROM has been moved, we can copy the contents of the top of
the XICOR to the CPU EEPROM. After we have programmed the correct
contents into the CPU EEPROM, we need to move the CPU EEPROM back to the
top of the memory map.

These operations occur in a sequence of steps with CPU resets separating
them. This is required because in order to change the address the CPU
EEPROM is mapped to, you must change the register contents, and then
reset the CPU because the mapping address is latched early in the reset
cycle and cannot be altered. In other words, in order for the CPU EEPROM
is actually be mapped to the new address, the CPU must go through a
reset. The whole sequence is:

After the CPU finishes the microcontroller register configuration, it
will check the address the CPU EEPROM is mapped to. If it is mapped to
the normal running address, then the code will check the two CRC\'s to
see if they match. If the two CRC\'s match, then the system is ready to
run. The code disables changes to the CPU EEPROM contents or location
and then returns to the next task.

If the two CRC\'s don\'t match, then the CPU EEPROM needs to be moved
lower in the memory map, and the CPU needs to be reset.

The code will disable changes to the CPU EEPROM contents, and then it
erases the config register, which is the register that controls where
the CPU EEPROM is mapped to. At this point the CPU EEPROM is mapped to
\$fe00 to \$ffff because an erased EEPROM cell contains all 1\'s.

The code now programs the contents of the config register to map the CPU
EEPROM to \$0e00 - \$0fff. After the programming cycle is complete, all
changes to the config register or CPU EEPROM contents are disabled, and
the code traps to a loop until the watchdog timer causes a reset.

After coming out of the prior reset, the CPU will eventually end up at
PGM again. This time, the config register contains CPU_VFY, indicating
that the CPU EEPROM is mapped low. The code then calls EC_OK to see if
the contents of the CPU EEPROM matches the high block of the XICOR
EEPROM. EC-OK compares each byte in the CPU EEPROM to the corresponding
byte in the XICOR EEPROM. If any byte doesn\'t match, EC_OK returns
FALSE. At this point, we know that the contents don\'t match, because at
least the CRC values don\'t match. Because EC_OK returns FALSE, the code
protects the contents of the config register, then erases the contents
of the CPU EEPROM. After the erase is complete, the code will program
each byte from the top of the XICOR EEPROM into the CPU EEPROM. Before a
byte is programmed, the watchdog timer is reset in order to insure that
the system doesn\'t reset during CPU EEPROM programming. After all bytes
have been programmed, the CPU traps to a loop and waits for the watchdog
reset.

After coming out of reset this time, the code ends up PGM again. This
time, the config register contains CPU_VFY, so the code call EC_OK.
Since we just programmed the CPU EEPROM from the XICOR EEPROM, the
contents will match and EC_OK returns TRUE. This causes MCE to protect
the CPU EEPROM and erase the config register. After the config register
is erased, it is programmed with CPU_RUN, which locates the CPU EEPROM
in the top of the memory map. The code then traps to an endless loop and
waits for the watchdog reset.

After the CPU comes out of reset this time, it ends up in PGM. The
config register indicates that the CPU EEPROM is mapped to the top of
the memory map. The code calls MC_OK to see if the two CRCs match. Since
they do, PGM returns. After the return from PGM, the mainline code
enables the real time clock interrupt.

#### Data Structure Initialization

First off the code initializes several simple variables. RB_MAX is set
to the maximum number of bytes that we will process in a single attempt
to assemble a message. The limit is required in order to keep the code
from hanging on a noisy line that is generating a constant stream of
garbage.

Next TRC is set TRUE. This will cause certain errors and sequences to be
announced.

#####  Panel Mode

A panel can be in one of two states, hot or cold. A hot panel is one
that is being viewed by one of the system consoles. A hot panel will
announce all changes to it\'s configuration by sending messages to the
system consoles.

When a system console calls up a display of a panel, it requests the
current state of all the lamps on the panel, and sends a command to make
the panel hot. This allows the console to display the initial state of
the panel, and track all changes so that the console display always
matches the actual panel.

When a panel is hot, every time a lamp goes on or goes off, a message is
sent to the systems consoles. This allows the system console to update
it\'s display of the panel so that the system console tracks the
appearance of the actual panel.

When the system console is finished looking at the panel, it sends a
cold command to the panel. A cold panel does not send change
notifications to the system consoles.

Panels are normally left cold to keep system traffic down. There can be
128 panels connected to a matrix. The matrix has a single 9600 baud link
to each system console. This link is the bottleneck that limits systems
performance. In order for the system to be as robust as possible,
traffic on this link is kept to a minimum.

When reset, the panel is marked cold by setting PMOD to PCLD.

#####  Locks

After setting the panel cold, a set of lock flags are cleared. These
locks are for download on side A, download on side B and zone selection
lock. The zone selection lock is only used on Emergency Warning panels
for weather warning tones. During a weather warning tone activation,
this flag is set. This will prevent any zone selections from being
processed while a weather warning tone is active. After the weather
warning tone completes, and the hold time expires, the panel sends a
tray release command and clears this flag.

The hold time was added to keep the trays pulled in during the period
from the end of the weather warning tone to the request from the
operator depressing the microphone PTT.

The download locks prevent any panel changes from occurring while the
system consoles are loading a new configuration to the panel. When the
systems consoles have a new configuration for a panel, they send a lock
request. If no panel operations are in progress, the panel will set the
download lock, start a download release timer, and send a download lock
response to the system console.

The download lock prevents the software from processing zone selections,
microphone checks, and area warning changes. Any area warning changes
that occur will be recorded, but the panel display will not be updated
to reflect the changes until the panel comes out of download lock.

#####  Error Tables

The panel software maintains several tables that contain counts of
various errors that have occurred. These tables can be read using PDS.

Every time a certain type of error occurs, the count for that error type
is incremented. The count will stop before it rolls around to 0. One
table tracks various software errors. Another tracks the health of the
serial links between the panel and the matrix. A third table tracks
errors that can occur while the interrupt handlers are running. A reset
will clear the error counts by calling EC_INIT. The error counts can
also be cleared under software command.

#####  UART Data Structures

The DUART uses two small circular queues for buffering received
characters. These buffers are set to empty and the insertion and
extraction indices are set to the first slot. The transmit buffers are
marked as empty and the transmitters are marked as idle.

#####  Console Message Buffers

The system contains a buffer that is used to hold messages that are
being sent to the matrix or system console. The buffer is marked as
being free.

#####  Message Assembly Structures

Messages are assembled from a stream of received bytes and validated by
a small state machine. A structure maintains the current state for
message assembly as well as a small push back buffer. In the event that
error is detected during message assembly, the first byte of the message
is discarded, and the code searches through the remaining bytes for the
next start marker. If one is found, it, and all of the following bytes
are moved to the push back buffer. Bytes will always come from the push
back buffer first before the code goes to the receive buffers for input.

The message assembly state is set to looking for Start Of Message. (SOM)
The push back buffer is set to empty and the push back buffer extraction
index is set to 0.

#####  Keyboard Initialization

The keyboard indicator only provides indications of key presses. The
software in the panel must track the actual state of the \"key\" (On or
Off) All the zone select switches are marked as being off. All the
special switches, except the alarm enabled switch are marked as off.
(The alarm enabled switch is marked as on.) The buzzer duration is set
to 0. (This is the audio indicator used to beep to gain the operator\'s
attention. The duration of the beep is controlled by the buzzer
duration.)

The microphone prior state is set to unkeyed. The area warning state is
marked as inactive. The software also records that no pages are in
progress.

#####  Lamp States

The panel maintains the state of each lamp, on or off. This is required
because there are several things than can cause a lamp to blink, and the
system needs a way to restore the original state of the lamp after these
conditions clear.

All of the zone lamps are turned off, and marked as being off. The
special flags for each zone are also cleared. At the present, there is
only one special flag. This flag is used to indicate that the zone
selection occurred during area warning tone. This requires special
processing of the matrix response.

The software then turns off, and marks off, the following indicators:

-   Mike Keyed

-   Voice Ready

-   Busy/Cutoff

-   Area Warning

-   Aux Audio

-   Lamp Test

-   Audio Indicator

The alarm enabled indicator is turned on, and marked as being on.

#####  Circular Queue

The panel code uses a circular queue to maintain a list of zones that
are pending on. When an operator selects a zone, the panel adds the zone
to a pending on list, starts a timer, and sends a tray test request to
the matrix. The panel looks at the timer for the zone at the top of the
circular queue, and when the timer expires, it processes the responses
to the tray test request.

The pending on circular queue is initialized to empty, and the insertion
and extraction indices are set to 0.

##### Map Initialization

Each zone select button has an A side list and a B side list of trays
associated with that button. The panel builds a pair of global tray maps
by taking all the trays for all selected zones and adding them to the
global tray map for each side. (A and B)

When a page is attempted, the global tray map is sent to the matrix as a
page request.

The global tray maps are initialized to empty by zeroing out the tray
map and recording their status as empty.

The panel also searches the zone maps and makes a record of all the
empty zone maps. This map of empty zone maps allows the panel code to
perform certain operation faster.

##### Area Warning Initialization

When the system goes into area warning mode, each matrix will send a map
of the trays that are in area warning mode to every panel. Each panel
maintains two maps of the trays in area warning, one for the A side, and
one for the B side.

Using these maps, the panel will then build a map of zones that contain
trays that are in area warning mode.

When the panel is reset, it zeros out the area warning tray maps for
both sides and zeros out the maps of zone containing trays in area
warning. The system maintains a count of the number of zones affected by
area warning, these counts are zeroed at this time.

##### Large Buffer Initialization

The dual UART code buffers received characters in a small circular
queue. These queues are not large enough to prevent lost messages during
a download where the panel may spend most of it\'s time programming
EEPROM locations, so there are two large circular buffers maintained
that provide the bulk of storage for received data. The buffers are
initialized to empty, and the insertion and extraction indices are set
to 0. Before entering a section of code that result in EEPROM
programming, the contents of the small buffers are moved to the large
buffers so there will be enough room to buffer all received data during
the EEPROM programming.

##### Re-page Initialization

The administration panel is used to play prerecorded messages as
announcements. Some of these announcements are fairly long, increasing
the chance that they may be cutoff by higher priority pages. When this
happens, the administration panel will periodically re-send the page in
an effort to get the trays back. This feature is only active for aux
audio pages. When the re-page succeeds, it will stop trying to get the
trays back. After a reset, the panel clears the re-page flag and zero
out the re-page timer.

##### Run Time Initialization

The panel maintains a record of the amount of time it\'s been running
since the last reset. This is a 32 bit count that is incremented about
once a second. (The time period is actually a little over one second.)
This can be read using PDS. When troubleshooting a panel problem it will
often be helpful to look at the reason for the last reset, and look at
SSS (Seconds Since Starting) to see how long ago the reset occurred. If
the panel is resetting (other than power on resets from being turned off
and on) you will need to start tracking down the failure.

#### Hardware Initialization

Early in the reset cycle the microcontroller hardware is initialized,
which also initializes several of the indicators on the panel, but there
are other harware resources that need to be initialized after some of
the data structures have been initialized.

#####  Real Time Counter Initialization

All of the timing in the panel is derived from a 4 millisecond real time
clock interrupt. Each real time interrupt bumps a real time interrupt
counter. In the main loop, any real time timer interrupts that have
occurred are run through the software based timer chain. This allows us
to defer timer processing when busy without dropping any timer ticks.

The real time clock interrupts go into a tick counter which is used for
short duration times. This timer overflows into a click counter for
longer durations. The click timer overflows into a \"seconds\" counter
for even longer durations. The \"seconds\" are also recorded as a 32 bit
elapsed time.

The actual implementation bumps the tick count (TICKS) in the real time
interrupt handler. These are then \"moved\" into the real time interrupt
count (RTI_CT) one at a time in the main line. This insures that all
possible \"times\" actually occur, even if they are not as far apart as
they should be. Each RTI_CT represents 4 milliseconds. After processing
any tasks that were due to run at that tick, the code bumps the
fractional click count.

After 16 fractional clicks, the actual click count (KLIKS) is bumped,
and then any tasks due to run at that click are processed. Each click is
64 milliseconds, which gives a maximum time of a little 16 seconds for
click based timers. After processing the click based work, the
fractional seconds count is bumped. There are 16 clicks in a \"second\"
so the system\'s seconds are actually 1.024 seconds each. When the
fractional seconds count reaches 16, the seconds based tasks are run and
the seconds since starting count is bumped.

Time initialization zeros the tick counter (TICKS), the real time
interrupt counter (RTI_CT), the fractional clicks counter (FRAC), the
click counter (KLIKS), the fractional seconds counter (SFRK) and the
seconds counter (SECS.)

#####  Dual UART Initialization

DU_INIT initializes the dual UART used to communicate with the matrices.
The UART is set up for 9600 baud, 8 data bits, odd parity. The receive
interrupts are enabled, but the transmit interrupts are disabled. (They
are enabled once there is something to transmit.)

#### Panel Type Tables

There are 4 types of panels, all of which operate slightly differently.
There is only one panel EEPROM, it contains the code for each of the 4
panel types. Since most of the operations are common to all panel types,
the special operations of a given panel type are based on special tests
of the panel type. Most of the differences between the various panels
have to due with the mapping between the LED drivers and the I/O
addresses and bits. This problem is handled by a set of translation
tables, each panel type having it\'s own set of translation tables. All
internal operations are done based on map numbers, which are logical
zone numbers. When required, these are translated into physical button
numbers and I/O addresses using these tables.

There are three tables in each table set. The first table is used to
translate zone numbers into map numbers. The second table is used to
translate key scan codes to map numbers. The third table is used to
translate map numbers to button numbers.

The panel code calls a routine that reads in two ID bits that come from
the front panel that identify the type of front panel connected to the
panel card. Based on this ID, the panel code will record a physical
table address in each table pointer.

The three table pointers are, the zone to map table, (ZMTAB) the key to
map table, (KMTAB) and the map to button table (MBTAB.)

#### Interrupts

After the translation tables are set, the code finally enables
interrupts in the CPU.

#### Reset Notification

Every time the panel goes through a reset, it sends a reset message to
the systems consoles. The system console keeps a record of these
messages. This allows you to detect problems before the failures are
sever enough to cause system failures.

#### Test Tone Selection

There are four audio sources on a panel card. There is the normal
microphone input, the aux audio input, the gooseneck audio input, and an
on card test tone generator. When the panel is powered up, it will
enable the test tone output. This provides a known signal to matrix
which can be used for testing and troubleshooting.

After enabling the test tone, the panel code enters the main operation
loop.

#### Watchdog Reset

The first task in the main loop is to reset the watchdog timer. The
watchdog is a counter that rolls over after about one second. When the
counter rolls over, it forces a reset. This feature is used to insure
that if the code ever gets hung in a loop, the panel will reset, which
improves the availibility of the system. The watchdog timer is reset by
writing two values to a special register.

#### Fill Large Buffers

Received characters are stored in a small circular queue by the UART
interrupt handler. This buffer is limited to 256 bytes due to
limitations on the size of the interrupt handler.

Because code can not be executed out of the XICOR EEPROM while it is in
a programming cycle, some code must execute from the CPU\'s EEPROM. The
XICOR programming cycle takes 10 milliseconds. Any code that can not be
disabled for 10 milliseconds must be placed in the CPU\'s EEPROM. In the
case of the panel, the real time interrupt and the UART interrupt must
be placed in the CPU\'s EEPROM. This also requires that the interrupt
table itself must be placed in the CPU\'s EEPROM, as reading the XICOR
during a programming cycle will corrupt the contents of the XICOR.

The CPU\'s EEPROM is very small, so the size of the interrupt handlers
must be minimized.

Due to addressing limitations of the microcontroller, the size of the
UART receive buffer had to be limited to 256 bytes, otherwise the size
of the UART receive interrupt handler would have exceeded the allowable
size.

(Using a larger buffer would require using larger instructions and more
code, which would exceed the amount of memory available for the
interrupt handler.)

While the 256 byte buffer is more than large enough to hold all bytes
received while the XICOR is in a programming cycle, during a download,
where the panel receives a new mapping from the panel buttons to trays
required, it will receive up to 128 messages that require the XICOR to
be programmed. This causes the received messages to back up in the
buffer as the messages are received faster than they can be programmed
into the XICOR. Eventually the received bytes overflow the small buffer
and configuration information is lost.

In order to prevent this from happening, the panel will drain the small
buffer, moving the received data to a large buffer, before it executes
any code that may require a XICOR programming cycle.

Before the main loop tries to assemble a message received from the A
side matrix, it will move the bytes in the side A small buffer to the
side A large buffer and the bytes in the side B small buffer to the side
B large buffer. This insures that the small buffers will not overflow
while any received message is being processed.

The large buffers provide a 1024 byte circular queue for buffering
received data. Data is moved from the small circular queue to the large
buffer by LD_BA and LD_BB, which handle the A side and the B side
respectivly. When called these routines move data from the small buffer
to the large buffer until the large buffer is full or the small buffer
is empty.

#### Message Assembly

Message assembly and processing is driven by a loop that attempts to get
a received byte and add it to the message being assembled. The loop is
counter driven to limit the amount of time the panel will spend
attempting to assemble from a given port. The loop terminates when the
maximum number of bytes have been processed, there are no more received
bytes to process, or when a message has been assembled.

The process of adding a byte is performed by PSCB. The routine attempts
to add a single byte to the message being assembled. It first checks the
push back buffer for the message. If there are any bytes in the pushback
buffer, it gets a byte from there to add.

If the push back buffer is empty, the code checks the large buffer. If
any bytes are there, it gets a byte from the large buffer to add.

If both the push back buffer and the large buffer are empty, message
assembly terminates for this pass.

If a received byte is available, an attempt to add it to the message
being assembled is performed by a state machine. If this was the last
byte of a valid message, the assembled message is processed.

There are four major phases in message assembly. The first phase is
waiting for the Start Of Message (SOM) marker. Once SOM has been
detected, the second phase is waiting for the optional data length. Once
the optional data length has been received, the code can calculate how
many more bytes appear before the end marker. The third phase is
processing the balance of the message, including the optional data and
the CRC bytes. By running the received CRC through the CRC calculation,
the results will be 0 if the message was correctly received. After
checking the CRC, the last phase is waiting for the End Of Message (EOM)
marker.

If a complete message is received and validated, the message is handed
off to the message decode/process routines.

#### Message Processing

If while assembling a message, the final byte is added to produce a
complete message, the code will call DO_SCM in order to start processing
the message. The program walks a tree of decoding routines to decode the
message and call the correct routine to actually process the message.

DO_SCM checks the destination bits in the high byte of the command to
see if the message was addressed to a panel. If the message was not
addressed to the panel, the not addressed to me error count is bumped
and the message assembly structure is reset so the system can start
assembling the next message.

After determining that the message is addressed to a panel, the code
examines the type bits in the high byte of the command. The code will
determine which type of message it is, and vector to the routine that
processes that type of message.

The message types processed on the panel include writes, processed by
PWRT, responses, processed by PRSP, requests, processed by PREQ,
commands, processed by PCMD, and announcements, processed by PANN.

If the message is not of the types processed by the panel, the message
type error counter is bumped and the message assembly structure is reset
so the system will attempt to assemble the next message.

##### PWRT

On a panel, there is only one type of write allowed, a zone list write.
If the write message low command byte is anything other than zone list
write, the write error count is bumped and the message assembly
structure is reset.

For each zone select button on a panel, there are actually three
representations. To the outside world, the button is named for it\'s
physical location on the table, which is represented by the row and
column number which are packed into a single byte in the high and low
nybble respectivily.

Because of the way the traces were routed on the front panels, there is
not a constant mapping between the button location, and it\'s
addressing, so some mappings are required.

Inside the XICOR EEPROM, there is a region set aside for each side of
each button to hold the priority and tray maps. The addresses of each
region are another way to refer to the \"button.\" While these actual
physical addresses are required for the panel code that works with zone
lists, they have little meaning outside the panel.

Internally, for consistancy, all the zones are referred to by a map
number . the map number is a logical button number that ties all the
various ways of addressing a button together.

For a zone list write, the zone number is extracted from the message and
translated to a map number. If it is not a valid zone number, the error
count is bumped, a message announcing the error is sent to both system
consoles, and the message assembly structure is reset.

After the map number is obtained, the code checks to see which side, A
or B, the message was received from. It then verifys that the panel is
in a download lock. (If not locked, the code returns, and no other
action is taken.) If the panel is locked, the code checks the contents
of the message against the current zone list contents to see if they
actually differ. If there is no difference, the code returns. If there
is a difference between the zone list contents and the message contents,
XIR_WR is called to write the message contents to the XICOR EEPROM.

##### PRSP

There are five types of responses processed by the panel, they are:

1.  Tray test response

2.  Page response

3.  Area Warning response

4.  Weather Warning Tone response

5.  Source Select response

The code will bump the response error count, send a message announcing
the error to both system consoles and reset the message assembly
structure if the response is not one of the five types processed by the
panel.

For the five types of responses processed by the panel, the response in
the message is recorded for the side the message was received from. (For
tray tests, the response is recorded in a data structure assoicated with
the zone select button.)

##### PREQ

The panel supports four types of requests; Byte read, Configuration,
Lamp State and Download lock. If the request is not one of the four
types supported on the panel, the code will bump the request error
count, send a message announcing the error to each system console, and
reset the message assembly structure.

For a byte read, the panel will extract the address to be read from the
message. The panel code then reads that memory location, and builds a
message containing the address and the contents of that address. The
message is returned to the requesting system console. This feature is
used extensivley by PDS.

After the system console has downloaded a new configuration to a panel,
it verifies that the panel contains the correct configuration. Instead
of reading the entire contents of all the buttons on the panel, the
system console computes a CRC based on what it thinks the zone select
buttons should contain, then asks for the CRC that the panel calculates
based on the contents of the zone select buttons on the panel. The panel
returns the CRC it calculates, and the system console compares it to the
CRC it calculated. If they match, the system console assumes that the
download was accomplished.

For a configuration request, the panel code will run a CRC for all the
zone select buttons. The CRC calculation starts with the panel type,
then runs the priority and tray list for each button. The order of the
calculation is controlled by a table based on the panel type. The
systems console also uses this same order when it computes what the
configuration of the panel should be.

For a lamp state request, the panel will build a bit map for all the
lamps and certain buttons and send the bit map to the requestor. If a
bit is a one, the lamp is lit, or the button is depressed. The system
console uses this map to build a representation of the panel on the
system console display when the system console calls up a display of a
panel.

Before a new configuration can be downloaded to a panel, the panel has
to be placed in a download lock. The system console will send a download
request to the panel. If there are no outstanding operations on the
panel, then the panel will return a download locked response. If any
outstanding operations are in progress, the panel will wave off the
download lock by sending a download lock reject back.

As mentioned earlier, when the system console needs to download a new
configuration to a panel, it will lock the panel. When the panel is
locked, it beeps to draw the operator\'s attention. If the system
console fails to unlock the panel within 10 seconds, the panel will beep
and unlock itself. There is no beep when the system console unlocks the
panel is less than 10 seconds.

The download request will fail if the panel is doing any kind of page,
(including weather warning tone) or if it is waiting for a response from
the matrix.

##### PCMD

The panel supports eight commands. The commands are panel hot, panel
cold, panel reset, area warning trays, local area warning on, local area
warning off, zero error counts and download unlock. If the command is
not one of the eight types supported on the panel, the code will bump
the command error count, send a message announcing the error to each
system console, and reset the message assembly structure.

###### Panel Hot

The operator at the system console can call up a display of any given
panel in the system. This display visually indicates the state of the
panel, including panel type, which zones are selected, and the state of
the special lamps. In order to keep the system console display up to
date while it is examining the panel, the panel is made \"hot.\" This is
accomplished by the system console sending a hot command to the panel.

A hot panel will send a notice to the system console every time a lamp
changes state. These messages are used to update the system console\'s
display of the panel so that the system console display tracks the
actual appearance of the panel.

When the system console display of the panel is terminated, the system
console sends a panel cold command to the panel. This causes the panel
to cease sending the lamp state updates to the system console.

(On area warning panels, any time the position of the area warning key
switch changes state, the panel will send a message to the system
console, wether the panel is hot or not. These changes appear in the
system console\'s log file.)

Lamp state change messages are only sent by hot panels in order to keep
down the number of messages the system must process. PAWS is limited by
the bandwidth of the link between the matrix and the system console, so
this traffic is kept to a minimum.

###### Panel Cold

The operator at the system console can call up a display of any given
panel in the system. This display visually indicates the state of the
panel, including panel type, which zones are selected, and the state of
the special lamps. In order to keep the system console display up to
date while it is examining the panel, the panel is made \"hot.\" This is
accomplished by the system console sending a hot command to the panel.

A hot panel will send a notice to the system console every time a lamp
changes state. These messages are used to update the system console\'s
display of the panel so that the system console display tracks the
actual appearance of the panel.

When the system console display of the panel is terminated, the system
console sends a panel cold command to the panel. This causes the panel
to cease sending the lamp state updates to the system console.

(On area warning panels, any time the position of the area warning key
switch changes state, the panel will send a message to the system
console, wether the panel is hot or not. These changes appear in the
system console\'s log file.)

Lamp state change messages are only sent by hot panels in order to keep
down the number of messages the system must process. PAWS is limited by
the bandwidth of the link between the matrix and the system console, so
this traffic is kept to a minimum.

###### Reset

Panels can be reset by the panel operator turning the panel power off
and on. Panels can also be reset by sending a reset command to them.
There are several things that can cause the panel to reset, including a
number of software and hardware faults. The actual cause for the reset
will be recorded in the RST variable, which can be read using PDS. All
of the resets will go through the same sequence of events, they differ
only in the value that gets stored in RST. Every reset goes through the
initialization sequence detailed early in this section. See 1.2.1. PANEL
OPERATION.

###### Area Warning Trays

When the system goes into area warning mode, each matrix will send a map
of the trays that are in area warning mode to each panel. The panel will
record the contents of this map, (one for each side) and then it builds
a map of zones that contain any of the specified trays.

If the panel is locked for downloading, the panel will stop processing
at this point, the rest of the operation is deferred until after the
panel comes out of download lock. If the panel is not locked for
downloading, then the lamp states are restored.

The actual blinking of the lamps is controlled by some timers and the
affected zone lists when the timers are serviced.

###### Local Area Warning On

A pull station is used to activate a local area warning from within a
area. When someone activates a pull station mounted on the wall in an
area that performs hazardous operations, an area warning tone is
generated and distributed to that area. Local beacons may be activated
as well.

When this happens, the matrix will send a local area warning on command
to all the panels in the system. Most of the panels simply throw this
message away, but the area warning panels have a local area warning
indicator that will be turned on when this command is received.

The matrix also builds a map of all the trays that are in area warning
mode as a result of the local area warning activation, and sends this
map to all the panels. This is processed by all panels so that they can
indicate which zones are affected by area warnings by blinking the
affected zones.

It is possible that there may be more than one area warning activation
in the system at any given time. Everytime there is a change in area
warning status (another zone goes into or out of area warning) the
matrix will build a new area warning tray map. If there is any change in
the map, the matrix will send the new map to all the panels.

Only the area warning panels can tell the difference between a local
area warning and a panel initiated area warning.

###### Local Area Warning Off

Because many areas can have their pull stations activated, the matrix
maintains a list of trays that are in area warning as a result of pull
station activation. When the last pull station has been turned off, the
matrix will send a local area warning off command to all the panels.

Most panels will throw this message away, but the area warning panels
will process it and turn their local area warning indicator off.

######  Reset Error Counts

The panel maintains three tables of error counts. Every time a certain
type of error occurs, the count for that error type is incremented. The
count will stop before it rolls around to 0.

One table tracks various software errors. Another tracks the health of
the serial links between the panel and the matrix. A third table tracks
errors that can occur while the interrupt handlers are running. A reset
error counts command will clear the error counts by calling EC_INIT.

For a complete listing of the errors tracked, see the following
sections:

-   2.2.12 ERROR COUNT TABLE

-   2.2.13 INTERRUPT HANDLER ERROR TABLE.

-   2.2.29 LINK HEALTH TABLE.

###### Download Unlock

Before a new configuration can be downloaded to a panel, the panel has
to be placed in a download lock. The system console will send a download
request to the panel. If there are no outstanding operations on the
panel, then the panel will return a download locked response. If any
outstanding operations are in progress, the panel will wave off the
download lock by sending a download lock reject back.

As mentioned earlier, when the system console needs to download a new
configuration to a panel, it will lock the panel. When the panel is
locked, it beeps to draw the operator\'s attention. If the system
console fails to unlock the panel within 10 seconds, the panel will beep
and unlock itself. There is no beep when the system console unlocks the
panel is less than 10 seconds.

If the panel receives a download unlock command while locked, it will
unlock that side. Each side of the panel can be locked and unlocked
independtly. If either side is locked, then the panel is locked. The
panel will not unlock until both sides have received the unlock command
or timed out waiting for the unlock command.

##### PANN

There is only one announcement handled by the panel, the cutoff
announcement. If any other announcement is received, the code will bump
the announcement error count, send a message announcing the error to
each system console, and reset the message assembly structure.

When the cutoff message is received, the response bytes are set to
indicate cutoff, in case the panel was waiting for a page request
response.

If an aux page is in progress when the cutoff message is received, the
panel will set a flag indicating that the panel should try re-paging.
The actual re-paging is based on a timer, and occurs when the panel code
services the timers.

In the re-page, the panel resends the original page request. If the tray
that was taken away and caused the cutoff is free, the matrix will give
it back to the administrative panel, and the administrative panel will
clear the re-page flag.

If the administrative panel doesn\'t get the tray back, it keeps trying
until it gets the tray, or the page completes. re-paging only occurs on
an administrative panel, and only for aux pages.

If the panel is in download lock, or not keyed, the message assemble
structure is reset. (The message is just thrown away.)

If no special processing is required, the panel will turn the voice
ready indicator off, the busy/cutoff indicator on, and the panel will
beep.

#### Timer Processing

All of the timing in the panel is derived from a 4 millisecond real time
clock interrupt. Each real time interrupt bumps a real time interrupt
counter. The main loop calls CK_TMR, which takes any real time timer
interrupts that have occurred and runs them through the software based
timer chain. This allows us to defer timer processing when busy without
dropping any timer ticks.

The real time clock interrupts go into a counter (TICKS) which just
buffers the timer ticks in case the software is too busy to process the
real time clock interrupts all the way through the timer chain. CK_TMR
will copy the tick count into a temporary variable and zero TICKS.

CK_TMR nows runs a loop where each \"tick\" is added to the real time
interrupt count. (RTI_CT) RTI_CT is incremented. After incrementing
RTI_CT, CK_TMR will call TM_TST, which is the routine that handles all
work that is based on ticks.

For every tick added to RTI_CT, the fractional click count is
incremented by calling TOCK. After 16 fractional clicks, the actual
click count (KLIKS) is bumped, and then any tasks due to run at that
click are processed by calling YAK.

YAK is called to process click based tasks and to propogate the timer
increment to the seconds count. Each click is 64 milliseconds, which
gives a maximum time of a little over 16 seconds for click based timers.
Longer duration timers are based on a seconds counter. There are 16
clicks in a \"second\" so the system\'s seconds are actually 1.024
seconds each.

The first thing YAK does is increment the fractional seconds count,
SFRK. If SFRK has reached 16, then the seconds count (SECS) is
incremented, and the fractional seconds count is zeroed. YAS is called
to handle seconds based tasks, and BMP_RT is called to bump the 32 bit
seconds since starting counter.

After taking care of propogating the click count to the seconds chain,
YAK checks to see if a download is in progress. If either side is in a
download lock, YAK returns. If no download is in progress, YAK calls
DK_RT to handle the processing of the weather warning tone hold timer.

It then calls THMP to handle the timer machine that causes the
indicators to blink.

##### TM_TST, Tick Based Tasks

TM_TST is the routine that actually handles the tick based tasks. For
many tick based tasks, a counter is maintained. The counter is set to a
duration when some task is initiated, and is decremented when a timing
routine is called. When it is decremented to zero, the results
processing code is run. If the timing routine finds the counter at 0
when it is called, it returns, knowing that the timer is no longer
active.

TM_TST calls all of the tick based timing routines, and handles the zone
select timing processing.

###### DK_BT

The first timing routine called is DK_BT, which handles the buzzer
duration for beeping. If BTLFT is zero when DK_BT is called, it returns.
If BTLFT is non-zero when DK_BT is called, it is decremented. If BTLFT
is zero after it is decremented, SA_OFF is called to turn the buzzer off
and mark it as off. If it is non-zero after being decremented, the timer
hasn\'t expired, so the routine just returns.

###### DK_PR

DK_PR handles page request timing.

A page can be the result of operator pressing the microphone PTT, or it
can be an admin re-page. The admin re-page is only active if an aux
audio page on the administration panel gets cut off. When this happens,
the panel will try re-paging.

When an operator presses the microphone PTT switch, the panel sends the
global tray map for each side to the matrix, clears the page request
response flags and starts the page request timer. (PGR_TM)

When each response is returned from the matrix, it is recorded by
setting one of the response flags for that side. When the page request
timer expires, these two responses are examined and the panel reacts
accordingly.

If PGR_TM is zero when DK_PR is called, it returns. If PGR_TM is
non-zero when DK_PR is called, it is decremented. If PGR_TM is non-zero
after it is decremented, DK_PR returns, as we have not waited long
enough to expect to have received both responses

DK_PR next checks to see if the current page is an aux audio re-page. If
it is, the matrices responses are saved for later processing.

There are five responses that the matrix can return for a page request;
bad, busy, partial, good, and no trays.

The bad response indicates that the panel has requested one or more
trays that are not listed as being present. The matrix has two lists of
trays that are installed, the old style trays, and the new style trays.
If a request contains a tray that does not appear on either list, then
the matrix assumes that the panel contains an invalid configuration, and
rejects the request.

The busy response indicates that the panel has requested one or more
trays that are currently being used at an equal or higher priority than
the current request. If a tray is being used by a panel with a lower
priority, the tray will be taken away from the current owner, and given
to the new panel. If the panel using the tray is at an equal or higher
priority to the new requestor, the new requestor will receive a busy
response.

The matrix can check new style trays to see if they actually closed when
activated. This means that it is possible under some circumstances for
the matrix to determine that some of the requested trays are working,
while others are failing. If this happens, the matrix will return a
partial response to the panel.

Because old style trays can not be checked to see if they are working,
old style trays are always recorded as having worked by the matrix.

If all trays requested actually close when activated, or check good,
(old trays always check good) the matrix will send a good response
indicating that all requested trays are available and working.

A zone on a panel may have any number of trays assigned to it. If it
contains only new style trays, it is possible for all the trays to be
available, but fail, leaving no trays to satisfy the page request. If
this happens, then the matrix will return a no trays response.

This is a likely failure mode as many zones only have a single tray
assigned to them, so a single tray failure may result in a no trays
response.

Because the panel talks to both matrices, it is possible for the panel
to receive different answers from each matrix. It is also possible that
one side of the zone is empty. The two responses must be examined, as
well as the contents of each side of the zone list, in order to
determine the proper panel reaction to the matrices responses.

If either matrix returned a busy response, then the panel treats the
whole request as busy. For a busy response, the panel will turn the
busy/cutoff indicator on, and mark the status of the request as pending
off. Before returning, the panel will beep to draw the operator\'s
attention to the failure indication.

If the response was not busy, then the panel checks to see if there were
no trays granted for the request. In addition to checking the matrix
response, the code also checks the global tray map for each side. If the
global tray map is empty, meaning that there are no trays being
requested for that side, then the response for that side does not
matter, in terms of determining if any trays were granted. If the global
map is not empty, then the code checks for a good or partial response
for that side. Either response indicates that at least some trays were
granted, so we are not in a no trays situation.

If it turns out that there were no trays granted for the request, then
the code marks the page status as pending off and beeps to indicate the
failure for the operator before returning.

If the page was not busy and was not no trays, then the code checks to
see if the page request was good. This is handled by the routine PG_AG.
If the global tray map is not empty for a side, then the response from
the matrix must be good, indicating that all trays requested were
available and working. This must be true for both sides. If the global
tray map is empty, then the response does not matter, except that at
least one side must be non-empty.

If the page request was good, the code turns the voice ready indicator
on and marks the page status as active and then returns.

If the page was not busy, was not no trays, and was not good, then by a
process of elimination we know that the page had to have been partial,
meaning that at least one tray was available for the page and at least
one tray failed. For a partial page, the code turns the voice ready
indicator on, marks the page as active, but also beeps to let the
operator know that not all trays were available.

If it turns out that the page was an admin re-page, then the processing
of the responses is handled by a different block of code. For this case,
the code will check the response flags against the original response
flags to see if they match. If they do, then the panel assumes that the
re-page was successful.and turns the voice ready indicator on, turns the
busy/cutoff indicator off, and resets the re-page flag.

If the responses don\'t match the original request, then the code checks
to see if both sides got a partial or good response. If both sides got a
good or partial response, then the panel knows that the tray that was
taken away has been returned. (If it was still owned by another panel,
we would have received a busy response.) If it turns out that both sides
did get a good or partial response, the code turns the vocie ready
indicator on, the busy/cutoff indicator off, and resets the re-page
flag.

If the responses were not the original responses, and we did not get
partial or good for both, then the code assumes that the re-page failed,
so it restarts the re-page timer, so that another re-page will occur.

###### MR_TST

MR_TST is a routine that is called to determine if the panel did not
receive a response. If a matrix did not return a response, this usually
indicates that there is a problem with the communication link between
the matrix and the panel. A record is kept of the number of these
failures, as this is a good indication of link health.

###### DK_ST

DK_ST handles the timing for the lamp test of the special lamps. In a
lamp test, the indicators are divided into two groups, the zone select
indicators, and the special indicators. Any indicator that is not a zone
select indicator is a special indicator.

A lamp test occurs in two phases. In the first phase, all the zone
select indicators are turned off, and all the special indicators are
turned on. During the second phase, all the special indicators are
turned off and all the zone select indicators are turned on. After the
second phase completes, all indicators are restored to their recorded
state, on or off.

If the special indicator timer (STDUR) is zero when DK_ST is called,
DK_ST returns as the panel is not in the first phase of the lamp test
sequence. If STDUR is non-zero when DK_ST is called, then it is
decremented. If STDUR is non-zero after being decremented, then DK_ST
returns as it is not yet time to enter the second phase of the lamp
test.

If STDUR is zero after being decremented, then the end of the first
phase of the lamp test has been reached. In this case, the code turns
all the special indicators off, turns all the zone select indicators on,
and sets the zone select lamp test timer to it\'s starting value.

###### DK_ZT

DK_ZT handles the timing for the lamp test of the zone select lamps. In
a lamp test, the indicators are divided into two groups, the zone select
indicators, and the special indicators. Any indicator that is not a zone
select indicator is a special indicator.

A lamp test occurs in two phases. In the first phase, all the zone
select indicators are turned off, and all the special indicators are
turned on. During the second phase, all the special indicators are
turned off and all the zone select indicators are turned on. After the
second phase completes, all indicators are restored to their recorded
state, on or off.

If the zone select timer (ZTDUR) is zero when DK_ZT is called, DK_ZT
returns as the panel is not in the second phase of the lamp test
sequence. If ZTDUR is non-zero when DK_ZT is called,then it is
decremented. If ZTDUR is non-zero after being decremented, then DK_ZT
returns as the second phase of the lamp test is not active.

If ZTDUR is zero after being decremented, then the end of the second
phase of the lamp test has been reached. In this case, the code restores
the state of all the special indicators and the zone select indicators.

###### DK_AR

If the panel is not routing audio to a tray that is active, then the
tray emits noise. In order to prevent this, when a page is terminated,
the audio from the panel is not released right away. By continuing to
send audio after the page release message has been transmitted, the
panel allows the matrix time to receive and process the request before
it drops the audio. This allows the tray to be deactivated before the
audio feed drops. When the operator terminates a page, the code starts
the audio release timer. DK_AR handles the audio release timing.

If the audio release timer (ARL_TM) is zero when DK_AR is called, then
DK_AR returns as audio release timing is not active. If ARL_TM is
non-zero when DK_AR is called, it is decremented. If it is still
non-zero after being decremented, then DK_AR returns as it is not yet
time to perform the audio release.

If ARL_TM is zero after having been decremented, then the time has
arrived to relase the audio output. DK_AR then deselects all audio
output from the panel.

###### DK_AT

DK_AT handles area warning request timing.

When an operator activates the area warning tone by pressing the area
warning active actuator, the panel sends the global tray map for each
side to the matrix, clears the area warning response flags and starts
the area warning request timer. (ATR_TM)

When each response is returned from the matrix, it is recorded by
setting one of the response flags for that side. When the area warning
request timer expires, these two responses are examined and the panel
reacts accordingly.

If ATR_TM is zero when DK_AT is called, it returns. If ATR_TM is
non-zero when DK_AT is called, it is decremented. If ATR_TM is non-zero
after it is decremented, DK_AT returns, as we have not waited long
enough to expect to have received both responses.

If it is zero after being decremented, the timer has expired, so the
routine must react correctly to the responses recevied from the
matrices. MR_TST is called to increment the no matrix response error
counts if required. (If the panel did not receive an area warning
response from a matrix, it will bump the no response count for that
side. )

There are five responses that the matrix can return for a page request;
bad, busy, partial, good, and no trays.

The bad response indicates that the panel has requested one or more
trays that are not listed as being present. The matrix has two lists of
trays that are installed, the old style trays, and the new style trays.
If a request contains a tray that does not appear on either list, then
the matrix assumes that the panel contains an invalid configuration, and
rejects the request.

The busy response indicates that the panel has requested one or more
trays that are currently in area warning mode as the result of another
panel performing an area warning request.

The matrix can check new style trays to see if they actually closed when
activated. This means that it is possible under some circumstances for
the matrix to determine that some of the requested trays are working,
while others are failing. If this happens, the matrix will return a
partial response to the panel.

Because old style trays can not be checked to see if they are working,
old style trays are always recorded as having worked by the matrix.

If all trays requested actually close when activated, or check good,
(old trays always check good) the matrix will send a good response
indicating that all requested trays are available and working.

A zone on a panel may have any number of trays assigned to it. If it
contains only new style trays, it is possible for all the trays to be
available, but fail, leaving no trays to satisfy the page request. If
this happens, then the matrix will return a no trays response.

This is a likely failure mode as many zones only have a single tray
assigned to them, so a single tray failure may result in a no trays
response.

Because the panel talks to both matrices, it is possible for the panel
to receive different answers from each matrix. It is also possible that
one side of the zone is empty. The two responses must be examined, as
well as the contents of each side of the zone list, in order to
determine the proper panel reaction to the matrices responses.

If either matrix returned a busy response, then the panel treats the
whole request as busy. For a busy response, the panel will turn the
busy/cutoff indicator on, and mark the status of the request as area
warning pending off. Before returning, the panel will beep to draw the
operator\'s attention to the failure indication.

If the response was not busy, then the panel checks to see if there were
no trays granted for the request. In addition to checking the matrix
response, the code also checks the global tray map for each side. If the
global tray map is empty, meaning that there are no trays being
requested for that side, then the response for that side does not
matter, in terms of determining if any trays were granted. If the global
map is not empty, then the code checks for a good or partial response
for that side. Either response indicates that at least some trays were
granted, so we are not in a no trays situation.

If it turns out that there were no trays granted for the request, the
code sends an area warning release message to each matrix, then turns
the area warning active indicator off and beeps to draw the operator\'s
attention to the failure. The code then marks the area warning request
status as area warning off, and records the position of the area warning
active actuator as up.

The reason that an area warning release message is sent when the panel
detects a no trays response is to prevent the system from being locked
up.

It is possible that the reason there is a no trays condition is because
the panel never received an area warning response from the matrix. This
could be the result of the matrix being busy and not getting the
response back to the panel is time, or the message from the matrix could
have been corrupted, and as a result, thrown away. In either case, the
trays are actually in area warning mode, but the panel has left area
warning mode. This means that the trays in question are no longer
available to the rest of the system, and the panel operator has no way
of knowing that he has the trays tied up. To prevent this, the panel
sends an area warning release message, just to be on the safe side.

If the area warning response was not busy and was not no trays, then the
code checks to see if the area warning request was good. This is handled
by the routine AT_AG. If the global tray map is not empty for a side,
then the response from the matrix must be good, indicating that all
trays requested were available and working. This must be true for both
sides. If the global tray map is empty, then the response does not
matter, except that at least one side must be non-empty.

If the area warning response was good, the code marks the area warning
request status as active and then returns.

If the response was not busy, was not no trays, and was not good, then
by a process of elimination we know that the area warning response had
to have been partial, meaning that at least one tray was available for
the page and at least one tray failed. For a partial page, the code
marks the page status as area warning active, but also beeps to let the
operator know that not all trays were available.

###### DK_WT

DK_WT handles weather warning tone timing.

When the operator of an emergency warning panel activates the weather
warning tone by pressing the weather warning actuator, the panel sends a
weather warning tone request to each matrix, clears the weather warning
response flags and starts the weather warning response timer. (WTR_TM)
It also starts a weather warning tone release timer.

If the weather warning timer (WTR_TM) is zero when DK_WT is called,
DK_WT returns as the panel is not in a weather warning. If WTR_TM is
non-zero when DK_WT is called, then it is decremented. If WTR_TM is
non-zero after being decremented, then DK_WT returns as not enough time
has passed to be expecting the responses to have been returned.

When each response is returned from the matrix, it is recorded by
setting one of the response flags for that side. When the weather
warning response timer expires, these two responses are examined and the
panel reacts accordingly.

There are five responses that the matrix can return for a page request;
bad, busy, partial, good, and no trays.

The bad response indicates that the panel has requested one or more
trays that are not listed as being present. The matrix has two lists of
trays that are installed, the old style trays, and the new style trays.
If a request contains a tray that does not appear on either list, then
the matrix assumes that the panel contains an invalid configuration, and
rejects the request.

The busy response indicates that the panel has requested one or more
trays that are currently being used at an equal or higher priority than
the current request. If a tray is being used by a panel with a lower
priority, the tray will be taken away from the current owner, and given
to the new panel. If the panel using the tray is at an equal or higher
priority to the new requestor, the new requestor will receive a busy
response.

The matrix can check new style trays to see if they actually closed when
activated. This means that it is possible under some circumstances for
the matrix to determine that some of the requested trays are working,
while others are failing. If this happens, the matrix will return a
partial response to the panel.

Because old style trays can not be checked to see if they are working,
old style trays are always recorded as having worked by the matrix.

If all trays requested actually close when activated, or check good,
(old trays always check good) the matrix will send a good response
indicating that all requested trays are available and working.

A zone on a panel may have any number of trays assigned to it. If it
contains only new style trays, it is possible for all the trays to be
available, but fail, leaving no trays to satisfy the page request. If
this happens, then the matrix will return a no trays response.

This is a likely failure mode as many zones only have a single tray
assigned to them, so a single tray failure may result in a no trays
response.

Because the panel talks to both matrices, it is possible for the panel
to receive different answers from each matrix. It is also possible that
one side of the zone is empty. The two responses must be examined, as
well as the contents of each side of the zone list, in order to
determine the proper panel reaction to the matrices responses.

If either matrix returned a busy response, then the panel treats the
whole request as busy. For a busy response, the panel will turn the
busy/cutoff indicator on, and mark the status of the request as pending
off. Before returning, the panel will beep to draw the operator\'s
attention to the failure indication.

If the response was not busy, then the panel checks to see if there were
no trays granted for the request. In addition to checking the matrix
response, the code also checks the global tray map for each side. If the
global tray map is empty, meaning that there are no trays being
requested for that side, then the response for that side does not
matter, in terms of determining if any trays were granted. If the global
map is not empty, then the code checks for a good or partial response
for that side. Either response indicates that at least some trays were
granted, so we are not in a no trays situation.

If it turns out that there were no trays granted for the request, then
the code sends a weather warning tone release message, turns the weather
warning tone active indicator off, beeps, and marks the indicator as off
and the switch as up. It then clears the weather warning tone release
timer and clears the zone select lock flag.

The reason that a weather warning tone release message is sent when the
panel detects a no trays response is to prevent the system from being
locked up.

It is possible that the reason there is a no trays condition is because
the panel never received an a weather warning response from the matrix.
This could be the result of the matrix being busy and not getting the
response back to the panel is time, or the message from the matrix could
have been corrupted, and as a result, thrown away. In either case, the
trays are actually passing the weather warning tone, but the panel has
left weather warning mode. This means that the trays in question are no
longer available to the rest of the system, and the panel operator has
no way of knowing that he has the trays tied up. To prevent this, the
panel sends a weather warning release message, just to be on the safe
side.

If the page was not busy and was not no trays, then the code checks to
see if the page request was good. This is handled by the routine WT_AG.
If the global tray map is not empty for a side, then the response from
the matrix must be good, indicating that all trays requested were
available and working. This must be true for both sides. If the global
tray map is empty, then the response does not matter, except that at
least one side must be non-empty.

If the page request was good, the code marks the page status as weather
warning active and then returns.

If the page was not busy, was not no trays, and was not good, then by a
process of elimination we know that the page had to have been partial,
meaning that at least one tray was available for the page and at least
one tray failed. For a partial page, the code marks the page as weather
warning active, but also beeps to let the operator know that not all
trays were available.

###### DK_SS

DK_SS handles source select timing.

When an area warning panel operator activates area warning tone, he can
override the tone to give voice directions. To do this, he simply keys
the microphone, and voice is routed to the trays instead of the area
warning tone. When the microphone PTT is released, the voice is replaced
by the area warning tone.

Because there are no changes in the set of trays involved in these
operations, a slightly different method is used to switch back and forth
between the area warning tone and the voice routing. These transistions
use a source select message. The source select message changes the audio
being routed to a set of trays, but does not change which trays are
keyed.

In order to allow the area warning panel operator to know if his voice
override worked, the source select sequence expects to get a response
back from the matrix indicating the results of the requested change.

When an operator presses or releases the microphone PTT switch, the
panel sends the global tray map for each side to the matrix, clears the
source select response flags and starts the source select timer. (SS_TM)

When each response is returned from the matrix, it is recorded by
setting one of the response flags for that side. When the source select
timer expires, these two responses are examined and the panel reacts
accordingly.

If SS_TM is zero when DK_SS is called, it returns. If SS_TM is non-zero
when DK_SS is called, it is decremented. If SS_TM is non-zero after it
is decremented, DK_SS returns, as we have not waited long enough to
expect to have received both responses

When SS_TM is decremented to 0, the code calls MR_TST to record any
matrix response errors.

There are five responses that the matrix can return for a source select
request; bad, busy, partial, good, and no trays.

The bad response indicates that the panel has requested one or more
trays that are not listed as being present. The matrix has two lists of
trays that are installed, the old style trays, and the new style trays.
If a request contains a tray that does not appear on either list, then
the matrix assumes that the panel contains an invalid configuration, and
rejects the request. (This should never happen with a source select
unless you hit the select right in the middle of a download.)

The busy response indicates that the panel has requested one or more
trays that are currently being used at an equal or higher priority than
the current request. If a tray is being used by a panel with a lower
priority, the tray will be taken away from the current owner, and given
to the new panel. If the panel using the tray is at an equal or higher
priority to the new requestor, the new requestor will receive a busy
response. (A source select can get a partial response, but should never
receive a busy response. The busy response would have been received by
the original page.)

The matrix can check new style trays to see if they actually closed when
activated. This means that it is possible under some circumstances for
the matrix to determine that some of the requested trays are working,
while others are failing. If this happens, the matrix will return a
partial response to the panel.

Because old style trays can not be checked to see if they are working,
old style trays are always recorded as having worked by the matrix.

If all trays requested actually close when activated, or check good,
(old trays always check good) the matrix will send a good response
indicating that all requested trays are available and working.

A zone on a panel may have any number of trays assigned to it. If it
contains only new style trays, it is possible for all the trays to be
available, but fail, leaving no trays to satisfy the page request. If
this happens, then the matrix will return a no trays response.

This is a likely failure mode as many zones only have a single tray
assigned to them, so a single tray failure may result in a no trays
response.

Because the panel talks to both matrices, it is possible for the panel
to receive different answers from each matrix. It is also possible that
one side of the zone is empty. The two responses must be examined, as
well as the contents of each side of the zone list, in order to
determine the proper panel reaction to the matrices responses.

After recording any matrix response errors, DK_SS will call SS_BOTH to
see if both source selects were good. At least one side needs to be
non-empty, and all non-empty sides must have received a response of good
in order for SS_BOTH to return TRUE.

If SS_BOTH indicates that the source select was successful, DK_SS checks
the audio source requested. If the audio source requested was the panel
audio, then DK_SS turns on the voice ready indicator to let the operator
know he can make his announcement. If the requested source was the area
warning tone, then the operator has just released the PTT. (The voice
ready lamp was cleared when the panel detected the release of the
microphone PTT.)

If the source select was not successful, DK_SS tries to determine if it
received some of the requested trays. To do this, it calls SS_SUM.
SS_SUM will return TRUE if at least one side is non-empty, and all
non-empty sides got a good or partial response. If SS_SUM returns TRUE,
then DK_SS checks the audio source requested. If the audio source
requested was the panel audio, then DK_SS turns on the voice ready
indicator to let the operator know he can make his announcement. If the
requested source was the area warning tone, then the operator has just
released the PTT. ( The voice ready lamp was cleared when the panel
detected the release of the microphone PTT.) After turning on the voice
ready indicator if required, the panel beeps to let the operator know
that not all areas have the correct audio.

If SS_SUM returns FALSE, the panel beeps to alert the operator to the
fact that some trays do not have the correct audio feed. No attempt is
made to turn on the voice ready indicator, even if the source select was
a result of the microphone PTT being pressed.

##### Pending Zone Selects

When the operator presses an inactive zone select actuator, the keyboard
encoder chip will debounce the key closure and release. After it\'s
fully released, the keyboard encoder indicates that it has data
available. The CPU will read the scan code from the keyboard encoder,
and turn the indicator on. It also sends a tray test request to each
matrix. In addition to sending the message, the code clears the response
flags for that button and starts a response timer by placing the zone
record index on a circular queue.

TM_TST handles processing the zones on the circular queue using a
software loop to process all zones that may have expired. It starts off
by calling PON_TOP to see if there are any zones on the circular queue.
If there are no zones on the circular queue, then TM_TST is done, and it
breaks out of the loop and returns.

If there are zones on the circular queue, then the map number (all
internal zone operations use map numbers) is saved in a temporary
variable and GET_ZT is called to get the zone\'s completion time. If
this does not match the current time, (RTI_CT) the code breaks out of
the loop and returns.

If it turns out that the zone\'s completion time matches the current
time, then the zone is removed from the circular queue by RMV_PON.
MR_TST is called to record and \"no matrix response\" errors. Next the
code checks to see if the tray test passed by calling TT_PASS.

The tray test will pass if both side responded, all non-empty sides
passed, and at least one side is non-empty. If the tray test passes, the
code resets the area warning zone select flag for the zone and goes to
the top of the loop.

Area warning panels have an unusual feature. They are required to allow
the operator to do zone selects while the area warning tone is active.
Activating the area warning tone is really just a page with a tone
generator as the audio source. This means that on area warning panels
the code needs to allow zone selects during a page. This requires
special processing. When this operation is performed, a flag is set in
the zone\'s record to indicate that special processing is required.
After the zone select processing has been performed, this flag is reset.

If the tray test did not pass, the code calls TT_FAIL to determine if no
trays were granted. TT_FAIL will return TRUE if both sides had no trays
confirmed. This will be true for any side that got a bad response, no
response, or is empty.

TT_FAIL checks the area warning zone select flag. If it is set, the code
runs AZ_FAIL to see if no trays were granted. This required because the
response returned in this case is an area warning response, and because
you can\'t destinguish complete or partial failures as there are trays
associated with other zones that were selected earlier and the matrix
returns the aggregate result.

If the tray test failed, the panel beeps and resets the area warning
zone select flag before going to the top of the loop. If the tray test
didn\'t fail, then by a process of elimination, it must have been
partially successful. The code calls ZPN_XP to handle the partial
success. If the area warning zone select flag is set, the panel justs
beeps. The zone select lamp remains on.

If the area warning zone select flag is not set, the zone indicator is
turned off and marked as being off. The code also indicates that the
zone select button is deselected. The panel beeps to draw the
operator\'s attention to the failure.

After running ZPN_XP, the code builds new global tray maps by calling
MGTM. If the area warning zone select flag was set, the zone remained
active, so the global tray maps don\'t change. The last action is to
reset the area warning zone select flag before jumping to the top of the
loop.

###### TOCK

TOCK runs the ticks through the fractional click counter. When the
fractional click counter rolls over, TOCK calls YAK to handle the click
based tasks.

####### YAK

YAK handles running running the clicks through the fractional seconds
counter. If the fractional seconds count rolls over, the code calls YAS
to handle the seconds based work and calls BMP_S to increment the
seconds since starting count. (elapsed run time counter)

If a download is in progress, the code skips running the click based
tasks and returns. If a download is not in progress, the code will call
DK_RT to handle weather warning tone release and THMP to handle blinking
the indicators.

######## DK_RT

DK_RT handles the weather warning tone release timing.

When an emergency warning panel operator presses the weather warning
tone activate actuator, the panel started a weather warning tone release
timer. (WWR_TM)

If WWR_TM is zero when DK_RT is called, DK_RT returns as the weather
warning tone release timer is not active.

If WWR_TM is non-zero when DK_RT is called, it is decremented and the
code checks to see if it has reached the hold time.

When the weather warning tone is activated, the panel requests the
weather warning tone from the matrix, and then waits two seconds and
shuts off the tone without releasing the trays. It is expected that the
panel operator will make a voice announcement after the weather warning
tone has been terminated by the panel. The trays are held for two
seconds after the tone has terminated. If the operator has not initiated
a page by then, the trays are released. The period between the tone
ending and the trays being released is referred to as the hold time.

When the weather warning tone release timer reaches the start of the
hold time, the code will turn the weather warning tone active indicator
off, and record it as being off. It also turns the busy/cutoff indicator
off in case the weather warning tone was cutoff by a higher priority
page.

When the weather warning tone release timer is decremented to 0, the
code calls CWWR to handle the release. CWWR is also called to handle a
page override of a weather warning tone, so the first thing it does is
inspect the weather warning release timer to determine if the hold time
expired or if the operator overrode the hold.

If the operator allows the hold to expire without without making a page,
the code sends a weather warning tone release message to free up the
trays. It then turns the weather warning tone active indicator off, and
marks it off. It also turns the busy/cutoff indicator off in case the
weather warning tone was cutoff by a higher priority page. It then
records the weather warning tone active button as being up and clears
the zone lock.

If the operator overrode the hold, then the code turns the weather
warning tone active indicator off, and marks it off. It also turns the
busy/cutoff indicator off in case the weather warning tone was cutoff by
a higher priority page. It then records the weather warning tone active
button as being up and clears the zone lock.

######## THMP

THMP handles the blink timing. If the panel is in a download lock when
THMP is called, it returns. (The panel indicators are in a special
configuration during a download so the operator can tell when the
download is complete.)

If the panel is not in a download lock, the code checks the count of
affected zones. If there are no zones afected by an area warning mode,
THMP returns.

If there are zones affected by an area warning, the code will run the
blink checks. There are two different blink rates to make it easier for
the operator to tell the affected selected zones from the affected
unselected zones. The code runs a 16 click cycle, so it only looks at
the lower 4 bits of the click count.

When the low nybble of the click count is 0, all the affected selected
zones are turned on. The code will also turn on the area warning
indicator and the local area warning indicator if possible. The area
warning lamp will not be turned on if the area warning is the result of
an area warning activation on the current panel.

When the low nybble of the click count is 14, all the affected
unselected zones are turned on.

When the low nybble of the click count is 15, all affected zones are
turned off. (The area warning and local area warning indicators are also
turned off if possible.)

###### YAS

YAS handles all the seconds based tasks. On the panel there are really
only two seconds based tasks, the download lock release and the re-page.
Since there are two sides, and each can be independently locked and
unlocked, there are two routines for download lock release, one for the
A side (DK_DLA) and one for the B side. (DK_DLB) The re-page timer is
handled by DK_RP.

####### DK_DLA

DK_DLA handles download lock release timing for side A of the panel.
Before the system console can download a new configuration to the panel,
it must be placed in a download lock. The system console sends a
download lock request to the panel, and if the panel is not busy, it
will set the download lock flag and start a download lock release timer.

While a panel is locked for downloading, all panel actions are disabled.
In order to prevent a dropped message from disabling a panel, a download
lock release is implemented. This is a timer that will unlock the panel
when it expires if the system console did not unlock the panel.

If the A side download lock release timer (DLA_TM) is zero when DK_DLA
is called, the routine returns as the timer is not enabled. If DLA_TM is
non-zero on entry, it is decremented. If DLA_TM decrements to 0, the
code will clear the A side download lock and beep to draw the
operator\'s attention to the problem.

If the B side is in download lock after the beep, the code returns. If
the B side is not download locked, the code restores the former state of
the zone select indicators by calling ZL_BAK, and restores the former
state of the special indicators by calling SL_BAK.

After the indicators have been restored, MAZ is called to build new maps
of zones affected by area warning. This is required because the trays
that are mapped to a zone may have been changed by the download,
changing which zones are affected.

####### DK_DLB

DK_DLB handles download lock release timing for side B of the panel.
Before the system console can download a new configuration to the panel,
it must be placed in a download lock. The system console sends a
download lock request to the panel, and if the panel is not busy, it
will set the download lock flag and start a download lock release timer.

While a panel is locked for downloading, all panel actions are disabled.
In order to prevent a dropped message from disabling a panel, a download
lock release is implemented. This is a timer that will unlock the panel
when it expires if the system console did not unlock the panel.

If the B side download lock release timer (DLB_TM) is zero when DK_DLB
is called, the routine returns as the timer is not enabled. If DLB_TM is
non-zero on entry, it is decremented. If DLB_TM decrements to 0, the
code will clear the B side download lock and beep to draw the
operator\'s attention to the problem.

If the A side is in download lock after the beep, the code returns. If
the A side is not download locked, the code restores the former state of
the zone select indicators by calling ZL_BAK, and restores the former
state of the special indicators by calling SL_BAK.

After the indicators have been restored, MAZ is called to build new maps
of zones affected by area warning. This is required because the trays
that are mapped to a zone may have been changed by the download,
changing which zones are affected.

#######  DK_RP

DK_RP handles aux re-page timing.

Only admisitrative panels can make an aux audio page. This fearture is
used to play pre-recorded announcements over the public address system.
If an aux audio page it cut off, the panel will start a re-page timer.
(RP_TM) If RP_TM is zero when DK_RP is called, it returns as the re-page
feature is not active.

If RP_TM is non-zero when DK_RP is called, it is decremented. If RP_TM
decrements to zero, the code will perform a re-page.

The first step is doing a re-page is to send a message to the matrix
telling it to clear the panel preempt bit for that panel.

In order to cut down on un-needed traffic on the system, the matrix
maintains a list of panels that have received a cutoff message. That
way, if a second tray is taken away from the panel, the panel does not
receive another cutoff message. (The panel is already indicating cutoff
from the first time it lost a tray.)

In order to insure that the panel will be notified if a tray is taken
away after it\'s successfully re-paged, it sends a message to the matrix
to clear the panel preempt bit in the matrix.

After clearing the panel preempt bit, the panel will send a page request
to the matrix, asking for all the trays. It also clears the page
response flags and starts the page response timer. It then sets the
panel status to page pending.

Once the flags have cleared, and the timer started, the re-page is done.
The processing will be handled by the response timer timing out.

#### Download Lock

When the system console needs to download a new configuration to a
panel, it will lock the panel. When the panel is locked, it beeps to
draw the operator\'s attention. If the system console fails to unlock
the panel within 10 seconds, the panel will beep and unlock itself.
There is no beep when the system console unlocks the panel is less than
10 seconds.

After processing any expired timers, the main loop checks the download
flag. This flag is set whenever the panel receives a download lock
command. During downloads, configuration information is sent to the
panel, which programs it into the XICOR EEPROM. During a download, the
panel disables any operator input. When the code sees the download flag
set, it skips the code that would normally check for changes in zone
selections, microphone state and area warning changes.

The download locks prevent any panel changes from occurring while the
system consoles are loading a new configuration to the panel. When the
systems consoles have a new configuration for a panel, they send a lock
request. If no panel operations are in progress, the panel will set the
download lock, start a download release timer, and send a download lock
response to the system console.

The download lock prevents the software from processing zone selections,
microphone checks, and area warning changes. Any area warning changes
that occur will be recorded, but the panel display will not be updated
to reflect the changes until the panel comes out of download lock.

Before a new configuration can be downloaded to a panel, the panel has
to be placed in a download lock. The system console will send a download
request to the panel. If there are no outstanding operations on the
panel, then the panel will return a download locked response. If any
outstanding operations are in progress, the panel will wave off the
download lock by sending a download lock reject back.

The download request will fail if the panel is doing any kind of page,
(including weather warning tone) or if it is waiting for a response from
the matrix.

#### Zone Selections

The zone select switches on the front of a panel are connected to a
keyboard encoder chip that handles scanning and debouncing. The keyboard
encoder waits for a contact closure followed by a contact open. After
the button is released the keyboard encoder will have a valid key press.
When it has a valid key press, it signals it by driving its data
available line. The keyboard encoder\'s data available line is connected
to bit 0 of port A on the microcontroller.

The keyboard indicator only provides indications of key presses. The
software in the panel must track the actual state of the \"key.\" (On or
Off)

When the operator presses an inactive zone select actuator, the keyboard
encoder chip will debounce the key closure and release. After it\'s
fully released, the keyboard encoder indicates that it has data
available. The CPU will read the scan code from the keyboard encoder,
and turn the indicator on. It also sends a tray test request to each
matrix. In addition to sending the message, the code clears the response
flags for that button and starts a response timer by placing the zone
record index on a circular queue.

If the tray test request passes, the trays assigned to that zone are
added to the panel\'s global tray maps.

When the operator presses an active zone select actuator, the keyboard
encoder chip will debounce the key closure and release. After it\'s
fully released, the keyboard encoder indicates that it has data
available. The CPU will read the scan code from the keyboard encoder,
and turn the indicator off. It also builds a new set of global tray
maps. (one for each side) The new maps will not contain the trays
assigned to the zone that was just deselected.

No message is sent on a zone deselect. The tray test request will only
pull in the trays long enough to determine that the trays are working,
then they are released automatically by the matrix, therefore there is
no need for any messages to free the trays after a zone is deselected.

(Except in the case of a zone deselect while area warning tone is
active. See section 1.2.1.14.2 Pending Zone Selects.)

#### Keying Checks

Most panels have only one keying source, the microphone push to talk
(PTT) switch. An administrative panel has two microphones, the normal
front panel microphone and a gooseneck microphone activated by a foot
switch to allow hands free operation. It also has an aux audio button
for the rear panel line level input.

For all panels, the microphone PTT line is connected to Bit 1 of port A.
This line is used to sense the position of the microphone Push To Talk
line. Debounce of this signal is handled by a 14490 chip that sits
between the microcontroller and the microphone PTT switch.

Bit 3 of port A is used to sense the position of the foot switch. This
switch is only present on Administrative panels, where it used as a PTT
switch for the gooseneck mike. This signal is debounced by the 14490
chip.

A page can also be performed using the auxiliary audio input. An audio
source must be connected to the auxiliary input on the rear panel.

To initiate a page using the auxiliary audio input, press the aux input
enable actuator/indicator, which is located on the left side of the
panel near the center.

This input is handled by the keyboard encoder chip.

The aux input enable actuator/indicator should illuminate. It serves the
same purpose as the microphone keyed indicator, except for the Aux Audio
input. Pin 2 of Port D drives the Aux audio indicator.

The only difference between the three pages is the circuit used as the
PTT and the audio selected for routing to the matrix. The balance of the
page is identical to using the normal panel microphone with it\'s push
to talk switch.

The main keying check is MK_CK. When it is called, it checks to see if
any other type of page is active. (Other that a normal microphone page.)
If some other type of page is active, MK_CK will return.

Assuming that no other page is active, MK_CK will call PG_NHB to see if
there is any reason why it should not initiate a page. PG_NHB returns
TRUE if a lamp test is in progress, if a zone test is in progress, if
the audio release timer is active, if the panel is waiting for a page
request response, or if the panel is waiting for a weather warning tone
request response.If PG_NHB returns TRUE, MK_CK will return.

If normal pages are not inhibited, MK_CK compares the current microphone
keying state to the previous microphone keying state. If they are the
same, no change has occurred, so no actions are required, and MK_CK
returns.

If they differ, the new microphone keying state is recorded the
microphone previous keying state so that future transistions can be
detected.

MK_CK then checks to see if it is running on an area warning panel due
to the special processing that may be required. For normal pages, the
code checks the microphone previous state to see if a page was just
started or just terminated.

If a page is being initiated, the code checks to see if we\'re
overriding a weather warning tone. If we are, the code calls CWWR to
clear the weather warning timer.

After clearing the weather warning tone release timer if required, the
code call MK_ON to record the PTT as being dpressed. It also calls PG_RQ
to send a page request to both matrices, and calls SEL_MA to route
microphone audio to the matrices. It then marks the panel status as page
pending and sets the page type to a normal page.

When the mike check code is run on an area warning panel, it will call
ATN_MK to handle processing of microphone states while the area warning
tone is in progress.

When called, ATN_MK will start the source select response timer and
check the microphone prior state.

If this indicates that the microphone was just keyed, the mike on
indicator is lit, the microphone audio is selected for routing to the
matrices and a source select message is sent to the matrices to select
the panel audio. This results in the microphone audio being routed to
the trays.

If MPS indiactes that the microphone was unkeyed, ATN_MK will send a
source select message to the matrices selecting the area warning tone
generator as the source of the audio to be fed to the trays. It will
also turn off the microphone keyed indicator, schedule the audio release
(By starting the audio release timer) and turn the voice ready indicator
off.

If the code is running on an administrative panel, it will call GN_CK to
see if a gooseneck microphone page is being initiated or terminated.

When GN_CK is called, it checks to see if any other type of page is
active. If any other kind of page is active, GN_CK returns. If no other
pages are in progress, GN_CK calls PG_NHB to see if pages are inhibited
for any reason. PG_NHB returns TRUE if a lamp test is in progress, if a
zone test is in progress, if the audio release timer is active, if the
panel is waiting for a page request response, or if the panel is waiting
for a weather warning tone request response.If PG_NHB returns TRUE,
GN_CK will return.

The code then calls FS_DN to get the state of the gooseneck microphone
keying. This is compared to the microphone prior state, and if there is
no change, GN_CK returns.

If the gooseneck microphone was just keyed, the code calls MK_ON to turn
on the misrophone keyed indicator, and calls PG_RQ to transmit a page
request to the matrices. It then calls SEL_GA to select gooseneck
microphone audio to be fed to the matrices. It marks the panel status as
page pending and sets the page type to gooseneck.

If the gooseneck microphone was just unkeyed, the code calls PGR_ZR to
reset the page request timer, MK_ON to turn on the misrophone keyed
indicator, and calls PG_RQ to transmit a page request to the matrices.
It then calls SEL_GA to select gooseneck microphone audio to be fed to
the matrices. It marks the panel status as page pending and sets the
page type to gooseneck.

If the gooseneck microphone was just keyed, the code will reset the page
request response timer via a call to PGR_ZR, turn the microphone keyed
indicator off and mark the panel status as page released. It then
schedules the audio release by calling WR_ARL and sends a page release
message to both matrices. It then cleans up the indicators by turning
off the voice ready and busy/cutoff indicators. Finally, it sets the
page type to no page in progress.

#### Area Warning Checks

At the bottom of the main loop, we call AW_CK to process area warning
changes. When AW_CK is called, it checks to see if it is running on an
area warning panel. If it is not running on an area warning panel, it
returns.

On an area warning panel, AW_CK will call NO_PG to see if any pages are
in progress. NO_PG checks to see if the page status is equal to idle.
(No pages.) If a page is in progress, AW_CK returns. If no pages are in
progress, AW_CK calls PG_NHB to see if any operations are in progress
that should inhibit page attempts. If there is an operation in progress,
AW_VK returns.

If page transistions are allowed, AW_CK calls AWKS to get the current
area warning key status and compares it to the previous area warning key
status. (AWPS) If there is no difference, AW_CK returns.

If an area warning transistion is detected, the new state is saved.and
the code determines if the key was just turned on or off.

If the area warning key was just turned on, the code sets AW_MD on to
indicate that the panel is in area warnig mode. It then starts a loop
where is turns off all zone select indicators and records all the zone
select buttons as being deselected. It then builds a new (empty) global
tray map for each side. The last action is to send an area warning key
on message to both matrices.

There are two ways to handle turning the area warning key off. Which is
executed is determined by the area warning tone state when the area
warning key switch was turned off.

If the area warning tone was active when the area warning key switch was
turned, an area warning release message is sent to both matrices. The
code next records the key as being off, and turns off the area warning
indicator. It also turns off the busy/cutoff indicator.

The above tasks are not performed if area warning tone was off when the
area warning key was turned off.

After handling the area warning tone tasks, if required, the code will
record the area warning mode as being off, and sends an area warning key
switch off message to both matrices.

### LAWI OPERATION

After the system was designed a cable plant limitation came to light
which required a new panel type. This new panel was required to
interface to wall mounted switch stations for the activation and
deactivation of local area warnings.

The system originally provided an interface to these switch stations,
but they were indicators only, which notified the PAWS of their
activation. The original method relied on local beacons and distributed
area warning tone.

The new system is actually required to initiate an area warning for the
activated zone. Activation of the switch station will cause the Local
Area Warning Interface (LAWI) to request an area warning tone page to
the activated area. This means that the area warning tone will be routed
to the activated zone from the tone generator on the matrix secondary
card via the crossbar switch on the matrix primary card. When the area
warning tray is activated in these areas, the local beacons will also be
activated.

Because of the need to be able to override a local area warning
activation by an area warning panel, the LAWI can not use the regular
panel code, as the priority on the area warning tone request is such
that other area warning panels could not override the page.

There are two, simple changes to the regular panel code in order to
generate the LAWI code.

The first change is in PC.ASM. During hardware initialization, the LAWI
will strobe PORT D bit 2 in order to reset the LAWI daughter card. There
is also a 10 millisecond delay after resetting the LAWI daughter card to
give it time to completely reset before the panel begins operation.

The second change is in UART.ASM. In the page request routine, PG_RQ,
conditional assembly will cause the LAWI to send it\'s area warning
requests at a lower priority than the normal area warning tone requests.

There are no other software changes from normal panel code.

### PSIC OPERATION

The paging and area warning system actually consists of two paging and
area warning systems, one for the industrial area and one for the LC-39
area. Certain pages must go to selected zones in both areas. The Paging
System Interface Card (PSIC) was designed to handle this requirement.

PSIC\'s are installed in pairs, one for the A side and one for the B
side. They act as a bridge between systems. To one of the PAWS, they
appear as just another panel, and have the normal serial links to the
matrices for voice and signalling. On the other system, they appear to
be just another old style tray. The tray side system will be referred to
as the master side, and the panel side system will be referred to as the
slave side.

The slave side system controls which zones the bridged page will be
routed to by downloading a configuration to the PSIC just as it would
for a normal panel.

The master side system controls when a page bridges the two system by
controlling when it activates the tray associated with the PSIC.

The PSIC itself monitors the tray output from the master side system,
using the tray drive signal as a PTT input. By using the tray drive for
it\'s PTT, the amount of difference between normal panel code and PSIC
code is minimalized.

In addition to the mod that uses the tray drive for the PTT input,
several other minor mods were required for the PSIC software. Since
there is no operator to select a zone on the PSIC, and no zone buttons,
the PSIC code has a modification so that it will do the zone select
whenever it is powered up and anytime the tray mapping on the zone
changes.

A modification is required in order to compensate for the lack of normal
hardware. The code that actually controls the indicators is stubbed out
because there are no indicators on the PSIC. This includes the audio
indicator.

Another modification is required to stub out the the keyboard scanning.
Since there are no zone buttons for the operator to press, new routines
run in place of the normal zone select scanning.

The PSIC features a serial diagnostic port on the front panel. It is
interfaced to the SCI interface of the microcontroller. This allows
limited diagnostics to be performed while the PSIC is powered up and
operational.

The actual differences between the regular panel code and the PSIC code
are listed below.

#### Main File Differences

There are several differences in the initialization of the
microcontroller between the normal panel code and the PSIC code. There
are also a few differences in the main loop code between the normal
panel code and the PSIC code.

#####  Initialization Differences

Due to the lack of certain hardware devices, the PSIC initialization of
the microcontroller is a little different from normal panel code. On the
PSIC, PORTA is initialized to all inputs, since the upper nybble is no
longer required to drive hardware. The code that resets the zone select
indicator drivers is not present in the PSIC.

On the PSIC, PORTD D pins 2 through 5 are set to inputs as they are not
required to drive hardware.

On the normal panels, all pins of PORT G are set to output, but on the
PSIC, only the high nybble of PORT G is set to output.

The PSIC has an additional serial link that connects to a front panel
connector. The UART for this interface is a part of the microcontroller
itself. The PSIC code calls the routine RST_SC to initialize the data
structures used for the SCI interface to the front panel.

The PSIC has the additional requirement to select the zone for button
0,0. In order to do so, it has to track the state of this zone select
button. It does this with the zone selected variable, ZN_SEL. This is
initialized to FALSE, indicating that the PSIC has not yet selected the
zone.

The actual SCI registers are initialized with a small block of inline
code for 9600 baud, 8 data bits and odd parity.

Normally the panel code would read the state of two sense lines coming
from the front panel card to determine what kind of panel it was
attached to, but in the PSIC, the code forces the panel type to an ops
panel, since there is not a front panel card.

Normally, right before a panel enters the main loop, it announces a
reset by beeping, sending a reset message to the matrices. The PSIC has
no audio indicator, so the code to initiate a beep is not present. A
normal panel will also enable a test tone output from an onboard tone
generator. The PSIC does not have this tone generator, so it cannot be
selected.

#####  Main Loop Differences

There are only a few differences in the main loop between a normal panel
and the PSIC. The first difference is the PSIC calls DO_SCI near the
bottom of the main loop in order to process any data received from the
front panel serial link. This link is only used for diagnostics. DO_SCI
will attempt to assemble and process a message suing data received from
the front panel serial link.

Near the bottom of the loop, the normal panel code will check to see if
it is running on an administrative panel, and if it is, it will call
GN_CK to see if a page is being initiated using the gooseneck
microphone. Since the PSIC is hardcoded to an Operational panel, this
block of code was removed.

The last difference in the PSIC code occurs at the very bottom of the
loop. Here the PSIC code calls XMTS in an effort to transmit a byte to
the front panel serial link. The serial output for the diagnostics port
is polling driven.

#### Keyboard Differences

There is no front panel card, so there are no zone select buttons on a
PSIC. This means that PSIC zone selection processing is very different
from normal panel code.

The routine DO_ZS is replaced with a PSIC specific routine. This version
of DO_ZS first checks the ZN_SEL flag to see if button 0,0 has already
been selected. If it currently selected, (TRUE) then the code will
return.

If ZN_SEL indicates that button 0,0 has not been selected, then the code
will load register A with the scan code for button 0,0 and translate
that to a map number. It then calls KHIT for normal zone selection
processing.

In KHIT, when the code marks the zone as pending on, it also sets ZN_SEL
TRUE. If the button is being turned off, ZN_SEL is set FALSE. The button
should never be turned off on the PSIC, but just in case some error
causes this to happen, the state is updated so that sometime later it
may re-selected.

The normal panel code calls PTT to check the state of the microphone
Push To Talk switch. This is used to initiate and terminate normal
pages. In the PSIC, there is no microphone. The PSIC is slaved to a
tray. On the PSIC a special version of PTT is used.

On the master side, the matrix treats the PSIC slot just like any other
control tray output card. It will write a bit pattern to a certain
memory location in order to control which trays are keyed and which
trays are unkeyed.

On the PSIC, this memory address actually selects a FIFO register. That
way, every time the matrix keys or unkeys the tray, the PSIC FIFO will
save the command the matrix sent.

The PSIC will check the FIFO status flag. If there is no data in the
FIFO, the PSIC version of PTT will return the microphone prior state.
(MPS) This indicates that the microphone Push To Talk switch is in the
same state as it was when last checked. If the FIFO status register
indicates that data is availble in the FIFO, the PSIC will read the data
and check the bit that controls the keying and unkeying of the first
tray for that slot.

(There are four trays controlled by each Control Tray Output Card.
(CTOC) Only the first tray is used by the PSIC.)

Based on the bit for the first tray, the PSIC version of PTT will return
TRUE if the bit indicates the tray is keyed, and returns FALSE if the
bit indicates that the tray is unkeyed.

There are two additional routines that differ on the PSIC. FS_DN is
normally used to check the state of the foot switch used on the
administration panel for paging with the gooseneck microphone. On the
PSIC, this routine always returns FALSE. This routine should never be
called on the PSIC as it is hardcoded to be an ops panel. Just in case,
if some error results in FS_DN being called, it will indicate that no
gooseneck page is being attempted.

The other routines that differs on the PSIC is AWKS. This routine is
called to see if the position of the area warning key has changed. On
the PSIC, this routine always returns FALSE. It should never be called
on the PSIC, but just in case some kind of error results in this routine
being called, it will indicate that the area warning key is in the
inactive position to keep the PSIC from attempting an area warning
activation.

#### LED Differences

The file LED.ASM contains all the code associated with indicator
processing. Since the PSIC doesn\'t have any indicators, the code to
control the indicators is stubbed out at a very low level in the PSIC
version of the code. There are 9 pairs of routines that have been
modified. Each pair has a turn on and a turn off routine that has been
stubbed out. These routines cover the zone select indicators and 8
special indicators. The special indicators are:

-   Microphone keyed

-   Voice ready

-   Busy/Cutoff

-   Area Warning

-   Aux Audio

-   Alaram enabled

-   Lamp test

-   Sonalert alarm

#### Message Assembly Differences

The file MSG.ASM contains all the code used for message assembly and
validation. Because the PSIC has a front panel serial port in addition
to the dual UART used as a serial link to the matrices, it has an
additional buffer for message assembly. SRMB is used in the same manor
as URM_A and URM_B except it buffers messages received via the front
panel diagnostic port.

In addition to the new structure, MDS_INIT is modified on the PSIC so
that SRMB is initialized in addition to URM_A and URM_B.

#### Timer Processing Differences

The file TMR.ASM contains the code for processing the various timers
used on the panel. One modification was required for PSIC operation. In
TM_TST, in the loop that processes expired tray test timers, if the zone
select test fails, the zone selected flag (ZN_SEL) is set to false. This
will cause the zone select to be attempted again later. It will continue
until the zone select test passes.

#### UART Differences

There are two differences in the file UART.ASM associated with the PSIC.
Because of the front panel diagnostic port, there is an additional
serial receive buffer, SCI_R which must be initialized by UD_INIT. To
support interrupt driven reception for the diagnostics port, the SCI
interrupt vector actually has an interrupt handler installed. (SHND)
UART.ASM also contains the diagnostics port receive handler, SHND.

#### SCI

The file SCI.ASM contains the code that assembles, validates and
processes messages received from the diagnostics port. It also contains
the code used to send messages to the diagnostics port. DO_SCI is called
from the main loop to try and assemble and process a valid message. If a
valid message is assembled, then it will be decoded and processed.

There are only a few things that can be done from the diagnostics port.
You can read any memory location. You can write to any RAM location. You
can force a PSIC reset and you can zero out the error count tables. This
limited number of operations was implemented in order to support
checkout of the PSIC hardware prior to the development of the final PSIC
code.

In addition to the assembly and processing of received messages, SCI.ASM
also contains code that support polling driven output to the serial
port. XMTS is called at the bottom of the main loop. It will output
another byte to the diagnostics port if there is anything to transmit
and the SCI transmit buffer is empty.

### MATRIX OPERATION

The matrix software is event driven. The events that the matrix software
reacts to are received messages, timers and pull station transistions.
The event processing is implemented by a polling loop. Serial
transmission, serial reception and the basic system timer are
implemented as interrupt handlers.

The first block of matrix code initializes the microcontroller. After
the microcontroller is initialized, the code checks to see if the EEPROM
in the CPU needs to be updated. Due to certain hardware constraints, the
interrupt handlers can not be run from the XICOR EEPROM that serves as
the main memory device. These routines have to be placed in the CPU
EEPROM for execution. If changes between the CPU EEPROM and the XICOR
EEPROM are detected, the new interrupt handler code is moved into the
CPU EEPROM.

After any required CPU EEPROM programming, the CPU\'s real time
interrupt is enabled.

The code then initializes the matrix data structures, followed by
hardware initialization.

Before the software enters the main polling loop, it calls a routine to
send a reset message to the system consoles.

The first task of the main loop is to call a routine that resets the
CPU\'s watchdog timer. The watchdog timer will generate an interrupt if
a certain period of time passes without the timer being reset. This
feature is used to reset the matrix in the event that a software bug
causes the matrix to stop executing the main loop.

After resetting the watchdog timer, the matrix will check to see if any
of the local area warning pull stations have changed state. If one or
more change state, new area warning maps are constructed and
distributed.

After the local area warning pull station processing, DO_PNL is called.
It will attempt to assemble a message from a panel..

Because the matrix sits between the system consoles and the panels, it
acts as a router for all traffic between the systems consoles and the
panels. Many of the messages received by the matrix are simply forwarded
to the destination device. Some messages will require processing by the
matrix.

After assembling a panel message, the next task is to fill the large
buffers. The matrix uses a dual UART for communications between the
matrix and the system consoles. The matrix software uses a pair of
buffers for received data. When a byte is received, the interrupt
handler will place the byte in a small circular buffer. The code in the
main loop moves any data that is in the small circular buffer into a
large buffer. This double buffering of the received data is forced by
hardware constraints.

Because code can not be executed out of the XICOR EEPROM while it is in
a programming cycle, some code must execute from the CPU\'s EEPROM. The
XICOR programming cycle takes 10 milliseconds. Any code that can not be
disabled for 10 milliseconds must be placed in the CPU\'s EEPROM. In the
case of the matrixl, the real time interrupt and the UART interrupt must
be placed in the CPU\'s EEPROM. This also requires that the interrupt
table itself must be placed in the CPU\'s EEPROM, as reading the XICOR
during a programming cycle will corrupt the contents of the XICOR.

The CPU\'s EEPROM is very small, so the size of the interrupt handlers
must be minimized.

Due to addressing limitations of the microcontroller, the size of the
UART receive buffer had to be limited to 256 bytes, otherwise the size
of the UART receive interrupt handler would have exceeded the allowable
size.

While the 256 byte buffer is more than large enough to hold all bytes
received while the XICOR is in a programming cycle, during a download,
where the matrix receives several new mappings from the system console
that require the XICOR to be programmed. This causes the received
messages to back up in the buffer as the messages are received faster
than they can be programmed into the XICOR. Eventually the received
bytes overflow the small buffer and configuration information is lost.

In order to prevent this from happening, the matrix will drain the small
buffer, moving the received data to a large buffer, before it executes
any code that may require a XICOR programming cycle. Before the main
loop tries to assemble a message received from the A side system
console, it will move the bytes in the side A small buffer to the side A
large buffer and the bytes in the side B small buffer to the side B
large buffer. This insures that the small buffers will not overflow
while any received message is being processed. After the two small
buffers have been drained, the main loop calls a routine that attempts
to assemble a message from the A side system console.

After attempting A side message assembly, the main loop will once again
drain the two small buffers before calling the code to assemble a side B
message.

After processing the messages received from the system consoles, the
matrix will process any panel messages that were assembled.

After processing any assembled panel messages, the code calls a routine
to see if any timers have expired.

Because the matrix has to control trays, which are basically relays,
which due to mechanical inertia take some time to actually react to a
command, it makes heavy use of timers. When ever a new style tray is
commanded to a new state, the matrix will start a timer for that tray.
When the timer expires, enough time has passed that the tray should have
reached it\'s commanded state, so the matrix checks the feedback contact
to see if the tray is working.

This actually occurs in two steps. When the timer expires, the tray is
moved to a list of trays to be checked. There are two lists, one
contains trays that are to be verified on and the other list contains
trays to be verified off. When the timer expires, the tray is moved to
the proper list.

After all expired timers have been processed, the code will call DO_VON
which will process all trays that have been placed on the verify on
list. After doing all the verify on trays, the code calls DO_VOF which
will process all trays that had been placed on the verify off list.

#### Microcontroller Initialization

The first thing done for microcontroller initialization is to set up the
stack pointer so that subroutines can be called. Next we clear the block
protect flags. This allows us to program the CPU EEPROM. Clearing the
block protect flags must be accomplished within the first 64 cycles
after coming out of reset. If this operation is delayed, the CPU
hardware will lock out clearing the block protect register.

Next the option register is set to enable slow clock resets, and the
watchdog period is set to 1 second.

The microcontroller has circuitry to detect the fact that the clock
input to the chip is lower in frequency that a certain minimum. If this
condition is detected, the microcontroller will go through a reset.

The watchdog timer is a timer that counts up with each clock. When it
reaches overflow, a reset is generated. There is a programmable
prescaler that drives the watchdog timer counter. We set the prescaler
for divide by 64, which yields a watchdog timer period of a little over
a second.

After setting the options register, the code sets the chip select
register. The microcontroller is capable of generating several chip
select signals for external chips. We select two I/O chip select lines
to be active low during the address valid phase of bus cycles. The
general select line is also programmed as active low, and is mapped to
the lower 32K of the memory map. This line is used to select a 32K RAM
chip on the matrix card.

The clock stretch register is set to add 3 extra cycles for bus accesses
via the first I/O chip select. The second I/O chip select has one extra
cycle added. The general chip select and the program chip select do not
have any additional wait states added.

The chip select control register is programmed to enable both I/O chip
selects as active low. The PROG chip select is enabled, and mapped to
the upper 32K of the memory map. This line is used as the chip enable
for a 32K XICOR EEPROM on the matrixl card.

After setting up the chip select registers, the code will record the
contents of the RST variable. This value is used to indicate the reason
the CPU reset. The value is placed in a CPU register by the code that is
run by the reset vector. This value is moved into a RAM location after
the chip

select lines have been set up. This location can be read using the PDS
program to determine the reason for the last reset the matrix
experienced. This is only a single location, so information is only
recorded for the last reset. Information about prior resets are lost.

Port D is not connected, but it is programmed for outputs and
initialized low. Bit 0 of port G is used to initiate the weather warning
tone generator on the matrix secondary card. The high nybble of port G
are the chip select lines.

#### CPU EEPROM Checks

The main memory device in the matrix is a 32K XICOR EEPROM. This
contains the configuration information, as well as containing the
majority of the code. Due to the nature of the XICOR EEPROM, you can not
perform any reads from the XICOR while it is in a programming cycle. The
programming cycle can take as long as 10 milliseconds. During this
period, the CPU must be running code that resides somewhere besides the
XICOR chip. Any operation that can not be suspended for 10 milliseconds
needs to reside in a different location.

In our case, this turns out to be the interrupt handlers, the interrupt
vector table and the code that is used to program the XICOR.

The microcontroller used in PAWS has a small amount of EEPROM built into
it. In order to allow the system to program configuration information
into the XICOR, certain code had to be moved to the CPU EEPROM. The code
that resides in the CPU EEPROM consists of the code to program the
XICOR, the DUART interrupt handlers, the real time clock interrupt code,
and the interrupt vector table.

Since the vector table resides at the top of the memory map, all of the
indicated code must reside there. Since the XICOR chip is also mapped to
the top of the memory map, the code can be assembled to reside at the
top of the memory map. Only one block of memory can actually reside in
the top block of the memory map, the CPU EEPROM or the XICOR EEPROM.
Since the CPU EEPROM is an image of the XICOR EEPROM, the system will
run with either block mapped to the top.

When one block is mapped to the top block, the other block is no longer
accessible to the controller.

It was desired that from a maintenance standpoint, no special operations
would be required when upgrading the code in any of the PAWS units. This
required a rather involved method of updating the CPU EEPROM code.

If the new code in the XICOR has any changes to the interrupt handlers,
the vector table or the code that programs the XICOR, it will not appear
in the CPU\'s memory map as the CPU EEPROM is mapped to this region.

Some method had to be found that would allow the CPU to detect the fact
that the code in the top of the XICOR did not match what was programmed
into the CPU EEPROM. The method used is fairly simple. All of the code
that ends up in the CPU EEPROM is contained in a single file, uart.asm.
We run the CRC of the source file uart.asm, and this CRC is recorded in
two locations in the XICOR EEPROM. One of these locations is at the top
of the XICOR and the other is much lower.

If the contents of uart.asm changes, then the new CRC is recorded in the
two locations in the XICOR EEPROM. Since the CPU EEPROM is mapped to the
highest block, the top CRC will be the one programmed into the CPU
EEPROM while the lower one will be the new CRC in the XICOR. If these
two don\'t match, then the code in the CPU EEPROM needs to be updated.

#### CPU EEPROM Programming

At this point, things get a little tricky. The contents of the top of
the XICOR EEPROM need to be copied into the CPU EEPROM, but you can\'t
see the contents of the top of the XICOR as it is masked by the CPU
EEPROM.

There is a register that controls where the CPU EEPROM appears in the
memory map. In order to copy the top of the XICOR contents to the CPU
EEPROM, we have to move the CPU EEPROM lower in the memory map. After
the CPU EEPROM has been moved, we can copy the contents of the top of
the XICOR to the CPU EEPROM. After we have programmed the correct
contents into the CPU EEPROM, we need to move the CPU EEPROM back to the
top of the memory map.

These operations occur in a sequence of steps with CPU resets separating
them. This is required because in order to change the address the CPU
EEPROM is mapped to, you must change the register contents, and then
reset the CPU because the mapping address is latched early in the reset
cycle and cannot be altered. In other words, in order for the CPU EEPROM
is actually be mapped to the new address, the CPU must go through a
reset. The whole sequence is:

After the CPU finishes the microcontroller register configuration, it
will check the address the CPU EEPROM is mapped to. If it is mapped to
the normal running address, then the code will check the two CRC\'s to
see if they match. If the two CRC\'s match, then the system is ready to
run. The code disables changes to the CPU EEPROM contents or location
and then returns to the next task.

If the two CRC\'s don\'t match, then the CPU EEPROM needs to be moved
lower in the memory map, and the CPU needs to be reset.

The code will disable changes to the CPU EEPROM contents, and then it
erases the config register, which is the register that controls where
the CPU EEPROM is mapped to. At this point the CPU EEPROM is mapped to
\$fe00 to \$ffff because an erased EEPROM cell contains all 1\'s.

The code now programs the contents of the config register to map the CPU
EEPROM to \$0e00 - \$0fff. After the programming cycle is complete, all
changes to the config register or CPU EEPROM contents are disabled, and
the code traps to a loop until the watchdog timer causes a reset.

After coming out of the prior reset, the CPU will eventually end up at
PGM again. This time, the config register contains CPU_VFY, indicating
that the CPU EEPROM is mapped low. The code then calls EC_OK to see if
the contents of the CPU EEPROM matches the high block of the XICOR
EEPROM. EC-OK compares each byte in the CPU EEPROM to the corresponding
byte in the XICOR EEPROM. If any byte doesn\'t match, EC_OK returns
FALSE. At this point, we know that the contents don\'t match, because at
least the CRC values don\'t match. Because EC_OK returns FALSE, the code
protects the contents of the config register, then erases the contents
of the CPU EEPROM. After the erase is complete, the code will program
each byte from the top of the XICOR EEPROM into the CPU EEPROM. Before a
byte is programmed, the watchdog timer is reset in order to insure that
the system doesn\'t reset during CPU EEPROM programming. After all bytes
have been programmed, the CPU traps to a loop and waits for the watchdog
reset.

After coming out of reset this time, the code ends up PGM again. This
time, the config register contains CPU_VFY, so the code call EC_OK.
Since we just programmed the CPU EEPROM from the XICOR EEPROM, the
contents will match and EC_OK returns TRUE. This causes MCE to protect
the CPU EEPROM and erase the config register. After the config register
is erased, it is programmed with CPU_RUN, which locates the CPU EEPROM
in the top of the memory map. The code then traps to an endless loop and
waits for the watchdog reset.

After the CPU comes out of reset this time, it ends up in PGM. The
config register indicates that the CPU EEPROM is mapped to the top of
the memory map. The code calls MC_OK to see if the two CRCs match. Since
they do, PGM returns. After the return from PGM, the mainline code
enables the real time clock interrupt.

#### Data Structure Initialization

First off the code initializes several simple variables. RB_MAX is set
to the maximum number of bytes that we will process in a single attempt
to assemble a message. The limit is required in order to keep the code
from hanging on a noisy line that is generating a constant stream of
garbage.

Next TRC is set TRUE. This will cause certain errors and sequences to be
announced.

#####  Error Tables

The matrix software maintains several tables that contain counts of
various errors that have occurred. These tables can be read using PDS.

Every time a certain type of error occurs, the count for that error type
is incremented. The count will stop before it rolls around to 0. One
table tracks various software errors. Another tracks the health of the
serial links between the matrix and the panels and system consoles. A
third table tracks errors that can occur while the interrupt handlers
are running. A reset will clear the error counts by calling EC_INIT. The
error counts can also be cleared under software command.

#####  List Initialization

After clearing the error counts, the initialization code calls L_INIT to
initialize the panel polling list and the pull station polling list.

In order to keep the matrix as responsive as possible, by keeping the
latency down, the matrix will only check for messages from panels that
are listed as being connected to the system. In the same manner, the
matrix will only check local area warning pull stations that are listed
as being installed in the system.

The list of panels installed is part of the matrix configuration, and is
stored in the XICOR EEPROM as a bit map. By storing it in the EEPROM,
the list of installed panels is non-volatile. When the matrix is reset,
it walks the installed panel bit map and builds a list of installed
panels in a special structure. This structure not only contains the
number of each installed panel, it also contains a scanning index.

The scanning index is used by the matrix software to keep track of which
panel to process next. The matrix code will only attempt to assemble a
message from a single panel in each pass. When a panel is checked for
messages, it \"moves\" to the bottom of the list, so on the next pass a
different panel will be checked. All other panels will be checked for
messages before the first panel is serviced again.

To speed up the matrix code, the panel numbers are not actually moved,
instead the scanning index is incremented each time so that it points to
a new panel. When the scanning index reaches the end of the list, it
wraps back around to 0.

The matrix also keeps a list of the local area warning pull stations
that is used in exactly the same way.

#####  UART Data Structures

The DUART uses two small circular queues for buffering received
characters. These buffers are set to empty and the insertion and
extraction indices are set to the first slot. The transmit buffers are
marked as empty and the transmitters are marked as idle.

#####  Real Time Counter Initialization

All of the timing in the matrix is derived from a 4 millisecond real
time clock interrupt. Each real time interrupt bumps a real time
interrupt counter. In the main loop, any real time timer interrupts that
have occurred are run through the software based timer chain. This
allows us to defer timer processing when busy without dropping any timer
ticks.

The real time clock interrupts go into a tick counter which is used for
short duration times. This timer overflows into a click counter for
longer durations. The click timer overflows into a \"seconds\" counter
for even longer durations. The \"seconds\" are also recorded as a 32 bit
elapsed time.

The actual implementation bumps the tick count (TICKS) in the real time
interrupt handler. These are then \"moved\" into the real time interrupt
count (RTI_CT) one at a time in the main line. This insures that all
possible \"times\" actually occur, even if they are not as far apart as
they should be. Each RTI_CT represents 4 milliseconds. After processing
any tasks that were due to run at that tick, the code bumps the
fractional click count.

After 16 fractional clicks, the actual click count (KLIKS) is bumped,
and then any tasks due to run at that click are processed. Each click is
64 milliseconds, which gives a maximum time of a little 16 seconds for
click based timers. After processing the click based work, the
fractional seconds count is bumped. There are 16 clicks in a \"second\"
so the system\'s seconds are actually 1.024 seconds each. When the
fractional seconds count reaches 16, the seconds based tasks are run and
the seconds since starting count is bumped.

Time initialization zeros the tick counter (TICKS), the real time
interrupt counter (RTI_CT), the fractional clicks counter (FRAC), the
click counter (KLIKS), the fractional seconds counter (SFRK) and the
seconds counter (SECS.)

#####  Console Message Buffers

The system contains a buffer that is used to hold messages that are
being sent to the system consoles. The buffer is marked as being free.

#####  Message Assembly Structures

Messages are assembled from a stream of received bytes and validated by
a small state machine. A structure maintains the current state for
message assembly as well as a small push back buffer. In the event that
error is detected during message assembly, the first byte of the message
is discarded, and the code searches through the remaining bytes for the
next start marker. If one is found, it, and all of the following bytes
are moved to the push back buffer. Bytes will always come from the push
back buffer first before the code goes to the receive buffers for input.

The matrix has two message assembly structures for the system consoles
and 128 message assembly structures for the panels.

For each of the 130 structures, the message assembly state is set to
looking for Start Of Message. (SOM) The push back buffer is set to empty
and the push back buffer extraction index is set to 0.

#####  Tray Structure Initialization

There are two types of trays used in PAWS, the new style trays which
have a feedback contact, and the old style trays that have no feedback.
As far as the matrix is concerned, a tray can be activated for one of
two reasons, it can be used in a page, or it can be activated to see if
it is working. (A tray test.)

Because the trays are basically relays, which have inertia, new style
trays take some time to reach their commanded state. The matrix needs a
way of keeping track of the state of the trays so it can test the new
trays at the proper time.

The matrix also has to track the priority of the page that a tray is
passing and the panel that is using the tray for a page because the page
may be interrupted by a higher priority request. The matrix needs the
priority of the current page so it can tell if a new request should
receive the tray. It needs the owner of the tray in the event that the
page is overridden by a higher priority request because the matrix must
notify the panel that lost the tray that it was overridden.

While a tray can only be used for one page, any number of tray tests can
occur in conjunction with a page, or as a group of tray tests on the
tray. Because more than one panel may be waiting to see if a tray works,
each tray record has a bit map of panels waiting on tray test results.

TT_INIT is called to initialize the tray record. During the first phase
of TT_INIT, each tray record is initialized by OT_INIT. This marks the
tray as free, (Not being used for a page or tray test.) it also marks
the tray as not installed. It will record the state of the tray as
inactive (not keyed) and set the page priority field to the lowest
priority. The owner field is set to a special value that indicates no on
own the tray, and the tray test bit map is zeroed out.

After all tray records are initialized by OT_INIT, the tray structure
initialization code runs two routines that finish initializing the tray
structures.

As mentioned before, there are two types of trays, an old style tray and
a new style tray. The matrix maintains two bit maps in the XICOR EEPROM,
one is a map of the new style trays that are installed, and the other is
a bit map of the old style trays installed.

REC_NT will walk the bit map, and for every bit that is set, it will
mark the tray structure for that tray as being a new style tray.

After running REC_NT, REC_OT is run. It walks the old style tray bit map
and for every bit that is set, it will mark the tray structure for that
tray as being an old style tray.

Because of the order that these routines are run in, if a tray is listed
as being a new style tray and an old style tray, the matrix will treat
it as an old style tray.

#####  Circular Queue Initialization

The matrix software uses several circular queues as FIFOs for processing
certain tasks. Due to the time lag between commanding a tray to a state
and the tray reaching that state, tray operations require that the
matrix \"remember\" that something is supposed at some time in the
future when working with new style trays.

The matrix maintains 4 FIFOs using circular queues for tray operations.
There is a timer on circular queue, TON_CQ, a verify on circular queue,
VON_CQ, a timer off circular queue, TOF_CQ, and a verify off circular
queue, VOF_CQ.

When a new style tray is keyed, the matrix records the time it should
reach it\'s keyed state, and places the tray number on the TON_CQ. The
matrix code will check the TON_CQ once each pass, and if the timer for
the \"first\" tray has expired, the tray number is moved to the verify
on queue.

Once each pass, the matrix code will check the verify on queue, VON_CQ,
to see if there are any trays that need to be checked. All trays on the
verify on queue will be processed, and the tray number will be removed
from the VON_CQ.

When a new style tray is unkeyed, the matrix records the time it should
reach it\'s unkeyed state, and places the tray number on the TOF_CQ. The
matrix code will check the TOF_CQ once each pass, and if the timer for
the \"first\" tray has expired, the tray number is moved to the verify
off queue.

Once each pass, the matrix code will check the verify off queue, VOF_CQ,
to see if there are any trays that need to be checked. All trays on the
verify off queue will be processed, and the tray number will be removed
from the VOF_CQ.

Because each matrix is responsible for up to 128 panels, there may be
many panels that have assembled messages waiting in their message
assembly buffers. Each time the matrix finishes assembling a panel
message, it places the panel number on the assembled messages list,
AS_LST.

Once each pass the matrix will check the assembled message list and
process any assembled messages. When the message is processed, the panel
number is removed from the list.

To decrease the time required to add and remove tray and panel numbers
to these lists, a circular queue is used. Each queue has an insertion
index, and extraction index and a count of the number of the number of
items on the list.

To add an item to the list, it is recorded in the slot identified by the
insertion index, and the insertion index and list count are incremented.
To remove an item from the list, the extraction index is incremented and
the list count is decremented.

During data structure initialization, the 5 circular queues are
initialized to empty by setting the insertion and extraction indecies to
0 and setting the list count to 0.

#####  CLR_IPM

The matrix maintains a bit map of panels that are paging, known as the
in progress map. This map is used as part of the information in
determing if the matrix needs to send a cutoff message to the panel when
preempting a tray. If the in progress map does not indicate that the
panel is making a page, no cutoff message is sent. It is possible that
the panel was just running a tray test.

During data structure initialization, all of the bits in the in progress
map are cleared.

##### CLR_PPM

The matrix maintains a bit map of panels that have received a cutoff
message, known as the page preempt map. This map is used as part of the
information in determing if the matrix needs to send a cutoff message to
the panel when preempting a tray. If the page preempt map indicates that
the panel has already received a cutoff message, no cutoff message is
sent. This can happen when a page is overridden by more than one other
panel, but the cutoff message is only transmitted for the first tray
lost.

During data structure initialization, all of the bits in the page
preempt map are cleared.

##### AM_INIT

The matrix uses several maps to track which trays are in area warning
mode. Trays can be placed in area warning mode by either an area warning
panel, or by a local area warning pull station. The matrix will generate
the area warning map it broadcasts to the panels by ORING together the
panel caused area warning map with the local area warning pull station
caused area warning map.

The matrix also saves a copy of this merged map as the final map.

In order to cut down on traffic on the system, the matrix will only send
out a new area warning map to the panels if there is some change to the
set of trays that are in area warning mode.

In order to do this, the system must compare the old map, the last map
sent to the panels, with the new map that was generated. If they differ,
the new map is sent to each panel. If they are the same, the map is not
sent out.

One other related map is initialized, the local area warning pull
station state map. This is a bit map, one bit for each of the 128 local
pull stations the matrix supports. If the bit is set, that indicates
that the corresponding local area pull station is active. If the bit is
clear, the pull station is inactive.

This map allows the matrix to detect when the state of a local area
warning pull station has changed. New maps are generated whenever one of
the local area warning pull stations changes state.

AM_INIT initializes these maps by calling CLR_GAW, CLR_LAW, CLR_PSS,
CLR_FAW, and CLR_OAW.

##### Newest Active Tray Initialization

The PAWS supplies a way of monitoring system operation by allowing the
system operators to listen in on the pages that the system is
performing. There is no summing hardware in the PAWS, so the global sum
of pages can not be monitored. The method provided allows you to hear
the newest page on the system. While you are monitoring a page, if
another page is initiated, the monitor function switches to the new
page.

This feature allows you to designate a tray as the monitor tray. The
monitor tray will always be slaved to the newest page in the system. A
record is kept of the newest active tray, which is the tray the monitor
tray will be slaved to. This tray number is initialized to the null tray
number.

##### Large Buffer Initialization

The dual UART code buffers received characters in a small circular
queue. These queues are not large enough to prevent lost messages during
a download where the matrix may spend most of it\'s time programming
EEPROM locations, so there are two large circular buffers maintained
that provide the bulk of storage for received data. The buffers are
initialized to empty, and the insertion and extraction indices are set
to 0. Before entering a section of code that may result in EEPROM
programming, the contents of the small buffers are moved to the large
buffers so there will be enough room to buffer all received data during
the EEPROM programming.

##### Run Time Initialization

The matrix maintains a record of the amount of time it\'s been running
since the last reset. This is a 32 bit count that is incremented about
once a second. (The time period is actually a little over one second.)
This can be read using PDS. When troubleshooting a matrix problem it
will often be helpful to look at the reason for the last reset, and look
at SSS (Seconds Since Starting) to see how long ago the reset occurred.
If the matrix is resetting (other than power on resets from being turned
off and on) you will need to start tracking down the failure.

##### Page Count Initialization

The matrix maintains a record of how many pages each panel has
performed. Each panel has a 16 bit counter that is bumped each time a
panel makes a page. You can view the page count table with PDS to get an
idea of the amount of system activity. The count will stop when it
reaches \$ffff. A command has been provided to allow you to zero the
page count table after you have retreived the data.

#### Hardware Initialization

Early in the reset cycle the microcontroller hardware is initialized,
but there are other harware resources that need to be initialized after
some of the data structures have been initialized.

#####  Dual UART Initialization

DU_INIT initializes the dual UART used to communicate with the matrices.
The UART is set up for 9600 baud, 8 data bits, odd parity. The receive
interrupts are enabled, but the transmit interrupts are disabled. (They
are enabled once there is something to transmit.)

#####  IM_INIT

The matrix has a chassis containing the cards used for the serial links
to the panels. This chassis is known as the input module, and the cards
contained in it have FIFOs that are used for serial communications with
the panels. These FIFOs need to be initialized in order to function
properly. IM_INIT will call a routine to reset the receive and transmit
FIFO for each panel.

#####  TR_INIT

The matrix has a chassis containing the cards used for control of the
trays. This chassis is known as the output module, and the cards
contained in it have the registers that are used to control the trays
and read the feedback contacts. Each register controls 4 trays. Writing
to the register will allow you to key or unkey the trays. Reading the
register will return the state of the feedback contacts for the trays.
(Actually there can be 8 trays on a register counting area warning
trays, which are keyed and unkeyed seperately from the normal tray.)

Because the register controls more than one tray, and you can not read
back the register to see the state of the other trays, the software must
maintain an image of the write register so that it can control each tray
without affecting the others.

During tray initialization, the code will unkey all trays and update the
register images to show all trays as being unkeyed.

#####  CBS_INIT

Audio routing within the PAWS is handled by a MITEL cross bar switch
controlled by the microcontroller on the master matrix card. This chip
allows you to connect any input to any output. A given input can drive
any number of outputs, but an output can only be connected to a single
input.

This routine will set all of the trays to the idle source, and
initializes the OIS-D interface. The OIS-D interface is not active at
this time, but when activated, it will allow pages to be performed from
an OIS-D headset.

#### Interrupts

After the data structures and hardware have been initialized, the code
finally enables interrupts in the CPU.

#### Reset Notification

Every time the matrix goes through a reset, it sends a reset message to
the systems consoles. The system console keeps a record of these
messages. This allows you to detect problems before the failures are
sever enough to cause system failures.

#### Watchdog Reset

The first task in the main loop is to reset the watchdog timer. The
watchdog is a counter that rolls over after about one second. When the
counter rolls over, it forces a reset. This feature is used to insure
that if the code ever gets hung in a loop, the matrix will reset, which
improves the availibility of the system. The watchdog timer is reset by
writing two values to a special register.

#### Pull Station Processing

The first thing CHK_PS does is to check the pull station circular queue.
If the queue is empty, no pull stations are installed in the system, so
CHK_PS returns; Calling CHK_PS will bump the scanning index so that on
the next pass, a different pull station will be checked. As a result,
pull station processing is round robin. If the pull station circular
queue is not empty, CHK_PS saves the pull station number and checks the
former state of the pull station. It then runs one of two blocks of code
depending on the former state.

#####  Pull Station Former State On

CHK_PS checks the current state of the pull station. If it is still on,
CHK_PS returns.

If the pull station is now off, CHK_PS calls PS_OFF to handle pull
station deactivation.

###### Pull Station Deactivation

The first thing that PS_OFF does is to mark the pull station as inactive
and decrement the count of active pull stations. If there are still
other pull stations active, PS_OFF calls PS_CHG to process the change
and sends a message to the systems consoles indicating the pull station
deactivation.

If there are no other pull stations active, a local area warning off
message is sent to all the panels. The code next builds a new local area
warning map, (which will be empty) and a new area warning map. (Panel
generated area warnings) If the new map is empty, then an empty area
warning map is sent to all panels. If the new map is not empty, it is
compared to the last area warning map that was sent to the panels. If
there is no difference in the maps, the processing is complete. If there
is a difference, the new map is saved as the old map, and a copy of it
is sent to all panels. Finally, a message is sent to the system consoles
indicating the pull station deactivation.

####### Pull Station Change

PS_CHG builds a new local area warning map, and a new area warning map.
(Panel generated area warnings) If the new map is empty, then an empty
area warning map is sent to all panels. If the new map is not empty, it
is compared to the last area warning map that was sent to the panels. If
there is no difference in the maps, the processing is complete. If there
is a difference, the new map is saved as the old map, and a copy of it
is sent to all panels.

###### Pull Station Former State Off

CHK_PS checks the current state of the pull station. If it is still off,
CHK_PS returns.

If the pull station is now on, CHK_PS calls PS_ON to handle pull station
activation.

####### Pull Station Activation

The first thing that PS_ON does is to mark the pull station as active
and increment the count of active pull stations. If there were other
pull stations active, PS_OFF calls PS_CHG to process the change and
sends a message to the systems consoles indicating the pull station
activation.

If this is the first pull station activated, a local area warning on
message is sent to all the panels. The code next builds a new local area
warning map, and a new area warning map. (Panel generated area warnings)
If the new map is empty, then an empty area warning map is sent to all
panels. If the new map is not empty, it is compared to the last area
warning map that was sent to the panels. If there is no difference in
the maps, the processing is complete. If there is a difference, the new
map is saved as the old map, and a copy of it is sent to all panels.
Finally, a message is sent to the system consoles indicating the pull
station activation

#### Panel Message Assembly

DO_PNL is actually a large loop that looks for a panel that has received
data waiting in the matrix. It will try up to 8 times to find a panel
that has data ready. The loop will terminate as soon as it finds a panel
with data. The first thing the DO_PNL loop does is to check the polling
circular queue. If the queue is empty, no panels are installed in the
system, so DO_PNL returns; Calling NXTPNL will bump the scanning index
so that on the next pass, a different panel will be checked. As a
result, panel processing is round robin.

If the polling circular queue is not empty, DO_PNL gets the message
assembly structure for the panel, and tries to get data from the push
back buffer. If there is no data in the push back buffer, DO_PNL will
try and get data from the panel\'s FIFO. If it can\'t find data in
either place, it bumps the panel inspected count and if 8 panels have
been checked, it returns. If fewer than 8 panels have been checked, the
code goes to the top of the loop where it gets the next panel number.

We check 8 panels at a time as a comprimise. If the code only checked
one panel each time through the loop, the latency to get around to
checking the last panel is too high. If we checked all installed panels
in a single pass, the tray processing latency and pull station
processing latency becomes excessive. By doing a small block of panels
each pass, the total system latency is a more reasonable value. The 8
panel figure was arrived at empirically using the first PAWS system when
it was installed in the lab.

If panel data is found, message assembly is attempted. Message assembly
is driven by a loop that attempts to get a received byte and add it to
the message being assembled. The loop is counter driven to limit the
amount of time the matrixl will spend attempting to assemble from a
given panel. The loop terminates when the maximum number of bytes have
been processed, there are no more received bytes to process, or when a
message has been assembled.

If a received byte is available, an attempt to add it to the message
being assembled is performed by a state machine.

There are four major phases in message assembly. The first phase is
waiting for the Start Of Message (SOM) marker. Once SOM has been
detected, the second phase is waiting for the optional data length. Once
the optional data length has been received, the code can calculate how
many more bytes appear before the end marker. The third phase is
processing the balance of the message, including the optional data and
the CRC bytes. By running the received CRC through the CRC calculation,
the results will be 0 if the message was correctly received. After
checking the CRC, the last phase is waiting for the End Of Message (EOM)
marker.

If a complete message is received and validated, the panel number is
removed from the polling list, and added to the assembled message list.

#### Fill Large Buffers

Received characters are stored in a small circular queue by the UART
interrupt handler. This buffer is limited to 256 bytes due to
limitations on the size of the interrupt handler.

Because code can not be executed out of the XICOR EEPROM while it is in
a programming cycle, some code must execute from the CPU\'s EEPROM. The
XICOR programming cycle takes 10 milliseconds. Any code that can not be
disabled for 10 milliseconds must be placed in the CPU\'s EEPROM. In the
case of the panel, the real time interrupt and the UART interrupt must
be placed in the CPU\'s EEPROM. This also requires that the interrupt
table itself must be placed in the CPU\'s EEPROM, as reading the XICOR
during a programming cycle will corrupt the contents of the XICOR.

The CPU\'s EEPROM is very small, so the size of the interrupt handlers
must be minimized.

Due to addressing limitations of the microcontroller, the size of the
UART receive buffer had to be limited to 256 bytes, otherwise the size
of the UART receive interrupt handler would have exceeded the allowable
size.

(Using a larger buffer would require using larger instructions and more
code, which would exceed the amount of memory available for the
interrupt handler.)

While the 256 byte buffer is more than large enough to hold all bytes
received while the XICOR is in a programming cycle, during a download,
where the panel receives a new mapping from the panel buttons to trays
required, it will receive up to 128 messages that require the XICOR to
be programmed. This causes the received messages to back up in the
buffer as the messages are

received faster than they can be programmed into the XICOR. Eventually
the received bytes overflow the small buffer and configuration
information is lost.

In order to prevent this from happening, the matrix will drain the small
buffer, moving the received data to a large buffer, before it executes
any code that may require a XICOR programming cycle.

Before the main loop tries to assemble a message received from the A
side system console, it will move the bytes in the side A small buffer
to the side A large buffer and the bytes in the side B small buffer to
the side B large buffer. This insures that the small buffers will not
overflow while any received message is being processed.

The large buffers provide a 1024 byte circular queue for buffering
received data. Data is moved from the small circular queue to the large
buffer by LD_BA and LD_BB, which handle the A side and the B side
respectivly. When called these routines move data from the small buffer
to the large buffer until the large buffer is full or the small buffer
is empty.

#### System Console Message Processing

Each matrix is connected to two system consoles. Message processing is
the same for both sides with the exception of which data structures are
being used, and which side is recorded as the current side.

##### Message Assembly

Message assembly and processing is driven by a loop that attempts to get
a received byte and add it to the message being assembled. The loop is
counter driven to limit the amount of time the matrix will spend
attempting to assemble from a given system console. The loop terminates
when the maximum number of bytes have been processed, there are no more
received bytes to process, or when a message has been assembled.

The process of adding a byte is performed by PSCB. The routine attempts
to add a single byte to the message being assembled. It first checks the
push back buffer for the message. If there are any bytes in the pushback
buffer, it gets a byte from there to add.

If the push back buffer is empty, the code checks the large buffer. If
any bytes are there, it gets a byte from the large buffer to add.

If both the push back buffer and the large buffer are empty, message
assembly terminates for this pass.

If a received byte is available, an attempt to add it to the message
being assembled is performed by a state machine.

There are four major phases in message assembly. The first phase is
waiting for the Start Of Message (SOM) marker. Once SOM has been
detected, the second phase is waiting for the optional data length. Once
the optional data length has been received, the code can calculate how
many more bytes appear before the end marker. The third phase is
processing the balance of the message, including the optional data and
the CRC bytes. By running the received CRC through the CRC calculation,
the results will be 0 if the message was correctly received. After
checking the CRC, the last phase is waiting for the End Of Message (EOM)
marker.

If a complete message is received and validated, the message is handed
off to the message decode/process routines by calling DO_SCM.

##### Message Processing

System console message processing starts with an inspection of the high
byte of the command. The code extracts the destination to see if the
message is addressed to the matrix or one of the panels. Messages
addressed to the matrix are handled by calling SCM_MM. Messages
addressed to one of the panels are processed by calling SCM_PM. If the
message is not addressed to either, the code calls E_RPT to record the
error and send an error message.

After one of the above routines are called, MBF_RES is called to reset
the message assembly structure.

######  Matrix Message Processing

SCM_MM performs first level decoding by looking at the low nybble of the
high byte of the command. Writes are handled by calling SCM_WR, requests
are handled by calling SCM_RQ, and commands are handled by calling
SCM_CM. If the operation is not one of these types, E_RPT is called with
ERR_15 as an argument.

####### Matrix Writes

SCM_WR performs the second level decoding for write messages. It
inspects the low byte of the command to see what type of write is being
requested. Bit map writes are handled by MTX_BMW, tracking tray writes
are handled by MTX_TTW, and local tray map writes are handled by
MTX_LTW. Any other write is an error, and results in E_RPT being called
with an argument of ERR_16.

########  Bit Map Writes

MTX_BMW gets the number of optional data bytes so it can compute the bit
map length. The bit map length is saved in a local variable. It next
extracts the bit map number from the message and saves that in a
variable. It checks the bit map number to insure that it is valid, and
calls E_RPT with an argument of ERR_17 if it is not valid.

If the bit map number is valid, it gets a pointer to the start of the
bit map in the message and saves this as the source address. Using the
bit map number, it calls GET_BMA to get the address of the bit map in
EEPROM. This is saved as the destination address. It loads the source
address, destination address and length in the proper registers and
calls BM_CHG to see if the maps differ.

If the maps differ, the new map is copied to the EEPROM by a call to
XIR_WR. After recording the new bit map in memory, it calls RE_LST to
perform any required cleanup. (Such as generating a new polling list.)

######## Tracking Tray Writes

MTX_TTW gets the tracking tray map number. It checks the bit map number
to insure that it is valid, and calls E_RPT with an argument of ERR_1F
if it is not valid.

If the tracking tray number is valid, it saves the address of the
destination in a local variable. It then grabs the tray number from the
message and checks to see if it is valid. If the tray number is invalid,
E_RPT is called with an argument of ERR_07. If the tray number is valid,
it is compared to the tray number stored at the destination address to
see if they differ. If they differ, the new value is stored im memory
via a call to XIR_WR.

########  Local Tray Map Writes

MTX_LTW gets the number of optional data bytes so it can compute the bit
map length. The bit map length is saved in a local variable. It next
extracts the pull station number from the message and saves that in a
variable. It checks the pull station number to insure that it is valid,
and calls E_RPT with an argument of ERR_17 if it is not valid.

If the pull station number is valid, it gets a pointer to the start of
the bit map in the message and saves this as the source address. Using
the pull station number, it calls GT_PSMA to get the address of the bit
map in EEPROM. This is saved as the destination address. It loads the
source address, destination address and length in the proper registers
and calls BM_CHG to see if the maps differ.

If the maps differ, the new map is copied to the EEPROM by a call to
XIR_WR.

####### Matrix Requests

SCM_RQ performs the second level decoding for request messages. It
inspects the low byte of the command to see what type of request it is.
Bit map reads are handled by BMRD, configuration requests are handled by
MT_CFG, and local memory reads are handled by RDBYT. Any other type of
request will result in E_RPT being called with ERR_18 as the

argument.

######## Bit Map Reads

BMRD handles matrix bit map read processing. It first extracts the map
number from the message, and checks to see that it is valid. If it is
not valid, E_RPT is called with ERR_19.

If the map number is valid, GET_BMA is called to get the EEPROM address
where the map is stored. Next, GET_BML is called to get ehe map length.

The code now waits for the console output message buffer to be free via
a call to CMB_WT. When the message buffer is free, the code uses TC_CPY
to copy the bit map message response template to the console message
buffer. It then stores the map number in the response, and uses MOVE to
copy the EEPROM contents to the console message buffer. After the map
has been inserted into the console buffer, the code calls SND_CM with an
argument of BT_SDS to send the message just constructed to both system
consoles.

########  Configuration Requests

MT_CFG handles matrix configuration request processing.

After the system console has downloaded a new configuration to a matrix,
it verifies that the matrix contains the correct configuration. Instead
of reading the entire contents of all the maps on the matrixl, the
system console computes a CRC based on what it thinks the maps should
contain, then asks for the CRC that the matrix calculates based on the
current contents of the maps. The matrix returns the CRC it calculates,
and the system console compares it to the CRC it calculated. If they
match, the system console assumes that the download was accomplished.

######## Byte Reads

For a byte read, the matrix will extract the address to be read from the
message. The code then reads that memory location, and calls BVRPT to
build a message containing the address and the contents of that address.
The message is returned to the requesting system console. This feature
is used extensivley by PDS. It is also used to read the tray failure
tables so the system console can announce tray failures.

####### Matrix Commands

SCM_CM performs the second level decoding for command messages. It
inspects the low byte of the command to see what is being commanded. The
matrix supports 8 commands. If the low byte of the command does not
match one of the 8 supported commands, E_RPT is called with an argument
of ERR_1A.

The 8 commands supported are; Reset, Zero Page Counts, Zero Error
Counts, Add A Panel To The Polling List, Remove A Panel From the Polling
List, Reset A Panel\'s FIFO, Write A Byte, and Release A Tray.

########  Reset

The reset command is handled by performing a jump to BEG, which is where
the reset vector points. This results in the matrix going through a
power on cycle where everything is initialized.

########  Zero Error Counts

The matrix maintains a table that tracks the number of times certain
errors have occurred. Each type of error has it\'s own 16 bit counter,
and everytime the error occurs, the count is incremented. When the count
reaches \$ffff, it stops incrementing. The Zero Error Counts command is
handled by calling EC_INIT, which sets all of the error counts to 0.

########  Zero Page Counts

The matrix has a table of 16 bit counters, one for each panel, that keep
track of the number of pages that a given panel has performed. This
count is incremented each time a panel makes a page. When the count
reaches \$ffff, it stops incrementing. The Zero Page Counts command is
handled by calling ZRO_PC which sets all the page counts to 0.

######## Add A Panel To The Polling List

CMD_PP is used to add a panel to the polling list. When the matrix is
reset, it builds a panel polling list based on a map of installed panels
that has been recorded in it\'s EEPROM. Normally a panel will only
appear in the panel polling list if the system console has downloaded a
configuration to the matrix that contains that panel. For testing and
diagnostics, it is sometimes useful to place a panel in the system
temporarily. By using this command, a panel can be added to the polling
list without downloading a new configuration. The panel will not be on
the polling list after the matrix goes through a reset. Be careful, it
is possible to place a panel on the polling list twice. The system
reacts very poorly to such an error.

######## Remove A Panel From The Polling List

CMD_RP is used to remove a panel from the panel polling list. When the
matrix is reset, it builds a panel polling list based on a map of
installed panels that has been recorded in it\'s EEPROM. Normally a
panel will only appear in the panel polling list if the system console
has downloaded a configuration to the matrix that contains that panel.
For testing and diagnostics, and under certain failures, it is sometimes
useful to remove a panel from the system temporarily. By using this
command, a panel can be removed from the polling list without
downloading a new configuration.

When a panel has been removed from the polling list, the matrix will no
longer attempt to assemble messages from that panel, but any messages
addressed to that panel will still be delivered.

########  Reset A Panel\'s FIFO

CMD_PR handles the command to reset a panel\'s FIFO. Communications
between the matrix and a panel occur over a differntial serial link at
9600 baud. A 1 K hardware FIFO sits between the matrix and the UART that
talks to the panel. Under certain rare conditions, this FIFO may enter a
mode that prevents proper operation. This command will allow a single
panel\'s FIFO to be reset without affecting the operation of the rest of
the system. This feature can also be useful when troubleshooting certain
communication problems.

########  Write A Byte

WRBYT handles write byte command processing. It extracts the address and
the value to be written from the message, and write the byte to the
address.

########  Release A Tray

CMD_TR handles the forced tray release. It extracts the tray number from
the message and calls TR_RLS to unkey the tray. TR_RLS is the normal
release code for a tray, but CMD_TR bypasses the checks that are
normally performed prior to releasing a tray.

###### System Console To Panel Message Processing

SCM_PM handles forwarding of messages from the system consoles to the
panels. It calls GET_MBX to get the panel number out of the received
message and calls GET_MSL to get the insertion index in the buffer where
the message is stored. It then calls GET_MA to point to the start of the
message and calls SND_PM to actually send the message to the panel.

###### Error Reporting

E_RPT records and reports errors that occur while the matrix software is
running. It starts off by passing the error number to BMP_E to record
the error. It then calls CMB_WT to wait for the console message output
buffer to be come free. Once the buffer is free, E_RPT uses TC_CPY to
copy the error number message template to the console message output
buffer, and then copies the error number to the buffer. The last step is
to call SND_CM with an argument of BT_SDS to transmit the message to
both system consoles.

####### BMP_E

BMP_E is responsible for actually recording the error. The first thing
it does is to check the error number and make sure it\'s within range.
If the error number is valid, it calls LH_CHK to see if the error number
indicates a possible comm link problem. It then uses the error number as
an index into the error count table and bumps the count if it is not
already maxed out. (oxffff or 65535)

########  LH_CHK

The first thing LH_CHK does is to check the error number to see if the
error is one of the 5 errors that may indicate a comm link problem. The
errors are; Garbage in front of message, Panel message addressing error,
False start or corrupted length, Invalid EOM, Invalid CRC.

If the error is one of the above five, LH_CHK checks the link number to
see if it\'s within range. If it is, LH_CHK uses the link number to
index into the link health table and bumps the count there if it is not
already maxed out.

#### Panel Message Processing

DO_ASM handles processing of assembled panel messages. It calls GETASM
to retreive a panel number from the assembled message list. If there are
no panel numbers on the assembled message list, DO_ASM returns.

Once DO_ASM has a panel number from the list, it calls PTOMBA to get the
address of the message assembly structure that contains the assembled
message. It then calls DO_PMS to actually process the assembled message.

##### Assembled Panel Message Processing

DO_PMS handles the top level of assembled panel message processing. It
checks the destination address in the message to see who the message is
addressed to. The matrix receives messages from the panels that are
addressed to the matrix and messages that are addressed to the system
consoles.

The panels have no direct connection to the system consoles, so all
messages that the panel wants to send to the system console are sent to
the matrix, which has the responsibility to forward them to the system
consoles.

If the message was addressed to the matrix, PNL_MM is called to process
the message. If the message is addressed to the system consoles, PNL_FC
is called to forward the message to the system consoles. If the message
is not addressed to the matrix or the system console, E_RPT is called
with an argument of ERR_1B to record and announce the error.

The final processing in DO_PMS is common to all addresses. The matrix
data structures could be left in an invalid state if the matrix started
processing another message from a panel before it finished processing
the previous message. To prevent problems, the matrix will not start
assembling another message from a given panel until it has finished
processing the panel\'s last message.

The matrix can be working on messages from many different panels at a
single time, but there will only be one message from any given panel
being processed at any given time.

When the matrix is processing a panel message that may take some time to
completely process, it sets the message assembly structure status to
locked to indicate that it should not try assembling another message for
that panel.

Near the end of DO_PMS, it calls GET_MST to get the message structure
status. If the buffer is locked, DO_PMS returns, leaving the buffer
alone, and the panel off of the polling list. In this way, the matrix
will not start working on another message for the panel.

If the buffer is not locked, MBF_RES is called to reset the message
assembly state so that it is looking for the start of the next message.
The associated panel number is read from CURPNL and passed to ADD_PLR so
that the panel is placed back on the panel polling list.

###### Matrix Message Processing

PNL_MM handles processing of panel messages addressed to the matrix.
There are only two types of panel messages that the matrix processes,
requests and commands. PNL_MM looks at the message type and calls PNL_RQ
to handle requests and PNL_CM to handle commands. If any other type
message is received, E_RPT is called with ERR_1C to record and report
the error.

####### Panel To Matrix Request Processing

There are five types of panel requests handled by the matrix. They are;
Tray Tests, Page Requests, Area Warning Tone Requests, Weather Warning
Tone Requests, and Source Select Requests. If the low byte of the
command field matches one of these request types, a call to the routine
that processes that type of request is made. If the request is not one
of these five, E_RPT is called with ERR_1D to record the error.

######## Tray Test Processing

PNL_TT handles the tray test processing. The button number and the
address of the bit map are extracted and the software calls TR_AHR to
see if all requested trays are actually installed in the system. If some
of the requested trays are not listed as being installed, the code grabs
the panel number and calls T_RPT with PG_BR as the argument to fail the
request.

If all of the requested trays are installed in the system, the code
grabs the button number and the current panel number (the panel number
of the panel we received the message from) and calls MKPTR to construct
a tray test record for the panel. The code then calls RM_OT to remove
all the old style trays from the tray map. This is done because there is
no feedback contact on the old style trays, so they can not be tested.
Because of this, all old style trays are always assumed to be good.

After removing the old style trays, PTR_CT is called to see how many
trays are left in the tray test map. If there are no trays left, the
code branches to the completion section.

If any trays are left, they must be new style trays, so they must be
tested to see if they are operational. RM_ACT is called to check any of
the new style trays that are currently keyed.

After that, a loop is used to walk the rest of the tray test map. At the
top of the loop is a call to PTR_CT to see if there are any trays left
in the tray test map. If there are no trays left, the code will branch
to the completion section. The code calls SC_PTT to schedule a tray test
of the tray, and then calls MBF_LCK to lock the message assembly buffer.

At this point, we are waiting for the trays to actually close. The rest
of the tray test is driven from the tray timers expiring.

#########  TR_AHR

TR_AHR checks each bit in the tray bit map. If a bit is set, indicating
that the tray is being requested, TR_AHR then checks the type field in
the tray\'s record. If the value is TR_IV, then that tray does not
appear in either the old style tray list or the new style tray list. In
this case, TR_AHR will return FALSE. If it makes all the way through the
tray map, it returns TRUE.

#########  T_RPT

T_RPT will copy the tray response message template to the message output
buffer using TP_CPY. It then records the response in the message, and
stores the button number in the message. After constructing the message,
it calls XPM to send the message to the panel.

#########  XPM

XPM does all the preparation for sending a message to a panel. The
message template must have been copied to OUTP and the optional data
filled in before calling XPM. XPM will compute the number of bytes the
CRC must be calculated over. It then runs the CRC calculation. Once it
has the CRC, it computes the CRC\'s location within OUTP and stores the
CRC there. It then computes the message length and calls SND_PM to
transmit the message.

######### SND_PM

SND_PM is the code that actually sends the message in OUTP to the panel.
First it checks to see if the panel number is valid. If it is not a
valid panel number, E_RPT is called with an argument of ERR_09. If it is
a valid panel number, the code calls GET_PSA to get the panel\'s FIFO
record address.

SND_PM now enters a loop that sends each byte of the message. At the top
of the loop, it gets the address of the panel\'s FIFO status register.
It then reads the FIFO\'s status and checks to see if the transmit FIFO
is full. If the transmit FIFO is full, the code branches back to the top
of the loop. It will keep polling the FIFO transmit status until the
transmit FIFO is not full.

(Please note that the transmit FIFO is 1024 bytes deep, and should never
back up.)

Once there is room in the transmit FIFO, the code gets the source
address (where it is in OUTP) and fetches a message byte. The code then
gets the transmit FIFO address and writes the message byte to the
transmit FIFO. After that, it increments the source address and
decrements the message length. If the message length is still greater
than 0, it jumps to the top of the loop.

######### MK_PTR

MK_PTR builds a record used in processing tray tests in the panel\'s
test record structure. This same structure is used for processing page
requests, which means that only one panel operation should be processed
at a time. MK_PTR uses the panel number to get the address of the
panel\'s test record. It then saves the button number in the record, and
sets the operation type to tray test.

The code next clears the pass and fail flags, and copies the tray test
bit map from the message to the panel\'s test record. The last thing it
does is to count the number of set bits in the map and save this in the
panel\'s test record.

#########  RM_OT

RM_OT is used to remove old style trays from a tray test bit map. Old
style trays do not have a feedback contact, so their position can not be
verified. Since they can not actually be checked, they are defined to
always be good.

RM_OT uses the panel number to find the address of the panel\'s test
record. With the address of the panel\'s test record, it can find the
address of the bit map itself. It then starts a loop to walk the bit
map, looking for set bits. When it finds a set bit, it goes to the
corresponding tray record and checks the tray type. If it\'s an old
style tray, it clears the bit from the panel\'s test map, sets the tray
passed flag, and decrements the tray count. If it\'s now zero, RM_OT
returns, as there are no more bits set.

#########  PTR_CT

PTR_CT uses the panel number index into a table to fetch the address of
the panel\'s test record. Once it has this address, it fetches the set
bit count from the count field and returns it.

#########  RM_ACT

RM_ACT is used to remove new style trays that are currently active from
a tray test bit map.

RM_ACT uses the panel number to find the address of the panel\'s test
record. With the address of the panel\'s test record, it can find the
address of the bit map itself. It then starts a loop to walk the bit
map, looking for set bits. When it finds a set bit, it goes to the
corresponding tray record and checks the tray type. If it\'s an old
style tray, it clears the bit from the panel\'s test map, sets the tray
passed flag, and decrements the tray count. If it\'s now zero, RM_OT
returns, as there are no more bits set.

######### SC_PTT

This routine handles starting the testing of the new style trays. It
uses the panel number to get the address of the panel\'s test record. It
then gets the address of the bit map within the record and starts
walking the bit map. For each set bit, it calls IT_FREE to see if the
tray is currently idle. If the tray is not free, the code branches to
..MARK. If the tray is free, the code calls VT_ON to key the tray, calls
ST_ON to start the timer for the movement of the tray, and calls ADD_TON
to place the tray number on the timer on list, and calls ST_PON to set
the tray\'s status to pending on. (To indicate that the tray has been
keyed and we\'re just waiting long enough to get to it\'s new position.)
The code then falls through to ..MARK.

At ..MARK the code gets the panel number and calls MRK_TT to record the
fact that the current panel is waiting on a tray test on the tray .

######## Page Request Processing

PNL_PG handles the page request processing. When a page request comes
in, PNL_PG resets the area warning and weather warning request flags,
then using the panel number, it calls PTR_NR to record in the panel\'s
structure that it is not using area warning or weather warning
processing. It then calls PNL_TR to finish processing the page request.

#########  PNL_TR

PNL_TR is the common back end that handles the bulk of the page request
processing for all types of pages. (Regular pages, weather warning tone
requests, and area warning tone requests.)

The first thing PNL_TR does is to save the address of the message
assembly structure that it is processing. It then clears the flag that
indicates that it has processed the first tray in the request. (This is
used in newest active tray tracking which allows monitoring the
operation of the paging system.)

The page priority and the address of the tray map are saved. PNL_TR then
verifies that the request is not empty by calling TR_NT. TR_NT checks
each byte of the tray map until it finds a byte with one or more bits
set. If there are no trays in the tray map, PNL_TR calls P_RPT with
PG_NT (no trays) as the argument to return the results to the requesting
panel.

If the tray map is not empty, PNL_TR calls TR_AHR to see if all
requested trays are listed as being installed in the system. If one or
more requested trays are not installed, the code calls P_RPT with PG_BR
as the argument to indicate a bad request. (Due to illegal trays.)

Next the code calls TR_AAH to see if all requested trays are available.
A tray is available if it is not being used or it is being used at a
lower priority than the current page. If one or more of the requested
trays are being used at a priority equal to or greater than the current
request, PNL_TR calls P_RPT with PG_BZ as the argument to send a
response to the panel indicating that some of the trays are busy.

If nothing has prevented the page up to this point, PNL_TR calls MK_PPR
with the current panel number in order to build a page map. It then
passes the current panel number to SET_IPB so that the panel is marked
as having a page in progress. The code then enters a loop where it walks
the tray map. When it finds a set bit, it checks ..SET to see if it has
already selected a new newest active tray.

If this is the first tray in the bit map, it records the tray as the
newest active tray and checks to see if there has been a global tray
assigned. If there is a global tray, VT_ON is called to key it. The code
then sets ..SET to TRUE to indicate that it has assigned a newest active
tray from the current page.

PNL_TR then calls GRB_TR with the priority in order to key the tray or
to route audio through it. It then calls ADD_AWT to add the tray to the
delta area warning map in case we\'re doing an area warning page.
Finally, it increments the tray number and checks to see if it has
completed walking the map. If it has, the code returns.

#########  MK_PPR

MK_PPR builds a panel page record for the indicated panel. It first
locates the correct structure based on the panel number passed to it. It
then resets all the flags except the area warning and weather warning
flags. (These were set before this routine was called if they are
needed.)

It then sets the operation type to page and copies the tray map to the
record. After the tray map is recorded, it counts the number of set bits
in the map and stores the count in the panel page record.

######### GRB_TR

This is the routine that actually acquires trays for use in the page. A
new style tray can be in one of six states; free, pending on, verify
on,active, pending off, and verify off. Old style trays can only be free
or active.

GRB_TR calls TR_STAT to get the tray state. It then checks to see which
of the six states the tray is in, and vectors to one of three targets
depending on the current state. The three targets are ..FRE, ..DWN, and
..ACT. If the state is not one of the six states listed above, E_RPT is
called with ERR_10 as an argument to record the error. PPR_TF is then
called with the panel number as an argument to record a tray failure in
the panel\'s record by setting the tray fail flag.

For a free tray, the code calls TR_TYP to see if the tray is an old
style tray or a new style tray. If it is not marked as either, E_RPT is
called with ERR_11 to record the error and PPR_TF is called with the
current panel number to set the tray failed flag in the panels record.

If the free tray is an old style tray, the code calls PPR_TP to set the
tray passed flag in the panel\'s record and then calls TR_OTF to handle
the rest of the processing.

If the free tray is a new style tray, the code calls TR_NTF to handle
the rest of the processing.

For trays that were pending off or verify off, the target is ..DWN. The
code here grabs the priority of the page and calls TR_TGD to mark the
trays as being required for a page. The code that releases the trays
will check a flag to see if the tray is required for a page, and seeing
the flag set will key the tray.

For trays that are active when the page request is processed, the code
at ..ACT will call TR_TYP to get the tray type and vector to one of two
targets

If the tray is listed as a new style tray, TR_PEA is called to handle
the rest of the processing.

If the tray is an old style tray, the code will check to see if the new
owner is the same panel as the old owner. If it is the same panel,
AT_OFF is called to release the area warning tray, (It will be picked up
later if it is required.) the code then grabs the panel number and calls
PPR_TP to indicate that at least one tray passed. The code then gets the
priority and the tray number and calls TR_OTF to finish the rest of the
processing

If the old style tray is being picked up by a different panel, the code
calls PPR_TP with the new panel number to set a flag indicating that at
least one tray passed. It then calls ROUTE with the new panel number to
select the proper audio to route to the tray. At that point it calls
PRE_MT to notify the former owner that it was cutoff. (If required.)
AT_OFF is called to release the area warning tray, (It will be picked up
later if it is required.) the code then grabs the panel number and calls
PPR_TP to indicate that at least one tray passed. The code then gets the
priority and the tray number and calls TR_OTF to finish the rest of the
processing. (Yes, there is some redundancy here, the code actually
branches back to an earlier sequence which results in two calls to
PPR_TP. This does not cause any harm.)

If the tray is not an old style tray or a new style tray, E_RPT is
called with an argument of ERR_12 to record the error, and PPR_TF is
called to set the tray failed flag in the panel\'s record.

#########  TR_OTF

The code calls IAWTR to see if an area warning tone request is being
processed. If it is, it calls SET_AT to set the area warning bit in the
tray record\'s flag field, and calls CLR_WT to reset the weather warning
tone bit in the tray record\'s flag field. It then branches to ..BAL for
completion of old tray processing.

If it is not processing an area warning tone request, the code calls
IWWTR to see if a weather warning tone request is being processed. If it
is, it calls SET_WT to set the weather warning bit in the tray record\'s
flag field, and calls CLR_AT to reset the area warning tone bit in the
tray record\'s flag field. It then falls through to ..BAL for completion
of old tray processing.

If it is not processing an area warning tone request or a weather
warning tone request, it calls CLR_AT to reset the area warning bit in
the tray record\'s flag field, and calls CLR_WT to reset the weather
warning bit in the tray record\'s flag field before branching to ..BAL
for completion of old tray processing.

..BAL is the start of actual old tray processing. It grabs the priority
and calls VT_ON to key the tray. It then calls TR_AO to mark the tray as
passing audio for the owning panel, and calls ST_ACT to set the tray\'s
status to active.

The code then grabs the current panel number and calls ROUTE to select
the proper audio source for the tray. It then calls RM_TP passing it the
current panel number and the tray number to remove the tray from the
panel record\'s paging map, and calls PPR_TP to indicate that at least
one tray worked when the page was attempted.

The code then calls PG_END to see if it has finished processing trays
for this page.

If it has, PG_END will send the required response to the panel.

######### TR_NTF

The code calls IAWTR to see if an area warning tone request is being
processed. If it is, it calls SET_AT to set the area warning bit in the
tray record\'s flag field, and calls CLR_WT to reset the

weather warning tone bit in the tray record\'s flag field. It then
branches to ..BAL for completion of new tray processing.

If it is not processing an area warning tone request, the code calls
IWWTR to see if a weather warning tone request is being processed. If it
is, it calls SET_WT to set the weather warning bit in the tray record\'s
flag field, and calls CLR_AT to reset the area warning tone bit in the
tray record\'s flag field. It then falls through to ..BAL for completion
of new tray processing.

If it is not processing an area warning tone request or a weather
warning tone request, it calls CLR_AT to reset the area warning bit in
the tray record\'s flag field, and calls CLR_WT to reset the weather
warning bit in the tray record\'s flag field before branching to ..BAL
for completion of new tray processing.

..BAL is the start of actual new tray processing. It grabs the priority
and calls VT_ON to key the tray. It then calls TR_AO to mark the tray as
passing audio for the owning panel, and calls ST_TON to set the tray\'s
expected on time, ADD_TON to add the tray number to the timer on list
and ST_PON to set the tray\'s status to pending on. It then calls
MBF_LCK to lock the message assembly structure so no other message are
processed from the current panel.

The code then grabs the current panel number and calls ROUTE to select
the proper audio source for the tray. The balance of the new tray
processing will be performed when the tray\'s timer expires in the
future.

######### TR_TGD

The code first calls TR_AO to set the owning panel number, the page
priority and the passing audio flag in the tray\'s record.

The code calls IAWTR to see if an area warning tone request is being
processed. If it is, it calls SET_AP to set the area warning pending bit
in the tray record\'s flag field, and calls CLR_WP to reset the weather
warning tone pending bit in the tray record\'s flag field. The balance
of the processing will be performed when the tray has reached the off
state and the code there checks to see if any operations for that tray
are pending.

If it is not processing an area warning tone request, the code calls
IWWTR to see if a weather warning tone request is being processed. If it
is, it calls SET_WP to set the weather warning pending bit in the tray
record\'s flag field, and calls CLR_ATPto reset the area warning tone
pending bit in the tray record\'s flag field. The balance of the
processing will be performed when the tray has reached the off state and
the code there checks to see if any operations for that tray are
pending.

If it is not processing an area warning tone request or a weather
warning tone request, it calls CLR_AP to reset the area warning pending
bit in the tray record\'s flag field, and calls CLR_WP to reset the
weather warning pending bit in the tray record\'s flag field. The
balance of the processing will be performed when the tray has reached
the off state and the code there checks to see if any operations for
that tray are pending.

######### TR_PEA

This routine is used to preempt a new style tray that is already active,
or shortly will be. The code will check to see if the new owner is the
same panel as the old owner. If it is the same panel, AT_OFF is called
to release the area warning tray. (It will be picked up later if it is
required.) The code then calls TR_STAT to figure out which list the tray
is on, the pending on or the verify on list.

If the tray is on the pending on list, the tray number is removed from
the pending on list. If it is on the verify on list, the tray number is
removed from the verify on list.

The code then calls TR_NTF to handle the balance of the new tray
processing.

If the new panel is not the same as the old panel, ROUTE is called to
select the proper audio source for the tray and PRE_MT is called to
handle preemption processing for the panel that lost the tray. Next
AT_OFF is called to release the area warning tray. (It will be picked up
later if it is required.) The code then calls TR_STAT to figure out
which list the tray is on, the pending on or the verify on list.

If the tray is on the pending on list, the tray number is removed from
the pending on list. If it is on the verify on list, the tray number is
removed from the verify on list.

The code then calls TR_NTF to handle the balance of the new tray
processing.

######### PRE_MT

The code first calls CHK_IPB with the panel number to see if the panel
still has a page in progress. If the panel does not have a page in
progress, the code returns as there is nothing that needs to be done.

If the panel does have a page in progress, the code calls CHK_PPB to see
if the panel has already received a cutoff message. If it has, the code
braches to ..BAL for the completion of the processing.

If the panel has not already received a cutoff message, SET_PPB is
called to mark the panel as having been preempted and C_RPT is called
with the panel number to send a cutoff message to the panel before the
code falls through to ..BAL.

..BAL is the entry point for the remaining preemption processing. It
calls RM_TP to remove the tray from the panel record\'s paging map, and
calls PG_END to see if it has finished processing trays for this page.
If it has, PG_END will send the required response to the panel.

######### PG_END

PG_END is called with a tray number. It passes this to OWNER to get the
number of the panel that is using the tray for a page. With the panel
number, it calls PTR_CT to see how many trays are left in the panel\'s
page map. If there are trays left, PG_END returns

If the page map is now empty, the code calls CHK_PPB to see if the panel
was preempted. If the panel was preempted the code gets the address of
the message assembly structure using PTOMBA. It then calls GET\_ MST to
see if the structure is locked. If the structure is locked, ADD_PLR is
called to put the panel back ion the panel polling list, and MBF_RES is
called to reset message assembly so the code will be looking for the
start of a new message.

If GET_MST indicates that the structure is not locked, MBF_RES is called
to reset message assembly so that the code will be looking for the start
of a new message.

If the panel was not preempted, the code calls ASK_TR to get the tray
test results and then passes the result to P_RPT which sends the
required response back to the panel. After sending the response, the
code gets the address of the message assembly structure using PTOMBA. It
then calls GET\_ MST to see if the structure is locked. If the structure
is locked, ADD_PLR is called to put the panel back on the panel polling
list, and MBF_RES is called to reset message assembly so the code will
be looking for the start of a new message.

If GET_MST indicates that the structure is not locked, MBF_RES is called
to reset message assembly so that the code will be looking for the start
of a new message.

########  Area Warning Tone Request Processing

PNL_AT handles the area warning tone request processing. It sets AWTR
TRUE and sets WWTR FALSE to indicate that an area warning request is
being processed. It then calls ZRO_DM to clear the area warning delta
map. The code then calls PTR_AW with the current panel number to mark
the panel\'s record as doing area warning processing. It then calls
PNL_TR to handle the tray processing.

After PNL_TR returns, the code calls SUM_AW to build a new global area
warning map containing both the local area warning initiated trays and
area warning panel initiated trays. The code will then call NW_AWT to
build a new area warning tray map message.

After building the message, the code calls FA_MT to see if the area
warning map is empty. If the map is empty, it is sent to all panels to
insure that all panels stop indicating area warning. If the map is not
empty, the code calls FO_DIF to see if the old map and the new map are
the same. If there are not any deltas in the map, the code returns as
the panels have already received the map. If the two maps differ, SV_FA
is called to save a copy of the new map and then SALL is called to send
the message to all panels that are listed as being installed.

########  Weather Warning Tone Request Processing

PNL_WT handles the weather warning tone request processing. It sets AWTR
FALSE and sets WWTR TRUE to indicate that a weather warning request is
being processed. It then calls PTR_WW with the current panel number to
mark the panel\'s record as doing weather warning processing. It then
calls PNL_TR to handle the tray processing.

######## Source Select Processing

PNL_SS handles source select processing. The code starts by setting two
local variables false. These variables indicate that at least one tray
was good and at least one tray was bad. After initializing the local
result variables, the code will get the requested audio source number
from the message and save it in a local variable. and save the address
of the tray map from the message and then sets SRCFLG TRUE to indicate
that it is performing source select processing.

The code then starts a loop that walks the tray bit map in the source
select message. For each set bit, OWNER is called with the tray number
to see which panel owns the tray. If the tray is owned by the current
panel, ..OG is set TRUE to indicate that at least one tray is good .
Next, based on the indicated audio source in the source select message,
the code will will either call TIDL to kill all audio to the tray, or
call ROUTE with the current panel number to route the panel\'s audio to
the tray, or calls ROUTE with the weather warning tone selector to
initiate the weather warning tone sequence.

After selecting the source for the tray, the tray number is bumped and
checked to see if we have finished walking the bit map.

If the tray is owned by another panel, ..OB is set TRUE to indicate that
at least one tray is bad, and the code branches to the end of the loop
where the tray number is bumped and checked to see if we have finished
walking the bit map.

If the map has been traversed, SRCFLG is set FALSE because the source
select tray processing has been completed. Then, based on the values of
..OG and ..OB, the code loads a status indicating all trays failed, all
trays passed or some trays passed into the A register, loads the current
panel number into the B register and calls SS_ANS to send a source
select response to the requesting panel.

####### Panel To Matrix Command Processing

PNL_CM handles the top level of panel to matrix command processing. It
looks at the low byte of the command in the message to see which command
has been received. There are four panel to matrix commands supported.

PNL_PR is called to handle page release commands. PNL_AR is called to
handle area warning release commands. PNL_WR is called to handle weather
warning release commands. If the command is a clear panel preempt
commmand, the code gets the current panel number and calls CLR_PPB to
reset the panel\'s bit in the preempt map.

Any other command is illegal and E_RPT is called with ERR_1E and an
argument to record the error.

########  PNL_PR

PNL_PR sets AWTR FALSE to indicate that area warning trays are not being
used and calls PNL_RL to handle the actual release.

######### PNL_RL

The first thing PNL_RL does is call GET_MA to get the tray bit map
address. It then enters a loop that walks the bit map. For each set bit,
the code calls OWNER to see if the tray is owned by the current panel.

If the tray is owned by the current panel, then the code calls IAWTR to
see if the area warning tray is active in addition to the voice tray. If
the area warning trays are not active, the code calls CLR_AT to clear
the area warning tray flag.

The code then calls TR_RLS to actually release the tray, and then calls
ADD_AWT to add the tray to the AW map.

It then increments the tray number and checks to see if it finished
walking the map. If it has finished walking the map, the code calls
CLR_PPB to clear the panel\'s preempted bit, and then calls CLR_IPB to
clear the panel\'s page in progress bit.

#########  TR_RLS

TR_RLS first calls TR_NAO to set the tray\'s record to indicate that the
tray is no longer passing audio for a page. It then calls TR_STAT to get
the tray\'s state. If the tray is active, the code calls TR_TYP to get
the tray style.

For old style trays, the code calls VT_OFF to unkey the tray (VT_OFF
will also unkey the area warning tray if the area warning flag is set.)
and then calls ST_FREE to set the tray\'s status to free, and calls TIDL
to route a null audio stream to the tray.

For new style trays, the code calls FR_TRAY to handle release and test
scheduling.

If the active tray is not an old style tray or a new style tray, the
code calls E_RPT with an argument of ERR_14 to record the error.

If the tray status indicates that the tray is free, E_RPT is called with
an argument of ERR_13 to record and announce the attempt to release an
already released tray.

The other states will be taken care of as the tray completes the pending
off and verify off path.

######### FR_TRAY

FR_TRAY is called to release an active new style tray. It calls VT_OFF
to unkey the tray, and then calls ST_TOF to set the tray\'s expected off
time. It then calls ADD_TOF to add the tray number to the timer off list
and calls ST_POF to set the tray\'s status to pending off. The balance
of the release processing will be picked up by the timer code when the
tray\'s timer expires.

#########  PNL_AR

PNL_AR sets AWTR TRUE to indicate that area warning trays are being
used. It then calls ZRO_DM to zero out the area warning delta map and
calls PNL_RL to handle the actual release. After PNL_RL has completed,
DIF_AW is called to build a new global area warning difference map
containing the trays remaining in area warning, and then calls NW_AWT to
build a message containing a map of the trays left in area warning mode.

After building the message, the code calls FA_MT to see if the area
warning map is empty. If the map is empty, it is sent to all panels to
insure that all panels stop indicating area warning. If the map is not
empty, the code calls FO_DIF to see if the old map and the new map are
the same. If there are not any deltas in the map, the code returns as
the panels have already received the map. If the two maps differ, SV_FA
is called to save a copy of the new map and then SALL is called to send
the message to all panels that are listed as being installed.

#########  PNL_WR

PNL_WR sets AWTR FALSE to indicate that area warning trays are not being
used and calls PNL_RL to handle the actual release.

#### Timer Processing

All of the timing in the panel is derived from a 4 millisecond real time
clock interrupt. Each real time interrupt bumps a real time interrupt
counter. The main loop calls CK_TMR, which takes any real time timer
interrupts that have occurred and runs them through the software based
timer chain. This allows us to defer timer processing when busy without
dropping any timer ticks.

The real time clock interrupts go into a counter (TICKS) which just
buffers the timer ticks in case the software is too busy to process the
real time clock interrupts all the way through the timer chain. CK_TMR
will copy the tick count into a temporary variable and zero TICKS.

CK_TMR nows runs a loop where each \"tick\" is added to the real time
interrupt count. (RTI_CT) RTI_CT is incremented. After incrementing
RTI_CT, CK_TMR will call TM_TST, which is the routine that handles all
work that is based on ticks.

For every tick added to RTI_CT, the fractional click count is
incremented by calling TOCK. After 16 fractional clicks, the actual
click count (KLIKS) is bumped, and YAK is called to propagate the click.

YAK is called to propogate the timer increment to the seconds count.
Each click is 64 milliseconds, which gives a maximum time of a little
over 16 seconds for click based timers. Longer duration timers are based
on a seconds counter. There are 16 clicks in a \"second\" so the
system\'s seconds are actually 1.024 seconds each.

The first thing YAK does is increment the fractional seconds count,
SFRK. If SFRK has reached 16, then the seconds count (SECS) is
incremented, and the fractional seconds count is zeroed. YAS is called
to handle seconds based tasks, and BMP_RT is called to bump the 32 bit
seconds since starting counter.

#####  TM_TST, Tick Based Tasks

TM_TST is the routine that actually handles the tick based tasks. For
many tick based tasks on the matrix, an alarm time is maintained. Every
time we process another tick, we check to see if the current time is the
alarm time. If they match, the alarm has \"gone off\" or \"expired.\"

Most of these alarm times are recorded in arrays of structures, and the
structure index is stored on a circular queue in order of expiration
time. This gives the advantage of being able to check the first record
to see if processing is required. If the first alarm has not expired,
then none of the others have either, as they must have the same or later
alarm times.

The first thing TM_TST does is check the timer on list. This list
contains tray numbers for new style trays that have been recently keyed.
These trays take several milliseconds to actually reach the keyed state.
When the tray is keyed, the software got the current time (in ticks) and
added a value to it that should allow the tray to reach it\'s final
state. The tray number is then added to the timer on list.

The code calls TON_TOP to see if there is a tray on the timer on list.
If there is a tray on the timer on list, the code calls GET_TT to fetch
the alarm time and then compares it to the current time, RTI_CT. If the
time has expired, the code calls RMV_TON to remove the tray number from
the timer on list, then calls ADD_VON to add the tray number to the
verify on list. It then calls ST_VON to set the tray\'s status to verify
on.

At this point, timer on processing for this tray is complete, but it is
possible that a group of trays may have all been added to the timer on
list at once, such as when a panel performs an all call, so the code
loops back to where it calls TON_TOP. This loop continues until the
timer on list is empty, or the alarm for the tray at the top of the list
has not expired.

After processing the timer on list, TM_TST starts the second loop which
processes the timer off list. The loop starts by calling TOF_TOP to see
if there is a tray on the timer off list.

If there is a tray on the timer off list, the code calls GET_TT to fetch
the alarm time and then compares it to the current time, RTI_CT. If the
time has expired, the code calls RMV_TOF to remove the tray number from
the timer off list, then calls ADD_VOF to add the tray number to the
verify off list. It then calls ST_VOF to set the tray\'s status to
verify off.

At this point, timer off processing for this tray is complete, but it is
possible that a group of trays may have all been added to the timer off
list at once, such as when a panel completes an all call, so the code
loops back to where it calls TOF_TOP. This loop continues until the
timer off list is empty, or the alarm for the tray at the top of the
list has not expired.

###### YAK, Click Based Tasks

YAK handles running running the clicks through the fractional seconds
counter. If the fractional seconds count rolls over, the code calls YAS
to handle the seconds based work and calls BMP_S to increment the
seconds since starting count. (elapsed run time counter) On the matrix,
there are no click or seconds based tasks, but these calls remain in
place in order to maintain the seconds since starting count.

#### Verify On Processing

DO_VON handles verify on processing. Only new style trays have the
feedback contact, so only new style trays will be found on the verify on
list. There are two reasons why a tray ends up on the verify on list. A
tray can be used to pass audio in some kind of a page, or it can be
keyed as the result of a tray test. It is possible that a tray may be
used for both functions at the same time.

The first thing DO_VON does is to call VON_TOP to see if there is a tray
on the verify on list. If there is a tray on the verify on list, the
code calls RMV_VON to remove the tray number from the verify on list,
then calls ST_ACT to set the tray\'s status to active. It then calls
VV_ON to see if the tray actually closed. If the tray is now closed, the
code calls CK_TST to see if any panels are waiting on this tray for a
tray test. If any panels are waiting on this tray for a tray test,
TR_CLS is called to process the outstanding tray tests.

After calling TR_CLS, the code calls CK_VOP to see if any panel is
trying to use the tray to pass audio. If any panel is using the tray for
a page, the code calls OWNER with the tray number to get the panel that
needs the tray. It then calls PPR_TP to record the tray as passing in
the panel\'s record and then calls RM_TP to remove the tray from the
panel\'s page record map.

After removing the tray from the panel\'s test record, the code calls
PG_END to finish page request processing if required.

If no panel needs the tray for a page, the code will call IT_POF to see
if anyone has already released the tray. If the tray has not been
released, the code calls FR_TRAY to release the tray.

If VV_ON indicates that the tray is not actually closed, the code calls
CK_TST to see if any panels are waiting on this tray for a tray test. If
any panels are waiting on this tray for a tray test, TR_FAIL is called
to process the failure for all outstanding tray tests.

After calling TR_FAIL, the code calls CK_VOP to see if any panel is
trying to use the tray to pass audio. If any panel is using the tray for
a page, the code calls OWNER with the tray number to get the panel that
needs the tray. It then calls PPR_TF to record the tray as failing in
the panel\'s record and then calls RM_TP to remove the tray from the
panel\'s page record map.

After removing the tray from the panel\'s test record, the code calls
PG_END to finish page request processing if required.

If no panel needs the tray for a page, the code will call IT_POF to see
if anyone has already released the tray. If the tray has not been
released, the code calls FR_TRAY to release the tray.

##### TR_CLS, Tray Test Processing, Passed

TR_CLS handles the processing of tray test successful results. Given a
tray number, it will index into the tray record address table and get
the address for the record for the given tray. It then gets the address
of the panel map within that tray\'s record.

TR_CLS will walk the panel bit map, and for each set bit it will call
PPR_TP to set the tray passed flag in that panel\'s record. It then
calls RM_TP to remove the current tray from the panel record\'s tray
map. After removing the tray from the panel\'s map, it calls PTR_CT to
see if there are any trays left in the panel\'s record. If this was the
last tray the panel was waiting on, the code gets the button number from
the panel\'s record (a single tray may appear on different buttons on
different panels) and calls ASK_TR to get the final test results from
the panel\'s record. It then calls T_RPT to send the response to the
panel.

After notifying the panel of the test results, the code calls ADD_PLR to
add the panel to the panel polling list, and calls MBF_RES to reset the
message assembly process so that the matrix will start looking for the
start of the next mesage from that panel.

After getting the panel all set, the code bumps the panel number and
checks to see if it is done walking the tray\'s panel bit map. If it is
not done, the code branches to the top of the loop and looks at the next
panel bit.

After running all the panels, the code will clear the tray test bit in
the tray\'s record and then clears out the panel map in the tray\'s
record.

##### TR_FAIL, Tray Test Processing, Failed

TR_FAIL handles the processing of tray test failure results. Given a
tray number, it will index into the tray record address table and get
the address for the record for the given tray. It then gets the address
of the panel map within that tray\'s record.

TR_FAIL will walk the panel bit map, and for each set bit it will call
PPR_TF to set the tray failed flag in that panel\'s record. It then
calls RM_TP to remove the current tray from the panel record\'s tray
map. After removing the tray from the panel\'s map, it calls PTR_CT to
see if there are any trays left in the panel\'s record. If this was the
last tray the panel was waiting on, the code gets the button number from
the panel\'s record (a single tray may appear on different buttons on
different panels) and calls ASK_TR to get the final test results from
the panel\'s record. It then calls T_RPT to send the response to the
panel.

After notifying the panel of the test results, the code calls ADD_PLR to
add the panel to the panel polling list, and calls MBF_RES to reset the
message assembly process so that the matrix will start looking for the
start of the next message from that panel.

After getting the panel all set, the code bumps the panel number and
checks to see if it is done walking the tray\'s panel bit map. If it is
not done, the code branches to the top of the loop and looks at the next
panel bit.

After running all the panels, the code will clear the tray test bit in
the tray\'s record and then clears out the panel map in the tray\'s
record.

#### Verify Off Processing

DO_VOF handles the verify off processing for new style trays that have
been recently unkeyed.

Only new style trays have the feedback contact, so only new style trays
will be found on the verify off list. The only reason why a tray ends up
on the verify off list is that it has been released. It may have been
released as the result of a page being completed, or it may have been
released because it was only keyed for a tray test and the test has
completed. A tray can be used to pass audio in some kind of a page, or
it can be keyed as the result of a tray test. It is possible that a tray
may be used for both functions at the same time. In this case, it will
be released when the page completes.

The first thing DO_VOF does is to call VOF_TOP to see if there is a tray
on the verify off list. If there is a tray on the verify off list, the
code calls RMV_VOF to remove the tray number from the

verify off list, then calls ST_FREE to set the tray\'s status to free.
(unused). It then calls VV_OFF to see if the tray actually opened. If
the tray is now open, the code calls CK_TST to see if any panels are
waiting on this tray for a tray test. If any panels are waiting on this
tray for a tray test, it calls CK_VOP to see if any panel needs the tray
for passing audio as well.

If no panels need a tray test on that tray, it calls CK_VOP to see if
any panel\'s need the tray for a page.

If the tray is not needed for a tray test, and it\'s not needed for a
page, the code calls TIDL to route null audio to the tray and returns.

If the tray is needed for a tray test, but not a page, the code calls
TIDL to route null audio to the tray before falling through to the
balance of the reactivation code. If the tray is needed for a page, TIDL
is not called, the code branches directly to the balance of the
reactivation code.

The reactivation code starts out by checking to see if area warning or
weather warning processing is required by calling AWTP and WWTP.

If an area warning is required, the code sets the area warning flag by
calling SET_AT and clears the weather warning flag by calling CLR_WT.

If a weather warning is required, the code sets the weather warning flag
by calling SET_WT and clears the area warning flag by calling CLR_AT.

If neither an area warning or a weather warning are required, the code
clears the area warning flag with a call to CLR_AT and clears the
weather warning flag with a call to CLR_WT.

After the flags have been properly configured, the code calls VT_ON to
key the tray, then calls ST_TON to set the tray\'s on time alarm, calls
ADD_TON to place the tray number on the timer on list, and calls ST_PON
to set the tray\'s status to pending on.

##### VV_OFF, Tray Open Verification

VV_OFF calls TR_CVS to get the current state of the tray\'s feedback
contact. If the tray has not opened, the code calls F_RPT with an
argument of TF_CLS to record the tray failure. The panel is not notified
of this failure, as it has released tray some time ago.

The code then calls SAWT to see if it doing area warning processing, if
it is the code calls CLR_AT to reset the area warning flag and then
calls AT_CVS to check the current state of the area warning tray\'s
feedback contact. If the area warning tray is not open, the code calls
AF_RPT with an argument of TF_CLS to record the area warning tray
failure

###### TR_CVS

TR_CVS is called to get the current state of the voice tray\'s feedback
contact. It calls TR_ADR to get the address of the tray\'s hardware
record. This record contains information about the interface to the
tray. Using the structure address, the code fetches the status register
address from the structure. It also fetches the masks from the
structure, and then ANDs the masks with OM_VKM to extract the voice key
status bit. It then ANDs the mask with the status register contents and
returns the result.

###### AT_CVS

AT_CVS is called to get the current state of the voice tray\'s feedback
contact. It calls TR_ADR to get the address of the tray\'s hardware
record. This record contains information about the interface to the
tray. Using the structure address, the code fetches the status register
address from the structure. It also fetches the masks from the
structure, and then ANDs the masks with OM_AWM to extract the area
warning key status bit. It then ANDs the mask with the status register
contents and returns the result.

# PAWS DATA STRUCTURES

## SCOPE

This section lists the major data structures used in the PAWS system in
the panel. matrix, and PSIC code.

## STRUCTURES

For each data structure, the common name is listed, along with the size
of the data structure, the symbolic names as they appear in the source
code, the fields and values.

Most structures will also have a short description of how the structure
is used in the system.

### MESSAGE STRUCTURES.

Message Buffers For Panels. **MS_XX** (i.e. MS_00 - MS_7f)

Message buffer for DUARTS. **URM_A URM_B**

Size = 87 bytes (**MS_SZ**)

Fields:

  ----------------- --------------------- --------------------------------
  Offset            SYM                   Function

  0                 **MS_ST**             Message Status

  1                 **MS_INS**            Insertion index

  2                 **MS_END**            Completion index

  3                 **CRC_HI**            High byte of CRC

  4                 **CRC_LO**            Low byte of CRC

  5                 **MS_BF**             Message buffer (40 bytes)

  44                **PBB_CT**            Push back count

  45                **PBB_XT**            Push back extraction index

  46                **PBB_BF**            Push back buffer (40 bytes)
  ----------------- --------------------- --------------------------------

**MS_ST** VALUES

  ----------------------- ----------------------- -----------------------
  SYM                     Value                   Function

  MS_LK                   fc                      Locked

  MS_ND                   fd                      Need data

  MS_NL                   fe                      Need length

  MS_NS                   ff                      Need SOM

  MS_CMP                  0                       Message assembled
  ----------------------- ----------------------- -----------------------

As bytes are received from a serial port, the code tries to assemble
them into a legal message. This structure is where the assembly and
validation occurs.

The message status field (**MS_ST**) indicates the state of this
structure.

**MS_NS** means that the code is looking for the start of message
character. (SOM) In this state, only the SOM character is acceptable,
other characters are considered to be garbage bytes in front of the
message.

**MS_NL** indicates that the SOM has been received, and the code expects
the next byte to be the optional data length. Once the optional data
length has been received the code can compute the total message length.
With this information in hand the code can record the completion index.
When the insertion index is equal to the completion index, the complete
message has been received. (The received bytes are stored in the MS_BF
buffer.) After the data length has been received, the code is buffering
the message data itself.

**MS_ND** indicates that we buffering the message data. Once the last
byte of the message has been received, the structure state is set to
MS_CMP to indicate that a complete message has been assembled.

**MS_CMP** indicates that the message has been assembled.

**MS_LK** indicates that the message buffer is locked.

Certain messages (such as page requests containing new trays) take a
long time to fully process. When one of these messages is being
processed, the structure is locked. A locked structure prevents the
assembly of any additional message. At a later time, when the message
processing is complete, the structure is unlocked so another message may
be received.

The insertion index **(MS_INS**) indicates where in the buffer the next
byte received will be stored. Once the SOM character has been received,
the code expects to receive the optional data length byte. This byte
indicates how many bytes of optional data are contained in the message
being assembled.

**MS_END** indicates where the insertion index will be when we have
received the last byte of the message. We can not calculate the
completion index until after we have received the optional data length
byte of the message.

In order to detect and reject corrupted messages the code runs a CRC
across all bytes in the message except for the SOM and EOM (End of
Message) characters. The CRC on the bytes received so far is kept in the
**CRC_HI** and **CRC_LO** fields.

The message itself ends with a CRC and EOM. The calculated CRC is
compared to the received CRC. If they do not match, then an error has
occurred, and the message is rejected.

(The message is also rejected if the character stored at the completion
index is not the EOM character.)

If a corrupt message is detected, the SOM character is thrown away and
the bytes remaining in the **MS_BF** are saved in the push back buffer.
(**PBB_BF**) Bytes stored here are read in first, before any bytes are
processed from the serial port.

The extraction index (**PBB_XT**) indicates where the next byte is to be
read from, while the push back count (**PBB_CT**) indicates how many
bytes are left in the push back buffer.

MS_00 is used to buffer messages from panel 0 while MS_01 is used to
buffer messages from panel 1 and so forth.

### UART RECEIVE STRUCTURES.

A side UART rcv buffer: **URB_A**

B side UART rcv buffer: **URB_B**

Size = 259 byte (**URB_SZ**)

Fields:

  ------------------ ------------------ ----------------------------------
  Offset             SYM                Function

  0                  **URB_ST**         Buffer state

  1                  **URB_IN**         Insertion index

  2                  **URB_EX**         Extraction index

  3                  **URB_BF**         Circular buffer (256 bytes,
                                        URB_DS)
  ------------------ ------------------ ----------------------------------

**URB_ST** VALUES

  ----------------------- ----------------------- -----------------------
  SYM                     Value                   Function

  **URB_MT**              00                      Empty

  **URB_PR**              80                      Partially filled

  **URB_FL**              ff                      Full
  ----------------------- ----------------------- -----------------------

This structure is used to store all bytes received by the dual UART.
Since dropping even a single byte will corrupt a message, and cause it
to be discarded, dual UART reception is interrupt driven. When a byte is
received by the dual UART it is stored in this circular buffer.

**URB_IN** is the insertion index, it indicates where the next byte will
be stored.

**URB_EX** is the extraction index. This indicates where a byte will be
removed from when attempting to build a message.

**URB_BF** is the circular buffer itself. This is where the received
bytes are stored.

If the insertion index and extraction index are equal, then the buffer
is either full or empty. **URB_ST** will be equal to **URB_MT** if the
buffer is empty, and **URB_FL** when the buffer is full. If the buffer
is not empty or full, **URB_ST** will be equal to **URB_PR**. (partial)

UART reception is a bit tricky because of the memory devices used by
PAWS. The main memory device is a XICOR EEPROM, which stores the
majority of the executable code, along with the configuration data the
system consoles download to the system.

You cannot read from the EEPROM while it is undergoing a programming
cycle. This means that you cannot run any code from the EEPROM while you
are recording configuration data.

The upshot is that the interrupt handler that services the dual UART
must be stored in the EEPROM that is in the CPU, since we cannot stop
servicing the dual UART for the 10 milliseconds or so that it takes to
program new configuration information into the XICOR EEPROM. This EEPROM
is about 500 bytes, and the interrupt vector tables take up part of that
space. The dual UART interrupt handler is optimized for small size and
high speed, which is why the routine uses a circular queue. The
reception routines just store the bytes in the circular buffer, the
bytes are extracted later by mainline routines that assemble and process
messages.

### PANEL COMM STRUCTURES.

Panel comm records: **PA_XX** (i.e. PA_00 - PA_7f)

Size = 10 bytes

Fields:

  -------------------- -------------------- -----------------------------
  Offset               SYM                  Function

  0                    **PS_FAD**           FIFO address

  2                    **PS_SRA**           FIFO status address

  4                    **PS_RSM**           Receive mask

  5                    **PS_TSM**           Transmit mask

  6                    **PS_RSC**           Reset command

  7                    **PS_PSA**           Pull Station Status address

  9                    **PS_PSM**           Pull Station Status Mask
  -------------------- -------------------- -----------------------------

These structures are only present on the matrix. All traffic that flows
between the matrix and the panels flows through FIFOs that are present
in the matrix\'s memory map. The hardware actually resides on the PPIC.
(Paging Panel Input Card.)

When the matrix is ready to send a byte to a panel, it has to find the
address of the FIFO registers used to talk to that panel. There are two
FIFO addresses in each panel\'s record. One is the address of the FIFO
status register, and the second is the address of the data registers.
Within the status register is a bit to indicate if the receive buffer
has any data, and a bit to indicate if there is any room left in the
transmit buffer.

The status register contains bits for four FIFOs. Since four FIFOs share
a single status register, each panel has its own transmit status mask
and receive status mask. There is also a bit value used in resetting the
FIFO. (The address of the reset register is \"known\" because it is a
fixed offset from the FIFO status register.)

Please note that the read FIFO and write FIFO for panel communication
are mapped to the same address. Reading the FIFO address will return a
byte received from the panel, while writing to the FIFO address will
send a byte to the panel via the UART connected to the read/write FIFOs.

Another function that is supported on the PPIC is the remote area
warning input. There are fields to identify the address and bit within
the address that is used to sense the state of a remote area warning
station.

(As of this date, 10/23/95, discussion is underway on replacing the
remote area warning stations with a modified panel. If this occurs,
these fields will become unused. No software changes will be required as
you can simply download an empty pull station map to disable pull
station processing, but if you pull the pull station support code out of
the matrix, the matrix code will be a little faster, and it\'ll free up
some memory.)

The information in the table built from these records is fixed. It
supports rapid look up of addresses and masks needed to interface with
the panels. The file containing the PA_XX records is actually built by a
\"C\" program, mktab.exe.

### MESSAGE OUTPUT STRUCTURE.

Buffer for message to panels: **OUTP**

Buffer for message to DUART: **OUTC**

Size = 87 bytes (**OUT_SZ**)

Fields:

  ---------------------- ---------------------- --------------------------
  Offset                 SYM                    Function

  0                      **OUT_ST**             Status

  1                      **OUT_LEN**            Template length

  2                      **OUT_BEG**            SOM byte

  3                      **OUT_DL**             Optional data length

  4                      **OUT_CH**             High byte of command

  5                      **OUT_CL**             Low byte of command

  6                      **OUT_OD**             Start of optional data
  ---------------------- ---------------------- --------------------------

**OUT_ST** VALUES

  ----------------------- ----------------------- -----------------------
  SYM                     Value                   Function

  **OUT_FR**              00                      Free

  **OUT_BZ**              ff                      Busy
  ----------------------- ----------------------- -----------------------

OUTC is present on the matrix and the panels, while OUTP is only present
on the matrix. On the matrix, OUTC is used for sending messages to the
systems console, while on the panels, OUTC is used for sending messages
to the matrix. The matrix uses OUTP for sending messages to the panels.

Messages that originate on the panel or matrix are stored as a message
template. This contains the message itself, along with several bytes
used for transmission of the message.

When a message needs to be sent to a system console, matrix, or panel,
the message template is copied to the message output structure and any
required optional data is filled in.

For OUTC, transmission is initiated by software that reads the first
byte of the message (the SOM byte) and writes it to a UART transmission
register. As part of this sequence, the UART transmission interrupts are
enabled. This causes transmission interrupts from the UART which result
in the rest of the bytes of the message being written to the UART
transmission register.

The buffer status byte, at offset **OUT_ST**, is used to indicate the
state of the message output structure. **OUT_FR** indicates that the
buffer is idle while a value of **OUT_BZ** indicates that the buffer is
still in use.

(Some messages are sent to just the A side or just the B side system
console or matrix, while other messages are sent to both the A and the B
sides. If a message is going to both sides, transmission may be
completed on one side or the other, but the buffer can\'t be freed until
transmission is completed on both sides.)

The value stored at **OUT_LEN** is the number of bytes in the template,
which contains the message itself along with several buffer associated
values. (Including OUT_ST and OUT_LEN.) This is the total number of
bytes copied to OUTC or OUTP.

The fields starting with **OUT_BEG** are part of the message itself.
**OUT_DL** is the number of optional data bytes in the message. This
value is used in figuring out how many bytes will be used in computing
the CRC prior to sending the message. It determines how many bytes to
include in the CRC, and where in the buffer to store the calculated CRC.
When the actual transmission is set up, it is also used to compute the
number of bytes that must be written to the UART transmission register.
(This is simply the number of optional data bytes, plus the size of the
fixed message fields.)

**OUT_CH** and **OUT_CL** are the high byte and low byte of the command
field. They are not usually changed in message transmission.

**OUT_OD** is the offset to the optional data area. Any variable message
data will be recorded starting at this offset.

On the matrix, for messages being sent to the panels, transmission
interrupts are not generated. For these messages, polled output is used.
When the matrix wishes to send a message to a panel, it writes each byte
of the message to a 1K FIFO which feeds a UART without CPU intervention.
A status register indicates if the FIFO register is full. In the
unlikely event that the FIFO register fills up, the matrix CPU will poll
the status register until it can write another byte.

### OUTPUT MODULE STRUCTURES.

Tray control records: **TA_XX** (i.e. TA_00 - TA_bf)

Size = 5 bytes

Fields:

  ----------------------- ----------------------- -----------------------
  Offset                  SYM                     Function

  0                       **OM_RA**               Register address

  2                       **OM_IA**               Image address

  4                       **OM_BM**               Bit masks
  ----------------------- ----------------------- -----------------------

**OM_BM EXTRACTION VALUES**

  ----------------------- ----------------------- -----------------------
  SYM                     Value                   Function

  **OM_VKM**              f0                      Voice Key control bit
                                                  mask

  **OM_AWM**              0f                      Area Warning control
                                                  bit mask
  ----------------------- ----------------------- -----------------------

A tray is a device used to distribute audio to an area. Each tray has
two control signals. The first is used to key (activate) audio
distribution within a given area, while the second removes a 10 db pad
from the audio feed when activated, thereby increasing the audio level.

In the matrix, these control signals are referred to as the voice key
and the area warning key. (Area Warning controls the 10 dB pad.)

When a page, or other audio, needs to be sent to a given area on KSC the
matrix must route the required audio feed through a crossbar switch to
the tray and then activate the tray. In order to activate the correct
tray, it uses the tray number to index into a table of tray control
records.

Each record indicates the memory address of the register used to control
the tray, (OM_RA) the memory address of the image of the register,
(OM_IA) and a pair of bit masks packed into a byte. (OM_BM)

An image of the tray control register is required as there are control
bits for four trays packed into a single byte, (by the hardware design
of the control tray output cards, CTOC\'s) and you can not read the
current contents of the control register.

In order to control one of the four trays, independently of the other 3
trays, you must OR in or AND out a bit, without disturbing the bits for
the other trays. By keeping an image of the contents of the tray control
register, we can manipulate the bits for a given tray, and keep the bit
values for the other trays intact.

The **OM_BM** field contains a bit mask for the voice key in the upper
nybble, and a bit mask for the area warning key in the lower nybble. By
ANDing the OM_BM contents with **OM_VKM**, you are left with the single
bit that controls voice keying. **OM_AWM** is used to extract the area
warning bit from the OM_BM contents.

The sequence used to key a tray is as follows:

-   Index into the tray table using the tray number.

-   Grab the image address.

-   AND the OM_BM field with OM_VKM to get the voice key bit.

-   OR the voice key bit with the image to \"key\" the tray.

-   Save the new value at the image address.

-   Write the new value to the register address.

The sequence used to unkey a tray is as follows:

-   Index into the tray table using the tray number.

-   Grab the image address.

-   AND the OM_BM field with OM_VKM to get the voice key bit.

-   Invert the voice key bit value. (and all other bits)

-   AND the voice key bit inverse with the image to \"unkey\" the tray.

-   Save the new value at the image address.

-   Write the new value to the register address.

### LIST STRUCTURES.

Panel polling list: **PL_LST**

Pull station list: **PS_LST**

Size = 258 bytes (**LST_SZ**)

Fields:

  ----------------------- ----------------------- -----------------------
  Offset                  SYM                     Function

  0                       **LST_FR**              Free index

  1                       **LST_SC**              Scanning index

  2                       **LST_DT**              Buffer
  ----------------------- ----------------------- -----------------------

This structure is used to hold two lists, a list of the active panels
present in the system and a list of pull stations present in the system.

In order to make the system as responsive as possible, yet allow
expansion, the system will only attempt \"reception\" from devices that
are identified as being present.

Specifically, the matrix will only check those panels listed in the
**PL_LST** for input. (Messages being sent to a panel will be forwarded
to the panel even if it is not listed in PL_LST.)

Only those pull stations listed in **PS_LST** are checked to see if
their state has changed.

Once each pass through the main loop of the matrix program, the matrix
will get a new panel number from the PL_LST and check that panel\'s FIFO
to see if the panel has sent any data to the matrix.

Any received data is stored in a message buffer where the matrix
attempts to build a valid message. There is a limit to the number of
bytes that the matrix will fetch from a single panel in a pass. The
matrix will also stop fetching data from the panel as soon as a
complete, legal, message has been assembled.

On the next pass through the main loop, the matrix will get a different
panel number, and check for input from that panel.

The upshot is the matrix receives messages from all the panels listed as
being in the system in a round robin fashion.

In addition to a panel list, the matrix contains a pull station list.
Once each loop the matrix software gets a pull station number from the
pull station list and checks to see if the pull station has changed
states.

A pull station is used to activate a local area warning from within a
area. When someone activates a pull station mounted on the wall in an
area that performs hazardous operations, an area warning tone is
generated and distributed to that area. Local beacons may be activated
as well.

An important fact to note is that there are several reasons why a panel
that is present in the system may not appear in the PL_LST. If a panel
request will take some time to fulfill, the matrix will remove the panel
from the PL_LST until processing of the request is completed. This is
required because each panel has only one message buffer, and any
reception of a new message from the panel would overwrite the old
message that the matrix was working on.

Panels can also be removed from the polling list (PL_LST) under software
command. This may be required when the comm link to the panel fails,
which can cause the matrix to spend a lot of time polling the panel on
the failed link, trying to assemble a valid message. A temporary fix
would be to remove the panel from the polling list until the comm
problem can be corrected.

The system will tolerate several down comm links, but system response
drops off with each failure, and eventually a point is reached where
page attempts will start failing due to the matrix not responding to a
working panel in time.

It is a good idea to temporarily remove any panels you know are having
comm problems from the polling list until the problem is fixed. This
will result in a more robust system.

The lists are large enough to hold the maximum number of units (panels
or pull stations) with room to spare.

The **LST_FR** field indicates which slot in the list is the first open
(unused) slot. When a panel is returned to the list after having been
removed to service a long request, it will be added to the list in the
LST_FR slot, and the LST_FR value is incremented.

**LST_SC** is the scanning index. It is used to index into the list on
each pass to see which panel (or pull station) to check that pass.
LST_SC is bumped after each pass, so that on the next pass, a different
panel or pull station will be checked. (When LST_SC reaches LST_FR, it
wraps back to 0, the top of the list.)

**LST_DT** is the unit number buffer. Each slot in the list will contain
a panel or pull station number. The collection of slots (and their
contents) form the LST_DT.

### MATRIX BIT MAPS

  ----------------------- ----------------------- -----------------------
  **PN_TBL**              16 bytes                Panel present map

  **PS_TBL**              16 bytes                Pull Station present
                                                  map

  **NT_TBL**              24 bytes                New trays present map

  **OT_TBL**              24 bytes                Old trays present map

  **PP_MAP**              16 bytes                Panel preempted map

  **IP_MAP**              16 bytes                Page in progress map
  ----------------------- ----------------------- -----------------------

If a bit is set, that unit is present or marked.

The **PN_TBL** is a list of panels that the system console has indicated
are installed in the system. It is used to build the initial polling
list (PL_LST) but panels can be added to, or removed from the PL_LST for
various reasons.

The **PS_TBL** is a list of pull stations that the system console has
indicated are installed in the system. It is used to build the PS_LST.
Pull stations can be added to, or removed from the PS_LST only by
downloading a new PS_TBL.

**NT_TBL** is a list of new style trays that the system console has
indicated are installed in the system. New style trays contain a
feedback circuit that indicates the current state of the tray, active or
idle. Whenever the matrix keys or unkeys a new tray, it will test the
state of the tray a short period of time later to insure that the tray
went to the desired state. (The system has to allow about 40
milliseconds for the tray to physically reach the desired state, due to
propagation delays and mechanical inertia.

**OT_TBL** is a list of old style trays that the system console has
indicated are installed in the system. Old style trays do not contain a
feedback circuit, so their state can not be checked.

All trays in a panel\'s page request or zone select must appear in
either the new tray table or the old tray table. If a request contains
one or more trays that don\'t appear in either list, the matrix rejects
the request as an illegal request.

**PP_MAP** is a list of all panels that have already received a cutoff
message from the matrix. It is used to reduce the amount of traffic that
the matrix sends to the panel when a higher priority page overrides a
page from another panel.

**IP_MAP** is a list of all panels that are currently performing a page.
This list is used in page preemption. When the system grabs a tray for a
high priority page, the matrix checks to see if a panel that it thinks
owns the tray in question is active. If the panel does not have a page
in progress, the owning panel number is stale, or leftover from an
earlier page. In this case, the matrix does not have to send a cutoff
message to the panel.

### PANEL BIT MAPS

  ------------------- ------------------- --------------------------------
  **BSMAP**           8 bytes             Button state map (1 is active )

  **AWT_A**           24 bytes            Area Warning Trays, A side

  **AWT_B**           24 bytes            Area Warning Trays, B side

  **AWZ_A**           8 bytes             Affected Zones, A side

  **AWZ_B**           8 bytes             Affected Zones, B side
  ------------------- ------------------- --------------------------------

If a bit is set, that unit is present or marked.

**BSMAP** is a list of all zone buttons that are active. (depressed)

**AWT_A** is a list of trays that are in the area warning mode on the A
side of the system.

Whenever a panel or a pull station initiates an area warning, all panels
are notified because they must blink the zones that are affected by the
area warning. This is accomplished by each matrix sending a list of
trays that are in area warning mode to all panels. The panel stores this
list and checks selected zones against it to see which zones it should
blink.

**AWT_B** is a list of trays that are in the area warning mode on the B
side of the system.

**AWZ_A** is a list of zones affected by area warnings on the A side of
the panel. The panel builds this list each time it receives a new AWT_A
list from the matrix.

**AWZ_B** is a list of zones affected by area warnings on the B side of
the system. The panel builds this list each time it receives a new AWT_B
list from the matrix.

When the matrix receives information that one or more devices have
activated area warning, it builds a map of trays that are currently in
area warning mode. This map is sent to each panel present in the system.
The panel stores the map in memory.

A panel will receive an area warning map from both the A matrix and the
B matrix. The panel compares the area warning maps to the zone tray maps
programmed on each button and builds a list of zones affected by A side
area warnings and a list of zones affected by B side area warnings.
Using the A side affected zone map and the B side affected zone map, the
panel blinks all zones affected by area warnings.

Every time a panel changes area warning states or a pull station changes
state, the matrix builds and distributes a new area warning tray map.

###  CIRCULAR QUEUE STRUCTURES.

  ----------------------------------- -----------------------------------
  **TON_CQ**                          Timer on (new trays waiting to
                                      close)

  **VON_CQ**                          Verify on (new trays that should be
                                      closed)

  **TOF_CQ**                          Timer off (new trays waiting to
                                      open)

  **VOF_CQ**                          Verify off (new trays that should
                                      be open)

  **PON_CQ**                          Pending on zones (map numbers)

  **AS_LST**                          Assembled panel messages

  **TMP_CQ**                          Temporary, used in compacting
  ----------------------------------- -----------------------------------

Size = 259 bytes (**CRQ_RS**)

Fields:

  -------------------- -------------------- ------------------------------
  Offset               SYM                  Function

  0                    **CRQ_IN**           Insertion index

  1                    **CRQ_EX**           Extraction index

  2                    **CRQ_CT**           Count

  3                    **CRQ_DT**           Data (256 bytes, CRQ_SZ)
  -------------------- -------------------- ------------------------------

**CRQ_IN** is the insertion index. This is where the next item added to
the list will go. It wraps around the end to the top.

**CRQ_EX** is the extraction index. This is where the top record lives.

**CRQ_CT** is the count of the number of items on the list.

**CRQ_DT** is the circular buffer itself.

Normally, an item is removed from the list by decrementing the CRQ_CT
field, and incrementing the CRQ_EX field.

Circular queue structures are mainly used for keeping track of the
states of new style trays as they cycle from inactive to active and back
to inactive.

When the matrix keys a new style tray, it places the tray number on the
timer on circular queue. (**TON_CQ**) In the outer loop of the matrix
software, the matrix will check the tray at the top of the queue to see
if enough time has passed that the tray should be in the active state.

The TON_CQ contains the tray number. Each tray has a record that
contains the time the tray should reach its next state. When the matrix
keys the tray, it adds the tray to the TON_CQ and records the current
time plus the amount of time required for a tray to pull in the tray\'s
time field.

If the current time is less than time when the tray is supposed to reach
the active state, then the other trays on the TON_CQ do not need to be
checked since all trays take the same time to reach the active state and
they are placed on TON_CQ in the order that they were activated.

If the tray at the top of TON_CQ has reached the time where it should be
engaged, the tray is removed from the TON_CQ and added to the verify on
circular queue. (VON_CQ) If the top tray is moved to the VON_CQ, the new
top tray on the TON_CQ is checked to see if it has reached the time
where it should be engaged. (Since a single page can often pull in
several trays, trays are usually added to the TON_CQ as a block.)

The TON_CQ is checked until we reach a tray that has not yet reached the
time where it should be engaged. Once that happens, we stop checking the
TON_CQ since the rest of the trays are also still waiting.

The **VON_CQ** contains a list of trays that should have reached the
engaged state. In the outer loop of the matrix software, we check the
VON_CQ to see if there are any trays on it. For each tray listed on the
VON_CQ, the matrix checks the tray\'s feedback circuit to see if the
tray is actually engaged. The results of the test are then recorded in
each panel\'s record. If the tray failed to close, the failure is
recorded in an error table the matrix maintains. Only one tray is
processed each pass.

A panel always instigates closure of a tray. It is possible for the tray
to be \"in use\" by more than one panel. Each time a zone select button
is pressed on a panel, the panel asks the matrix to test all the trays
associated with that button. For each page performed by any panel, the
matrix will also test all new trays associated with the page.

The matrix will return the test results to the panel so the panel can
indicate to the operator if any problems exist. If more than one panel
requests a zone select test, or one panel requests a page, and one or
more other panels request a zone test at nearly the same time, there can
be many panels waiting for the results of the tray activation.

After a tray\'s feedback circuit is checked, the tray is removed from
VON_CQ.

When the matrix unkeys a tray, it places the tray number on the timer
off circular queue. (**TOF_CQ**) In the outer loop, the matrix code
checks the top tray on the TOF_CQ list. If enough time has passed that
the tray should be disengaged, the tray number is removed from the
TOF_CQ and placed on the verify off circular queue. (VOF_CQ)

The matrix code will check the **VOF_CQ**, and for each tray on it, it
will check the tray\'s feedback circuit to see if the tray really
opened. If the tray failed to open, the failure is recorded in an error
table the matrix maintains. Panels are not notified of failures to open.

After each tray is checked, it is removed from the VOF_CQ.

The system console does a periodic read of the matrix error table and
notifies the system console operator of any new failures since the last
time the error table was checked. The errors count up to 255, and stop.
There is a command that can be sent to the matrix that causes it to
reset all the error counts.

**PON_CQ** is a circular queue that contains a list of maps that are
pending. Zone buttons are translated to map numbers in the panel. When
the user presses a zone select button, the panel translates the zone
number to a map number, and adds the map number to the pending on list.
The zone select lamp is turned on, and the panel requests a tray test
from the matrix. It also records the time it expects an answer back from
the matrix in the map record.

The panel\'s outer loop checks the PON_CQ, and if a map is present, and
the map\'s time field indicates that the matrix answers should have been
received by now, the map is removed from the PON_CQ and the panel looks
at the response from both the A and B side matrix and either leaves the
lamp on, leaves the lamp on but beeps, or beeps and turns the lamp off.

If the lamp is left on, the trays associated with the map are added to
the panel\'s global tray maps. (one for the A side and one for the B
side.)

**AS_LST** is a circular queue used on the matrix to maintain a list of
panels that have been removed from the polling list because a complete,
valid message has been received from the panel, but the message has not
been processed yet. In the outer loop of the matrix, we check the AS_LST
and if any panels are listed, the message in the panel\'s message buffer
is processed.

**TMP_CQ** is a temporary circular queue. If a record is deleted from
the middle of a list, the list is compacted by copying all the records,
except for the one being removed, to the temporary buffer, and the
original buffer is overwritten by the temporary buffer. (This could be
cleaned up if we ever do a garbage collection drop, but right now the
customer does not want to change the code much. It is used
infrequently.)

###  TRAY STRUCTURES

Tray state records: **TR_XX** (i.e. TR_00 - TR_bf)

Size = 22 bytes (**TR_SZ**)

Fields:

  -------------------- -------------------- ------------------------------
  Offset               SYM                  Function

  0                    **TR_ST**            Tray State

  1                    **TR_FLG**           Tray bit flags

  2                    **TR_PRI**           Request priority

  3                    **TR_OWN**           \"Owning\" panel

  4                    **TR_TMR**           Time relay S/B open/closed

  5                    **TR_CT**            Bits set count

  6                    **TR_TM**            test map (16 bytes)
  -------------------- -------------------- ------------------------------

**TR_ST VALUES**

  ----------------------- ----------------------- -----------------------
  SYM                     Value                   Function

  **TR_FRE**              00                      Free

  **TR_PON**              02                      Pending on

  **TR_VON**              03                      Verify on

  **TR_ACT**              ff                      Active

  **TR_POF**              11                      Pending off

  **TR_VOF**              10                      Verify off
  ----------------------- ----------------------- -----------------------

TR_FLG BIT VALUES

  --------------------- --------------------- ----------------------------
  SYM                   Value                 Function

  **TR_IV**             00                    Not installed, unused

  **TR_TST**            80                    Testing

  **TR_OP**             40                    Pass audio

  **TR_NW**             20                    New tray

  **TR_OL**             10                    Old tray

  **TR_AT**             08                    AW tray too

  **TR_PA**             04                    Pending AW

  **TR_WT**             02                    WWT required

  **TR_PW**             01                    Pending WW
  --------------------- --------------------- ----------------------------

TR_XX records are used to track tray operations.

The **TR_ST** field indicates the current state the tray is in.

**TR_FRE** indicates that the tray is idle, i.e., no panel has requested
the tray for anything.

**TR_PON** indicates that the tray has been keyed, and in a short time
should be closed. (active) Trays with a state of TR_PON should be on the
PON_CQ.

**TR_VON** indicates that enough time has elapsed for the tray to close,
and it is awaiting testing of its feedback circuit to verify that the
tray closed. Trays with a state equal to TR_VON should be on the VON_CQ.

**TR_ACT** indicates that the tray is being used for a page. (And the
feedback circuit has already been tested if it\'s a new style tray. Old
style trays do not have a feedback circuit, so when keyed, they go
directly from TR_FRE to TR_ACT.)

**TR_POF** indicates that the tray has been unkeyed, and the matrix is
waiting for the tray to have enough time to open. Trays that have a
state of TR_POF should be on the POF_CQ.

**TR_VOF** indicates that the tray has been unkeyed long enough that it
should now be open, and is awaiting testing of its feedback circuit to
verify that it has opened. Trays with a status of TR_VOF should be on
the VOF_CQ. (Old trays don\'t have a feedback circuit, so when unkeyed,
they go directly from TR_ACT to TR_FRE.)

The second field, **TR_FLG** is a collection of flag bits.

**TR_IV** is the value that indicates that the tray is not listed as
being present.

**TR_TST** is a bit indicating that one or more panels have requested
that the tray be tested as a result of an operator\'s zone selection. (A
map of the panels waiting on the test is contained in the structure.)

**TR_OP** is a bit indicating that a panel has requested that the tray
pass audio in support of a page operation by that panel. (Only a single
panel can use a tray for passing audio because there is no provision to
sum audio from more than one panel to feed to the tray. Since a zone
select does not require passing audio, any number of panels can request
a zone select test, even in parallel with a page.)

**TR_NW** is a bit that indicates that the tray is a new style tray that
features the feedback circuit. (Which allows the matrix to determine the
actual state the tray is in at any given time.)

**TR_OL** is a bit that indicates the tray is an old style tray, and has
no feedback circuit. Without the feedback circuit, the matrix has no way
of checking the actual state of the tray, so old style trays are assumed
to be good whenever a test is required.

**TR_AT** is a bit that indicates an area warning operation is being
performed with the tray. This means that in addition setting and
clearing the voice key bit, the matrix should also set and clear the
area warning key bit. (In addition, the audio for the tray may be coming
from the panel or from an area warning tone generator in the matrix. The
audio source is controlled by message sent by the panel.)

**TR_WT** is a bit that indicates a weather warning operation is being
performed with the tray. This means that instead of audio from the panel
being fed to the tray, the tray\'s audio comes from a weather warning
tone generator in the matrix.

The next two bits indicate operations that are requested between the
time the tray was released and when it actually became free. These
indicate that as soon as the tray is verified off (since it had already
been unkeyed when the request came in) it should be keyed in support of
another operation.

**TR_PA** indicates that a panel wants to use the tray in support of an
area warning operation.

**TR_PW** indicates that a panel wants to use the tray in support of a
weather warning operation.

TR_PRI indicates the priority of the page. All pages have an associated
priority. If a request comes in from a panel requesting a page at a
higher priority than the priority the tray is currently being used at,
the tray will be taken away from the panel currently using it and given
to the new, higher priority, panel.

If a page request comes in from a new panel that is the same or lower
priority than the current operation, the new request is rejected.

The current priority must be stored so the matrix can decide which panel
gets the tray when it is requested by two or more panels.

**TR_OWN** indicates which panel \"owns\" the tray. Normally the audio
being fed to the tray will come from the owning panel, but the audio
source may be one of the tone generators in the matrix.

In the event that a higher priority page request comes in, the owning
panel is sent a cutoff message, and the owner of the tray is changed to
the new panel.

The owning panel also serves to help the matrix decide when to send the
page request granted/page request rejected messages.

When a tray is taken off the VOF_CQ, the matrix looks at the TR_OWN
field to see which panel was waiting for the tray for a page. The
panel\'s record contains a list of all the trays that the panel needs
for its current page. The matrix will remove the tray it just verified
from the panel\'s tray map. When the last tray is removed from the
panel\'s tray map, the results of all of the tests are used to determine
what kind of page request response to send to the panel.

**TR_TMR** contains the time when the tray should reach its commanded
state. The tray will remain on one of the two pending lists until this
time.

**TR_CT** contains a count of the number of panels waiting on the tray
to close. (The number of panels that are waiting on a zone select tray
test.) A tray can pass audio on behalf of only a single panel, but
several panels can request the tray be tested to see if it is
operational, so a bit map of the panels requesting the tray be tested is
stored in the tray record. When all of the panels requesting a tray test
have been notified of the results the tray can be released. (Unless a
panel is using the tray for a page.)

TR_TM is a bit map of the panels that have requested the tray be tested
in support of a zone selection by a panel operator.

###  PANEL/TRAY STRUCTURES.

Panel tray records: **PTR_XX** (i.e. PTR_00 - PTR_7F)

Size = 28 bytes (**PT_SZ**)

Fields:

  ----------------------- ----------------------- -----------------------
  Offset                  SYM                     Function

  0                       **PT_OP**               Op field

  1                       **PT_BN**               Button number

  2                       **PT_FL**               Flags

  3                       **PT_BC**               Bit count

  4                       **PT_DA**               Data area (24 bytes)
  ----------------------- ----------------------- -----------------------

**PT_OP VALUES**

  ----------------------- ----------------------- -----------------------
  SYM                     Value                   Function

  **PT_TT**               00                      Tray test

  **PT_PG**               ff                      Page
  ----------------------- ----------------------- -----------------------

PT_FL BIT VALUES

  ----------------------- ----------------------- -----------------------
  SYM                     Value                   Function

  **PT_TP**               20                      Tray(s) passed

  **PT_TF**               80                      Tray(s) failed

  **PT_AR**               40                      AW request

  **PT_WR**               10                      WW request
  ----------------------- ----------------------- -----------------------

Panel tray records (PTR_XX) are used to keep track of what trays a panel
is working with, and what it\'s doing with them.

**PT_OP** is the operation field.

If the panel has requested a tray test, PT_OP will be **PT_TT**.

If the panel is performing a page, PT_OP will be **PT_PG**.

**PT_BN** is the button number.

This field is used for tray tests. When a panel operator presses a zone
select button, the panel sends a tray test request to the matrix. The
request contains the button number along with a list of trays assigned
to the button.

Button numbers consist of a row and a column packed into the upper and
lower nybble of a byte.

When the matrix returns the tray test results, it includes the button
number. (Internally, all panel operations are performed on maps, which
act as an index into tables in memory, but outside the panel, everything
is done in terms of button numbers. Map numbers are contiguous, button
numbers are not.)

**PT_FL** is the flags field. This consists of a number of bits that
indicate specific things.

**PT_TP** is a bit set if one or more trays have passed. This is used
for both tray tests and pages.

**PT_TF** is a bit set if one or more trays have failed. This is used
for both tray tests and pages.

**PT_AR** is a bit set if the page is an area warning request.

**PT_WR** is a bit set if the page is a weather warning request.

**PT_BC** is a count of the number of trays that are still waiting for
test results. It is a count of the number of bits set in the tray map
field.

**PT_DA** is the data area. It contains a bit map of the trays that are
still waiting on test results.

When a tray reaches the time that its activation can be verified, its
state is checked, and one of the flags, PT_TP or PT_TF, is set, and the
bit is removed from the bit map and PT_BC is decremented.

When PT_BC reaches 0, the matrix sends a response to the panel based on
PT_TP, PT_TF, PT_OP and PT_AR and PT_WR.

(Different opcodes are used for normal pages, area warning pages and
weather warning pages.)

###  ERROR COUNT TABLE

**E_TBL**

Size = 64 bytes (**EC_SZ**)

**TABLE ENTRIES**

  --------------- --------------- ----------------------------------------
  Offset          SYM             Function

  0               **ERR_00**      Garbage in front of message

  1               ERR_01          Unused

  2               ERR_02          Unused

  3               ERR_03          Unused

  4               ERR_04          Unused

  5               **ERR_05**      No response from matrix A

  6               **ERR_06**      No response from matrix B

  7               **ERR_07**      Invalid tray number in tracking write

  8               **ERR_08**      Panel polling deletion error, panel not
                                  there

  9               **ERR_09**      Invalid panel number in forwarding

  10              **ERR_0A**      Large buffer overflow, side A

  11              **ERR_0B**      Large buffer overflow, side B

  12              ERR_0C          Unused

  13              ERR_0D          Unused

  14              ERR_0E          Unused

  15              ERR_0F          Unused

  16              **ERR_10**      Undefined tray state during page attempt

  17              **ERR_11**      Free tray type undefined, page attempt

  18              **ERR_12**      Active tray type undefined, page attempt

  19              **ERR_13**      Attempt to release free tray

  20              **ERR_14**      Tray type undefined during release

  21              **ERR_15**      Invalid message from system console

  22              **ERR_16**      Invalid write command

  23              **ERR_17**      Invalid map number, write command

  24              **ERR_18**      Invalid request

  25              **ERR_19**      Invalid map number, read command

  26              **ERR_1A**      Illegal command

  27              **ERR_1B**      Message from panel not addressed to
                                  matrix/console

  28              **ERR_1C**      Invalid message type from panel

  29              **ERR_1D**      Invalid request from panel

  30              **ERR_1E**      Invalid command from panel

  31              **ERR_1F**      Invalid tracking number

  32              **ERR_20**      Invalid message type

  33              **ERR_21**      Invalid write command

  34              **ERR_22**      Bad map number, zone write

  35              **ERR_23**      Invalid response

  36              **ERR_24**      Bad map number, tray test response

  37              **ERR_25**      Invalid request

  38              **ERR_26**      Invalid command

  39              **ERR_27**      Invalid announcement

  40              ERR_28          Unused

  41              ERR_29          Unused

  42              ERR_2A          Unused

  43              ERR_2B          Unused

  44              ERR_2C          Unused

  45              ERR_2D          Unused

  46              ERR_2E          Unused

  47              ERR_2F          Unused

  48              **ERR_30**      Not addressed to me

  49              **ERR_31**      False start or corrupted length

  50              **ERR_32**      Invalid EOM

  51              **ERR_33**      Invalid CRC

  52              ERR_34          Unused

  53              ERR_35          Unused

  54              ERR_36          Unused

  55              ERR_37          Unused

  56              ERR_38          Unused

  57              ERR_39          Unused

  58              ERR_3A          Unused

  59              ERR_3B          Unused

  60              ERR_3C          Unused

  61              ERR_3D          Unused

  62              ERR_3E          Unused

  63              ERR_3F          Unused
  --------------- --------------- ----------------------------------------

The error count table contains a count of the number of errors of a
given type that have occurred since the table was last zeroed. (The
table is zeroed by any reset, and there is a command that will zero
several tables, including the error table.)

Each different type of error has its own position within the table. For
a list of the errors, look at ETYPE.H. Not all errors can occur on all
devices. As an example, the \"No response from matrix A\" errors occur
on the panels, and should not occur on either matrix.

The best way to determine exactly what each error \"means\" is to
examine where the error occurs in the source code. As an example, to
figure out what \"Undefined tray state during page attempt\" means, find
where ERR_10 occurs in the source code. (zgrep ERR_10 \*.asm while in
the root source directory, RS)

###  INTERRUPT HANDLER ERROR TABLE.

**IHE_TBL**

Size = 4 bytes (**IHE_SZ**)

ENTRIES

  ----------------------------------- -----------------------------------
  Offset                              Function

  0                                   Break detected, A side

  1                                   Break detected, B side

  2                                   Receive buffer overflow, A side

  3                                   Receive buffer overflow, B side
  ----------------------------------- -----------------------------------

The interrupt handler error table records the count of certain errors
that are detected during dual UART interrupt handler execution.

Due to hardware constraints, we can\'t run the normal error recording
code for these errors. (You can\'t read from the XICOR chip while it\'s
in a programming cycle, or you\'ll corrupt the Xicor contents, so the
dual UART interrupt handlers live in a small block of EEPROM in the
CPU.)

The dual UART is used in the matrix for communication with the systems
consoles. The panel uses the dual UART for communications with the
matrices.

It is not unusual to get a break detected error when power is cycled on
the matrix or panel, or when cable connections are disturbed. Breaks
that occur at other times are usually signs of hardware related
communication link problems. Receive buffer overflows should never
occur.

###  ZONE MAP STRUCTURES.

A side zone maps: **ZMXXA** (i.e. ZM00A - ZM3FA)

B side zone maps: **ZMXXB** (i.e. ZM00B - ZM3FB)

Size = 25 bytes

Fields:

  ----------------------------------- -----------------------------------
  Offset                              Function

  0                                   Zone priority

  1                                   Tray map, first byte
  ----------------------------------- -----------------------------------

Zone maps are used to store panel configuration. Each zone map stores
the trays associated with one side of one zone select button. These are
recorded in the panel\'s Xicor chip. The system console performs a
download to record new zone maps when the configuration is altered.

Each zone select button has an associated priority, and a list of trays
assigned to that zone. A page can be performed with many zones selected.

When a page is performed, the panel looks at the zone maps for all of
the selected zones, and uses the highest priority it finds as the global
priority. All of the selected zone\'s trays are ORed together to
generate a global tray map. The global priority and global tray map are
used in the page request.

There are actually separate priorities and global tray maps for the A
side and the B side, since not all areas have redundant trays.

The system consoles must lock the panel before a new configuration can
be downloaded. If the panel is performing a page, or awaiting the
results of a tray test, it will wave off the lock and the download
cannot be performed.

If the panel is idle, the lock is performed. No other operations can be
performed while the panel is locked. A timer is started on the panel
when it is locked, and if the system console does not perform an unlock
within a reasonable amount of time (about 10 seconds for all panels
except the admin) the panel will unlock itself.

If the panel is not locked, any download messages that arrive are not
processed.

When the panel receives a download message, it checks the message
contents against the Xicor contents. If there is no difference, the
message is discarded. If the message and the Xicor differ, a write cycle
is initiated to program the Xicor.

After the zone record has been updated, the global priority and the
global tray maps are updated.

###  ZONE RECORDS

Zone lamp states: **ZLSXX** (i.e. ZLS00 - ZLS3F)

Size = 3 bytes (**ZR_SZ**)

Fields:

  ----------------------- ----------------------- -----------------------
  Offset                  SYM                     Function

  0                       **ZS_OFF**              Zone State

  1                       **ZT_OFF**              Time field

  2                       **ZR_OFF**              Response byte
  ----------------------- ----------------------- -----------------------

**ZS_OFF VALUES**

  ----------------------- ----------------------- -----------------------
  SYM                     Value                   Function

  **IN_OFF**              \$00                    Indicator off

  **IN_ON**               \$01                    Indicator on

  **IN_AWS**              \$80                    AW selected
  ----------------------- ----------------------- -----------------------

**IN_ON** indicates the zone button lamp is on.

**IN_OFF** indicates that the zone button lamp is off.

**IN_AWS** is ORed in when a zone selection is performed while the panel
has area warning tone active. (Normally, the panel will not allow any
zone select operations while audio is being routed to trays, but area
warning is a special case.)

**ZR_OFF VALUES**

  ----------------------- ----------------------- -----------------------
  SYM                     Value                   Value

  **ZR_RST**              \$00                    No responses

  **ZR_SAG**              \$80                    Side A good

  **ZR_SAI**              \$40                    Side A Illegal

  **ZR_SAP**              \$20                    Side A partial

  **ZR_SAB**              \$10                    Side A busy

  **ZR_SBG**              \$08                    Side B good

  **ZR_SBI**              \$04                    Side B Illegal

  **ZR_SBP**              \$02                    Side B partial

  **ZR_SBB**              \$01                    Side B busy
  ----------------------- ----------------------- -----------------------

Zone records contain information about zone buttons and zone button
operation state.

**ZS_OFF** contains information about the zone button\'s lamp state and
a flag for an area warning select. (Which requires special processing.)

**ZT_OFF** contains the time when all responses should have been
received from both matrices. When this time arrives, the panel checks
the responses it received from the matrices and leaves the lamp on,
beeps and leaves the lamp on, or beeps and turns the lamp off.

**ZR_OFF** contains flags that record the response received from each
matrix.

When the panel receives a page request response from the matrix, it
records the information in the ZR_OFF field. When the response timer
expires, the panel will check these flags.

There are two blocks of flags in this field, one for the A side, and one
for the B side. For the A side flags, the fifth character is A while
it\'s a B for the B side flags. As an example, ZR_SAG is the good flag
for the A side.

**ZR_RST** is the value recorded in ZR_OFF to clear the response byte.

**ZR_SAG, ZR_SBG** indicate that the page was good, that all the trays
requested are available and working.

**ZR_SAI, ZR_SBI** indicate that one or more trays in the panel\'s
request are not listed as being installed.

The matrix has a list of old style trays and a list of new style trays
that are installed. If a panel asks for a tray that does not appear on
one of these two lists, the matrix rejects the request as illegal. This
can happen if operations are performed during a download when the matrix
and the panels may have different configurations on them.

**ZR_SAP, ZR_SBP** indicate that one or more trays the panel requested
are not working. It is only sent if there is one or more trays that did
work.

In the event that there are no working trays in the panel\'s request,
the matrix sends a message indicating that there are no trays. There is
no bit in this field for this condition, as the occurrence is handled
the same as no matrix response. (In the event that there really isn\'t
any response received from a matrix, the panel code will bump the no
matrix response received error count. This count is not bumped if the
matrix sends a \"no trays\" response.)

**ZR_SAB, ZR_SBB** these values are not used in zone selects. They are
used for pages. (In other structures.)

###  VERSION DETECTION.

**SIG** 2 bytes

**MAGIC** 2 bytes

The software compares these two values to determine if it needs to
reprogram the CPU EEPROM. The value is generated by running the CRC
across UART.ASM. If they differ, the CPU EEPROM is reprogrammed to
contain the new interrupt handlers.

The configuration information the system consoles send to the various
devices in the PAWS is recorded in the XICOR chip. This forces us to
write to the XICOR chip while we are receiving data over the serial
link.

The interrupt handlers have to live in the CPU EEPROM because they have
to run during the 10 milliseconds of the Xicor programming cycle. During
XICOR programming, you can\'t read (and therefore can\'t run any code
in) the Xicor. If interrupts were disabled for the time it takes to
program the Xicor, we would loose bytes coming from the system consoles.

The system is designed such that if a new EEPROM is installed in a
panel, matrix or PSIC card, the CPU EEPROM contents is reprogrammed if
required. Five items are used to determine the state of CPU EEPROM
programming. The five items are; the value in the configuration
register, the XICOR EEPROM contents, the CPU EEPROM contents, the MAGIC
value and the SIG value.

The CPU chip contains a configuration register. This configuration
register determines where the CPU\'s EEPROM will appear within the
CPU\'s memory map. In normal operation, the CPU\'s EEPROM is mapped to
the \$FE00 to \$FFFF range. The configuration register will contain
\$FF.

In order to compare the contents of the CPU\'s EEPROM to the contents of
the XICOR EEPROM, (Which is mapped to the range \$8000 to \$FFFF.) the
CPU must move it\'s EEPROM to an address range outside of the \$FE00 to
\$FFFF range so that the CPU\'s EEPROM does not overlap the code
contained in the XICOR. The CPU\'s EEPROM must also be moved for
programming to take place.

The interrupt handlers are burned into the XICOR chip. They are mapped
to the actual physical addresses that they normally run from. The CPU
will copy the code from this section of the XICOR chip into the CPU\'s
EEPROM, and then map the CPU EEPROM to the actual physical addresses.
When the CPU EEPROM occupies the upper end of the memory map, the XICOR
is no longer accessed, the code comes from the CPU EEPROM instead. The
same code lives in the CPU EEPROM and the upper end of the XICOR chip,
but the XICOR chip will not receive a chip select signal once the CPU
has moved its EEPROM to the high end of the memory map.

In order to compare the CPU EEPROM contents to the XICOR contents, the
CPU must move its EEPROM to a lower memory address. This is also true
when the CPU needs to copy the XICOR code to the CPU\'s EEPROM, the copy
cannot take place unless the CPU moves its EEPROM to a lower address.

In order to determine if the XICOR chip has been replaced with one that
contains updated interrupt handlers, the system records a signature in
two locations in the XICOR chip. The value is generated by running a CRC
across the source code file that contains the interrupt handler code.
One of these XICOR locations resides within the block that is copied to
the CPU\'s EEPROM. After the CPU\'s EEPROM is remapped, that signature
comes from the CPU\'s EEPROM instead of the XICOR\'s.

When the CPU compares the value from its EEPROM to the value recorded in
the XICOR, if the two values differ, then the CPU knows that the XICOR
chip has been replaced.

Normally, the CPU EEPROM has the correct information programmed into it,
and the CPU configuration register is correctly set. In this case, the
code checks the config register, sees that it contains \$FF, and vectors
to check the SIG value against the MAGIC value. SIG is recorded in the
XICOR memory while MAGIC is recorded in the CPU EEPROM. (Within the
block that contains the interrupt handlers.) If both values match, the
code returns.

If SIG doesn\'t match MAGIC, the XICOR has been replaced, and there may
be new interrupt handlers to install. In this case, the code will change
the configuration register contents to \$0F, moving the CPU\'s EEPROM to
the \$0E00 - \$0FFF range. On a panel, it will illuminate the voice
ready indicator. The code then falls through to a software trap. (A
branch statement that branches to itself.)

If the CPU has never been programmed, or in the case that the first pass
altered the contents of the configuration register, on the second pass
through the pgm routine, the config register will not contain \$FF, so
the code vectors to a section that checks to see that the config
register contains \$0F. If it does not, the config register contents is
set to \$0F, the voice ready indicator is illuminated, and the code
falls through to the software trap. (The same as when SIG and MAGIC do
not match.)

If the config register contains \$0F, the code will compare the contents
of \$FE00 - \$FFFF (The XICOR EEPROM) to the contents of \$0E00 to
\$0FFF. (The CPU EEPROM.) If the two blocks of code match, the config
register is set to \$FF, and on a panel the busy indicator is
illuminated. The code then falls through to a software trap.

If the config register contains \$0F, but the ranges \$FE00 - \$FFFF,
\$0E00 - \$EFFF don\'t match, the contents of \$FE00 - \$FFFF is copied
to the CPU\'s EEPROM and programmed in. After the programming is
complete, on a panel the lamp test indicator is illuminated, and the
software falls through to a software trap.

In most cases, when the software falls through to a software trap, a
watch dog timer interrupt will hit, which starts the programming cycle
again. In a worst case situation, the power must be cycled on twice to
complete a full re-programming.

###  ZONE MAP LOOK UP TABLES

**MAATAB, MABTAB**

Size = 64 words (128 bytes)

These tables are used to translate a map number into the address of a
zone map. (ZMXXA/ZMXXB) They are lists of addresses. Given a map number,
use it (the map number) as an index into the table to get the address of
the record for that map.

###  ZONE LAMP STATE LOOK UP TABLE

**ZLMAP**

Size = 64 words (128 bytes)

This table is used to translate a zone lamp record number into the
address of a zone lamp record structure. (ZLSXX) Given a zone lamp
record number, use it to index into the table to get the address of the
actual zone lamp record.

###  COMPRESSED ZONE NUMBER TO MAP NUMBER TABLES.

**ADMZ2M, WRNZ2M, OPSZ2M**

Size = 64 bytes

These tables are used to translate button numbers into map numbers. Pack
the 3 bits of the row number and the 3 bits of the column number from a
button number into the low order 6 bits of a byte. Use the result to
index into the table. The value fetched is the map number. The emergency
warning and area warning panels share a table.

###  KEY SCAN CODE TO MAP NUMBER TRANSLATION TABLES

**ADMK2M, WRNK2M, OPSK2M**

Size = 108 bytes

The tables are used to translate a key scan code to a map number. The
zone select buttons are interfaced to the panel CPU through a keyboard
encoder. The keyboard encoder handles debouncing the contact closures,
and reports key hits via a scan code. The panel code uses the scan code
as an index into a table to fetch the map number, which is how all the
internal routines refer to a \"button.\" The table varies with the panel
type, because the actual mapping of button position to scan code varies
with the panel type due to wiring differences.

###  MAP NUMBER TO BUTTON NUMBER TRANSLATION TABLES.

**ADMM2B, WRNM2B, OPSM2B**

Size = 64 bytes

These tables are used to translate a map number to a button number. When
the panel needs to communicate with the outside world it has to
translate the map number (which is how all internal operations refer to
a button) back into a button number. The panel code uses the map number
to index into this table to fetch the button number. Button numbers are
used in zone selects. Button numbers are based on physical position on
the panel, while map numbers are \"logical\" button numbers that are
mapped to the physical button numbers.

###  TRANSLATION TABLE ADDRESSES.

**ZMTAB, KMTAB, MBTAB**

Size = 2 bytes

These values are set when the panel code determines what type of panel
it is running on. These are the addresses of tables used to do the
following translations:

  ----------------------------------- -----------------------------------
  **ZMTAB**                           Compressed Zone (button) to map
                                      number

  **KMTAB**                           Key scan code to map number

  **MBTAB**                           Map number to button number
  ----------------------------------- -----------------------------------

There are actually several tables for translating button numbers to map
numbers, one for each type of panel. (The emergency warning panel and
area warning panels share most maps due to the zone select buttons being
wired the same way.)

ZMTAB, KMTAB and MBTAB are the addresses of the correct tables to use
for the panel the code is running on.

By setting up the variables in the initialization phase, we can avoid
code to test what type of panel the software is running on. This saves
considerable room in memory and execution time. During the
initialization phase the panel code checks to see what type of panel it
is running on, and records the panel type and then sets the table
variables.

###  CONTROL BYTE.

**CTLB**

Size = 1 byte

**CTLB VALUES**

  ------------------- ------------------- --------------------------------
  SYM                 Value               Function

  **ZLOCK**           \$80                Zone selections Locked

  **DL_A**            \$01                Download in progress, A side

  **DL_B**            \$02                Download in progress, B side
  ------------------- ------------------- --------------------------------

The control byte contains lock bits to prevent certain operations.

The zone lock bit, **ZLOCK** is set when a weather warning is initiated,
and it is cleared when the weather warning completes. (or is
terminated.)

There are two download locks, one for the A side, **DL_A**, and one for
the B side, **DL_B**. DL_X (A or B depending on the side.) is set when
the panel goes into a download lock, and is cleared when the download
unlock command is received from the system console, or when the panel
times out without receiving an unlock command.

The weather warning tone is actually a type of page. Normally, the
operator will select his zones, then hit the weather warning tone
activate button. The weather warning tone is sent out, and the weather
warning tone lamp illuminates. When the weather warning lamp goes out on
the panel, the operator keys the microphone and makes the weather
announcement. When the announcement is completed, the operator releases
the mic PTT key, and the page terminates.

When the weather warning tone is activated on an emergency warning
panel, the panel sends a weather warning tone page request to the
matrices. The matrices pull in the trays listed in the request, and
route the output of the weather warning tone generator to the trays.

At the time the panel sent the weather warning tone page request to the
matrices, it also started a timer. The weather warning tone takes two
seconds to complete a full cycle. While the tone is active, the weather
warning tone lamp on the panel is illuminated. Two seconds after the
panel sent the weather warning tone page request, the panel will send a
tone release. This shuts off the weather warning tone, but does not
release the trays. Four seconds after the panel sent the weather warning
tone page request, it will send a page release to return the trays to
use. (If the cycle has not been overridden by the operator pressing the
mic PTT.)

During the four seconds of a weather warning cycle, zone selection
operations are locked by the ZLOCK bit. The weather warning tone can be
terminated before completion of a full cycle by overriding the tone with
mic audio.

###  PANEL MODE.

**PMOD**

Size = 1 byte

**PMOD VALUES**

  ----------------------- ----------------------- -----------------------
  SYM                     Value                   Function

  **PHOT**                \$ff                    Panel Hot

  **PCLD**                \$00                    Panel Cold
  ----------------------- ----------------------- -----------------------

This byte indicates if the panel is hot or cold.

The operator at the system console can call up a display of any given
panel in the system. This display visually indicates the state of the
panel, including panel type, which zones are selected, and the state of
the special lamps. In order to keep the system console display up to
date while it is examining the panel, the panel is made \"hot.\" This is
accomplished by the system console sending a hot command to the panel.

A hot panel will send a notice to the system console every time a lamp
changes state. These messages are used to update the system console\'s
display of the panel so that the system console display tracks the
actual appearance of the panel.

When the system console display of the panel is terminated, the system
console sends a panel cold command to the panel. This causes the panel
to cease sending the lamp state updates to the system console.

(On area warning panels, any time the position of the area warning key
switch changes state, the panel will send a message to the system
console, wether the panel is hot or not. These changes appear in the
system console\'s log file.)

Lamp state change messages are only sent by hot panels in order to keep
down the number of messages the system must process. PAWS is limited by
the bandwidth of the link between the matrix and the system console, so
this traffic is kept to a minimum.

###  PANEL TYPE.

**PNL_TYP**

Size = 1 byte

**PNL_TYP VALUES**

  ----------------------- ----------------------- -----------------------
  SYM                     Value                   Function

  **AW_PNL**              \$00                    Area Warning

  **AD_PNL**              \$01                    Administrative

  **EW_PNL**              \$02                    Emergency Warning

  **OP_PNL**              \$03                    Operational
  ----------------------- ----------------------- -----------------------

This indicates what type of panel it is.

When the panel code starts up, one of the tasks it performs before
entering the main loop is to determine and record the panel type.

Each panel has two lines that connect the CPU to the front panel. These
two lines carry the panel type ID. The CPU reads the panel ID lines, and
then records the information in the panel type byte. (It also sets up
pointers to several tables that vary based on the panel type.)

###  DUART TRANSMITTER VARIABLES

These variables are used for sending messages out the Dual UART. There
are two sets, one for the A side and one for the B side.

#### Buffer Status Variables.

**XA_BSA, XB_BSA**

Size = 2 bytes

**XX_BSA VALUES**

  ----------------------- ----------------------- -----------------------
  SYM                     Value                   Function

  **OUT_FR**              \$00                    Free

  **OUT_BZ**              \$ff                    Busy
  ----------------------- ----------------------- -----------------------

**XX_BSA** is the buffer status address. This variable contains the
address of the buffer status value.

Some messages transmitted will go to only one side of the system, and
others are sent to both sides.

There is only one output buffer. When a message must go to both sides
there is only one copy of the message but it is sent to both sides of
the dual UART.

When a message is being sent to both sides, the buffer can not be freed
until both sides are finished transmitting the buffer. The buffer status
byte keeps track of the status of the buffer.

If the buffer status is OUT_BZ one or both of the sides of the dual UART
is still using the contents of the buffer, so the buffer can not be used
to hold a new message.

When both sides are done with the buffer (when the message is being sent
to both sides) the last one to finish will set the buffer status to
OUT_FR, which indicates that a new message can be copied to the buffer.

#### Buffer Extraction Addresses

**XA_BEA, XB_BEA**

Size = 2 bytes

**XX_BEA** is the buffer extraction address. This is where the next byte
to be sent comes from.

The first byte of the message is written to the dual UART transmit
register and the transmit interrupts are enabled. Since the dual UART
used has an 8 byte buffer, as soon as the transmit interrupt is enabled,
a series of transmit interrupts will hit that load the next seven bytes
of the message into the dual UART transmit buffer. After that, as a
character is shifted out of the dual UART, a space becomes available in
the dual UART\'s transmit FIFO, and a transmit interrupt occurs, which
will load another byte.

The buffer extraction address field gives the address that the next byte
will be fetched from. The value is incremented each time a byte is read
from the buffer and sent to the dual UART.

#### Buffer Message Length

**XA_BML, XB_BML**

Size = 1 byte

**XX_BML** is the number of bytes in the message left to send.

This starts out as the message length and every time a byte is fetched
from the buffer this value is decremented.

When a transmit interrupt occurs, the interrupt handler will check
XX_BML. If XX_BML is zero, then the message has completed transmission.
In this case, the transmit interrupt for that side of the dual UART is
disabled. If the other side has completed (or was not being used) the
buffer is marked as free as well.

#### Transmitter Status

**XA_TS, XB_TS**

Size = 1 byte

**XX_TS VALUES**

  ----------------------- ----------------------- -----------------------
  SYM                     Value                   Function

  **UTS_ID**              \$00                    Idle (Free)

  **UTS_BZ**              \$ff                    Busy
  ----------------------- ----------------------- -----------------------

**XX_TS** is the transmitter status.

XX_TS indicates if that side of the dual UART is in use, or is free. The
transmitter status is marked as Idle as soon as the last byte of the
message has been transmitted. When both transmitters are idle, the
output buffer can be released.

###  SIDE

**SIDE**

Size = 1 byte

**SIDE VALUES**

  ----------------------------------- -----------------------------------
  SYM                                 Value

  **SIDE_A**                          \$01

  **SIDE_B**                          \$02
  ----------------------------------- -----------------------------------

This indicates which side of the dual UART the last message was received
from.

(Please note that reading this value with pds sends a message to the
matrix or panel, and receipt of this message will indicate what side of
the device pds is talking to. It is much more useful when using the
logic analyzer of in-circuit emulator.)

The side the message came from becomes important when data needs to be
recorded in the XICOR, when errors need to be recorded, or when certain
messages need to be returned.

###  GLOBAL TRAY MAPS

**GMA,GMB,OGMA,OGMB,DGMA,DGMB**

Size = 24 bytes (**TT_LEN**)

**GMA,GMB** are the global tray maps. Each zone button has a tray map
for the A side and for the B side. These trays are assigned to the zone
button by the system console. The console operator can edit a tray map
for any given button on any given panel. After adding and deleting trays
as desired, he can perform a download. The panel will record the new
tray map in the button\'s tray record.

For each selected button, the panel will add the trays associated with
that button to the global tray map for that side by ORing the button
tray map contents with the current global tray map. (The panel maintains
two global tray maps, one for the A side and one for the B side. Each
button has an A side record and a B side record.)

When the panel operator initiates a page request, the panel copies the
global tray map into the page request.

When the system console performs a download to a panel, the panel will
regenerate a new global tray map.

Normally, the zones that are selected can only change when there are no
pages going on, but in the event that the panel operator has initiated
an area warning, the system is required to allow the operator to select
and deselect zones while the area warning tone is flowing.

(The system will not allow zone selection and deselection while the
microphone is keyed, even when the panel is in area warning mode. The
only time you can select and deselect zones in area warning mode is when
the microphone is unkeyed and the trays are receiving audio from the
area warning tone generator.)

When area warning has been activated, the area warning tone can be
overridden by keying the microphone PTT. This causes the panel to send a
source select message to the matrices. The source select message does
not alter which trays are pulled in, but it does result in the audio
going to the trays to come from a different source.

When the microphone PTT switch is keyed the panel sends a source select
message switching the trays to the microphone audio from the panel. When
the PTT switch is released, the panel sends a source select message to
switch the tray\'s audio source back to the matrix\'s area warning tone
generator.

**OGMA,OGMB** are temporary copies of the global maps used in computing
deltas. (For AW mode zone selections and deselections while tone is
flowing.) When a zone is deselected while area warning tone is flowing,
the panel has to release the trays that had been in area warning mode,
but are no longer required.

You cannot simply send the contents of the button\'s tray map, because a
tray can appear on more than one button on a panel.

Instead, the panel copies the old (before the zone deselect) global tray
map to the temporary tray map. It then generates a new global tray map
based on the new set of selected zone buttons. (Without the newly
deselected zone button.)

Next it computes the difference between the two maps, and sends the
results as a page release.

This frees only those trays that were on the recently deselected button
that are not on any of the other selected zone buttons.

When a zone is selected while area warning tone is flowing, the panel
will copy the old (before the zone button selection takes affect) global
tray map to the temporary global tray map.

It then generates a new global tray map (Actually two, one for the A
side and one for the B side.) and computes the difference between the
two maps.

This delta contains only the trays that are on the new button that were
not on any of the other (selected) zone buttons.

Finally it sends this delta map as an area warning request to the
matrices.

**DGMA,DGMB** contain the differences (in selected trays) when doing
zone selects with AW Tone active.

In simple terms, they contain the delta tray maps after the panel has
computed new sets after a zone selection or deselection when area
warning tone is active. These maps are copied to the output message
buffer when the panel gets ready to send the tray release or page
requests.

###  LINK HEALTH TABLE.

**LHTAB**

Size = 130 bytes

This table keeps track of serial link failures.

When a message assembly error occurs, the entry in the link health table
is incremented.

On the matrix there is one entry for each panel plus one for each side
of the dual UART. The panels only use the DUART slots. (The matrix uses
the DUART to talk to the system consoles. On the panels, the DUART is
used to talk to the matrices.)

Panel 0 errors are stored in slot 0, while panel 127\'s error count is
stored in slot 127. The A side of the DUART\'s errors are stored in slot
in 128, while the B side errors are stored in slot 129.

This table is reset with the zero command. (Which also resets other
error tables.)

When the error count for any given link reaches 255, it stays there. (If
allowed to roll over, you may be fooled into believing that a link is
healthier than it really is.)

Examples of the type of errors that are recorded in the table include:
garbage bytes in the front of messages, invalid lengths, bad CRCs,
invalid/corrupted End Of Message, etc.

###  TRACKING TRAYS

**TRG_TR, MON_TR, GBL_TR, NWA_TR**

Size = 1 byte

Each of these contains a tray number.

-   **TRG_TR** is the monitor input tray.

-   **MON_TR** is the monitor output tray.

-   **NWA_TR** is the global input tray.

-   **GBL_TR** is the global output tray.

In order to allow the system operators to monitor certain areas, PAWS
provides a way of monitoring the activity of any given tray.

To do this, the matrix software implements a monitor tray. The monitor
tray operates in parallel with the tray being monitored.

To define the operation, the system console needs to download the tray
number that the operators want to monitor to **TRG_TR**, the monitor
input tray. You also need to record the tray number the operators use to
monitor the activity by downloading a tray number to **MON_TR**, the
monitor output tray.

After these steps are performed, every time the TRG_TR is keyed, the
MON_TR tray will be keyed as well. Every time the TRG_TR is unkeyed, the
MON_TR is unkeyed as well. In addition to following the keying, the
MON_TR also gets the same audio that is routed to the TRG_TR.

**GBL_TR**. Another capability supplied by the system is a system
activity monitoring function.

With this feature, the system console downloads a tray number to the
global output tray, GBL_TR. The global output tray allows the operators
to monitor PAWS activity by always outputting the audio from the most
recent page.

Every time the matrix starts processing a page, it takes the first tray
used in the new page and records it in the newest available tray
variable, **NWA_TR**.

The global output tray is slaved to the NWA_TR just like the monitor
output tray is slaved to the monitor input tray. The only difference is
that the global tray is slaved to the newest available tray, which
changes each time a page is initiated.

(NWA_TR is stored in RAM since it changes so often. The three other tray
numbers are stored in EEPROM.)

###  PULL STATION TRAY LISTS

**PSM_XX** (i.e. PSM_00 - PSM_7f)

Size = 24 bytes

Each pull station (remote area warning panel) has an associated set of
trays that are affected when that station is activated.

The matrix is responsible for notifying all panels in the system of all
trays affected by area warning, whether panel initiated or pull station
initiated. In order to do this, the matrix requires a list of trays that
are affected by each pull station activation.

The panel sends a tray map to the matrix when it requests an area
warning, but the pull stations only provide active/inactive indications
to the matrix.

The system console is responsible for downloading a bit map of trays
affected by a pull station activation for each pull station in the
system.

The matrix builds a map of trays affected by area warning by ORing all
the trays affected by panel initiated area warnings with all the trays
affected by pull station activation. This map is sent to each panel
every time there is a change in the trays affected by area warnings.
(adding or removing trays from area warning mode)

The pull station tray maps are bit maps. When a pull station is
activated, you can tell which trays are affected by looking at its tray
map. If a bit is set, then the indicated tray will be in area warning
mode. (And the indicated tray will appear in the matrix\'s area warning
tray list.)

###  PULL STATION STATUS

**PS_ST**

Size = 128 bytes (**PSMAX**)

This table contains the status of the pull stations.

If a byte is TRUE (\$ff) then the pull station is active. If the byte is
FALSE (\$00) then the pull station is inactive.

This table is used to detect state changes of pull stations. Every time
there is a pull station state change, the matrix generates a new area
warning tray map. If there is any delta from the old area warning tray
map, the new, updated, area warning tray map is sent to all the panels.

The table also serves as input when building the list of trays affected
by pull station initiated area warnings.

###  ACTIVE PULL STATION COUNT

**PS_AC**

Size = 1 byte

This is the number of active pull stations. (Pull stations that are in
area warning mode.)

###  ACTIVE AREA WARNING TRAY MAP

**AA_MAP, LA_MAP**

Size = 24 bytes (**TT_LEN**)

These maps contain the trays that are in area warning mode.

**AA_MAP** trays are in area warning mode due to an area warning panel
activating them.

**LA_MAP** trays are in area warning mode due to a pull station being
activated.

**AA_MAP** is updated each time a panel initiates an area warning page,
or terminates an area warning page. This includes the operator selecting
an additional zone when area warning tone is active as this results in
the panel sending a new area warning page request with additional trays
listed.

Source selects that result from a panel\'s operator keying and unkeying
the microphone do not result in area warning tray maps being sent from
the matrices to the panels as this does not cause any changes in which
trays are involved in the area warning, only the source of audio being
distributed to the trays.

LA_MAP is updated each time a pull station changes state, both from
active to inactive and inactive to active.

The area warning tray maps the matrices distribute to the panels are
generated by ORing the AA_MAP with the LA_MAP.

###  PAGE COUNT TABLE

**PC_TBL**

Size = 256 bytes (MAXPNL \* 2)

This table contains the number of pages that each panel has performed
since the last zero page count command.

Each count is a word, giving a max count of 65535. When the page count
maxes out, the matrix stops incrementing the page count for that panel
in order to keep the count from rolling over.

###  MATRIX RESPONSE FLAGS

**GOT_A, GOT_B**

Size = 1 byte

If the byte is FALSE (\$00) then no response was received from the
matrix for that side. If a response is received from the matrix, the
byte will be TRUE. (\$ff)

When a panel sends a request to the matrix, (either a tray test request,
or a page request) it resets both of these variables to FALSE. When a
response arrives from the matrix, the panel sets the variable for that
side to TRUE.

These results are checked when the panel\'s response timer expires,
which is the time that a matrix response should have been received by.

If no response is received from one or both matrices, the no matrix
response error count is incremented for the side or sides that failed to
respond.

###  LARGE BUFFER STRUCTURES

A side large buffer **LBA**

B side large buffer **LBB**

Size = 2053 bytes (**LRG_SZ**)

Fields:

  ------------------ ------------------ ----------------------------------
  Offset             SYM                Function

  0                  **LRG_ST**         Buffer state

  1                  **LRG_IN**         Insertion index

  3                  **LRG_EX**         Extraction index

  5                  **LRG_BF**         Circular buffer (2048 bytes,
                                        LRG_DS)
  ------------------ ------------------ ----------------------------------

**LRG_ST VALUES**

  ----------------------- ----------------------- -----------------------
  SYM                     Value                   Function

  **LRG_MT**              00                      Empty

  **LRG_PR**              80                      Partially filled

  **LRG_FL**              ff                      Full
  ----------------------- ----------------------- -----------------------

The large buffers are used to buffer characters that are received from
the DUART. Received messages come in the DUART which has an 8 byte FIFO
built into it.

When a receive interrupt hits, the interrupt handler gets the character
from the DUART and saves it in a small circular buffer that holds 256
bytes. Because writes to the XICOR take so long, and a download can
require 135 writes, the circular buffer may overflow during a full
download.

In order to avoid the circular buffer from overflowing, in the outer
loop, before any time consuming operation is performed, the contents of
the circular buffer is moved into the large buffer.

The size of the circular buffer could have been increased, but due to
limitations of the 68HC11 instruction set, the code to store characters
into a larger buffer would have been larger and taken longer. Since the
interrupt handler is memory and time limited, this approach is not
practical.

The outer loop actually drains the circular buffers several times to
insure that the maximum amount of storage is available when we enter
code sections that may take a long time to execute.

The message assembly code actually goes to the large buffers to get
system console / matrix messages. (Because each panel has a 1K hardware
FIFO in the matrix, the matrix only uses the large buffers for the
system console messages.)

LRG_IN indicates where the next byte should be stored. Note that the
buffer is used as a circular queue, so the insertion index wraps around
to 0 when it reaches the physical end of the buffer.

LRG_EX indicates where the next byte should be removed from the buffer.
It also wraps around to the beginning of the buffer when it reaches the
physical end of the buffer.

###  VERSION

**VER**

Size = 1 byte

This buffer contains a null terminated ASCII string that gives the date
and time the code was linked to produce the version installed in the
matrix or panel in question.

###  SECONDS SINCE STARTING

**SSS**

Size = 4 bytes

This field gives an approximation of the number of seconds that the code
has been running.

The basic unit of time in PAWS is a 4 millisecond real time interrupt.
This is referred to as a tick. Every time a real time interrupt hits, a
variable, ticks, is incremented.

In the outer loop, a routine, CK_TMR, will process these ticks by
decrementing the ticks, and incrementing the tick count. The tick count
is our basic timer. The tick count is an 8 bit variable, and wraps from
255 to 0. Short duration intervals are based directly on the tick count,
while longer duration intervals are based on counts derived from the
tick count. As an example, the maximum interval for the tick count is
1.024 seconds.

For each 16 ticks, we bump a click counter. (KLIKS) Clicks give a
maximum time interval of 16.384 seconds. Clicks are used for download
lock timers, and other timers that require a duration in excess of a
second.

Finally, for every 16 clicks, we bump our seconds count. This results in
our second being 1024 milliseconds long, so the seconds since starting
is only an approximation.

SSS is a very useful variable to check to see if the system has hit any
snags. There is a watchdog timer that causes a reset when the code gets
wrapped, and most other error vectors, (such as illegal instruction)
also vector to a reset. This keeps the panel or matrix available, at the
danger of missing some bugs. For this reason, the panel and the matrix
code will send a reset message to the system console every time they go
through a reset. These messages can be lost if the console are not up
and running, so the seconds since starting gives you a backup method to
spot problems.

###  REASON FOR RESET

**RST**

Size = 2 bytes

When the CPU on a panel or a matrix goes through a reset, it will record
the reason for the reset in the reset variable. This is actually the
reset vector number and its complement. You can inspect this variable
and determine the reason for the reset by looking at an MC68HC11 manual.
You can also look at the file UART.ASM, which has a comment on each
vector in the table.

# MESSAGE FORMAT

## PACKET FORMAT

Each message used in PAWS is formed into a packet with a defined
structure. Each packet has a header and a trailer. If the message
contains any optional data, it appears between the header and the
trailer. The packets are delineated by start and end markers that are
part of the header and trailer sections of the message. The message
header is made up of all the fields prior to the optional data while the
message trailer is made up of all the fields after the optional data.

The header and the trailer are made up of several fields, each of which
occurs at a certain offset. The offsets are measured from the start of
the message so that the header fields are always at a fixed offset but
the trailer field offsets vary with the number of optional data bytes in
the message.

The PAWS packet format is shown below in Table 3-1.

Table 3‑1 PAWS Packet Format

  ------------------------ ----------------------- -----------------------
  Offset                   Function                Value(s)

  0                        Start of Message        0x24

  1                        Data Length             0x00-0x19

  2                        Command, high byte      (See 3.1.1)

  3                        Command, low byte       

  4                        Optional data           

  X                        CRC high byte           0x00-0xff

  Y                        CRC log byte            0x00-0xff

  Z                        End of message          0d0d
  ------------------------ ----------------------- -----------------------

### HIGH BYTE OF COMMAND

The high byte of the command contains several fields. The source field
is made up of bits 7 & 6. It identifies the origin of the message. The
destination field is made up of bits 5 & 4. It identifies the message
destination. Bits 0 - 3 identify the message type.

.

#### Addressing

The source and destination values are:

0x00 (00b) System console

0x01 (01b) Matrix

0x02 (10b) Panel

0x03 (11b) PSIC

The high nybble of the command will give source and destination address.
The complete map of addresses is shown in Table 3-2.

Table 3‑2 PAWS Addresses

  ----------- ------------- ---------------------------------------------
  Hex         Binary        Address

  0x0         \(0000\)      From system console to system console

  0x1         \(0001\)      From system console to matrix

  0x2         \(0010\)      From system console to panel

  0x3         \(0011\)      From system console to PSIC

  0x4         \(0100\)      From matrix to system console

  0x5         \(0101\)      From matrix to matrix

  0x6         \(0110\)      From matrix to panel

  0x7         \(0111\)      From matrix to PSIC

  0x8         \(1000\)      From panel to system console

  0x9         \(1001\)      From panel to matrix

  0xA         \(1010\)      From panel to panel

  0xB         \(1011\)      From panel to PSIC

  0xC         \(1100\)      From PSIC to system console

  0xD         \(1101\)      From PSIC to matrix

  0xE         \(1110\)      From PSIC to panel

  0xF         \(1111\)      From PSIC to PSIC
  ----------- ------------- ---------------------------------------------

#### Message Type

The message type is determined by the operation field. The operation
type field is made up of bits 3 - 0 of the high byte of the command.
(The low nybble of the high byte of the command word.) The operation
type values are listed in Table 3-3.

Table 3‑3 Message Type

  ----------------------------------- -----------------------------------
  Operation Type                      Value

  Command                             0x00

  Write                               0x01

  Request                             0x02

  Response                            0x03

  Announcement                        0x04

  Error report                        0x05

  Debug                               0x06
  ----------------------------------- -----------------------------------

A command is a message that is sent to a target to change the state of
the target. If the target is not required to acknowledge the message,
the message is a command. The change is lost if the target is powered
down.

A write is an operation that results in a change in the target device
that persists through a power-down/ power-up cycle. This implies a write
to a region of the EEPROM. The target does not acknowledge the write.

A request message specifies that certain information about the target be
returned to the source of the request message. The request message may
attempt to change the state of the target. A target is expected to
acknowledge the request message with a response message. If a response
message is not received, (within a given, limited time) then an error
condition exists.

A response is a message that a target sends to the source when it
receives a request. It usually contains information about the state of
the target, or the results of an attempted change of state.

An announcment is a message that indicates a change of state of the
system who\'s sole function is to notify an operator of the current
state.

An error report is a message that is transmitted to indicate the
occurance of an event or condition that should not have occurred.

Debug messages are used to support software development. They will not
be present in an operation system. They provide information about the
state of the software and hardware to the project engineers.

##### Operation Sub Options

The low byte of the command provides additional data about the command.
The actual meaning of each value is dependent on the operation type.
Information about the sub options for each operation type can be found
in the tables that appear below.

###### Command Sub Options

Command sub options are shown in Table 3-4.

Table 3‑4 Command Sub Options

  ----------------------------------- -----------------------------------
  Sub Options                         Value

  Page release                        0x00

  Panel hot                           0x01

  Panel cold                          0x02

  Reset                               0x03

  AW release                          0x04

  WW release                          0x06

  AW Tray map                         0x07

  Local AW on                         0x08

  Local AW off                        0x09

  Reset Error Counts                  0x0A

  Release tray                        0x0B

  Force Poll                          0x0C

  Remove poll                         0x0d

  Zero Page Counts                    0x0e

  Download Unlock                     0x0f

  Port Reset                          0x10

  Write Byte                          0x11

  Reset PPB                           0x12
  ----------------------------------- -----------------------------------

###### Write Sub Options

The write sub options are shown in Table 3-1.

Table 3‑5 Write Sub Options

  ----------------------------------- -----------------------------------
  Sub Operation                       Value

  Bit Map                             0x00

  Zone List                           0x01

  File Create                         0x02

  File Append                         0x03

  File Load                           0x04

  Tracking Tray                       0x05

  Local AW Tray Write                 0x06
  ----------------------------------- -----------------------------------

#######  Zone List Layouts

For zone lists, the 1st byte of optional data provides the panel number.
The second byte of optional data provides the button number.

Button numbers are encoded as row and column. The column number is in
the upper nybble and the row number is in the lower nybble. Both row and
column start numbering at 0. The upper left button on a panel will
therefore have a button number of 0x00.

####### Bit Map Numbers

The bit map numbers used in the Bit Map Write are shown in Table 3-6.

Table 3‑6 Bit Map Numbers

  ----------------------- ----------------------- -----------------------
  Name                    Location                Value

  Old Tray List           Matrix                  0x00

  New Tray List           Matrix                  0x01

  Pull Station List       Matrix                  0x02

  Panel List              Matrix                  0x03
  ----------------------- ----------------------- -----------------------

####### Tracking Tray Numbers

The tracking tray numbers used in the Tracking Tray Write are shown in
Table 3-7.

Table 3‑7 Tracking Tray Numbers

  ----------------------------------- -----------------------------------
  Tray                                Value

  Monitor Input                       0x00

  Monitor Output                      0x01

  Global Output                       0x02
  ----------------------------------- -----------------------------------

####### Request Sub Options

The request sub options are show in Table 3-8

Table 3‑8 Request Sub Options

  ----------------------------------- -----------------------------------
  Sub Option                          Value

  Bit Map Read                        0x00

  Zone List Read                      0x01

  Configuration \*                    0x02

  Tray Test                           0x03

  Area Warning                        0x04

  Page                                0x05

  Byte Read                           0x06

  Weather Warning                     0x07

  Lamp State                          0x08

  Source Select                       0x09

  Download Lock                       0x0A
  ----------------------------------- -----------------------------------

\* Matrix configuration order can be found by looking at MT_CONFIG in
SCM.ASM. Panel configuration order can be found by looking at SA_CRC and
SB_CRC in MAPS.ASM.

####### Page Responses

When a panel sends a page request, it can expect back one of the
responses shown in Table 3-9

Table 3‑9 Page Request Responses

  ----------------------------------- -----------------------------------
  Response                            Value

  Bad Request                         0x00

  Busy                                0x01

  Partial                             0x02

  Passed                              0x03

  Failed                              0x04
  ----------------------------------- -----------------------------------

A bad request indicates that the panel requested a tray that is not
listed on the matrix as being installed.

A busy indicates that one or more of the requested trays is already
being used for an equal or higher priority page.

A partial indicates that one or more of the requested trays failed to
close.

Passed indicates that all the requested trays are closed.

Failed indicates that none of the requested trays closed.

####### Source Select Request Sources

The sources used in the source select request are shown in Table 3-10

Table 3‑10 Sources for Source Select Requests

  ----------------------------------- -----------------------------------
  Audio Source                        Value

  Panel Audio                         0x00

  Weather Warning Tone                0x81

  Area Warning Tone                   0x82

  Test Tone                           0x83

  Null Audio                          0xff
  ----------------------------------- -----------------------------------

###### Response Sub Options

The response sub options are show in Table 3-11

Table 3‑11 Response Sub Options

  ----------------------------------- -----------------------------------
  Sub Option                          Value

  Bit Map Read                        0x00

  Zone List Read                      0x01

  Configuration                       0x02

  Tray Test                           0x03

  Area Warning                        0x04

  Page                                0x05

  Byte Read                           0x06

  Weather Warning                     0x07

  Lamp State                          0x08

  Source Select                       0x09

  Download Lock                       0x0A
  ----------------------------------- -----------------------------------

###### Announcement Sub Options

The announcement sub options are shown in Table 3-12.

Table 3‑12 Announcement Sub Options

  ----------------------------------- -----------------------------------
  Sub Option                          Value

  Lamp Off                            0x00

  Lamp On                             0x01

  Area Warning                        0x02

  Cutoff                              0x03

  Reset                               0x04

  Pull Station                        0x05

  Waveoff (Busy)                      0x06
  ----------------------------------- -----------------------------------

###### Error Sub Options

The error sub options are shown in Table 3-13.

Table 3‑13 Error Sub Options

  ----------------------------------- -----------------------------------
  Sub Option                          Value

  Address                             0x00

  Tray Failure                        0x01

  AW Tray Failure                     0x02

  Number                              0x03

  Source                              0x04
  ----------------------------------- -----------------------------------

####### Tray Failure States

The tray failure error states are shown in Table 3-14.

Table 3‑14 Tray Failure States

  ----------------------------------- -----------------------------------
  Failure Mode                        Value

  Stuck Open                          0x00

  Stuck Closed                        0xff
  ----------------------------------- -----------------------------------

###### Debug Sub Options

The Debug commands are used in the development/testing phase of software
development. At the present, the only capability supplied is the ability
to read the current value of a byte in memory. The \"system console\"
will send a Read Byte command followed by the high byte of an address
and the low byte of an address.

The target will return the value of the byte at that location with a
Byte read opcode followed by the actual value read.

The debug sub options are shown in Table 3-15.

Table 3‑15 Debug Sub Options

  ----------------------------------- -----------------------------------
  Sub Option                          Value

  Read Byte                           0x00

  Byte Read                           0x01

  Register Dump                       0x02

  Event                               0x03
  ----------------------------------- -----------------------------------

# TOOLS

## CALLING TREES

A variety of tools are available that make trouble shooting panel and
matrix problems easier. The source code is maintained on a machine with
a tree based directory structure. When the code is assembled, using a
makefile, a procedure calling tree is generated for each of the three
main executables; the panel, the matrix and the PSIC. These will give
you a better idea of which routines are used by other routines.

The calling tree files are named CALL.TRE and can be found in the
product directories, MP, PP, and EP. In addition to generating a calling
tree, the programs also record the current stack depth, in bytes, for
that level of calling. This allows us to size the stack depth correctly,
as later code will note the maximum stack depth the program can reach.

The procedure calling tree is not a high fidelity model. The code that
analyzes the calls contained in a procedure does not perform any
analysis of the surrounding code, so the calling tree produced is that
of all calls, some of which may not be possible. The actual calling tree
will be a subset of the listed calling tree.

### STACK DEPTH CHECKING. 

The code that generates the calling tree, and calculates maximum stack
depth also flags mismatched pushes and pops. The stack location before
calling a routine should be equal to the stack location after returning
from that routine. The code will attempt to find and flag sources of
stack creep.

## SEARCHING

A tool supplied with the Zortech compiler is also present, and useful
for finding references to variables and routines. Zgrep can be used to
search a file or files to find lines that contain a certain pattern. I
often use this to find where a routine is called from, the address of
the routine in memory, and which source file contains the routine. Other
programs are available that perform this function.

## ABSOLUTE ADDRESSES

In each product directory, MP, PP and EP, there is a batch file fix.bat.
This file will replace all the relative addresses in the .prn (print)
files in the directory with their physical addresses. It also uses an
archive program, pkzip, to bundle all of the .prn files into a
compressed file. When using the logic analyzer or in circuit emulator to
debug software, it is helpful to copy the .zip file to a floppy, and
then copy and unzip the .prn files on a laptop next to the logic
analyzer or in circuit emulator. This makes tracing operation much
easier.

## PDS

### ABOUT PDS

PDS (Paws Data Structures) is a utility program that runs on a DOS box,
and talks to the matrix, panels and PSICs via a serial link. It allows
you to examine various data structures used by the software, as well as
providing a way of performing simple system console functions such as
downloading a new panel list, resetting a device, and requesting
configuration information.

PDS connects to a matrix in place of one of the system consoles, and as
far as the matrix and panels are concerned, it is a system console.

PDS is the main tool used by the developers for trouble shooting panel,
matrix and PSIC problems. PDS is command line driven.

### REQUIRED PDS FILES 

In order to use PDS, you must have the correct data record files copied
to the PDS directory. PDS uses three data record files. The first file
contains matrix data records. The second file contains panel data
records. The third file contains PSIC data records.

Each data record file contains a series of data structure records. Each
data structure record has three fields. The first field is the data
structure name. The second field is address of the data structure in
memory. The third field is the length of the data structure. The data
record files are built each time the PAWS software is assembled and
linked.

The data record files (.REC files) can be found in the product
directories, MP, PP and EP. All three files must be present in order for
PDS to run. If you make any changes to the PAWS code, you should copy
the new .REC files to the PDS directory before you start trouble
shooting.

#### Required PDS File Names and Locations

matrix data records: **MMR.REC** in MP directory

panel data records: **PMR.REC** in PP directory

PSIC data records: **EMR.REC** in MP directory

### PDS COMMANDS

PDS supports the commands shown in Table 4-16.

Table 4‑16 PDS Commands

  --------------------------- -------------------------------------------
  Command                     Action

  QUIT                        Exits the program

  HELP                        Displays all commands

  ?                           Displays all commands

  TARGET                      Shows current target

  ZERO                        Reset Target\'s error counts

  RESET                       Reset the current target

  CLEAR                       Clear the computer\'s screen

  MATRIX                      Set current target to the matrix

  BITS                        List contents of bit map

  NOBITS                      Set bit map to empty

  PSLIST                      Download pull station list

  TORTURE                     Disable limit checks

  SAFE                        Enable limit checks

  HIDE                        Suppress display of spurious messages

  SHOW                        Enable display of spurious messages

  PNLLIST                     Download panel list

  OTLIST                      Download old tray list

  NTLIST                      Download new tray list

  CONFIG                      Request current target\'s configuration CRC

  ZEROPAGE                    Reset page counts

  LOCK                        Lock panel or PSIC for download

  UNLOCK                      Release panel or PSIC from download

  HOT                         Make a panel or PSIC hot

  COLD                        Make a panel or PSIC cold

  BLANK                       Set panel for empty configuration

  ALL                         Set panel\'s buttons all to one
                              configuration

  VIEW                        View target symbol records

  PANEL \<NUM\>               Set current target to indicated panel

  PSIC \<NUM\>                Set current target to indicated PSIC

  POLL \<PNL\>                Add indicated panel to polling list

  UNPOLL \<PNL\>              Remove the indicated panel from the polling
                              list

  RELEASE \<TRAY\>            Unkey the indicated tray

  TRACK \<TRAY\>              Set the monitor input tray number

  MONITOR \<TRAY\>            Set the monitor output tray number

  GLOBAL \<TRAY\>             Set the global output tray number

  \+ \<BIT\>                  Add a bit to the bit map

  \- \<BIT\>                  Remove a bit from the bit map

  LAW \<PS\>                  Download a local area warning tray map for
                              the indicated pull station

  READBUTTON \<RC\>           Read the indicated button\'s zone list

  FIFO \<PNL\>                Reset the FIFO for the indicated panel

  TRAFFIC ON                  PDS starts polling the current target

  TRAFFIC OFF                 PDS stops polling the current target

  TRAFFIC REPORT              List polling attempts and errors

  BUTTON \<RC\> \<PRI\>       Download a zone list to the indicated
                              button using the indicated priority

  WRITE \<ADDR\> \<BYTE\>     Write the indicated byte to the indicated
                              address on the current target

  \<SYMBOL\>                  Read the contents of the indicated
                              structure

  \<ADDR\> \<LEN\>            Read the indicated region of memory
  --------------------------- -------------------------------------------

**QUIT** and **F10** are used to terminate PDS.

**HELP** and **?** are used to display the help screens, which list the
above commands.

**TARGET** will cause PDS to print the input prompt, which identifies
the type, and possibly the unit number, of the device PDS is talking to.
(Unit numbers are displayed for PSICs and panels.)

Upon starting, PDS will have target set to matrix, so any reads will
come from the matrix PDS is connected to. Also, any commands that can be
sent to more than one device will be addressed to the matrix. PDS also
has commands that allow you to set the target to a panel or a PSIC.

**ZERO** is used to reset the contents of several tables on the target
device. On all devices, ZERO will reset the contents of the Interrupt
Handler Error table. (IHE_TBL) It also clears the Link Health table.
(LHTAB) This table contains counts of errors for all serial links the
target device uses. ZERO also clears the error table (E_TBL) on all
devices.

If the current target is the matrix, the tray open failure table (TOTBL)
and the tray closed failure table (TCTBL) are reset as well.

**RESET** causes the target device to go through a reset cycle. The
software commanded reset is almost identical to a power on reset with
the exception of the RST variable. The RST variable will be set to a
value that indicates the reason for reset was a software command rather
than a power on reset. (There are several things that can cause a reset,
each has a unique value that is recorded in RST.)

The reset reasons appear in Table 4-17. RST values are usually the
vector number as the first byte, and the logical complement as the
second byte. The exception is the software commanded reset, which does
not have a vector number.

Table 4‑17 Reset Reasons

  ----------------------------------- -----------------------------------
  RST                                 Reason

  0CF3                                SPI Interrupt

  0DF2                                Pulse accumulator edge interrupt

  0EF1                                Pulse accumulator overflow
                                      interrupt

  0FF0                                Timer overflow interrupt

  10EF                                IC4/OC5 interrupt

  11EE                                OC4 interrupt

  12ED                                OC3 interrupt

  13EC                                OC2 interrupt

  14EB                                OC1 interrupt

  15EA                                IC3 interrupt

  16E9                                IC2 interrupt

  17E8                                IC1 interrupt

  18E7                                External interrupt (XIRQ)

  19E6                                Software Interrupt (SWI)

  1AE5                                Illegal instruction interrupt

  1BE4                                COP interrupt

  1CE3                                clock monitor interrupt

  1DE2                                reset

  20DF                                software reset command
  ----------------------------------- -----------------------------------

**CLEAR** will cause the PDS screen to clear. Because received messages
are normally displayed on the PDS screen, you can sometimes end up with
a lot of junk on screen, and need to clear it so you can see how the
system reacts to certain commands.

**MATRIX** will cause PDS to change the current target to the matrix.
The current target defines how certain messages are addressed. (Messages
that can be sent to more than one target.) The current target also
determines which data file PDS searches when looking for variables.
(Each target type has its own data record file. The matrix uses records
from MMR.REC, the panel uses records from PMR.REC and the PSIC uses
records from EMR.REC.)

**BITS** will display a list of the bit numbers for all bits currently
set in the PDS bit map. In order to save space, many data structures
used in PAWS software are bit maps. There are commands to add and remove
bits from the PDS bit map. Many commands that PDS sends use the current
PDS bit map as the data that is sent.

As an example, each button on a panel has associated tray maps, one for
the A side and one for the B side. In order to reconfigure one of a
panel\'s button, you construct a tray bit map using PDS\' + and -
commands.

Each tray that is used for a page in that area for the side of the
system you are currently connected to should appear in the PDS bit map.
You can use BITS to verify that the map contents are correct before
using the map via the BUTTON command.

Please note that PDS and most PAWS software starts numbering units from
0 while the system console starts unit numbering from 1. This means that
when using PDS, you must subtract one from the usual unit number.

**NOBITS** will reset the PDS bit map to empty. If many changes are
required, it is sometimes quicker to reset the bit map and start over.

**PSLIST** will send the current PDS bit map to the matrix as a write
pull station list command. Every bit set in the PDS bit map will result
in that pull station being listed in the pull station bit map on the
matrix and in the pull station polling list.

Only the listed pull stations are checked for activity. (The pull
station bit map on the matrix is stored in EEPROM, so it is persistent.)

**TORTURE** will disable certain sanity checks PDS normally performs on
operator input. In normal operation PDS checks things like panel numbers
in the panel command to prevent PDS from generating illegal messages. In
the event that you want to see how the system reacts to certain illegal
messages, you can enter TORTURE to disable the checks and generate
illegal messages.

TORTURE will disable argument checking for the following PDS commands:

-   PANEL

-   POLL

-   UNPOLL

-   LAW

-   READBUTTON

-   BUTTON

-   FIFO

-   PSIC

**SAFE** will enable argument checking for certain commands. (See the
command list in TORTURE.) PDS will come up in safe mode, so argument
checking is normally enabled.

**HIDE** will suppress the display of spurious messages. Normally PDS
will display all messages it receives. This can be a problem at times,
since the system consoles will periodically ask for data from the
matrix. These messages coming in during a PDS data structure read can
cause the data you were trying to read to scroll off the screen. HIDE
will prevent this from happening.

**SHOW** will enable the display of spurious messages. PDS comes up in
SHOW mode, so normally spurious messages are displayed.

**PNLLIST** will send the contents of the PDS bit map to the matrix as a
panel list. The matrix will store this panel list in EEPROM, making it
persistent. Only the panels in the matrix panel list, and panels added
with the POLLING command will be checked for activity. Messages are
always sent from the matrix to any panel, but the matrix will only check
for messages coming from the panels listed in the polling list.

This means you can always send messages to any panel, but you can only
receive messages from panels listed in the panel polling list.

**OTLIST** will send the contents of the PDS bit map to the matrix as an
old tray list. The matrix will store the old tray list in EEPROM, making
it persistent.

Old trays do not have the feedback contact, so the actual physical
position of the tray can not be checked. As a result, old trays are
assumed to always be good by the matrix since there is no way of
detecting tray failure.

**NTLIST** will send the contents of the PDS bit map to the matrix as a
new tray list. The matrix will store the new tray list in EEPROM, making
it persistent.

New trays have the feedback contact, so the actual physical position of
the tray can be checked. As a result, new trays are always tested by the
matrix to insure that they reached the commanded position. (After
allowing enough time for the tray to actually switch states.)

**CONFIG** will send a request for the device configuration to the
current target. The configuration is actually a 16 bit CRC generated
across certain data within the target device. If the CRC matches what
the system console computed for the target, it is very likely that the
target contains the correct download. Each side has its own
configuration CRC, so the system console will normally ask for the
configuration of both the A side and the B side.

**ZEROPAGE** will reset the page attempt tables in the matrix. Every
time a panel attempts a page, the matrix will bump a 16 bit page count
associated with that panel. When the count reaches 65535, it is no
longer incremented.

By reading the page attempt table periodically, you can determine how
much paging activity there has been. In order to keep the page attempt
counts from topping out, you should zero the page count table once in a
while. (Like every time you read the page count table. That gives the
counts since last check, which can be used to keep a running tally of
pages.)

**LOCK** will send a download lock command to the target device. Before
you can download a new configuration to a target device, you must lock
the device first.

If the device is busy, it will wave off the lock attempt. If the device
is idle, the download lock will be accepted.

When a target device enters the lock state, it starts a timer. If the
device does not receive an unlock command within a short period of time,
it will unlock itself. This prevents dropped messages from disabling
parts of the PAWS. If a download write command is received while the
target is not locked, it will be thrown out. Data can only be written to
EEPROM when the system is locked.

(Note that you can download to the matrix without locking it, due to the
way the software in the matrix works. The panels and the PSICs must be
locked and unlocked before you can write to any of the buttons.)

**UNLOCK** will send an unlock command to the target device. This causes
the target to enter the unlocked state. Any downloads received while the
target is unlocked will be discarded.

**HOT** will cause the target device (panel or PSIC) to enter the hot
mode. In the hot mode, the target will send notification of any lamp
state changes to the system console so that the display on the system
console matches the actual target.

Certain changes are always sent to the system consoles, such as area
warning key switch position changes.

Lamp state changes that occur as the result of lamp tests are not sent
to the system consoles due to the large amount of traffic this would
generate.

**COLD** will cause the target device (panel or PSIC) to enter the cold
mode. In the cold mode, the target will not send notification of any
lamp state changes to the system console.

Panels are normally cold to decrease the amount of traffic that the
system must handle. When a system console operator brings up a display
of a panel, the panel is sent the hot command. As soon as the system
console display of the panel is closed, the panel is switched back to
cold mode.

**BLANK** will send an empty tray map to every button on the target
device. This leaves the panel (or PSIC) with no ability to perform
pages.

**ALL** will send the PDS bit map to every button on the target device.
This means that every button on the target will page the same areas.

BLANK and ALL were added to make it easy to change panel configuration
for testing during development. They should be used with caution on a
live system. (BLANK can be used to temporarily take a panel out of
service by removing all the trays from all the buttons. This will
prevent the panel from being able to make any pages.)

**VIEW** allows you to examine the list of data structures on the
current target device that PDS can read. This is helpful if you\'ve
forgotten the exact name of a data structure that you want to inspect.

There are three data structure files, one for the panels, one for the
matrices, and one for the PSICs. These .REC files are generated when the
code is assembled and linked. Each file has several entries, with each
entry consisting of the data structure name, the address of the data
structure in memory and the length of the data structure.

All three files must be present in order for PDS to run. If you make any
changes to the PAWS code, you should copy the new .REC files to the PDS
directory before you start trouble shooting.

**PANEL** will cause PDS to change the current target to a panel. The
current target defines how certain messages are addressed. (Messages
that can be sent to more than one target.) The current target also
determines which data file PDS searches when looking for variables.
(Each target type has its own file. The panel uses records from
PMR.REC.)

Which panel you\'re talking to is determined by the argument given with
the PANEL command. An example, PANEL 4 will cause PDS to start
communicating with panel 4. (Remember that PDS starts numbering from 0.
This would be the systems console\'s panel 5.)

**PSIC** will cause PDS to change the current target to a PSIC. The
current target defines how certain messages are addressed. (Messages
that can be sent to more than one target.) The current target also
determines which data file PDS searches when looking for variables.
(Each target type has its own file. The PSIC uses records from EMR.REC.)

Which PSIC you\'re talking to is determined by the argument given with
the PSIC command. An example, PSIC 7 will cause PDS to start
communicating with PSIC 7. (Remember that PDS starts numbering from 0.
This would be the systems console\'s PSIC 7.)

To the rest of the system, a PSIC looks like a panel. The PSIC number is
determined by which input on which PPIC the PSIC is connected to. It has
the same number as a panel would if it were connected to the same
location.

**POLL** will cause a panel to be added to the panel polling list. Which
panel is added is determined by the argument given to the POLL command.
As an example, POLL 5 will add panel 5 to the panel polling list.
(Remember that PDS starts numbering at 0, so this is the same panel as
the system console\'s panel 6.)

Only panels on the panel polling list are checked for messages going
from the panel to the matrix or system console.

Adding a panel to the panel polling list with the POLL command is a
temporary patch. If the matrix goes through a reset, a new panel polling
list will be constructed using the contents of the panel list stored in
EEPROM in the matrix. The POLL command will not add the panel to the
EEPROM list.

The system does not react well to having the same panel on the panel
polling list twice. Use care in adding a panel to the polling list with
the POLL command.

**UNPOLL** will temporarily remove a panel from the panel polling list.
If the matrix goes through a reset, a new panel polling list will be
constructed from the contents of the panel list in the matrix\'s EEPROM.

Which panel is removed is determined by the argument given to the UNPOLL
command. As an example, UNPOLL 7 will remove panel 7 from the panel
polling list. (Remember that PDS starts numbering from 0. This is the
same panel as the system console\'s panel 8.)

The UNPOLL command will not remove a panel from the panel list in the
matrix\'s EEPROM.

If you attempt to remove a panel from the panel polling list that is not
present, the panel polling list is not changed.

UNPOLL is very useful for removing a panel from the system when there is
a communications problem with the panel. Under certain circumstances, a
noisy line can cause a large amount of garbage on the panel comm port.
Processing these garbage bytes can require a lot of matrix time, slowing
the whole system down. If too many panels are having comm problems,
pages and tray tests will start to fail due to the panels timing out
before the matrix has had a chance to return a response.

Another circumstance in which it is useful to use the UNPOLL command is
when a PPIC card must be removed from the system. When a PPIC card is
pulled, the matrix will think it has received a byte from any panel that
was connected to that PPIC every time it checks the PPIC.If you remove a
PPIC that had any panels connected to it, use the UNPOLL command to
remove each panel that was connected to that PPIC.

**RELEASE** will cause a tray to be unkeyed. Which tray is unkeyed is
determined by the argument given to the RELEASE command. RELEASE 5 will
cause tray 5 to be unkeyed. (Remember, since PDS starts counting from 0,
this is the same as the system console\'s tray 6.)

If a panel is powered off, or fails, while a page is in progress, the
trays involved will be left keyed. The only way to unkey them from the
panel is to get a working panel installed, select the same zones, page,
and then release. In the event of a panel failure, this recovery method
may take too much time due to the time to replace the panel, so the
RELEASE command was added to the system. RELEASING an unkeyed tray has
no affect.

**TRACK** allows you to define a tray that you wish to monitor.

Used together, TRACK and MONITOR define an input tray and an output tray
that operate as a slaved pair. That is, every time the TRACK tray is
keyed, the MONITOR tray is keyed. Both trays receive the same audio.

Which tray is the master (or input) tray is determined by the argument
given to the TRACK command. As an example, TRACK 9 will cause tray 9 to
act as the master tray. Remember that PDS starts counting at 0, so this
is the same tray as the system console\'s tray 10. If the TRACK tray is
255, (\$ff) then the MONITOR tray is not keyed. This can be used to
disable the tracking feature.

**MONITOR** allows you to define a tray that you wish to use to monitor
another tray.

Used together, TRACK and MONITOR define an input tray and an output tray
that operate as a slaved pair. That is, every time the TRACK tray is
keyed, the MONITOR tray is keyed. Both trays receive the same audio.

Which tray is the slave (or output) tray is determined by the argument
given to the MONITOR command. As an example, MONITOR 7 will cause tray 7
to act as the slave tray. Remember that PDS starts counting at 0, so
this is the same tray as the system console\'s tray 8.

If the MONITOR tray is 255, (\$ff) then the MONITOR tray is not keyed.
This can be used to disable the tracking feature.

GLOBAL is a command used to activate a most recent page monitor. The
GLOBAL tray will always be slaved to the first tray used in the most
recent page.

If pages do not overlap, the GLOBAL tray will allow you to hear every
page being performed in the PAWS.

In the event that pages overlap, then when the new page starts, the
GLOBAL tray will switch from the old page to the new one. This means you
can not hear the end of the old page, but will hear the entire new page.
(Unless it is cut off by a new page coming in.)

Which tray serves as the GLOBAL output tray is determined by the
argument given to the GLOBAL command. As an example, GLOBAL 27 will
cause the newest page (regardless of which tray it uses) to be heard on
tray 27. (Remember that PDS starts number at 0, so this is the same tray
as the system console\'s 28.)

If the GLOBAL tray is set to 255 (\$ff) the global monitoring feature is
disabled.

**+** is used to add a bit to the PDS bit map. As an example, + 10 will
set bit 10 in the PDS bit map.

In order to save space, many data structures used in PAWS software are
bit maps. There are commands to add and remove bits from the PDS bit
map.

Many commands that PDS sends use the current PDS bit map as the data
that is sent.

You must have a space between the plus sign and the number that follows.

The number following + is the bit number that will be set. PDS starts
its bit numbering from 0.

**-** is used to remove a bit from the PDS bit map. As an example, - 6
will clear bit 6 from the PDS bit map.

In order to save space, many data structures used in PAWS software are
bit maps.

There are commands to add and remove bits from the PDS bit map.

Many commands that PDS sends use the current PDS bit map as the data
that is sent.

You must have a space between the minus sign and the number that
follows.

The number following - is the bit number that will be cleared. PDS
starts its bit numbering from 0.

**LAW** is used to assign a tray map to a pull station.

When a local area warning pull station is activated, the matrix must
notify all the panels in the system which zones are in area warning
mode. In order to do this, the matrix must have a map of trays that go
into area warning mode when each area warning pull station is activated.

Which pull station gets the new map is determined by the argument given
to the LAW command. The PDS bit map is sent to the matrix as the tray
bit map to associate with that local area warning pull station.

The sequence to use is: Set up the tray bit map using the + and
commands. Once the PDS bit map contains the correct trays, use the LAW
command to send the map.

As an example:

  ---------------- ------------------------------------------------------
  NOBITS           The first command clears the PDS bit map

  \+ 0             The second command sets bit 0, indicating tray 0

  LAW 5            The third command sends the PDS bit map, with tray 0
                   in it, to the matrix, indicating LAW station 5.
  ---------------- ------------------------------------------------------

The matrix will record tray 0 as being placed in area warning mode
whenever local area warning pull station 5 is activated.

Remember that PDS starts numbering from 0, while the system consoles
start numbering from 1.

**READBUTTON** is a command that allows you to determine which trays are
associated with both sides of a given button on a panel. It also shows
the priority associated with the zone button. Buttons are identified by
a row number and a column number. Both numbers are packed into a single
two digit number.

Row and column numbering start from 0. The upper left button is button
00.

The READBUTTON command should display two data structures. The first
data structure is the one for side A, while the second is the one for
side B.

In each record displayed, the first byte is the priority for the zone
select button. The bytes following that are a bit map of trays assigned
to that button.

As an example, if the current target is panel 0:

READBUTTON 11

will return the information for the button to the right of, and one down
from the button in the upper left corner of panel 0. (Remember that PDS
starts numbering from 0 while the system console starts numbering from
1.)

**FIFO** is used to reset the fifo the matrix uses to communicate with
the panel.

Each PPIC has four fifos, one for each panel it connects to. Each fifo
has a 1K buffer on both the transmit and receive side.

The fifo does not go through a power on reset, so the matrix must
perform a software reset on each fifo when the matrix comes out of reset
to insure the fifos are operational.

The fifo command was added as a possible way to restore panel
communications in some circumstances.

Which panel\'s fifo gets reset is determined by the argument given the
FIFO command.

**TRAFFIC ON** is used to activate polling in PDS. When traffic is on,
about once a second PDS will attempt to read a byte from the current
target. If the target does not return the requested byte, a traffic
error is recorded in PDS.

This feature is useful for detecting low error rates on a panel comm
link. You can start PDS traffic to a panel, and let it run overnight.
The request rate is low enough that it should not interfere with normal
system operation, but high enough to detect slight panel communications
problems if you run it for several hours.

**TRAFFIC OFF** is used to deactivate panel polling in PDS. When traffic
is on, about once a second PDS will attempt to read a byte from the
current target. When traffic is off, PDS does not ask for any data from
the target unless requested by the PDS operator.

TRAFFIC REPORT is used to report on the health of a matrix/panel comm
link. When entered, it will cause PDS to display the number of times PDS
has requested a byte from the target and the number of errors that
occurred.

A healthy link should have error rates on the order of parts per
million.

**\<SYMBOL\>** The main use of PDS is inspecting PAWS data structures.
You can examine a data structure on the current target by entering the
data structure name.

As an example, IHE_TBL will cause PDS to display the interrupt handler
error table.

Only the data structures listed in the target\'s data records file can
be read this way. Each type of target has its own data record file.

The contents of the data structure file can be viewed from within PDS
using the VIEW command.

PDS will not run unless all three data record files are present.

Appendix A details the steps needed to add a data structure to the data
record file.

**\<ADDR\> \<LEN\>** PDS provides a more general method of examining
target device memory. You can always examine target memory by entering a
hex address and a length, separated by a space. This can be used to
examine data structures that are not listed in the data record file.
(You can find all data structure addresses in the .SYM file in the
product directory for the target. (matrix: MC.SYM, panel: PC.HEX, PSIC:
EC.HEX)

This command can also be used to inspect code in the target. Most
routines will have an address in the symbol file (.SYM) which you can
use. This is handy if you\'re afraid that the XICOR content\'s was
somehow corrupted.

### USING PDS FOR QUICK CHECKS ON UNIT HEALTH

When I start looking at a unit with PDS, I usually start with a quick
series of tests to see if there are any major problems I should know
about.

#### Interrupt Handler Error Table

The first thing I examine is the interrupt handler error table, IHE_TBL.
There are four bytes in this table. The first byte (IHE_TBL\[0\]) is a
count of the number of breaks detected on the A side. The second byte
(IHE_TBL\[1\]) is a count of the number of breaks detected on the B
side.

Since PAWS does not use breaks for signaling, you would expect this
count to always be 0. There are conditions where the serial lines can be
held in a certain state long enough for the UART to detect a break.
These usually occur when the device on the other end of the serial link
has had its power cycled.

As a result of turning things on and off, you can sometimes see the
error count for these with a value of one or two, instead of the
expected 0. Unless things are being turned on and off a lot, you should
not see counts higher than 2. If these counts are high, there may be a
problem with the serial link.

(Since the matrix should never be turned off, and the console may be
turned on and off frequently, if you let the matrix run long enough
without a reset or a zero, the counts on the matrix may creep up.)

The third and forth bytes are counts of receiver buffer overflows for
the A side and B side. The software was designed so that these events
should never happen. If these counts are ever nonzero, we\'ve got big
troubles or a memory overwrite problem. (I\'d bet on a memory
overwrite.)

#### Error Table

The next item I check is the error table. This table contains counts of
several errors that can be detected. Some errors, such as garbage in
front of message, are not really unexpected. This can happen when the
device on the other end of the serial link is powered on and off.

No response from matrix A and no response from matrix B can occur when
the system becomes overloaded, usually due to other communication
problems. If there are a lot of other errors on the system, some panels
may show nonzero counts here. On the other hand, if the system has not
been too busy, these errors on a panel can indicate a problem with the
communication link to the matrix.

Invalid tray number in tracking write, Panel polling deletion errors
should not occur unless PDS has been used in the torture mode. If these
counts are nonzero, there may be a system console problem, or a memory
overwrite problem.

Invalid panel number in forwarding should only occur when using PDS in
torture mode to generate invalid messages, otherwise suspect a system
console problem, or a low chance of a corrupted message getting through
the CRC check. (Or the ever-famous memory overwrite.)

Large buffer overflows should never occur. The software was designed so
that buffering and servicing should occur frequently enough that we do
not lose any bytes. If you see large buffer overflows, suspect a noisy
serial link generating a lot of garbage. If it is really being caused by
a noisy serial link, you would also expect to see a lot of garbage in
front of message errors with this problem, along with bad CRC and
Invalid EOM errors.

Undefined tray state during page attempt indicates that the matrix has
had a serious memory corruption problem, or there is some other bug in
the matrix code. The tray state should always be defined.

Free tray type undefined, page attempt. This indicates a serious matrix
problem, either memory corruption or some other bug. A tray needs to be
defined as either a new tray or an old tray in order to be a legal tray.
A page attempt containing an illegal tray should be rejected as an
illegal page, and not attempted by the matrix. The matrix should never
attempt a page that contains a tray that was not defined as new or old
tray.

Active tray type undefined, page attempt. This differs from Free tray
type undefined, page attempt, only in the state of the tray in question
and where the problem was detected.

Attempt to release free tray. This error indicates that the matrix
received a message releasing a tray from a page, when the tray is
already listed as free. This indicates that the matrix has fouled up its
internal bookkeeping somehow. Suspect a software bug or a memory
corruption problem.

Tray type undefined during release. This differs from Free tray type
undefined, page attempt, only in the state of the tray in question and
where the problem was detected.

-   Invalid message from system console

-   Invalid write command

-   Invalid map number, write command

-   Invalid request

-   Invalid map number, read command

-   Illegal command

-   Message from panel not addressed to matrix/console

-   Invalid message type from panel

-   Invalid request from panel

-   Invalid command from panel

-   Invalid tracking numbering

-   Invalid message type

-   Invalid write command

-   Bad map number, tray test response

-   Invalid request

-   Invalid command

-   Invalid announcement

-   Not addressed to me

These errors indicate a poorly formed message. It is possible that these
are due to a software bug on the recording device, or corruption in the
serial link that slipped through the CRC checks, but it more likely that
they indicate a problem on the device sending messages to the recording
device. (The one containing the errors in its error table.)

It is possible to induce some errors using PDS. As an example, you could
induce the Invalid map number, write command, error by using PDS in the
torture mode to send a tray map for a pull station above 191.

-   False start or corrupted length

-   Invalid EOM

-   Invalid CRC

These errors usually indicate a problem on the serial link.

#### Link Health Table

The next thing to check is the link health table. This table records
errors that can be associated with problems on the serial links. All
devices have two serial links for the DUART links. The matrix also has
entries for each panel.

All devices have the same number of entries. The first 128 entries in
the link health table (0 through 127) are panel link health entries, and
are only used on the matrix. The A Side of the DUART is offset 128 and
the B side of the DUART uses offset 129. On the Panels and the PSICs,
errors should not be recorded for low offsets.

Errors that are recorded in the link health table should result in
errors being recorded in the error table as well. (E_TBL)

#### Seconds Since Starting

The next thing I check is the seconds since starting. (SSS) This
indicates how long the unit has been running.

The matrix should not be powered down or reset except for software
upgrades or otherwise unrecoverable errors, which should be noted in the
log. If SSS indicates the matrix has not been running as long as it
should have, look at RST, which indicates the reason for the last reset.
This may provide some indication as to what has gone wrong.

On the panels, SSS is less useful as the panel operators may turn their
panels on and off more frequently. It is still worth looking at RST on
the panels, you should not see anything except a power on reset. The
only exception is a software command reset which can be induced via the
RESET command from PDS. Any other reset value indicates a problem that
needs to be investigated.

### TROUBLE SHOOTING PANEL PROBLEMS

Most of the panel problems that we\'ve experienced during the
development phase of PAWS have been associated with communications
between the matrix and the panel, and configuration problems. Here are a
few tips for investigating these kinds of problems.

Can you communicate with the panel?

The first PDS check is to hook PDS to the matrix, and turn the power on
the panel in question off and on. This should result in a reset message
from the panel. Make sure the panel number in the message is correct.

A panel reset message will look like:

24 01 84 04 PN XX YY 0d

PN is the panel number. XX YY is the message CRC and varies with the
panel number.

If you see the panel reset message, you know that comm from the panel to
the matrix is fine, and you should skip the following tests. If you
don\'t see the panel reset message, then you need to make sure the
matrix is configured for communications with the panel.

First check the PN_TBL to see if the panel is listed in the matrix\'s
panel list. For messages to be forwarded from the panel to the system
console, the panel must be listed in the matrix panel list, or have been
manually inserted into the polling list.

If the panel does not appear in the panel table, try downloading a panel
table that contains the panel in question. (You can also use the POLL
command to temporarily add the panel to the polling list for trouble
shooting.) If this fixes the problem, you need to check the
configuration listed on the system consoles to see if you can figure out
why the panel does not appear in the panel list.

If the panel appears in the PN_TBL, check to see if the panel is in the
panel polling list, PL_LST. If the panel is not on the panel polling
list, you need to find out why the panel was removed from the polling
list. Usually the panel is removed from the polling list when a message
has been received, but it is normally placed back on the polling list as
soon as message processing is complete, usually within 40 to 50
milliseconds.

It is unlikely that you will find the panel listed on the assembled
message list as panels appear here for a very brief time. They will be
processed shortly after returning to the main loop, or if trays have to
be pulled in or released, after the trays have been keyed or unkeyed.

If a panel is in the panel table, PN_TBL, but is not on the polling
list, PL_LST, or assembled message list, AM_LST, then you should look at
the panel record to see if its still waiting on one or more trays. (This
would indicate a software bug in the matrix, but at least you would have
some idea of where the bug may lie.)

It is also possible that the panel was removed manually using the UNPOLL
command. If this is the case, you can use the POLL command to place the
panel back on the panel polling list. (Make sure the panel appears in
the panel table, PN_TBL, or you\'ll lose the panel again as soon as the
matrix goes through a reset.)

If you find the panel listed in the panel polling list but the matrix
does not seem to be receiving messages from the panel, check the message
buffer structure for that panel to see if messages are being assembled
but not acted on.

As an example, if you are having problems with messages from panel 5,
but it is listed in the panel polling list, power panel 5 off and back
on, then check MS_05. (Remember PDS numbers starting with 0 and the
system console numbers starting with 1.) You should be able to see the
panel reset message in the message buffer.

The matrix will send messages to a panel even if it is not listed in the
panel table. You should be able to send messages to any panel that is
physically connected to the system. A quick check with PDS is to send a
reset message to the panel and see if it beeps. If it beeps, the message
made it to the panel.

(Note that if comm is down, PDS will attempt to read the panel type
several times, and it will take a minute or two for PDS to reach the
point where it is ready to send the reset command.)

It is possible for the communications link between the matrix and the
panel to be down in only one direction. Keep this in mind when trouble
shooting panel problems. Also remember that panels are connected to two
matrices, which gives you two paths to and from the panel for testing.
(and failures)

If the configuration appears correct, and the software looks good, check
physical connections.

### TROUBLE SHOOTING TRAY PROBLEMS

Here are a few tips for trouble shooting tray problems. It is not always
easy to spot tray related problems. As an example, if you don\'t include
a tray in the download to the matrix, you may disable all buttons on all
panels in the system that contain that tray.

(If the other side of the button is empty, the illegal tray will prevent
the panel operator from selecting that zone. Even if the other side
isn\'t empty, you greatly increase the chances that the system will not
allow operations with that button.)

The first thing to do is to check and verify the tray is listed as being
installed.

Old style trays will be listed in the old tray table, OT_TBL. This is a
bit map. If the bit is set, the tray is installed. New style trays, with
feedback contacts, are listed in the new tray table, NT_TBL.

If a tray is installed, but doesn\'t appear in the correct list, you\'ll
want to look at the system configuration on the system consoles.

When the matrix is reset, it will read the OT_TBL and NT_TBL and set
bits in the tray records to indicate what kind of tray each is. (Each
tray has its own record, see the TR_XX entry in the structures section.)

If you are not getting audio from a certain tray, the first thing you
should do is check to see if the tray is actually assigned to the zone
in question, then verify that it is installed by looking at OT_TBL or
NT_TBL as required.

After you verify that the tray is listed as installed and is assigned to
the zone in question, check the other trays assigned to that zone to
verify that all trays are listed as installed. As mentioned earlier,
having a single illegal tray on a zone can disable the entire zone.

If the tray in question is a new tray, you can check the tray open
failure table and the tray closed failure table to see if the tray
appears to be failing.

Another reason for a tray to \"fail\" is that it is tied up. If a panel
makes a page, then fails while it has trays keyed, the matrix will never
receive a tray release command from the panel. This results in the trays
being continuously busy, preventing other panels from using them.

To see if this is what is happening, look at the TR_XX record to see if
its tray state field indicates that the tray is active. Most trays
should be listed as Free except for when they are being used in a page,
and for short times around keying and unkeying of new trays. (These
periods are about 40 milliseconds in length, so it is hard to catch a
tray in this state.)

If a tray is active, you can find out which panel owns it by looking at
the TR_OWN field. If you can verify that the panel listed there is not
using the tray, you can use the RELEASE command to free the tray. If you
have to do this, it is a good idea to check the other tray records to
see which other trays are in the same state, and free them as well.
(Active and owned by the panel that is not using them.)

It is not too hard to actually get the system in this state. All you
have to do is start a page using a panel, then without letting up the
microphone push to talk switch, turn the panel power off. This will
leave the trays that were being used in the page hung. You can recover
without PDS by selecting the same zones, and doing a short page. This
will cause the panel to send a page request and a page release, which
will free the trays.

### ADDING A DATA STRUCTURE TO THE .REC FILE 

The makefile will generate a .rec file every time a product is assembled
and linked. The assembly and link process produces a symbol file. The
symbol file is one of the inputs that is used to produce the .rec file.
The other input is a string selection file, which is located in the
control directory. (MC, PC and EC)

The string selection file contains a series of records, one per line.
Each record consists of two fields. The first field is the data
structure name. This should be an exact match with one of the symbols
that appears in the symbol file.

The second field contains the data structure length. We can get the
memory address for the data structure from the symbol file, but the
length is not included in the symbol file, so you must supply this
information in the string selection file, str.sel.

To add a new data structure to the .rec file so PDS can read it, given
only the name, you have to add the name and the length of the data
structure to the string selection file, str.sel, in the control
directory for the unit type. (matrix, panel or PSIC)

After adding the name and length, the next make will generate a new .rec
file containing the new data structure.