Language selection

Search

Patent 2332297 Summary

Third-party information liability

Some of the information on this Web page has been provided by external sources. The Government of Canada is not responsible for the accuracy, reliability or currency of the information supplied by external sources. Users wishing to rely upon this information should consult directly with the source of the information. Content provided by external sources is not subject to official languages, privacy and accessibility requirements.

Claims and Abstract availability

Any discrepancies in the text and image of the Claims and Abstract are due to differing posting times. Text of the Claims and Abstract are posted:

  • At the time the application is open to public inspection;
  • At the time of issue of the patent (grant).
(12) Patent Application: (11) CA 2332297
(54) English Title: WIRELESS ELECTRONIC ENERGY METER
(54) French Title: COMPTEUR D'ENERGIE ELECTROSTATIQUE SANS FIL
Status: Deemed Abandoned and Beyond the Period of Reinstatement - Pending Response to Notice of Disregarded Communication
Bibliographic Data
(51) International Patent Classification (IPC):
  • G8C 17/00 (2006.01)
  • G1R 21/00 (2006.01)
  • H4Q 9/00 (2006.01)
(72) Inventors :
  • MUELLER, WILFRED (Canada)
  • JOHNSON, RODERICK MICHAEL (Canada)
  • BLACKWELL, DANE (Canada)
  • HAMILTON, PATRICK C. (Canada)
  • NEEDHAM, DENNIS M. (Canada)
  • SCRIBNER, ALLAN L. (Canada)
(73) Owners :
  • SMARTSYNCH LTD.
(71) Applicants :
  • SMARTSYNCH LTD. (Canada)
(74) Agent: BENNETT JONES LLP
(74) Associate agent:
(45) Issued:
(22) Filed Date: 2001-01-25
(41) Open to Public Inspection: 2002-07-25
Availability of licence: N/A
Dedicated to the Public: N/A
(25) Language of filing: English

Patent Cooperation Treaty (PCT): No

(30) Application Priority Data: None

Abstracts

English Abstract


A wireless electrical energy meter is provided comprising an interface board
for
connecting an electrical power usage meter to a pager board capable of
transmitting data
to a remote host computer. The interface board includes an input port or
connection to
the meter for periodically reading data from the meter, and an output port for
connection
to the pager board for outputting data to the pager board. The data may be
transmitted
via the pager board and a pager system to a remote host computer. A compact,
efficient
differential compression method is provided in the interface board to reduce
the airtime
duration and cost of transmission of data via the pager system to the host
computer.


Claims

Note: Claims are shown in the official language in which they were submitted.


Claims:
1. An interface board for connecting an electrical power usage meter to a
pager
board capable of transmitting data to a remote host computer, the interface
board
comprising:
an input port for connection to the meter for periodically reading load
profile data from
the meter; and
an output port for connection to the pager board for outputting load profile
data to the
pager board,
whereby the load profile data may be transmitted via the pager board and a
pager system
to a remote host computer.
2. An interface board for connecting an electrical power usage meter to a
pager
board capable of transmitting data to a remote host computer, the interface
board
comprising:
an input port for connection to the meter for periodically reading load
profile data from
the meter;
a data processor for compressing the load profile data read from the meter;
and
an output port for connection to the pager board for outputting compressed
load profile
data to the pager board,
whereby the compressed load profile data may be transmitted via the pager
board and a
pager system to a remote host computer.
212

3. The interface board of claim 2, wherein:
the load profile data is read serially from the meter; and
the load profile data is compressed by a differential compression process in
which each
load profile datum is represented in the compressed load profile data by the
difference
between it and the preceding load profile datum if that difference can be
represented by a
selected number of bits that is less than the number of bits needed to
represent the largest
possible load profile datum and is represented in the compressed load profile
data
uncompressed if that difference cannot be so represented.
4. The interface board of claim 3, wherein a bit pattern that would otherwise
be a
possible representation of a difference is excluded from use as a
representation of a
difference and used to indicate the end of a sequence of differences.
5. A computer method for compressing load profile data for transmission from
an
electrical power usage meter via a pager system to a remote host computer, the
method
comprising:
reading the load profile data serially from the meter; and
compressing the load profile data by a differential compression process in
which each
load profile datum is represented in the compressed load profile data by the
difference
between it and the preceding load profile datum if that difference can be
represented by a
selected number of bits that is less than the number of bits needed to
represent the largest
possible load profile datum and is represented in the compressed load profile
data
uncompressed if that difference cannot be so represented.
213

6. The method of claim 5, wherein a bit pattern that would otherwise be a
possible
representation of a difference is excluded from use as a representation of a
difference and
used to indicate the end of a sequence of differences.
7. An interface board for installation within the housing of an electrical
power usage
meter, the interface board comprising:
an input port for connection to the meter for reading data from the meter
indicative of the
quality of the power passing through the meter;
a data processor for processing the data read from the meter to determine
whether a
power quality event has occurred; and
an output port for transmitting notification that a power quality event has
occurred to a
remote location.
8. The interface board of claim 7, wherein the data read from the meter
includes
average voltages supplied to the meter.
9. The interface board of claim 8, wherein the data read from the meter
includes
samples of the voltage supplied to the meter.
10. A method for monitoring quality power passing through an electrical power
usage
meter comprising:
reading data from the meter indicative of the quality of the power passing
through the
meter;
processing the data read from the meter to determine whether a power quality
event has
occurred; and
214

transmitting notification that a power quality event has occurred to a remote
location.
215

Description

Note: Descriptions are shown in the official language in which they were submitted.


CA 02332297 2001-O1-25
Wireless Electronic Energy Meter
A portion of this disclosure of this patent document contains material that is
subject to copyright protection. The copyright owner has no objection to the
reproduction of the patent document or disclosure as it appears in the Patent
and
Trademark Office files or records, but otherwise reserves all copyright rights
whatsoever.
Field of the Invention
The present invention relates generally to electronic energy meters, and more
particularly to programmable wireless electronic meters.
Background of the Invention
Conventional commercial and industrial electronic meters, such as the meter
described in United States Patent 6,112,159 ("the Siemens S4"), the meter
described in
United States Patent 6,081,204, and the meter described in United States
Patent No.
6,094,622, are primarily designed for reading via an optical port. Although
collection of
meter data by wired and wireless networks has been proposed and such meters
generally
include ports for connectors other than the optical port that could be used by
automated
meter reading ("AMR") systems, the widespread development of AMR systems has
been
uneconomic due to either high equipment costs or significant usage costs when
compared
to the generally low value of meter readings. The telephone system and wide
area
networks, such as pager systems, are examples of public wired and wireless
networks.
The use of such networks for data collection from meters has generally been
uneconomic
unless the data is of high value.
There is therefore a need for a lower-cost method for collecting meter
readings
over wireless wide-area networks, such as pager networks.

CA 02332297 2001-O1-25
Summary of the Invention
In one aspect of the invention, an interface board is provided for connecting
an
electrical power usage meter to a pager board capable of transmitting data to
a remote
host computer. The interface board includes an input port for connection to
the meter for
periodically reading load profile data from the meter; and an output port for
connection to
the pager board for outputting load profile data to the pager board. The load
profile data
may be transmitted via the pager board and a pager system to a remote host
computer. A
compact, efficient differential compression method is provided in the
interface board to
reduce the airtime cost of transmission of load profile data. A battery
charging and power
supply system is also provided in which power for transmissions is built up
between
transmissions so that the power drawn from the meter is reduced.
In another aspect of the invention, an electronic meter is provided with an
output
port for outputting load profile data to a pager board capable of transmitting
data to a
remote host computer. A compact, efficient differential compression method is
provided
to reduce the airtime cost of transmission of load profile data.
Brief Description of the Drawings
Figure I is a block diagram showing the functional components of an exemplary
electronic energy meter reading system, including the components within the
meter
enclosure, a pager system, and a host computer.
Figure 2 is a block diagram showing the functional components of an exemplary
interface
board for use in an electronic energy meter system such as that shown in
Figure 1.
Figure 3 is a block diagram showing the functional components of an exemplary
electronic energy meter reading system including an electronic energy meter
for use with
a pager board, a page pager board, a page system, and a host computer.
2

CA 02332297 2001-O1-25
Figure 4 is a flowchart showing a simplified differential compression process
for use in
transmission of load profile data by the systems shown in Figures 1 and 3.
Figure 5 is a flowchart showing an improvement to the simplified differential
compression process shown in Figure 4
Figure 6 is a flowchart showing a preferred differential compression process.
Figure 7 is a block diagram showing the functional components of an exemplary
electronic energy meter system located within the meter enclosure, with the
exception of
the power supply/charger board.
Figure 8 is a block diagram showing the functional components of an exemplary
power
supply/charger board for use with the system of Figure 7.
Figure 9 is a detailed schematic circuit diagram of the interface board of
Figures 1 and 2.
Figure I O is a detailed schematic circuit diagram of the microprocessor
(marked as
"CPU") section of the interface board of Figure 9.
Figure I 1 is a detailed schematic circuit diagram of the chip select-decoding
(marked as
"CS-Decode") section of the CPU portion of Figure 10.
Figure 12 is a detailed schematic circuit diagram of the memory array (marked
as
"Memory-Array Memory - Sheet 4") portion of the CPU section of Figure 10.
Figure I 3 is a detailed schematic circuit diagram of the serial EEPROM and
real-time
clock (marked as "RTC and Serial EEProm") portion of the CPU section of Figure
10.

CA 02332297 2001-O1-25
Figure 14 is a detailed schematic circuit diagram of the regulators (marked as
"Regulators
Pager and Vcc") portion of Figure 9.
Figure 1 S is a detailed schematic circuit diagram of the temperature sensing
and analog
control (marked as "Temp Sensor Temp-Sense") portion of Figure 9.
Figure 16 is a detailed schematic circuit diagram of the LED options (marked
as "Option-
LEDs") portion of Figure 9.
Figures 17 and 18 together are a detailed schematic circuit diagram of the
power
supply/charger board of Figure 1.
Detailed Description of Invention
One preferred embodiment of the invention is an interface board that may be
used
to convert a conventional electronic commercial and industrial meter such as a
Siemens
S4 meter to wireless operation. Meters such as the Siemens S4 comprise an
enclosure,
the front and sides of which are a glass cover, a base to which the glass
cover is attached,
and a meter board that includes an analog to digital converter, a digital
signal processor, a
micro-controller, and a power supply. For examples of such meters, see Figures
1 of
United States Patent Nos. 6,094,622 and 6,081,204. The meter board also
contains at
least one functional component, generally an optical port, for communication
with the
outside world, and may include other ports or connectors. The Siemens S4
meter, for
example, provides a serial port in addition to the optical port from which the
inventors
realized that it is possible to extract the same information that is available
from the
optical port.
While the exemplary interface board to be described below has been designed
for
use with a meter, such as the Siemens S4, that has a serial port that provides
the same
data as the optical port, it is within the ability of those skilled in the art
to modify the
4

CA 02332297 2001-O1-25
design of the interface board so that it may be connected directly into the
circuitry of the
meter board, such as to a bus to which a digital signal processor or a micro-
controller is
connected, so that the interface board may obtain data without use of a low
speed serial
port. For example, the interface board may be modified so that it can be
connected to the
option connector 38 shown in Figure 1 of United States Patent No. 6,094,622.
For the purpose of the following description, the meter board may be treated
as a
black box which, when sent the appropriate commands via its serial port
provides the
same electrical usage data that it provides to the optical port when
interrogated with an
optical probe.
Hardware
Figure 1 shows, in an overall block diagram, a meter reading system 10 that
includes a meter board 12 having an optical port 14 and a serial input/output
port 16, an
interface board 18 having a first serial port 20 connected to the serial
input/output port 16
of the meter board 12 and a second serial input/output port 22, a fixed two-
way wireless
pager board 24 connected to the second serial input/output port 22, a pager
system 26
such as the SkyTel System, and a remote host computer 28. Generally, the
interface board
18 obtains electrical usage data from the meter board 12 and packages it in an
appropriate
form for transmission to a remote host computer 28 via the pager board 24 and
the pager
system 26. To reduce airtime cost the interface board 14 compresses the
electrical usage
data using a differential compression method to be described below. The
interface board
18 also provides a capability for monitoring power quality that may be turned
on and off
from the remote host computer 28. If power quality monitoring is turned on,
the interface
board 18 obtains data including average phase voltages and angles from the
meter board
12 using commands sent to the meter serial input/output port 16 and notifies
the remote
host computer 28 whenever certain criteria indicating a change in power
quality to be
described below are met.

CA 02332297 2001-O1-25
In an exemplary embodiment described here, the pager board 24 is a Motorola 2-
Way ReFlex SOTM Pager Board and the meter board 12 is an unmodified meter
board of a
Siemens S4 meter. The interface board 18 is installed together with the meter
board 12
and the pager board 24 in a Siemens S4 meter enclosure (not shown). The
interface board
18 is designed to fit inside the S4 meter enclosure with the meter board 12,
the pager
board 24, and a power supply and battery charger board 30 so that the
resulting
combination is entirely within the enclosure of the unmodified Siemens S4
meter
enclosure. In Figure 1, the boundary of the enclosure of the Siemens S4 meter
is
indicated by dashed line 11.
The interface board 18 is built on a conventional printed circuit board
designed to
fit within the S4 meter enclosure from hardware components that are
commercially
available. A block diagram of the interface board 18 is shown in Figure 2. The
interface
board 18 includes a Microchip PIC 17C756-16/IL microprocessor 32, which
provides the
first serial input/output port 20 for connection to the meter serial
input/output port 16 and
the second serial input/output port 22 for connection to the pager board 24.
Also
connected to the microprocessor 32 by an Inter-Integrated Circuit ("I'C") bus
34 are a
real time clock 36 and a serial electrically-erasable read-only memory
("EEPROM") 40.
The microprocessor 32 also contains internal EEPROM (not shown) and is
provided with
external RAM and flash memory, indicated in Figure 2 by reference numeral 38.
The
necessary address decoding circuitry (not shown) to allow the microprocessor
32 to
access the external RAM and flash memory 38 is provided on the interface board
18.
Instructions for execution by the microprocessor 32 are stored mainly in the
flash
memory portion of the external RAM and flash memory 38, except for test
software, boot
loader software, and reset algorithms, which are stored in the internal EEPROM
within
the microprocessor 32. Programmable and configurable parameters are stored in
the
EEPROM 40.
6

CA 02332297 2001-O1-25
The interface board 18 has two major functions. The first is to obtain load
profile
data periodically from the meter board 12 and transmit that data to a host
computer 28 via
the pager board 24 and the pager network 26. The second major function of the
interface
board 18 is to monitor power quality data available from the meter board 12.
The meter
board 12 provides the three phase voltages and phase angles of the current
passing
through the mete. The host computer 28 is notified whenever a reportable power
quality
event as defined below occurs. A primary characteristic of power quality
events is that
they cannot be reported at scheduled times as can load profiles. Hence other
non-
scheduled alarm conditions that the interface board 18 may be configured to
monitor,
such as demand threshold reporting, are described below together with power
quality
event reporting.
The power supply/charger board 30 is needed to use the interface board 18 in
an
S4 meter application because the power supply available from the S4 meter
board 12 does
not have sufficient capacity to power the interface board 18 and the pager
board 24 during
a transmission. In particular, the pager board 24 requires a large amount of
electrical
power when it is transmitting. For example, every one second of transmission
by the
pager board 24 requires approximately 30 seconds of charging assuming that 50
mA of
charging current is available from the meter board 12. Also, because the S4
meter is
powered from phase C of the current being metered, for the interface board 18
is to
continue operating (e.g., providing power outage and restoration notification)
during a
power failure, it is necessary for the interface board 18 to have backup
battery power.
Under normal operating condition (power being provided by the S4 meter), the
power
supply/charger board 30 recharges a 1.3 A-hr capacity gel lead acid battery
(not shown in
Figure 1 ) between transmissions by the pager board 24. By doing so, the
amount of
power drawn from the S4 meter is kept within the amount that can be drawn from
the S4
meter. In effect the power supply/charger board 30 levels out the rate of
power
consumption by the pager board 24.
7

CA 02332297 2001-O1-25
The power supply/charger board 30 is also controlled by the interface board 18
so
as to curtail drawing power from the S4 meter as the available power on phase
C drops
off during a power failure so that the meter board 12 has power long enough to
store its
own data.
The battery is also managed by the interface board 18. The system (the
combination of the interface board 18, the power supply/charger board 30, and
the pager
board 24 is referred to herein as "the interface system 13") into either a
sleep mode or a
kill power mode if phase C power fails. Which mode is chosen can be preset via
the
pager system 26. In the sleep mode, then the battery will last for
approximately 6 days.
If the kill power mode is chosen, then power usage is cut to a minimum,
providing
approximately 30 days of battery life. The kill power mode would be chosen by
a utility
if it appeared that a major disaster, such as a hurricane, was about to occur.
In either
mode, the interface system 13 will return to normal operation when power is
restored to
phase C and will then send a power restoration notification to the utility via
the pager
system 26.
The primary difference between the sleep and kill power modes is that if the
interface system 13 is in kill power mode, then the interface system 13 cannot
be
contacted via the pager system 26 until phase C power is restored, whereas in
sleep mode
the interface system 13 is able to receive messages via the pager system 26.
The kill
power mode is also useful in that S4 meters with the interface system 13
installed may be
kept in the kill power mode until ready for field installation for
approximately 30 days
without disconnecting the battery. Disconnecting the battery requires removal
of the
meter cover, which is best only done in a clean facility, not in the field.
For shelf storage
over 30 days, however, it is necessary to disconnect the battery as even in
the kill power
mode, the interface system 13 is drawing some power. A battery connector is
included
that has a "park" position that disconnects the battery completely, thereby
allow long
term storage of the meter with interface system 13 installed and configured.
8

CA 02332297 2001-O1-25
Figures 7 and 8 show a somewhat more detailed view of the interface board 18
and the power supply/charger board 30.
Figures 9 - 16 provide a detailed schematic circuit diagram of the currently
preferred embodiment of the interface board 18. The components shown in
Figures 9 -
16 are listed in Appendix B. Similarly, Figures 17 and 18 together provide a
detailed
schematic circuit diagram of the power supply/charger board 30. The components
shown
in Figures 17 and 18 are listed in Appendix C. Those skilled in the art of
electronic
design will understand that these Figures are only one of many alternative
ways in which
the interface board 18 and power supply/charger board 30 may be constructed.
Alternative Hardware Embodiment
The interface board 18 and power supply/charger board 30 are useful for
retrofitting existing Siemens S4 meters and other electronic meters that
provide or can be
adapted to provide load profile, phase voltage, and phase angle data, but
which do not
have sufficient electrical power or computational power to drive a pager board
24
directly. The power quality monitoring aspect of the interface board 18
disclosed below
may also be implemented in existing electronic meters in which a programmable
microprocessor has access to digitized phase voltage measurements and phase
angles.
Further, the wireless aspect of the interface board 18 may be implemented in
an existing
electronic meter provided that the meter has a suitable serial port or
provided that a
suitable serial port can be added for connection to a two-way pager board.
Both aspects of the interface board 18 may be added in a new meter board
design.
Figure 3, a modified version of Figure 1 of U.S. Patent No. 5,924,051, shows a
possible
meter board in block diagram form. In Figure 3, a serial interface component
50 such as
a UART replaces the line carrier network interface 48 of Figure 1 of U.S.
Patent No.
5,924,051. In Figure 3, the power supply 42, power connections 44, and battery
47 of
Figure 1 of U.S. Patent No. 5,924,051 are not shown. The specification of U.S.
Patent

CA 02332297 2001-O1-25
No. 5,924,051 is hereby incorporated by reference. Reference numeral 52 in
Figure 3
indicates the modified meter board. Reference numeral 54 indicates the
boundary of a
meter enclosure for containing the meter board 52 and a pager board 24.
As suggested above, existing meter boards may have to be redesigned in order
to
provide the necessary electrical power and computational power needed to send
load
profile and power quality data via a pager system. However, such redesign
should be
straightforward if the principles disclosed herein with respect to the
interface board 18
and power supply/charger board 30 are applied.
Load Profile Reporting
A basic function of the interface board 18 is to provide daily load profiles
to the
host computer 28 for billing purposes. The readings taken for this purpose are
scheduled.
15 In order to reduce the cost of airtime, load profile data is compressed in
the manner
described below before being sent.
Raw load profile data is read from meter serial port 16 via interface serial
port 20
and stored in an input buffer by the microprocessor 32. The raw data is a
series of 16-bit
20 words, each of which may be either a data value providing the power
consumption for a
defined interval (typically 15 minutes) or a time/date stamp. If the high
order bit of a raw
data word is a l, then the word is a time/date stamp. The second highest order
bit is a
parity bit, leaving 14 data bits for a load profile data value. Hence load
profile data
values can be in the range 0 to 16383.
In general, the differential compression method used compresses the data
values
by, where possible, transmitting only differences between successive data
values, so long
as the differences can be represented by an 8-bit byte. Note that in the
following
discussion a twos-complement representation of negative numbers is used.
10

CA 02332297 2001-O1-25
In a simple form of differential compression, compression may turned on and
off
as the stream of raw data words are read from the input buffer by examining
the data
value of the current word to determine whether the difference between it and
the data
value of the last data word read can be represented by a single byte. A
special byte value
may be sent to indicate that compression is on for succeeding bytes until
turned off. If
compression is on, then to indicate that compression will be off for
successive data, a
special byte value is used. This means that a difference value can have only
one of 255
possible values (0x00 to OxFF provides 256 possible differences, less one
value for the
compression-off special byte value), say -127 to +127, using -128 as the
special byte
value. When uncompressed values are being sent and a value is encountered that
could
be sent as a difference from the last value, then a special byte such as OxFF
may be sent
as the high byte of the word to indicate that compression is to be on and the
low byte
should be treated as a difference value. Note that the special byte value
indicating that
compression is on for succeeding bytes may be the same as the byte value sent
while
compression is on that a particular difference value. Hence OxFF when
compression is on
means a difference of negative 1, whereas when compression is off, OxFF means
that the
next byte is a difference value and that compression is on for succeeding
bytes.
The simple differential compression scheme described above may be improved by
looking ahead in the input buffer before turning compression off to determine
whether the
next data word read could be compressed if the current word were sent
uncompressed.
For example, if compression is on and a data word having a value of 300 is
read and the
previous data work had a value of 100, then the difference of +200 would be
too large to
represent in one byte and under the simple scheme described above, a special
byte value
of -128 would be sent to turn compression off, followed by the value 300 as a
two-byte
word. However, suppose the value of the next data word following 300 is 301.
In that
case, the simple scheme would send a byte value OxFF to indicate compression
is on and
then +1 as a byte value. The total cost in bytes to send the two readings
would be five
bytes. If the byte value of the next word were scanned before sending the
compression-
off byte value, then a second special value indicating that compression is off
only for the
11

CA 02332297 2001-O1-25
next word could be sent instead of the compression-off byte value. The byte
cost would
then be reduced by one as the 301 value could be sent as a difference without
prefacing it
by the compression-on byte.
The differential compression scheme may be further improved upon for handling
data that varies slowly over a range that is somewhat larger than can be
handled with
difference encoded in single bytes. To do so, further special bytes are sent
while
compression is on to indicate that the magnitude of the difference byte should
be
increased. For example, if the difference value is only slightly outside the
range of
possible differences, say +130, then a special byte value may be sent before a
difference
value of +5, indicating that 125 is to be added to the value 5 and the sign of
the difference
is +. It should be noted that this scheme reduces the number of difference
values that can
be sent in a byte as some of the possible values are taken as special values.
In the
preferred scheme illustrated in Figure 6, the special byte values 126, 127,
and 128
indicate adding 125, 252, and 379 to the next byte, respectively. The special
byte values
-127 turns compression off and the special byte value -126 indicates that
compression is
to be on, except for the next two bytes, which are to be taken as a 16-bit
word.
Flowcharts describing the simple, improved, and a preferred compression
processes in more detail are shown in Figures 4, 5, and 5, respectively. The
following
variables are used:
InBuff input buffer
OutBuff output buffer
q InBuff pointer (initialized to 0)
Q total number of bytes in InBuff
r OutBuff pointer (initialized to 0)
cMode compression mode flag, a value of 1 means compression is "on" and 0
means compression is "off' (initialized to 0)
Word current word read from InBuff
12

CA 02332297 2001-O1-25
nextWord the word after the current word in InBuff
oldV previous value of Word (initialized to 0)
Base either oldV (if Word is a date/time stamp) or Word (if Word is not a
date/time stamp)
dV (Word - oldV)
dVsign sign of dV
dateStamp flag indicating that the current Word is a date/time stamp
The simplified compression process described in Figure 4 begins with
initialization of the variables as discussed above (block 110). The first word
in the input
buffer InBuff is then read (block 112) and its high order bit tested (block
114). If the
high order bit is 1, the word is a date/time stamp, so the dateStamp flag is
set (block 116).
Otherwise, the word is taken to be one measurement of load profile data, which
includes
a 14-bit data value preceded by a parity bit. Hence the parity bit must
stripped off by
AND-ing the word with Ox3FFF (block 118). In block 120, a difference value dV
is
determined by subtracting the previous value of the word oldV from the word
just read
and the sign dVsign of the difference value dV is determined. As the previous
value was
initialized to zero, the first difference value will be equal to the first
word read that is not
a date/time stamp.
The process then continues by checking (block 122) to determine whether
compression is on. If compression is not on, the absolute value of dV and the
dateStamp
flag are checked (block 124) to determine whether the absolute value of dV is
greater
than 125 or if the dateStamp flag is set. If neither is true, then Word must
be a data value
that differs from its previous value by less than 126 and the operations of
block 126 are
performed, namely, a word having OxFF as the high order byte and dV as the low
order
byte is written to the output buffer, the high order byte signifying that
compression is on
and the low order byte representing the first difference value, and the flag
cMode
indicating whether compression is on or off is set to value 1. The output
buffer pointer is
then incremented (block 128) by 2. If compression is not on and the absolute
value of the
13

CA 02332297 2001-O1-25
dV is greater than 126 or dateStamp flag is set, then Word is written (block
130) to the
output buffer and the output buffer pointer r is incremented 128 by 2.
In the exemplary process shown in Figure 4, difference values may range from -
125 to +125, the special byte value -127 (0x81 in hexadecimal) being reserved
to act as a
flag that compression is to be off for successive transmissions. This scheme
only uses
252 (251 difference values, including 0, plus one flag) of the 256 possible
values that
could be represented in one 8-bit byte in order to be consistent with the
choice of special
bytes used in the schemes presented in Figures 5 and 6. Clearly, the
difference values in
the range -127 to +127 could be represented if only one byte (say 128) is used
as a flag.
On the other hand, if compression was on at the decision point indicated by
block
122, then the absolute value of dV and the dateStamp flag are checked (block
132) to
determine whether the absolute value of dV is greater than 125 or if the
dateStamp flag is
set. If neither is true, then Word must differ from its previous value by less
than 126 and
compression may remain on. In that case, the operations of block 134 are
performed,
namely, difference value dV is written to the output buffer and the output
buffer pointer r
is incremented by 1. If either the absolute value of dV is greater than 125 or
the
dateStamp flag is set, then compression will have to be turned off as in the
scheme shown
in Figure 4 cannot handle difference values greater than 125 or two-byte
time/date
stamps. In that case, the operations of block 136 are performed, namely,
special byte
0x81 (decimal 128) is written to the output buffer and the compression flag
cMode is
cleared (set to value 0) and the operations of block 138 are performed,
namely, the
current Word, which must be either a data value with the parity bit stripped
off or a
date/time stamp, is written to the output buffer and the output buffer pointer
r is
incremented by 3 (one position for the special byte and two for the current
Word.
After the output buffer pointer r is incremented in each of the situations
above, the
operations of block 140 are performed, namely, if the current Word is not a
date/time
14

CA 02332297 2001-O1-25
stamp, then the variable oldV holding the previous value of the current Word
is set to the
value of the current Word and the input buffer point q is incremented by 2.
The input buffer point q is then tested (block 142) against the total number
of
bytes Q in the input buffer to determine whether the input buffer has been
completely
read. If it has the process is complete. If not, another word is read (block
112) and
processed as above until at block 142 it is determined that the input buffer
has been
completely read.
The process described above in relation to Figure 4 has two weaknesses that
reduce its usefulness in the compression of load profile data in the interface
board 18.
The first, and most serious problem, is that it can be fooled into sending
more data than
would be sent if compression were not used at all. For example, suppose a
sequence of
load profile readings differed from each other by differences that alternated
between
values less than 126 and greater than 126. Compression would be turned
alternately on
and off repeatedly until the sequence ended. Each time compression is turned
off an extra
byte is used so that for every pair of data values in the sequence, five bytes
are sent,
rather than the four bytes that would be sent if the compression were never
used. In fact
even an isolated large difference preceded and followed by a series of small
differences
cause one extra byte to be sent.
Figure 5 illustrates an improvement to the process described above in relation
to
Figure 4 that handles the first weakness in that process by scanning ahead in
the input
buffer to determine whether anything can be gained by delaying going in or out
of
compression. For example, if compression is already on and the current Word in
the
input buffer represents a large difference from the previous Word value, but
the next
Word value in the input buffer represents a small difference from the current
Word, then
using a byte to turn compression off and then a byte to turn it on again means
that five
bytes have been sent to represent two two-byte data words. If on the other
hand a special
byte (0x82 in Figure 5) is sent to indicate that compression is only to off
for the current

CA 02332297 2001-O1-25
Word, then the total number of bytes needed is four. Similarly, if compression
is off and
the current Word in the input buffer represents a small difference from the
previous Word
value, compression may be left off if the next Word value in the buffer
represents a large
change from the current Word value. In either case, the compressed result can
be no
longer than no compression at all and will be shorter if the input buffer
contains
sequences of Word values that differ by small differences. In this discussion,
"small
differences" means differences of less than 126 in absolute value.
The improved compression process described in Figure 5 begins with
initialization of the variables as discussed above (block 210). The first word
in the input
buffer InBuff is then read (block 212) and its high order bit tested (block
214). If the
high order bit is 1, the word is a date/time stamp, so the dateStamp flag is
set (block 216).
Otherwise, the word is taken to be one measurement of load profile data, which
includes
a 14-bit data value preceded by a parity bit. Hence the parity bit must
stripped off by
AND-ing the word with Ox3FFF as indicated in block 218. As indicated by block
220, a
difference value dV is then determined by subtracting the previous value of
the Word
oldV from the word just read and the sign dVsign of the difference value dV
determined.
As the previous value was initialized to zero, the first difference value will
be equal to the
first word read that is not a date/time stamp.
The process then continues by checking (block 222) to determine whether
compression is on. If compression is not on, then the absolute value of dV and
the
dateStamp flag are checked (block 224) to determine whether the absolute value
of dV is
greater than 125 or if the dateStamp flag is set. If either is true, then the
current Word is
written (block 230) to the output buffer and the output buffer pointer r is
incremented by
2 (block 228).
If compression is not on and the absolute value of dV is not greater than 125
and
the dateStamp flag is not set, then the next word in the input buffer is read
(block 246)
into nextWord and checked (block 248) to determine if it is a date/time stamp.
If
16

CA 02332297 2001-O1-25
nextWord is a date/time stamp, then the current Word, which is a data value,
is written
(block 230) to the output buffer and the output buffer pointer r is
incremented by 2 (block
228). If nextWord is not a date/time stamp, then the parity bit is stripped
off (block 250)
and the absolute value of the difference between nextWord and the current Word
checked
(block 258). If the absolute value of that difference is less than 126, then
the operations
of block 226 are performed, namely, a word having OxFF as the high order byte
and dV
as the low order byte is written to the output buffer, the high order byte
signifying that
compression is on and the low order byte representing the first difference
value, and the
flag cMode is set to value 1 indicating that compression is on. The output
buffer pointer r
is then incremented by 2 (block 228). On the other hand, if the absolute value
of the
difference checked at block 258 is not less than 126, then the current Word,
which is a
data value, is written (block 230) to the output buffer and the output buffer
pointer r is
incremented by 2 (block 228).
On the other hand, if compression was on at the decision point indicated by
block
222, then the absolute value of dV and the dateStamp flag are checked (block
232) to
determine whether the absolute value of dV is greater than 125 or if the
dateStamp flag is
set. If neither is true, then Word must differ from its previous value by less
than 126 and
compression may remain on. In that case, the operations indicated in block 234
are
performed, namely, difference value dV is written to the output buffer and the
output
buffer pointer r is incremented by 1.
If either the absolute value of dV is greater than 125 or the dateStamp flag
is set,
then the next word in the input buffer is read (block 260) into nextWord and
nextWord is
checked (block 262) to determine if it is a date/time stamp. If nextWord is a
date/time
stamp, then the operations indicated in block 236 are performed, namely,
special byte
0x81 (decimal 128) is written to the output buffer and the compression flag
cMode is
cleared (set to value 0). Then the operations indicated in block 238 are
performed,
namely, the current Word, which must be either a data value with the parity
bit stripped
17

CA 02332297 2001-O1-25
off or a date/time stamp, is written to the output buffer and the output
buffer pointer r is
incremented by 3 (one position for the special byte and two for the current
Word).
If nextWord is not a date/time stamp, then the parity bit is stripped off
(block
264). If the current word is a date/time stamp, then nextWord should be
compared to the
last data value of Word, oldV. Otherwise, nextWord should be compared to the
current
value of Word. To do this the current value of the dateStamp flag is checked
(block 266)
and the variable Base is set to the value of oldV if dateStamp is set (block
268) or to the
value of Word if dateStamp is not set (block 270). Then the absolute value of
the
difference between nextWord and Base may be checked (block 272). If the
absolute
value of the difference is less than 126, then special byte 0x82 (decimal -
126) is written
(block 274) to the output buffer and operations indicated in block 238 are
performed,
namely, the current Word, which must be either a data value with the parity
bit stripped
off or a date/time stamp, is written to the output buffer and the output
buffer pointer r is
incremented by 3 (one position for the special byte and two for the current
Word.
On the other hand, if the absolute value of the difference checked at block
272 is
not less than 126, then the operations indicated in block 236 are performed,
namely,
special byte 0x81 (decimal -127) is written to the output buffer and the
compression flag
cMode is cleared (set to value 0). The operations indicated in block 238 are
performed,
namely, the current Word, which must be either a data value with the parity
bit stripped
off or a date/time stamp, is written to the output buffer and the output
buffer pointer r is
incremented by 3 (one position for the special byte and two for the current
Word).
After the output buffer pointer r is incremented in each of the situations
above, the
operations indicated in block 240 are performed, namely, if the current Word
is not a
date/time stamp, then the variable oldV holding the previous value of the
current Word is
set to the value of the current Word and the input buffer point q is
incremented by 2.
18

CA 02332297 2001-O1-25
The input buffer point q is then tested (block 242) against the total number
of
bytes Q in the input buffer to determine whether the input buffer has been
completely
read. If it has the process is complete. If not, another word is read (block
212) and
processed as above until at block 242 it is determined that the input buffer
has been
completely read.
The compression process illustrated in Figure 5 can be improved further by the
use range-expansion byte values 126, 127, and -128 to indicate that the next
difference
value is to be increased in absolute value by 125, 252, or 379, respectively.
If that
improvement is added, then the scan-ahead improvement discussed above in
relation to
Figure ~ should be expanded to scanning ahead past any Words that could be
represented
by one of the range-expansion byte values 126, 127, or -128 and a difference
value to the
first Word in the rest of input buffer that is either a data value that can be
represented as a
single-byte difference without a range-expansion byte, a data value that
cannot be
represented as a single-byte difference even with a range-expansion byte, or a
time/date
stamp. In effect, since data values represented by a range-expansion byte and
a difference
byte require a two-byte word to transmit, they should be ignored for the
purpose of
scanning ahead. If the expansion of the scan-ahead process is not added, then
under some
circumstances an extra byte is used because compression may be started and
stopped
without actually sending a data value as a single byte. For example, a large
difference
might be followed by several differences that can be represented by a range-
expansion
byte with a difference byte (a "medium difference"), another large difference,
and finally
a medium difference. Going into compression and then out again, as would occur
if the
process described in relation to Figure 5 were used, would take one extra byte
beyond not
using compression at all.
Figure 6 illustrates a preferred compression scheme incorporating by the range-
expansion bytes and the expanded scanning-ahead improvements. It begins with
initialization of the variables as discussed above (block 310). The first word
in the input
buffer InBuff is then read (block 312) and its high order bit tested (block
314). If the
19

CA 02332297 2001-O1-25
high order bit is 1, the word is a date/time stamp, so the dateStamp flag is
set (block 316).
Otherwise, the word is taken to be one measurement of load profile data, which
includes
a 14-bit data value preceded by a parity bit. Hence the parity bit must
stripped off by
AND-ing the word with Ox3FFF as indicated in block 318. As indicated in block
320, a
difference value dV is then determined by subtracting the previous value of
the Word
oldV from the word just read and the sign dVsign of the difference value dV
determined.
As the previous value was initialized to zero, the first difference value will
be equal to the
first word read that is not a date/time stamp.
The process then continues by checking (block 322) to determine whether
compression is on. If compression is not on, then the absolute value of dV is
checked
(block 324) to determine whether the absolute value of dV is less than 126. If
it is not,
then the current Word is written (block 330) to the output buffer and the
output buffer
pointer r is incremented by 2 (block 328).
If compression is not on and the absolute value of dV is less than 126, then
the
operations indicated in block 376 are performed, namely, an index m is
initialized to 0,
and nextWord(m) is initialized to the previous value of Word, if the current
Word is a
time/date stamp, or to the current value of Word, if Word is a data value, and
an index k
to the input buffer is initialized to point to the first byte of next Word
following the
current Word in the input buffer.
Following the initialization (block 376), a loop is run in which the
operations
indicated in block 378 are performed, namely, m is incremented by 1, nextWord
(m) is
set to the next word in the input buffer InBuff(k+l,k), and then k is
increment by 2. The
high order bit of nextWord(m) is then tested (block 380) to determine if
nextWord(m) is a
time/date stamp. If it is, then the current Word is written (block 330) to the
output buffer
and the output buffer pointer r is incremented by 2 (block 328). If it is not,
then
nextWord(m) must be a data value, so the parity bit is stripped-off (block
382) and the
absolute value of the difference between nextWord(m) and nextWord(m-1) is
checked

CA 02332297 2001-O1-25
(block 384) to determine if it is greater than the largest difference that can
be represented
with the range-expansion bytes (506). If it is, then the current Word is
written (block
330) to the output buffer and the output buffer pointer r is incremented by 2
(block 328).
If it is not, a further check (block 386) is made to determine whether the
absolute value of
the difference is less than 126. If it is, then the operations indicated in
block 326 are
performed, namely, a word having OxFF as the high order byte and dV as the low
order
byte is written to the output buffer, the high order byte signifying that
compression is on
and the low order byte representing the first difference value, and the flag
cMode is set to
value 1 indicating that compression is on. The output buffer pointer r is then
incremented
by 2 (block 328). On the other hand, if the absolute value of the difference
checked at
block 386 is not less than 126, then by testing (block 388) the index k
control loops back
to the operations indicated by block 378 if all of the words in the input
buffer have not
already been tested or otherwise the current Word is written (block 330) to
the output
buffer and the output buffer pointer r is incremented by 2 (block 328).
On the other hand, if compression was on at the decision point indicated by
block
322, then the absolute value of dV and the dateStamp flag are checked (block
332) to
determine whether the absolute value of dV is greater than 506 or if the
dateStamp flag is
set. If neither is true, then the absolute value of dV is tested (block 390)
to determine if it
is less than 126. If it is, then difference value dV is written (block 392) to
the output
buffer and the output buffer pointer r is incremented by 1 (block 394).
If absolute value of dV is tested 390 to be not less than 126, then absolute
value of
dV is tested (block 396) to determine if it is less than 253. If it is, then a
word having as
a high order byte the value Ox7E and as a low order byte a value having an
absolute value
of dV less 125 and the same sign as dV is written (block 398) to the output
buffer and the
output buffer pointer r incremented by 2 (block 406).
If absolute value of dV as tested at block 396 is not less than 253, then it
is further
tested at block 400 to determine if it is less than 380. If it is less than
380, then a word
21

CA 02332297 2001-O1-25
having as a high order byte the value Ox7F and as a low order byte a value
having an
absolute value of dV less 252 and the same sign as dV is written (block 402)
to the output
buffer and the output buffer pointer r incremented by 2 (block 406). If it is
not less than
380, then a word having as a high order byte the value 0x80 and as a low order
byte a
value having an absolute value of dV less 379 and the same sign as dV is
written (block
404) to the output buffer and the output buffer pointer r incremented by 2
(block 406).
If compression the absolute value of dV was greater than 506 or if the
dateStamp
flag was on at the decision point indicated by block 332, then the operations
indicated by
block 408 are performed, namely, an index m is initialized to 0, and
nextWord(m) is
initialized to the previous value of Word, if the current Word is a time/date
stamp, or to
the current value of Word, if Word is a data value, and an index k to the
input buffer is
initialized to point to the first byte of next Word following the current Word
in the input
buffer.
Following the initialization block 408, a loop is run in which the operations
indicated by block 410 are performed, namely, m is incremented by 1, nextWord
(m) is
set to the next word in the input buffer InBuff(k+l,k), and then k is
increment by 2. The
high order bit of nextWord(m) is then tested (block 412) to determine if
nextWord(m) is a
time/date stamp. If it is, then the current Word is written (block 336) to the
output buffer
and the output buffer pointer r is incremented by 2 (block 338). If it is not,
then
nextWord(m) must be a data value, so the parity bit is stripped-off (block
414) and the
absolute value of the difference between nextWord(m) and nextWord(m-1 ) is
checked
(block 416) to determine if it is greater than 506, the largest difference
that can be
represented with the range-expansion bytes. If it is, then the current Word is
written
(block 336) to the output buffer and the output buffer pointer r is
incremented by 2 (block
338). If it is not, a further check (block 418) is made to determine whether
the absolute
value of the difference is less than 126. If it is, then a byte having the
value 0x82 is
written (block 374) to the output buffer to indicate that the next word
written to the
output buffer is not compressed, but that compression should stay on. The
operations
22

CA 02332297 2001-O1-25
indicated by block 338 are then performed, namely, the current Word is written
to the
output buffer and the output buffer pointer r is incremented by 3 (one
position for the
special byte and two for the current Word).
On the other hand, if the absolute value of the difference checked at block
418 is
not less than 126, then the index k is tested (block 420) and control loops
back to the
operations indicated by block 410 if all of the words in the input buffer have
not already
been tested or otherwise the operations indicated by block 336 are then
performed,
namely, special byte 0x81 (decimal -127) is written to the output buffer and
the
compression flag cMode is cleared (set to value 0). The operations indicated
by block
338 are performed, namely, the current Word is written to the output buffer
and the
output buffer pointer r is incremented by 3 (one position for the special byte
and two for
the current Word).
After the output buffer pointer r is incremented in each of the situations
above, the
operations indicated by block 340 are performed, namely, if the current Word
is not a
date/time stamp, then the variable oldV holding the previous value of the
current Word is
set to the value of the current Word and the input buffer point q is
incremented by 2.
The input buffer point q is then tested (block 342) against the total number
of
bytes Q in the input buffer to determine whether the input buffer has been
completely
read. If it has the process is complete. If not, another word is read (block
312) and
processed as above until at block 342 it is determined that the input buffer
has been
completely read.
The compression scheme described in relation to Figure 6 has an advantage over
other more complex compression schemes in that the required memory and
computational power is quite low. For example, because the process proceeds
sequentially through the input buffer, the output buffer may occupy the same
memory
positions as the input buffer. A major design goal has been to eliminate the
possibility
23

CA 02332297 2001-O1-25
that more bytes could be written to the output buffer than have been read from
the input
buffer, even if the data were extremely perverse. An example of perverse data
would be
if large differences between data values alternated with same differences
throughout the
data. The improved simple scheme shown in Figure 5 and the preferred scheme
shown in
Figure 6 would under such circumstances simply not compress the data at all.
The simple
scheme shown in Figure 4 would, however, compress every other value, resulting
in an
output buffer about 20% than the input buffer.
Those skilled in the art will recognize the detailed flowcharts presented in
Figures
4, 5, and 6 are but one possible representation of the invention. They do not
necessarily
represent the most efficient manner in which the process might be coded. For
example,
those skilled in the art will recognize that the operations indicated by
blocks 408 - 420
could be embodied in a single procedure that could also be used to perform the
operations
indicated by blocks 376 - 388 and doing so would be within the skill expected
of those
skilled in the art. Those sets of operations have been shown separately in
Figure 6 to aid
in the explanation of the overall compression.
Those skilled in the art will also recognize that the use of three as the
number of
range-expansion bytes is arbitrary. Clearly, depending upon the
characteristics of the
data to be compressed, more or fewer range-expansion bytes may be used. In
fact, the
number of range-expansion bytes could be varied dynamically by scanning the
input
buffer before commencing the compression process.
In a typical situation, the input buffer hold 96 words of load profile data
and one
time/date stamp. (There may be more than one time/date stamp if the real time
clock has
been reset during the last day.) In one typical situation in which a
compression scheme of
the form shown in Figure 6 was used, there were four words of data that
required range-
expansion bytes and one word of data that could not be compressed. The balance
of the
data words were compressed without using range-expansion bytes. The result was
that
24

CA 02332297 2001-O1-25
104 bytes were needed to send the 97 two-byte words, a compression of almost
50%
using a fast routine that needs only a single input/output buffer.
In the current embodiment of the interface board 18, it is possible that more
than
one channel of data may be stored alternating word-by-word in the input
buffer. In that
case, the compression process treats each channel completely separately from
the other.
Power Quality Monitoring
The power quality events monitored and reported by the exemplary interface
board 18 are ( 1 ) power outage events, (2) high/low voltage events, (3)
voltage unbalance
events, and (4) momentary interruption/voltage sag events, which are defined
as follows:
( 1 ) A power outage event occurs when a phase voltage has dropped to less
than a pre-
selected percentage (e.g., 50%) of nominal phase voltage for a pre-selected
interval of time. For example, an interval in the range of 1 to 10 minutes may
be
pre-selected for the exemplary interface board 18.
(2) A high/low voltage event occurs when a phase voltage has deviated from
nominal
phase voltage by a pre-selected percentage for a pre-selected interval of
time. For
example, a percentage in the range from 5 to 20 percent and an interval in the
range of 1 to 30 minutes may be pre-selected for the exemplary interface board
18.
(3) A voltage unbalance event occurs when a phase-to-phase voltage has
deviated
from the average of the three phase-to-phase voltages by a pre-selected
percentage
for a pre-selected interval of time. For example, a percentage in the range
from 2
to 6 percent and an interval in the range of 15 to 30 minutes may be pre-
selected
for the exemplary interface board 18.
25

CA 02332297 2001-O1-25
(4) A reportable momentary interruption/voltage sag ("MIVS") event occurs when
an
average phase voltage has dropped below the nominal phase voltage a pre-
selected number of times within a predefined window of time by more than a pre-
selected percentage. For example, a percentage of 20 percent or more, a number
of times in the range of 1 to 10, and a window of time in the range of 1 to 60
minutes may be pre-selected for the exemplary interface board 18. Each voltage
drop is referred to herein as a MIVS event; if a sufficient number of MIVS
events
are recorded, then a MIVS report is made by the interface board 18. Because
the
monitoring MIVS events is more complex than the monitoring of the other
events,
it is described in detail below.
The meter board 12 calculates average phase voltages, currents, and angles and
updates such data every 300 milliseconds in a register that is accessible via
the serial port
16. During an update the data in the register may be incorrect. To use such
data for
monitoring power quality, the interface board 18 could read the stored phase
voltages
every 300 milliseconds if its clock were synchronized with the meter board 12
so that the
readings would always take place between updates to the stored data. The
inventors have
found, however, that it is preferable to take not attempt to synchronize with
the meter
board 12 and instead to poll the meter serial port 16 every 100 milliseconds
for the
necessary data. By taking more readings than necessary the interface board 18
can weed
out any readings that might be taken during the period the phase voltages are
being
updated (and which therefore may be incorrect) or that might be taken when the
meter
board is too busy to respond, but still be able to capture the necessary data
in most cases.
While the meter board 12 raises a flag during its updating process to signify
that data read
from the serial port 16 may be incorrect, the inventors have found that bad
readings can
occur even if the flag is not set. Also, it has been found that under certain
circumstances
(when the meter board 12 has been polled too soon after powering up), the
voltage data
may be incorrect (zero or very small). A filter can be used to cause such
readings to be
ignored or they may be allowed treated as MIVS events so that the
malfunctioning of the
26

CA 02332297 2001-O1-25
meter board 12 can be monitored. In any case readings taken while the updating
flag is
set can be ignored.
An alternative to obtaining data from the meter board serial port 16 may be to
connect directly to the data/address bus of the meter board 12 and listen for
data being
stored.
Assuming that good data has been obtained from the serial port 16 (because it
has
been read when the meter board 12 is not updating the data and no other
problems are
causing bad data to be read), the average phase voltages will be read every
100 ms.
However, because the underlying data stored in the meter board 12 changes
every 300
ms, the voltage for a particular phase will consist of consecutive groups of
three identical
readings. The interface board 18 treats each phase voltage reading as if it
were an
independent average for 100 ms of the phase voltage. The consequences of this
treatment
are that ( 1 ) a momentary interruption cannot be distinguished from a voltage
sag and (2)
at a given threshold reduction in average phase voltage, some momentary
interruptions or
sags may not be detectable.
For example, if the average phase voltage on one phase drops by 20% (to 96
volts
if the nominal voltage is 120 volts) for three consecutive 100 ms average
phase voltage
readings (we are assuming that all readings are good data, so there will be
three identical
readings), then there could have been an interruption (zero volts, say) for 50
ms and full
nominal voltage of 120 volts for 250 ms. On the other hand, there could have
been a
voltage sag to 96 volts for the entire 300 ms or a deeper sag for a portion of
the 300 ms
and nominal voltage for the remainder of the 300 ms. If the threshold for
reporting is set
at 96 volts, then no momentary interruption of less than 50 ms within the 300
ms period
can be detected. Hence a phase voltage reading of 96 volts can mean anything
from an
interruption of 50 ms to a sag to 96 volts for 300 ms. Also, an interruption
or sag can
cross a boundary between 300 ms periods. To detect an interruption that
straddles the
boundary, the interruption would have to last for at least 50 ms in one of the
two 300 ms
27

CA 02332297 2001-O1-25
periods. In the case of voltage sags, a voltage sag to 96 volts that began in
one 300 ms
period would have to continue through the entire succeeding 300 ms period or
no MIVS
event would be detected by the interface board 18 if the threshold for MIVS
events were
set at 96 volts.
A MIVS event is considered to continue until a reading of the relevant average
phase voltage is not longer less than the nominal voltage by the predefined
percentage.
One option for dealing with bad data is to require that there be two
consecutive
average voltage readings that are both less than the nominal voltage by the
predefined
percentage before a MIVS event is treated as having begun. This criterion
could be
strengthened even further by requiring that three consecutive average voltage
readings all
be less than the nominal voltage by the predefined percentage before a MIVS
event is
treated as having begun. However, in some situations that would mean that an
isolated
MIVS event would be missed if a reading were ignored because the data was
being
updated.
In the past monitoring of power quality events has been done by large
dedicated
instruments, not as an adjunct to a power usage measurement in a conventional
commercial and industrial meter such as the Siemens S4. The interface board 18
provides a means for inexpensively turning a meter such as the Siemens S4 into
a power-
quality monitoring device. While many of the features of the interface board
described
below make it most useful when coupled with a two-way pager, the interface
board can
also be used to advantage if it is connected by a land telephone line or a
hardwired
network connect to a host computer 28. Those skilled in the art will
understand that
connections such as RS-485, CDPD modem, or telephone modem may also be used.
The host computer is not described in detail here. However, an important
feature
of the interface board 18 is that it provides for reporting of power quality
events such that
the host computer may notify the electricity supplier or its customer of power
quality
28

CA 02332297 2001-O1-25
events in near real-time. Means such as fax, email, the Internet, telephone,
or personal
messaging devices such as pagers and web or email-enabled cellular telephones
may be
used by the host computer 28 to provide nearly immediate notification of power
quality
events.
All power quality events are logged in a circular buffer. The interface board
accepts commands from the host to send out the contents or part of the
contents of the
buffer via the pager so as to provide data for later diagnosing of problems in
the meter.
The fundamental elements of the power quality aspect of the interface board 18
are that it is interrupt driven, uses an ad hoc (circular) buffer to record
power quality
events that may be reported, is remotely configurable, tracks network time,
and uses
average phase voltages to determine when a MIVS event has occurred.
The interface board 18 may be reset from the remote host so that the interface
board 18 provides load profile data, but not power quality data, to the host
28 via the
pager board 254 and pager system 26. This capability makes possible the
granting of
"migrating licenses" to use the power quality features of fewer than all of
the meters
installed and licensed for current usage data collection. The utility whose
power sales are
being metered may wish to collect power quality data only from a small number
of
meters, but have the capability of re-designating on its own volition which
meters collect
power quality data.
The interface board 18 also provides running mean power consumption tracking
for up to four daily periods and notifies the host 28 if the specified
threshold levels are
exceeded during those periods. This is treated a power quality event, so that
the host 28
is notified in near-real time when the running average exceeds the threshold.
Security (a required password) is provided to prevent unauthorized access to
the
hardware and firmware. This security is in addition to the meter's own
security system.
29

CA 02332297 2001-O1-25
Encryption is also provided using industry standard methods. The usage and
power quality data, key management, and the power quality license data are
encrypted
separately.
The interface board 18 also provides a report flag that allows all or some
power
quality reporting functions to be turned off to be set and reset from the
host. The
interface board 18 can also be configurated from the host 28 to change the
definition of a
reportable power quality event. For example, the utility may only want to have
a report if
five MIVS events occur within five minutes.
Further, the interface board 18 also provides for the option of reporting
together
with a reportable power quality event any partially collected data regarding a
condition
that would trigger a report of a power quality event if the condition being
monitored were
to continue. For example, if a high voltage condition were to continue long
enough to
trigger a report of it as a power quality event, then in the same report to
the host, the
firmware can be set to also include data being collected on MIVS events for
which the
defined time interval has not yet elapsed. This capability allows airtime on
the pager
system 26 to be minimized and the cost of operation of power quality
monitoring to
reduced.
The interface board 18 also provides for remote selection of the use of
compression, binary, or ASCII data formats for transmitting data to the host
28.
If there is CRC corruption, then the interface board 18 is automatically reset
to
factory defaults.
The interface board 18 keeps its time synchronized with the pager system 26 by
resetting the time when the network time changes by one minute. The network's
time
resolution is one minute, but the interface board 18 has one-second time
resolution. The

CA 02332297 2001-O1-25
interface board time can be allowed to drift a user configurable time up to
five minutes
from the network time before it is reset.
All the power quality parameters are configurable from the host 26.
The interface board 18 uses a back-off and retry process when a message sent
from the pager board 24 to the host 28 fails to be acknowledged. After three
tries the
interface board 18 resets the pager board 24 in case the pager board 24 has
gone into a
loop.
The parameters used to control the effect of all commands that can be executed
by
the interface board 18 can be changed from the host 28.
The source code for creating the instructions stored in the interface board 18
to
perform the functions discussed above is reproduced as Appendix A, which forms
a part
of this specification.
31

CA 02332297 2001-O1-25
Appendix A
Copyright ~ 2000 SmartSynch Inc.
#include<pI7c7~6.h>
#include <usartl6.h>
#include <defltkey.h>
#include "delay.h"
#include "iodef.h"
#include "fcode.h"
#include "time.h"
#defineNAK 0x15
#define SOH 0x01
#define EOT 0x04
#define ACK 0x06
#define CAN Oxl8
#detine HOURSYNC
#defineOFFSETI X12
#define OFFSET2 0x4800
#define OFFSET3 Ox~600
#define BLOCKSIZE 256
#define MAXADDRESS 62
#define CLIPSIZE 64
#define PAGER 1
#deFne METER 2
#define RTC 3
#define RTC_ALARM 4
#define RTC_NO_YEAR 5
#define ASCII 1
3D #define BIN 2
#detine PREAMBLE 4
#define XPTPASSW'ORD OX210C
#define FALSE 0
#detine TRUE 1
#define pqMivsDuration pqOffDelay
#define pqMivsLimit pqReminderDelay
#define pqMivsCount pqOfffime
unsigned char abortFlag;
unsigned char economyFlag;
unsigned char sendFlag;
unsigned char onlyDates;
unsigned char binaryFlag;
unsigned char status;
unsigned char timer;
unsigned char pending:
unsigned char padHeaderEven;
unsigned char pqEnabled;
unsigned int iPacketSize;
unsigned char successCount;
unsigned int crc;
unsigned int sum:
unsigned int hemp:
unsigned int Itemp2;
unsigned int Itemp3:
unsigned int Istart:
unsigned int linden:
unsigned int IindexSave;
32

CA 02332297 2001-O1-25
unsigned int packetStart;
unsigned int packetEnd;
unsigned int tempPacketStart
unsigned int bytesSentOK;
unsigned int oldBytesSentOK;
unsigned char moreDataToMeter;
unsigned char justDataToMeter;
unsigned char meterResponse;
unsigned char IastSyncDay;
unsigned char firstPassSync;
unsigned char i,j;
unsigned char received_byte;
unsigned char last byte;
unsigned char iMCmnd;
unsigned int tempSum;
unsigned char dayOfWeek;
unsigned char interval;
unsigned char period;
unsigned int ilndex;
unsigned char hemp;
unsigned char itemp2;
unsigned char iTimer;
unsigned char totalPackets;
unsigned char totalPages;
unsigned char fullPages;
unsigned char partPacket;
unsigned char partPage;
unsigned char packetsForPage;
unsigned char pageNumber;
unsigned char blockNum:
unsigned char checksum;
unsigned char headerSize;
unsigned char headerCount;
unsigned char headAddress;
unsigned char headerOverhead;
unsigned char useTempAddress;
unsigned char valDegrade;
unsigned char attemptCount;
unsigned char pagerMessage;
unsigned char start0l;
unsigned char end0l;
unsigned char noMeterResponse;
unsigned char badHandshake;
unsigned char tempMask;
unsigned char timerMask;
unsigned char exceptionMask;
unsigned char exceptionFlag;
unsigned char spreadDelay:
unsigned char spreadCount;
unsigned char dateFound;
unsigned char neverFound;
unsigned char gotlncomingMessage;
unsigned int stringPointer;
unsigned int stringEnd;
unsigned char clipPointer;
char startMonth;
char startDay;
char endMonth;

CA 02332297 2001-O1-25
char endDay;
struct time tag alarm;
struct time tag time;
unsigned char lastKnownYr;
unsigned char templ,temp2,temp3;
unsigned char meterlPassH,meterlPassM,meterlPassL;
unsigned char meter2PassH,meter2PassM,meter2PassL;
unsigned int modulelPass,module2Pass;
unsigned int password;
unsigned int paramCheckSum;
unsigned char whichPass;
unsigned char lastl,last2;
unsigned int offset;
unsigned char distance;
unsigned char LPintervaI,LPchannels,LPdays:
unsigned int LPavailable;
unsigned char bytesFromMeter;
unsigned int totalBytesFromMeter;
unsigned char totalBlocks;
unsigned char block;
unsigned char startByte;
unsigned char endByte;
unsigned char TxlInPnt;
unsigned char Tx 1 OutPnt
unsigned char Tx2InPnt;
unsigned char Tx20utpnt;
unsigned char Rc l InPnt;
unsigned char RclOutPnt;
unsigned char Rc2lnPnt;
unsigned char Re20utPnt;
unsigned int IastCentiTime;
unsigned char firstMainLoopState;
unsigned char registerPagerState:
unsigned char checkAlarmsState;
unsigned char yyl6State;
unsigned char yylbState;
unsigned char putchPagerState;
unsigned char yyyState;
unsigned char yyl8State;
unsigned char xmod_dataState:
unsigned char pagerResponse:
unsigned char handshakeState;
unsigned char unlockState;
unsigned char isLPenabledState;
unsigned char isLPenabIedReturn;
unsigned char getLPdataState;
unsigned char pagerIncomingState;
unsigned char storeAddressState;
unsigned char setNicknameState;
unsigned char getMessageState;
unsigned char executePagerCommandState;
unsigned char executeMultipleState;
unsigned char pqPoIlState;
unsigned char sendCommandState;
unsigned char calcSendDataState;
unsigned char sendPageState:
unsigned char sendPingState;
unsigned char sendAlarmState;
unsigned char sendParsingArrayState:
34

CA 02332297 2001-O1-25
unsigned char degradeState;
unsigned char exceptionPageState;
unsigned char writeTimeState;
unsigned char getMeterTimeState;
unsigned char getMeterTimeReturn;
unsigned char getPagerTimeState;
unsigned char writeTimeFrom;
unsigned char sendingPage;
unsigned char badSendCommand;
unsigned char MbuffPointer;
unsigned int meterDataChksum;
unsigned char meterSentLowChk;
unsigned char meterSentHiChk;
#pragma udata temp 1 buf
unsigned char stlmode;
unsigned char st2mode;
unsigned char stlpulse;
unsigned char st2pulse;
unsigned char pulseCount;
unsigned char pulseState;
unsigned char pulseCycles;
unsigned char beepState;
unsigned char testState;
unsigned char testError;
unsigned char checkErrorState;
unsigned char unlockFlag;
unsigned char spreadTimerState;
unsigned char saveParCheckSumState;
unsigned int voltAfraction;
unsigned int voltBfraction;
unsigned int voltCfraction;
unsigned int unbaIVoItAvg;
unsigned char unbalanceStatus;
unsigned char unbalPollState;
unsigned int unbalVoltAfrac;
unsigned int unbalVoltBfrac;
unsigned int unbalVoltCfrac;
unsigned int unbalAngleAfrac;
unsigned int unbalAngIeBfrac;
unsigned int unbalAngIeCfrac;
unsigned int unbalVoItAB;
unsigned int unbalVoltBC;
unsigned int unbalVoltCA;
unsigned char AsicStatus;
unsigned int suspendPQtime;
unsigned char pqLogOff~tate;
unsigned char hexNibble;
unsigned int pqOfffime;
unsigned char pqMivsScanState;
unsigned char pqMivsBuffPnt;
unsigned char pqDateFound;
unsigned int pqDuration;
unsigned char messageStatus;
unsigned char scanMIVSonly;
unsigned char hadLPerror;
unsigned char compressionEnabled;
unsigned char sendCompletePQ;
unsigned char unanswered~5s;
unsigned char meterComFault;

CA 02332297 2001-O1-25
unsigned char writeMeterSeriaIState;
unsigned char pqVerbosityEnabled;
unsigned char pagerResetHardState;
unsigned char pqReportNow;
unsigned int acOKtimer;
unsigned int messageEnd;
unsigned char terminatorFlag;
unsigned char messageReplied;
unsigned char runSSIcommand;
unsigned int demandSampIeTime;
unsigned char demandWindow;
unsigned char demandReport;
unsigned char sendParametersState;
unsigned char sendDemandReportState;
#pragma udata tempi buf
unsigned char TMROchanged;
unsigned char RAM_L,RAM H;
unsigned int pulseTime;
unsigned int beepTimer;
unsigned int putchPagerTime;
unsigned int pagerComAbortTime;
unsigned int meterComAbortTime;
unsigned int degradeTime;
unsigned int exceptionTime;
unsigned char whichPQ;
unsigned char minPQ;
unsigned char maxPQ;
unsigned char storePQeventState;
unsigned char sendPQstatusState;
unsigned char reportPQeventState;
unsigned int pqPendingTime;
unsigned int timeOfDayInc;
unsigned int timeOfDaySync;
unsigned int timeOfDay;
unsigned int execMultiPointer;
unsigned char sendPageReturn;
unsigned char echoBuff(9];
unsigned char command[11];
unsigned char wasReset;
unsigned char addCRCftag;
unsigned char synchToAtomicTime;
unsigned int mTime:
unsigned int prime;
unsigned int deltaTime;
unsigned char deltaTimeNegative;
unsigned char timeSynchMode;
unsigned char writeDecimalDivider;
unsigned char writeDecimalTemp;
unsigned char preamble[4];
unsigned int pagerPoIlTimeout;
unsigned char pagerStatusl;
unsigned char pagerStatus2;
unsigned char reestablishPagerState;
unsigned char noPagesToday:
unsigned char thisMessageUnlocked:
unsigned int messageLength;
unsigned int messageCRC;
unsigned int cryptData;
unsigned int cryptDataLength;
36

CA 02332297 2001-O1-25
unsigned int expiryTime;
unsigned int expiryDate;
unsigned char eeBuffInPnt;
unsigned char eeBuffOutPnt;
unsigned char pqBuffInPnt;
unsigned char pqBuffOutPnt;
unsigned char buffroPromState;
unsigned char pqLogToPromState:
unsigned char tempPromData;
unsigned int tempPromAddress;
unsigned int pqLogAddress;
unsigned char uritingEeprom;
unsigned char pqLogRequest
unsigned char pqScanEnd;
unsigned char eventType;
unsigned int pqScanPointer;
unsigned char timeChanged;
unsigned char timeChangeState;
unsigned char timeAdjustedToday;
unsigned int pqLogMask;
unsigned int sleepTime;
unsigned char outageReportSent;
unsigned char optionToGet;
unsigned char getOptionState;
unsigned char pagerOptionl;
unsigned char pagerOption2;
unsigned char pagerDiagnostics;
unsigned char pagerDiagCounter;
unsigned char oldOptionl;
unsigned char oldOption2;
unsigned char oldStatusl;
unsigned char oldStatus2;
unsigned char newDestination;
unsigned char autoRegisterDestination:
unsigned char yy~l7State;
unsigned char productlnfo;
unsigned char variableOffset;
unsigned char variableNumber;
unsigned char sleepiest;
unsigned char killPower;
unsigned char postDecimalCharacter:
unsigned char serialAtStart;
unsigned int crcEcho;
unsigned char autoRegisterData;
unsigned char pqPollEnabled;
unsigned int demandValue;
unsigned char pulseClear;
unsigned char ioState;
unsigned char demandTimer;
5D unsigned char runTimerState;
unsigned char checkBatteryState;
unsigned char updateAnalogInputsState;
unsigned char IBSenseH;
unsigned char IBSenseL;
unsigned char TempSenseH;
unsigned char TempSenseL;
unsigned char VBSenseH;
unsigned char VBSenseL;
unsigned int batteryTimerl;
unsigned int batteryTimer2;
J7

CA 02332297 2001-O1-25
#pragma udata tempt buf
unsigned int RamDATA;
unsigned int RamADDRESS;
union of tag{
unsigned char OLCHAR;
struct OLbits{
unsigned OL0:1;
unsigned OL1:1;
unsigned OL2:1;
unsigned OL3:1;
unsigned OL4:1;
unsigned OL5:1;
unsigned OL6:1;
unsigned OL7:1;
bits;
;OUTLATCH;
union ib tag{
unsigned char IBCHAR;
struct IBbits{
unsigned IB0:1;
unsigned IB1:1;
unsigned IB2:1;
unsigned IB3:1;
unsigned IB4:1;
unsigned IB~:I;
unsigned IB6:1;
unsigned IB7:1;
; bits;
INBUFF;
unsigned int tempGarbage;
unsigned char echoSize;
unsigned int TMROcentiSeconds;
unsigned int tempRamADDRESS;
unsigned int tempRamDATA;
unsigned char tempTBLPTRL;
unsigned char tempTBLPTRH;
unsigned char tempTBLATL;
unsigned char tempTBLATH;
unsigned char pqlnProgress;
unsigned int pqReportTime;
unsigned char pqEvent;
unsigned int pqValue;
unsigned int pqComparison;
unsigned int pqStartTime;
unsigned char pqFault;
unsigned char pqReportSize;
unsigned char pqReportFlag;
unsigned char pqDurationLimit;
unsigned char pqReportDelay;
unsigned char pqReminderDelay;
unsigned char pqEventStatus;
unsigned int pqEventDuration;
unsigned char pqOffDelay;
unsigned int fracMultiplier;
unsigned int fracDivider;
38

CA 02332297 2001-O1-25
rom char sDefauItEmail[] _ "Edev a xptechnology.com";
rom unsigned char sDefaultPin[9] _ {8,I,0x50,Ox34,Ox31,Ox36,Ox31,Ox30,Ox30};
rom char sDefaultInfoCommands[] _ "71,c0,8a,72,6d,1f
c4,c3,a6,08,8f,9B,07,06;";
rom char sDefaultlnfoParsing[22] _
{Oxc0,0,1,Oxff,0x72,0,3,Oxff,Oxc3,0,2,Oxff,Oxa6,0,2,Oxff,Ox06,OxfU,O,Oxf0,3,Oxf
f};
#define DEFAULT_INFO_PARSE_LENGTH 22
#define PQ SETUP_LENGTH 108
rom unsigned char sDefaultPQsetup[PQ SETUP_LENGTEI] _ {
40,80,50,1,10,2,0,200,20,20,240,180,1,10,2,0,255,13,
40,80,50,1,10,2,0,200,20,20.240,20,1,10,2,0,255,13,
5,20,10,1,30,2,0,200,40,20,240,180,1,30,2,0,255,13,
5,20,10,1,30,2,0,200,40,20,240,180,1,30,2,0,255,13,
1,6,2,15,30,15,0,200,40,20,240,180,1,30,2,0,255,13,
50,90,80,1,60,10,0,200,40,1,15,3,1,255,1,0,1,1 };
rom char sDefaultKeySeed[17] _ {defaultSeed};
rom char sFailed[] _ " Failed! »"~
rom char sDemandDisabled(] _ "/Demand Disabled";
rom char sPQDisabled[] _ "/PQ Disabled";
rom char sTemporarily[] _ " Temporarily";
rom char sPingVersion[J = "V J1.28 LV";
rom char sAutoReg[4] _ {'J',OxOl.Ox28,0; ;
rom char sBF03FF[4] _ {Oxbf;Ox03,Oxff,O};
rom char sMacc o[] _ " MACC O";
rom char sOut[] _ "OUT";
rom char sUnbal[] _ "UNBAL";
rom char sMivs[] _ "MIVS";
rom char s_com[] _ "/com";
rom char sOK_[] _ "OK ";
rom char s_IN_[] _ " IN ";
rom char sNOV~_[] _ "NOW ";
rom char sC_OUT_[] _ "C OUT ";
rom char sMIVS-(] _ "MIVS ";
#pragma romdata sRevision = 0x4000
rom char sRevision[] _ ".11.28";
rom char sBootBanner[] _ "RevJ 1.28";
rom char sSleepTest[] _ "Sleep Test";
#pragma romdata sCodeSpace = 0x4010
rom int sCodeSpace[6] _ {OxSfff,Ox7fff,Ox9fff,Oxbfff,Oxdfff,Oxffff;;
rom char sKilITest[] _ "Kill Test";
rom char sNewLine[5] _ {OxOa,OxOd,'>','>',0};
39

CA 02332297 2001-O1-25
/************************************************/
// Main Program //
/************************************************/
void main( void);
/************************************************/
// External Functions in "1a2465.c" //
/************************************************/
void initI2CQ;
char read_ext eeprom(unsigned int address);
void write eeprom_noDelay(unsigned int address, unsigned char data);
void set high endurance(unsigned char block);
/************************************************/
// External Functions in "lpef8583.c" //
/************************************************/
unsigned char to_dec(unsigned char datain, unsigned char maskhi);
unsigned char to_bcd(unsigned char datain);
void rte set_datetime(struct time tag *time);
void rtc_get datetime(struct time tag *time);
void rtc clear_irq(void);
void rtc set irq(void);
void rtc set alarm_datetime(struct time tag *alarm);
void rtc get alarm_datetime(struct time tag *time);
unsigned char rtc_read(unsigned char address);
void rte write(unsigned char address. unsigned char data);
/************************************************/
// Interrupt Service Routines //
/************************************************/
void _TMRO(); // Timer 0 Overflow
void_INT(); // RTC alarm
void _PIRQ; // Peripherals interupt
/************************************************/
// Serial Communication //
/************************************************/
unsigned char kbhitPager(void);
unsigned char getchPager(void):
void putchPager(unsigned char ch);
void putePager(unsigned char ch):
unsigned char kbhitMeter(void);
unsigned char getchMeter(void);
unsigned char getc(unsigned char whichPort);
void putchMeter(unsigned char ch);
void prepReceive(unsigned char whichPort);
void putHexIntPager(unsigned int hexData);
//void putHexCharPager(unsigned char hexData);
/************************************************/
// Eeprom buffering and PQ Log
functions //
/*** *********************************************/
void eepromBuffer(unsigned int address,
unsigned char data);
void bufferToEeprom(void);
pqLog(unsigned char data);
void
void pqLogToEeprom(void);
unsigned
int
pqScanRemaining(void);
void pqScan(void);
void pqScanReset(void);
getEventType(void);
void

CA 02332297 2001-O1-25
/************************************************/
// External RAM functions //
/************************************************/
unsigned int ramReadInt(void);
void ramWriteInt(unsigned int integerToWrite);
unsigned char ramReadUchar(void);
/************************************************/
t0 // Conversions //
/************************************************/
char to ascii(char din);
char toint(char cin);
unsigned int meterFIoatToInt(unsigned char baseExponent);
t5
/************************************************/
// Pager Interface (CLP commands & xmodem) //
/************************************************/
void yyy(void);
20 void yyl6(void):
void yy 17(void): // get configuration and product info.
void yy 18(void);
void getOption(void);
unsigned char yy 1 a(char option, char param);
25 void yylb(void);
void check( unsigned char xmitbuf);
char xmod_data( void);
void pagerResetHard( void);
void reestablishPager(void):
/************************************************/
// Meter Interface (DGCOM) //
/************************************************/
char handshake( void);
char unlock( void);
void findClip( unsigned char command);
char clipFound( void);
void getLPdata( void);
char isLPenabled( void);
void sendLPerror( void):
void calcLPsize(void):
void calcStart( void);
void sendCommand(void);
void executeMultipleCommands(unsigned int start);
void compressLPdata(void);
void getChannellnfo(void); // Restores OIdV and cMode for this channel.
void compressScan(void);
/************************************************/
// Power Quality Functions //
/************************************************/
void storePQevent(void);
unsigned
int
getDecimal(void);
void sendPQstatus(void);
voidwriteDecimaIToSendBuffer(unsigned
int decNumber);
void pqCalc(void);
void pqAddToReport(unsigned char
addToReport);
void pqAddIntToReport(unsigned int
IntToReport);
void pqLogMeterComFault(void);
voidpqPoll(void);
41

CA 02332297 2001-O1-25
void calcComparisons(void);
unsigned
int
fractionMultiply(unsigned
int
fracData);
void pqLogOff(void);
void pqMivsLog(void);
void pqMivsScan(void);
void pqUnbalanceCalc(void);
unsigned
int
sqrt(unsigned
int
sqData,
unsigned
int
guess);
void pqUnbalancePoll(void);
void checkDemand(void);
/************************************************/
// Address Handlers //
/************************************************/
void storeAddress( unsigned char tempFlag);
void setNickname(void);
/************************************************/
// Incoming Message Handlers //
/************************************************/
unsigned char getByte( unsigned int address);
char getMessage( void);
char matchPassword( unsigned int password):
unsigned char checkExpiration(void):
void getChar(void);
void rc4crypt(void);
void executePagerCommand(void);
void runTimer(void);
/************************************************/
// Outgoing Message Handlers //
/************************************************/
void degrade( void);
void sendPage( void);
void BitwiseCrcl6 (int bit);
void CaIcCRConRamAddress(unsigned int address);
void CaIcCRC(unsigned char data);
void addCRC();
void calcSendData( void);
void sendPing( void);
void spreadTimer(void):
void exceptionPage(void);
void reportPQevent(void);
void sendAlarm(void);
void checkMeterErrors(void);
void writeTime( char from);
void writeMeterSerial( void);
void sendParameters(void);
void sendDemandReport(void);
void ioStateUpdate(void);
void convertAndWriteToSendBuffer(unsigned char data):
void writeToSendBuffer(unsigned char data);
/************************************************/
// Setup //
/************************************************/
char invalidParameters(void);
void getParCheckSum(void);
void saveParCheckSum(void);
void putStringInEeprom( static const rom char *data); // for null terminated
strings
void putArraylnEeprom( static const rom char *data): // for strings that
contain nulls
42

CA 02332297 2001-O1-25
void putArrayInExtRam( static const rom char *data); // for strings that
contain nulls
void writeStringToSendBuffer( static const rom char *data); // for null
terminated strings
void putArrayInRTC( static const rom unsigned char *data); // for strings that
contain nulls
void commissionButtonPress( void);
void registerPager( void);
//void syncClocks( void);
void getPagerTime( void);
char getMeterTime( void);
void getSyncTime( void);
char verifyTime(struct time tag *time);
void timeChange(void);
void setParsingArray(void);
void sendParsingArray(void);
void clipEepromToRam(void);
void codeCRC(void);
void codeCRCblock(void);
void read_flash(void);
void updateTimeOfDay(void);
/************************************************/
// Miscellaneous //
/************************************************/
char delay 3sec(unsigned char howMany, unsigned char pattern);
void delay sec(unsigned int howMany);
void delay ms-plus(unsigned int howmany); // delay-ms plus check clear switch
and latch if pushed.
void pulse(void);
void testSy~stem( void);
void checkBattery(void);
void updateAnalogInputs(void);
void testlnFlash(void);
void putstring( static const rom char *data, char w~hichPort ):
void powerSaveSleep(void);
/************************************************/
// 32 bit floating point functions. //
/************************************************/
void uintl6ToFloat32(unsigned int datal6, unsigned char float32Address);
int float32Tolntl6(unsigned char float32Address);
void floatMultiply(unsigned char addressA, unsigned char addressB, unsigned
char addressAtimesB);
void floatDivide(unsigned char addressA, unsigned char addressB, unsigned char
addressAoverB);
void floatAdd(unsigned char addressA, unsigned char addressB, unsigned char
addressApIusB);
void floatChangeSign(unsigned char addressA);
void cos128(unsigned int cosData, unsigned char float32Address);
void FL01632U(void);
void FPD32(void);
void FPM32(void);
void FPA32(void);
void INT3216(void);
voidFXM1616U(void);
void FXD3216U(void);
//void calcCos(void);
43

CA 02332297 2001-O1-25
/************************************************/
l/ Main Program //
/************************************************/
#pragma code main = 0x8000
void main( void)(
unsigned char i;
OpenUSARTI(USART_TX_INT OFF&USART_RX_INT_OFF&USART ASYNCH MODE&USART EIGH
T BIT&USART CONT RX, 5);
OpenUSART2(USART_TX_INT OFF&USART RX INT OFF&USART ASYNCH MODE&USART SIGH
T BIT&USART CONT RX, 5);
PAGER_PWR_OUTP = I; // Turn Pager On
PAGER_RESET_EN_OUTP = 0; // Turn Pager Reset Enable Off
PAGER_RESET OUTP = 1; // Turn Pager Reset inactive
TOSTA = Ob01100000;
nCLEAR S W_LED_IO = 0;
nCLEAR S W SET DDRB = I ; // Turn Switch 2 off by setting it to be an input
autoRegisterData = 0;
if(!nCLEAR_SW_LED_IO && !nMAG-SWITCH-INP)
autoRegisterDcstination ='T;
else if(!nCLEAR SW LED_l0 R& !nTEST JUMP-INP);
received_byte=rtc_read(OxF2);
if(received byte==OxD6);
autoRegisterData = 1;
;
else {
rtc_write(OxF2, OxD6);
delay_ms(10); // Just in case a reset immediately after a rtc_write disturbs
the write
KILL_PWR_OUTP = l:
rtc write(OxF2, OxFF);
i
autoRegisterDestination ='8';
else
autoReeisterDestination = 0:
nSTATUS2_LED_OUTP = 0; // Turn LED 2 on
nSTI LED_LATCHED_OP = 0; // Turn LED 1 on
RW_EXT_IO;
set high endurance(6);
RAM_H = Oxdd;
RAM_L = 0x47:
TMROcentiSeconds = 0;
Install_TMRO( TMRO):
INTSTAbits.TOIE = I
Install_PIV( PIR);
INTSTAbits.PEIE = 1;
CPUSTAbits.GLINTD = 0;
sleepiest = 0;
Tx I InPnt=0;
Tx I OutPnt=0;
Tx2InPnt=0:
Tx2OutPnt=0;
44

CA 02332297 2001-O1-25
firstMainLoopState=1;
putchPagerState=0;
yyyState=0;
yy 16State=0;
yyl7State=0;
yy 18 State=0;
getOptionState=0;
yy I bState=0;
xmod_dataState=0;
'I0 pagerResetHardState=0;
reestablishPagerState=0;
handshakeState=0;
unlockState=0;
isLPenabIedState=0;
'C5 getLPdataState=0;
pagerIncomingState=0;
storeAddressState=0;
setNicknameState=0;
getMessageState=0;
20 executePagerCommandState=0;
runTimerState=0;
executeMultipleState=0;
registerPagerState=0;
checkAlarmsState=0;
25 sendCommandState=0;
calcSendDataState=0;
sendPageState=0;
sendPingState=0;
sendAlarmState=0;
30 sendParsingArrayState=0;
degradeState=0;
exceptionPageState=0;
writeTimeState=0;
getMeterTimeState=0;
35 getPagerTimeState=0;
sendingPage=0;
sendPageReturn=0;
checkErrorState=0;
sendParametersState=0;
40 sendDemandReportState=0;
pulseState=0;
beepState=0;
testState=0;
checkBatteryState=0;
45 batteryTimerl=0;
batteryTimer2=0;
updateAnaloglnputsState=1;
pulseCycles=0;
pulseTime=0;
50 unlockFlag=0;
addCRCflag = 0;
pagerMessage = 0;
spreadTimerState = 0;
timeAdjustedToday=1;
55 timeChanged = 0;
timeChangeState = OxFF: // non existent statejust to stop from being run b~~
timer function
// until after startup.
writeMeterSeriaIState = 0;
pqReportNow=0;
60 sleepTime=0;

CA 02332297 2001-O1-25
outageReportSent=0;
pagerDiagnostics=0;
pagerDiagCounter=0;
oldOption 1=0;
oldOption2=0;
oldStatus 1=0;
oldStatus2=0;
pqPollState=0;
AsicStatus=0;
sendPQstatusState=0;
storePQeventState=0;
reportPQeventState=0;
pqLogOffState=0;
pqMivsScanState=0;
scanMIVSonly=0;
pqPendingTime=0;
timeOfDayInc=0;
timeOfDaySync=0;
updateTimeOfDay();
pqReportSize=0;
suspendPQtime=0;
unbalanceStatus=0;
unbaIPoIlState=0;
compressionEnabled=1;
sendCompletePQ=0;
unanswered~5s=0;
meterComFault=0;
saveParCheckSumState=0;
acOKtimer-0;
runSSIcommand = 0;
timeSynchMode = 2; // Set RTC
to meter time only.
serialAtStart = 0;
delay-sec(3); // wait 1 ~ seconds for pager to stabilize
// Loader timeout + delay + check for invalid parameters
prepReceive(PAGER);
prepReceive(METER);
nSTILED_LATCHED_OP=1; //Turn LED
1 off
R W_EXT_IO;
nSTATUS2_LED_OUTP = 1; // Turn
LED 2 off
delay=ms_plus(250);
nSTATUS2_LED_OUTP = // Turn
0; LED 2 on
nSTI LED_LATCHED_OP = // Turn
0; LED 1 on
RW EXT_IO;
delay_ms_plus(2~0);
nST I LED_LATCHED_OP = // Turn
l ; LED 1 off
RW_EXT_IO;
nSTATUS2 LED OUTP = 1; // Turn
LED 2 off
newDestination = read ext eeprom(OxOC);
timerMask = read ext eeprom(Ox 10);
exceptionMask = read ext_eeprom(Ox 1 1 );
spreadDelay=read_ext eeprom(Oxl2);
meter 1 Passes=read_ext~eeprom(Ox 13);
meterlPassM=read_ext eeprom(Oxl4);
mcterlPassL=read_ext eeprom(OxlS);
meter2PassH=read eat eeprom(Oxl6);
46

CA 02332297 2001-O1-25
meter2PassM=read_ext_eeprom(Ox 17);
meter2PassL=read_ext eeprom(OxlB);
modulelPass=read_ext_eeprom(Oxl9);
module( Pass = module( Pass«8;
module 1 Pass += read ext eeprom(Ox I a)&Oxff;
module2Pass=read_ext_eeprom(Ox 1 b);
module2Pass = module2Pass«8;
module2Pass+=read ext_eeprom(Oxlc)&Oxff;
headerSize=read_ext eeprom(Oxld);
economyFlag=read ext eeprom(OxSd);
binaryFlag=read_ext eeprom(OxSe);
compressionEnabled=read_ext eeprom(OxSf);
pqVerbosityEnabled=read_ext eeprom(Oxlfd);
synchToAtomicTime=read_ext_eeprom(Ox 1 fc);
killPower=read_ext eeprom(Oxlfb);
Itemp2 = 0x60;
clipEepromToRamQ;
pqPollEnabled=0; // Enable after initiallizing, resetting pager and checking
for valid eeprom data.
pqEnabled=real( ext eeprom(Oxl9A);
useTempAddress = 0;
successCount=rtc read(OxlO);
IastKnownYrrtc read(Oxl2);
fastSymcDay=rtc read(Oxll);
bytesSentOK=rtc_read(Ox l 5);
bytesSentOK = bytesSentOK«8;
bytesSentOK += rtc read(Ox 16)&Oxff;
noPagesToday = 0;
eeBuffInPnt=0;
eeBuffOutPnt=0;
pqBuffInPnt=0;
pqBuffOutPnt=0;
bufffoPromState=0;
pqLogToPromState=0;
writingEeprom=0;
pqLogAddress = rtc_read(OxF3);
pqLogAddress = pqLogAddress«8;
pqLogAddress += rtc_read(OxF4)&Oxff;
if((pqLogAddress<Ox600) /~ ((pqLogAddress&Ox7fft~>OxIFFF))
pqLogAddress = 0x600;
start0l=0;
end01=Oxff;
abortFlag = FALSE;
onlyDates = FALSE;
pending=FALSE;
wasReset = 1;
moreDataToMeter = 0;
justDataToMeter = 0;
meterResponse = 0;
gotIncomingMessage=0;
dayOfWeek=0;
firstPassSync=0;
stringPointer-0x80;
stringEnd=stringPointer+PQ_SETUP LENGTH;
putArrayInRTC(sDefaultPQsetup);
for (i=Oxl8;i<Ox40;i++) // Clear Timer Alarm Times
rtcyrite(i,0);
47

CA 02332297 2001-O1-25 ,
1
received byte = read ext eeprom(OxOd); // Rev. Flag Change if you want to
if(received byte != 0x18) // force an auto-commission.
eepromBuffer(OxOd,Ox 18);
RamDATA = 0;
RamADDRESS = 0x4400;
for (whichPQ=O;whichPQ<OxEA;whichPQ++){ // Clear PQ temporary variables
RAM WRITE;
r
for (whichPQ=O;whichPQ<6;whichPQ++) // Calculate PQ Comparison values.
calcComparisonsQ;
RamADDRESS=0x5000; // Mirror Get Meter Info commands in RAM
for(i=O;i< 128;i++) {
RamDATA = read ext eeprom(Ox 11 A + i);
RAM WRITE;
{ _
RamADDRESS=Ox4C00; // Mirror Timer Event Definitions in RAM
for(ltemp=OFFSETI;ltemp<Ox600;ltemp++){
RamDATA = read ext eeprom(ltemp);
RAM WRITE;
i _
RamADDRESS = 0x5200; // Clear MIVS Buffer
RamDATA = 0;
pqMivsBuffPnt=0;
do {
RAM_WRITE;
pqMivsBuffPnt++;
while(pqMivsBuffPnt);
demandSampleTime=0;
demandWindow=read_ext eeprom(OxlC6);
RamADDRESS = 0x5400; // Clear Demand Sample Array
RamDATA = 0;
demandReport=0;
do {
RAM_V'RITE;
demandReport++;
while(demandReport);
RamADDRESS = Ox~39F; // Clear Demand Temporary variables
for(i=0; i< 17; i++) {
RAM_WRITE;
for(whichPQ=O;whichPQ<l7;whichPQ++)( // Load RAM copy of secret key.
received byte = read_ext_eeprom(Ox 1 EO+whichPQ);
RamADDRESS = Ox538C + whichPQ;
RamDATA = received byte;
RAM WRITE;
i
rtc write(O.Ox04); // control register = timer on, 32728 Hz, alarm enabled
rtc write(8.Ox30); // alarm control = dated alarm. interrupt disabled
rtc clear irq();
IastCentiTime = TMROcentiSeconds:
for(;;) {
PqPoll();
CPUSTAbits.GLINTD=1;
48

CA 02332297 2001-O1-25
lastCentiTime = TMROcentiSeconds;
CPUSTAbits.GLINTD = 0;
TMROchanged=0;
CIrWdt();
1//// Roll Back Timers /////
if (lastCentiTime>32768){
TMROcentiSeconds-=32768;
IastCentiTime-=32768;
if(pulseTime>32768) pulseTime-=32768; else pulseTime=0;
if(putchPagerTime>32768) putchPagerTime-=32768; else putchPagerTime=0;
if(pagerComAbortTime>32768) pagerComAbortTime-=32768; else
pagerComAbortTime=0;
if(meterComAbortTime>32768) meterComAbortTime-=32768; else
meterComAbortTime=0;
if(degradeTime>32768) degradeTime-=32768; else degradeTime=0;
if(exceptionTime>32768) exceptionTime-=32768; else exceptionTime=0;
if(timeOfDaylnc>32768) timeOfDayInc-=32768; else timeOfDaylnc=0;
if(timeOfDaySync>32768) timeOfDaySync-=32768; else timeOfDaySync=0;
if(suspendPQtime>32768) suspendPQtime-=32768; else suspendPQtime=0;
if(demandSampleTime>32768) demandSampleTime-=32768; else demandSampleTime=0;
if(acOKtimer) {
if(acOKtimer>32768) acOKtimer-=32768;
else acOKtimer=1;
for(i=10;i<13;i++) {
RamADDRESS = 0x4400 + i*Oxl2:
RAM_READ;
pqInPro~ress = RamDATA&OxOf:// Lower nibble only
if(pqlnProgress);
RamDATA ~= pqlnProgress+1; // Will only increment up to 0x10
RamADDRESS = Ox4-X00 + i*Ox 12;
RAM WRITE;
r
pqEvent=0;
pqMivsLog();
if(meterComFault && meterComFault!=6){
meterComFault += Ox 10;
pqLogMeterComFault();
i
;
// timeOtDay is incremented every 2 seconds so that an int can represent a 27
hour period. (27
// hours allows time delays of 3 hours to be simply added to timeOfDay.) This
is created
// for time stamps for PQ events but there is no reason it could not be used
for other purposes.
// Once a minute the timeOfDay is synchronized to the RTC. timeOfDaylnc is
used to increment the
// time every two seconds. timeOfDaySync is used to synchronize to the RTC.
When timeOfDay rolls
// over 24 hours, a day stamp is added to the log, all set times have 24 hours
subtracted from
// them, all pqInProgress flags that are set are incremented to indicate that
their start times are
// actually from the previous day.
if(timeOfDaylnc<lastCentiTime)
timeOfDay++;
timeOfDaylnc = lastCentiTime+200;
unbalanceStatus=1; // To run Voltage Unbalance Calc. ever~~ 2 sec.
;
if(timeOfDaySyne<IastCentiTime R:& !timeChangeState);
timeOfDaySync = timeOfDay;
updateTimeOfDay();
if(timeOfDay<10800 && timeOfDaySyne>32400){ // RTC < 0600 & timeOfDay > 1800
// This is a date roll over.
49

CA 02332297 2001-O1-25
if(dayOfWeek) dayOfWeek++; // Used by weekly events.
time.yr = time.yr%4;
time.yr = time.yr«4;
time.yr += time.mth;
pqLog(to_bcd(time.day));
pqLog(time.yr);
pqLog(0); // Date Stamp
for(i=O;i< 10; i++) {
RamADDRESS = 0x4400 + i*Oxl2;
RAM_READ;
pqInProgress = RamDATA&OxOf;// Lower nibble only
if(pqlnProgress){
RamDATA ~= pqlnProgress+1; // Will only increment up to 0x10
RamADDRESS = 0x4400 + i*Ox 12;
RAM WRITE;
RamADDRESS = 0x4404 + i*Ox 12;
pqReportTime = ramReadlnt();
if(pqReportTime);
if(pqReportTime>43200) pqReportTime -= 43200;
else pqReportTime= 1;
RamADDRESS = 0x4404 + i*Oxl2;
ramWritelnt(pqReportTime);
if(pqPendingTime) {
if(pqPendingTime>43200) pqPendingTime -= 43200;
else pqPendingTime= 1;
if(pagerPollTimeout>43200) pagerPoIlTimeout -= 43200;
else pagerPollTimeout = 0;
if(sleepTime>43200) sleepTime -= 43200;
else sleepTime = 0;
RamADDRESS = Ox53A8:
pqReportTime = ramReadlnt();
if(pqReportTime);
if(pqReportTime>43200) pqReportTime -= 43200;
else pqReportTime = 1;
RamADDRESS = Oxi3A8;
ramWriteInt(pqReportTime);
pqReportTime = ramReadIntQ;
if(pqReportTime)
if(pqReportTime>43200) pqReportTime -= 43200;
else pqReportTime = 1;
RamADDRESS = Ox~3AA;
ramWritelnt(pqReportTime);
i
v
timeOfDaySync = lastCentiTime+6000;
timeOfDaylnc = IastCentiTime+200;
i
if (pulseCycles ~.& pulseTime<IastCentiTime) pulse();
if (putchPagerState && putchPagerTime<lastCentiTime) putchPager(0);
if (yyyState) yyy();
if (yy l6State) yy 16Q;
if (yy 18State) yy 18();
if (yy 17State) yy 17Q;
if (getOptionState) getOption();

CA 02332297 2001-O1-25
if (yy I bState) yy I b();
if (xmod dataState) xmod_dataQ;
if (pagerResetHardState) pagerResetHard();
if (reestablishPagerState) reestablishPager();
if (handshakeState) handshake();
if (unlockState) unlock();
if (isLPenabledState) isLPenabledQ;
if (getLPdataState) getLPdata();
if (storeAddressState) storeAddress(0);
if (setNicknameState) setNickname();
if (getMessageState) getMessage();
if (executePagerCommandState) executePagerCommand();
if (runTimerState) runTimerQ;
if (executeMultipleState) executeMultipleCommands(0);
if (registerPagerState) registerPager();
if (checkAlarmsState) checkAlarmsQ;
if (sendCommandState) sendCommand();
if (calcSendDataState) calcSendData();
if (sendPageState) sendPage();
if (sendPingState) sendPingQ;
if (sendAlarmState) sendAlarm();
if (sendParsingArrayState) sendParsingArray();
if (checkErrorState) checkMeterErrors();
if (sendParametersState) sendParameters();
if (sendDemandReportState) sendDemandReport();
if (degradeState) degrade();
if (exceptionPageState) exceptionPage();
if (writeTimeState) writeTime(0);
if (getMeterTimeState) getMeterTime();
if (getPagerTimeState) getPagerTime();
if (sendPQstatusState) sendPQstatusQ;
if (storePQeventState) storePQevent();
if (reportPQeventState) reportPQevent();
if (pqLogOffState) pqLogOff();
if (pqMivsScanState) pqMivsScan();
if (spreadTimerState) spreadTimer();
if (timeChangeState) timeChange();
if (writeMeterSeriaIState) writeMeterSerial();
if (saveParCheckSumState) saveParCheckSumQ;
if (pqPendingTime && pqPendingTime<timeOtDay && !reportPQeventState)
reportPQeventQ;
bufferToEeprom( );
pqLogToEeprom();
if (!nMAG SWITCH INP && !pqLogOff~tate) pqLogOffQ;
checkBatteryQ;
if(updateAnalogInputsState) updateAnalogInputs();
switch (firstMainLoopState){
case 1:
pqLog(OxFD);
tempi = invalidParametersQ;
yy 1 a(4,1 ); // turn off notification (LFs)
pagerResetHard();
firstMainLoopState=2;
break;
case 2:
if(!pagerResetHardState){
y~~la(OxOa,Ox80); // enable system updates to Greemvich Mean Time
pagerResetHardQ;
firstMainLoopState=3;
51

CA 02332297 2001-O1-25
break;
case 3:
if(! pagerResetHard State) {
PAGER PWR OUTP = 0;
yyl8Q;
firstMainLoopState=4;
break;
case 4: // Wait until registerPager done.
1D if(!yylBState){
PAGER_PWR OUTP= 1;
if(!pagerResponse)
autoRegisterData+=2;
if (!nCLEAR SW LED I0 ~~ tempi){ // If switch 2 pressed or garbage in eeprom
then recommission
if(!nCLEAR_SW_LED_IO){
if(autoRegisterDestination='T) newDestination = 0x20; // Lafayette
if(autoRegisterDestination='8') newDestination = 0x30; // Calgary
else newDestination = 0x40; // Manual in the Field Set to Defaults
T
1
else newDestination = Ox 10;
eepromBuffer(OxOC,newDestination); // using default destination
commissionButtonPress();
pqPollEnabled= I;
registerPager();
firstMainLoopState=~;
break;
case 5:
if(registerPagerState=0) {
timeChangeState = 0;
timeChange();
firstMainLoopState=6;
2
1
break:
case 6: // Wait until syncClocks done.
if(timeChangeState---0)
firstMainLoopState=7;
break;
case 7:
initAlarmsQ;
checkAlarms();
firstMainLoopState=8;
break;
case 8: // Wait until checkAlarms done.
firstMainLoopState=9;
break;
case 9:
setAlarmQ; // No Wait.
firstMainLoopState=0;
break;
case 0:
if ((!nTEST JUMP INP ~~ testState) && !sendingPage) testSystem();
switch(pagerIncomingState) {
case 0: // Idle
if(!testState && !sendingPage && nTEST JUMP' INP &&
pagerComAbortTime<lastCentiTime);
sendingPage=I;
if(runTimerState=1 );
runTimerState++;
52

CA 02332297 2001-O1-25
pagerIncomingState=20;
}
else if(demandReport%2) // 1 or 3 but not
2
sendDemandReport();
else if(runSSIcommand){
messageReplied=0;
messageStatus = ACK;
getMessageState = 5;
pagerlncomingState=3;
}
else {
yy 1 b();
pagerIncomingState=1;
rtc_get datetime(&time);
if(timeAdjustedToday==time.hr && !timeChangeState
&& ((time.min=7 && time.sec>30) ~~ time.min>7)){
if(timeSynchMode!=Oxff) {
timeChanged=1;
if(time.hr-2) timeSynchMode=1;
else timeSynchMode=0;
l
l
else if(time.hr--2){
timeChanged=I ;
}
}
r
break;
case 1:
if(!yy 1 bState) {
if(pagerResponse==1) // Should differentiate
neg. vs no response
pagerIncomingState=2;
else if(outageReportSent > 1 ){
powerSaveSIeepQ;
}
else {
stlpulse=1;
st2pulse=OxF;
pulseCycles=4;
if(runTimerState---1 ) {
runTimerState++~
pagerlncomingState=20;
i
else if(pagerDiagnostics){
pagerIncomingState=10;
i
else {
sendingPage=0;
pagerlncomingState=0;
oldOption I=0;
oldOption2=0:
oldStatus 1=0:
oldStatus2=0:
}
break;
case 2:
messageReplied=0;
putcPager(NAK);
53

CA 02332297 2001-O1-25 ,
getMessage();
pagerIncomingState=3;
break;
case 3:
if (!getMessageState){
runSSIcommand = 0;
if (pagerMessage){
pagerIncomingState=4;
else {
sendingPage=0;
pagerIncomingState=0;
if(! messageRepl ied) {
if(exceptionMask&8 && exceptionFlag!=~){
exceptionFlag=4;
exceptionPageQ;
if(exceptionMask&0x10 && exceptionFlag-~){
exceptionPage();
;
break;
case 4:
executePagerCommandQ;
pagerIncomingState=5;
break;
case 5:
if (!executePagerCommandState && !saveParCheckSumState){
pagerIncomingState=7;
pqLog(messageStatus);
pqLog(timeOlDay&OxF F);
pqLog(timeOfDay8);
pqLog(pagerMessage);
if(exceptionMask&8 && messageReplied!=2){
sendingPage=0;
exceptionFlag=4;
exceptionPage();
pagerIncomingState=6;
l
1
L
1
break;
case 6:
if(!exceptionPageState && !sendingPage);
sendingPage=I ;
pagerlncomingState=7;
r
break;
case 7:
messageReplied=1;
messageStatus = ACK;
getMessageState = 5;
pagerIncomingState=3;
break;
case 10:
if(5<pagerDiagCounter++) {
pagerDiagCounter-0;
pagerIncomingState=1 1;
optionToGet = 0x09;
54

CA 02332297 2001-O1-25
getOptionQ;
else {
pagerIncomingState=12;
yy 18();
break;
case 11:
if(! getOptionState) {
if((pagerOption I !=oldOption 1 ) ~~ (pagerOption2!=oldOption2)) {
pqLog(pagerOption2);
pqLog(pagerOption 1 );
pqLog(timeOfDay&OxFF);
pqLog(timeOfDay»8);
pqLog(Ox78);
oldOptionl =pagerOptionl;
oldOption2 = pagerOption2;
pagerlncomingState=0;
sendingPage=0;
break
case 12:
if(!yy 18State) {
pagerIncomingState=0;
sendingPage=0;
r
break;
case 20:
if(!runTimerState){
pagerIncomingState=0;
sendingPage=0;
break:
if(nAC
OK_INP&&(exceptionMask&I)&&!pending&&!exceptionPageState&&!sendAlarmState);
rtc-get datetime(&alarm);
received byte = read_ext_eeprom(Ox 1 F9):
alarm.hr += received-byte/60;
alarm.min += received byte%60;
validateTime(&alarm);
if(alarm.hr>=24)
alarm.hr-=24;
rtc set alarm_datetime(&alarm);
exceptionFlag=1;
exceptionPage();
pending=TRUE;
if ((!nAC
OK_INP)&&(exceptionMask&2)&&!pending&&!exceptionPageStateR;&!sendAlarmState);
rtc_get datetime(&alarm);
received byte = read_ext_eeprom(Ox 1 FA);
alarm.hr += received byte/60;
alarm.min += received byte%60;
validateTime(&alarm);
if(alarm.hr>=24)
alarm.hr-=24;
rtc_set alarm_datetime(&alarm);
exceptionFlag=2;
exceptionPageQ;
5$

CA 02332297 2001-O1-25
pending=TRUE;
}
if (firstPassSync) {
firstPassSync=0;
checkMeterErrors();
}
if (!nRTC INT INP){ // Time to send scheduled Data (Pin AO is RTC interrupt)
if(!sendAlarmState) sendAlarm();
}
if (timeChanged && !nAC OK_INP && !(exceptionMask&2)){
if(!timeChangeState) timeChange();
}
break;
} // switch (firstMainLoop)
} // for ever
} // main
56

CA 02332297 2001-O1-25
/************************************************/
// Interrupt Service Routines //
/************************************************/
void TMRO(){ // Timer 0 Overflow
_asm // Preload timer to acheive overflow in 10 ms
BANKSEL RAM_L
MOVFP RAM_L, TMROL
MOVFP RAM_H, TMROH
_endasm
TMROcentiSeconds++;
TMROchanged=1;
void _INT() { // RTC alarm input.
TMROcentiSeconds++; // Just so this isn't a null function.
void PIRA { // Peripherals interupt
_asm
BANKSEL RamADDRESS
MOVFP RamADDRESS,WREG
MOV WF tempRamADDRESS
MOVFP RamADDRESS+1,WREG
A90VWFtempRamADDRESS+I
MOVFP RamDATA,WREG
MOVWF tempRamDATA
MOVFP RamDATA+1,WREG
MOV WF tempRamDATA+1
MOVPF TBLPTRL,tempTBLPTRL
MOVPF TBLPTRH,tempTBLPTRH
TLRD O,tempTBLATL
TLRD l,tempTBLATH
_endasm
if (PIElbits.RBIE && PIRlbits.RBIF){ // PortB change
PIE 1 bits.RBIE = 0;
if (PIElbits.TMR3IE && PIRIbits.TMR3IF);// Timer 3
PIE 1 bits.TMR3IE = 0;
;
if (PIE 1 bits.TMR2IE && PIR 1 bits.TMR2IF) {// Timer 2
PIEIbits.TMR2IE=0;
if (PIE 1 bits.TMRI1E && PIR1 bits.TMRI IF) {// Timer I
PIE 1 bits.TMR l IE = 0;
r
if (PIEIbits.CA2IE && PIRIbits.CA2IF){ // Capture 2
PIE I bits.CA2lE = 0;
if(PIElbits.CAIIE&&PIRlbits.CAIIF){ //Capture 1
PIE I bits.CA I IE = 0;
if (PIElbits.TXIIE && PIRlbits.TXlIF){ // Transmit 1 Empty
if (Tx 1 InPnt != Tx 1 OutPnt) {
_asm
BANKSEL TxlOutPnt
INCF Tx 1 OutPnt, l
MOVFP TxlOutPnt,VVREG
BANKSEL RamADDRESS
MOVWFRamADDRESS
$~

CA 02332297 2001-O1-25
MOVLW 0x40
MOV WF RamADDRESS+I
_endasm
RamReadQ;
_asm
BANKSEL TXREG1
BANKSEL RamDATA
MOVFP RamDATA,TXREGI
_endasm
else {
PIElbits.TXI IE = 0;
// Interrupt driven receive.
// Before sending out any characters that you expect a response from, turn
continuous
// receive enable (CREN) off, clear the receive registers, set Rcl InPnt=Rcl
OutPnt and
!/ then turn CREN on again. As characters come in the "receive buffer full"
ISR puts
/1 them in a circular buffer in external RAM and increments RclInPnt. The
function
// handling the incoming characters takes them from the circular buffer and
increments
// RclOutPnt until it equals RclInPnt.
// What about overflowing 2~6 byte circular buffer? Ignore possibility for
now.
if(PIElbits.RCIIE && PIRlbits.RCIIF){// Receive
1 Full
_asm
BANKSEL Rc I InPnt
INCF Rc 1 InPnt. l
MOVFP RclInPnt,~VREG
BANKSEL RamADDRESS
MOVWF RamADDRESS
MOVLW 0x41
~90VWF RamADDRESS+1
BANKSEL RCREG1
BANKSEL RamDATA
MOVPF RCREGI,RamDATA
_endasm
RamWriteQ;
L
if (PIE2bits.SSPIE && PIR2bits.SSPIF){// SSP
PIE2bits.SSPIE = 0;
r
if (PIE2bits.BCLIE &R. // SSP/I2C
PIR2bits.BCLIF) { Bus Collision
PIE26its.BCLIE = 0:
;
if (PIE2bits.ADIE && PIR2bits.ADIF)// A/D Module
{
PIE2bits.ADIE = 0:
r
if (PIE2bits.CA4IE && PIR2bits.CA4IF){// Capture
4
PIE2bits.CA4lE = 0;
i
if (PIE2bits.CA3IE R.& // Capture
PIR26its.CA3IF){ 3
PIE2bits.CA3IE = 0;
1
1
if (PIE2bits.TX2IE && PIR2bits.TX2IF){// Transmit
2 Empty
if (Tx2InPnt != Tx2OutPnt)
_asm
BANKSEL Tx2OutPnt
IIv'CF Tx2OutPnt.1
MOVFP Tx2OutPnt,WREG
$g

CA 02332297 2001-O1-25
BANKSEL RamADDRESS
MOV WF RamADDRESS
MOVLW 0x42
MOV WF RamADDRESS+1
_endasm
RamRead();
_asm
BANKSEL TXREG2
BANKSEL RamDATA
MOVFP RamDATA,TXREG2
_endasm
1
1
else {
PIE2bits.TX2IE = 0;
)
if (PIE2bits.RC2IE && PIR2bits.RC2IF) { // Receive 2 Full
_asm
BANKSEL Rc2InPnt
INCF Rc2InPnt, I
MOVFP Rc2InPnt,WREG
BANKSEL RamADDRESS
MOVWF RamADDRESS
MOVLW 0x43
MOVWFRamADDRESS+1
BANKSEL RCREG2
BANKSEL RamDATA
MOVPF RCREG2,RamDATA
_endasm
RamWriteQ;
_asm'
BANKSEL RamADDRESS
MOVFP tempRamADDRESS,WREG
MOV~VF RamADDRESS
MOVFP tempRamADDRESS+I,WREG
MOVWF RamADDRESS+1
MOVFP tempRamDATA,WREG
MOV WF RamDATA
MOVFP tempRamDATA+1,WREG
MOV WF RamDATA+1
MOVFP tempTBLPTRL,TBLPTRL
MOVFP tempTBLPTRH,TBLPTRH
TLWT O,tempTBLATL
TLWT l,tempTBLATH
endasm
i
/******************************************************
Serial Communication
unsigned char getchPager(void);
void putchPager(unsigned char ch);
void putcPager(unsigned char ch);
unsigned char getchMeter(void);
void putchMeter(unsigned char ch);
void putHexIntPager(unsigned int hexData);
void putHexCharPager(unsigned char hexData);
*******************************************************/
unsigned char kbhitPager(void){
59

CA 02332297 2001-O1-25
if (Rcl InPnt!=Rc 1 OutPnt) return( 1 );
return(0);
unsigned char kbhitMeter(void){
if (Rc2InPnt!=Rc2OutPnt) return( 1 );
return(0);
unsigned char getc(unsigned char whichPort){
unsigned char inChar,chTemp;
if(whichPort=PAGER){
Rc I OutPnt++;
RamADDRESS = 0x4100+Rc 1 OutPnt;
else {
Rc2OutPnt++;
RamADDRESS = 0x4300+Rc2OutPnt;
{
RAM_READ;
inChar = RamDATA&Oxff;
return(inChar);
z
void putchPager(unsigned char ch) {
if (!putchPagerState) {
putcPager(ch);
putchPagerState=l
putchPagerTime=lastCentiTime+5;
;
else putchPagerState=0;
r
void putcPager(unsigned char ch){
CPUSTAbits.GLINTD=1;
Tx 1 InPnt++;
RamADDRESS = 0x4000+Tx 1 InPnt;
RatnDATA = ch;
RamVVriteQ;
PIE 1 bits.TX I IE = 1:
CPUSTAbits.GLINTD=0:
r
void putchMeter(unsigned char ch) {
unsigned char chTemp;
CPUSTAbits.GLINTD=1;
Tx2InPnt++;
RamADDRESS = 0x4200+Tx2InPnt;
RamDATA = ch;
RamWritep;
PIE2bits.TX2lE= 1;
CPUSTAbits.GLINTD=0;
i
void prepReceive(unsigned char whichPort) {
CPUSTAbits.GLINTD=1:
if(whichPort=PAGER)
RCSTA 1 bits.CREIv' = 0:
received byte=RCREG1;
received byte=RCREG1; // read hvice to clear buffer

CA 02332297 2001-O1-25
Rc 1 OutPnt = Rc l InPnt;
RCSTAIbits.CREN= 1;
PIElbits.RCIIE= l;
else {
RCSTA2bits.CREN = 0;
received byte=RCREG2;
received byte=RCREG2; // read twice to clear buffer
Rc2OutPnt = Rc2InPnt;
RCSTA2bits.CREN=1;
PIE2bits.RC2lE= 1;
CPUSTAbits.GLINTD=0;
/************************************************
Eeprom buffering and PQ Log functions
void eepromBuffer(unsigned int address, unsigned char data);
void bufferToEeprom(void);
void pqLog(unsigned char data);
void pqLogToEeprom(void);
unsigned int pqScanRemaining(void);
void pqScan(void):
void pqScanReset(void);
************************************************/
void eepromBuffer(unsigned int address, unsigned char data) {
// This function is to be called by any other function that wishes to store
data
// in the Eeprom. Address and data are stored in a circular buffer in external
// RAM and then slowly written to the eeprom by the bufferToEeprom() function.
// If the circular buffer would wrap on itself if this data was put into it
then
// this function clears any in progress flags for eeprom and then calls the
// function that takes data from this circular buffer.
if((eeBufflnPnt+1)=eeBuffOutPnt ~~ (eeBuffInPnt+2)==eeBuffOutPnt ~~
(eeBuff7nPnt+3) =eeBuffOutYnt);
buffToPromState = 0;
pqLogToPromState = 0;
bufferToEeprom();
eeBuffInPnt++;
RamADDRESS = 0x4700+eeBuftInPnt;
ramWriteInt(address);
RamDATA = data;
RAM_WRITE;
eeBuffInPnt += 2;
writingEeprom=I;
void bufferToEeprom(void){
// This function takes data from the circular buffer in external RAM. that was
// put there by the eepromBuffer function, and writes it with delays between
bytes
// to the eeprom. This function is called roughly ever7~ l Oms so the time
delay is
// simply a second call. This function takes turns with pqLogToEeprom().
if(!buffToPromState){
if(!pqLogToPromState && eeBuffInPnt!=eeBuffOutPnt){
buffToPromState=1;
eeBuffOutPnt++;
RamADDRESS = 0x4700+eeBuffOutPnt:
tempPromAddress = ramReadInt();
RAM_READ;
tempPromData = RamDATA&Oxff;
G1

CA 02332297 2001-O1-25
eeBuffOutPnt += 2;
write eeprom noDelay(tempPromAddress,tempPromData);
f
else {
buffroPromState=0;
if(eeBuffInPnt=eeBuffOutPnt)
writingEeprom=0;
)
void pqLog(unsigned char data){
l/ Similar to eepromBufferQ, this function puts data into a temporary buffer
in
// external RAM. No addresses are stored because anything put in here just
goes
// sequentially into the PQ & Communication event log which is a large
circular
// buffer in the Eeprom.
if((pqBuffTnPnt+I )=pqBuffOutPnt) {
buffToPromState = 0;
pqLogToPromState = 0;
pqLogToEepromQ;
pqBuffInPnt++;
RamADDRESS = 0x4600+pqBuffInPnt;
RamDATA = data;
RAM WRITE;
void pqLogToEeprom(void);
// This function moves the buffered data for PQ & Communication events from
RAM
// to eeprom. The position in the Eeprom is stored in two bytes in the
// RTC RAM. On startup, if the stored pointer is invalid then it is set to the
// beginning of the circular buffer. When the circular buffer wraps the high
bit
// of the pointer is set to 1 to indicate that the end of the circular buffer
is
// valid data as well.
if(!pqLogToPromState){
if(!buffroPromState && pqBuffInPnt!=pqBuffOutPnt){
pqLogToPromState=l;
pqBuffOutPnt++;
RamADDRESS = 0x4600+pqBuffOutPnt;
RAM_READ;
tempPromData = RamDATA&Oxff;
pqLogAddress++;
tempPromAddress = pqLogAddress&Ox3FFF;
if(tempPromAddress>Ox 1 FFF) {
pqLogAddress = 0x8600;
tempPromAddress = 0x0600;
if(tempPromAddress=pqScanPointer) {
if(pqScanEnd=2) {
pqScanEnd=0;
else {
pqScanEnd=1;
rtc write(OxF3,pqLogAddress»8);
rtc write(OxF4,pqLogAddress&OxFF);
write eeprom noDelay(tempPromAddress,tempPromData);
W
62

CA 02332297 2001-O1-25
else {
pqLogToPromState=0;
unsigned int pqScanRemaining(void) {
// This function returns the amount of data still to be scanned in the PQ &
// Communication events log. This is a circular buffer so the value returned
// from this function is more meaningful than comparing the pqScanPointer to
// pqLogAddress. This does not return a valid result if pqScanPointer is
// actually still in the RAM buffer.
if(pqLogAddress&0x8000) {
if(pqScanPointer>pqLogAddress)
tempPromAddress = pqScanPointer-pqLogAddress;
else
tempPromAddress = pqScanPointer+Ox l9ff pqLogAddress; // pqSP-0x600 + Ox 1 fff
pqLA
else {
tempPromAddress = pqScanPointer - 0x600;
;
if(pqScanEnd)
tempPromAddress=0;
return(tempPromAddress);
void pqScan(void) {
// This function returns the previous log entry from the PQ and communications
// Log. The eventType variable is set by the function and the data associated
// with the entry is put into a buffer in RAM including the number of bytes of
// data in the entry.
tempPromAddress = pqScanRemaining();
if(tempPromAddress){
eventType = read_ext_eeprom(pqScanPointer--):
if(pqScanPointer<Ox600) pqScanPointer = Ox 1 FFF;
if(eventType=OxFE)
tempPromData = 6;
else if(eventType=OxFD)
tempPromData = 0;
else if(eventType=OxFC ~~ eventType==OxFB)
tempPromData = 2;
else if(eventType>OxAD)
tempPromData = 4;
else if(eventType>OxAA)
tempPromData = 2;
else if(eventType>OxAO ~~ (eventType>Ox77 && eventType<Ox7D))
tempPromData = 4;
else if(eventType=0 ~~ (eventType>Ox70 && eventType<Ox80))
tempPromData = 2;
else
tempPromData = 3;
if(tempPromData<tempPromAddress){
RamADDRESS = Ox44F0;
RamDATA = tempPromData;
RAM_WRITE;
for(i=O;i<tempPromData;i++){
RamDATA = read ext eeprom(pqScanPointer--);
RAM_WRITE;
if(pqScanPointer<Ox600) pqScanPointer = (Ix 1 FFF;
return:
63

CA 02332297 2001-O1-25
l
l
pqScanEnd=I;
eventType=Oxff;
void pqScanReset(void){
// This function is used to set the pqScanPointer to the end of the PQ Log
// circular buffer. It also resets the flag pqScanEnd to 2 if there is part
// of the log in the RAM buffer and to 0 if the log is all in eeprom. tf
// pqScanEnd is set to 2 now then it will be set to 0 by pqLogToEeprom when
what
// is in the RAM buffer now is shuffled into the eeprom.
tempPromData = pqBufflnPnt-pqBuffOutPnt;
if(tempPromData) {
pqScanEnd=2;
else {
pqScanEnd=0;
pqScanPointer = pqLogAddress&Ox 1 fff;
pqScanPointer += tempPromData;
if(pqScanPointer>Oxlfff){
pqScanPointer -= Ox l9ff; // pqScanPointer - Ox 1 fff + 0x600
)
;
void getEventType(void);
if(eventType=0) received byte=0:
else if(eventType<Ox40)received byte=1;
else if(eventType<Ox~O)received byte=2;
else if(eventType<Ox70)received byte=3;
else if(eventType<Ox78)received byte=4;
else if(eventType<Ox7E) received byte=~;
else if(eventType<Ox80)received-byte=8;
else if(eventType<OxAO) received byte=1;
else if(eventType<OxA 1 ) received byte=9;
else if(eventType<OxA4) received byte=10;
else if(eventType<OxA7) received byte=1 I;
else if(eventType<OxAA) received byte=12;
else if(eventType<OxAB) received byte=13;
else if(eventType<OxBB) received_byte=14;
else if(eventType<OxCO) received byte=1~;
else if(eventT~~pe<OxFB) received byte=9;
else if(eventType<OxFC) received-byte=7;
else if(eventType<OxFD) received byte=6;
else received byte=7;
pqComparison = I;
pqComparison «= received byte;
i
/************************************************
External RAM functions
unsigned int ramReadInt(void);
void ramWriteInt(unsigned int integerToWrite);
unsigned char ramReadUchar(void);
************************************************/
unsigned int ramRead(nt(void){
unsigned int returnInt;
RAM READ;
64

CA 02332297 2001-O1-25 ,
returnInt = RamDATA«8;
RAM_READ;
returnInt += RamDATA&Oxff;
return(returnlnt);
;
void ramWriteInt(unsigned int integerToWrite){
RamDATA = integerToWrite»8;
RAM_WRITE;
RamDATA = integerToWrite&OxFF;
RAM WRITE;
unsigned char ramReadUchar(void){
RAM_READ;
return(RamDATA&Oxff);
T
J
unsigned char getByte( unsigned int address) {
terminatorFlag=0;
RamADDRESS=address;
itemp=0;
for (j=O;j<2;j++){
hemp *= 16;
RAM_READ;
i = RamDATA&Oxff;
if(i=;' II i=~'){
terminatorFlag = 0x03;
return(0);
i = toint(i);
if(i=OxFF);
terminatorFlag = 0x02;
return(0);
;
itemp += i;
return(itemp);
r
unsigned int getDecimal(void) {
hemp = 0;
terminatorFlag = 0x02; // Set Null flag
RamADDRESS=(start:
while (ltemp<10000){
RAM_READ;
(start++;
i = RamDATA&Oxff;
if((i=',7 II (~ - ~') II (~=/7 II (i- ':'))
if((i =':') II (i=:'))
terminatorFlag I= 0x01; // Set terminator Flag
return(Itemp);
else if(i<Ox30 II i>Ox39){
terminatorFlag = 0x02; // Set Null flag
messageStatus = NAK;
return(0);
r
i -= 0x30;
(temp *= 10:
GS

CA 02332297 2001-O1-25
(temp += i;
i
(start++; // To increment pointer beyond delimiter if a ~ digit number.
return(Itemp);
/************************************************
Conversions
char to ascii(char din);
char toint(char cin);
unsigned int meterFIoatToInt(unsigned char baseExponent);
************************************************/
char to_ascii(char din){ // convert byte to char. -3 I for error
if ((din>=0)&&(din<10)) return(din+48); // 0 to 9
if ((din>9)&&(din<16)) return(din+5~); // A to F
return (Oxff);
char toint(char cin){ // convert char to int. -1 for error
if ((cin>=0x30)&&(cin<=0x39)) return(cin-0x30); // 0 to 9
if ((cin>=0x41 )&&(cin<=0x46)) return(cin-~5); // A to F
if ((cin>=0x61 )&&(cin<=0x66)) return(cin-87): // a to f
messageStatus = NAK:
return(Oxff):
unsigned int meterFIoatTolnt(unsigned char baseExponent);
// using pqReportTime as a temporary variable here. It is always updated from
external RAM
// after this function is called.
pqReportTime = ramReadlnt();
RAM_READ;
received_bvte = RamDATA&Oxff;
if(received--byte<=baseExponent){
received-byte=baseExponent-received byte:
pqReportTime+=Ox7fff:
pqReportTime = pqReportTime»received byte;
else pqReportTime = Oxffff;
return(pqReportTime);
l
/******************************************************
Pager Interface (CLP commands & xmodem)
void yyy(void);
void yyl6(void);
void yyl7(void); // get configuration and product info.
void yyl8(void);
void getOption(void);
unsigned char yy 1 a(char option, char param);
void yy 1 b(void);
void check( unsigned char xmitbuf);
char xmod_data( void);
void pagerResetHard( void);
void reestablishPager(void);
//void pagerResetRealIyHard( void);
//void pagerResetSoft( void);
******************************************************/
void yyy(void){
66

CA 02332297 2001-O1-25 ,
if (!yyyState)
yyyState=1;
if (yyyState<4){
if (!putchPagerState && pagerComAbortTime<IastCentiTime) {
putchPager(Ox l9);
yyyState++;
else if (!putchPagerState) {
yyyState=0;
prepReceive(PAGER);
void yyl6(void){ //Ready to send packet
switch(yy 16State) {
case 0:
yy I 6State=1;
case l:
if(!yyyState){
ffYO;
yy 16State=2;
break;
case 2:
if (!yyyState && !putchPagerState) {
putchPager(Ox31 );
yy 16State++;
break;
case 3:
if(!putchPagerState) {
putchPager(Ox36);
yy 16State++;
;
break;
case 4:
if (!putchPagerState) {
putchPager(' ');
yy l6State++;
i
break;
case 5:
if (!putchPagerState) {
putchPager(Ox30);
yy 16State++;
1
break:
case 6:
if (!putchPagerState) {
temp 1=iPacketSize»8;
tempt=to_asci i(temp 1 );
putchPager(temp2);// number of chars in message 2nd nibble
yy 16State++;
;
break;
case 7:
if (!putchPagerState) {
temp I=iPacketSize»4:
tempt=temp 1 ~:OxOf;
67

CA 02332297 2001-O1-25 ,
tempi=to_ascii(temp2);
putchPager(temp3);1/ number of chars in message 3rd nibble
yy 165tate++;
break;
case 8:
if (!putchPagerState) {
temp 1=iPacketSize&OxOf;
tempt=to_ascii(temp 1 );
putchPager(temp2);// number of chars in message to nibble
yy 16State++;
break;
case 9:
if (!putchPagerState) {
putcPager(Ox 19);
yy 16State++;
pagerResponse=0;
pagerComAbortTime=lastCentiTime+j00;
)
break;
case 10:
if (kbhitPager()) {
received byte = getc(PAGER);
if(received_byte==EOT);
yy 16State++;
pagerComAbortTime=IastCentiTime+j00;
i
else yy l6State=0:
else if (pagerComAbortTime<lastCentiTime) yy l6State=0;
break:
case 11:
if (kbhitPager()){
received byte = getc(PAGER);
if(received byte==NAK){
pagerResponse=1;
)')' l6State=0;
;
else if (pagerComAbortTime<IastCentiTime) yy l6State=0;
break;
r
void yyl7(void){ // get configuration and product info
switch(yy 175tate) {
case 0:
yy l7State=1:
break;
case 1:
if (!yyyState) {
y)')'0;
)')' 17State=2;
f
break;
case 2:
if (!yyyState && !putchPagerState) {
if(productInfo)
putchPager(Ox33);
68

CA 02332297 2001-O1-25
else
putchPager(Ox31 );
yy 17State++;
i
break;
case 3:
if (!putchPagerState) {
putchPager(Ox37);
yy 17State++;
}
break;
case 4:
if (!putchPagerState) {
putcPager(Oxl9);
yy 17State++;
pagerResponse=0;
pagerComAbortTime=IastCentiTime+500;
r
break;
case 5:
if (kbhitPager()) {
received byte = getc(PAGER);
writeToSendBuffer(received_byte);
pagerResponse++;
if ((productInfo && pagerResponse>2) ~~ (!productInfo && pagerResponse>33))
yyl7State++;
pagerComAbortTime=IastCentiTime+500;
r
else if (pagerComAbortTime<IastCentiTime) yyl7State=0:
break;
case 6:
yy l7State=0;
pagerComAbortTime=lastCentiTime+~00;
break:
}
void yy 18(void) { // get status
switch(yy 18State) {
case 0:
yyl8State++;
RamADDRESS = Ox50C0;
RamDATA = 0;
for(pagerResponse=O:pagerResponse<43;pagerResponse++){
RAM_WRITE;
;
break;
case 1:
if (!yyyState){
YYYO>
yy 18State++;
}
break;
case 2:
if (!yyyState && !putchPagerState) {
putchPager(Ox31 );
yy I 8State++;
break;
case 3:
if (!putchPagerState) {
69

CA 02332297 2001-O1-25
putchPager(Ox38);
yy 18State++;
break;
case 4:
if (!putchPagerState) {
putcPager(Ox 19);
yy 18 State++;
pagerResponse=0;
pagerStatus 1=0;
pagerStatus2=0;
pagerComAbortTime=lastCentiTime+500;
i
break;
case 5:
if (kbhitPagerQ){
RamDATA = getc(PAGER);
RamADDRESS = Ox50C0 + pagerResponse;
RAM_WRITE;
pagerResponse++;
if (pagerResponse>42) yyl8State++;
pagerComAbortTime=lastCentiTime+j0;
i
else if (pagerComAbortTime<IastCentiTime) yy l8State=0;
break;
case 6:
RamADDRESS = Ox~OCO; // Transmit short message flag
RAM_READ;
pagerStatusl =RamDATA&Oxff;
pagerStatusl =toint(pagerStatusl);
pagerStatusl &=OxOE;
pagerStatusl «= 4;
RAM_READ; // Transmit message flag
pagerStatus2 = RamDATA&Oxff:
pagerStatus2 = toint(pagerStatus2);
received byte = pagerStatus2&OxOE;
pagerStatusl~= received byte«1;
RAM_READ; // Device Busy
received byte = RamDATA&0x01: // Either 0x30 or 0x31
pagerStatusl ~=received byte«1;
RAM_READ; // Out of Range
received byte = RamDATA&0x01; // Either 0x30 or 0x31
pagerStatusl ~= received byte;
pagerStatus2 &= l; // Unread Message
pagerStatus2 «= 3;
RAM_READ; // Transmitter Status
received byte = RamDATA~R,OxOI; // Either 0x30 or Ox31
pagerStatus2 ~= received byte«1;
RAM_READ; // Battery Status
received byte = RatnDATA&Oxff;
pagerStatus2~= received byte«4;
RamADDRESS = Ox50D0; // Registration Status
RAM_READ:
received byte = RamDATA&0x01; // Either 0x30 or 0x31
pagerStatus2 ~= received_byte;
RAM_READ; // Message Status
received byte = RamDATA&0x01;
pagerStatus2 ~= received byte«2;
yy 18State=0;
if(pagerDiagnostics &R, ((pagerStatusl!=oldStatusl) ~~
(pagerStatus2!=oldStatus2)));

CA 02332297 2001-O1-25 ,
pqLog(pagerStatus2);
pqLog(pagerStatus 1 );
pqLog(timeOfDay&OxFF);
pqLog(timeOfDay»8);
pqLog(Ox79);
oldStatusl =pagerStatusl;
oldStatus2 = pagerStatus2;
pagerComAbortTime=lastCentiTime+500;
break;
void getOption(void){
switch(getOptionState) {
case 0:
getOptionState=1;
pagerOption 1=0;
pagerOption2=0;
break;
case 1:
if (!yyyState){
YYYO
getOptionState=2;
break;
case 2:
if (!yyyState &R. !putchPagerState) {
putchPager(Ox3 I );
getOptionState++;
break:
case 3:
if (!putchPagerState) {
putchPager('a');
getOptionState++;
l
break;
case 4:
if (!putchPagerState) {
putchPager(' ');
getOptionState++;
break;
case ~:
if (!putehPagerState) {
putehPager(optionToGet);
getOptionState++;
break;
case 6:
if (!putchPagerState) {
putcPager(Oxl9);
getOptionState++;
pagerComAbortTime=lastCentiTime+500;
i
break;
case 7:
if (kbhitPager()) {
received byte = getc(PAGER);
71

CA 02332297 2001-O1-25 ,
if (received byte = NAK){
getOptionState = 0;
pagerOption2 = NAK;
else if (received byte = OxFF){
getOptionState++;
else {
getOptionState = 9;
pagerOption 1 = received byte;
pagerComAbortTime=lastCentiTime+j00;
r
else if (pagerComAbortTime<IastCentiTime) getOptionState=0;
break;
case 8:
if (kbhitPagerQ){
pagerOption 1 = getc(PAGER);
getOptionState++;
pagerComAbortTime=IastCentiTime+j00;
r
else if (pagerComAbortTime<IastCentiTime) getOptionState=0:
break:
case 9:
if (kbhitPager()) {
pagerOption2 = getc(PAGER);
getOptionState=0;
pagerComAbortTime=IastCentiTime+j00;
i
else if (pagerComAbortTime<IastCentiTime) getOptionState=0;
break;
1
1
1
unsigned char yyla(char option, char param);
putcPager(Oxl9);
delay_ms(40):
putcPager(Ox 19);
delay_ms(40);
putcPager(Ox 19);
delay_ms(40);
putcPager(' 1');
delay _ms(40);
putcPager('a');
delay_ms(40);
putcPager(' ');
delay_ms(40);
putcPager(option);
delay_ms(40);
prepReceive(PAGER);
if (param=Oxff) {
putcPager(Oa 19);
r
else{
putcPager(' ');
delay_ms(40);
putcPager(param);
delay_ms(40);
putcPager(Oal9);
77

CA 02332297 2001-O1-25 ,
while (!kbhitPager()); // Can Watch Dog TimeOut here.
itemp=getc(PAGER);
return(itemp);
void yylb(void){ // Read message and Delete
switch(yy 1 bState) {
case 0:
yy 1 bState=1;
case 1:
if (!yyyState){
YYYO
yy 1 bState=2;
break;
case 2:
if (!yyyState && !putchPagerState) {
putchPager(Ox31);
yy 1 bState++;
break;
case 3:
if (!putchPagerState) {
putchPager('b');
yy 1 bState++;
break;
case 4:
if (!putchPagerState) {
putcPager(Ox 19);
~~y 1 bState++;
pagerResponse=0;
pagerComAbortTime=IastCentiTime+~00;
i
break;
case ~:
if (kbhitPagerQ) {
received byte = getc(PAGER);
if(received_byte=EOT){
pagerResponse=1;
y~~ 1 bState=0:
else if(pagerComAbortTime<lastCentiTime) yylbState=0;
break;
i
void check( unsigned char xmitbuf){
putcPager(xmitbuf);
checksum = checksum + xmitbuf;
j++;
ltemp3++;
r
char xmod_data( void)
unsigned char i;
switch(xmod dataState) {
case 0:
xmod dataState++;
73

CA 02332297 2001-O1-25
j=0;
checksum = 0;
putcPager(SOH);
putcPager(blockNum);
putcPager(-blockNum);
if (blockNum = 1 ){
if(binaryFlag&&(!status)) check(OxF7);
else check(OxFD);
check(OxIA);
if(useTempAddress) hemp = 0x42;
else hemp = Ox I F;
for(i=O;i<headerSize;i++){
if(useTempAddress)
received byte = rtc read(itemp+i);
else
received byte = read ext eeprom(itemp+i);
if(received_byte=','){
check(OxIF);
// if(binaryFlag&&(!status)) check(OxIF);
check(Ox lA);
L
1
else check(received byte);
i
1
check(OxIF);
if(binaryFlag&&(!status)) check(OxIF);
check(':');
if (padHeaderEven) check(':');
Itemp3=headerOverhead;
if(status!=2){
for(i=O;i<4;i++){
if((binaryFlag)&&(!status)) {
check(preamble[i]);
1
1
else {
temp 1=preamble[i]4;
tempt=to_ascii(templ);
check(temp2):
temp 1=preamble[i]&OxOf;
tempt=to_ascii(temp 1 );
check(temp2);
1
1
for(packetStart;packetStart<packetEnd;packetStart++) {
RamADDRESS = packetStart+OFFSET3:
RAM READ;
hemp = RamDATA&Oxff;
if((status)~~(binaryFlag));
check(itemp);
else{
temp 1=hemp»4;
tempt=hemp&OxOf;
tempi=to_ascii(temp 1 );
check(temp3);
tempi=to_ascii(temp2);
check(temp3);
1
;
74

CA 02332297 2001-O1-25 ,
while (j < 128){
putcPager(0);
j++;
r
putcPager(checksum);
pagerResponse=0;
break;
case 1:
if(!PIElbits.TXIIE){ // Wait until all characters have gone out.
pagerComAbortTime = IastCentiTime+500;
xmod dataState=2;
break:
case 2:
if(kbhitPagerQ){
pagerResponse=getc(PAGER);
xmod dataState=0;
else if (pagerComAbortTime<lastCentiTime) xmod_dataState=0;
break;
void pagerResetHard( void){
switch(pagerResetHardState){
case 0:
pagerResetHardState++;
break;
case 1:
pagerResetHardState++;
PAGER RESET_EN_OUTP = 1; // Turn Pager Reset Enable On
PAGER RESET_OUTP = 0; /! Turn Pager Reset Active
pagerComAbortTime = lastCentiTime+1 ~;
break;
case 2:
if (pagerComAbortTime<lastCentiTime);
pagerResetHardState++;
PAGER RESET OUTP = 1; // Turn Pager Reset Inactive
PAGER RESET_EN OUTP = 0: // Turn Pager Reset Enable Off
pagerComAbortTime = IastCentiTime+800:
a
r
break;
case 3:
if (pagerComAbortTime<IastCentiTime)
pagerResetHardState=0;
break;
1
1
void reestablishPager(void) {
switch(reestablishPagerState) {
case 0:
reestablishPagerState++;
break;
case 1:
pagerResetHard();
reestablishPagerState++;
break:
case 2:
if(!pagerResetHardState){
7J

CA 02332297 2001-O1-25
reestablishPagerState++;
pagerPollTimeout=timeOfDay+300; // 10 minutes.
break;
case 3:
fY 18()>
reestablishPagerState++;
break;
case 4:
if(!yyl8State){
reestablishPagerState++;
if(pagerResponse!=43)
reestablishPagerState=7;
break;
case 5:
reestablishPagerState++;
if(pagerStatusl ~~ ((pagerStatus2&3)!=3))
reestablishPagerState=7;
break;
case 6: // All OK
reestablishPagerState=0;
pqLog(timeOfDay&OxFF);
pqLog(timeOfDay»8);
pqLog(Ox7D);
break;
case 7:
if(pagerPollTimeout<timeOfDay){ // 10 minutes elapsed, Abort!
reestablishPagerState=0;
pqLog(pagerStatus2);
pqLog(pagerStatus 1 );
pqLog(timeOfDay&OxFF);
pqLog(timeOfDay»8);
pqLog(Ox7C);
;
else {
reestablishPagerState=3;
break;
/******************************************************
Meter Interface (DGCOM)
char handshake( void);
char unlock( void):
void findClip( unsigned char command);
char clipFound( void);
void getLPdata( void);
char isLPenabled( void);
void sendLPerror( void);
void calcLPsize(void);
void calcStart( void);
void pqCalc(void);
void pqPoll(void);
void sendCommand(void);
void executeMultipleCommands(unsigned int start);
void compressLPdata(void);
void getChannellnfo(void); // Restores OIdV and cMode for this channel.
76

CA 02332297 2001-O1-25
void compressScan(void);
******************************************************~
char handshake( void){
switch(handshakeState) {
case 0:
badHandshake=0;
handshakeState++;
case 1:
prepReceive(METER);
putchMeter(Ox55);
meterComAbortTime = lastCentiTime+4;
handshakeState++;
badHandshake++;
if(badHandshake>5)
handshakeState=0;
case 2:
if (kbhitMeter()){
noMeterResponse=0;
if (getc(METER) != 0x55)
handshakeState=l;
else {
handshakeState++;
putchMeter(OxAA);
meterComAbortTime = IastCentiTime+4:
1
I
else if (meterComAbortTime<lastCentiTime) handshakeState=1:
break;
case 3:
if (kbhitMeter()){
if (getc(METER) = OxAA) {
badHandshake=0:
handshakeState=0;
;
else {
handshakeState=1;
i
i
else if (meterComAbortTime<IastCentiTime) handshakeState=l;
break;
1
1
char unlock( void){
switch(unlockState){
case 0:
sum=Ox00ff;
if(whichPass =1){
sum+=meterl Passes;
sum+=meter l PassM;
sum+=meterl PassL:
else {
sum+=meter2PassH;
sum+=,neter2PassM;
sum+=meter2PassL;
unlockState++;
break;
77

CA 02332297 2001-O1-25
case 1:
putchMeter(OxFF);
if(whichPass=1 ) {
putchMeter(meter 1 PassH);
putchMeter(meterl PassM);
putchMeter(meterl PassL);
f
else {
putchMeter(meter2PassH);
putchMeter(meter2PassM);
putchMeter(meter2PassL);
l
putchMeter( 1 );
putchMeter(1);
sum += 2;
for(i=O;i<3; i++) {
putchMeter(0);
putchMeter(sum&OxFF): // LSB
putchMeter(sum » 8); // MSB
meterComAbortTime = IastCentiTime+4;
unlockState++;
break;
case 2:
if(kbhitMeter()){
meterResponse = getc(METER);
unlockState++;
i
else if (meterComAbortTime<IastCentiTime) {
unlockState=0;
i
break;
case 3:
unlockState=0;
if(meterResponse == 0x99)
unlockState=1;
i
else if ((meterResponse =- Oxdd)~~(meterResponse - 0x33)){
i
break;
L
void findClip( unsigned char command){
clipPointer-1;
RamADDRESS=0x5080;
RAM_READ;
received byte = RamDATA&Oxff;
if(received byte-command){
return;
while(clipPointer<(CLIPSIZE-4)){
RAM_READ;
received byte = RamDATA&Oxff;
clipPointer++;
if(received byte=Oxff){
RAM_READ;
received byte = RamDATA&Oxff:
clipPointer++;
if (received byte-command) {

CA 02332297 2001-O1-25 ,
return;
clipPointer=0;
char clipFound( void){
RamADDRESS=clipPointer+0x5080;
RAM_READ;
received byte = RamDATA&Oxff;
if(received byte!=Oxffj {
offset += distance;
offset += received byte;
RAM_READ;
distance = RamDATA&Oxff;
clipPointer += 2;
return(TRUE);
i
return(FALSE);
1
f
void getLPdata( void){
switch(getLPdataState) {
case o:
command[0]=4;
for(i=l;i<1 1:i++) command[i]=0:
command[9]=4;
sendFlag=FALSE;
sendCommandp;
getLPdataState=1;
break;
case l:
if(!sendCommandState) {
RamADDRESS = Ox4b02;
LPinterval = ramReadUchar();
if (LPinterval==0) {
RamADDRESS = Ox4b00;
LPinterval = ramReadUchar();
if (LPinterval&0x40) LPinterval=l;
else if (LPintervalROx20) LPinterval=5:
else if (LPinterval&4) LPinterval=30;
else if (LPinterval&2) LPinterval=15;
else LPinterval=60;
;
RamADDRESS = Ox4b01;
LPchannels = ramReadUcharQ;
RamADDRESS = Ox4b03:
LPavailable = ramReadlnt():
getLPdataState=0;
break;
;
char isLPenabled( void){
switch(isLPenabledState){
case 0:
79

CA 02332297 2001-O1-25
hadLPerror=0;
lindexSave=lindex;
command[0]=OxSa;
for(i=l;i<ll;i++) command[i]=0;
command[9]=OxSa;
sendFlag=FALSE;
sendCommand();
isLPenabledState=1;
break;
case I:
if(! sendCommandState) {
RamADDRESS = 0x4600;
tempi =ramReadUchar();
if (temp 1 &8)
isLPenab(edReturn=1;
else {
if (temp 1 &4)
tempt=2;
else
tempt=1;
isLPenabledReturn=0:
sendLPerror();
isLPenabledState=0;
break;
)
1
J
void sendLPerror( void) {
lindex=IindexSave;
writeStringToSendBuffer(sBF03FF);
writeToSendBuffer(temp2);
hadLPerror=1:
;
void calcLPsize(void){
Itemp3 = time.hr;
Itemp3 *= 60;
ltemp3 += time.min;
Itemp3 /= LPinterval;
ltemp3 += 15; // Padding.
Itemp2 = 1440/LPinterval; // # of intervals per day.
ltemp2 += 15; // Padding.
Itemp2 *= LPdays;
ltemp2 += ltemp3; // Total # of Intervals.
ltemp2 *= LPchannels;
tempt=(Itemp2/512)+1; // # of k Rounded up.
command[0]=3;
command[1]=tempi;
command(10]=0;
command[9]= tempi+3;
1
l
void calcStart( void);
startMonth=endMonth;
startDay=endDay;
startDay-=LPdays;
if (startDay<=0){
startMonth--;
if ((startMonth = 4)~~(startMonth---6)~~(startMonth-9)I~(startMonth==1 1 ));

CA 02332297 2001-O1-25
startDay=30+startDay;
else;
if (startMonth=2)(
if ((time.yr)%4)
startDay=28+startDay;
else
startDay=29+startDay;
r
else;
startDay=31+startDay:
if (startMonth=0)
startMonth=12:
startDay=to bcd(startDay);
startMonth=to bcd(startMonth);
startMonth~=0x80;
if(!C,Pdays)
endDay++;
#pragma code sendCommand = Ox40C0
void sendCommand(void);
unsigned char i.block;
switch(sendCommandState);
case 0:
if (sendFlag);
convertAndV'riteToSendBuffer(OxBF);
convertAndWriteToSendBuffer(command[0]);
convertAndWriteToSendBuffer(OxFF);
i
r
sendCommandState=1;
break;
case I:
if(!pqPoIlState);
findClip(command[0]):
offset=0;
distance=0:
totalBlocks=1;
totalB~~tesFromMeter=0;
switch(command[0]){ // These commands have multiple packet returns.
// All others have single packet returns.
case 3:
totalBlocks=command[1 ]* 8;
break;
case Ox06:
totalBlocks=7:
break;
case 0x09:
case OxAB:
totalBlocks=~:
break;
case Ox 10:
totalBlocks=3;
break;
case 0x98:
totalBlocks=2;
g]

CA 02332297 2001-O1-25
break;
case OxAB:
totalBlocks=11:
break;
; // switch
block=1;
neverFound=TRUE;
dateFound=FALSE;
handshake();
sendCommandState=2;
if(acOKtimer){
sendCommandState=0;
badSendCommand=11;
break;
case 2:
if (!handshakeState){
if (badHandshake){
badSendCommand=I ;
sendCommandState=0;
1
l
else {
if (unlockFlag) {
unlockQ;
sendCommandState++;
i
else {
sendCommandState=5;
;
break;
case 3:
if(!unlockState){
sendCommandState=5;
i
l
break;
case 4: // Just waiting here for more data when multiple data packets to
break; // meter. executeMultipleCommands will change to next state.
case 5:
for(temp2=O;temp2< 1 I ;tempt++)
putchMeter(command[tempt]);
r
sendCommandState=6:
break;
case 6:
if(!PIE2bits.TX2IE) { // Wait until all characters have gone out.
meterComAbortTime = lastCentiTime+10;
sendCommandState=7;
meterResponse = 0;
r
break;
case 7:
if (kbhitMeter()) {
meterResponse = gete(METER):
if (meterResponse = 0x33) { // Transmission Accepted
if (unlockFlag){
meterComAbortTime = IastCentiTime+10:
unlockFlag = 0;
82

CA 02332297 2001-O1-25
else
meterComAbortTime = lastCentiTime+$0;
justDataToMeter-0;
sendCommandState=8;
else if (meterResponse = 0x99){ // Checksum error - resend
sendCommandState=5;
else if (meterResponse=0x66 && moreDataToMeter) {
sendCommandState=4;
else { // Command not accepted
sendCommandState=0;
badSendCommand=2;
else if (meterComAbortTime<IastCentiTime) {
sendCommandState=0;
badSendCommand=3;
break;
case 8:
if (kbhitMeter()) {
bytesFromMeter = getc(METER);
meterDataChksum=bytesFromMeter;
MbuffPointer = 0;
meterComAbortTime = lastCentiTime+10;
sendCommandState=9;
)
else if (meterComAbortTime<lastCentiTime) {
sendCommandState=0;
badSendCommand=4;
i
break;
case 9:
if (kbhitMeter()) {
received byte = gete(METER);
meterDataChksum = meterDataChksum + received byte:
RamDATA = received byte;
RamADDRESS = Ox4B00 + MbuffPointer;
RAM_WRITE;
MbuffPointer++;
meterComAbortTime = IastCentiTime+10;
if (MbuffPointer>=bytesFromMeter){
sendCommandState=10;
l
1
else if (meterComAbortTime<IastCentiTime) {
sendCommandState=0,
badSendCommand=~;
i
break;
case 10:
if (kbhitMeterQ){
received byte = getc(METER);
meterDataChksum-=received byte;
meterComAbortTime = lastCentiTime+10:
sendCommandState=1 1;
;
83

CA 02332297 2001-O1-25 ,
else if (meterComAbortTime<IastCentiTime) {
sendCommandState=0;
badSendCommand=6;
break;
case 11:
if (kbhitMeter()){
received byte = getc(METER);
sendCommandState=0;
if (meterDataChksum&Oxff) {
badSendCommand=7;
putchMeter(Ox33);
else {
meterDataChksum = meterDataChksum»8;
if (meterDataChksum!=received_byte){
badSendCommand=8;
putchMeter(Ox33);
else if(block < totalBlocks){
sendCommandState=13;
// Next Packet can come in while processing previous.
putchMeter(Ox66);
meterComAbortTime = lastCentiTime+10;
)
else {
sendCommandState=13;
putchMeter(Ox33);
else if (meterComAbortTime<IastCentiTime) {
sendCommandState=0;
badSendCommand=9;
)
break;
case 13:
if (sendFlag){
if (economyFlag && clipPointer && command[0]!=3){
for(;;) {
if(offset>(totalBytesFromMeter+bytesFromMeter)) break;
else if ((offset+distance)<=totalBytesFromMeter);
if(!clipFound()) break;
r
else {
if (offset<=totalBytesFromMeter)
startByte=0;
else
startByte = offset - totalBytesFromMeter;
if ((offset+distance) <_ (totalBytesFromMeter+bytesFromMeter))
endByte = offset+distance-totalBytesFromMeter;
else
endByte = bytesFromMeter;
for(i=startByte;i<endByte;i++) {
// received_byte=Mbuffer[i];
RamADDRESS = Ox4b00 + i;
received byte = ramReadUcharQ;
convertAndWriteToSendBuffer(received_b~~te);
if(endByte<=bytesFromMeter) {
84

CA 02332297 2001-O1-25
if(!clipFound()) break;
1
l
)
else{ //(!econoFlag~~command[0]-3)
for(i=0; i<bytesFromMeter; i++) {
ClrWdtQ;
RamADDRESS = Ox4b00 + i;
received byte = ramReadUchar();
if ((command[0]==3) && economyFlag);
if (dateFound){
writeToSendBuffer(received byte);
if (lindex >= 2500){
tempt=3;
sendLPerror();
sendCommandState=0;
badSendCommand=l0;
return;
;
if (!(i&1)){ // ever~~ other byte
/l tempt=Mbuffer[i+I]:
RamADDRESS = Ox4b00 + i + 1;
temp 1 = ramReadUchar();
temp I=temp 1»6;
if (onlyDates&&((temp 1-2)~~(temp 1=3))){
if ((tempt=2)~~(onl~~Dates---3)){
RamADDRESS = Ox4b00 + ];
received byte = ramReadUcharQ;
writeToSendBuffer(received byte);
RamADDRESS = Ox4b00 + i + 1;
received b~~te = ramReadUchar();
writeToSendBuffer(received b~~te);
;
else if (temp 1=2)
RamADDRESS = Ox4b00 + i:
received_byte = ramReadUcharQ;
hemp = ramReadUchar():
if (dateFound);
if
(((received byte>=endDay)&&(itemp==endMonth))~~(itemp>endMonth)) {
writeToSendBuffer(itemp);
lindex-=2; // Kill last dateStamp
dateFound=FALSE;
else {
if ((received_byte==startDay)&:.&(itemp-startMonth));
writeToSendBuffer(received_byte):
dateFound=TRUE;
neverFound=FALSE;
i
)
else{convertAndVv'riteToSendBuffer(received byte):
)

CA 02332297 2001-O1-25
1
1
1
1
1
1
if (block < totalBlocks);
block++;
totalBytesFromMeter+=bytesFromMeter;
sendCommandState=8;
else
sendCommandState=14;
break;
case 14:
if ((((command[0]=3) && economyFlag)&&neverFound)&&!onlyDates){
tempt=4;
sendLPerrorQ;
r
if(sendFlag && !(command[0]==3 && compressionEnabled && !hadLPerror))
IindexSave=lindex;
badSendCommand=0: // Send completed OK
sendCommandState=0;
break;
i
void executeMultipleCommands(unsigned int start) {
switch(executeMultipleState) {
case 0:
unlockFlag = 0;
moreDataToMeter = 0;
]ustDataToMeter = 0;
execMultiPointet=start-I;
last byte-=, ,
executeMultipleState=2:
break;
case I:
RamADDRESS=execMultiPointer;
RAM READ;
last byte = RamDATA&Oxff;
executeMultipleState=2;
break:
case 2:
if(last_byte !_';' && last_byte !_':');
iMCmnd=0:
sum=0;
if(moreDataToMeter) {
if(meterResponse!=0x66){ // If you have more data
// but the meter doesn't want it, flush it.
while((last byte !_ ;')&&(last byte !_':')&&(last byte !_',')&&(last byte
!_'.'));
execMultiPointer++;
RamADDRESS=execMuItiPointer;
RAM_READ;
last byte = RamDATA&Oxff;
sendCommandState=0;
;
else {
sum=command[0];
iMCmnd++:
justDataToMeter=1;
;
86

CA 02332297 2001-O1-25
moreDataToMeter = 0;
if((last byte =',')~~(last byte ='.'));
execMultiPointer++;
RamADDRESS=execMultiPointer;
RAM_READ;
last byte = RamDATA&Oxff;
if(last byte ='S'){
messageEnd = 0;
while (last byte !_ ;'){
execMultiPointer++;
RamADDRESS=execMuItiPointer;
RAM_READ;
last byte = RamDATA&Oxff;
RamADDRESS = messageEnd + pFFSET2;
RAM_WRITE;
messageEnd++;
runSSIcommand=I;
executeMultipleState=0;
elseif(last byte='L')[
execMultiPointer++:
RamADDRESS=execMuItiPointer;
RAM_READ;
whichPass = RamDATA&Oxff;
whichPass = toint(whichPass);
execMultiPointer++;
RAM_READ;
last byte = RamDATAR.Oxff;
r
while(last byte!=;' && last byte!--':' && last byte!=,' && last byte!='.' &~.
!moreDataToMeter);
hemp=getB~ te(execMultiPointer):
command[iMCmnd]=hemp:
sum+=command[iMCmnd];
execMultiPointer+=2;
iMCmnd++;
RamADDRESS=execMultiPointer;
RAM_READ;
last byte = RamDATA&Oxff;
if ((iMCmnd>8) && (last byte !_';') && (last byte !_':') && (last byte !_'.')
&& (last byte !_
s
moreDataToMeter = I ;
1
if(!runSSIcommand);
if(iMCmnd!=1) unlockFlag=1;
for(;iMCmnd<9;iMCmnd++) command[iMCmnd]=0:
tempSum=sum;
command[10]=sum » 8;
command[9]=sum&OxFF;
executeMultipleState=3;
else executeMultipleState=0;
break;
case 3:
if (command[0] = 3){
unlockFlag=0:

CA 02332297 2001-O1-25
lindexSave=(index;
LPdays=command[I];
isLPenabledQ;
executeMultipleState=4;
;
else executeMultipleState=6;
break;
case 4:
if (! isLPenabIedState) {
if(isLPenabledReturn){
if(economyFlag) {
getLPdataQ;
executeMultipleState=5;
l
else {
command[0]=3;
command[ 1 ]=LPdays;
command[10]=tempSum » 8; // GMS check if 0 good enough
command[9]=tempSum&.OxFF;
executeMultipleState=6;
else {
sendLPerror();
executeMultipleState=2;
break:
case ~:
if(!getLPdataState);
endDay=time.day;
endMonth=time.mth:
calcStart();
endDay=to bcd(endDay);
endMonth=to bcd(endMonth);
endMonth~=0x80;
caIcLPsizeQ;
executeMuItipIeState=6;
break;
case 6:
sendFlag=TRUE;
if~justDataToMeter) sendCommandState=~:
if (command[0]=0x21 ~~ command[0]=0x22) {
timeChanged=1;
timeSynehMode=2;
sendCommand();
executeMultipleState=7;
break;
case 7:
if(!sendCommandState ~~ sendCommandState= 4){
if(command[0]=3 && compressionGnabled && !hadLPerror);
compressLPdataQ;
executeMultipleState=0:
i
else {
executeMultipleState=2;
;
1
1
88

CA 02332297 2001-O1-25
break;
void compressLPdata(void){
// Before starting the compression routine:
// lindex+OFFSET3 points to one address location beyond the end of LP data.
// IindexSave+OFFSET3 points to the beginning of the BF03Ff sequence.
// Save lindex+OFFSET3-1 in cEndLPdata; lindex should be reset to
lindexSave+3;
// lindex will be incremented by writeToSendBuffer();
// unsigned int's
#define cOldV pqComparison
#define cValue pqStartTime
#define cInPnt pqReportTime
#define cEndLPdata pqOfffime
#define cNewV pqValue
l/ unsigned char's
#define cDeItaVnegative pqEvent
#define cDateStamp pqInProgress
#detine cChannel pqDurationLimit
#detine cMode pqReportDelay
#define cScanResult pqEventStatus
#define cTempChannel pqReminderDelay
cEndLPdata = lindex+OFFSET3-I ;
lindex = IindexSave + 3;
cInPnt = lindex+QFFSET3;
RamADDRESS = 0x5300;
RamDATA=0;
for(eChannel=O;cChannel<Ox30;cChannel++) {
RAM V'RITE;
cChannel=0:
getChannelInfo(); // Restores OIdV and cMode for this channel.
mhile(clnPnt<cEndLPdata) {
CIrWdt();
RamADDRESS=clnPnt+1:
RAM_READ;
received_byte = RamDATA&Oxff;
if ((received byte&0x80)=0){
cDateStamp = 0;
cIv'ewV = received byte&Ox3f;
cNewV «= 8;
RamADDRESS=clnPnt;
RAM_READ;
cNewV += RamDATA&Oxff;
if (cNewV<cOldV) {
cOldV -= cNewV;
cDeltaVnegative = 1;
i
else {
cOldV = cNewV - cOldV;
cDeltaVnegative = 0;
else {
cDateStamp= 1;
cNewV = received byte;
cNewV «= 8;
89

CA 02332297 2001-O1-25
RamADDRESS=cInPnt;
RAM_READ;
cNewV += RamDATA&Oxff;
if(cMode){ // In Compression.
if(cOldV>506 ~~ cDateStamp){
compressScanQ;
if(cScanResult) {
writeToSendBuffer(Ox82);
)
else {
writeToSendBuffer(Ox8 l );
cMode = 0;
t
writeToSendBuffer(cNewV&Oxft);
writeToSendBuffer(cNewV8);
else {
if(cOldV>379) {
writeToSendBuffer(Ox80);
cOldV -= 379;
else if(cOIdV>252){
writeToSendBuffer(Ox7f);
cOldV -= 252;
else if(cOIdV>125){
writeToSendBuffer(Ox7e);
cOldV -= 125;
)
if(cDeltaVnegative){
cOldV--;
cOIdV ~= Oxff;
writeToSendBuffer(cOldV&Oxff);
r
1
l
else { // Not In Compression.
if(cOIdV<l26 && !cDateStamp){
compressScan();
if(cScanResult){
if(cDeItaVnegative)
coldV--;
cOIdV ~= Oxff;
writeToSendBuffer(cOIdV&Oxff);
writeToSendBuffer(OxFF);
cMode = 1;
else {
writeToSendBuffer(cNewV&Oxff);
writeToSendBuffer(cNewV8);
else {
writeToSendBuffer(cNewV&Oxff);
writeToSendBuffer(cNewV8);
r
t
if(!cDateStamp){

CA 02332297 2001-O1-25
cOldV = cNewV;
// Save OIdV and cMode for this channel.
RamADDRESS = 0x5300 + (cChannel*3);
ramWriteInt(cOIdV);
RamDATA = cMode;
RAM fVRITE;
cChannel++;
cChannel %= LPchannels;
getChannelInfoQ; // Restores OIdV and cMode for this channel.
cInPnt += 2;
IindexSave = lindex;
void getChannelInfo(void) { // Restores OIdV and cMode for this channel
RamADDRESS = 0x5300 + (cChannel*3);
cOIdV = ramReadInt();
RAM_READ;
cMode = RamDATA&Oxff;
void compressScan(void){
// Save cOldV, cInPnt and cNemV in external RAM and restore when completed
scan
RamADDRESS = 0x5330;
ramWriteInt(cOIdV);
ram WriteInt(cInPnt);
ramWriteInt(eNewV);
cTempChannel = cChannel;
if(!cDateStamp)
cOldV = cNewV;
cTempChannel ++;
cTempChannel %= LPchannels;
i
cInPnt += 2;
cScanResult= 1;
while(cInPnt<cEndLPdata){
RamADDRESS=cInPnt+1;
RAM_READ;
received byte = RamDATA&Oxff;
if ((received byte&0x80)=0) {
if(cTempChannel---cChannel) {
cNewV = received byte&Ox3f:
cNewV «= 8; _ y
RamADDRESS=cInPnt;
RAM_READ;
received byte = RamDATA&Oxff;
cNewV += received byte;
if (cNewV>cOldV) cOIdV = cNewV - cOldV;
else cOIdV -= cNewV;
if (cOldV<126) clnPnt = cEndLPdata; // Return true.
if (cOIdV>506){
cInPnt = cEndLPdata;
cScanResult = 0; // Return false.
i
cOIdV = cNewV;
r
cTempChannel++;
91

CA 02332297 2001-O1-25
cTempChannel %= LPchannels;
else if(cTempChannel=cChannel) {
cInPnt = cEndLPdata;
cScanResult = 0; // Return false.
clnPnt += 2;
RamADDRESS = 0x5330;
cOldV = ramReadlnt();
cInPnt = ramReadInt();
cNewV = ramReadInt();
i
void CaIcCRC(unsigned char data){
unsigned char i;
for(i=O;i<8; i++)
{
_asm
BANKSEL crc
BCFOx4,Ox0
RLCF crc
RLCF crc+1
// if(carry flag
set)
BTFSS Ox4,Ox0
GOTO SKIPXOR1021
MOVLW 0x21
XORWF crc.l
MOVLWOxIO
XORWF crc+1,1
_endasm
SKIPXOR1021:
_asm
/1 data = 1;
//BANKSEL data
BcFOxa.oxo
RLCF PRODL
BANKSEL crc
// if(carry flag
set)
BTFSC Ox4,Ox0
BTG crc,OxO
endasm
r
void CaIcCRConRamAddress(unsigned int address) {
RamADDRESS = address;
RAM_READ;
received_bvte = RamDATA&Oxff;
CaIcCRC(received byte);
;
void addCRC(void) {
crc=0;
for(hemp=OFFSETS;ltemp<OFFSET3+lindex:ltemp++) {
CaIcCRConRamAddress(Itemp);
CIrWdtQ;
1
1
CaIcCRC(Ox00);
CaIcCRC(Ox00);
92

CA 02332297 2001-O1-25
temp I=crc»8;
tempi=cre&Oxff;
addCRCflag= 1;
convertAndWriteToSendBuffer(tempi);
convertAndWriteToSendBuffer(tempi);
lindexSave=(index;
if(!status){
messageCRC = crc;
cryptData=OFFSETS+I;
cryptDataLength = lindex - 3;
rc4cryptQ;
addCRCflag = 0;
void sendPing(void){
switch(sendPingState) {
case 0:
sendPingState=1;
break;
case 1:
lindex = 0;
writeStringToSendBuffer(sPingVersion);
received byte = read_ext_eeprom(Ox02);
if (received byte<Ox30 ~~ received byte>Ox39) received byte=0x30;
writeToSendBuffer(received byte);
writeToSendBuffer('.');
received byte = read_ext_eeprom(Ox03 );
if(received_byte<Ox30~~received-byte>Ox39)received byte=0x30:
writeToSendBuffer(received byte);
writeToSendBuffer('f);
received byte = read_ext_eeprom(Ox04);
convertAndWriteToSendBuffer(received byte);
received_byte = read_ext_eeprom(OxO~)
convertAndWriteToSendBuffer(received byte);
writeToSendBuffer('f);
received byte = read_ext_eeprom(Ox06);
convertAndV'riteToSendBuffer(received_byte);
received byte = read_ext_eeprom(Ox07);
convertAndWriteToSendBuffer(received byte);
writeToSendBuffer('f);
writeMeterSerial():
sendPingState++,
break;
case 2:
if(!writeMeterSerialState){
IindexSave=lindex;
calcSendDataQ;
sendPingState++;
break;
case 3:
if(!calcSendDataState)
sendPingState=0;
break;
void exceptionPage(void);
93

CA 02332297 2001-O1-25
switch(exceptionPageState){
case 0:
exceptionPageState++;
break;
case 1:
if(! sendingPage) {
sendingPage=1;
status=FALSE;
useTempAddress = 0;
if(exceptionFlag!=4) {
pagerMessage=0;
sendParametersQ;
exceptionPageState++;
break;
case 2:
if(sendParametersState=5){
sendParametersState=0;
if(exceptionFlag=I ){
outageReportSent++;
i
if(exceptionFlag-4 && pagerMessage) {
writeToSendBuffer(messageStatus):
;
else {
writeToSendBuffer(OxBF);
writeToSendBuffer(0);
writeToSendBuffer(OxFF);
writeToSendBuffer(exceptionFlag);
if(exceptionFlag!=4 ~~ !pagerMessage){
pagerMessage = 0x50 + exceptionFlag; // For logging in Ad-Hoc Buffer
i
if(exceptionFlag=5) {
received_byte = crcEcho»8;
writeToSendBuffer(received byte);
received byte = crcEchoROxff;
writeToSendBuffer(received-b~~te);
if(exceptionFlag=10) {
for(i=O;i<4;i++) {
RamADDRESS = Ox50fU+i;
RAM_READ;
received byte = RamDATA&Oxff;
writeToSendBuffer(received byte);
r
if(exceptionFlag=0) {
writeToSendBuffer(autoRegisterData + newDestination);
writeStringToSendBuffer(sAutoReg); // Flash Version.
received byte = read eat eeprom(Ox02)_
received byte «= 4;
received byte += read_ext_eeprom(Ox03)&OxOf;
writeToSendBuffer(received byte); // Loader Version.
for(i=O;i<2;i++){ // Pager Network Zone
RamADDRESS = Ox50fl7+i;
RAM_READ;
received byte = RamDATA&Oxff;
writeToSendBuffer(received byte);
94

CA 02332297 2001-O1-25
1
exceptionPageState=4;
break;
case 4:
addCRC();
if(exceptionFlag=1 ~~ exceptionFlag=2){
exceptionPageState++;
spreadTimer();
else {
exceptionPageState=6;
if(exceptionFlag=0 && (autoRegisterDestination ~~ newDestination)){
useTempAddress= 1;
stringPointer = 0x40;
stringEnd = 0x49;
putArrayInRTC(sDefaultPin);
if(autoRegisterDestination)
rte write(Ox49,autoRegisterDestination); // P4161007 or P4161008
else
rtc write(Ox49,'9'); // P4161009
break;
case J:
if(!spreadTimerState)
exceptionPageState++;
break;
case 6:
calcSendData();
exceptionPageState++;
break;
case 7:
if(!calcSendDataState){
exceptionFlag = 0; // To stop a 04 after a 0~ from being changed to a 0~.
exceptionPageState=0;
sendingPage=0;
;
break;
a
void updateTimeOfDay(void);
rtc-get datetime(&time);
timeOfDay = time.min;
timeOfDay *= 30;
timeOfDay += time.sec/2;
timeOfDay += time.hr* 1800;
r
void checkBattery(void){
switch(checkBatteryState){
case 0:
if(! updateAnalogInputsState){
if(IBSenseH>13) // ~%
batteryTimerl = 0;
else {
if(!batteryTimerl)

CA 02332297 2001-O1-25
batteryTimerl = timeOfDay + 1800; // 1 hour
else if(batteryTimerl<timeOfDay)
checkBatteryState++;
if(VBSenseH<204) // 80%
batteryTimer2 = 0;
else {
if(! batteryTimer2)
batteryTimer2 = timeOfDay + 15; // 30 seconds
else if(batteryTimer2<timeOfDay)
checkBatteryState++;
i
if(!checkBatteryState)
updateAnalogInputsState = 2;
)
break;
case I:
batteryTimer2 = timeOfDay + 1; // 2 seconds
VPWM_OUTP = 0;
checkBatteryState++;
break;
case 2:
if(batteryTimer2<timeOfDay) {
updateAnaloglnputsState = 2;
checkBatteryState++;
v
break:
case 3:
if(!updateAnaloglnputsState){
if(IBSenseH>OxfO){
ADCONO = 0;
ADCON 1 = Ox I e; // All digital
checkBatteryState++;
i
else if(IBSenseH<OxOf){
checkBatteryState=7;
1
1
else
updateAnaloglnputsState = 2;
break;
case 4:
VPWM_OUTP= 1;
checkBatteryState++;
break;
case 5:
if(nOVERCHARGING)
batteryTimerl =0;
else {
if(!batteryTimer 1 )
batteryTimerl = timeOfDay + 1800; // 1 hour
else if(batteryTimerl<timeOfDay){
checkBatteryState++;
VPWM OUTP = 0;
L
break:
case 6:
if(nOVERCHARGING)
checkBatteryState=4;
96

CA 02332297 2001-O1-25
break;
case 7: // PWM control starts here
break;
case 8:
break;
case 9:
break;
/******************************************************
Power Quality Functions
void storePQevent(void);
unsigned int getDecimal(void);
void sendPQstatus(void);
void writeDecimalToSendBuffer(unsigned int decNumber);
void pqCalc(void);
void pqAddToReport(unsigned char addToReport);
void pqLogMeterComFault(void);
void pqPoll(void);
void calcComparisons(void);
unsigned int fractionMultiply(unsigned int fracData);
void pqLogOff(void);
void pqMivsLog(void);
void pqMivsScan(void);
void pqUnbalanceCalc(void);
unsigned int sqrt(unsigned int sqData, unsigned int guess):
void pqUnbalancePoll(void);
void checkDemand(void);
******************************************************/
void storePQevent(void){
switch (storePQeventState){
case 0: // Store Percentage
case 3: // Store Duration (Total for MIVS)
case 6: // Store Report Delay
case 9: // Store Reminder Delay (Count for MIVS)
case 12: // Store Off Delay (Individual Duration of MIVS)
case 15: // Store Report Flags
if(storePQeventState=15)
itemp = getB~~te(lstart);
else
hemp=getDecimal();
minPQ = (whichPQ* 18)+0x80+storePQeventState;
maxPQ=minPQ+l;
minPQ = nc read(minPQ);
maxPQ = rtc_read(maxPQ);
if( hemp<minPQ) {
itemp=minPQ;
messageStatus = NAK;
i
if(itemp>maxPQ) {
hemp=maxPQ;
messageStatus = NAK;
;
hemp = storePQeventState/3;
(temp += whichPQ*6:
hemp += Ox 1 A2;
eepromBuffer(Itemp,itemp);
storePQeventState += 3;
97

CA 02332297 2001-O1-25
break;
case 18:
saveParCheckSum();
storePQeventState=0;
break;
void sendPQstatus(void);
switch (sendPQstatusState);
case 0:
sendPQstatusState++;
break;
case I:
status=1;
useTempAddress= 1;
sendParameters();
sendPQstatusState++;
break;
case 2:
if(!sendParametersState)
sendPQstatusState=0;
if(sendParametersState=~) {
sendPQstatusState++;
;
break;
case 3:
writeToSendBuffer('f);
hemp = (whichPQ*6) + Ox 1A2;
received byte = read_ext_eeprom(Itemp++); // Percentage
received byte = to_bcd(received_byte);
convertAndWriteToSendBuffer(received byte);
writeToSendBuffer('f);
hemp=read ext_eeprom(Ox 19C); // Nominal A
hemp = (temp«8;
(temp += read_ext_eeprom(Oxl9D)&Oxff:
writeDecimalDivider= 10;
postDecimalCharacter ='V';
writeDecimalToSendBuffer(hemp);
hemp=read ext_eeprom(Oxl9E); //Nominal B
hemp = hemp«8;
hemp += read_ext_eeprom(Ox 19F)&Oxff;
writeDecimalToSendBuffer(hemp);
hemp=read ext_eeprom(Ox 1 AO); // Nominal C
Itemp = hemp«8:
(temp += read_ext_eeprom(Ox 1 A 1 )&Oxff;
writeDecimalToSendBuffer(hemp);
writeToSendBuffer('f);
hemp = (whichPQ*6) + OxlA3;
received byte = read_ext_eeprom(ltemp++); // Duration Limit
received byte = to_bcd(received byte);
convertAndfVriteToSendBuffer(received byte);
writeToSendBuffer('f);
received byte = read ext eeprom(Itemp++); // Report Delay
if(received byte>99);
98

CA 02332297 2001-O1-25
writeToSendBuffer((received byte/100)+0x30)
received byte % 100;
received byte = to_bcd(received byte);
convertAndWriteToSendBuffer(received byte);
writeToSendBuffer('f);
received byte = read ext eeprom(ltemp++); // Reminder Delay
if(received byte>99){
writeToSendBuffer((received_byte/100)+0x30);
received byte %= 100;
received byte = to_bcd(received_byte);
convertAndWriteToSendBuffer(received byte);
writeToSendBuffer('f);
received byte = read_ext eeprom(Itemp++); // Off Delay
if(received_byte>99) {
writeToSendBuffer((received byte/100)+0x30);
received byte % 100;
l
received byte = to_bcd(received_byte);
convertAndWriteToSendBuffer(received byte);
writeToSendBuffer('f);
received~byte = read_ext_eeprom(ltemp); // Report Flags
convertAndWriteToSendBuffer(received byte);
writeToSendBuffer('f);
sendParametersState++,
sendPQstatusState++;
break;
case 4:
if (!sendParametersState)
sendPQstatusState=0;
break;
void writeDecimaIToSendBuffer(unsigned int decNumber) {
writeDecimalTemp = decNumber % writeDecimalDivider;
decNumber /= writeDecimalDivider:
received_byte = decNumber/10000;
if(received byte){
received-byte += 0x30;
writeToSendBuffer(received byte);
L
l
decNumber %= 10000;
if(received byte ~~ (decNumber/1000)){
received byte = decNumber/1000;
received byte += 0x30;
writeToSendBuffer(received_byte);
i
decNumber %= 1000;
if(received byte ~~ (decNumber/100)){
received byte = decNumber/100:
received byte += 0x30;
writeToSendBuffer(received byte);
L
l
decNumber %= 100;
99

CA 02332297 2001-O1-25
if(received byte ~~ (decNumber/10)){
received byte = decNumber/10;
received byte += 0x30;
writeToSendBuffer(received byte);
)
received byte = decNumber%10;
received byte += 0x30;
svriteToSendBuffer(received byte);
svriteToSendBuffer('.');
decNumber=writeDecimalTemp;
decNumber *= 100;
decNumber += writeDecimalDivider/2;
decNumber /= writeDecimalDivider;
if(decNumber>99) decNumber-99;
received byte = decNumber/10;
received byte += 0x30;
writeToSendBuffer(received byte);
received_byte = decNumber%10;
if(received byte){
received byte += 0x30;
writeToSendBuffer(received byte);
f
svriteToSendBuffer(postDecimalCharacter);
svriteToSendBuffer(' ');
void pqCalc(void){
// "pqInProgress" high bit indicates whether it seas in fault condition with
the previous scan.
// Lower nibble set to 1 when event goes into fault condition and incremented
whenever the
// day rolls over. This is used when calculating the event duration.
// Cleared after Off Delay or when coming out of fault condition when not yet
an event.
// "pqStartTime" present time saved whenever a PQ event goes into fault
condition.
// "pqReportTime" when event starts this is initially set to time when event
becomes an event
// and then set to the time when the report should be sent out and then set to
the time to
// send reminder messages.
// "pqEventStatus" set to 1 when event becomes an event, incremented with each
report or reminder.
// Cleared after Off Delay.
// "pqOffrime" calculated every time the PQ event comes out of fault
condition. If this time is
// surpassed with the PQ event still not in a fault condition then the event
is considered to
// have terminated.
// "pqEventDuration" calculated and saved every time the PQ event comes out of
fault condition.
// If the off delay is surpassed then this value will be used in logging the
event.
// "pqMivsCount" incremented with each AZIVS and when the MIVS limit is
reached then the MIVS log is
// scanned to see how many of there were in the occurrance window. If there
were enough in
// occurance svindosv to initiate a report then a report is sent and this
value is zeroed.
// If there mere not enough in the occurance window then this value is left at
the number that
// were in the occurance svindosv.
if(AsicStatus=1 ) {
RamADDRESS = Ox536D:
voltAfraction = meterFloatToInt(Ox89); // Convert Va from 24 bit Float to
64xVa 16 bit Int
voltBfraction = meterFIoatTolnt(Ox89);// Convert Vb from 24 bit Float to 64xVb
16 bit Int
voltCfraction = meterFloatTolnt(Ox89);// Convert Vc from 24 bit Float to 64xVc
16 bit Int
if(pqPollState=30 ~~ pqPolIState=40){
voltCfraction = 0;
s
if(AsicStatus=1 ~~ pqPoIlState=30 ~~ pqPoIIState=40){
if(demandWindosv)
checkDemandQ;
AsicStatus=0; // To stop a second calculation on previously manipulated data.
l~~

CA 02332297 2001-O1-25
if(!pqEnabled)
return;
for(pqEvent=O;pqEvent<l3;pqEvent++){
if((pqPoIlState=30 ~~ pqPollState=40)
&& pqEvent=0)
pqEvent=2;
if((pqEvent%3)=0)
pqValue = voltAfraction;
else if((pqEvent%3)=1)
pqValue = voltBfraction;
else
pqValue = voltCfraction;
RamADDRESS = Ox~3B0 + pqEvent*2;
pqComparison = ramReadlnt();
if(pqEvent<2) 1/ Out AB
RamADDRESS = Ox53D0;
else if(pqEvent<3) // Out C
RamADDRESS = Ox53D8;
else if(pqEvent<6) // Hi
RamADDRESS = Ox53E0:
else if(pqEvent<9) // Lo
RamADDRESS = Ox53E8;
else if(pqEvent<10) // Unbalance
RamADDRESS = Ox~3F0;
else // MIVS
RamADDRESS = Ox53F8:
RAM_READ;
pqDurationLimit = RamDATA&Oxff;
RAM_READ;
pqReportDelay = RamDATA&Oxff;
RAM_READ;
pqReminderDelay = RamDATA&Oxff; // pqMivsLimit
for MIVS
RAM_READ;
pqOffDelay = RamDATAR,Oxff; // pqMivsDuration
for MIVS
RAM_READ:
pqReportFlag = RamDATA&Oxff;
RamADDRESS = oxaaoo + pqEvent*Oxl2;
RAM_READ;
pqInProgress = RamDATA&Oxff;
RAM_READ;
pqEventStatus = RamDATA&Oxff;
pqStartTime = ramReadInt();
pqReportTime = ramReadInt();
pqOfffime = ramReadIntQ;
pqEventDuration = ramReadlnt();
if(pqValue < pqComparison)
pqFault= 1;
else
pqFault = 0;
if(pqEvent>2 && pqEvent<6){ // if High
event.
if(pqFault) pqFault=0;
1~1

CA 02332297 2001-O1-25
else pqFault=1;
if(pqEvent=9){
if(unbalanceStatus>2){
if(unbalanceStatus=3) pqFault=0;
else pqFault=I;
unbalanceStatus=0;
else { // Only end up here when pqReportNow is set.
if(pqlnProgress&0x80) pqFault=1;
else pqFault=0;
if((pqInProgress&0x80) && pqFault){
if(pqEvent<10){ //NotMIVS
if((pqEventStatus && pqReportNow && !(pqEventStatus=1
&& !(pqReportFlag&0x02)))
~~ (pqReportTime<timeOfDay && pqEventStatus=0 && !(pqReportFlag&0x02))){
if(pqReportFlag&0x01 ){
received byte = OxA 1+pqEvent;
if(pqEvent=2 && pqlnl'rogress&0x20) // OUT C/com
received b~~te = OxAF;
pqAddToReport(received byte);
pqAddIntToReport(pqStartTime);
if(pqEvent=9){
pqAddIntToReport(unbalVoItAB);
pqAddIntToReport(unbalVoltBC);
pqAddIntToReport(unbalVoltCA);
received byte = read ext eeprom(Ox 1 BA);
pqAddToReport(received_byte);
pqAddIntToReport(unbalVoltAfrac);
pqAddIntToReport(unbalVoItBfrac);
pqAddlntToReport(unbalVoltCfrac);
pqAddIntToReport(unbalAngIeAfrac):
pqAddIntToReport(unbalAngIeBfrac):
pqAddIntToReport(unbalAngIeCfrac);
v
else if(pqEvent!=2){
pqAddIntToReport(pqValue);
pqAddIntToReport(pqComparison);
;
received byte = pqEventStatus;
if(!received byte) received byte=1;
pqAddToReport(received byte);
;
if(pqReportTime<timeOfDay ~~ (pqEventStatus && pqReportNow));
if(pqEventStatus=0) { // It has not been identified as an event.
pqReportTime = pqReportDelay;
pqReportTime *= 3;
pqReportTime /= 2;
else {
pqReportTime = pqReminderDelay;
pqReportTime *= 30;
}
pqReportTime += timeOfDay;
if(pqReportFlag&0x01 && !pqReportNow){
if((pqEventStatus=0 && !(pqReportFlag&0x02))
II (pqEventStatus=1 && pqReportFlag&0x02) ~~ (pqEventStatus>I ~C.&
pqReportFlagROx04));
// meterComFault can only be set at this point if we are reporting an outage
on phase C.
102

CA 02332297 2001-O1-25
// we are setting it equal to 6 here to inhibit a fault flagged after the
poever comes back
// on when communication is delayed momentarily.
if(meterComFault) meterComFault=6;
if(!pqEventStatus && !(pqReportFlag&0x02)){
if(!pqPendingTime ~~ pqPendingTime>pqReportTime)
pqPendingTime = pqReportTime;
else {
pqPendingTime = timeOfDay;
)
pqReportTime += 10; // To avoid double entries.
i
RamADDRESS = 0x4404 + pqEvent*Ox 12; // Save Report Time
ramWritelnt(pqReportTime);
if(pqEventStatus<2 ~~ pqReportNow)
pqEventStatus++;
RamADDRESS = 0x4401 + pqEvent*Oxl2; // Save Event Status
RamDATA = pqEventStatus;
RAM WRITE;
r
else if((pqInProgress&0x80) && !pqFault); // Terminating fault condition.
if(pqEventStatus ~~ pqEvent>9){ // Has been defined as an event already.
if(pqEvent<10); // Outage. Hi/Lo or Unbalance
received_byte = pqlnProgress&Ox I F: // strip upper 3 hits
if(received byte=2){
pqEventDuration = 43200-pqStartTime;
pqEventDuration += timeOfDay;
if(pqEventDuration<timeOfDay) // overflow.
pqEventDuration=OxFFFF;
1
1
else if(received byte>2){
pqEventDuration=OxFFFF;
i
else pqEventDuration = timeOfDay-pqStartTime:
pqOffTime = pqOffDelay:
pqOffTime *= 30;
pqOftTime += timeOtDay;
RamADDRESS = 0x4406 + pqEvent*Oxl2; // Save pqOfffime
ramWriteInt(pqOfff ime);
ramWriteInt(pqEventDuration);
else { // MIVS
if(pqlnProgress=0x82){
pqEventDuration = 32768-pqStartTime;
pqEventDuration += IastCentiTime;
else if(pqlnProgress>Ox82);
pqEventDuration=OxFFFF;
;
else pqEventDuration = fastCentiTime-pqStartTime;
pqMivsLog();
pqMivsCount++;
received byte = pqOffFime;
if(received byte>=pqReminderDelay && Ox01&pqReportFlag){
103

CA 02332297 2001-O1-25
pqMivsScan();
RamADDRESS = 0x4407 + pqEvent*Oxl2; // Save pqMivsCount
RamDATA = pqMivsCount // Low byte only
RAM_WRITE;
pqlnProgress = 0; // Will have been modified in pqMivsScan()
RamADDRESS = 0x4400 + pqEvent*Ox 12; // Clear pqInProgress
RamDATA = Ox7f&pqInProgress;
if(!pqEventStatus){
if(pqEvent=2) RamDATA = 0x60&pqInProgress; // Leave Meter Com Fault
else RamDATA = 0;
J
RAM WRITE;
else if(!(pqInProgress&0x80) && pqFault){ // Start of fault condition.
pqReportTime = pqDurationLimit;
pqReportTime *= 30;
pqReportTime += timeOfDay;
if(!pqEventStatus){
RamADDRESS = 0x4402 + pqEvent*Oxl2; // Set pqStartTime Hi Byte
if(pqEvent>9)
ramWriteInt(lastCentiTime);
else
ramWriteInt(timeOfDay);
ramWriteInt(pqReportTime);
RamDATA = 0x81 ~pqInProgress; // Set pqInProgress
else {
RamDATA = Ox80~pqlnProgress; // Set pqInProgress
1
RamADDRESS = 0x4400 + pqEvent*Ox 12; // Set pqlnProgress
RAM_WRITE;
else { // !pqlnProgress && !pqFault
if(pqEventStatus && pqOfffime<timeOfDay){
// add statistics to report.
// PQ event is logged in reverse order because it is read from present back.
pqLog(pqEventDuration&OxFF);
pqLog(pqEventDuration»8);
pqLog(pqStartTime&OxFF);
pqLog(pqStartTime»8);
pqLog(OxA 1+pqEvent);
if(pqReportFlag&0x01 && pqReportFlag&0x08 &R, !(pqEventStatus=I &&
pqReportFlag&0x02)){
pqReportTime = pqReportDelay;
pqReportTime *= 3;
pqReportTime /= 2;
pqReportTime += timeOfDay;
if(!pqPendingTime ~~ pqPendingTime>pqReportTime)
pqPendingTime = pqReportTime;
received byte = OxB 1+pqEvent;
pqAddToReport(received byte);
pqAddIntToReport(pqStartTime);
pqAddIntToReport(pqEventDuration);
r
RamADDRESS = 0x4400 + pqEvent*Oxl2; // Clear pqlnProgress
RamDATA = pqInProgress&0x40; // Except bit 6
RAM WRITE;
104

CA 02332297 2001-O1-25
RamDATA = 0;
RAM WRITE;
if(pqEvent=8 && unbalanceStatus<3 && !pqReportNow) pqEvent=9; // to skip
unbalance.
if(pqPoIlState=30) {
if(pqEvent=2)
pqEvent=10;
else
pqEvent=12;
if(pqPollState=40){
pqEvent=12;
r
t5 )
t
pqReportNow=0;
void pqAddToReport(unsigned char addToReport){
if(pqReportSize<255){
RamADDRESS = pqReportSize+px4500;
RamDATA = addToReport;
RAM_WRITE;
pqReportSize++;
void pqAddIntToReport(unsigned int IntToReport){
received byte = IntToReport»8;
pqAddToReport(received byte);
received-byte = IntToReport&Oxff;
pqAddToReport(received byte);
i
void pqLogMeterComFault(void){
RamADDRESS = Ox53DC;
RAM_READ;
pqReportFlag = RamDATA&Oxff;
RamADDRESS = 0x4424;
RAM_READ;
pqInProgress = RamDATA&Oxff;
if((pqInProgress&Ox40~0){ // Start of fault session.
pqLog(timeOfDay&OxFF);
pqLog(timeOfDay»8);
pqLog(Ox77);
pqInProgress (= 0x40; // Set bit 6
RamDATA = pqlnProgress;
RamADDRESS = 0x4424;
RAM_V~RITE;
T
1
if(meterComFault==4 ~~ meterComFault==6) { // End of fault session.
pqlnProgress &= OxBF; // Clear bit 6
RamDATA = pqInProgress;
RamADDRESS = 0x4424;
RAM WRITE;
if(meterComFault>6){
meterComFault -= Ox 10;
pqLog(timeOfDay&OxFF);
105

CA 02332297 2001-O1-25
pqLog(timeOfDay»8);
pqLog(Ox'76);
if(pqReportFlag&0x80){
pqAddToReport(0);
else {
pqLog(lastCentiTime&OxFF);
pqLog(lastCentiTime»8);
received byte = meterComFault + 0x70;
pqLog(received byte);
if(pqReportFlag&0x80){
received byte = lastCentiTime»12;
received byte += meterComFault«4;
pqAddToReport(received byte);
received byte = IastCentiTime»4;
pqAddToReport(received byte);
void pqPoll(void) {
unsigned char iPQ;
do{
if(TMROH<RAM H) // Somehow overflowed TMRO without setting interrupt flag.
_TMROQ;
if(nAC_OK_INP)
acOKtimer = (astCentiTime+200;
else if(acOKtimer<IastCentiTime){
acOKtimer = 0;
sleepTime = 0;
outageReportSent = 0:
if(acOKtimer && !sleepTime)
sleepTime = timeOfOay+1800;
else if(acOKtimer && sleepTime<timeOfDay && outageReportSent =0)
powerSaveSleep();
if(acOKtimer && (pqEnabled ~~ demandWindow) &&. pqPollState!=31 &&
pqPollEnabled)
pqPoIIState=30;
switch(pqPoIIState) {
case 0:
if(!sendCommandState && (pqEnabled ~~ demandWindow) && !pqLogOffState &&
pqPoIlEnabled);
prepReceive(METER):
putchMeter(Ox55);
meterComAbortTime = lastCentiTime+10;
pqPoIlState=I ;
r
break;
case 1:
if (kbhitMeter()){
received byte = getc(METER);
if (received byte = 0x99)
pqPollState=3;
else if (received byte != 0x55)
pqPollState=0;
else {
if(meterComFault && meterComFault!=6);
meterComFault=4;
pqLogMeterComFauItQ;
if(!pqPendingTime &R pqReportFlag&0x80);
106

CA 02332297 2001-O1-25
// pqReportFlag set in pqLogMeterComFaultQ
pqPendingTime = timeOfDay + 30;
if(meterComFault)
pqLogOff();
meterComFault=0;
unanswered55s=0;
pqPoIIState=2;
putchMeter(OxAA);
meterComAbortTime = IastCentiTime+4;
else if (meterComAbortTime<lastCentiTime){
RamADDRESS = Ox53DC;
RAM_READ;
pqReportFlag = RamDATA&Oxff;
received byte = pqReportFlag&0x60;
if(meterComFault!=6 && ((unanswered55s=1 && received byte=0x00)
~~ (unanswered55s=6 && received byte=0x20)
~~ (unanswered55s=13 && received byte---0x40))){
meterComFault=1;
pqLogMeterComFauItQ;
l
if(unanswered~5s<20){
unanswered>js++;
pqPollState=0;
r
else {
meterComFault=2;
pqLogMeterComFaultQ;
unanswered55s=0;
pqPollState=40;
meterComAbortTime = lastCentiTime + 4300:
RamADDRESS = 0x4424;
RAM_READ;
pqlnProgress = RamDATAR.Oxff;
pqlnProgress ~= 0x20; // Set bit ~ (Out C/com)
RamDATA = pqlnProgress;
RamADDRESS = 0x4424;
RAM WRITE;
break;
case 2:
if(kbhitMeterQ){
if (getc(METER) = OxAA) {
pqPollState=3;
l
else pqPoIIState=0;
r
else if (meterComAbortTime<IastCentiTime) pqPolIState=0:
break;
case 3:
putchMeter(Ox80);
for(iPQ=1;iPQ<9;iPQ++) {
putchMeter(0);
putchMeter(Ox80);
putchMeter(0);
107

CA 02332297 2001-O1-25
if(unbalanceStatus=2)
pqUnbalanceCalc();
else
pqCalc(); // Calculate the previously read data.
pqPoIlState=4;
break;
case 4:
if(!PIE2bits.TX2IE){ // Wait until all characters have gone out.
meterComAbortTime = IastCentiTime+10;
pqPoIIState=5;
break;
case 5:
if (kbhitMeterQ){
received byte = getc(METER);
if (received byte - 0x33) { // Transmission Accepted
meterComAbortTime = lastCentiTime+4;
pqPollState=6;
r
else if (received byte = 0x99) { // Checksum error - resend
pqPollState=3;
i
else { // Command not accepted
pqPollState=0;
;
r
else if (meterComAbortTime<lastCentiTime) {
pqPollState=0;
r
break:
case 6:
if (kbhitMeterQ);
bytesFromMeter = getc(METER);
meterDataChksum=bytesFromMeter;
MbuffPointer = 0;
meterComAbortTime = IastCentiTime+4;
pqPolIState=17;
else if (meterComAbortTime<IastCentiTime) {
pqPolIState=0;
break:
case 17:
if (kbhitMeterQ) {
received byte = gete(METER);
meterDataChksum = meterDataChksum + received byte;
RamDATA = received byte;
RamADDRESS = 0x5361 + MbuffPointer;
RAM_WRITE;
MbuffPointer++;
meterComAbortTime = lastCentiTime+4;
if (MbuffPointer>42){
pqPollState++;
r
;
else if (meterComAbortTime<lastCentiTime)
pqPoIIState=0;
break:
case 18:
1~8

CA 02332297 2001-O1-25
if (kbhitMeterQ){
AsicStatus = getc(METER);
if (sendCompletePQ=4) {
convertAndWriteToSendBuffer(AsicStatus);
sendCompIetePQ = 0;
meterDataChksum = meterDataChksum + AsicStatus;
MbuffPointer++;
meterComAbortTime = IastCentiTime+4;
pqPol IState=19;
i
else if (meterComAbortTime<IastCentiTime) {
pqPollState=0;
break;
case 19:
if (kbhitMeterQ){
received byte = getc(METER);
meterDataChksum-=received byte;
meterComAbortTime = lastCentiTime+4;
pqPoIIState=20;
else if (meterComAbortTime<lastCentiTime)
AsicStatus=0;
pqPolIState=0;
i
break;
case 20:
if (kbhitMeter()) {
received byte = getc(METER);
pqPoIlState=0;
bytesFromMeter-44;
if (meterDataChksum&Oxff) {
putchMeter(Ox33);
AsicStatus=0;
else {
meterDataChksum = meterDataChksum»8;
if (meterDataChksum---received byte);
// nCLEAR SW_LED_IO=0;
// nCLEAR SW_SET DDRB = !nCLEAR SW SET DDRB;
pulseClear= 1;
if(unbalanceStatus=1 ){
pqPol I State=21;
;
r
else {
AsicStatus=0;
i
putchMeter(Ox33);
r
r
else if (meterComAbortTime<IastCentiTime) {
pqPolIState=0;
AsicStatus=0;
break;
case 21:
pqUnbalancePoll();
pqPolIState++;
109

CA 02332297 2001-O1-25
break;
case 22:
if(unbalPollState)
pqUnbalancePoll();
else {
bytesFromMeter=44;
pqPoIlState=0;
)
break;
case 30:
if(meterComFault!=3 && meterComFault!=6){
meterComFault=3;
pqLogMeterComFault();
f
AsicStatus=0;
pqCalcQ; // Keep track of when
to report event.
meterComAbortTime = lastCentiTime+20;
pqPolIState++:
break;
case 31:
if (meterComAbortTime<IastCentiTime)
{
if(acOKtimer)
pqPollState=30;
else {
pqPollState=40;
meterComAbortTime = lastCentiTime
+ 10;
break;
case 40:
if (kbhitMeter()) {
if (getc(METER) ---- OxOd) {
pqPollState=41;
putchMeter('O');
putchMeter('K');
putchMeter(OxOd);
meterComAbortTime = IastCentiTime+50;
if(meterComFault!=6){
meterComFault=~;
pqLogMeterComFault();
else if (meterComAbortTime<IastCentiTime);
// V'e get to this point from a loss and restoration of the AC OK signal or
after 40 seconds of silence.
// Either way let's extend the "Out C/Com" PQ event.
AsicStatus=0;
pqCalc(); // Keep track of when to report event.
pqPol lState=0;
break;
case 41:
if(kbhitMeterQ){
pqPolIState= 40;
meterComAbortTime = IastCentiTime+20;
r
else if (meterComAbortTime<IastCentiTime) pqPollState=0:
break;
i
; while (!TMROchanged && sendCommandState<2);
110

CA 02332297 2001-O1-25
#pragma code calcComparisons = 0x6000
void calcComparisons(void){
switch(whichPQ) {
case 0: // Outage A&B
// hemp = (pqNominal/10)*(percentage/100)*64= pqNominal*percentage*8/125
fracMultiplier=read ext eeprom(OxlA2);//Percentage
fracMultiplier *= 8;
fracDivider= 125;
hemp=read ext_eeprom(Oxl9C);
ltemp = ltemp8;
(temp += read_ext_eeprom(Ox
19D)&Oxff;
hemp = fractionMultiply(ltemp);
RamADDRESS = Ox53B0;
ram WriteInt(ltemp);
(temp=read ext eeprom(Ox
19E);
(temp = hemp8;
(temp += read_ext_eeprom(Ox
19F)&Oxff;
hemp = fractionMultiply(ltemp);
RamADDRESS = Ox53B2;
ramWriteInt(ltemp);
RamDATA = read_ext_eeprom(OxlA3);// Duration Limit
RamADDRESS = Ox53D0;
RAM_WRITE;
RamDATA = read ext eeprom(OxlA4);// Report Delay
RAM_WRITE;
RamDATA = read ext eeprom(Ox// Reminder Delay
1A5);
RAM_WRITE;
RamDATA = read ext eeprom(Ox// Off Delay
1 A6);
RAM_WRITE;
RamDATA = read ext eeprom(OxlA7);// Report Flags
RAM
WRITE;
_
break
case 1: // Outage C
// ltemp = (pqNominal/10)*(percentage/100)*64= pqNominal*percentage*8/125
fracMultiplier=read ext eeprom(OxlAB);//Percentage
fracMultiplier *= 8;
fracDivider = 125;
hemp=read ext_eeprom(Ox l
AO);
ltemp = hemp8;
hemp += read_ext_eeprom(Ox
1 A 1 )&Oxff;
hemp = fractionMultiply(ltemp);
RamADDRESS = Ox53B4;
ramWriteInt(ltemp);
RamDATA = read_ext_eeprom(Ox// Duration Limit
I A9);
RamADDRESS = Ox53D8;
RAM_WRITE;
RamDA T A = read ext eeprom(Ox// Report Delay
I AA);
RAM_WRITE;
RamDATA = read ext eeprom(OxIAB);// Reminder Delay
RAM_WRITE;
RamDATA = read ext eeprom(Ox// Off Delay
1 AC);
RAM_WRITE;
RamDATA = read ext eeprom(OxIAD);// Report Flags
RAM_WRITE;
break; //
case 2: // Hi Voltage
//hemp=(pqNominal/10)*((100+percentage)/100)*64=pqNominal*(100+percentage)*8/12
5

CA 02332297 2001-O1-25
fracMultiplier=read_ext eeprom(OxIAE);
fracMultiplier+= 100;
fracMultiplier *= 8;
fracDivider = 125;
hemp=read ext_eeprom(Ox 19C);
ltemp = ltemp8;
hemp += read_ext_eeprom(Ox
19D)&Oxff;
Itemp = fractionMultiply(Itemp);
RamADDRESS = Ox53B6;
ramWriteInt(Itemp);
hemp=read ext_eeprom(Oxl9E);
Itemp = Itemp8;
hemp += read_ext_eeprom(Ox
19F)&Oxff;
Itemp = fractionMultiply(ltemp);
RamADDRESS = Ox53B8;
ramWriteInt(Itemp);
ltemp=read ext_eeprom(OxIAO);
(temp = ltemp8;
hemp += read_ext_eeprom(Ox
t A 1 )&Oxff;
ltemp = fractionMultiply(Itemp);
RamADDRESS = Ox~3BA;
ramWriteInt(Itemp);
RamDATA = read_ext_eeprom(Ox 1/ Duration Limit
lAF);
RamADDRESS = Ox53E0;
RAM_WRITE:
RamDATA = read ext_eeprom(Ox !/ Report Delay
1 BO);
RAM_W RITE;
RamDATA = read ext eeprom(Oxl// Reminder Delay
B 1 );
RAM_W RITE;
RamDATA = read ext_eeprom(Ox // Off Delay
1 B2);
RAM_WRITE;
RamDATA = read ext eeprom(Ox // Report Flags
1 B3 );
RAM_WRITE;
break;
case 3: // Low Voltage
// (temp = (pqNominal/10)*((100-percentage)/100)*64
= pqNominal*(100-percentage)*8/125
fracMultiplier = read_ext_eeprom(Ox
1 B4);
fracMultiplier = 100-fracMultiplier;
fracMultiplier *= 8;
fracDivider= 125;
hemp=read ext_eeprom(Ox (
9C );
hemp = ltemp8;
hemp += read_ext_eeprom(Ox
19D)&Oxff;
ltemp = fractionMultiply(Itemp);
RamADDRESS = Ox53BC;
ramWritelnt(ltemp);
Itemp=read ext_eeprom(Oxl9E);
hemp = hemp8;
ltemp += read_ext_eeprom(Ox
19F)&Oxff;
(temp = fractionMultiply(Itemp);
RamADDRESS = Ox53BE;
ramWritelnt(Itemp);
hemp=read ext_eeprom(Ox l
AO);
hemp = ltemp8;
hemp+=read_ext_eeprom(OxIAI)&Oxff:
(temp = fractionMultiply(Itemp);
RamADDRESS = Ox53C0;
ramWriteInt(Itemp);
RamDATA = read_ext_eeprom(OxIBS);// Duration Limit
RamADDRESS = Ox53E8;
112

CA 02332297 2001-O1-25
RAM_WRITE;
RamDATA = read ext eeprom(Ox// Report Delay
1 B6);
RAM_WRITE;
RamDATA = read ext eeprom(Ox// Reminder Delay
1 B7);
RAM_WRITE;
RamDATA = read ext eeprom(Ox// Off Delay
I B8);
RAM_WRITE;
RamDATA = read ext eeprom(Ox// Report Flags
1 B9);
RAM_WRITE;
break;
case 4: // Voltage Unbalance
uintl6ToFloat32(64,Ox10);
uintl6ToFloat32(3,Ox14);
uintl6ToFloat32(4256,Ox
18);
uintl6ToFloat32(IOOOO,OxIC);
floatDivide(Ox 1 C,Ox 14,0x1
C);
fracMultiplier = read_ext_eeprom(Oxl; // Percentage
BA)
fracDivider = 100 - fracMultiplier;
fracMultiplier+= 100;
RamDATA = fracDivider&OxFF;
RamADDRESS = Ox53C2;
RAM_WRITE;
RamDATA = fracMultiplier&OxFF;
RAM_WRITE;
RamDATA = read_ext_eeprom(Ox// Duration Limit
1 BB);
RamADDRESS = Ox53F0;
RAM_WRITE;
RamDATA = read ext_eeprom(Ox// Report Delay
1 BC);
RAM_WRITE;
RamDATA = read ext eeprom(OxIBD);// Reminder Delay
RAM_WRITE;
RamDATA = read ext eeprom(Ox// Off Delay
1 BE);
RAM_WRITE:
RamDATA = read ext eeprom(Ox// Report Flags
I BF);
RAM WRITE;
uintl6ToFloat32( 1,0x58);
floatChangeSign(Ox58);
uintl6ToFloat32(I 192,0x40);
uintl6ToFloat32(1000,Ox3C);
floatDivide(Ox40,Ox3C,Ox40);
uint 16ToFloat32(6890,Ox3C);
floatDivide(Ox58,Ox3C,Ox3C);
uint 16ToFloat32( 122,0x44);
floatDivide(Ox58,Ox44,Ox44);
uint I 6ToFloat32( 17800,0x48);
floatDivide(Ox58,Ox48,Ox48);
uint l6ToFloat32( 128,Ox4C);
floatChangeSign(Ox58);
floatDivide(Ox58,Ox4C,Ox4C);
floatDivide(Ox58,Ox10,Ox10);
uint l6ToFloat32(2,Ox5C);
floatChangeSign(OxSC);
break;
case 5: // MIVS
// hemp = (pqNominal/10)*(percentage/100)*64= pqNominal*percentage*8/125
fracMultiplier = read ext // Percentage
eeprom(OxlCO);
fracMultiplier *= 8;
fracDivider = 125;
hemp=read ext eeprom(Oxl9C);
113

CA 02332297 2001-O1-25
Itemp = (temp«8;
Itemp += read_ext_eeprom(Oxl9D)&Oxff;
Itemp = fractionMultiply(Itemp);
RamADDRESS = Ox53C8;
ramWritelnt(Itemp);
(temp=read ext_eeprom(Oxl9E);
(temp = hemp«8;
hemp += read_ext eeprom(Ox 19F)&Oxff;
ltemp = fractionMultiply(ltemp);
RamADDRESS = Ox53C4;
ramWriteInt(ltemp);
(temp=read ext_eeprom(OxIAO);
hemp = hemp«8;
hemp += read_ext_eeprom(Ox 1 A 1 )&Oxff;
hemp = fractionMultiply(ltemp);
RamADDRESS = Ox53C6;
ramWriteInt(ltemp);
RamDATA = read_ext_eeprom(Ox 1 C 1 ); // Occurance Window
RamADDRESS = Ox53F8;
RAM_WRITE;
RamDATA = read ext eeprom(OxlC2); // Report Delay
RAM_WRITE;
RamDATA=read ext eeprom(OxlC3); // MIVS Count Limit
RAM_WRITE;
RamDATA = read ext eeprom(OxIC4); // MIVS Individual Max Duration
RAM_WRITE;
RamDATA = read ext eeprom(Ox I CS); I/ Report Flags
RAM_WRITE;
break
;
unsigned int fractionMultiply(unsigned int fracData) {
AARGBO=fracMultiplier»8;
AARGB1=fracMultiplier&Oxff;
BARGBO=fracData»8;
BARGB 1=fracData&Oxff;
FXM 1616UQ;
BARGBO=fracDivider»8;
BARGE 1=fracDivider&Oxff:
FXD3216UQ;
fracData = AARGB2;
f~acData = fracData«8;
fracData += AARGB3:
return(fracData);
void pqLogOff(void) {
switch(pqLogOffState) {
case 0:
pqLogOffState++; // If pqPendingTime is set because of a previous swipe
// then delay sending until after this session.
if(suspendPQtime=pqPendingTime) pqPendingTime = 0;
if(!meterComFault) {
suspendPQtime = IastCentiTime + 100;// Temp PQ Disable switch debounce.
pqLog(timeOYDay&OxFF);
pqLog(timeOfDay»8);
pqLog(Ox7E):
received byte=read ext eeprom(OxIFF);
if(received byte){
114

CA 02332297 2001-O1-25
pqAddToReport(Ox7E);
pqAddIntToReport(timeOfDay);
else { // Log off to clear intermittent zero reads after a power down or MIVS
// This was helping at one time but may not be necessary anymore.
suspendPQtime = lastCentiTime + 30;
pqLogOffState = 31;
break;
case I:
case 31:
if(!sendCommandState && !pqPollState){
pqLogOff~tate++;
command[0]=0x79;
command [ 1 ]=0x04;
for(i=2;i<1 1;i++) command[i]=0;
command[9]=Ox7d;
sendFlag=FALSE;
sendCommand(); // There is a small chance that there will be an overlap here.
break;
case 32:
if(!sendCommandState && suspendPQtime<IastCentiTime){
pqLogOffState = 0;
break;
case 2:
if(!sendCommandState && suspendPQtime<lastCentiTime){
pqLogOffState = 18;
pqLogOffState -= read ext eeprom(Ox 1 FE):
i
break;
case 19:
pqLogOffState=21;
suspendPQtime=0;
break;
case 20:
if(nMAG_SWITCH INP){
pqLogOffState++;
suspendPQtime = lastCentiTime + 100; // Temp PQ Disable switch debounce.
l
break;
case 21:
if(suspendPQtime<lastCentiTime) {
received byte = read ext eeprom(Ox 1 FF);
if(received byte);
if(!pqPendingTime) {
suspendPQtime = received byte;
suspendPQtime *= 30;
suspendPQtime += timeOfDay;
pqPendingTime = suspendPQtime;
pqAddToReport(Ox7F);
pqAddIntToReport(timeOfDay);
l
pqLog(timeOfDay&OxFF);
pqLog(timeOfDay»8);
pqLog(Ox7F);
pqLogOff~tate=0;
115

CA 02332297 2001-O1-25
t
break;
default : // 3 to 18
if(suspendPQtime<IastCentiTime){
pqLogOffState++;
suspendPQtime = IastCentiTime + 6000;
if(!nMAG_SWITCH INP){
pqLogOffState=20;
}
break;
void pqMivsLog(void){
// Puts time stamps based on IastCentiTime into a circular buffer for MIVS
only cu 0x5200-Ox52FF
// pqEvent = 10, 1 I or 12 corresponding to MIVS on phase B, C or A. This is
put into the upper
// nibble of the high byte of the time stamp and the upper 12 bits of
IastCentiTime are saved
// in the lower nibble and the low byte. A single 0x00 is put into the log
every time the
// IastCentiTime variable is rolled back 32768.
if(pqEvent=0) {
pqMivsBuffPnt++;
RamADDRESS = 0x5200+pqMivsBuffPnt;
RamDATA = 0;
RAM_WRITE:
else if (pqEventDuration>pqMivsDuration) {
pqMivsBuffPnt++;
RamADDRESS = Ox~200+pqMivsBuffPnt;
RamDATA = IastCentiTime»4;
RamDATA &= OxFF;
RAM_WRITE;
pqMivsBuffPnt++;
RamDATA = lastCentiTime» 12;
RamDATA += pqEvent«4;
RAM WRITE;
r
// For now we will log every MIVS in the Ad-Hoc buffer as well for debugging
purposes.
if(pqEvent){
pqLog(pqEventDuration&OxFF):
pqLog(pqEventDuration»8);
pqLog(timeOfDay&OxFF);
pqLog(timeOfDay»8);
pqLog(OxB 1+pqEvent);
void pqMivsScan(void){
// This function scans back in time from the present in the MIVS log counting
the number of MIVS
// in a phase that are within the occurrance window. Occurance window is
stored in external
// RAM at Ox44BB in minutes (1 to 60). Time stamps are based on 16x
IastCentiTime (0.16s)
// Occurance window is multiplied by 37~ (= 60* 100/16) to be in the same
scale. First the # of
// lastCentiTime rollbacks to scan past are calculated and then the lowest
value of timeStamp to
// include in the count is calculated.
// pqMivsCount (same as pqOfffime) will be zeroed if it is an event and left
at however many are within the occurance
// window if it is not an event. pqEvent must not be modified, pqReportDelay
and pqMivsLimit (same
// as pqReminderDelay) are used here. pqlnProgress and pqGventStatus may be
modified as long as pqInProgress
// is set to zero after running pqMivsScan. Any other temporary pq variables
can be modified without
// needing to restore them.
// pqStartTime used here for occurance window in 0.16s increments.
116

CA 02332297 2001-O1-25
// pqComparison used here for earliest time stamp to include.
// pqDurationLimit used here for # of rollbacks to scan past.
// pqlnProgress used here for a MIVS log pointer.
// pqEventStatus used here for a flag to end scanning.
// pqReportTime used here for the time between now and the earliest MIVS
within the occurance window.
// pqValue used here for time stamps to be evaluated.
#define pqMIVSoccurance pqStartTime
#define pqMIVSrollbacks pqDurationLimit
#define pqMIVSpointer pqInProgress
#define pqMIVSscanExit pqEventStatus
#define pqMIVSwindow pqReportTime
#define pqMIVStime pqValue
RamADDRESS = Ox53f8; !/ get occurance window
RAM_READ;
pqMIVSoccurance = RamDATA&Oxff;
pqMIVSoccurance *= 375; // 6000/16
if(scanMIVSonly){
pqMivsCount = pqReportDelay; // pqMivsCount used temporarily.
pqMivsCount *= 75; // 300/16
pqMivsCount /=4; // 300/16
pqMIVSoccurance += pqMivsCount;
pqMivsCount=0;
pqComparison = lastCentiTime»4;
if(pqMIVSoccurance<pqComparison) {
pqMIVSrollbacks=0; // # of rollbacks
pqComparison -= pqMIVSoccurance; // earliest time stamp to include
else ;
pqComparison = pqMIVSoccurance - pqComparison;
pqMIVSrollbacks = pqComparison/2048; // # of rollbacks
pqMIVSrollbacks++;
pqComparison %= 2048;
pqComparison = 2048 - pqComparison; // earliest time stamp to include
pqMIVSscanExit=0;
pqMIVSpointer = pqMivsBuffPnt;
do ;
RamADDRESS = 0x5200+pqMIVSpointer;
RAM_READ;
received_byte = RamDATA&Oxff;
pqMIVSpointer--;
if(pqMIVSpointer=pqMivsBuffPnt) {
pqMIVSscanExit=1;
;
else if(!received byte) {
if(pqMIVSrollbacks) {
pqMIVSrollbacks--;
else {
pqMIVSscanExit=I;
else {
pqMIVStime = received byte&OxOf;
117

CA 02332297 2001-O1-25
pqMIVStime «= 8;
RamADDRESS = 0x5200+pqMIVSpointer;
RAM_READ;
pqMIVStime += RamDATA&Oxff;
pqMIVSpointer--;
if(pqMIVSpointer=pqMivsBuffPnt) {
pqMIVSscanExit=1;
received byte »= 4;
if(!pqMIVSrollbacks && pqMIVStime<pqComparison){
pqMIVSscanExit=1;
else if(pqEvent=received byte);
pqMivsCount++;
pqMIVSwindow = pqMIVSrollbacks*2048;
pqMIVSwindow += pqMIVStime;
pqMIVSwindow -= pqComparison;
~ while (!pqMIVSscanExit);
if(pqMivsCount>=pqMivsLimit && !scanMIVSonI~~);
if(!pqPendingTime){
pqPendingTime = pqReportDelay;
pqPendingTime *= 3;
pqPendingTime /= 2;
pqPendingTime += timeOfDay;
i
pqMIVSwindow = pqMIVSoccurance - pqMIVSwindow:
pqMIVSwindow *= 2;
pqMIVSwindow /= 2~;
pqMIVSwindow *=2;
pqAddToReport(OxA 1+pqgvent);
pqAddlntToReport(timeOfDay);
pqAddToReport(pqMivsCount);
pqAddIntToReport(pqMIVSwindow);
pqLog(timeOfDay&OxFF):
pqLog(time0lDay»8);
pqLog(OxAI+pqEvent):
pqMivsCount=0;
;
void pqUnbalanceCalc(void){
// A voltage unbalance condition is determined from the GyrBox Phase
Information.
// This function does the
// calculation to determine if a fault condition is present and sets a flag if
so. The function
// pqCalc uses this fault flag to keep track of the duration of the voltage
unbalance event and
!/ determines when it becomes an event for logging and reporting.
RamADDRESS = Ox~340:
unbalVoltAfrac = meterFloatTolnt(Ox89): U Convert Va from 24 bit Float to
64xVa 16 bit Int
unbalVoltBfrac = meterFloatToInt(Ox89); // Convert Vb from 24 bit Float to
64xVb 16 bit Int
unbalVoltCfrac= meterFIoatToInt(Ox89); // Convert Ve from 24 bit Float to
64xVc 16 bit Int
unbalAngIeBfrac = meterFloatToInt(Ox88); // Convert Angle of Vb from 24 bit
Float to 128x 16 bit Int
unbalAngleCfrac = meterFloatToInt(Ox88); // Convert Angle of Vc from 24 bit
Float to 128x 16 bit Int
// Angle A between Va and Vb is the angle of Vb.
unbalAngIeAfrac = unbalAngleBfrac;
// Angle B between Vb and Vc is the angle of Vc - the angle of Vb
if(unbalAngleCfrac>unbalAngleBfrac)
118

CA 02332297 2001-O1-25
unbalAngleBfrac = unbalAngleCfrac - unbalAngIeBfrac;
else
unbalAngIeBfrac = unbalAngIeBfrac - unbalAngleCfrac;
// Angle C between Vc and Va is 360(x128) - the angle of Vc
unbalAngleCfrac = 46080 - unbalAngleCfrac;
unbalVoltAvg = unbalVoItAfrac/3; // Calculate the average Phase Voltage
unbaIVoItAvg += unbalVoltBfrac/3;
unbalVoltAvg += unbalVoltCfrac/3;
uint 16ToFloat32(unbal V oltAfrac,Ox00);
uintl6ToFloat32(unbalVoltBfrac,Ox04);
uintl6ToFloat32(unbalVoltCfrac,Ox08);
uint 16ToFloat32(unbal VoltAvg,OxOC);
floatMultiply(OxOC,OxIO,OxOC); // Multiply by 1/64
floatDivide(OxIC,OxOC,Ox20); // 10000/(3Vavg)
floatDivide(Ox20,OxOC,Ox20); // 10000/(3(Vavg**2))
cos128(unbalAngIeAfrac,Ox24); // cos(A)
cos128(unbalAngleBfrac,Ox28): l/ cos(B)
cos128(unbalAngIeCfrac,Ox2C); // cos(C)
for( i=0; i<9; i+=4) {
floatMultiply(i,OxlO,i); // Multiply by I/64
floatMultiply(i,i,Ox30+i); // Va**2
for(i=O;i<9;i+=4) {
floatMultiply(0x24+i,OxSC,Ox24+i); // -2cos(A)
floatMultiply(Ox24+i,i,Ox24+i); //-2Va*cos(A)
floatMultiply(0x24+i,(4+i)%OxOC,Ox24+i); //-2VaVb*cos(A)
floatAdd(Ox24+i,Ox30+i,Ox24+i): // Va**2 - 2VaVb*cos(A)
floatAdd(0x24+i,Ox30+((4+i)%OxOC),Ox24+i); // Va**2 + Vb**2 - 2VaVb*cos(A)==
Vab**2
floatMultiply(0x24+i,Ox20,Ox24+i); // (Vab**2 * 100**2)/(3*Vavg**2)
1
unbalVoltAB = float32ToIntl6(OX24); // Approx. Vab as a % of average squared
unbalVoltBC = float32ToIntl6(OX28); // Approx. Vbc as a % of average squared
unbalVoItCA = float32ToIntl6(OX2C);// Approx. Vca as a % of average squared
45
unbalVoltAB = sqrt(unbaIVoItAB,100);
unbalVoltBC = sqrt(unbalVoltBC,100);
unbalanceStatus=3;
unbalVoltCA = sqrt(unbalVoltCA,100);
unbalVoltAvg = unbalVoltAB + unbalVoltBC + unbaIVoItCA:
unbalVoltAvg /= 3;
fracMultiplier = 10000;
fracDivider=unbaIVoItAvg;
unbalVoItAB = fractionMultiply(unbaIVoItAB);
unbalVoltBC = fractionMultiply(unbalVoItBC);
unbalVoltCA = fractionMultiply(unbalVoItCA);
RamADDRESS = Ox53C2;
RAM_READ;
// unbalVoltAvg used here for lower limit comparison.
unbalVoltAvg = RamDATA&Oxff;
unbalVoltAvg *= 100;
if(unbalVoltAB<unbalVoltAvg ~~ unbaIVoItBC<unbalVoltAvg ~~
unbalVoltCA<unbalVoItAvg)
119

CA 02332297 2001-O1-25
unbalanceStatus=4;
RamADDRESS = Ox53C3;
RAM_READ;
// unbaIVoItAvg used here for upper limit comparison.
unbalVoltAvg = RamDATA&Oxff;
unbalVoltAvg *= 100;
if(unbaIVoItAB>unbalVoltAvg ~~ unbalVoItBC>unbalVoltAvg ~~
unbalVoItCA>unbaIVoItAvg)
unbalanceStatus=4;
unsigned int sqrt(unsigned int sqData, unsigned int guess) {
unsigned int guess2;
unsigned char negativeFlag;
// This function accepts a value that should be beUveen 50 squared and 150
squared if the guess
// is 100. The return value is an approximation of the square root times 100.
It will extrapolate
// beyond 50 to 150 but errors become larger the farther from 100 you get.
This is OK for voltage
// unbalance calculations where the difference from the average should be less
than 6%.
guess *= 100;
for(i=O;i<3;i++) {
guess /= 100;
if(guess<2) guess=2;
guess2 = guess*guess;
if(guess2>sqData) {
guess2 -= sqData;
negativeFlag=0;
r
else {
guess2 = sqData-guess?;
negativeFlag=1;
)
if(guess2<1300){
guess2 *= 50;
guess2 /= guess;
else {
guess? /= guess:
guess? *= 50:
guess *= 100:
if(negativeFlag) guess += guess2;
else guess -= guess2;
return(guess);
void pqUnbalancePoll(void) {
// This function will be called by pqPoll so decisions of when to run it will
be made by pqPoll.
// This function reads the GyrBox Phase Information from the meter. While
waiting for the data
// to come back from the meter the Asic data from the previous meter read is
processed. The
// data from this read is processed when the data from the next Asic read is
being waited on.
unsigned char iPQ;
switch(unbalPollState) {
case 0:
putchMeter(Ox55);
meterComAbortTime = lastCentiTime+4;
unbaIPolIState++;
break;
case 1:
if (kbhitMeterQ){
120

CA 02332297 2001-O1-25
if (getc(METER) != 0x55)
unbalPoIIState=0;
else {
unbalPol lState++;
putchMeter(OxAA);
meterComAbortTime = IastCentiTime+4;
i
else if (meterComAbortTime<lastCentiTime) unbalPollState=0;
break;
case 2:
if (kbhitMeter()) {
if (getc(METER) = OxAA) {
unbalPollState++;
}
else unba1Po11State=0;
r
else if (meterComAbortTime<IastCentiTime) unbaIPoIlState=0;
break;
case 3:
putchMeter(Ox94);
for(iPQ=I;iPQ<9;iPQ++){
putchMeter(0);
}
putchMeter(Ox94);
putchMeter(0);
pqCalc(); // Calculate the previously read data.
unbalPollState++;
break;
case 4:
if(!PIE2bits.TX2IE){ // Wait until all characters have gone out.
meterComAbortTime = lastCentiTime+10;
unbalPoIlState=5;
r
break:
case 5:
if (kbhitMeter()) {
received byte = getc(METER);
if (received byte ---- 0x33) { // Transmission Accepted
meterComAbortTime = IastCentiTime+4;
unbaIPolIState++;
i
else if (received byte--- Ox99); // Checksum error - resend
unbalPoIlState=3;
;
else { // Command not accepted
unbalPollState=0;
r
1
1
else if (meterComAbortTime<lastCentiTime) {
unbaIPolIState=0;
}
break;
case 6:
if (kbhitMeterQ){
bytesFromMeter = getc(METER);
meterDataChksum=b~~tesFromMeter;
MbuffPointer = 0;
meterComAbortTime = IastCentiTime+4;
unbalPolIState=22;
121

CA 02332297 2001-O1-25
else if (meterComAbortTime<IastCentiTime) {
unbalPollState=0;
break;
case 22:
if (kbhitMeter()){
received byte = getc(METER);
meterDataChksum = meterDataChksum + received byte;
RamDATA = received byte;
RamADDRESS = 0x5340 + MbuffPointer;
RAM_WRITE;
MbuffPointer++;
meterComAbortTime = lastCentiTime+4;
if (MbuffPointer>32){
unbalPoIlState++;
else if (meterComAbortTime<IastCentiTime) {
unbaIPolIState=0;
break;
case 23:
if (kbhitMeter()) {
received byte = getc(METER);
meterDataChksum-=received byte;
meterComAbortTime = lastCentiTime+4;
unba1Po11State++;
else if (meterComAbortTime<lastCentiTime) {
unbalPollState=0;
break;
case 24:
if (kbhitMeterQ) {
received-byte = getc(METER);
unbalPoIlState=0;
if (meterDataChksum&Oxft) {
putchMeter(Ox33);
;
else {
meterDataChksum = meterDataChksum»8;
if (meterDataChksum-received byte) {
// nCLEAR_SW_LED_IO=0;
// nCLEAR_SW_SET_DDRB = !nCLEAR SW SET DDRB;
unbalanceStatus=2;
i
r
putchMeter(Ox33);
r
;
else if (meterComAbortTime<lastCentiTime) {
unbalPoIlState=0;
break:
;
void checkDemand(void){
// unsigned int's
#define demandThreshold pqComparison
122

CA 02332297 2001-O1-25
#define demandTemp pqStartTime
#define demandReminderDelay
pqReportTime
#define demandSampIeAverage
pqOfffime
#define demandWindowAverage
pqValue
#definedemandOKdelay pqEventDuration
// unsigned char's
#define demandWindowRemainder
pqInProgress
#define demandDataPointerpqDurationLimit
#define demandSampleNumber
pqReportDelay
#definedemandMaxExp pqFault
Int
if(AsicStatus){
RamADDRESS = 0x5389;
demandValue = meterFloatToInt(read ext eeprom(Ox 1 cb)); // Convert Watts from
24 bit Float to 16 bit
else
demandValue = 0;
RamADDRESS = Ox539F;
RAM_READ;
demandSampleNumber = RamDATA&Oxff;
demandSampIeAverage = ramReadlnt();
demandSampIeNumber++;
demandTemp = demandSampleAverage % demandSampIeNumber;
demandTemp *=demandSampleNumber-1;
demandTemp += demandValue % demandSampIeNumber;
demandTemp += demandSampIeNumber/2;
demandTemp /= demandSamp(eNumber;
demandSampleAverage /= demandSampleNumber:
demandSampIeAverage *= demandSampIeNumber-I:
demandSampIeAverage += demandValue/demandSampIeNumber:
demandSampleAverage += demandTemp;
if(demandSampleTime<IastCentiTime) {
RamADDRESS = Ox53A8;
demandReminderDelay = ramReadIntQ;
demandOKdelay = ramReadInt();
demandWindowAverage = ramReadlnt();
RAM_READ;
demandW indowRemainder = RamDATA&Oxff;
RAM_READ;
demandDataPointer = RamDATA&Oxff;
demandSampIeTime = demandWindow;
demandSampleTime *= 47; // (60s* 100)/128
demandSampleTime += lastCentiTime;
demandSampleNumber = 0;
RamADDRESS = 0x5400 + demandDataPointer;
demandTemp = ramReadIntQ;
RamADDRESS = 0x5400 + demandDataPointer;
ramWriteInt(demandSampleAverage);
demandDataPointer += 2;
demandWindowAverage -= demandTemp/128;
demandTemp % 128;
if (demandTemp > demandWindowRemainder){
demandWindowRemainder += 128 - demandTemp;
demandWindowAverage --;
else
demandWindowRemainder -= demandTemp;
demandWindowAverage+= demandSampleAverage / 128;
IZJ

CA 02332297 2001-O1-25
demandWindowRemainder+= demandSampIeAverage%128;
if (demandWindowRemainder > 128){
demandWindowRemainder-= 128;
demand W indowAverage ++;
)
received byte = timeOfDay/450;
if ((received byte<read ext eeprom(Oxlc7)) ~~ (received byte>=read
ext_eeprom(Oxlca)))
demandTemp = Ox 1 d2;
else if (received byte<read ext eeprom(OxlcB))
demandTemp = Ox 1 cc;
else if (received byte<read ext eeprom(Oxlc9))
demandTemp = Ox 1 ce;
else
demandTemp = Ox 1 d0;
received byte = read ext_eeprom(demandTemp+1 );
demandThreshold = read ext_eeprom(demandTemp);
demandThreshold = (demandThreshold«8) + received byte;
if(demandWindowAverage>demandThreshold &c~.
demandSampleAverage>demandThreshold &&
demandThreshold){
if(demandReminderDelay < timeOfDay) {
demandReport = 1;
demandReminderDelay = read_ext eeprom(Ox 1 D4);
demandReminderDelay *= 30;
demandReminderDelay += timeOfDay;
ioState = read_ext eeprom(demandTemp+12); J/ Timer to run when over.
ioStateUpdate();
demandOKdelay = 0;
else if((demandWindowAverage<demandThreshold ~~ !demandThreshold) &&
demandReminderDelay){
if(!demandOKdelay){
demandOKdelay = read ext eeprom(Ox 1 d5);
demandOKdelay *= 30;
demandOKdelay += timeOfDay;
;
else if(demandOKdelay<timeOfDay) {
demandReminderDelay=0;
demandOKdelay=0;
if(read_ext_eeprom(Ox 1 d6))
demandReport= 1;
ioState = read_ext eeprom(demandTemp+13); // Timer to run when OK.
ioStateUpdate();
L
if(demandReport){
RamADDRESS = Ox53A2;
ramWriteInt(demandWindowAverage);
ramWriteInt(demandThreshold);
ramWritelnt(timeOfDay);
if(demandReport=2)
demandReport=3;
RamADDRESS = Ox53A8;
ramWriteInt(demandReminderDelay);
ramWriteInt(demandOKdelay);
ramWriteInt(demandWindowAverage);
RamDATA = demandWindowRemainder;
RAM_WRITE;
RamDATA = demandDataPointer;
RAM WRITE;
124

CA 02332297 2001-O1-25
RamADDRESS = Ox539F;
RamDATA = demandSampIeNumber;
RAM_WRITE;
ramWriteInt(demandSampleAverage);
~******************************************************
Address Handlers
void storeAddress( unsigned char tempFlag);
void setNickname(void);
******************************************************/
void storeAddress( unsigned char tempFlag)(
switch(storeAddressState){
case 0:
storeAddressState++;
if (tempFlag)
headAddress=0x42;
else
headAddress=OxIF;
headerSize=0;
headerCount=1;
(temp=(start;
RamADDRESS=(temp;
RAM_READ:
last byte = RamDATA&Oxff;
if(tempFlag && (last byte=.' ~~ last_byte--=:'));
useTempAddress=0;
storeAddressState=0:
i
break;
case I:
RamADDRESS=(temp;
RAM_READ;
last byte = RamDATA&Oxff;
if(last_byte !='E' && last byte !='P')
storeAddressState=10; // Bad Address
else
storeAddressState++;
break;
case 2:
while (last byte !_':' RR last byte!--':' && headerSi-r_e<1~9AXADDRESS);
headerSize++;
if (last byte =',')
headerCount++;
Itemp++~
RamADDRESS=(temp;
RAM_READ;
last byte = RamDATA&Oxff;
if(headerSize<MAXADDRESS && headerSize>(headerCount*7));
headerSize=0;
(temp=Istart
storeAddressState++;
r
else
storeAddressState=10; // Bad Address
break;
125

CA 02332297 2001-O1-25
case 3:
RamADDRESS=(temp;
RAM_READ;
last byte = RamDATA&Oxff;
if (last byte !_';' && last byte!--':'){
if(headAddress=0x42)
rtc write(headerSize+headAddress,last byte);
else
eepromBuffer(headerSize+headAddress,last byte)
headerSize++;
hemp++;
)
else storeAddressState=5;
break;
case 5:
if(headAddress=0x42)
rtcyrite(headAddress-2,headerSize);
else
eepromBuffer(headAddress-2,headerSize);
storeAddressState++;
break;
case 6:
if(headAddress =0x42)
rtc write(headAddress-l,headerCount);
else
eepromBuffer(headAddress-I,headerCount);
storeAddressState++;
break;
case 7:
storeAddressState=0;
break;
case 10: // Bad Address. The calling function will set state back to 0.
break;
void setNickname(void){
switch(setNicknameState){
case 0:
setNicknameState++;
(temp=OxAO;
RamADDRESS=lstart
RAM_READ;
last byte = RamDATA&Oxff;
break;
case 1:
l start++;
RamADDRESS=lstart;
RAM_READ;
received_bvte = RamDATA&Oxff:
if ((last byte = OxSc) && (received byte =='n')) {
(start++;
RamADDRESS=lstart;
RAM_READ;
received byte = RamDATA&Oxff;
eepromBuffer(Itemp,OxOd);
else
eepromBuffer(Itemp,last_byte);
ltemp++;
126

CA 02332297 2001-O1-25
last byte=received byte;
setNicknameState++;
break;
case 2:
if (last byte !_ ;' && last byte !_':' && hemp<OxDA)
setNicknameState=1;
else if(Itemp<OxDA){
eepromBuffer((temp,';');
setNicknameState++;
}
else {
setNicknameState=0;
break;
case 3:
setNicknameState=0;
break;
}
~******************************************************
Incoming Message Handlers
unsigned char getByte( unsigned int address);
char getMessage( void);
char matchPassword( unsigned int password);
unsigned char checkExpiration(void);
void getChar(void);
void executePagerCommand(void);
******************************************************~
char getMessage( void){
switch(getMessageState) {
case 0:
getMessageState=1;
lindex=0;
pagerResponse=0;
noPagesToday = 0;
thisMessageUnlocked = 0;
pagerComAbortTime=lastCentiTime+jp0;
messageStatus=ACK;
break;
case 1:
if (kbhitPagerQ){
received byte=getc(PAGER);
pagerResponse++;
if (pagerResponse>2){
getMessageState=2;
pagerResponse=1;
1
1
pagerComAbortTime=IastCentiTime+500;
i
else if (pagerComAbortTime<lastCentiTime) getA9essageState=Oxff;
break;
case 2:
if (kbhitPager()){
RamDATA = getc(PAGER);
RamADDRESS = lindex+OFFSET2;
RAM_WRITE;
lindex++;
pagerResponse++;
127

CA 02332297 2001-O1-25
pagerComAbortTime=IastCentiTime+500;
if(pagerResponse>128){
getMessageState=3;
)
else if (pagerComAbortTime<lastCentiTime) getMessageState=Oxff;
break;
case 3:
if (kbhitPager()) { // We should check the checksum and NAK if wrong here!!
received byte = getc(PAGER);
getMessageState=4;
putcPager(ACK);
pagerComAbortTime=lastCentiTime+500;
else if (pagerComAbortTime<lastCentiTime) getMessageState=Oxff;
break;
case 4:
if (kbhitPager()){
received byte = getc(PAGER):
if(received byte=EOT) {
getMessageState=~;
messageEnd = lindex;
putcPager(ACK);
pagerComAbortTime=IastCentiTime+100;
else {
getMessageState=1;
pagerResponse=I;
pagerComAbortTime=IastCentiTime+500;
;
else if (pagerComAbortTime<IastCentiTime) getMessageState=Oxff;
break;
case ~:
if (pagerComAbortTime<lastCentiTime) ( // .lust used as a time delay here.
pagerMessage=0;
getMessageState++;
for(lstart=OFFSET2;lstart<messageEnd+OFFSET2;lstart++){
RamADDRESS=(start;
RAM_READ;
i = RamDATA&Oxff;
RAM_READ;
j = RamDATA&Oxff;
if ((i =_':') && (j =':')) {
RamADDRESS = lstart;
RamDATA = 0:
RAM_V'RITE; // Clear the ":." for next scan for concatenated commands
RAM_WRITE;
Istart+=2;
crc=0;
CaIcCRConRamAddress(lstart);
CaIcCRConRamAddress(lstart+I );
pagerMessage = getByte(Istart);
lstart+=2;
if((pagerMessage=OxOD)~ ~(pagerMessage=Ox07)~ ~ (pagerMessage=Ox I D)~ I
(pagerMessage==0x27)~~(pagerMessage=Ox92)~~(pagerMessage=Ox96)~~
(pagerMessage=OxOE)~~
thisMessageUnlocked) {
break:
;
128

CA 02332297 2001-O1-25
else{
if(!binaryFlag){
for (itemp=O;itemp<4;itemp++){
CaIcCRConRamAddress(Istart+itemp);
)
messageLength = getByte(Istart);
messageLength «= 8;
messageLength += getByte(Istart+2);
messageLength -= 8;
messageCRC = getByte(lstart+messageLength);
messageCRC «= 8;
messageCRC += getByte(lstart+2+messageLength);
(start += 4;
cry°ptData = (start;
cyptDataLength = messageLength - 4;
else {
for (itemp=O;hemp<2;itemp++){
CaIcCRConRamAddress((start+itemp);
1
RamADDRESS = (start;
messageLength = ramReadlnt();
messageLength -= 6;
RamADDRESS = (start + messageLength:
messageCRC = ramReadlnt():
(start +_ ~;
cryptData = (start;
cryptDataLength = messageLength - 2;
1
1
if(messageLength>750) {
pagerMessage = 0;
break;
rc4crypt();
if(!binaryFlag)
cr)~ptDataLength »= 1;
for (hemp=O;itemp<cryptDataLength;itemp++) {
CaIcCRConRamAddress((start+itemp):
i
1
CaIcCRC(Ox00):
CaIcCRC(Ox00);
if(messageCRC != crc){
pagerMessage = 0;
putHexIntPager(messageCRC);
putHexIntPager(crc);
break;
RamADDRESS = (start;
expiryTime = ramReadInt();
expiryDate = ramReadInt();
password = ramReadInt();
i=matchPassword(password);
(start+=6;
if ((i=1 )II(i=~)) i
thisMessageUnlocked = 1:
else if (i=3){
RamADDRESS=(start;
RAM_READ;
j = RamDATA&Oxff;
129

CA 02332297 2001-O1-25
whichPass=toint(j);
if ((whichPass=I )~~(whichPass=2)){
(start++;
thisMessageUnlocked = 1;
;
if(thisMessageUnlocked){
received byte = checkExpiration();
if(received byte){
thisMessageUnlocked = 0;
pagerMessage = 0;
crcEcho = messageCRC;
exceptionFlag = ~;
)
else {
pagerMessage = 0;
break:
;
r
break;
case 6:
getMessageState=Oxff;
if(pagerMessage){
RamADDRESS=lstart;
for(hemp=lstart;Itemp<messageEnd+OFFSET2;ltemp++) { // if ok password, scan
for closing ":'
RAM_READ;
i = RamDATA&Oxff;
if(i =_':')
getMessageState=0:
if(getMessageState) // Did not find a ";'
pagerMessage=0;
break;
case Oxff:
messageStatus=NAK;
getMessageState=0;
break;
r
char matchPassword( unsigned int password) {
whichPass=0;
if (password =XPTPASSWORD) whichPass=3;
else if (password=modulelPass) whichPass=I;
else if (password=module2Pass) whichPass=2;
return(whichPass);
r
unsigned char checkExpiration(void) {
rtc_get datetime(&time);
alarm.yr = expiryDate» 12;
alarm.mth = expiryDate»8;
alarm.mth &= OxOF;
alarm.day = expiryDate&OxFF:
if(alarm.yr != time.yr);
1~~

CA 02332297 2001-O1-25
if(alarm.yr=-((time.yr+1 )%4)) {
if(alarm.mth=1 && time.mth=12 && (31-time.day+alarm.day)<8){
return (0);
}
return (1);
if(alarm.mth !=time.mth){
if(alarm.mth=(time.mth+1 )) {
if((31-time.day+alarm.day)<11){ // Specify 1 week max but allow 11 days
return (0); // except for Feb. 28th (sloppy is OK)
i
return (2);
}
if(alarm.day<time.day ~~ alarm.day>(time.day+7))
return (3);
if(alarm.day!=time.day ~~ timeOfDay<expiryTime)
return (0);
return (4);
void getChar(void){
RamADDRESS=lstart;
RAM_READ;
received byte = RamDATA&Oxff;
Istart++;
terminatorFlag = 0;
if(received_byte=;' ~~ received b~~te--=:')
terminatorFlag++;
void rc4crypt(void){
// unsiened rot's
#define cyptDataPos pqReportTime
// unsigned char's
#define xCrypt pqEvent
#dctine yCrypt pqInProgress
#define keyPosition pqDurationLimit
#define keyByte pqReportDelay
#define sxCrypt pqEventStatus
#define syCrypt pqReminderDelay
#define keyLength pqOffDela~~
#define cryptDataByte pqFault
RamADDRESS = 0x5500;
RamDATA = 0;
xCrypt=0;
do {
RAM_WRITE;
RamDATA++;
xCrypt++;
while(xCrypt);
xCrypt = 0;
yCrypt = 0;
keyPosition = 0;
RamADDRESS = Ox538C;
RAM_READ;
keyLength = RamDATA&Oxff;
if(!ke~~Length){
131

CA 02332297 2001-O1-25
if(!binaryFlag && !addCRCflag){
for(cryptDataPos=O;cryptDataPos<cryptDataLength;cryptDataPos+=2) {
cryptDataByte = getByte(cryptData+cryptDataPos);
RamADDRESS = (cryptDataPos» 1 ) + cryptData;
RamDATA = cryptDataByte;
RAM_WRITE;
1
J
1
J
return;
RamADDRESS = Ox538D + keyLength;
ram W ritelnt(messageCRC);
keyLength += 2;
do {
RamADDRESS = Ox538D + keyPosition;
RAM_READ;
keyByte = RamDATA&Oxff;
RamADDRESS = 0x5500 + xCrypt;
RAM_READ;
sxCrypt = RamDATA&Oxff;
yCrypt += sxCrypt + keyByte;
RamADDRESS = 0x5500 + yCrypt;
RAM_READ;
RamADDRESS = 0x5500 + xCrypt;
RAM_WRITE;
RamADDRESS = 0x5500 + yCrypt;
RamDATA = sxCrypt;
RAM V~RITE;
keyPosition++;
if(keyPosition=keyLength)
keyPosition=0:
xCrypt++;
while(xCrypt);
xCrypt = 0;
y,Crypt = 0;
cryptDataPos = 0;
do J
xCr~~pt++;
RamADDRESS = 0x5500 + xCrypt;
RAM_READ;
sxCrypt = RamDATA&Oxff;
yCrypt += sxCrypt;
RamADDRESS = 0x5500 + yCrypt;
RAM_READ;
syCrypt = RamDATA&Oxff;
RamADDRESS = 0x5500 + xCrypt;
RAM_WRITE;
RamADDRESS = 0x5500 + yCrypt;
RamDATA = sxCrypt;
RAM_WRITE:
sxCrypt += syCrypt;
RamADDRESS = 0x5500 + sxCrypt:
RAM READ:
132

CA 02332297 2001-O1-25
syCrypt = RamDATA&Oxff;
if(!binaryFlag && !addCRCflag)
cryptDataByte = getByte(cryptData+cryptDataPos);
else {
RamADDRESS=cryptData+cryptDataPos;
RAM_READ;
cryptDataByte = RamDATA&Oxff;
cryptDataByte ~= syCrypt;
RamADDRESS = cryptDataPos;
if(!binaryFlag && !addCRCflag)
RamADDRESS »= 1:
RamADDRESS += cryptData;
RamDATA = cryptDataByte;
RAM WRITE;
cryptDataPos ++;
if(!binaryFlag && !addCRCflag)
cryptDataPos ++;
} while(cryptDataPos<cryptDataLength);
r
void spreadTimer(void){
switch(spreadTimerState){
case 0:
spreadTimerState++;
spreadCount=0;
exceptionTime = lastCentiTime + 300;
break;
case 1:
if (exceptionTime<lastCentiTime){
spreadCount++;
if(spreadCount>=spreadDelay){
spreadTimerState=0;
}
else {
exceptionTime = lastCentiTime + 300:
spreadTimerState++;
yy 18();
;
break;
case 2:
if(!yy l8State){
RamADDRESS = Ox50CF; // Pbuffer[ 15}
RAM_READ;
received byte = RamDATA&Oxff;
if(received_byte) {
spreadTimerState=0;
if(degradeState)
abortFlag = TRUE;
else {
if(degradeState){
st 1 pulse=OxF;
st2pulse=OxA;
}
else {
st 1 pulse=OxA;
st2pulse=OxB;
IJJ

CA 02332297 2001-O1-25
pulseCycles=3;
spreadTimerState=1;
)
break;
f
1 0 void degrade( void){
if(degradeState=0){
if ( valDegrade = 0 ){
attemptCount=1;
valDegrade=2;
)
else {
if (valDegrade >= 32) {
abortFlag = TRUE;
else {
spreadDelay = 20;
spreadTimer();
degradeState=I;
;
r
else if (!spreadTimerState) {
if(abortFlag) {
degradeState=0;
spreadDelay=read ext eeprom(Ox 12);
W
else if (valDegrade>degradeState) {
spreadDelay = 20;
spreadTimer();
degradeState++;
else {
attemptCount++;
valDegrade+=valDegrade;
degradeState=0;
spreadDelay=read ext eeprom(Oxl2);
reestablishPager();
r
r
;
#pragma code executePagerCommand = OxA000
void executePagerCommand(void) {
switch(pagerMessage){
case I: // Resend last data
switch (executePagerCommandState){
case 0:
executePagerCommandState=I ;
break;
case I:
end01=Oxff;
start0l = getByte(lstart);
if (!terminatorFlag){
itemp=getByte(lstart+2);
134

CA 02332297 2001-O1-25
if (!terminatorFlag){
end01 = hemp;
l
calcSendDataQ;
executePagerCommandState=2;
break;
case 2:
if (!calcSendDataState);
executePagerCommandState=0;
start0l=0;
end01=Oxff;
break;
break;
case 2: // Set or Reset Economy flag
getChar();
if(! terminatorFlag) {
economyFlag=toint(received byte);
eepromBuffer(OW d,economyFlag);
saveParCheckSum();
else
messageStatus=NAK;
break;
case 3: // Execute command string immediately
switch (executePagerCommandState){
case 0:
executePagerCommandState++;
status=0;
useTempAddress = 0;
sendParameters();
break;
case 1:
if(sendl'arametersState==~);
executePagerCommandState++;
break;
case 2:
executeMultipleCommands(lstart);
executePagerCommandState++;
break;
case 3:
if(!executeMultipleState) {
sendParametersState++;
executePagerCommandState++;
r
break;
case 4:
if(!sendParametersState) {
executePagerCommandState=0;
i
break;
break;
case 4: // Set binary transmission flag
getCharQ;
if(!terminatorFlag){
received byte=toint(received byte);
135

CA 02332297 2001-O1-25
if(binaryFlag!=received byte){
binaryFlag = received byte;
eepromBuffer(OxSe,binaryFlag);
saveParCheckSum();
f
else
messageStatus=NAK;
break;
case 5: // Execute timer'n' command
string
switch (executePagerCommandState){
case 0:
executePagerCommandState++;
status=0;
useTempAddress = 0;
RamADDRESS=lstart;
RAM READ;
timer = RamDATA&Oxff;
timer = toint(timer);
if (timer>7){
executePagerCommandState=0;
messageStatus = NAK;
else {
iIndex=timer;
iIndex*=128;
iIndex+=5;
ilndex+=Oa4C00;
RamADDRESS=iIndex;
RAM_READ;
received byte = RamDATA&Oxff;
if(received byte='P'){
reestablishPager();
executePagerCommandState=10;
;
else {
sendParameters();
r
break;
case 1:
if(sendParametersState---5) {
executePagerCommandState++;
t
1
break;
case 2:
executeMultipleCommands(ilndex);
executePagerCommandState++;
break;
case 3:
if(!executeMultipleState) {
if(runSSIcommand){
executePagerCommandState=0;
sendParametersState=0;
)
else {
sendParametersState++~
executePagerCommandState=4;
r
;
136

CA 02332297 2001-O1-25
break;
case 4:
if(! sendParametersState)
executePagerCommandState=0;
break;
case 10:
if(!reestablishPagerState)
executePagerCommandState=0;
break;
}
break;
case 6: // Change stored Destination ID(s)
switch (executePagerCommandState){
case 0:
executePagerCommandState= t ;
break;
case 1:
storeAddress(FALSE);
executePagerCommandState=2;
break;
case 2:
if(!storeAddressState)
executePagerCommandState=3;
if(storeAddressState==10) { // Bad Address.
executePagerCommandState=0;
storeAddressState=0;
messageStatus = NAK;
break;
case 3:
eepromBuffer(OxOC,O); // using new destination
newDestination = 0;
saveParCheckSumQ;
executePagerCommandState=0;
break;
r
break;
case Ox27:
economyFlag = 0;
case 7: // Send status string
switch (executePagerCommandState){
case 0: // In get Status
executePagerCommandState=1;
break;
case 1: // In get Status
RamADDRESS=lstart;
RAM READ;
echoSize = RamDATA&Oxff;
if (echoSize =_ '/') {
(start++;
RamADDRESS=lstart;
for(echoSize=O;echoSize<9;echoSize++)
RAM_READ;
timer = RamDATA&Oxff;
lstart++;
if (timer ='/') break;
echoBuffjechoSize]=timer;
r
else{
1~7

CA 02332297 2001-O1-25
echoBuff[0]='0';
echoSize=1;
status= I ;
useTempAddress= 1;
storeAddress(TRUE); // from incoming
to eeprom storage
executePagerCommandState=2;
break;
case 2: // In get Status
if(!storeAddressState)
executePagerCommandState=3;
if(storeAddressState=10) { // Bad
Address.
executePagerCommandState=0;
storeAddressState=0;
)
break;
case 3: // In get Status
executePagerCommandState=5;
break;
case 5: // In get Status
lindex=0;
convertAnd WriteToSendBuffer(pagerMessage);
pagerMessage=7; // If was 0x27 change
to 0x07
writeTime(RTC);
executePagerCommandState=6;
break;
case 6: // In get Status
if(!writeTimeState)
executePagerCommandState=7;
break;
case 7: // In get Status
writeToSendBuffer('f);
headerSize = read_ext eeprom(Ox 1 d);
for (i=O;i<headerSize;i++)(
received_byte = read_ext_eeprom(i+Ox 1 f);
writeToSendE3uffer(received byte);
writeToSendBuffer('f);
convertAndWriteToSendBuffer(timerMask);
convertAndWriteToSendBuffer(exceptionMask);
writeToSendBuffer('f);
received byte = read ext_eeprom(OxSd); // economyFlag
received byte ~= binaryFlag«I;
received byte ~= compressionEnabled«2;
received byte ~= pqEnabled«3;
received byte ~= pqVerbosityEnabled«4;
received byte ~= pagerDiagnostics«5;
received byte ~= killPower«6;
convertAndWriteToSendBuffer(received byte);
writeToSendBuffer('f);
convertAndWriteToSendBuffer(spreadDelay);
writeToSendBuffer('f);
writeToSendBuffer(to ascii(binaryFlag));
writeToSendBuffer('f);
138

CA 02332297 2001-O1-25
for (timer-O;timer<echoSize;timer++)
writeToSendBuffer(echoBuff(timer]); //Echo characters
writeToSendBuffer('f);
tempMask=1;
for(i=O;i<8; i++) {
if ((timerMask&tempMask) ~~ !economyFlag){
(temp=i;
Itemp*=128;
Itemp+=OFFSET 1;
j=0;
tempt=to_ascii(i);
writeToSendBuffer(temp2);
getAlarm(i);
itemp=to_bcd(alarm.mth);
convertAndWriteToSendBuffer(itemp);
hemp=to_bcd(alarm.day);
convertAndWriteToSendBuffer(hemp);
hemp=to_bcd(alarm.hr);
convertAndWriteToSendBuffer(hemp);
hemp=to_bed(alarm. mi n);
convertAndVhriteToSendBuffer(hemp);
hemp=to_bcd(alarm.sec);
convertAndWriteToSendBuffer(hemp);
do {
last byte=read_ext_eeprom(Itemp);
if (j=0 ~~ j=4) { // Period or add spread
delay
itemp=to_ascii(last byte);
writeToSendBuffer(itemp);
;
else if (j<4) { // interval, hour & minute
hemp=to_bcd(last byte);
convertAndWriteToSendBuffer(itemp);
i
else { // meter commands
writeToSendBuffer(last byte);
j++;
hemp++;
; while (j<j ~I last byte !_';');
tempMask*=2;
executePagerCommandState=8;
break;
case 8: // In get Status
if (!economyFlag) {
hemp=rtc_read(Oxl3); // Zone
convertAndWriteToSendBuffer(hemp);
hemp=rtc_read(Oxl4); // Subzone
convertAndWriteToSendBuffer(itemp);
writeToSendBuffer('f); // Bytes sent
OK
itemp=rtc_read(Ox 15 );
convertAndWriteToSendBuffer(itemp);
hemp=rtc_read(Ox 16);
convertAndWriteToSendBuffer(hemp);
writeToSendBuffer('f); // RTC Time and Alarm time
writeTime(RTC_NO_YEAR);
executePagerCommandState=9;
139

CA 02332297 2001-O1-25
t
else
executePagerCommandState=1 I ;
break;
case 9: // In get Status
if(!writeTimeState){
executePagerCommandState=10;
writeTime(RTC_ALARM);
break;
case 10: // In get Status
if(!writeTimeState)
executePagerCommandState=1 1;
break;
case 1 1: // In get Status
writeToSendBuffer('f);
received byte = read_ext_eeprom(OxOe); // Meter Error Mask
convertAndWriteToSendBuffer(received byte);
received byte = read_ext_eeprom(OxOf); // Meter Error Mask
convertAndWriteToSendBuffer(received byte);
writeToSendBuffer('f);
writeMeterSerial();
executePagerCommandState++;
break;
case 12: // In get Status
if (!writeMeterSerialState) {
writeToSendBuffer('f);
convertAndWriteToSendBuffer(synchToAtomicTime);
writeToSendBuffer('f);
economyFlag = read ext eeprom(OxSd): // Set it back if command 0x27
addCRCQ;
calcSendDataQ;
executePagerCommandState++;
t
break;
case 13: // In get Status
if (!calcSendDataState)
executePagerCommandState=0;
break;
;-
break;
case 8: // Set Timer and Exception Mask
switch (executePagerCommandState) {
case 0:
executePagerCommandState=1;
break;
case 1:
executePagerCommandState=2;
break;
case 2:
executePagerCommandState=3;
break;
case 3:
timerMask=getByte(lstart);
exceptionMask=getByte(Istart+2);
validateTimerMask();
eepromBuffer(Ox I O,timerMask);
eepromBuffer(Oxll,exceptionMask);
saveParCheckSum();
rtc set irqQ;
140

CA 02332297 2001-O1-25
executePagerCommandState=0;
if(acOKtimer && exceptionMask&0x02)
powerSaveSleep();
break;
;
break;
case OxOB: // Change spread Delay
spreadDelay=getByte(lstart);
eepromBuffer(Ox l2,spreadDelay);
saveParCheckSumQ;
break;
case OxOc: // Clear bytesSentOK
bytesSentOK=0;
rtc write(Ox15,0);
rtc_write(Ox16,0);
break;
case OxOd: // Ping
switch (executePagerCommandState){
case 0:
executePagerCommandState=1;
break;
case 1:
status=2;
useTempAddress= I;
storeAddress(TRUE);
executePagerCommandState=2;
break;
case 2:
if(!storeAddressState)
executePagerCommandState=3;
if(storeAddressState---10) { // Bad Address.
executePagerCommandState=0;
storeAddressState=0;
break;
case 3:
valDegrade=0;
sendPing();
executePagerCommandState=4;
break;
case 4:
if(!sendPingState){
executePagerCommandState=0;
useTempAddress = 0;
;
break;
r
break;
case OxOe: /1 Commission over the air
newDestination = 0x50;
eepromBuffer(OxOC,newDestination); // using default destination
commissionButtonPress();
break;
case OxOf: // Send Dates only
onlyDates = 2;
pagerMessage=Ox 10;
executePagerCommandState=I ;
break:
case 0x10: // Send Power Outage Data
141

CA 02332297 2001-O1-25
switch (executePagerCommandState){
case 0:
executePagerCommandState=1;
onlyDates = 3;
break;
case 1:
useTempAddress = 0;
status=0;
economyFlag= I;
sendParameters();
executePagerCommandState=2;
break;
case 2:
if(sendParametersState=S){
received byte=getByte(Istart);
command[0]=3;
command[1]=received byte;
for(i=2;i<9;i++) command[i]=0;
command [ 10]=0;
command[9]=received byte+3;
sendFlag=TRUE;
sendCommandQ;
executePagerCommandState=3;
break:
case 3:
if(!sendCommandState);
onlyDates = FALSE;
sendParametersState++:
executePagerCommandState=4;
break;
case 4:
if(!sendParametersState){
economyFlag=read ext_eeprom(OxSd);//
Restore economyFlag
executePagerCommandState=0;
i
break:
break;
case Ox 11: // Send specific Dates of Load Profile
switch (executePagerCommandState) {
case 0:
executePagerCommandState++;
break;
case 1:
useTempAddress = 0;
status=0;
economyFlag= 1;
startDay=getByte(Istart);
startDay=to dec(startDay,OxfD);
startMonth=getByte(lstart+2);
startMonth=to_dec(startMonth,Oxfl~);
endDay=1;
RamADDRESS=Istart+4;
RAM READ;
hemp = RamDATA&Oxff;
if (itemp !_';' && hemp !_':'){
142

CA 02332297 2001-O1-25
hemp=toint(itemp)* 16;
RamADDRESS=lstart+5;
RAM_READ;
endDay = itemp+toint(RamDATA&Oxff);
;
if (!startMonth ~~ !startDay){
executePagerCommandState=0;
messageStatus = NAK;
else {
sendParameters();
executePagerCommandState=2;
break;
case 2:
if(sendParametersState=5)
executePagerCommandState=3;
break;
case 3:
if (time.mth=startMonth){
if (time.day>startDay)
LPdays=time.day-startDay;
else
LPdays=0;
;
else {
if (time.mth<startMonth)
time.mth+=12;
LPdays=(31 *((time.mth-startMonth)-1 ))+time.day+(31-startDay):
)
time.day=startDay+endDay;
time.mth=startMonth;
time.period=1;
time.interval=1;
validateTime(&time):
if(time.mth> 12)
time.mth-=12;
endMonth=time.mth;
endDay=time.day;
startDay=to bcd(startDay);
startMonth=to bcd(startMonth);
startMonth~=0x80;
endDay=to bcd(endDay);
endMonth=to bcd(endMonth);
endMonth~=0x80;
isLPenabledQ;
executePagerCommandState=4;
break;
case 4:
if(! isLPenabledState){
if(isLPenabledReturn)
executePagerCommandState=5;
else{
executePagerCommandState=8;
sendParametersState=0;
r
1
l
break:
143

CA 02332297 2001-O1-25
case 5:
getLPdataQ;
executePagerCommandState=6;
break;
case 6:
if(! getLPdataState) {
caIcLPsize();
sendFlag=TRUE;
sendCommand();
executePagerCommandState=7;
l
l
break;
case 7:
if(!sendCommandState) {
if(compressionEnabled && !hadLPerror)
compressLPdataQ;
sendParametersState++;
executePagerCommandState=8;
break;
case 8:
if(! sendParametersState) {
economyFlag=read ext_eeprom(Ox~d);// Restore economyFlag
executePagerCommandState=0;
break;
i
break;
case Ox 12: // Get Parsing Array
switch (executePagerCommandState){
case 0:
executePagerCommandState=1;
break;
case 1:
Itemp2 = 0x60;
sendParsingArray();
executePagerCommandState=2;
break;
case 2:
if(!sendParsingArrayState)
executePagerCommandState=0;
break;
i
break;
case 0x13: // Set Parsing Array
ltemp2 = 0x60;
setParsingArray();
Itemp2 = 0x60;
clipEepromToRam();
break;
case 0x14: // Force WatchDog Timeout
if(exceptionMask&8){ // echo mode (change zone to force an autoregistration)
received byte = rtc read(Ox I 3) + 1;
rtc write(Oxl3,received_byte);
i
for(;;);
break;
case Ox I 5: // Set Meter Password
if (whichPass=1 ) {
144

CA 02332297 2001-O1-25
meter I Passes=getByte(Istart);
meter 1 PassM=getByte(lstart+2);
meterl PassL=getByte(lstart+4);
eepromBuffer(Oxl3,meterlPassH);
eepromBuffer(Ox l4,meterl PassM);
eepromBuffer(Ox 1 S,meter 1
PassL);
if (whichPass=2){
meter2PassH=getByte(lstart);
meter2PassM=getByte(Istart+2);
meter2PassL=getByte(Istart+4);
eepromBuffer(Ox 16,meter2PassH);
eepromBuffer(Ox 17,meter2PassM);
eepromBuffer(Ox 18,meter2PassL);
saveParCheckSumQ;
break;
case Ox 16: // Set Module Passwords
temp 1=getByte(Istart);
password=tempi;
password=password8;
tempt=getByte(Istart+2);
password+=tempt;
if (whichPass=1){
module 1 Pass=password;
eepromBuffer(Ox l9,temp I );
eepromBuffer(Ox 1 a,temp2);
i
if (whichPass=2) {
module2Pass=password;
eepromBuffer(Ox 1 b,temp 1
);
eepromBuffer(Ox 1 c,temp2);
saveParCheckSum();
break;
case Ox 1 c: // Set Site Name
switch (executePagerCommandState)
{
case 0:
executePagerCommandState=1;
break;
case 1:
setNicknameQ;
executePagerCommandState=2;
break;
case 2:
if(!setNicknameState) {
saveParCheckSumQ;
executePagerCommandState=0;
break;
break;
case Oxld: // Get Meter Information
(& Site Name)
switch (executePagerCommandState)
{
case 0: // In get Meter Info
executePagerCommandState=1;
break;
case 1: // In get Meter Info
status=1;
useTempAddress= 1;
145

CA 02332297 2001-O1-25
storeAddress(TRUE); // from incoming to eeprom storage
executePagerCommandState=2;
break;
case 2: // In get Meter Info
if(!storeAddressState){
executePagerCommandState=3;
if(storeAddressState=10) { // Bad
Address.
executePagerCommandState=0;
storeAddressState=0;
break;
case 3: // In get Meter Info
(index=0;
convertAndWriteToSendBuffer(pagerMessage);
command[0]=Ox6f;
for(i=l;i<1 (;i++) command[i]=0;
command[9]=Ox6f;
sendFlag=FALSE;
sendCommand();
executePagerCommandState++;
break;
case 4: // In get Meter Info
if(!sendCommandState){
executePagerCommandState++;
r
break;
case 5: // In get Meter Info
writeToSendBuffer('/');
if(!badSendCommand){
for(i=17;i!=255;1--){
// itemp = Mbuffer[i];
RamADDRESS = Ox4b00 + i:
hemp = ramReadUcharQ;
if (hemp<Ox20 ~~ itemp>Ox7E)
itemp ='$ ;
writeToSendBuffer(itemp);
writeToSendBuffer(OxOd);
writeToSendBuffer('f);
command[O]=0x02;
for(i=l;i<ll;i++) command[i]=0;
command[9]=0x02;
sendFlag=FALSE;
sendCommandQ;
executePagerCommandState++;
break;
case 6: // In get Meter Info
if(!sendCommandState) {
executePagerCommandState++;
break;
case 7: // In get Meter Info
if(!badSendCommand){
RamADDRESS = Ox4b00;
hemp = ramReadUchar();
convertAndWriteToSendBuffer(itemp);
RamADDRESS = Ox4b01;
hemp = ramReadUcharQ;
146

CA 02332297 2001-O1-25
convertAndWriteToSendBuffer(hemp);
RamADDRESS = Ox4b03;
hemp = ramReadUcharQ;
convertAndWriteToSendBuffer(itemp);
RamADDRESS = Ox4b02;
hemp = ramReadUchar();
convertAndWriteToSendBuffer(hemp);
writeToSendBuffer('f );
command [0]=0x01;
for(i=l;i<1 l;i++) command[i]=0;
command [9]=0x01;
sendFlag=FALSE;
sendCommandQ;
executePagerCommandState++;
break;
case 8: // In get Meter Info
if(! sendCommandState) {
executePagerCommandState++;
break;
case 9: // In get Meter Info
if(!badSendCommand){
RamADDRESS = Ox4b02;
hemp = ramReadUcharQ;
convertAndWriteToSendBuffer(hemp);
RamADDRESS = Ox4b01;
hemp = ramReadUchar();
convertAndWriteToSendBuffer(itemp);
RamADDRESS = Ox4b00;
hemp = ramReadUchar();
convertAndWriteToSendBuffer(hemp);
f
writeToSendBuffer('f);
command[0]=Ox9F;
for(i=l;i<I l;i++) command[iJ=0;
command[9]=Ox9F;
sendFlag=FALSE;
sendCommand();
executePagerCommandState++;
break;
case 10: // In get Meter Info
if(!sendCommandState)
executePagerCommandState++;
break:
case 1 1: // In get Meter Info
if(!badSendCommand){
RamADDRESS = Ox4b02:
hemp = ramReadUchar();
hemp*=3;
itemp+=5;
RamADDRESS = Ox4b00 + hemp;
received byte = ramReadUchar();
convertAndWriteToSendBuffer(received
byte):
;
writeToSendBuffer(OxOd);
writeToSendBuffer('f);
writeMeterSerial();
executePagerCommandState++;
break;
147

CA 02332297 2001-O1-25
case 12: // In get Meter Info
if(!writeMeterSerialState)
executePagerCommandState++;
break;
case 13: // In get Meter Info
writeToSendBuffer(OxOd);
(temp=OxAO;
do {
last byte=read_ext_eeprom(ltemp);
writeToSendBuffer(last byte);
(temp++;
} while (last byte !_ ;' && hemp<OxDA);
writeToSendBuffer(OxOd);
Itemp2 = OxDA;
clipEepromToRamQ;
economyFlag=1; // Always use Parsing Array
executeMultipleCommands(0x5000);
executePagerCommandState++;
break;
case 14: // In get Meter Info
if(!executeMuItipIeState)
executePagerCommandState++;
break;
case I ~: // In get Meter Info
ltemp2 = 0x60;
clipEepromToRam();
economyFlag=read_ext eeprom(Ox~d);// Restore economyFlag
writeToSendBuffer('f);
writeTime(PAGER);
executePagerCommandState++;
break;
case 16:
if(!writeTimeState) {
writeToSendBuffer('f);
addCRCQ;
calcSendDataQ;
executePagerCommandState++;
}
break;
case 17: // In get Meter Info
if(!calcSendDataState)
executePagerCommandState=0:
break;
r
break;
case Ox 1 e: // Set Timer Event
switch (executePagerCommandState) {
case 0:
executePagerCommandState++;
rtc_get datetime(&alarm);
RamADDRESS=lstart;
RAM_READ;
timer = toint(RamDATA&Oxff);
RamADDRESS=(start+1;
RAM_READ;
alarm.period = toint(RamDATA&Oxff);
alarm. interval=getByte(lstart+2):
alarm.interval=to dec(alarm.interval,Oxf>)):
148

CA 02332297 2001-O1-25
if (alarm.period=0 ~~ alarm.period>3 ~~ !alarm.
interval){
messageStatus = NAK;
executePagerCommandState=0;
i
break;
case 1:
if(alarm.period=1 && alarm.interval>96) alarm.interval=96;
if(alarm.period=2 && alarm.interval>7) alarm.
interval=7;
if(alarm.period=3 && alarm.interval>31) alarm.interval=31;
if(alarm.period=3) {
alarm.day = alarm.interval;
alarm.hr-getByte(Istart+4);
alarm.hrto dec(alarm.hr,OxfD);
alarm.min=getByte(lstart+6);
alarm.min=to_dec(alarm.min,OxfO);
RamADDRESS=Istart+8;
RAM_READ;
alarm.addSpreadDelay = RamDATA&Oxff;
alarm.addSpreadDelay = toint(alarm.addSpreadDelay);
alarm.sec=0;
saveAlarm(timer);
ltemp=timer;
ltemp*=128;
(temp+=OFFSET1;
eepromBuffer(hemp++,alarm.period);
eepromBuffer(hemp++,alarm.interval);
eepromBuffer(Itemp++,alarm.hr);
eepromBuffer(ltemp++,alarm.min);
eepromBuffer(hemp++,alarm.addSpreadDelay);
Itemp2=0;
ltemp3=lstart+9;
do {
RamADDRESS=Itemp3;
RAM_READ;
last byte = RamDATA&Oxff;
RamDATA = 0; // To clear possible embedded SSI
commands.
RamADDRESS=Itemp3; // So they won't be confused
with concatenated
RAM_WRITE; // SSI commands.
eepromBuffer((Itemp+ltemp2).last bye);
Itemp3++;
Itemp2++;
while (last byte !_';');
last byte = 1 timer;
timerMask ~= last byte;
eepromBuffer(Ox 1 O,timerMask);
saveParCheckSum();
executePagerCommandState++;
break;
case 2:
if(!saveParCheckSumState)
executePagerCommandState++;
break;
case 3:
initAlarm(timer);
checkAlarm(timer);
setAlarm();
ltemp=timer;
149

CA 02332297 2001-O1-25
(temp*=128;
RamADDRESS=(temp+0x4C00;
(temp+=OFFSET(;
for(i=0; i< I 28; i++) {
RamDATA = read ext_eeprom(ltemp
+ i);
RAM WRITE;
executePagerCommandState=0;
break;
;
break;
case Oxlf: // Set Meter Information
Command String
ltemp2 = Ox 11 A;
i=0;
do {
RamADDRESS=(start;
RAM_READ;
last byte = RamDATA&Oxff;
RamDATA = last byte;
RamADDRESS=0x5000+i;
RAM_W RITE;
eepromBuffer(ltemp2,last_byte);
i++;
(start++;
Itemp2++;
while (last byte !_';' && i<128);
saveParCheckSum();
break;
case 0x20: // Set Meter Information
Parsing Array
Itemp2 = OxDA;
setParsingArray();
break;
case Ox21: // Set Meter Error
Codes mask
hemp=getByte(Istart);
eepromBuffer(OxOe,itemp);
hemp=getByte(Istart+2);
eepromBuffer(OxOf,itemp);
saveParCheckSumQ;
break;
case 0x22: // Get Meter Information
Parsing Array
switch (executePagerCommandState){
case 0:
executePagerCommandState=1;
break;
case 1:
Itemp2 = OxDA;
sendParsingArray();
executePagerCommandState=2;
break;
case 2:
i f(! sendParsingArrayState)
executePagerCommandState=0;
break;
break;
case 0x23: // Set or Clear Economy, Binary and Compression flags
// bit 0 = econo flag, bit 1 = binaryFlag and bit 2 = compression flag.
hemp = getByte(Istart);
economyFlag = hemp&0x01;
binaryFlag = itemp8,Ox02;
150

CA 02332297 2001-O1-25
binaryFlag = 1;
compressionEnabled = hemp&0x04;
compressionEnabled = 2;
pqVerbosityEnabled = itemp&0x10;
pqVerbosityEnabled = 4;
pagerDiagnostics = hemp&0x20;
pagerDiagnostics = 5;
killPower = itemp&0x40;
killPower = 6;
synchToAtomicTime = getByte(Istart+2);
eepromBuffer(OxSd,economyFlag);
eepromBuffer(OxSe,binaryFlag);
eepromBuffer(OxSf,compressionEnabled);
eepromBuffer(Oxl fd,pqVerbosityEnabled);
eepromBuffer(Oxl9b,pagerDiagnostics);
eepromBuffer(Ox 1 fc,synchToAtomicTime);
eepromBuffer(Ox 1 fb,killPower);
saveParCheckSum();
break;
case 0x24: // Recalculate Flash
and Loader CRC's
switch (executePagerCommandState)
{
case 0:
executePagerCommandState++;
status=1;
useTempAddress= 1;
sendParameters();
break;
case 1:
if(! sendParametersState) {
executePagerCommandState=0;
else if(sendParametersState=5){
executePagerCommandState++;
break;
case 2:
pqPollEnabled=0;
executePagerCommandState++;
break;
case 3:
if(!pqPollState ~~ acOKtimer)
codeCRCQ;
pqPollEnabled= 1;
sendParametersState++;
executePagerCommandState++;
1
break;
case 4:
i f(! sendParametersState) {
executePagerCommandState=0;
break;
break;
case 0x26: // Set Secret Key
if (executePagerCommandState==0)
{
for(whichPQ=O;whichPQ<l7;whichPQ++){
received byte = getByte(Istart);
RamADDRESS = Ox538C + whichPQ;
RamDATA = received byte;
1$1

CA 02332297 2001-O1-25
RAM_WRITE;
eepromBuffer(Ox 1 E0+whichPQ,received_byte);
if(!whichPQ && received byte=Oxff) -
writeMeterSerialQ; /% Just used here to get a default key.
Istart += 2;
executePagerCommandState++;
v
r
else if (!writeMeterSerialState) {
saveParCheckSumO;
executePagerCommandState=0;
break;
case 0x28: // Get Pager Configuration and Product Info.
switch (executePagerCommandState){
case 0:
executePagerCommandState++;
status=0;
useTempAddress= l;
sendParameters0;
break:
case 1:
if(!sendParametersState)
executePagerCommandState=0;
else if(sendParametersState=~){
executePagerCommandState++;
productInfo = 0;
yyl7Q;
r
break;
case 2:
if(!yy 17State) f
executePaeerCommandState++;
productlnfo = I;
>'>' 170,
r
break;
case 3:
if(!yyl7State){
executePagerCommandState++;
sendParametersState++;
break;
case 4:
if(!sendParametersState)
esecutePagerCommandState=0;
break;
r
break:
case 0x29: // Miscellaneous variable Set
variableOffset = getByte(Istart+2);
variableNumber = getByte(lstart+4);
Istart += 6;
if(variableOffset<2 && variableNumber<3 && (variableOffset+variableNumber)<3)
f
variableNumber += variableOffset;
for(;variableOffset<variableNumber;variableOffset++){
received byte = getByte(Istart);
lstart += 2;
if (received byte<IS)
152

CA 02332297 2001-O1-25
received byte = 15;
eepromBuffer(OxlF9+variableOffset,received byte);
saveParCheckSum();
}
break;
case Ox2A: // Miscellaneous variable Get
if (!executePagerCommandState){
variableOffset=getByte(lstart+2);
variableNumber-getByte(Istart+4);
if(variableOffset<2 && variableNumber<3 && (variableOffset+variableNumber)<3){
executePagerCommandState++;
status=0;
useTempAddress = 0;
sendParametersQ;
r
else {
if(!sendParametersState)
executePagerCommandState=0;
else if(sendParametersState=5){
sendParametersState++;
writeToSendBuffer(0);
writeToSendBuffer(variableOffset);
writeToSendBuffer(variableNumber);
variableNumber += variableOffset;
for(;variableOffset<variableNumber;variableOffset++)
received byte = read_ext_eeprom(Ox 1 F9+variableOffset);
writeToSendBuffer(received byte);
;
l
1
break;
case Ox2B: // Kill Power Test
if(exceptionMask&8){ // echo mode (change zone to force an autoregistration)
received byte = rtc read(Oxl3) + I;
rtc write(Ox l3,received byte);
i
KILL_PWR_OUTP= 1;
if(exceptionMask&8) { // change zone back if kill fails.
messageStatus = NAK:
received byte--;
rtc write(Oxl3,received byte);
i
break;
case Ox2C: // Read/Write I/O
if (!executePagerCommandState) {
ioState=getByte(lstart);
if(ioState!=Oxff){
executePagerCommandState++;
status=0;
useTempAddress = 0;
sendParameters();
;
r
else {
if(!sendParametersState)
executePagerCommandState=0;
else if(sendParametersState=5){
153

CA 02332297 2001-O1-25
sendParametersState++;
ioStateUpdateQ;
writeToSendBuffer(ioState);
)
break;
case 0x80: // PQ Enable
RamADDRESS=lstart
RAM_READ;
tempi =toint(RamDATA&Oxff);
if(pqEnabled!=temp 1 ){
eepromBuffer(Ox l9A,temp
1 );
pqEnabled=tempi;
saveParCheckSumQ;
)
break;
case 0x81: // PQ Set Outage
Phase A&B
if (executePagerCommandState=0){
whichPQ=0;
storePQeventQ;
executePagerCommandState=1;
t
else if(!storePQeventState)
{
calcComparisons();
executePagerCommandState=0;
break;
case 0x82: // PQ Get Outage
Phase A&B
if (executePagerCommandState=0)
{
whichPQ=0;
sendPQstatusQ;
executePagerCommandState=1;
else if(!sendPQstatusState)
{
executePagerCommandState=0;
i
break;
case Ox83: // PQ Set Outage
Phase C
if (executePagerCommandState---0){
whichPQ=1;
storePQevent();
executePagerCommandState=1;
else if(!storePQeventState)
{
calcComparisons();
executePagerCommandState=0;
i
break;
case 0x84: // PQ Get Outage
Phase C
if (executePagerCommandState=0){
whichPQ=1;
sendPQstatusQ;
executePagerCommandState=1;
else if(!sendPQstatusState)
{
executePagerCommandState=0;
1
break;
case Ox8~: // PQ Set Hi
Voltage
if(executePagerCommandState
=0)(
154

CA 02332297 2001-O1-25
whichPQ=2;
storePQeventQ;
executePagerCommandState=1;
else if(!storePQeventState)
{
calcComparisons();
executePagerCommandState=0;
)
break;
case 0x86: // PQ Get
Hi Voltage
if (executePagerCommandState=0)
{
whichPQ=2;
sendPQstatus();
executePagerCommandState=1;
)
else if(!sendPQstatusState)
{
executePagerCommandState=0;
break;
case 0x87: // PQ Set
Low Voltage
if (executePagerCommandState=0){
whichPQ=3;
storePQevent();
executePagerCommandState=1;
;
else if(!storePQeventState)
;
calcComparisonsQ;
executePagerCommandState=0:
r
break;
case 0x88: // PQ Get
Low Voltage
if (executePagerCommandState=0)
{
whichPQ=3;
sendPQstatus();
executePagerCommandState=1;
1
1
else if(!sendPQstatusState)
{
executePagerCommandState=0:
break;
case 0x89: // PQ Set
Phase Unbalance
if (executePagerCommandState=0)
{
whichPQ=4;
storePQevent();
executePagerCommandState=1;
v
else if(!storePQeventState)
{
calcComparisons();
executePagerCommandState=0;
;
break;
case Ox8a: // PQ Get
Phase Unbalance
if (executePagerCommandState=0)
{
whichPQ=4;
sendPQstatusQ;
executePagerCommandState=1;
t
else if(!sendPQstatusState)
{
executePagerCommandState=0;
155

CA 02332297 2001-O1-25
break;
case OxBb: // PQ Set
MIVS
if (executePagerCommandState=0){
whichPQ=5;
storePQevent();
executePagerCommandState=l;
else if(!storePQeventState)
{
calcComparisonsQ;
executePagerCommandState=0;
break;
case OxBc: // PQ Get
MIVS
if (executePagerCommandState=0){
whichPQ=5;
sendPQstatus();
executePagerCommandState=1;
else if(!sendPQstatusState)
{
executePagerCommandState=0;
break;
case Ox8d: // PQ Nominal
Voltage
ltemp=getDecimal();
if(Itemp<800) // Less
than 80.0 Volts
messageStatus = NAK;
tempt = hemp8;
eepromBuffer(Ox l9C,temp
1 );
tempi = hemp&OxFF;
eepromBuffer(Ox l9D,temp
1 );
ltemp=getDecimalQ;
if(ltemp<800) // Less than 80.0 Volts
messageStatus = NAK;
temp 1 = hemp»8;
eepromBuffer(Ox l9E,temp 1 );
tempt = Itemp&OxFF;
eepromBuffer(Ox l9F,temp 1 );
(temp=getDecimal();
if(ltemp<800) // Less than 80.0 Volts
messageStatus = NAK;
temp 1 = (temp»8;
eepromBuffer(Ox 1 AO,temp 1 );
temp 1 = hemp&OxFF;
eepromBuffer(Ox 1 A l ,tempt );
saveParCheckSum();
for (whichPQ=O;whichPQ<6;whichPQ++) // Calculate PQ Comparison values.
calcComparisons();
break;
case OxBe: // Send PQ Log
switch (executePagerCommandState){
case 0:
pqLogRequest=getDecimalQ;
pqLogMask = getByte(Istart);
pqLogMask «= 8;
pqLogMask += getByte(lstart+2);
executePagerCommandState++,
break;
156

CA 02332297 2001-O1-25
case 1:
pqSeanReset();
status=1;
useTempAddress=0;
sendParameters();
executePagerCommandState++;
break;
case 2:
if(sendParametersState=5){
writeToSendBuffer('f);
received byte = pqScanPointer8;
convertAndWriteToSendBuffer(received
byte);
received byte = pqScanPointer&OxFF;
convertAndWriteToSendBuffer(received
byte);
writeToSendBuffer('f);
executePagerCommandState++;
break;
case 3:
if(pqScanEnd=0) {
executePagerCommandState++;
break;
case 4:
pqScanQ;
if(eventType=Oxff);
executePagerCommandState++;
sendParametersState++;
else if(!pqLogRequest ~~ !eventType){
getEventTypeQ;
if(pqLogMask & pqComparison){
convertAndWriteToSendBuffer(eventType);
RamADDRESS = Ox44F0;
RAM_READ;
received byte = RamDATA&Oxff;
for(i=O;i<received byte;i++) {
RamADDRESS = Ox44F I+i:
RAM_READ:
convertAndWriteToSendBuffer(RamDATA&Oxff):
l
1
writeToSendBuffer('f);
if(! eventType) {
if(!pqLogRequest){
executePagerCommandState++;
sendParametersState++;
l
i
pqLogRequest--;
break;
case 5:
if(! sendParametersState)
executePagerCommandState=0;
break;
break;
case OxBf: // Send Complete PQ RAM Buffer
if(!executePagerCommandState){
157

CA 02332297 2001-O1-25
sendCompletePQ=1;
if(pqEnabled && !pqLogOff~tate){
executePagerCommandState++;
reportPQevent();
)
else
messageStatus = NAK;
else if(!reportPQeventState){
executePagerCommandState=0;
break;
case 0x90: // Set Temp PQ Disable Switch Parameters
hemp=getDecimal();
if(itemp<I){
itemp=1;
messageStatus = NAK;
if(itemp>15) {
itemp=15;
messageStatus = NAK;
eepromBuffer(OxIFE,itemp);
itemp=getDecimalQ;
if(itemp>30){
hemp=30;
messageStatus = NAK;
eepromBuffer(Ox 1 FF,itemp);
saveParCheckSum();
break;
case 0x91: // Get Temp PQ Disable Switch Parameters
if (!executePagerCommandState)
executePagerCommandState++;
status=1;
useTempAddress= 1;
sendParameters();
else {
if(!sendParametersState)
executePagerCommandState=0;
else if(sendParametersState =5) {
sendParametersState++;
writeToSendBuffer('f);
received byte = read_ext_eeprom(Ox 1 FE): // Off Time
received byte = to_bcd(received byte);
convertAndWriteToSendBuffer(received byte);
writeToSendBuffer('f);
received byte = read_ext_eeprom(Ox 1 FF); // Report Delay
received byte = to_bcd(received_byte);
convertAndWriteToSendBuffer(received byte);
writeToSendBuffer('f);
break;
case 0x92: // Send Long "NOW" Values
if (!executePagerCommandState)
sendCompIetePQ=2;
// intentionally no break here.
case 0x93: // Send Short "NOW" Values
1$g

CA 02332297 2001-O1-25
switch (executePagerCommandState){
case 0:
if(!pqLogOffState && pqEnabled){
executePagerCommandState++;
reportPQeventQ;
l
else {
executePagerCommandState = 2;
status=1;
useTempAddress= 1;
sendParametersQ;
L
l
break;
case l:
if(!reportPQeventState){
executePagerCommandState = 0;
f
break;
case 2:
if(! sendParametersState)
executePagerCommandState=0;
else if(sendParametersState==5){
sendParametersState++;
writeStringToSendBuffer(sPQDisabled):
if(pqEnabled)
writeStringToSendBuffer(sTemporarily);
writeToSendBuffer('f);
i
break;
)
break;
case Ox94: // Set Demand parameters
for(whichPQ=O;whichPQ<26;whichPQ++) {
received_byte = getByte(lstart);
if(!whichPQ)
demandWindow=received byte;
eepromBuffer(OxlC6+whichPQ.received byte);
Istart += 2;
saveParCheckSum();
break:
case Ox95: // Get Demand parameters
if (!executePagerCommandState) {
executePagerCommandState++;
status=1;
useTempAddress = 1;
sendParametersQ;
l
i
else {
if(!sendParametersState)
executePagerCommandState=0;
else if(sendParametersState=5) {
sendParametersState++:
writeToSendBuffer('/');
for(itemp=O;itemp<26;itemp++){
received byte = read_ext_eeprom(Ox 1 C:6+itemp);
convertAndWriteToSendBuffer(received byte);
riteToSendBuffer('f);
159

CA 02332297 2001-O1-25
break;
case 0x96: // Send Demand status
switch (executePagerCommandState){
case 0:
if(!pqLogOff~tate && demandWindow){
executePagerCommandState++;
sendDemandReport();
demandReport=2;
else {
executePagerCommandState = 2;
status=I;
useTempAddress= 1;
sendParameters();
)
break;
case 1:
if(!sendDemandReportState){
executePagerCommandState = 0;
)
break;
case 2:
if(! sendParametersState)
executePagerCommandState=0;
else if(sendParametersState=S){
sendParametersState++;
writeStringToSendBuffer(sDemandDisabled):
if(demandWindow)
writeStringToSendBuffer(sTemporaril~-);
writeToSendBuffer('/');
break:
break;
default:
messageStatus = NAK;
break;
// switch
f
void runTimer(void){
switch(runTimerState)
case 0:
runTimerState++;
break;
case 1: // Main Loop increments this when the pager is available.
break;
case 2:
iIndex=demandTimer;
iIndex*=128;
iIndex+=5;
iIndex+=Ox4C00;
sendParameters();
runTimerState++;
break;
case 3:
if(sendParametersState=5) {
runTimerState++;
;
160

CA 02332297 2001-O1-25
break;
case 4:
executeMultipleCommands(iIndex);
runTimerState++;
break;
case 5:
if(!executeMultipleState){
if(runSSIcommand){
runTimerState=0;
sendParametersState=0;
r
else {
sendParametersState++;
runTimerState++;
)
break;
case 6:
if(!sendParametersState)
runTimerState=0;
break;
~******************************************************
Outgoing Message Handlers
void degrade( void);
void sendPing( void);
void sendPage( void);
void BitwiseCrcl6 (int bit);
void CaIcCRC(unsigned char data);
void addCRC(void);
void calcSendData( void);
void spreadTimer(void);
void exceptionPage(void);
void reportPQevent(void);
void sendAlann(void);
void checkMeterErrors(void);
void writeTime( char from);
void writeMeterSerial( void);
void sendParameters(void);
void sendDemandReport(void);
void convertAndWriteToSendBuffer(unsigned char data);
void writeToSendBuffer(char data);
******************************************************~
void sendPage( void){
switch(sendPageState) {
case 0:
sendPageState=l;
Itemp3=0;
preamble[0]=pageNumber;
preamble[3]=successCount;
noPagesToday = 0;
break;
case 1:
temp 1=OxaO;
if(badHandshake) tempi+=0x10;
if(abortFlag) tempi += 0x40;
abortFlag = 0;
161

CA 02332297 2001-O1-25
if(wasReset) temp 1 -= 0x20;
wasReset = 0;
if(nAC_OK INP) tempt -= 0x80;
preamble[2]=temp 1;
degrade();
sendPageState=2;
break;
case 2:
if(!degradeState && !reestablishPagerState){
if(abortFlag) {
sendPageState=0;
sendPageReturn=1;
pqLog(attemptCount+OxAO);
pqLog(timeOfDay&OxFF);
pqLog(timeOfDay»8);
pqLog(pagerMessage);
else
sendPageState=3;
break;
case 3:
if ((pageNumber>=start0l )&&(pageNumber<=end01 )){
sendPageState=4;
yyl6p;
r
else sendPageState=5;
break;
case 4:
if(!yyl6State)(
if(pagerResponse)
sendPageState=5;
else {
sendPageState=0;
sendPageReturn=0;
pqLog(pagerStatus2);
pqLog(pagerStatusl);
pqLog(timeOfDay&OxFF);
pqLog(timeOfDay»8);
pqLog(Ox7B);
1
break;
case ~:
blockNum = 0;
sendPageState=6;
break;
case 6:
if(packetsForPage){
blockNum++;
if (blockNum = 1 ) {
if ((partPacket)&& (totalPackets = t )) // first and only packet
packetEnd+=partPacket;
else { // first full packet
if (status~~binaryFlag)
packetEnd+=128-headerOverhead-PREAMBLE;
else
packetEnd+=64-(headerOverhead/2)-PREAMBLE;
if (status)
packetEnd-=PREAMBLE;
162

CA 02332297 2001-O1-25
]
else{ // second or later packet
if (((packetsForPage = 1 ) && fullPages ---- 0) && partPacket) // last packet
packetEnd+=partPacket;
else {
if ((status)~~(binaryFlag)) // not the last ASCII packet
packetEnd+=128;
else // not the last binary packet
packetEnd+=64;
temp I=preamble[2];
temp 1+=attemptCount&OxOf;
preamble[2]=templ;
if ((pageNumber>=start0l)&&(pageNumber<=end01)){
xmod_data();
sendPageState=7;
else {
packetStart=packetEnd;
if(packetsForPage=1 ){
sendPageState=0;
sendPageReturn=1;
]
else sendPageState=8;
L
i
else sendPageState=9;
break;
case 7:
if(!xmod dataState){
if(pagerResponse=ACK)
sendPageState=8;
else {
sendPageState=0;
sendPageReturn=0;
L
break;
case 8:
packetsForPage--;
if(packetsForPage)
sendPageState=6;
else sendPageState=9;
break;
case 9:
putcPager(EOT):
pagerResponse=0;
pagerComAbortTime=IastCentiTime+j00;
sendPageState=10;
break;
case 10:
if(kbhitPagerQ){
received byte = getc(PAGER);
pagerComAbortTime=lastCentiTime+1 j00;
pagerPolITimeout=timeOfDay+270; // 9 minutes for testing with Emu.
sendPageState=1 1;
else if (pagerComAbortTime<lastCentiTime) sendPageState=0;
163

CA 02332297 2001-O1-25
break;
case 1 1:
if (pagerComAbortTime<lastCentiTime) { // used for time delay here
YY 180;
sendPageState=12;
1
l
break;
case 12:
if(!yylBState){
RamADDRESS = Ox50C1;
RAM_READ;
received byte = RamDATA&Oxff;
received byte = toint(received byte);
received byte &= OxC;
if ((received byte = 0)~~(received byte == 4)~~(pagerPollTimeout<timeOtDay)) (
// negative response
sendPageState=0;
sendPageReturn=0;
if(pagerPollTimeout<timeOfDay) {
pqLog(pagerStatus2);
pqLog(pagerStatus 1 );
pqLog(timeOfDay&OxFF);
pqLog(timeOfDay»8);
pqLog(Ox7A);
reestablishPagerQ;
;
else if (received byte == 8); // positive response
pqLog(attemptCount):
pqLog(timeOfDay&OxFF):
pqLog(timeOfDay»8);
pqLog(pagerMessage);
valDegrade = 0;
bytesSentOK+=(tempi; // update total good bytes
rtc write(OxlS,bytesSentOK»8);
rtc_write(Ox 16,bytesSentOK&OxFF);
sendPageState=0;
sendPageReturn=1;
1
else {
pagerComAbortTime=lastCentiTimc+~00;
sendPageState=1 1;
break:
;
f
void calcSendData( void){
unsigned char icalc, fullSize, firstSize;
switch(calcSendDataState) {
case 0:
calcSendDataState=1;
messageReplied=2;
successCount++;
rte_write(OxlO,successCount);
if (useTempAddress);
headerSize = rtc read(Ox40):
headerCount = rtc read(Ox41 );
z
else {
164

CA 02332297 2001-O1-25
headerSize = read_ext eeprom(Ox I D);
headerCount = read ext eeprom(Ox 1 E);
fullSize = 128;
padHeaderEven=0;
headerOverhead = headerSize + 3 + headerCount;
if ((!status)&&binaryFlag) headerOverhead ++;
firstSize = 120 - headerOverhead:
if ((!status)&&binaryFlag)
firstSize += PREAMBLE;
else if (!status){
fullSize=64;
padHeaderEven = firstSize%2;
firstSize/=2; // This should be rounded down.
headerOverhead += padHeaderEven;
(temp=IindexSave;
totalPackets=0;
for(;;){
for(icalc=O;icalc<(BLOCKSIZE/128):icalc++) ( // Count the v-hole packets +
remainder
totalPackets++;
if(icalc){ // if second or later packet
if (hemp <= fullSize){ // and there is less than a packet left
partPacket=(temp; // partPacket is just the remainder
if (hemp = 0) // if remainder happens to be zero
totalPackets--; // reduce the total number of packets
goto carryon; // done counting packets
Itemp-=fullSize; // greater than a full packet left so
// reduce by 1 packet and keep counting
else { // if first packet
if (hemp <= firstSize) { // if this is the only packet and header fits
partPacket=ltemp; // partPacket is the remainder
if (hemp == 0)
totalPackets--; // othemvise there are no packets
goto canyon: // done counting packets
i
Itemp-=firstSize; // reduce hemp by packetSize less headerSize and preamble
; //else keep counting packets
// for(icalc=O;icalc<(BLOCKSIZE/128);icalc++)
// for(;;)
carryon: // Now calculate everything else based on the packet count
// and the remainder
fullPages=totalPages=totalPackets/(BLOCKSIZE/128);
partPage = totalPackets%(BLOCKSIZE/128); // number of packets short of a full
block
if ((partPacket) && (!partPage)) { // if the remainder is the only packet
fullPages--; // there are no full pages
totalPages--; // or total pages
partPage=(BLOCKSIZE/128); // and partPage = packet size
1
l
if (partPage) totalPages++; // if there is a partial page increase total pages
tempPacketStart = 0; // start at the beginning
iPacketSize = BLOCKSIZE;
preamble[I]=totalPages;
break;
case 1:
pageNumber= 1;
165

CA 02332297 2001-O1-25
if (fullPages>0) calcSendDataState=3;
else calcSendDataState=7;
break;
case 3:
valDegrade = 0;
calcSendDataState=4;
break;
case 4:
// Depending on how sendPage is done this may need to be repeated if send page
fails.
packetStart = tempPacketStart;
packetEnd = tempPacketStart;
packetsForPage = (BLOCKSIZE/128);
sendPageQ;
calcSendDataState=~;
break;
case S:
if(!sendPageState && !reestablishPagerState){
if(sendPageReturn=0)
calcSendDataState=4;
else
calcSendDataState=6;
l
break;
case 6:
fuIIPages--;
tempPacketStart = packetStart; // update the start point
if (abortFlag) calcSendDataState=10;
else if (fullPages>0) {
calcSendDataState=3;
i
else calcSendDataState=7;
pageNumber++;
break;
case 7:
if (partPage > 0){ // if there are partial pages
valDegrade = 0; // reset the backoff and retry variable
calcSendDataState=8;
else calcSendDataState=10;
break;
case 8:
// Depending on how sendPage is done this may need to be repeated if send page
fails.
packetStart = tempPacketStart; // send whatever packets remain
packetEnd = tempPacketStart;
packetsForPage = partPage;
iPacketSize = ((partPage-1 )* 128);
if ((status=1 )~~(binaryFlag)){ // if this an binary/status page
iPacketSize+=partPacket;
if (partPage=1 ) { // if this is the first packet
iPacketSize+=headerOverhead+PREAMBLE;
if(status) iPacketSize+=PREAMBLE;
v
else if (status=2) {
iPacketSize = partPacket + headerOverhead;
1
else { // if this is an ascii page
iPacketSize+=(partPacket*2);
166

CA 02332297 2001-O1-25
if (partPage=I ) // if this is the first packet
iPacketSize+=headerOverhead+(PREAMBLE*2);
sendPageQ;
calcSendDataState=9;
break;
case 9:
if(!sendPageState && !reestablishPagerState){
if(sendPageReturn=0)
calcSendDataState=8;
else
calcSendDataState=10;
break;
case 10:
calcSendDataState=0;
break;
void sendAlarm(void) {
switch(sendAlarmState) {
case 0:
sendAlarmState++;
break;
case 1:
if(!sendingPage) {
sendingPage=1;
rtc_clear irq();
sendAlarmState++;
t
break;
case 2:
status=FALSE;
useTempAddress = 0;
tempMask=1;
sendAlarmState++;
break;
case 3:
pending=FALSE;
tempMask=1;
rte-get datetime(&time);
iTimer-0;
sendAlarmState++;
break;
case 4:
sendAlarmState=10;
if (timerMask&tempMask) {
getAlarm(iTimer);
if (lessOrEqual(&alarm,&time)) {
pending=TRUE;
iIndex=iTimer;
iIndex*=128;
ilndex+=5;
iIndex+=Ox4C00;
RamADDRESS=ilndex;
RAM_READ;
received byte = RamDATA&Oxff;
if(received byte ='P')
reestablishPagerQ;
167

CA 02332297 2001-O1-25
sendAlarmState=20;
}
else {
lindex=0;
pagerMessage = 0x40 + iTimer;
// writeToSendBuffer(pagerMessage);
writeToSendBuffer(OxFF);
writeMeterSerialQ;
sendAlarmState=5;
}
}
}
break;
case 5:
if(!writeMeterSerialState){
writeTime(RTC);
sendAlarmState++;
}
break;
case 6:
if(! writeTimeState) {
executeMultipleCommands(iIndex);
sendAlarmState++;
i
break;
case 7:
if(!executeMultipleState) {
if(runSSIcommand)
sendAlarmState=9;
else {
addCRCQ;
if(alarm.addSpreadDelay)
spreadTimer();
sendAlarmState=8;
}
break;
case 8:
if(!spreadTimerState) {
calcSendDataQ;
sendAlarmState=9;
break;
case 9:
if(!calcSendDataState){
initAlarm(iTimer);
checkAlarm(iTimer);
sendAlarmState=10;
}
break;
case 10:
tempMask*=2;
iTimer++;
if(iTimer<8)
sendAlarmState=4;
else if(pending)
sendAlarmState=3:
else
sendAlarmState=I 1;
break;
168

CA 02332297 2001-O1-25
case 11:
setAlarmQ;
sendingPage=0;
sendAlarmState=0;
break;
case 20:
if(! reestablishPagerState)
sendAlarmState=9;
break;
}
}
void writeMeterSerial( void){
switch(writeMeterSerialState) {
case 0:
if(acOKtimer){
writeMeterSerialState = 8;
}
else {
writeMeterSeriaIState++;
command[0]=0x87;
for(i=l;i<ll;i++) command[i]=0;
command[9]=0x87;
sendFlag=FALSE;
sendCommandQ;
}
break;
case 1:
if (!sendCommandState){
v~riteMeterSeria(State=8;
if(!badSendCommand) {
writeMeterSerialState=2;
RamADDRESS = Ox538C;
if(ramReadUchar()==Oxft) { // Set encryption ke~~ to factory default.
writeMeterSerialState=5;
RamADDRESS = Ox4b00;
stringPointee=ramReadInt(); // temp use for moving meter
stringEnd=ramReadlnt(); // serial # to secret key area
RamADDRESS = Ox538C;
RamDATA = 4;
RAM_WRITE;
ram W ritelnt(stringPointer);
ramWritelnt(stringEnd);
stringPointer=Ox4B84;
stringEnd=stringPointer+16;
putArrayInExtRam(sDefaultKeySeed);
addCRCflag = 1; // To force binary handling of encryption.
messageCRC = defaultCRC;
cryptData = Ox4B84;
cryptDataLength = 16;
rc4crypt();
addCRCflag = 0;
RamADDRESS = Ox538C;
RamDATA = 16;
RAM_WRITE;
eepromBuffer(Oxl e0,16);
for( i=0; i< 16; i++) {
RamADDRESS = Ox4B84 + ;;
RAM_READ;
RamADDRESS = Ox538D + i;
169

CA 02332297 2001-O1-25
RAM_WRITE;
received byte = RamDATA&Oxff;
eepromBuffer(Oxlel+i,received byte);
break;
case 2:
case 5: // Will need a saveParCheckSum
writeMeterSerialState++;
for(i=O;i<4;i++)
received byte=read_ext_eeprom(Oxlfl -f i);
RamADDRESS = Ox4b00 + i;
last byte = ramReadUcharQ;
if(last byte != received byte)
writeMeterSerialState = 4;
break;
case 3:
writeMeterSeriaIState=7;
break;
case 4:
writeMeterSerialState=6;
for(i=O;i<4;i++)(
RamADDRESS = Ox4b00 + i;
received byte = ramReadUchar();
eepromBuffer(Oxlfl+i,received b~~te);
i
r
break;
case 6:
writeMeterSerialState++;
saveParCheckSum();
break;
case 7:
mriteMeterSeriaIState = 0;
if(!status ~~ serialAtStart)
convertAndVVriteToSendBuffer(0): // To pad a 4 byte serial # up to ~ bytes.
RamADDRESS = Ox4b03;
received byte = ramReadUchar();
convertAndWriteToSendBuffer(received byte);
if(status && !serialAtStart)
writeToSendBuffer(' ');
RamADDRESS = Ox4b02;
received byte = ramReadUchar();
convertAndWriteToSendBuffer(received byte);
RamADDRESS = Ox4b01:
received byte = ramReadUchar();
if(status && !serialAtStart){
writeToSendBuffer(to ascii(received_byte»~));
writeToSendBuffer(' ');
writeToSendBuffer(to ascii(received byte&OxOf));
i
else
convertAndWriteToSendBuffer(received_byte);
RamADDRESS = Ox4b00;
received byte = ramReadUchar();
convertAndWriteToSendBuffer(received byte);
break;
case 8: // Copy from eeprom to meter incoming buffer.
170

CA 02332297 2001-O1-25 '
writeMeterSerialState--;
for( i=0; i<4; i++) {
RamDATA = read_ext_eeprom(Ox 1 fl + i);
RamADDRESS = Ox4b00 + ;;
RAM WRITE;
)
break;
L
l
1~
#pragma code reportPQevent = OxC000
void reportPQevent(void){
switch(reportPQeventState){
case 0:
reportPQeventState++;
pqReportNow=1;
break;
case I:
if(!pqReportNow)
reportPQeventState=3;
break;
case 3:
if(!sendingPage ~~ pagerMessage=OxBf ~) pagerMessage=0x92 ~~
pagerMessage=0x93){
sendingPage=1;
pqPendingTime=0;
// status=FALSE;
status=TRUE; // For now.
useTempAddress= 1;
if(pagerMessage!=OxBf&& pagerMessage!=0x92 R& pagerMessage!=0x93);
pagerMessage = OxAO:
useTempAddress = 0;
1
sendParameters();
reportPQeventState=4;
i
break;
case 4:
if(! sendParametersState) {
reportPQeventState=0;
if(sendParametersState=~) {
reportPQeventState++;
r
break;
case ~:
if(!pqVerbosityEnabled){
writeToSendBuffer(' ');
for(pqValue=O;pqValue<pqReportSize;pqValue++) {
RamADDRESS = pqValue+0x4500;
RAM_READ;
pqEvent = RamDATA&Oxff;
convertAndWriteToSendBuffer(pqEvent);
1
writeToSendBuffer(' ');
1
else {
writeToSendBuffer('f);
for(pqValue=O;pqValue<pqReportSize:pqValue++) {
RamADDRESS = pqValue+Ox4~00;
1~1

CA 02332297 2001-O1-25
RAM_READ;
pqEvent = RamDATA&Oxff;
if(pqEvent<Ox7E){
writeToSendBuffer(' ');
writeToSendBuffer('X');
convertAndWriteToSendBuffer(pqEvent);
if (pqEvent){
pqValue++;
RamADDRESS = pqValue+0x4500;
RAM_READ;
pqEvent = RamDATA&Oxff;
convertAndWriteToSendBuffer(pqEvent);
i
else if(pqEvent=Ox7E ~~ pqEvent=Ox7F){
access.
writeStringToSendBuffer(sMacc o);
if(pqEvent=Ox7E){
writeToSendBuffer('F');
writeToSendBuffer('F');
else
writeToSendBuffer('N');
writeToSendBuffer(' ');
pqValue++;
RamADDRESS = pqValue+Ox4~00;
pqValue++;
(temp = ramReadInt();
received byte = Itemp/1800;
convertAndWriteToSendBuffer(to_bcd(received
byte));
writeToSendBuffer(':');
hemp % 1800;
received byte = Itemp/30;
convertAndWriteToSendBuffer(to bcd(received
byte));
writeToSendBuffer(':');
received byte = ltemp%30;
received byte *= 2;
convertAndWriteToSendBuffer(to bcd(received-byte));
i
else {
if (pqEvent>OxBO){
pqEvent -= OxB 1;
pqEventStatus = 1; // Used here to indicate
a restoration report.
else {
pqEvent -= OxA 1;
pqEventStatus = 0; // Used here to indicate
not a restoration report.
)
writeToSendBuffer(' ');
if(pqEvent<3 ~~ pqEvent=14);
writeStringToSendBuffer(sOut);
else if(pqEvent<6){
writeToSendBuffer('H');
writeToSendBuffer('f );
else if(pqEvent<9){
writeToSendBuffer('L');
writeToSendBuffer('O');
1
172

CA 02332297 2001-O1-25
else if(pqEvent<10){
writeStringToSendBuffer(sUnbal);
else {
writeStringToSendBuffer(sMivs);
writeToSendBuffer(' ');
if(pqEvent!=9) {
received byte = pqEvent%3;
if(received byte=0)
writeToSendBuffer('A');
else if(received byte=1)
writeToSendBuffer('B');
else
writeToSendBuffer('C');
if(pqEvent=14){
writeStringToSendBuffer(s com);
pqEvent=2;
writeToSendBuffer(' ');
i
if(pqEventStatus){ // Restoration report.
writeStringToSendBuffer(sOK~;
pqValue++;
RamADDRESS = pqValue+0x4500;
pqValue++;
(temp = ramReadlnt();
received byte = Itemp/1800;
convertAndWriteToSendBuffer(to bcd(received
byte));
writeToSendBuffer(':');
Itemp % 1800;
received byte = ltemp/30;
convertAndWriteToSendBuffer(to bcd(received_byte));
writeToSendBuffer(':');
received byte = ltemp%30;
received byte *= 2;
convertAndWriteToSendBuffer(to bcd(received
byte));
writeToSendBuffer(' ');
if(pqEventStatus){ // Restoration report.
pqValue++;
RamADDRESS = pqValue+Oa4~00;
pqValue++;
hemp = ramReadIntQ;
received_byte = Itemp/1800;
convertAndWriteToSendBuffer(to bcd(received
byte));
writeToSendBuffer(':');
hemp %= 1800;
received byte = Itemp/30;
convertAndWriteToSendBuffer(to bed(received
byte));
writeToSendBuffer(':');
received_byte = ltemp%30;
received byte *= 2;
convertAndWriteToSendBuffer(to bcd(received
byte));
writeToSendBuffer(' ');
i
else if(pqEvent<10){ // Outage, Unbalance
or Hi/Lo
if(pqEvent!=2) {
if(pqEvent<9)
received byte= 1;
173

CA 02332297 2001-O1-25
else
received byte = 0;
if(pqEvent=9){
for(itemp=0; hemp<3; itemp++) {
pqValue++;
RamADDRESS = pqValue+0x4500;
pqValue++;
hemp = ramReadInt();
writeDecimalDivider= 100;
postDecimalCharacter ='%';
writeDecimalToSendBuffer(hemp);
)
pqValue++;
RamADDRESS = pqValue+0x4500;
RAM READ;
Itemp = RamDATA&Oxff;
(temp += 0x30;
writeToSendBuffer(ltemp);
writeToSendBuffer('%');
writeToSendBuffer(' ');
if(pqEvent<9)
received byte= 1;
else
received byte = 0;
for(itemp=received byte;itemp<3;itemp++){
pqValue++;
RamADDRESS = pqValue+0x4500;
pqValue++;
ltemp = ramReadInt();
writeDecimalDivider = 64;
postDecimalCharacter ='V';
writeDecimalToSendBuffer(hemp):
if(pqEvent=~){
for(itemp=O;itemp<3:itemp++)
pqValue++;
RamADDRESS = pqValue+0x4500;
pqValue++;
hemp = ramReadlnt();
writeDecimalDivider = 128;
postDecimalCharacter ='d';
writeDecimaIToSendBuffer(Itemp);
writeToSendBuffer('#');
pqValue++;
RamADDRESS = pqValue+0x4500;
RAM_READ;
received byte = RamDATA&Oxff;
convertAndWriteToSendBuffer(to bcd(received byte));
writeToSendBuffer(' ');
i
l
else {
pqValue++;
RamADDRESS = pqValue+0x4500;
RAM_READ;
received byte = RamDATA&Oxff;
convertAndWriteToSendBuffer(to bcd(received byte));
174

CA 02332297 2001-O1-25
writeStringToSendBuffer(s_IN_);
pqValue++;
RamADDRESS = pqValue+0x4500;
pqValue++;
hemp = ramReadInt();
received byte = Itemp/60;
convertAndWriteToSendBuffer(to bcd(received
byte));
writeToSendBuffer('m');
received byte = hemp%60;
convertAndWriteToSendBuffer(tobcd(received_byte));
writeToSendBuffer('s');
writeToSendBuffer(' ');
;
pqReportSize = 0;
if (sendCompletePQ=1){
sendCompletePQ=0;
for (pqEvent=O;pqEvent<l3;pqEvent++) {
writeToSendBuffer('(');
convertAndWriteToSendBuffer(to bcd(pqEvent));
writeToSendBuffer(')');
for (i=0; i< 10; i++) {
RamADDRESS = i+0x4400 + (pqEvent* 18);
RAM_READ;
received_byte = RamDATA&Oxff;
convertAndWriteToSendBuffer(received byte):
i
r
?
writeToSendBuffer(' ');
i
writeStringToSendBuffer(sNOW~;
reportPQeventState=6;
break:
case 6:
if(acOKtimer ~~ pqPoIlState=40){
writeStringToSendBuffer(sC OUT );
outageReportSent++;
reportPQeventState=7;
else if(!unbalanceStatus){
writeDecimalDivider = 64:
postDecimalCharacter ='V';
writeDecimalToSendBuffer(unbalVoltAfrac);
writeDecimalToSendBuffer(unbalVoItBfrac);
writeDecimaIToSendBuffer(unbalVoItCfrac);
writeDecimalDivider = 128;
postDecimalCharacter ='d';
writeDecimalToSendBuffer(0);
writeDecimalToSendBuffer(unbalAngleAfrac);
hemp = 46080 - unbalAngIeCfrac;
writeDecimalToSendBuffer(hemp);
if (sendCompletePQ=2) {
sendCompletePQ=0;
for(i=O:i<18:i+=3) {
RamADDRESS = Ox534F + i;
hemp = meterFloatTolnt(Ox89);
writeDecimalDivider = 64;
if(i<9)
175

CA 02332297 2001-O1-25
else
postDecimalCharacter ='A';
postDecimalCharacter ='d';
writeDecimaIToSendBuffer(hemp);
)
writeDecimalDivider = 100;
postDecimalCharacter ='°/d;
writeDecimalToSendBuffer(unbalVoltAB);
writeDecimaIToSendBuffer(unbalVoItBC);
writeDecimalToSendBuffer(unbaIVoItCA);
writeDecimalDivider=read ext eeprom(OxlD7);
demandMaxExp = read ext_eeprom(Ox 1 CB);
postDecimalCharacter ='W
for(i=28;i<43;i+=3){
RamADDRESS = 0x5361 + i;
ltemp = meterFIoatToInt(demandMaxExp);
writeDecimalToSendBuffer(ltemp);
reportPQeventState=7;
r
break;
case 7:
writeStringToSendBuffer(sMIVS );
scanMIVSonly=1;
RamADDRESS = Ox~3F9; // get report delay
RAM_READ;
pqReportDelay = RamDATA&Oxff;
pqEvent=12;
pqMivsScan();
convertAndWriteToSendBuffer(to bcd(pqMivsCount));
writeToSendBuffer(' ');
for(pqEvent=lO:pqEvent<l2;pqEvent++)
pqMivsScanQ:
convertAndV'riteToSendBuffer(to bcd(pqMivsC'ount)):
writeToSendBuffer(' '):
scanMIVSonly=0;
writeToSendBuffer('/');
reportPQeventState=8;
break;
case 8:
sendParametersState++;
reportPQeventState++;
break;
case 9:
if (! sendParametersState);
reportPQeventState++;
r
break:
case 10:
reportPQeventState=0;
if(!executePagerCommandState)
sendingPage=0;
break;
void putHexIntPager(unsigned int hexData);
hexNibble = hexData» 12;
176

CA 02332297 2001-O1-25
putcPager(' ');
hexNibble = to_ascii(hexNibble);
putcPager(hexNibble);
hexData &= Oxfff;
hexNibble = hexData»8;
hexNibble = to_ascii(hexNibble);
putePager(hexNibble);
hexData &= Oxff;
hexNibble = hexData»4;
hexNibble = to_ascii(hexNibble);
putcPager(hexNibble);
hexNibble = hexData&Oxf;
hexNibble = to_ascii(hexNibble);
putcPager(hexNibble);
putcPager('h');
void writeTime( char from) {
switch(writeTimeState) {
case 0:
writeTimeState=3;
writeTimeFrom = from;
if (from=METER){
getMeterTime();
writeTimeState=1;
i
else if (from==PAGER);
getPagerTimeQ;
writeTimeState=2;
else if (from=RTC ~~ from---RTC NO YEAR)
rtc-get datetime(&time);
else if (from---RTC_ALARM)
rte_get alarm datetime(&time);
break;
case I:
if (!getMeterTimeState) {
writeTimeState=3;
i
r
break;
case 2:
if (!getPagerTimeState);
writeTimeState=3;
r
r
break;
case 3:
if ((writeTimeFrom!=RTC_ALARM)&&(writeTimeFrom!=RTC_NO YEAR))
convertAndWriteToSendBuffer(to bcd(time.yr));
convertAndWriteToSendBuffer(to bcd(time.mth));
convertAndWriteToSendBuffer(to bcd(time.day));
convertAndWriteToSendBuffer(to bcd(time.hr));
convertAndWriteToSendBuffer(to_bed(time.min));
convertAndWriteToSendBuffer(to bcd(time.sec));
writeTimeState=0;
break;
void checkMeterErrors(void){
switch(checkErrorState){
177

CA 02332297 2001-O1-25
case 0:
checkErrorState++;
break;
case 1:
checkErrorState++;
break;
case 2:
if(!sendingPage){
sendingPage=1;
checkErrorState++;
reestablishPagerQ;
break;
case 3:
if(!reestablishPagerState){
if(exceptionMask&4){
command(O]=0x83; // Get meter error codes.
for(i=l;i<ll;i++) command[i]=0;
command[9]=0x83;
sendFlag=FALSE;
sendCommandQ;
checkErrorState++;
v
else{
checkErrorState = 7;
break;
case 4:
if (!sendCommandState){
checkErrorState=7;
if(!badSendCommand){
received byte = read ext_eeprom(OxOe);
RamADDRESS = Ox4b00;
hemp = ramReadUchar();
received byte &= hemp;
last byte = read ext eeprom(OxOfJ;
RamADDRESS = Ox4b01;
itemp = ramReadUchar();
last byte &= itemp;
if(received_byte ~~ last byte){
status=0;
useTempAddress = 0;
pagerMessage = 0;
sendParametersQ;
checkErrorState=5;
l
1
T
1
break:
case ~:
if(sendParametersState=5) {
sendParametersState=0;
pagerMessage = 0x53;
writeToSendBuffer(OxBF);
writeToSendBuffer(Ox83);
writeToSendBuffer(OxFF);
for( i=0; i<7; i++) {
RamADDRESS = Ox4b00 + i;
hemp = ramReadUchar();
178

CA 02332297 2001-O1-25
writeToSendBuffer(itemp);
r
received byte = read_ext_eeprom(OxOe);
writeToSendBuffer(received_byte);
received byte = read_ext_eeprom(OxOf);
writeToSendBuffer(received
byte);
addCRCQ;
spreadTimer();
checkErrorState++;
}
break;
case 6:
if(! spreadTimerState) {
calcSendDataQ;
checkErrorState++;
break;
case 7:
if(!calcSendDataState) {
checkErrorState=0;
sendingPage=0;
if(noPagesToday){
received byte = rtc read(Ox
13) + 1;
rtc write(Oxl3,received byte);
for(;;);
noPagesToday = I;
l
i
break;
}
void sendParameters(void){
// If calling function is using a temporary address then it must check for
sendParametersState being set
// to zero (when it is waiting for sendParametersState being set to S) because
of a problem with the address.
switch (sendParametersState){
case 0:
sendParametersState++;
if(useTempAddress)
storeAddress(TRUE): // from incoming to eeprom storage
else
sendParametersState++; // skip to case 2
break;
case 1:
if(!storeAddressState)
sendParametersState++;
if(storeAddressState=10) { // Bad Address.
sendParametersState=0;
storeAddressState=0:
}
break:
case 2:
lindex=0;
if(pagerMessage=0x10 && onlyDates=2)
writeToSendBuffer(OxOf);
else
convertAndWriteToSendBuffer(pagerMessage);
serialAtStart= 1;
writeMeterSerial();
sendParametersState++;
179

CA 02332297 2001-O1-25
break;
case 3:
if(! writeMeterSerialState) {
serialAtStart = 0;
writeTime(RTC);
sendParametersState++;
break;
case 4:
if(!writeTimeState){
sendParametersState++;
break;
case 5: // Calling function adds data at this point and increments
sendParametersState
break;
case 6:
addCRC();
calcSendDataQ;
sendParametersState++;
break;
case 7:
if (!calcSendDataState)
sendParametersState=0;
break;
;
void sendDemandReport(void){
switch (sendDemandReportState){
case 0:
sendDemandReportState++;
break;
case 1:
status=1;
useTempAddress= I;
if(demandReport=1 ) {
pagerMessage = OxCO;
useTempAddress = 0;
sendParametersQ;
sendDemandReportState++;
break;
case 2:
if(! sendParametersState) {
sendDemandReportState=5:
if(sendParametersState =~) {
sendDemandReportState++;
pagerComAbortTime = lastCentiTime + 3000; // 30 seconds
)
break;
case 3:
if(demandReport!=2){
writeToSendBuffer('f);
RamADDRESS = Ox53A2;
demandWindowAverage = ramReadInt();
demandThreshold = ramReadInt();
demandT'emp = ramReadlnt();
writeDecimalDivider = read_ext eeprom(Ox 1 D7);
postDecimalCharacter ='W'
Ig~

CA 02332297 2001-O1-25
writeDecimalToSendBuffer(demandWindowAverage);
writeDecimalToSendBuffer(demandValue);
writeDecimaIToSendBuffer(demandThreshold);
writeDecimalDivider = 30;
postDecimalCharacter = 0x27; // single quote
writeDecimalToSendBuffer(demandTemp);
writeToSendBuffer('f);
pagerComAbortTime = IastCentiTime; // clear delay
sendDemandReportState++;
)
else if(pagerComAbortTime < lastCentiTime){
sendDemandReportState++;
break;
case 4:
sendDemandReportState++;
sendParametersState++;
break;
case 5:
if(!sendParametersState){
sendDemandReportState++;
break;
case 6:
sendDemandReportState=0;
demandReport=0;
if(!executePagerCommandState)
sendingPage=0;
break:
void ioStateUpdate(void){
received byte=read ext_eeprom(OxID6);
if(received_byte & 0x80 ~~ pagerMessage=Ox2c) {
received byte = ioState R, 0x03;
if(received byte=0)RLY1DRV LATCHED OP=0;
else if(received byte=0x01) RLY1DRV LATCHED OP= 1;
else if(RLY I DRV LATCHED OP) ioState ~= Ox0l;
else ioState &= OxPC:
received byte = ioState & OxOC;
if(received byte=0) RLY2DRV_LATCHED_OP = (1;
else if(received byte---0x04) RLY2DRV_LATCHED OP= 1;
else if(RLY2DRV_LATCHED OP) ioState ~= 0x04;
else ioState &= OxF3;
received byte = ioState & 0x30;
if(received byte---0) RLY3DRV_LATCHED_OP = 0;
else if(received_byte=0x10) RLY3DRV LATCHED_OP= 1;
else if(RLY3DRV_LATCHED OP) ioState ~= OxlO;
else ioState &= OxCF;
received byte = ioState & OxCO;
if(received byte=0) RLY4DRV_LATCHED_OP = 0;
else if(received byte=0x40) RLY4DRV LATCHED OP = l;
else if(RLY4DRV_LATCHED OP) ioState ~= 0x40;
else ioState &= Ox3F;
RW EXT IO;
181

CA 02332297 2001-O1-25
else if(ioState<8){
demandTimer = ioState;
runTimer();
void convertAndWriteToSendBuffer( unsigned char data){
if(status){
writeToSendBuffer(to ascii(data»4));
writeToSendBuffer(to ascii(data&OxOf));
1
else {
writeToSendBuffer(data);
}
void writeToSendBuffer(unsigned char data){
if(lindex<2550 ~~ addCRCflag) {
RamADDRESS = lindex+OFFSET3;
RamDATA = data;
RAM_W RITE;
lindex++;
/******************************************************
Setup
char invalidParameters(void);
void getParCheckSum(void);
void saveParCheckSum(void);
void putStringInEeprom( static const rom char *data); // for null terminated
strings
void putArrayInEeprom( static const rom char *data); // for strings that
contain nulls
void putArrayInExtRam( static const rom char *data): // for strings that
contain nulls
void putArrayInRTC( static const rom char *data); // for strings that contain
nulls
void commissionButtonPress( void);
void registerPager( void);
void getPagerTime( void);
char getMeterTime( void);
void getSyncTime( void);
char verifyTime(struct time tag *time);
void timeChange(void);
void setParsingArray(void);
void sendParsingArray(void);
void clipEepromToRam(void);
void codeCRC(void);
void codeCRCblock(void);
void read flash(void);
******************************************************/
char invalidParameters(void){
unsigned char invTemp,invTemp2;
// confirm that header is valid and do a 16 bit checksum of everything in
eeprom that is set by the
// commission function.
headerSize = read_ext_eeprom(Ox 1 d);
if (headerSize>MAXADDRESS) return(TRUE);
received_byte = read_ext_eeprom(Ox 1 f);
if((received byte!='P')&;&(received byte!=E')) return(TRUE);
if(received byte--'P'){
invTemp2=0;
182

CA 02332297 2001-O1-25 '
for(invTemp=0; invTemp<7; invTemp++) {
received byte = toint(read ext eeprom(Ox20+invTemp))
invTemp2 +_ (received byte);
if (received byte>9) retum(TRUE);
if (invTemp2=0) return(TRUE);
}
getParCheckSum();
received byte = read_ext_eeprom(Ox0);
invTemp = paramCheckSum»8;
if (received byte!=invTemp) return(TRUE);
received byte = read_ext_eeprom(Ox 1 );
invTemp = paramCheckSum&Oxff;
if (received byte!=invTemp) return(TRUE);
return(FALSE);
}
void getParCheckSum(void) {
unsigned int iPar;
paramCheckSum=0;
for(iPar=OxOd; iPar<Ox600; iPar++) {
received byte = read ext eeprom(iPar);
paramCheckSum += received byte;
i
ClrWdtQ;
r
void saveParCheckSum(void) {
switch(saveParCheckSumState) {
case 0:
saveParCheckSumState++;
pqPollEnabled=0;
pqLogToPromState=0;
while(writingEeprom)
bufferToEepromQ;
break;
case 1:
if(!pqPoIlState ~~ acOKtimer){
getParCheckSum();
eepromBuffer(OxO,paramCheckSum»8);
eepromBuffer(Ox l,paramCheckSumROxFF);
pqPollEnabled=1;
saveParCheckSumState=0;
break;
1
l
void putStringInEeprom( static const rom char *data){
do{
eepromBuffer(stringPointer++,*data);
while(*data++);
r
void putArrayInEeprom( static const rom char *data) { // for strings that
contain nulls
do{
eepromBuffer(stringPointer++,*data++);
}while(stringPointer<stringEnd);
r
183

CA 02332297 2001-O1-25
void putArrayInExtRam( static const rom char *data){// for strings that
contain nulls
do{
RamADDRESS = stringPointer;
RamDATA = *data++;
RAM_WRITE;
stringPointer++;
}while(stringPointer<stringEnd);
void writeStringToSendBuffer( static const rom char *data) { // for null
terminated strings
do{
RamADDRESS = (index+pFFSET3;
RamDATA = *data++;
RAM_WRITE;
(index++;
}while(*data);
void putArraylnRTC( static const rom unsigned char *data); !/ for strings that
contain nulls
do{
received byte=stringPointer;
rtc v°rite(received byte,*data++);
stringPointer++;
} while(stringPointer<stringEnd);
;
void commissionButtonPress( void) {
nCLEAR_SW_LED_IO = 0;
nCLEAR_SW_SET_DDRB = 0; // Turn switch 2 on by setting it to an output
eepromBuffer(Ox 10,0): // timer Mask all deactivated
timerMask=0;
eepromBuffer(Oxl I,Ox08); // exception Mask all deactivated except echo mode
exceptionMask=0x08;
eepromBuffer(OxOe,1 ); // meter error Maskl all deactivated except battery
test
eepromBuffer(OxOf,O); // meter error Mask2 all deactivated
eepromBuffer(Ox 1 d,21 ); // headerSize
eepromBuffer(Ox 1 e, l ); // headerCount
stringPointer-Ox 1 f;
putStringInEeprom(sDefaultEmail);
// Change spreadDelay to be a multiple of 3 second intervals between 0 and
256. Get random number by taking
// the low byte of TMRO counter. This overflows every 1/4 of a millisecond so
the communication with the
// pager to turn line feeds off before running commissioning should make this
random enough. Tested with a
// communication with meter so that I could display the value on the pager
port and seemed quite random.
spreadDelay = TMROL;
eepromBuffer(Oxl2,spreadDelay);
meterlPassH=0; // Make all Meter passwords 000
meter( PassM=0;
meter 1 PassL=0;
eepromBuffer(Ox13,0);
eepromBuffer(Ox14,0);
eepromBuffer(Ox 15,0);
meter2PassH=0;
meter2PassM=0;
meter2PassL=0;
eepromBuffer(Ox16,0);
eepromBuffer(Ox 17,0);
eepromBuffer(Ox 18.0);
module I Pass=1:
eepromBuffer(Ox 19,0);
eepromBuffer(Ox I a, l );
184

CA 02332297 2001-O1-25
module2Pass=2;
eepromBuffer(Ox 1 b,0);
eepromBuffer(Ox 1 c,2);
economyFlag=TRUE; // Default to Econo mode
eepromBuffer(OxSd,economyFlag);
binaryFlag=FALSE; // Default to ascii transmission mode
eepromBuffer(OxSe,binaryFlag);
compressionEnabled=FALSE; // Default to not in compression
eepromBuffer(OxSf,compressionEnabled);
pagerDiagnostics=FALSE; // Default to not in pager diagnostics mode
eepromBuffer(Oxl9b,pagerDiagnostics);
for(i=O;i<CLIPSIZE;i++){ // Erase Parsing Array
eepromBuffer(i+Ox60,Oxff);
Itemp2 = 0x60;
clipEepromToRam();
for (i=O;i<8;i++){ // Clear timer command strings
(temp=i;
(temp*=128;
(temp+=OFFSET1;
eepromBuffer(ltemp,0);
eepromBuffer(ltemp+I,0);
eepromBuffer(Itemp+2,0);
eepromBuffer(ltemp+3,0);
eepromBuffer(ltemp+4,0);
eepromBuffer(ltemp+5, ;');
eepromBuffer(OxAO,';'); // Nickname Cleared
stringPointer=OxllA;
putStringlnEeprom(sDefauItInfoCommands);
for(i=O;i<CLIPSIZE;i++){ // Erase Default Info Parsing Array
(temp = OxDA;
(temp += i;
eepromBuffer(ltemp,Oxff);
stringPointer-OxDA;
stringEnd=stringPointer+DEFAULT INFO PARSE LENGTH;
putArrayInEeprom(sDefaultlnfoParsing);
eepromBuffer(Ox1E0,0);// Secret key Cleared.
RamADDRESS = Ox538C;
RamDATA = 0;
RAM WRITE;
pqEnabled = 0;
eepromBuffer(Ox l9A,pqEnabled);
pqVerbosityEnabled=1;
eepromBuffer(Oxlfd,pqVerbosityEnabled);
synchToAtomicTime = 0x85;// 5 seconds max allowable error & use L2 to write
time.
eepromBuffer(Oxlfc,synchToAtomicTime);
killPower=1; // Kill power instead of sleeping.
eepromBuffer(Ox I fb,killPower);
received byte = 0x04; // high byte of 1200 (nominal voltage)
eepromBuffer(Oxl9C,received byte);
eepromBuffer(Oxl9E,received byte);
eepromBuffer(OxlAO,received byte);
received byte = OxBO; // low byte of 1200 (nominal voltage)
eepromBuffer(Oxl9D,received byte);
eepromBuffer(Oxl9F,received byte);
eepromBuffer(Ox 1 A l ,received byte);
185

CA 02332297 2001-O1-25
for (whichPQ=O;whichPQ<36;whichPQ++){ // Store default PQ values
received byte=(whichPQ*3)+0x82;
received byte = rtc_read(received byte);
hemp = whichPQ+Ox 1 A2;
eepromBuffer(ltemp,received byte);
eepromBuffer(Ox 1 FE,3); // PQ disable switch Off Time
eepromBuffer(Ox 1 FF,O);// PQ disable switch Report Delay
demandWindow = 0;
eepromBuffer(OxIC6,demandWindow);
eepromBuffer(OxICB,OxBF); // demand Maximum exponent
eepromBuffer(Ox1D7,1); //demand display divider
eepromBuffer(Ox 1 F9,15); // Power Off reminder delay
eepromBuffer(OxlFA,2~5); // Power On reminder delay
saveParCheckSum();
// Above this point Setup parameters, below Operational parameters (less
volatile, often used)
if (pagerMessage!=OxOe) {
rtc write(Ox 13,0); // Pager Network Zone
rtc write(Ox 14,0); // Pager Network Zone
rtc write(Ox10,0); // successCount
successCount=0;
bytesSentOK=0;
rtcyrite(Ox15,0); // bytesSentOK MSB
rtc write(Ox16,0); // bytesSentOK LSB
for (whichPQ=O;whichPQ<6;whichPQ++) // Calculate PQ Comparison values.
calcComparisons();
rtc_clear irq(); // clear rtc interrupt if set
lindex=0;
RamADDRESS = Ox538C;
received byte = 0; // To disable encryption.
selected.
RamDATA = received_b~-te;
RAM_WRITE;
eepromBuffer(OxleO.received byte);
writeMeterSeriaIQ; // Not used for write buffer, just here to put serial into
eeprom & set default key.
nCLEAR_Sf~~ SET DDRB = 1; // Turn snitch 2 off by setting it to an input
delay_sec(2);
void registerPager( void){
switch(registerPagerState) {
case 0:
registerPagerState=10;
pagerComAbortTime = IastCentiTime + 10;
break;
case 10:
if (pagerComAbortTime<lastCentiTime) {
>'Y 180
registerPagerState=l;
i
break;
case I:
186

CA 02332297 2001-O1-25
if(!yy l8State){
RamADDRESS = Ox50C3;
RAM_READ;
temp 1 = RamDATA&Oxff;
if(temp 1 !='0') {
pagerComAbortTime = lastCentiTime + 50(l;
registerPagerState=10;
st 1 pulse=Oxa;
st2pulse=Oxa;
pulseCycles=S;
else {
RamADDRESS = Ox50C6;
RAM_READ;
tempt = RamDATA&Oxff; // Get zone byte I
RamADDRESS = Ox50C7;
RAM_READ;
tempi = RamDATA&Oxff; // Get zone byte 2
RamDATA = tempt;
RamADDRESS = Ox50fb;
RAM_WRITE;
RamDATA = tempi;
RAM_WRITE;
// If Not Registered or new zone
if(newDestination~~(temp2!=rtc read(Oxl3))~~(temp3!=rtc read(Oxl4)))
registerPagerState=2;
else registerPagerState=0;
i
break;
case 2:
oldBytesSentOK = bytesSentOK;
nSTI LED_LATCHED_OP = 0; // Turn LED 1 on
RW_EXT_IO;
nSTATUS2_LED_OUTP = 0; // Turn LED 2 on
registerPagerState=3;
break:
case 3:
if (pagerComAbortTime<IastCentiTime){
exceptionFlag=0;
exceptionPageQ;
registerPagerState=4;
i
break;
case 4:
if(! exceptionPageState) {
pagerComAbortTime = IastCentiTime + 3000;
if (oldBytesSentOK---bytesSentOK)
registerPagerState=3;
else
registerPagerState=5;
break;
case 5:
if(!autoRegisterDestination){
pagerComAbortTime = IastCentiTime + 300;
yyl8(); // Get/Save zone and subzone
registerPagerState=6;
1
else
187

CA 02332297 2001-O1-25
registerPagerState=0;
break;
case 6:
if(!yy l8State){
RamADDRESS = Ox50C6;
RAM READ;
itemp = RamDATA&Oxff;
rtc write(Oxl3,itemp);
RamADDRESS = Ox50C7;
RAM READ;
itemp = RamDATA&Oxff;
rtc write(Oxl4,itemp);
registerPagerState=0;
l
i
break;
i
r
void getPagerTime( void) {
switch(getPagerTimeState) {
case 0:
getPagerTimeState=I ;
YY180;
break;
case 1:
if (!yy l8State){
if(pagerResponse=43)
getPagerTimeState=2'
else
getPagerTimeState=0;
;
break:
case 2:
RamADDRESS = Ox~OD4;
RAM_READ;
time.hi=toint(RamDATA&Oxff)* 10;
RAM_READ;
time.hr+=toint(RamDATA&Oxff);
RAM_READ;
time.min=toint(RamDATA&Oxff)* 10;
RAM_READ;
time.min+=toint(RamDATA&Oxff):
RAM_READ;
time.day=toint(RamDATA&Oxfl)* 10;
RAM_READ:
time.day+=toint(RamDATA&Oxff);
RAM_READ;
time.mth=toint(RamDATA&Oxff)* 10;
RAM_READ;
time.mth+=toint(RamDATA&Oxff);
RAM_READ;
time.yr-toint(RamDATA&Oxff)* 10;
RA~4_READ;
time.yr+=toint(RamDATA&Oxff);
time.sec=0;
getPagerTimeState=0;
break;
r
r
char getMeterTime( void){
188

CA 02332297 2001-O1-25
switch(getMeterTimeState){
case 0:
getMeterTimeState=1;
time.day=0;
time.mth=0;
command[0]=2;
for(i=l;i<ll;i++) command[i]=0;
command[9]=2;
sendFlag=FALSE;
sendCommandQ;
break;
case 1:
if (!sendCommandState){
if(badSendCommand) {
getMeterTimeState=4;
else {
RamADDRESS = Ox4b00;
itemp = ramReadUchar();
dayOfWeek=to_dec(itemp,OxFO);
RamADDRESS = Ox4b01;
hemp = ramReadUchar();
time.yr=to_dec(itemp,OxFO);
IastKnownYr-time.yr;
RamADDRESS = Ox4b02;
hemp = ramReadUchar();
time.day=to_dec(itemp,OxFO);
RamADDRESS = Ox4b03;
itemp = ramReadUchar();
time.mth=to_dec(itemp,OxFO);
rtc write(Oxl2,lastKnownYr);
command[0]=1;
command[9]=1;
getMeterTimeState=2;
sendFlag=FALSE;
sendCommandQ;
1
l
1
break;
case 2:
if (!sendCommandState){
if(badSendCommand){
getMeterTimeState=4;
else {
RamADDRESS = Ox4b00;
itemp = ramReadUchar();
time.sec=to_dec(itemp,OxFO);
RamADDRESS = Ox4b01;
itemp = ramReadUchar();
time.min=to_dec(itemp,OxFO);
RamADDRESS = Ox4b02;
itemp = ramReadUcharQ;
time.hr=to dec(itemp,OxFO);
getMeterTimeState=3;
l
break;
case 3:
if (!verifyTime(&time))
189

CA 02332297 2001-O1-25
getMeterTimeState=4;
else {
getMeterTimeReturn=1;
getMeterTimeState=0;
;
break;
case 4:
getMeterTimeState=5;
getMeterTimeReturn=0;
getPagerTime();
break;
case 5:
if (!getPagerTimeState)
getMeterTimeState=0;
break;
i
t
void getSyncTime( void){
// Get current time
rtc-get datetime(&time);
time.sec=0;
time.min=0;
time.period=1;
time. interval=1;
// If current time is equal or past sync time add 1 day to time
if (time.hr >= HOURSYNC) {
time.hr=HOURSYNC;
addTime(&time);
validateTime(&time);
if(lastSyncDay!=time.day) {
IastSyncDay=time.day;
rtc_write(Oh 1 1,lastSyncDay);
firstPassSync=1;
time.hr=HOURSYNC;
time.yr-time.yr%4;
i
1
char verifyTime(struct time_tag *time) {
if ((time->mth=0)~~(time->day=0)) return(FALSE);
if ((time->yr>99)~~(time->mth>12)~~(time->hr>23)~~(time->min>59)~~(time-
>sec>59)) return(FALSE);
if ((time->mth-4) ~~ (time->mth=6) ~~ (time->mth=9) ~~ (time->mth=11)){
if (time->day>30) return(FALSE);
i
else if (time->mth = 2){
if ((time->yr%4) > 0){
if (time->day>28) return(FALSE);
else if (time->day>29) return(FALSE);
i
else if (time->day>31) return(FALSE);
return(TRUE);
r
void timeChange(void){
switch(timeChangeState){
190

CA 02332297 2001-O1-25
C3Se 0:
timeChangeState++;
break;
case 1:
if(!sendingPage){
sendingPage=1;
timeChangeState++;
if(!synchToAtomicTime ~~ timeSynchMode>1){
getMeterTimeQ;
timeChangeState = 5;
break;
case 2:
getPagerTime();
timeChangeState++;
break;
case 3:
if (!getPagerTimeState){
prime = time.min;
timeChangeState++;
// getPagerTime();
i
break;
case 4:
if (!getPagerTimeState) {
if(pTime = time.min){
getPagerTimeQ;
pagerComAbortTime = IastCentiTime;
)
else {
timeChangeState++;
prime = time.min;
if(pTime > 29)
prime -= 30;
prime *= 60;
getMeterTime();
break;
case 5:
if (!getMeterTimeState){
timeChangeState=11;
if(getMeterTimeReturn){
timeChangeState=10;
if(synchToAtomicTime && timeSynchMode<2)
timeChangeState=6:
r
break;
case 6:
timeChangeState++;
mTime = time.min;
if(mTime > 29)
mTime -= 30;
mTime *= 60;
mTime += time.sec;
deltaTimeNegative = 0;
if(pTime > mTime) {
deltaTime = prime - m'f ime;
191

CA 02332297 2001-O1-25
if(deltaTime>899){
deltaTimeNegative= 1;
deltaTime = 1800 - deltaTime;
)
else {
deltaTime = mTime - prime;
if(deltaTime<900)
deltaTimeNegative = 1;
else
deltaTime = 1800 - deltaTime;
if(deltaTime>300){
timeSynchMode=Oxff; // Error flag.
exceptionFlag=10;
exceptionPageQ;
RamADDRESS = Ox50f0;
ramWritelnt(mTime);
ramWritelnt(pTime);
timeChangeState=10;
if(deltaTime<256){
received byte = deltaTime&Oxff;
if(received_byte<(synchToAtomicTime&Ox7~){
if(timeSynchMode)
timeChangeState=10;
else // check RTC and only change if in error.
timeChangeState=12;
i
;
break;
case 7:
mTime = time.min;
mTime *= 30;
mTime += time.sec/2;
mTime += time.hr* 1800;
pqLog(mTime&OxFF);
pqLog(mTime»8);
pqLog(OxFC);
if(deltaTimeNegative) {
if(time.sec>=deltaTime)
time.sec -= deltaTime;
else {
deltaTimeNegative = deltaTime%60; // deltaTimeNegative used for deltaSeconds
if(time.sec>=deltaTimeNegative){
time.sec -= deltaTimeNegative;
deltaTimeNegative = 0;
else {
time.sec += 60 - deltaTimeNegative;
deltaTimeNegative= 1;
deltaTimeNegative += deltaTime/60; // deltaTimeNegative used for deltaMinutes
if(time.min>=deltaTimeNegative)
time.min -= deltaTimeNegative;
else {
time.min += 60 - deltaTimeNegative;
if(time.hr)
time.hr--;
else {
192

CA 02332297 2001-O1-25
time.hr = 23;
// Time adjusted to previous day. Now what?
else {
time.sec += deltaTime;
time.min += time.sec/60;
time.sec % 60;
if(time.min>59){
time.min -= 60;
if(time.hr!=23)
time.hr ++;
else {
time.hr = 0;
!/ Time adjusted to next day.
Now what?
}
}
}
command[0]=0x21;
sum = 0x21;
received byte = to_bcd(time.sec);
command[1]=received byte;
sum += received byte;
received byte = to_bcd(time.min);
command[2]=received byte;
sum += received byte;
received_byte = to_bcd(time.hr);
command[3]=received byte;
sum += received byte;
for(i=4:i<9;i++) command[i]=0;
command[10]=sum 8;
command[9]=sumR.OxFF;
sendFlag=FALSE;
unlockFlag=l;
whichPass=1;
if(synchToAtomicTime&0x80)
whichPass++;
sendCommandQ;
timeChangeState++;
break;
case 8:
if (!sendCommandState){
if(badSendCommand && badSendCommand!=4){
exceptionFlag=9;
exceptionPageQ;
timeChangeState++;
getMeterTimeQ;
}
else {
timeChangeState=10;
}
}
break;
case 9:
if (!getMeterTimeState){
timeChangeState=11;
if(getMeterTimeReturn){
timeChangeState=10;
193

CA 02332297 2001-O1-25
break;
case 10:
b time.yr=time.yr%4;
rtc set_datetime(&time);
rtc write(Ox00,Ox04);
time.sec += 10; // So that a recalculation
from scratch can't skip an event.
for(timer=O;timer<8;timer++) {
getAlarm(timer);
if ((alarm.period!=0) && (alarm.interval!=0))
{
if (lessOrEqual(&time,&alarm)) {
initAlarm(timer);
checkAlarm(timer);
time.sec += 10; // checkAlarm redefines time
l
timeOfDaySync = timeOfDay;
timeOfDay = time.min;
timeOfDay *= 30;
timeOfDay += time.sec/2;
timeOfDay += tirne.hr* ( 800;
time.yr = time.yr4;
time.yr += time.mth;
pqLog(to bcd(time.day));
pqLog(time.yr);
pqLog(timeOfDay&OxFF);
pqLog(timeOfDay8);
pqLog(timeOfDaySyncR,OxFF);
pqLog(timeOfDaySync8);
pqLog(OxFE);
if(timeOfDay>timeOfDaySync){
timeOfDaySync = timeOfDay - timeOfDaySync;
timeChangeState= I;
else {
timeOfDaySync = timeOfDaySync - timeOfDa~
;
timeChangeState = 0;
;
for(i=O;i< 12;i++) {
RamADDRESS = 0x4404 + [*px 12;
pqReportTime = ramReadInt();
if(pqReportTime){
if(timeChangeState){
pqReportTime += timeOfDaySync;
else {
if(pqReportTime>timeOfDaySync)
pqReportTime -= timeOfDa~~Sync;
else
pqReportTime = 1;
r
RamADDRESS = 0x4404 + i*px 12;
ram WriteInt(pqReportTime);
if(pqPendingTime){
if(timeChangeState) {
pqPendingTime += timeOfDaySync;
194

CA 02332297 2001-O1-25
}
else {
if(pqPendingTime>timeOfDaySync) pqPendingTime -= timeOfDaySync;
else pqPendingTime = I;
}
if(pagerPollTimeout){
if(timeChangeState){
pagerPollTimeout += timeOfDaySync;
}
else {
if(pagerPoIlTimeout>timeOfDaySync) pagerPollTimeout -= timeOtDaySync;
else pagerPolITimeout = 0;
timeChangeState=11;
break;
case 11:
setAlarmQ;
timeChangeState=l3;
break;
case 12:
timeOfDaySync = timeOfDay;
timeOfDaySyne = time.min;
timeOfDaySync *= 30;
timeOfDaySync += time.sec/2;
timeOfDaySync += time.hr* 1800;
if(timeOfDaySync>timeOfDay)
timeOfDaySync -= timeOfDay;
else
timeOfDaySync = timeOfDay - timeOfDaySync;
timeChangeState=13;
it(timeOfDaySync>(synchToAtomicTime&Ox7fj){
timeChangeState=10;
break;
case 13:
sendingPage=0;
timeOfDaySync = IastCentiTime+6000;
timeOfDayInc = lastCentiTime+200;
timeChanged=0;
timeChangeState=0;
rtc_get datetime(&time);
timeAdjustedToday = time.hr;
if(timeSynchMode!=2 ~~ time.min>6)
timeAdjustedToday++~
if(timeAdjustedToday>23) ,
timeAdjustedToday = 0;
break;
)
void setParsingArray(void){
i=0;
do {
RamADDRESS=Istart;
RAM READ;
itemp = RamDATA&Oxff;
if (hemp !_';' R,& hemp !_':'){
received byte=toint(itemp)* 16;
195

CA 02332297 2001-O1-25
RAM_READ;
received byte += toint(RamDATA&Oxff);
eepromBuffer(ltemp2++,received_byte);
}
Istart+=2;
i++;
} while(itemp !_';' && itemp !_':' && i<CLIPSIZE);
i--; // To account for i incremented for';'
while (i<CLIPSIZE){
eepromBuffer(Itemp2++,Oxff);
i++;
r
saveParCheckSum();
void sendParsingArray(void){
switch (sendParsingArrayState){
case 0:
sendParsingArrayState++;
break;
case l:
status=0;
useTempAddress= 1;
sendParametersQ;
sendParsingArrayState++;
break;
case 2:
i f(! sendParametersState)
sendParsingArrayState=0;
else if(sendParametersState=5)
sendParsingArrayState++;
break;
case 3:
clipEepromToRam(); // ltemp2 should be set before sendParsingArray called
sendParsingArrayState++;
break;
case 4:
for(i=O:i<CLIPSIZE;i++)(
RamADDRESS = 0x5080+i;
RAM_READ;
received byte = RamDATA;
writeToSendBuffer(received_byte);
i
r
(tempt = 0x60;
clipEepromToRamQ;
sendParametersState++;
sendParsingArrayState++;
break;
case ~:
if(!sendParametersState)
sendParsingArrayStatc=0;
break;
void clipEepromToRam(void){
i=0;
RamADDRESS = 0x5080;
while(i<CLIPSIZE){
received byte=read ext eeprom(ltemp2++);
196

CA 02332297 2001-O1-25
RamDATA = received byte;
RAM WRITE;
i++; _
void codeCRC(void){
// unsigned int's
#define codeEnd pqComparison
#define codeStart pqStartTime
#define codeAddress pqReportTime
// unsigned char's
#define codePageNumber pqEvent
#define codeDataH pqInProgress
'I5 #define codeDataL pqDurationLimit
crc=0;
for(codePageNumber-O;codePageNumber<6;codePageNumber++) {
codeStart = codePageNumber;
codeStart *= 0x2000;
codeStart += 0x4000;
RamADDRESS = 0x4010+codePageNumber;
read_flash();
codeEnd = RamDATA;
if((codeEnd-codeStart)>Oxl fff){
crc=Oxffff;
return;
codeCRCbIockQ;
CaIcCRC(0);
CaIcCRC(0);
eepromBuffer(Ox04,crc8);
eepromBuffer(OxOS,crc&OxFF);
writeToSendBuffer('/');
convertAndWriteToSendBuffer(crc8);
convertAndWriteToSendBuffer(crc&OxFF);
writeToSendBuffer('/');
crc=0;
codeStart = 0;
codeEnd = Ox3fff;
codeCRCblockQ;
CaIcCRC(0);
CaIcCRC(0);
eepromBuffer(Ox06,crc8);
eepromBuffer(Ox07,crc&OxFF):
convertAnd WriteToSendBuffer(crc8);
convertAndWriteToSendBuffer(crc&OxFF);
writeToSendBuffer('f);
void codeCRCblock(void){
for (codeAddress=codeStart:codeAddress<codeEnd;codeAddress++) {
RamADDRESS = codeAddress;
read_flash();
codeDataH = RamDATA»8;
codeDataL = RamDATA&OxFF;
CaIcCRC(codeDataH);
CaIcCRC(codeDataL);
ClrWdtQ;
;
197

CA 02332297 2001-O1-25
void read_flash(void){
CPUSTAbits.GLINTD= 1;
_asm
BANKSEL RamADDRESS
MOVFP RamADDRESS,TBLPTRL
MOVFP RamADDRESS+1,TBLPTRH
TABLRD O,O,RamDATA //Nothing read just to load the Table Latch
NOP
TLRD l,RamDATA+1
TLRD O,RamDATA
_endasm
CPUSTAbits.GLINTD = 0;
)
/******************************************************
Miscellaneous
char delay_3sec(unsigned char howMany, unsigned char pattern);
void delay sec( int howMany);
void delay ms~lus( int howmany); // delay_ms plus check clear switch and latch
if pushed.
void pulse(void);
void beep(void);
void testSystem( void);
******************************************************/
void pulse(void){
switch(pulseState){
case 0: // Start
if (pulseCycles!=0){
st 1 mode = st 1 pulse;
st2mode = st2pulse;
if(stimode=O~~stlmode =OxOA)nSTILED LATCHED OP=0;
else nST 1 LED_LATCHED_OP = 1;
if (st2mode=0 ~~ st2mode==OxOA) nSTATUS2 LED OUTP = 0;
else nSTATUS2_LED_OUTP = 1:
RW_EXT_IO;
pulseCount=0;
if(stlmode>0 &R, stlmode<4) pulseState= 1;
else if(st2mode>0 && st2mode<4) pulseState = 2;
else pulseState = 3;
1
break;
case 1: // Pulse Status 1
switch(pulseCount){
case 0:
case 2:
case 4:
pulseCount++;
nSTILED_LATCHED OP= 1; RV'_EXT_IO;
pulseTime = lastCentiTime + 1 ~;
break;
case 1:
if(stlmode<2) pulseCount+=2;
case 3:
if(stlmode<3) pulseCount+=2;
case 5:
pulseCount++;
nST 1 LED_LATCHED_OP = 0; RW_EXT_IO;
if(pulseClear){
198

CA 02332297 2001-O1-25
pulseClear=0;
nCLEAR_S W_LED_IO = 0;
nCLEAR S W SET DDRB = 0;
pulseTime = IastCentiTime + 10;
break;
case 6:
pulseCount=0;
nSTILED_LATCHED_OP= 1; RW_EXT_IO;
nCLEAR_SW_SET_DDRB = 1;
if(st2mode>0 && st2mode<4) pulseState
= 2;
else {
pulseState = 3;
pulseCount=1;
;
pulseTime = lastCentiTime + 45;
break;
i
break;
case 2: // Pulse Status 2
switch(pulseCount) {
case 0:
case 2:
case 4:
pulseCount++;
nSTATUS2_LED_OUTP= 1;
pulseTime = lastCentiTime + 15;
break;
case 1:
if(st2mode<2) pulseCount+=2;
case 3:
if(st2mode<3) pulseCount+=2;
case 5:
pulseCount++;
nSTATUS2 LED_OUTP = 0;
pulseTime = lastCentiTime + 10;
break;
case 6:
pulseCount=0;
nSTATUS2_LED_OUTP= I;
if(stl mode>0 && st I mode<4) pulseState
= 4;
else {
pulseState = 3;
pulseCount=1;
;
pulseTime = lastCentiTime + 45;
break;
break;
case 3: // Toggle Only
switch(pulseCount){
case 0:
pulseCount++;
pulseTime = lastCentiTime + 75;
break;
case 1:
pulseCount++;
if (stl mode = OxA) {
nSTILED_LATCHED_OP= 1; RW_EXT_IO;
;
199

CA 02332297 2001-O1-25
if (st2mode = OxA){
nSTATUS2 LED OUTP= 1;
if (st2mode = OxB){
nSTATUS2 LED OUTP = 0;
pulseTime = lastCentiTime + 75;
break;
case 2:
pulseState = 4;
break;
break;
case 4: // Return to Start
pulseCycles--;
pulseState = 0;
break;
#pragma code testSystem = OxE000
void testSystem( void) {
switch(testState){
case 0:
testState = 1;
break;
case 1:
YY I 8Q;
testError = 0;
if (nAC OK INP) { // Power is out! Dont' even Try to talk to Meter
testError = 0x80;
badSendCommand = 0;
else {
command[0]=0x94;
for(i=l;i<I 1;i++) command[i]=0;
command[9]=0x94;
noMeterResponse=1;
sendFlag=FALSE;
sendCommand();
1
1
1=0;
testState = 2;
break;
case 2: // Test RTC, Eeprom and External Memory
rtc write(i+245,OxA~);
hemp=rtc read(i+245);
if (itemp!=OxAS) {
testError = Ox04~testError;
;
write eeprom noDelay(i+8086,OxA5);
hemp=read_ext_eeprom(i+8086);
if (itemp!=OxAS){
testError = 0x01 ~testError;
)
if (i++>9) testState = 3;
break;
case 3: // Wait for meter, pager and last pulse cycle complete
if (!yyl8State && !pulseCycles && !sendCommandState){
if (badSendCommand) {
200

CA 02332297 2001-O1-25
if(noMeterResponse) testError= OxAO~testError;
else if(badHandshake) testError= OxCO~testError;
else testError = OxEO~testError;
r
if (pagerResponse=0) testError = Ox l0~testError;
else if (pagerResponse!=43) testError = Ox l8~testError;
if (testError=0) {
stlpulse=OxA; st2pulse=OxB; pulseCycles=2;
1 0 testState = 9;
else {
testState = 4;
)
break;
case 4: // Meter Error
if (testError&0x80) {
testError = Ox7F&testError;
if(testError&0x40) {
testError = Ox3F&testError;
if(testError&0x20) {
testError = Ox 1 F&testError;
stlpulse=0x2; st2pulse=0x3; pulseCycles=2;
j
else {
stlpulse=0x2; st2pulse=0x2; pulseCycles=2;
L
else {
if(testError&0x20) {
testError = Ox 1 F&testError;
stlpulse=0x2; st2pulse=Oxl; pulseCycles=2;
1
else {
stlpulse=0x2; st2pulse=0x0; pulseCycles=2;
1
L
l
testState = 9:
else testState = 5;
break;
case 5: // Pager Error
if (testError&;OxlO) {
testError = OxOF&testError;
if(testError&0x08) {
testError = 0x07&testError;
stlpulse=0x3; st2pulse=0x3; pulseCycles=2;
else {
stlpulse=0x3; st2pulse=0x0; pulseCycles=2;
testState = 9;
i
J
else testState = 6;
break:
case 6: // RTC Memory Error
if (testError&0x04) {
testError = 0x03&testError;
stlpulse=Oxl; st2pulse=0x1; pulseCycles=2;
201

CA 02332297 2001-O1-25
testState = 9;
else testState = 7;
break;
case 7: // External RAM Memory Error
if (testError&0x02) {
testError = 0x01 &testError;
stlpulse=0x1; st2pulse=0x0; pulseCycles=2;
testState = 9;
)
else testState = 8;
break;
case 8: // Eeprom Memory Error
if (testError&0x01 ) {
testError = 0;
stlpulse=0x1; st2pulse=OxA; pulseCycles=2;
testState = 9;
break;
case 9: // Wait until Finished flashing
if (testError=0){ // Don't Wait
if (nTEST JUMP INP)
testState = 0;
else testState = 1;
else if (pulseCycles=0) {
testState = 4;
i
break;
1
l
void delay_sec( unsigned int howMany){
unsigned int i;
for (i=O:i<howMany;i++){
delay_ms-plus(1000);
ClrWdtQ:
1
i
void delay-ms~lus( unsigned int howMany) { // delay-ms plus check clear switch
and latch if pushed.
unsigned int iDelay;
for (iDelay=O:iDelay<howMany;iDelay++){
delay-ms(1);
if(!nCLEAR_SW LED_IO){
nCLEAR SW LED_IO = 0;
nCLEAR SW SET DDRB = 0: // Turn switch 2 on by setting it to an output
r
i
void updateAnalogInputs(void) {
switch(updateAnalogInputsState){
case 0:
break;
case 1:
ADCONO = 0x01;
ADCON1 = Ox4C;
break;
case 2:
ADCONO = OxO~:
202

CA 02332297 2001-O1-25
break;
case 3:
while(ADCONO&0x04);// will wait here but should be done
anyway (about 100 micro-seconds)
IBSenseH = ADRESH;
IBSenseL = ADRESL;
ADCONO = 0x81;
break;
case 4:
ADCONO = 0x85;
break;
case 5:
while(ADCONO&0x04);// will wait here but should be done
anyway (about 100 micro-seconds)
TempSenseH = ADRESH;
TempSenseL = ADRESL;
ADCONO = 0x91;
break;
case 6:
ADCONO = 0x95;
break;
case 7:
while(ADCONO&0x04);// will wait here but should be done
anyway (about 100 micro-seconds)
VBSenseH = ADRESH;
VBSenseL = ADRESL;
ADCONO = Ox0l;
updateAnalogInputsState=255;
// will be incremented
to zero.
break;
updateAnaloglnputsState++;
/******************************************************
32 bit floating point functions.
void uintl6ToFloat32(unsigned int datal6, unsigned char float32Address);
int float32ToIntl6(unsigned char float32Address);
void floatMultiply(unsigned char addressA, unsigned char addressB, unsigned
char addressAtimesB);
void floatDivide(unsigned char addressA, unsigned char addressB, unsigned char
addressAoverB);
void floatAdd(unsigned char addressA, unsigned char addressB, unsigned char
addressAplusB);
void cos128(unsigned int cosData, unsigned char float32Address);
void floatChangeSign(unsigned char addressA);
void putFIoatPager(unsigned char float32Address);
void FL01632U(void);
void FPD32(void);
void FPM32(void);
void FPA32(void);
void INT3216(void);
******************************************************/
void uintl6ToFloat32(unsigned int datal6, unsigned char float32Address);
AARGBO=datal6»8;
AARGB 1=datal6&Oxff;
FL01632U();
RamADDRESS = 0x5100+float32Address;
RamDATA = AARGBO;
RAM_WRITE;
RamDATA = AARGB 1;
RAM_WRITE;
RamDATA = AARGB2;
RAM_WRITE;
RamDATA = AEXP;
203

CA 02332297 2001-O1-25
RAM WRITE;
int float32T0Int16(unsigned char float32Address);
unsigned int datal6;
RamADDRESS = 0x5100+float32Address;
RAM_READ;
AARGBO = RamDATA;
RAM_READ;
AARGB 1 = RamDATA;
RAM_READ;
AARGB2 = RamDATA;
RAM_READ;
AEXP = RamDATA;
INT3216Q;
datal6=AARGBO;
datal 6 = (datal6«8) + AARGB 1;
return(datal6);
void floatMultiply(unsigned char addressA, unsigned char addressB, unsigned
char addressAtimesB);
RamADDRESS = 0x5100+addressA;
RAM_READ;
AARGBO = RamDATA;
RAM_READ;
AARGBI =RamDATA;
RAM_READ;
AARGB2 = RamDATA;
RAM_READ;
AEXP = RamDATA;
RamADDRESS = Ox~ 100+addressB;
RAM_READ;
BARGBO = RamDATA;
RAM_READ;
BARGBI =RamDATA;
RAM_READ;
BARGB2 = RamDATA;
RAM_READ;
BEXP = RamDATA;
FPM32Q;
RamADDRESS = 0x5100+addressAtimesB;
RamDATA = AARGBO;
RAM_WRITE;
RamDATA = AARGB 1;
RAM_WRITE;
RamDATA = AARGB2;
RAM_V~RITE;
RamDATA = AEXP;
RAM_WRITE;
;
void floatDivide(unsigned char addressA, unsigned char addressB, unsigned char
addressAoverB);
RamADDRESS = 0x5100+addressA;
RAM_READ;
AARGBO = RamDATA;
RAM_READ;
AARGB 1 = RamDATA;
RAM_READ:
AARGB2 = RamDATA;
RAM READ;
204

CA 02332297 2001-O1-25
AEXP = RamDATA;
RamADDRESS = 0x5100+addressB;
RAM_READ;
BARGBO = RamDATA;
RAM_READ;
BARGBI =RamDATA;
RAM_READ;
BARGB2 = RamDATA;
RAM_READ;
1 BEXP = RamDATA;
O
FPD32Q;
RamADDRESS = 0x5100+addressAoverB;
RamDATA = AARGBO;
RAM_W RITE;
RamDATA = AARGB 1;
RAM_WRITE;
RamDATA = AARGB2;
RAM_WRITE;
RamDATA = AEXP;
RAM WRITE;
void floatAdd(unsigned char addressA, unsigned char addressB, unsigned char
addressAplusB){
RamADDRESS = 0x5100+addressA;
RAM_READ;
AARGBO = RamDATA;
RAM_READ;
AARGB 1 = RamDATA:
RAM_READ;
AARGB2 = RamDATA;
RAM_READ;
AEXP = RamDATA;
RamADDRESS = 0x5100+addressB;
RAM_READ;
BARGBO = RamDATA;
RAM_READ;
BARGB1 =RamDATA;
RAM_READ;
BARGB2 = RamDATA;
RAM_READ;
BEXP = RamDATA;
FPA32Q;
RamADDRESS = 0x5100+addressAplusB;
RamDATA = AARGBO;
RAM_WRITE;
RamDATA = AARGB 1;
RAM_WRITE;
RamDATA = AARGB2;
RAM_WRITE;
RamDATA = AEXP;
RAM WRITE;
void floatChangeSign(unsigned char addressA);
RamADDRESS = 0x5100+addressA;
RAM_READ;
RamDATA ~= 0x80;
RamADDRESS = 0x5100+addressA;
RAM_WRITE;
;
205

CA 02332297 2001-O1-25
void cos128(unsigned int cosData, unsigned char float32Address){
// This function takes a value that is 128 times an angle between 0 and 360
degrees.
// 0 to 45 is approximated by cos(x) = 1 - (x*x/6890)
// 45 to 90 is approximated by cos(x) = 1.192 - (x/122) - (x*x/17800)
// 90 to 180 cos(x) =-cos(180-x)
// 180 to 270 cos(x) =-cos(x-180)
// 270 to 360 cos(x) = cos(360-x)
unsigned char negativeFlag;
negativeFlag = 0;
if(eosData>34560){ // 270 to 360 degrees
cosData = 46080 - cosData;
else if(cosData>23040){ // 180 to 270 degrees
cosData -= 23040;
negativeFlag = 1;
else if(cosData>11520){ // 90 to 180 degrees
cosData = 23040 - cosData;
negativeFlag= l;
i
uintl6ToFloat32(cosData, 0x50);
floatMultiply(Ox50, Ox4C, 0x50);
floatMultiply(Ox50, 0x50, 0x54);
if(cosData<5760) { // 0 to 45 degrees
floatMultiply(Ox54, Ox3C, 0x54);
floatAdd(Ox54, 0x58, float32Address);
i
else { // 45 to 90 degrees
floatMultiply(Ox50, 0x44, 0x50);
floatMultiply(Ox54, 0x48, 0x54);
floatAdd(Ox54, 0x40, 0x54);
floatAdd(Ox54, 0x50, float32Address);
if(negativeFlag)
floatChangeSign(float32Address);
r
void powerSaveSleep(void){
received byte = read_ext_eeprom(Ox02); // Check loader version for < 18
if (received byte<Ox30 ~~ received byte>Ox39)
pqEvent=0;
else {
received byte -= 0x30;
received byte *= 10;
pqEvent = read_ext_eeprom(Ox03);
if (pqEvent<Ox30 ~~ pqEvent>Ox39)
pqEvent=0;
else {
pqEvent -= 0x30;
pqEvent += received byte;
if(pqEvent < 18)
pqEvent=0;
if(!sleepTest){
if(!(exceptionMask&0x02));
exceptionMask ~= 0x02;
eepromBuffer(Ox 1 1.exceptionMask);
saveParCheckSumQ;
206

CA 02332297 2001-O1-25
pqPollState = 0;
while(saveParCheckSumState)
saveParCheckSum();
pqLog(timeOfDay&OxFF);
pqLog(timeOfDay»8);
pqLog(OxFB);
buffToPromState = 0;
pqLogToPromState=0;
while(writingEeprom)
bufferToEeprom();
buffToPromState = 0;
pqLogToPromState = 0;
while(pqBuffInPnt!=pqBuffOutPnt)
pqLogToEeprom();
delay_ms( I 0);
if(killPower)
KILL PWR OUTP= 1;
CPUSTAbits.GLINTD= 1;
TOSTA = Ob01100000;
InstalLINT(-INT);
INTSTAbits.INTE= l;
CPUSTAbits.GLINTD = 0;
PAGER_PWR_OUTP = 0;
nDCLED_OUTP = 0;
nSTILED_LATCHED_OP= I;
nSTATUS2_LED_OUTP= 1;
nCLEAR_SW_SET_DDRB = I; // Turn switch 2 off by setting it to an input
CPUSTAbits.GLINTD= I;
while(nAC OK_INP){
rtc-get datetime(&alarm);
alarm.period=I;
alarm.sec += 4;
validateTime(&alarm);
if(alarm.hr>=24){ // Day roll over.
for(;;); // Cause a WDT reset.
i
rtc_set_alarm_datetime(&alarm);
nLED_EN LATCHED_OP= l;
CPUSTAbits.GLINTD= l;
RWextendedIO();
if(pqEvent)
remoteSleepQ;
else {
_asm
sleep
_endasm
;
nLED_EN_LATCHED_OP = 0;
RWextendedIO();
CPUSTAbits.GLINTD = 0; // To allow RTC alarm interrupt flag to be cleared.
for(;;); // Cause a WDT reset.
#pragma code testInFlash = 0x4020
void testInFlash(void){
putstring(sNewLine,echoSize); // echoSize is in the same memory location
putstring(sBootBanner,echoSize);// as echoPort in the Loader.
207

CA 02332297 2001-O1-25
sleepiest = !(rtc read(Oxff));
rtc_write(Oxff,sleepTest);
if(sleepTest) {
putstring(sKillTest,echoSize);
KILL PWR_OUTP= 1;
putstring(sFailed,echoSize);
}
sleepiest= 1;
putstring(sSleepTest,echoSize);
powerSaveSleep();
_asm
movlw 0
movwf PCLATH
movwf PCL
endasm
}
void putstring( static const rom char *data, char whichPort );
do{
if(whichPort---I ){
while(BusyUSART 1 ());
putcUSART 1 (* data);
}
else {
while(BusyUSART2Q);
putcUSART2(* data);
}
}while(*data++);
208

CA 02332297 2001-O1-25
Appendix B
tlem.0uan(ityReferenceValw Descrip(ion -._ . ParlNo. Mfr.
1 Id Ct, C2. D.tuF Cap, Car, X7R, SMT-0805,ECJ-2vBtEt04KPanasonic
C3, CI, C5. 25v, t0%
C7. C8. C9,
C12.C11,Ct5.Ct7,Ct8.C19,C2D,
C2t, C22.
C2J. C25,
C26, C27,
C30,
CJ1, CJ2.
CJJ, C3d,
C75, C76.
CJB,
C40, C41,
C42, C43,
C44, C47,
C49,
C50, G52.
C57, C54,
C55. C56,
C60.
C61
~
2 6 xt, C6, Nm Installed -
. U9. C11,.
R20. R27
~
_ 1 C10 lOpF Cap. Car, NPO, S0.1T-0805.ECU-V1N100DCNPanasonic
50v, 5% -
4 2 Ct3, C28 t000uF Cep, Elytc, t05C. 10v,ECE-AIAFSt02Panasonic
~ 20%.2000nr, Radial,
HFS
1 C16 IOuF Cap. TanL 16v, 20%. ECS-HICCtO6RPanasonic
SMT C-Case
6 1 C24 68uF Cap, Tanl. 6.7v, 20%, ECS-HOJD686RPanasonro
SMT D-Case
7 t C29 - Nd Installed . -
8 t C37 t200uF Cap. Elytc, 105C, 16v,ECA-ICFOt22Panasonic
20%, 200Dbr, Radial,
HFO
9 t C39 t.OF Cap. NF Senes Super EEC-FSRSU105Panasonic
CaD. 5 5v, -25 - 70C
70 2 C46. C45 lBpF Gap. Car. NPO. SA1T-0605.ECU-V1Nt80JCNPanasonic
50v, 5 %
t1 1 Cd8 1uF Cap, Cer, %7R, SMT.1206,ECJ-3VB1Ct05KPanasonro
16v, t0%
t2 1 C51 O.OtuF Cap. Car, X7R, SMT-0805,ECU-VtHtOJKBGPanasonro
50v, 5%
1J 2 D1, D4 BA570 Onoda. Schotlky, 70v, BA570DI Diodes
SOT.23 Inc.
14 d D2, 07. FMMD9t1Die, Switching, 75v. FMMD914 - 2elea
D6, 07 SOT-23
1 DB 52D Orode,SmLRed.GP.200V/2A,S2D - - M~aosemi
SMT, DO-2t4AA
-
16 9 FBt, FB2. 1k Ferr4s BeaA, tK ~ 100Mnz,BLM-21Bt02SPTMurala
F87. FBd. 0.4 OCR, 200mA. D805
F85, F86.
F87,
FB9, fBtt
t7 2 F010. F88 . Nd Installed . -
t8 J W t, JPt, JMP1XJ Jumper, ts7, Tm tail, 51011-OJ Sullies
JP2 Gold Conl., 0230m.
lg.
19 1 Jt - Nd Instaked - -
t J2 JMPls7 Jumper, 1s7, Tin Uil, 57011-07 Sull~ns
Gold CoM., 0.230~n.
lg.
21 1 J3 fi9747-1Fles Foil Cable. 2 69317-7 Caole
s 6 Positron Connections
22 1 JI HDR Jumper, 2st 3. fn tail.5201 t-17 Sulkns
2 a Gold Cont., 0.270m.
13 lg.
23 1 J9 - No( Installed
2d 5 LEDt, LED2,REO . ~~LED RED WATER CLEARSSL-LxtSIC-TRLumea
LED7. LED4, ~ SOT.23
LEDB
d LEDS, LE06,GRN LEO GREEN WATER CLEAR SSLL%tSGC-TRLumea
LED7. LE09 SOT-23 -
26 1 PCBt 700t PCB, Gen 2 Pager Inledace,3001 t-0050XPT
t-0050 Rev. C
27 t Pt 873Jt-2220Header, 22 Pos. Str.. 87331-2220Moles
2mm. M~n~-GrM
26 1 P2 - Nd In5lalled
29 3 Ot. 07. MMBT3906TRAMS PNP dOV SkID MMBT7906 MOtorda
09 SOT-27
15 02, OJ, MMBT3904TRAMS NPN 40V SMD SOT-2JMM8T39M Motorola
Od, 05, O6.
08, OtO.
020.
021. 030.
071. 0J2.
0t00. 0101.
0102
71 10 Rt, R2. 2.2k Res. CarOOn, 5%, SMT-0605ERJ-6GEVJ222Panasonic
R7. Rd. R13.
R14, R15.
R16,
Rt 7, 8209
-
72 35 R5. R6, 10k Res. CdlbOn, 5.4. SMT.0805ERJ-6GEYJt03Panasonic
RB, Rte,
R19, R23,
R24, ~
R25. R26,
R29. R71,
R31, R40,
R41,
Ra2. R4 J,
R44, R45.
R17, R50,
R51,
R56. R57,
R62. R6J.
R67, R70,
R7t,
R79, R61,
8207. 8204,
8205, R2D6.
8207
37 t9 R7. R9, 100k Res. CsrOOn, 5%, SMT-0805ERJ-fiGEYJIOaPanasonic
RtO. Rag,
R52. RSJ.
R65.
R72. R77.
R90, R94,
8702. 8103,
Rt04. R105,
R20t, RJ(H1.
8301,
8302
3d 2 R11, R12 56k Ras, CarDOn, 5%. 5M7.0805ERJ-6GEYJ567Pan
ni
s
a
3 R21, R22, 1.7k Res, C8lDOn, 5%. SMT-0805ERJ-6GEYJ172o
R28 c
Panasmic
J6 t R30 .. 665k Res,MF,t%,SMT.0805 ERJ-6ENF665tPanasonro
~
77 2 2.00k. Res.MF,t%,SMT-Ot105 ERJ-6ENF2DOt- Panasonic
R32.R55 -
38 3 RJ3, R97, 5 6k Res. Carbon, 5X, SMT-OB05~ERJ-6GEYJ562- Panasonic
RlOt
39 1 RJ5 30.1k Ras. MF, 1%, SMT-0805 ERJ-6ENF7012Panason
t
10 1 RJ6 95.7k Res. MF, 1%, SMT-0805 ERJ-6ENF95J2Pan
aSMro
a1 7 R77, R39. 220k Res. Carbon ERJ-6GEVJ224P
R58. R59. 5%
R60, R61. SMT-0805
R83
, anasenro
,
a2 1 RJ8 22k Ras, Carbon. 5X. SMT-0805ERJ-6GEYJ22JPanasonro
47 t RSd 1.99k Res. MF, 1%, SMT.0805 ERJ-6ENF499tPanasonro
4a 1 R64 700 Res. Carbon, 5%. SMT.0805ERJ-6GEYJtOtPanasonro
-
2 R66. R78 Rx NOI Installed - -
46 1 R6B 10k Ras, Carbon, 5%. SMT-0805ERJ-6GEVJtOJPanaSOnK
d7 1 R73 765k _ Rss. MF, 1%. SMT-0805ERJ-6ENF3652Panasonic
- ~~
a8 1 25 5k Res. MF, 1%, SMT-0805 ERJ-6ENF2552Panasonro
R7t ~ ~ ~~
-
49 1 R75 97.6k Rsa, MF, 1%, SMT.p805 ERJ-6ENF9762Panasonro
1 R76 -__ 775 Res. MF. t%. SMT-OB05 ERJ-6ENF7150Panasonic
_ _.
209

CA 02332297 2001-O1-25
Appendix B continued
Item Guantlty Retarence ~...-. _ Vatw DW cr;pGOn van No. - Mrr.
1 R80 1704 Res. DaIDOIi, 5%, SMT.0805 ERJ-6GEYJ471 Panasonic
50 R82. R9t,174 Rea, Carbon, 5%, $M1-0805ERJ-6GEVJa7JPanasonrc
1 R92,
R93
51 R81 Ra Nd Instaued
1
52 R85 tOk Res,Carbon,5%,SMT-0805ERJ-6GEYJ103Panasonic
t
53 R86 625 Res. MF, t%. 5M70805 ERJ-6ENF8250Panasonic
t ~
~
t R8t tO.Ok Res. MF, t%. SMT-0805ERJ-6ENFt002Panasonic
51 ~ -
~~~~~-~~
55 R88 t2.74 Res,MF,1%.SMT-0805 ERJ-6ENFt272Panason~c
t ~ ~ -
~
~
~
1 R95 tOk Res, CarbM, 5X, $MT.O805ERJ-6GEVJt03~ Panasonic
58 ~
57 Rt06, Rz Nd Inauned
2 Rt00
58 8200 Rz Ndhnlalled
t
59 8202 Ra Nd Installed -
t
t R20B t4 Rea.CarDOn,S%.SMT-0805ERJ-6GEVJt02Panasonic
60 8209 224 Rea, CarDdl, 5%, SMT-0805ERJ-6GEYJ222Panasonic
t
61 8210 tO.Ok Res, MF, t%. $MT-OB05ERJ-6ENFt002Panasonic
t
62 R2tt 12.74 Res, MF, 1%, SMT-D805ERJ.6ENFt272Panasonrc
t
6J R2t2 1M Res.CarDOn,s%,SMT-0805ERJ-6GEYJt05Panasonla
t - . -.
-
-
t $t ....FR22d9 M~,Swdcn. t5-25 A/TLt04.FR2249 CP
64 200v.0 SA. SMT Clare
-
65 TPt, TP2.TESTPOINT..PCB Testpomt Only No Pan
3 TP7 ..
66 U1 Nol Installed
1
67 U3, U2 Nol Installed
2
68 W ~AM29Fd00BT-t20-EIFlath Memory. IMBd AM29F400BT-120-EIAMD
1 z 16 (256 kbytesl.
SMT, TSOP-18
69 US 2dLC65-I15MEEprom memory, e4 2aLC65-USMMicrochip
t s B Dyles, Serial.
$0L-08
70 U6 . Nd Irtstaced
7
1t U7 LH5t61AHN-10LSlakc RAM, Bk a 8 LH5t6dAHN.tOISharp
1 bytes, 100 n$ec,
SOL-28
-
72 U8 PCf8583TD RSet Tma Cbck - Calendar,PCF85B3TD Pnikpa
t 12C. SOL-B
7J Ut0 "... MM71HC241WMIC,OctaIBuderlprner,$MT50-11MM74HC2ddWMFairchild
t -
7d Utt MM7dHC37JM IC.Odal'D' Transp MM7dHC373M~ ~Fauchild
t - ...... Lalcn, SO-20 - -
~ .. -.........
75 Ut2.UiJ SN74HC573DWIC.Odal'D'lransp.Latch.SO-20SN74NC57JOW......MOlorda
Z ~ ~~
76 Ut1 LM291tS IC. 1 AMP low DropoutLM29d15 ~~~~~-Nalanal
1 Regulator, TO-263-5 ~~~ ~ -
~
t) Ut5 LP295tACM IC.MlustabklowdropoulRegulator,$MT.50-8LP295tACM
Falrchd0
t
78 Ut7 TC71NC08AFNIC, Ouad 211p NarM TC7dHCO8AFNTosluDa
t Gate, SMT SO-11
79 U18 MM7dHC27M IC, Tnple 3l/p NOR MM7dHC27M Fairchild
t Gate, SMT, SO-t4
80 Ut9 PICt7C756-16IILIC.CMOSMnaoconlroller,Ind.Temp.PICt7C756-
16/ILM~crocn~p
t
8t U20 MM7dHCJ2M IC, Ouad 2 VD OR Gale,MM7dHCJ2M Fa~rchdd
t SMT, SO-t1
82 U2t MM7dHCOdM IC. Hea tnvener, SMT,k1M71HC04MFairchild
t SO-td
8J U22 LM2902M IC, Ouad OPAmp, La LM2902M National
t - Power, SO-1d
-
84 U23 ~ Instaned -
t - .
..
es U2d - -NInstaaed...... - .. .. ...
1 ~ -
.
B6 U200 TCIINCt4AFN-IC, Hex Schm~ll Imener,TC7dHCtdAFN~ ~
t $MT, SO-11 ~ TosIYDa
-
87 VR1 - Ndlnstalled
t
BB VR1 - Nd Instaned
1
89 VR3 LM4JtBIM3 IC AOJ PRECISION ZENERLM4J1BIMJ Nalanal
1 REG $0T23
90 WR1 - Ndlnstalled
1
9t WR2 Notlnslalled
t
92 WRI . Nil Installed
1
93 WR5 0 Rea,CarDOn.S%.SMT.0805ERJ-6GEYDRDOVPanasonK
t
9d WRfi - Nd Inalallpd
t
95 WR7 - Nd Installed
t
96 WR8 Ndlnalallad
1 -
97 WR9 . ....~ynslalled~ .
a -
98 WRtO 0 Rea,Carpon,5%.SMT-OB05ERJ-6GEYOROOVPanasonK
t ~
99 WRt1 - Ndlnstalled -
t
t00 WRt2 0 Res,CarDOn.S%,SMT.pg05ERJ-6GEYORDOVPanasonrc
t
t01 WR73 - Nd Installed . -
t
102 WRt4 0 Res. Carbon, 5%, SMT-Ofi05ERJ-6GEVOROOVPanasonic
t
t03 WRtS - NdIrvWled
t
10a WR16 - Ndlnstafied
t
t05 WRt7 0 Ras. Dar00n.5%, $MT-OB05ERJ-6GEYOROOVPanasonic
t
t06 WR20 - Ndlnsislled -
t
t07 W2 JMPtX2 Jumper.la2.tnla4.GddCoM..017Qn$t0lt-0Z $uR~ns
t g.
t08 %Ut9 Socket. Socket, PLCC-68 510-99-068-17-400000M~IIMaa
t PLCC-6B
tOS x2 ~k~ xtaLTnc.Ortz.2oovm,t2.5oFECS3x6 ECS
t .. .. -
tt0 _ x3 3.6861MNZ xtal. Sml _Orlz, 50ppm.20pFECS-3620-SPECS
t
210

CA 02332297 2001-O1-25
Appendix C
Item tiy RetarencaValw - eon
Guan -- _ -
..
P arl No.
t 4 Ct,C9,C13,C17O.tuF Cap,Cer,X7R,ShlT-0805
25v
t0%
, ECJ.2VBtE104Kpanasonit
.
2 7 C2. CJ, Ca, C~
CS. C6,
C7, C30
Not used. _
3 2 C8
Ct6
, 100uF Cap, Elytc, 105c,
4 S C11 25v, 1000hr, SMT, EEV-HAIEtOIP
Ct2 F-Case
Cta
C75
Panasonic
- , O.OtuF Cap. Cer, X7R, SMT-0805.ECUV1Ht03KBGP
2 , 50v. 10%
.
C18
C70
anasonic
8 - , 0luF Cap, Cer, X7R, SMT-OB05.25v,ECJ
2 C19 t0%
C
-2VBtEtOaKPanasonic
7 , 1nF Cap, Cer, X7R
20 SKIT-1206
16v
10%
, ECJ-3YBtC105KPanasonic
2 D2. 01 52D ,
.
0i
d
S
R
8 5 01, 02 - o S2D r
OJ e, Mi
D3 m1,
07 ecLGP,200V12A, SMT,
DO-2taAA
c
9 1 , Do Nol Install - osemi
.
,
F1
J.tSAm . -
10t H5 D Fuse,5x20,SR216.F8,t25V
217-J15 Lrttetluse
1 - po Not Install
1t2 JPt.JP2 Jh1P1X2' J~~r
1z2
Tlnlad
GoldCont
0
270inl
, S1011-02 Sunirts
t2- - ,
.
.
..
g.
t31 Jt HOR 2 x Bos Connector Strip. -
1at J2 13 Horizontal Enly
2x13 Pos
t5t hITSW-t , BCS-113-L-D-HESamlec
10-14G-D-470-RA.,
Header, 2210. R1
Angie, O.a70m. Post
Height
0
8300AL
, MTSW-t
JJ MTSW-103-09-G-S-350-RA. t0-10-G-D-a70-RA
. Samtec
Header
1x3
Rt An
le
0
350~n
p
t H
, MTS'N-103-C9-G-S-350-RA Samlec
t6- ,
g
,
.
.
os
eghL 0730OAL.
t71 PC81 30021.0050PCB. Gen 2 Relay-Charger
Rev
C
, 30021-0050XPT
1B3 O4, O5, 08 MMBT390d .
TRANS NPN 40V SMD
SOT-23
h1h18T390aMotorola
t9t p6 MJD32C Trans PNP 100v 3A
O-Pak SMT
MJD32C ST Mncroelectromc5
20t Rt 20M Res. Carbon
5%
SMT-0805
, ERJ-6GEYJ206VPanasonic
,
21a R2, RiB, 100k Res. Carbon
Ra3, Ra4 5%
SMT-0805
, ERJ-6GEYJ10cyPanasons
22t9R3. Ra, R5, Ra ,
R6, R7, N
R8. R9,
RiS.
o1 used.
R16, R20, - -
R21, R22,
R2J, R2a,
R25, R26,
R27, R28.
R36
23t R70 0 Res, Carpon
5%
SMT-0805
, ERJ-6GEYJORDOVPanasonic
2a4 Rt t, RJS, 100k .
R37, Ra2 Res. Carbon
5%
SMT-0805
. ERJ-6GEY104VPanasonic
252 Rt3. R12 0 .
Res. Carbon
5%
SMT-0805
, ERJ-6GEYJOROOVPanasonic
26t Rta iR8 ,
Res, Carbon
5%
SM1-0805
, ERJ-6ROJ1R8VPanasonic
27 Rt7 22k ,
Res. Carbon
5%
SMT-0805
, ERJ-6GEY22JVPanasonic
28t Rt9 39k ,
Res, Carbon
5%
SMT-0805
, ERJ-6GEYJ393VPanasonic
291 R29 470 ,
Res, Carpon
5%
SMT-0805
, ERJ-0GEYJa7IVPanasonic
30t RJO l9.ik ,
Res, MF
1%
511T-0805
, ERJ-6ENF1g12PanaSOnic
31a R3t, RJ2. 390 ,
R73, R34 R
C
J21 R38 69 e5, ERJ-0GEY39tVP
8 arbon, 5%. SMT-0805
anasonic
331 R39 . Res. MF, t%, SMT-OB05ERJ
k 6ENF
-
- Panasonic
220 Res, CarDOn 6982
5%
SMT-0805
, ERJ-6GEY22tVPanasonic
3at Re0 390k .
Res. Carbon
5%
SKIT-0805
, ERJ-0GEY39aVPanasonic
351 Ra1 43.2k ,
- Res
MF
t%
SMT-OBOS
. ERJ-6ENFd322Panasonic
362 Ra6, Rd5 1k ,
.
Res. Carbon
5%
1IBW Leaded
, 1 OkEBK-ND
372 Ra7, RaB 6 8k .
Res. Carbon
5 %
SMT-0805
, ERJ-6GEY682VPanasonic
38t R50 Rs - ,
Nol used
.
J91 SCHt 30020-0050Schematic, Gen 2 X
a0 Rev. C Relay-Char
er Boara
g 3002p-0050PT
a12 St. 52 FR22a9 Alag. Swilcn. 15-25
AITLlOa
200v
O
SA
SMT
. FR22a9 CP Clare
t S3 .
x ,
.
Do Not Install
a21 TB1 31018103 3Pos.PWgonTertnmalBkxkHeader
31018107 RIA
434 TP t, TPJ. -
TPa, TPS
a41 TP2 - -
a5t Ut Uz po Notlnsia8 - -
a61 U2 UC2906N IC. SealeO Lead Acid
d7 Battery Charger
UC2906N Unilrode
1 UJ LM2902M Quad OyArt,p
Lo Power
S(?14
. LM2902M National
a8a Ua, U5, U6. LBAt t0 .
c9 U7 IC, ODto-MOS Relay,
350V
120mA
35 ohm
1A/10
l
, LBAt t0 CP Clare
2 U8, U9 PS2705-t ,
- ,
con
aa
IC. AC W Optcoupler,
3750 V(isol)
Snr
1e Tran
SOP
a
, PS2705-t NEC
50t NJR1 0 g
s ,
-
R
C
b
5t1 lvR2 0 ar ERJ-6GEYJOROOVPa
es,
on, 5%. SMT-0805
nasonic
5Zt WR3 Res. Carbon, S%. ERJ-6GEYJOROOV
SMT-0805
Panasonic
t Oo Nd Install -
3 R4 '
542 XF1 po Nd Instaa
XF2
. 111501 FuseNdr,2AG5a20.
55f XF3 111501
860620 Lrtlelfuse
F;nern,2AG15x20
.
5fit xTBt 71079102 2POS.plug-InTermmalBbck31
0
079 RIA
102
. 211

Representative Drawing
A single figure which represents the drawing illustrating the invention.
Administrative Status

2024-08-01:As part of the Next Generation Patents (NGP) transition, the Canadian Patents Database (CPD) now contains a more detailed Event History, which replicates the Event Log of our new back-office solution.

Please note that "Inactive:" events refers to events no longer in use in our new back-office solution.

For a clearer understanding of the status of the application/patent presented on this page, the site Disclaimer , as well as the definitions for Patent , Event History , Maintenance Fee  and Payment History  should be consulted.

Event History

Description Date
Inactive: IPC from MCD 2006-03-12
Application Not Reinstated by Deadline 2004-01-26
Time Limit for Reversal Expired 2004-01-26
Deemed Abandoned - Failure to Respond to Maintenance Fee Notice 2003-01-27
Application Published (Open to Public Inspection) 2002-07-25
Inactive: Cover page published 2002-07-24
Letter Sent 2002-06-17
Inactive: Delete abandonment 2002-06-17
Letter Sent 2002-06-17
Letter Sent 2002-06-17
Inactive: Abandoned - No reply to Office letter 2002-04-29
Inactive: Single transfer 2002-04-24
Inactive: Correspondence - Formalities 2002-04-12
Inactive: First IPC assigned 2001-03-21
Inactive: IPC assigned 2001-03-21
Inactive: Filing certificate - No RFE (English) 2001-02-26
Application Received - Regular National 2001-02-23

Abandonment History

Abandonment Date Reason Reinstatement Date
2003-01-27

Fee History

Fee Type Anniversary Year Due Date Paid Date
Application fee - small 2001-01-25
Registration of a document 2002-04-24
Owners on Record

Note: Records showing the ownership history in alphabetical order.

Current Owners on Record
SMARTSYNCH LTD.
Past Owners on Record
ALLAN L. SCRIBNER
DANE BLACKWELL
DENNIS M. NEEDHAM
PATRICK C. HAMILTON
RODERICK MICHAEL JOHNSON
WILFRED MUELLER
Past Owners that do not appear in the "Owners on Record" listing will appear in other documentation within the application.
Documents

To view selected files, please enter reCAPTCHA code :



To view images, click a link in the Document Description column (Temporarily unavailable). To download the documents, select one or more checkboxes in the first column and then click the "Download Selected in PDF format (Zip Archive)" or the "Download Selected as Single PDF" button.

List of published and non-published patent-specific documents on the CPD .

If you have any difficulty accessing content, you can call the Client Service Centre at 1-866-997-1936 or send them an e-mail at CIPO Client Service Centre.

({010=All Documents, 020=As Filed, 030=As Open to Public Inspection, 040=At Issuance, 050=Examination, 060=Incoming Correspondence, 070=Miscellaneous, 080=Outgoing Correspondence, 090=Payment})


Document
Description 
Date
(yyyy-mm-dd) 
Number of pages   Size of Image (KB) 
Representative drawing 2002-06-27 1 8
Description 2001-01-24 211 6,275
Claims 2001-01-24 4 101
Drawings 2001-01-24 17 484
Abstract 2002-04-11 1 19
Drawings 2002-01-24 17 487
Filing Certificate (English) 2001-02-25 1 162
Request for evidence or missing transfer 2002-01-27 1 108
Courtesy - Certificate of registration (related document(s)) 2002-06-16 1 114
Courtesy - Certificate of registration (related document(s)) 2002-06-16 1 114
Courtesy - Certificate of registration (related document(s)) 2002-06-16 1 114
Reminder of maintenance fee due 2002-09-25 1 109
Courtesy - Abandonment Letter (Maintenance Fee) 2003-02-23 1 178
Correspondence 2001-02-25 1 18
Correspondence 2002-04-11 5 129