Desc: How to make a new module to support another UPS
File: new-modules.txt
Date: 10 July 1999

The basic premise used to pass data between a module and the upsd is a 
state file that usually lives in /var/state/ups.  The module should update
that file whenever the status of the UPS changes, and probably even if it
doesn't.  The file mtime should always be relatively recent - within 5
minutes or so - or a "staleness" check in upsd will flag it unusable.

Updates to the state file should be completed in one operation.  This is
done to ensure that the data collected doesn't represent part of the
previous poll and part of the current poll.  This is relatively easy to do
- just use write() to store the entire array in one call.

The data itself lives in an array of type "itype" as defined in shared.h.
This array has no set upper limit, but should be have as many elements as
there are variables to store.  The first member of this array MUST be type
INFO_MEMBERS and the value MUST be equal to the number of members
including that first one.  In other words, if you use positions 0 through
3, store 4 in there.

This "count as first member" is done so that upsd knows how much memory
to set aside for your array.  If you put too much, upsd will malloc a ton
and waste memory.  If you put in too little, it will miss some of your
variables.  So, get it right.

All of the other types are optional.  Don't include them unless the UPS
you are monitoring actually supports that value in some way.  Some things
can't be determined by the UPS itself but should still be reported if you
can.  For example, the APC Back-UPS driver has no idea that it's really
talking to one of those, but it hardcodes it anyway.  This has the effect
of allowing it to look nice in multimon and other programs.

So, if you have a reasonable idea of what is out there, hardcoding the
value is probably better than not including it at all, especially for
something fairly important like the model string.

The general logic for your module should be as follows:

 1. Setup the array
 2. Fill it with data from the UPS in the proper format
 3. Write it to the disk
 4. Goto 2

It's that easy.

Formatting
----------

The data contained in the value for each member of the array must conform
to the standard or it will be impossible for client programs to parse.  
All values are stored in string form and should be null terminated.

Occasionally there are numeric values shown as nnn.n.  These can actually
be less (nn.n or even n.n).  The format shown is the usual one that will
occur.

 Name         | Format details 
--------------+--------------------------------------------------------------
INFO_MEMBERS  | Defines how many members of the array exist including the
              | one containing INFO_MEMBERS.  Must be stored in position 0.
              | Must exist unless using shared memory mode - see INFO_SHMID.
--------------+--------------------------------------------------------------
INFO_SHMID    | Defines the shared memory ID where the information is
              | really found when using shared memory mode.  Must be
              | stored in position 0 with no other members.  The array
              | must start with either INFO_MEMBERS or INFO_SHMID.
--------------+--------------------------------------------------------------
INFO_MFR      | Manufacturer's name.  Example: APC
--------------+--------------------------------------------------------------
INFO_MODEL    | UPS model name.  Example: SMART-UPS 700
--------------+--------------------------------------------------------------
INFO_UTILITY  | Voltage that UPS is receiving - nnn[.n] format  Ex: 116.7
--------------+--------------------------------------------------------------
INFO_BATTPCT  | UPS battery charge in percent - nnn[.n] format  Ex: 056.5
--------------+--------------------------------------------------------------
INFO_STATUS   | Current internal UPS power status - contains abbreviations
              | separated by spaces when necessary
              |
              | OFF   - UPS is off (not supplying power)
              | OL    - UPS is online (supplying power from the line/mains)
              | OB    - UPS is on battery
              | LB    - UPS battery is low (with OB = shutdown situation)
              | CAL   - UPS is performing calibration
              | TRIM  - UPS is trimming incoming voltage (APC "SmartTrim")
              | BOOST - UPS is boosting incoming voltage (APC "SmartBoost")
              | OVER  - UPS is overloaded
              | RB    - UPS battery needs to be replaced
              |
              | Things like "OL" and "OB" should not ever occur together.
              | Likewise, "OFF" and "OL" or "OB" are also mutually exclusive.
              |
              | Example for on battery + low battery: OB LB
--------------+--------------------------------------------------------------
INFO_UPSTEMP  | UPS internal temperature in degrees C - nnn[.n] format
              | Example: 037.0
--------------+--------------------------------------------------------------
INFO_ACFREQ   | Incoming frequency in Hz - nn[.nn] format   Example: 60.00
--------------+--------------------------------------------------------------
INFO_LOADPCT  | Load on UPS in percent - nnn[.n] format     Example: 023.4
--------------+--------------------------------------------------------------
INFO_LOWXFER  | UPS transfers to battery when incoming voltage drops below
              | this value - nnn[.n] format                 Example: 103
--------------+--------------------------------------------------------------
INFO_HIGHXFER | UPS transfers to battery when incoming voltage rises above
              | this value - nnn[.n] format                 Example: 132
--------------+--------------------------------------------------------------
INFO_AMBTEMP  | Current temperature outside the UPS.  Not to be confused
              | with INFO_UPSTEMP which is the _internal_ UPS temperature.
              | Degrees C - nnn[.n] format                  Example: 050.8
--------------+--------------------------------------------------------------
INFO_AMBHUMID | Current humidity outside the UPS.  Percentage.
              | nn.nn format                                Example: 25.40
--------------+--------------------------------------------------------------

New variable support
--------------------

To add support for a new variable, the following changes must happen:

1. Edit shared.h to give it an INFO_* identifier for the itype array

2. Edit upsd.h to match the INFO_* identifier to a text name

For sanity's sake, all variables have INFO_ as a prefix as their itype
array identifier.  A variable called FOO would be type INFO_FOO in the
array.

To keep things together, new variables should be submitted for inclusion
into the main source tree.

Shared memory support
---------------------

For speed and efficiency, this array will be stored in a shared memory
segment and upsd will attach to it for reading whenever possible.  upsd
monitors the number of attaches and the ctime info on the structure to
make sure it's staying fresh.  If it goes stale, upsd drops it and starts
rereading the state file for updates - either a new SHM id or the data
itself.

In shared memory mode, the state file should contain *ONE* element of type
INFO_SHMID.  The value for this element should be the shared memory ID.
upsd will detect this and switch into shared memory mode if possible.
If you manage to compile it without shared memory support and somehow give
it a shared memory state file, it will complain.

This is all handled for you by the routines in upscommon - create_info and
writeinfo take care of the details.  Making a driver use this shared
memory code is just a matter of calling those functions instead of local
ones that do similar things.
