Creating a new driver to support another device
===============================================

//////////////////////////////////////////////////////////////////////////////
// You can find a rendered variant of this document on the web at
// https://networkupstools.org/docs/developer-guide.chunked/new-drivers.html
//////////////////////////////////////////////////////////////////////////////

This chapter will present the process of creating a new driver to support
another device.

Since NUT already supports many major power device protocols through
several generic drivers (`genericups`, `usbhid-ups`, `snmp-ups`, `blazer_*`
and `nutdrv_qx`), creation of new drivers has become rare.

NOTE: We have yet to unify modbus drivers under same umbrella like `nutdrv_qx`
covering the Megatec Qx protocol family.

So most of the time, this process will be limited to completing one of these
generic drivers.

Smart vs. Contact-closure
-------------------------

If your UPS only does contact closure readings over an RS-232 serial port, then
go straight to the <<contact-closure, Contact closure hardware>> chapter for
information on adding support.  It's a lot easier to add a few lines to a
header file than it is to create a whole new driver.

Serial vs. USB vs. SNMP and more
--------------------------------

If your UPS connects to your computer via a USB port, then it most likely
appears as a USB HID device (this is the simplest way for the vendor to write
a Windows control program for it). What comes next depends on whether the
vendor implemented the HID PDC (Power Device Class) specification, or simply
used the HID protocol to transport serial data to the UPS microcontroller.

A rough heuristic is to check the length of the HID Descriptor length
(`wDescriptorLength` in `lsusb -v` output). If it is less than 200 bytes long,
the UPS probably has a glorified USB-to-serial converter built in. Since the
query strings often start with the letter `Q`, this family of protocols is
often referred to as `Q*` in the NUT documentation. See the
<<nutdrv_qx-subdrivers,Q* UPS>> chapter for more details.

Otherwise, if the HID Descriptor is longer, you can go to the
<<hid-subdrivers, HID subdrivers>> chapter. You can probably add support for
your device by writing a new subdriver to the existing usbhid-ups driver,
which is easier (and more maintainable) than writing an entire new driver.

If your USB UPS does not appear to fall into either of these two categories,
feel free to contact the `nut-upsdev` mailing list with details of your
device.

Similarly, if your UPS connects to your computer via an SNMP network
card, you can probably add support for your device by adding a new
subdriver to the existing snmp-ups driver. Instructions are provided
in the <<snmp-subdrivers, SNMP subdrivers>> chapter.

Overall concept
---------------

The basic design of drivers is simple.  `main.c` handles most of the work
for you.  You don't have to worry about arguments, config files, or
anything else like that.  Your only concern is talking to the hardware
and providing data to the outside world.

Skeleton driver
---------------

Familiarize yourself with the design of `skel.c` in the drivers directory.
It shows a few examples of the functions that `main.c` will call to obtain
updated information from the hardware.

Essential structure
-------------------

upsdrv_info_t
~~~~~~~~~~~~~

This structure tracks several description information about the driver:

 * *name*:    the driver full name, for banner printing and "driver.name" variable.
 * *version*: the driver's own version. For sub driver information, refer below
              to sub_upsdrv_info. This value has the form "X.YZ", and is
              published by main as "driver.version.internal".
 * *authors*: the driver's author(s) name. If multiple authors are listed,
              separate them with a newline character so that it can be broken
              up by author if needed.
 * *status*:  the driver development status. The following values are allowed:
              - DRV_BROKEN: setting this value will cause main to print an error
              and exit. This is only used during conversions of the driver core
              to keep users from using drivers which have not been converted.
              Drivers in this state will be removed from the tree after some
              period if they are not fixed.
              - DRV_EXPERIMENTAL: set this value if your driver is potentially
              broken. This will trigger a warning when it starts so the user
              doesn't take it for granted.
              - DRV_BETA: this value means that the driver is more stable and
              complete. But it is still not recommended for production systems.
              - DRV_STABLE: the driver is suitable for production systems, but
              not 100 % feature complete.
              - DRV_COMPLETE: this is the gold level! It implies that 100 % of
              the protocol is implemented, and a full QA pass.
 * *subdrv_info*: array of upsdrv_info_t for sub driver(s) information. For
              example, this is used by usbhid-ups.

This information is currently used for the startup banner printing and tests.

Essential functions
-------------------

For a full current list of functions expected in this context, please see the
`drivers/main.h` file in NUT sources.  Some more methods may be required by
driver structure, even if in the common case they have no-op implementations.

upsdrv_initups
~~~~~~~~~~~~~~

Open the port (`device_path`) and do any low-level things that it may need
to start using that port.  If you have to set DTR or RTS on a serial
port, do it here.

Don't do any sort of hardware detection here, since you may be going
into upsdrv_shutdown next.

upsdrv_initinfo
~~~~~~~~~~~~~~~

Try to detect what kind of UPS is out there, if any, assuming that's
possible for your hardware.  If there is a way to detect that hardware
and it doesn't appear to be connected, display an error and exit. This
is the last time your driver is allowed to bail out.

This is usually a good place to create variables like `ups.mfr`,
`ups.model`, `ups.serial`, determine and declare supported instant
commands (maybe model-dependent, typically for all devices supported
by the driver), and other "one time only" items.

upsdrv_updateinfo
~~~~~~~~~~~~~~~~~

Poll the hardware, and update any variables that you care about
monitoring.  Use `dstate_setinfo()` to store the new values.

Do at most one pass of the variables.  You MUST return from this
function or upsd will be unable to read data from your driver.  main
will call this function at regular intervals.

Don't spent more than a couple of seconds in this function. Typically
five (5) seconds is the maximum time allowed before you risk that the
server declares the driver stale. If your UPS hardware requires a
timeout period of several seconds before it answers, consider returning
from this function after sending a command immediately and read the
answer the next time it is called.

You must never abort from upsdrv_updateinfo(), even when the UPS doesn't
seem to be attached anymore. If the connection with the UPS is lost, the
driver should retry to re-establish communication for as long as it is
running. Calling `exit()` or any of the `fatal*()` functions is specifically
not allowed anymore.

upsdrv_shutdown
~~~~~~~~~~~~~~~

Do whatever you can to make the UPS power off the load but also return
after the power comes back on.  You may use a different command that
keeps the UPS off if the user has requested that with a configuration
setting.

You should attempt the UPS shutdown command even if the UPS detection
fails.  If the UPS does not shut down the load, then the user is
vulnerable to a race if the power comes back on during the shutdown
process.

This method should not directly `exit()` the driver program (neither
should it call `fatalx()` nor `fatal_with_errno()` methods).  It can
`upslogx(LOG_ERR, ...)` or `upslog_with_errno(LOG_ERR, ...)`, and then
`set_exit_flag(N)` if required, using values `EF_EXIT_FAILURE` (`-1`)
for eventual `exit(EXIT_FAILURE)` and `EF_EXIT_SUCCESS` (`-2`) for
`exit(EXIT_SUCCESS)`, which would be handled in the standard driver
loop or in `forceshutdown()` method of `main.c`.

addvar, getval and testvar
~~~~~~~~~~~~~~~~~~~~~~~~~~

NUT drivers can be configured at run-time with optional settings, which
can be passed on command line or via the linkman:ups.conf[5] file.
Such settings broadly fall into two categories: "values" which convey
some specific value (e.g. `port` or `desc` strings), and "flags" which
can be seen as a sort of booleans which are `true` if mentioned and
`false` if not (any assigned value would be ignored, if not rejected
by configuration parser).

Some options are common to all drivers and are handled in `drivers/main.c`
(which also defines and implements most of the methods in this area), while
others may be specific to individual drivers or even their sub-drivers.

The `addvar()` method allows to specify a certain option name, with its
type and a help message string:

	addvar(VAR_VALUE, "sdtype", "Specify simple shutdown method (0-6)");

	addvar(VAR_FLAG,  "wait",   "Wait for AC power");

In driver code, these calls should comprise the `upsdrv_makevartable()`
method.

The `getval()` method allows to get the user-provided string value (or
`NULL` -- but it is hard to tell apart if the option was not specified
or no value was assigned).  The `testvar()` method allows to check if
the option name was specified (even if without a value), so is better
suited for flags.  Internally there is no difference between "values"
and "flags", so historically some flags were "promoted" to values with
boolean-ish strings handled explicitly, in addition to some new features.

NOTE: Internally, the values can also be marked as reloadable (so that a
running driver program may change them when re-reading the configuration
file due to a signal).  The implementation may be currently limited to
common options handled by `main.c` itself.  In code base this is exposed
with the `addvar_reloadable()` and several `test*_reloadable()` methods.

Since these methods involve a data structure walk to locate (or not) the
entry for each option, they should not be used in data processing loops.
Instead, the driver initialization methods such as `upsdrv_initups()`
should consider all values and flags that can impact the set-up of the
driver, and save them into C variables (typically strings, booleans, or
processed and range/value-checked number types) which are then directly
used in the driver program code.

nut_usb_addvars
~~~~~~~~~~~~~~~

For consistency between USB-capable NUT drivers, a set of `addvar()`
options related to USB media setup and expected by `nut_libusb_open()`
can be defined by calling the `nut_usb_addvars()` method, which can be
seen in `drivers/libusb{0,1}.c`.

Like `addvar()`, a call to this method belongs in `upsdrv_makevartable()`
(see existing drivers for examples).


nut_ser_addvars
~~~~~~~~~~~~~~~

WARNING: NOT CURRENTLY IMPLEMENTED.

Issue https://github.com/networkupstools/nut/issues/2748 tracks the idea
to standardize the set and names of options involved in the serial driver
connection set-up (speed, parity, stop-bits, etc.) similarly to the
precedent of `nut_usb_addvars()`.  One problem is that many drivers
released during the past decades reinvented this wheel with different
option names.

nut_modbus_addvars
~~~~~~~~~~~~~~~~~~

WARNING: NOT CURRENTLY IMPLEMENTED.

Issue https://github.com/networkupstools/nut/issues/2419 tracks a similar
idea for Modbus-capable drivers (which may involve or not Serial and/or
USB link and option support, and uniquely TCP/IP RTU support, for example).


Data types
----------

To be of any use, you must supply data in `ups.status`.  That is the
minimum needed to let upsmon do its job.  Whenever possible, you should
also provide anything else that can be monitored by the driver.  Some
obvious things are the manufacturer name and model name, voltage data,
and so on.

If you can't figure out some value automatically, use the `ups.conf`
options to let the user tell you.  This can be useful when a driver
needs to support many similar hardware models, but can't probe to see
what is actually attached.

Manipulating the data
---------------------

All status data lives in structures that are managed by the dstate
functions.  All access and modifications must happen through those
functions.  Any other changes are forbidden, as they will not pushed out
as updates to things like upsd.

Adding variables
~~~~~~~~~~~~~~~~

	dstate_setinfo("ups.model", "Mega-Zapper 1500");

Many of these functions take format strings, so you can build the new
values right there:

	dstate_setinfo("ups.model", "Mega-Zapper %d", rating);

In a few cases you can use a formatting string coming from a mapping
table or constructed during run-time.  This is generally not safe (due
to references into the stack when handling the variable argument list),
and modern compilers warn against doing so.  While it is possible to
quiesce the warnings with pragmas, it is better to play safe with the
"dynamic" versions of methods provided by NUT -- they allow to combine
both compile-time checks of expected formatting string vs. types of data
in the method arguments, and run-time equivalence of the actual dynamic
formatting string to those expectations.  In this case, you would use
`dstate_setinfo_dynamic()` with a coding pattern similar to the following:

	char *fmt = "Mega-Zapper %d";
	dstate_setinfo_dynamic("ups.model", fmt, "%d", rating);

Please note that `ups.alarm` should no longer be manually set, but rather
the appropriate alarm functions should be used instead. For more details,
see below in the `UPS alarms` section.

Setting flags
~~~~~~~~~~~~~

Some variables have special properties.  They can be writable, and some
are strings.  The `ST_FLAG_*` values can be used to tell upsd more about
what it can do.

	dstate_setflags("input.transfer.high", ST_FLAG_RW);

Status data
~~~~~~~~~~~

UPS status flags like on line (OL) and on battery (OB) live in
ups.status.  Don't manipulate this by hand.  There are functions which
will do this for you.

	status_init()   -- before doing anything else (clear internal buffers,
	                   etc.)

	status_get(val) -- optionally check if a status word had been set
	                   since the most-recent status_init()

	status_set(val) -- add a status word (OB, OL, etc)

	status_commit() -- push out the update

Possible values for status_set:

	OL      -- On line (mains is present)
	OB      -- On battery (mains is not present)
	LB      -- Low battery
	HB      -- High battery
	RB      -- The battery needs to be replaced
	CHRG    -- The battery is charging
	DISCHRG -- The battery is discharging (inverter is providing load power)
	BYPASS  -- UPS bypass circuit is active -- no battery protection is available
	CAL     -- UPS is currently performing runtime calibration (on battery)
	OFF     -- UPS is offline and is not supplying power to the load
	OVER    -- UPS is overloaded
	TRIM    -- UPS is trimming incoming voltage (called "buck" in some hardware)
	BOOST   -- UPS is boosting incoming voltage
	FSD     -- Forced Shutdown (restricted use, see the note below)

`ALARM` should no longer be raised through the UPS status.
An `ALARM` value will be added internally (typically as first in the list)
if an alarm was set and committed through the appropriate alarm functions.
For more details, see below in the `UPS alarms` section.

[NOTE]
======
The NUT data server `upsd` initially sets `ups.status` to a value of `WAIT`
when first connecting to a NUT driver using the socket protocol, and issues
a `DUMPALL` command.  This temporary `WAIT` status gets overwritten whenever
any relevant information update from a driver arrives, typically either as
part of its own initialization, or of the regular polling loop.

This may seem roughly similar to a "Data stale" situation; however, the NUT
clients like `upsmon` should not infer anything for shutdown decisions from
this lack of initial connection, like they do for *loss* of connection during
a known critical power situation.

For some more detailed insight into the NUT driver's current state machine
position (as reported by the driver after communications are established),
see also `driver.state`.
======

Anything else will not be recognized by the usual clients expecting a
particular NUT standard release.  New tokens may appear over time, but
driver developers should coordinate with the nut-upsdev list before creating
something new, since there will be duplication and ugliness otherwise.
It is possible that eventually, due to hardware and software design evolution,
some concepts would be superseded by others.  Fundamental meanings of the
flags listed above should not change (but these flags may become no longer
issued by the current NUT drivers; then may still be used e.g. in forks or
older packaged builds).

Clients however MUST accept any space-separated tokens in `ups.status`
without error or crash, and MUST treat those defined above with the
ascribed meanings, but MAY ignore unidentified tokens (quietly by default,
or acknowledge the skip with a debug log message).

[NOTE]
==============================================================================

- upsd injects `FSD` by itself following that command by a primary upsmon
process.  Drivers must not set that value, apart from specific cases (see
below).

- As an exception, drivers may set `FSD` when an imminent shutdown has been
detected. In this case, the "on battery + low battery" condition should not be
met. Otherwise, setting status to `OB LB` should be preferred.

- the `OL` and `OB` flags are an indication of the input line status only.

- the `CHRG` and `DISCHRG` flags are being replaced with
`battery.charger.status`.  See the linkdoc:user-manual[NUT command and
variable naming scheme,nut-names] for more information.
==============================================================================

Similar functionality can be supported for `experimental.ups.mode.buzzwords`,
where it is tracked dynamically (e.g. due to ECO/ESS/HE/Smart or similar
marketing buzzword modes supported by the device), using the following
methods in the processing loop:

	buzzmode_init()   -- before doing anything else (clear internal buffers,
	                     etc.)

	buzzmode_get(val) -- optionally check if an UPS mode buzzword had been
	                     set since the most-recent buzzmode_init()

	buzzmode_set(val) -- add an UPS mode buzzword (vendor:eaton:ECO, etc.)

	buzzmode_commit() -- push out the update

UPS alarms
----------

These work like `ups.status`, and have three special functions which you
must use to manage them.

	alarm_init() -- before doing anything else

	alarm_set() -- add an alarm word

	alarm_commit() -- push the value into ups.alarm

NOTE: The ALARM flag in `ups.status` is automatically set whenever you use
`alarm_set()`.  To remove that flag from `ups.status`, call `alarm_init()`
and `alarm_commit()` without calling `alarm_set()` in the middle.

You should never try to set or unset the ALARM flag manually.

If you use UPS alarms, the call to `status_commit()` should be *after*
`alarm_commit()`, otherwise there will be a delay in setting the ALARM
flag in `ups.status`.

There is no official list of alarm keywords as of this writing, so don't
use these functions until you check with the upsdev list.

Also refer to the <<daisychain,NUT daisychain support notes>> chapter
of the user manual and developer guide for information related to alarms
handling in daisychain mode.

Staleness control
-----------------

If you're not talking to a polled UPS, then you must ensure that it
is still out there and is alive before calling dstate_dataok().  Even
if nothing is changing, you should still "ping" it or do something
else to ensure that it is really available.  If the attempts to
contact the UPS fail, you must call dstate_datastale() to inform the
server and clients.

- dstate_dataok()
+
You must call this if polls are succeeding.  A good place to call this
is the bottom of upsdrv_updateinfo().

- dstate_datastale()
+
You must call this if your status is unusable.  A good technique is
to call this before exiting prematurely from upsdrv_updateinfo().

Don't hide calls to these functions deep inside helper functions.  It is
very hard to find the origin of staleness warnings, if you call these from
various places in your code.  Basically, don't call them from any other
function than from within upsdrv_updateinfo().  There is no need to call
either of these regularly as was stated in previous versions of this
document (that requirement has long gone).

Serial port handling
--------------------

Drivers which use serial port functions should include serial.h and use
these functions (and cross-platform data types) whenever possible:

	- TYPE_FD
+
Cross-platform data type to represent a serial-port connection.

	- ERROR_FD_SER
+
Macro value representing an invalid serial-port connection.

	- VALID_FD_SER(TYPE_FD_SER fd)
+
This macro evaluates to `true` if `fd` currently has a "valid" value
(e.g. represents a connected device). You should invalidate the `fd`
when you initialize the variable or close the connection, by assigning
`fd = ERROR_FD`.

	- INVALID_FD_SER(TYPE_FD_SER fd)
+
This macro evaluates to `true` if `fd` does not currently have a
"valid" value.

	- TYPE_FD_SER ser_open(const char *port)
+
This opens the port and locks it if possible, using one of fcntl, lockf,
or uu_lock depending on what may be available.  If something fails, it
calls fatal for you.  If it succeeds, it always returns the fd that was
opened.

	- TYPE_FD_SER ser_open_nf(const char *port)
+
This is a non-fatal version of ser_open(), that does not call fatal if
something fails.

	- int ser_set_speed(TYPE_FD_SER fd, const char *port, speed_t speed)
+
This sets the speed of the port and also does some basic configuring
with tcgetattr and tcsetattr.  If you have a special serial
configuration (other than 8N1), then this may not be what you want.
+
The port name is provided again here so failures in tcgetattr() provide
a useful error message.  This is the only place that will generate a
message if someone passes a non-serial port /dev entry to your driver,
so it needs the extra detail.

	- int ser_set_speed_nf(TYPE_FD_SER fd, const char *port, speed_t speed)
+
This is a non-fatal version of ser_set_speed(), that does not call fatal
if something fails.

	- int ser_set_dtr(TYPE_FD_SER fd, int state)
	- int ser_set_rts(TYPE_FD_SER fd, int state)
+
These functions can be used to set the modem control lines to provide
cable power on the RS232 interface. Use state = 0 to set the line to 0
and any other value to set it to 1.

	- int ser_get_dsr(TYPE_FD_SER fd)
	- int ser_get_cts(TYPE_FD_SER fd)
	- int ser_get_dcd(TYPE_FD_SER fd)
+
These functions read the state of the modem control lines. They will
return 0 if the line is logic 0 and a non-zero value if the line is
logic 1.

	- int ser_close(TYPE_FD_SER fd, const char *port)
+
This function unlocks the port if possible and closes the fd.  You
should call this in your upsdrv_cleanup handler.

	- ssize_t ser_send_char(TYPE_FD_SER fd, unsigned char ch)
+
This attempts to write one character and returns the return value from
write.  You could call write directly, but using this function allows
for future error handling in one place.

	- ssize_t ser_send_pace(TYPE_FD_SER fd, useconds_t d_usec,
	                        const char *fmt, ...)
+
If you need to send a formatted buffer with an intercharacter delay, use
this function.  There are a number of UPS controllers which can't take
commands at the full speed that would normally be possible at a given
bit rate.  Adding a small delay usually turns a flaky UPS into a solid
one.
+
The return value is the number of characters that was sent to the port,
or '-1' if something failed.

	- ssize_t ser_send(TYPE_FD_SER fd, const char *fmt, ...)
+
Like ser_send_pace, but without a delay.  Only use this if you're sure
that your UPS can handle characters at the full line rate.

	- ssize_t ser_send_buf(TYPE_FD_SER fd, const void *buf, size_t buflen)
+
This sends a raw buffer to the fd.  It is typically used for binary
transmissions.  It returns the results of the call to write.

	- ssize_t ser_send_buf_pace(TYPE_FD_SER fd, useconds_t d_usec,
	                            const void *buf, size_t buflen)
+
This is just ser_send_buf with an intercharacter delay.

	- ssize_t ser_get_char(TYPE_FD_SER fd, void *ch, time_t d_sec, useconds_t d_usec)
+
This will wait up to d_sec seconds + d_usec microseconds for one
character to arrive, storing it at ch.  It returns 1 on success, -1
if something fails and 0 on a timeout.
+
NOTE: The delay value must not be too large, or your driver will not get
back to the usual idle loop in main in time to answer the PINGs from
upsd.  That will cause an oscillation between staleness and normal
behavior.

	- ssize_t ser_get_buf(TYPE_FD_SER fd, void *buf, size_t buflen,
	                      time_t d_sec, useconds_t d_usec)
+
Like ser_get_char, but this one reads up to buflen bytes storing all of
them in buf.  The buffer is zeroed regardless of success or failure.  It
returns the number of bytes read, -1 on failure and 0 on a timeout.
+
This is essentially a single read() function with a timeout.

	- ssize_t ser_get_buf_len(TYPE_FD_SER fd, void *buf, size_t buflen,
	                          time_t d_sec, useconds_t d_usec)
+
Like ser_get_buf, but this one waits for buflen bytes to arrive,
storing all of them in buf.  The buffer is zeroed regardless of success
or failure.  It returns the number of bytes read, -1 on failure
and 0 on a timeout.
+
This should only be used for binary reads.  See ser_get_line for
protocols that are terminated by characters like CR or LF.

	- ssize_t ser_get_line(TYPE_FD_SER fd, void *buf, size_t buflen,
	                       char endchar, const char *ignset,
	                       time_t d_sec, useconds_t d_usec)
+
This is the reading function you should use if your UPS tends to send
responses like "OK\r" or "1234\n".  It reads up to buflen bytes and
stores them in buf, but it will return immediately if it encounters
endchar.  The endchar will not be stored in the buffer.  It will also
return if it manages to collect a full buffer before reaching the
endchar.  It returns the number of bytes stored in the buffer, -1 on
failure and 0 on a timeout.
+
If the character matches the ignset with strchr(), it will not be added
to the buffer.  If you don't need to ignore any characters, just pass it
an empty string -- `""`.
+
The buffer is always cleared and is always `null`-terminated.  It does
this by reading at most `(buflen - 1)` bytes.
+
NOTE: Any other data which is read after the endchar in the serial
buffer will be lost forever.  As a result, you should not use this
unless your UPS uses a polled protocol.
+
Let's say your endchar is `\n` and your UPS sends `"OK\n1234\nabcd\n"`.
This function will `read()` all of that, find the first `\n`, and stop
there.  Your driver will get `"OK"`, and the rest is gone forever.
+
This also means that you should not "pipeline" commands to the UPS.
Send a query, then read the response, then send the next query.

	- ssize_t ser_get_line_alert(TYPE_FD_SER fd, void *buf, size_t buflen,
	                             char endchar, const char *ignset,
	                             const char *alertset,
	                             void handler(char ch),
	                             time_t d_sec, useconds_t d_usec)
+
This is just like ser_get_line, but it allows you to specify a set of
alert characters which may be received at any time.  They are not added
to the buffer, and this function will call your handler function,
passing the character as an argument.
+
Implementation note: this function actually does all of the work, and
ser_get_line is just a wrapper that sets an empty alertset and a NULL
handler.

	- ssize_t ser_flush_in(TYPE_FD_SER fd, const char *ignset, int verbose)
+
This function will drain the input buffer.  If verbose is set to a
positive number, then it will announce the characters which have been
read in the syslog.  You should not set verbose unless debugging is
enabled, since it could be very noisy.
+
This function returns the number of characters which were read, so you
can check for extra bytes by looking for a nonzero return value.  Zero
will also be returned if the read fails for some reason.

	- int ser_flush_io(TYPE_FD_SER fd)
+
This function drains both the in- and output buffers. Return zero on
success.

	- void ser_comm_fail(const char *fmt, ...)
+
Call this whenever your serial communications fail for some reason.  It
takes a format string, so you can use variables and other things to
clarify the error.  This function does built-in rate-limiting so you
can't spam the syslog.
+
By default, it will write 10 messages, then it will stop and only write
1 in 100.  This allows the driver to keep calling this function while
the problem persists without filling the logs too quickly.
+
In the old days, drivers would report a failure once, and then would be
silent until things were fixed again.  Users had to figure out what was
happening by finding that single error message, or by looking at the
repeated complaints from upsd or the clients.
+
If your UPS frequently fails to acknowledge polls and this is a known
situation, you should make a couple of attempts before calling this
function.
+
NOTE: This does not call dstate_datastale.  You still need to do that.

	- void ser_comm_good(void)
+
This will clear the error counter and write a "re-established" message
to the syslog after communications have been lost.  Your driver should
call this whenever it has successfully contacted the UPS.  A good place
for most drivers is where it calls dstate_dataok.

USB port handling
-----------------

Drivers which use USB functions should include usb-common.h and use these:

Structure and macro
~~~~~~~~~~~~~~~~~~~

You should use the usb_device_id_t structure, and the USB_DEVICE macro to
declare the supported devices. This allows the automatic extraction of
USB information, to generate the Hotplug, udev and UPower support files.

The structure allows to convey `uint16_t` values of VendorID and ProductID,
and an optional matching-function callback to interrogate the device in
more detail (constrain known supported firmware versions, OEM brands, etc.)

For example:

--------------------------------------------------------------------------------
/* SomeVendor name */
#define SOMEVENDOR_VENDORID		0xXXXX

/* USB IDs device table */
static usb_device_id_t sv_usb_device_table [] = {
	/* some models 1 */
	{ USB_DEVICE(SOMEVENDOR_VENDORID, 0xYYYY), NULL },

	/* various models */
	{ USB_DEVICE(SOMEVENDOR_VENDORID, 0xZZZZ), NULL },
	{ USB_DEVICE(SOMEVENDOR_VENDORID, 0xAAAA), NULL },

	/* Terminating entry */
	{ 0, 0, NULL }
};
--------------------------------------------------------------------------------

Function
~~~~~~~~

	- is_usb_device_supported(usb_device_id_t *usb_device_id_list,
	                          USBDevice_t *device)
+
Call this in your device opening / matching function. Pass your usb_device_id_t
list structure, and a set of VendorID, DeviceID, as well as Vendor, Product and
Serial strings, possibly also Bus, bcdDevice (device release number) and Device
name on the bus strings, in the USBDevice_t fields describing the specific piece
of hardware you are inspecting.
+
This function returns one of the following value:
+
--
		* NOT_SUPPORTED (0),
		* POSSIBLY_SUPPORTED (1, returned when the VendorID is matched,
		  but the DeviceID is unknown),
		* or SUPPORTED (2).
--
+
For implementation examples, refer to the various USB drivers, and search for
the above patterns.

NOTE: This set of USB helpers is due to expand is the near future...

Variable names
--------------

PLEASE don't make up new variables and commands just because you can.
The new dstate functions give us the power to create just about
anything, but that is a privilege and not a right.  Imagine the mess
that would happen if every developer decided on their own way to
represent a common status element.

Check the <<nut-names,NUT command and variable naming scheme>> section first to
find the closest fit. If nothing matches, contact the upsdev list, and we'll
figure it out.

Patches which introduce unlisted names may be modified or dropped.

[[commands]]
Message passing support
-----------------------

upsd can call drivers to store values in read/write variables and to kick
off instant commands.  This is how you register handlers for those events.

The driver core (drivers/main.c) has a structure called upsh.  You
should populate it with function pointers in your upsdrv_initinfo()
function.  Right now, there are only two possibilities:

- setvar  = setting UPS variables (SET VAR protocol command)
- instcmd = instant UPS commands (INSTCMD protocol command)

SET
~~~

If your driver's function for handling variable set events is called
my_ups_set(), then you'd do this to add the pointer:

	upsh.setvar = my_ups_set;

my_ups_set() will receive two parameters:

	const char * -- the variable being changed
	const char * -- the new value

You should return either STAT_SET_HANDLED if your driver recognizes the
command, or STAT_SET_UNKNOWN if it doesn't.  Other possibilities will be
added at some point in the future.

INSTCMD
~~~~~~~

This works just like the set process, with slightly different values
arriving from the server.

	upsh.instcmd = my_ups_cmd;

Your function will receive two args:

	const char * -- the command name
	const char * -- (reserved)

You should return either STAT_INSTCMD_HANDLED or STAT_INSTCMD_UNKNOWN
depending on whether your driver can handle the requested command.

Notes
~~~~~

Use strcasecmp.  The command names arriving from upsd should be treated
without regards to case.

Responses
~~~~~~~~~

Drivers will eventually be expected to send responses to commands.
Right now, there is no channel to get these back through upsd to
the client, so this is not implemented.

This will probably be implemented with a polling scheme in the clients.


Enumerated types
----------------

If you have a variable that can have several specific values, it is
enumerated.  You should add each one to make it available to the client:

	dstate_addenum("input.transfer.low", "92");
	dstate_addenum("input.transfer.low", "95");
	dstate_addenum("input.transfer.low", "99");
	dstate_addenum("input.transfer.low", "105");

Range values
------------

If you have a variable that support values comprised in one or more ranges,
you should add each one to make it available to the client:

	dstate_addrange("input.transfer.low", 90, 95);
	dstate_addrange("input.transfer.low", 100, 105);

Writable strings
----------------

Strings that may be changed by the client should have the ST_FLAG_STRING
flag set, and a maximum length (in bytes) set in the auxdata.

	dstate_setinfo("ups.id", "Big UPS");
	dstate_setflags("ups.id", ST_FLAG_STRING | ST_FLAG_RW);
	dstate_setaux("ups.id", 8);

If the variable is not writable, don't bother with the flags or the
auxiliary data.  It won't be used.

Instant commands
----------------

If your hardware and driver can support a command, register it.

	dstate_addcmd("load.on");

Don't forget to define the implementation for such commands in a common
method, and register that your driver has an instant command handler at
all -- with a line in `upsdrv_initinfo()` like:

	upsh.instcmd = blazer_instcmd;

Delays and ser_* functions
--------------------------

The new ser_* functions may perform reads faster than the UPS is able to
respond in some cases.  This means that your driver will call select()
and read() numerous times if your UPS responds in bursts.  This also
depends on how fast your system is.

You should check your driver with `strace` or its equivalent on your
system.  If the driver is calling read() multiple times, consider adding
a call to usleep before going into the ser_read_* call.  That will give
it a chance to accumulate so you get the whole thing with one call to
read without looping back for more.

This is not a request to save CPU time, even though it may do that.  The
important part here is making the strace/ktrace output easier to read.

	write(4, "Q1\r", 3)                     = 3
	nanosleep({0, 300000000}, NULL)         = 0
	select(5, [4], NULL, NULL, {3, 0})      = 1 (in [4], left {3, 0})
	read(4, "(120.0 084.0 120.0   0 60.0 22.6"..., 64) = 47

Without that delay, that turns into a mess of selects and reads.
The select returns almost instantly, and read gets a tiny chunk of the
data.  Add the delay and you get a nice four-line status poll.

Canonical input mode processing
-------------------------------

If your UPS uses "\n" and/or "\r" as endchar, consider the use of
Canonical Input Mode Processing instead of the ser_get_line* functions.

Using a serial port in this mode means that select() will wait until
a full line is received (or times out). This relieves you from waiting
between sending a command and reading the reply. Another benefit is,
that you no longer have to worry about the case that your UPS sends
"OK\n1234\nabcd\n". This will be broken up cleanly in "OK\n", "1234\n"
and "abcd\n" on consecutive reads, without risk of losing data (which
is an often forgotten side effect of the ser_get_line* functions).

Currently, an example how this works can be found in the safenet and
upscode2 drivers. The first uses a single "\r" as endchar, while the
latter accepts either "\n", "\n\r" or "\r\n" as line termination. You
can define other termination characters as well, but can't undefine
"\r" and "\n" (so if you need these as data, this is not for you).

Adding the driver into the tree
-------------------------------

In order to build your new driver, it needs to be added to
`drivers/Makefile.am`. At the moment, there are several driver list variables
corresponding to the general protocol of the driver (`SERIAL_DRIVERLIST`,
`SNMP_DRIVERLIST`, etc.). If your driver does not fit into one of these
categories, please discuss it on the nut-upsdev mailing list.

There are also `*_SOURCES` and optional `*_LDADD` variables to list the source
files, and any additional linker flags. If your driver uses the C math
library, be sure to add `-lm`, since this flag is not always included by
default on embedded systems.

When you add a driver to one of these lists, pay attention to the backslash
continuation characters (`\\`) at the end of the lines.

The `automake` program converts the `Makefile.am` files into `Makefile.in`
files to be processed by `./configure`. See the discussion in <<building>>
about automating the rebuild process for these files.

[[contact-closure]]

include::contact-closure.txt[]


[[hid-subdrivers]]

include::hid-subdrivers.txt[]


[[snmp-subdrivers]]

include::snmp-subdrivers.txt[]


[[nutdrv_qx-subdrivers]]

include::nutdrv_qx-subdrivers.txt[]
