Logo Search packages:      
Sourcecode: nut version File versions

tripplitesu.c

/* tripplitesu.c - model specific routines for
                   Tripp Lite SmartOnline (SU*) models

   Copyright (C) 2003  Allan N. Hessenflow <allanh@kallisti.com>

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

/* Notes:

   The map for commands_available isn't clear.  All of the information
   I have on the Tripp Lite SmartOnline protocol comes from the files
   TUN.tlp and TUNRT.tlp from their drivers, and some experimentation.
   One of those files told me what one bit was for in the AVL response,
   out of 18 that the SU1000RT2U sends or 21 that some other model
   sends.  Later I found a description of the Belkin protocol, which is
   the same.  Unfortunately it gives a definition of the AVL response
   that conflicts with the one bit I found from TUNRT.tlp, and in fact
   the response my SU1000RT2U gives, compared to the commands I have
   found it supports, does not match the Belkin description.  So I'm
   treating the whole field as unknown.  It would be nice to be able to
   use it to determine what variables to make RW.  As a workaround, I'm
   assuming any value I query successfully which also can be set on at
   least one model, can in fact be set on the one I'm talking to.

   I didn't just add Tripp Lite support to the existing Belkin driver
   because I didn't discover that they were the same protocol until
   after I had put more features in this driver than the Belkin driver
   has.  I'm not calling this a unified Belkin/Tripp Lite driver for a
   couple of reasons.  One is that I don't have a Belkin to test with
   (and so I explicitly check for Tripp Lite in this drivers
   initialization - it *may* work fine with a Belkin by simply removing
   that test).  The other reason is that I'd have to come up with a
   name - I don't know a name for the protocol, and I don't know which
   company (if either) originated the protocol.  Picking one of the
   companies arbitrarily to name it after just seems wrong.

   There are a few things still to add.  Primarily there's control of
   individual outlet banks, using (I presume) outlet.n.x variables.
   I'll probably wait for an example of that to show up in some other
   driver before adding that, to try to make sure I do it in the way
   that Russell Kroll envisioned.  It also might be nice to give the
   user control over the delays before shutdown and restart, probably
   with additional driver parameters.  Letting the user turn the buzzer
   off might be nice too; for that I'd have to investigate whether the
   command to do that disables it entirely, or just turns it off during
   the existing alarm condition, to determine whether it would be better
   implemented through variables or instant commands, and then of course
   request that those get added to the list of known names.  Finally,
   there are a number of other alarm conditions that can be reported
   that would be nice to pass on to the user; these would require new
   variables or new status values.


   The following parameters (ups.conf) are supported:
      lowbatt

   The following variables are supported (RW = read/write):
      ambient.humidity (1)
      ambient.temperature (1)
      battery.charge
      battery.current (1)
      battery.temperature
      battery.voltage
      battery.voltage.nominal
      driver.version.internal
      input.frequency
      input.sensitivity (RW) (1)
      input.transfer.high (RW)
      input.transfer.low (RW)
      input.voltage
      input.voltage.nominal
      output.current (1)
      output.frequency
      output.voltage
      output.voltage.nominal
      ups.firmware
      ups.id (RW) (1)
      ups.load
      ups.mfr
      ups.model
      ups.status
      ups.test.result
      ups.contacts (1)

    The following instant commands are supported:
      load.off
      load.on
      shutdown.reboot
      shutdown.reboot.graceful
      shutdown.return
      shutdown.stop
      test.battery.start
      test.battery.stop

    The following ups.status values are supported:
      BOOST (1)
      BYPASS
      LB
      OB
      OFF
      OL
      OVER (2)
      RB (2)
      TRIM (1)

    (1) these items have not been tested because they are not supported
    by my SU1000RT2U.
    (2) these items have not been tested because I haven't tested them.
*/


#include "main.h"
#include "serial.h"
#include "tripplitesu.h"

#define MAX_RESPONSE_LENGTH 256

static const char *test_result_names[] = {
      "No test performed",
      "Passed",
      "In progress",
      "General test failed",
      "Battery failed",
      "Deep battery test failed",
      "Aborted"
};

static struct {
      int code;
      const char *name;
} sensitivity[] = {
      {0, "Normal"},
      {1, "Reduced"},
      {2, "Low"}
};

static struct {
      int outlet_banks;
      unsigned long commands_available;
} ups;

/* bits in commands_available */
#define WDG_AVAILABLE            (1UL <<  1)

/* message types */
#define POLL             'P'
#define SET              'S'
#define ACCEPT           'A'
#define REJECT           'R'
#define DATA             'D'

/* commands */
#define AUTO_REBOOT                  "ARB" /* poll/set */
#define AUTO_TEST                    "ATT" /* poll/set */
#define ATX_REBOOT                   "ATX" /* poll/set */
#define AVAILABLE                    "AVL" /* poll */
#define BATTERY_REPLACEMENT_DATE     "BRD" /* poll/set */
#define BUZZER_TEST                  "BTT" /* set */
#define BATTERY_TEST                 "BTV" /* poll/set */
#define BUZZER                       "BUZ" /* set */
#define ECONOMIC_MODE                "ECO" /* set */
#define ENABLE_BUZZER                "EDB" /* set */
#define ENVIRONMENT_INFORMATION      "ENV" /* poll */
#define OUTLET_RELAYS                "LET" /* poll */
#define MANUFACTURER                 "MNU" /* poll */
#define MODEL                        "MOD" /* poll */
#define RATINGS                      "RAT" /* poll */
#define RELAY_CYCLE                  "RNF" /* set */
#define RELAY_OFF                    "ROF" /* set */
#define RELAY_ON                     "RON" /* set */
#define ATX_RESUME                   "RSM" /* set */
#define SHUTDOWN_ACTION              "SDA" /* set */
#define SHUTDOWN_RESTART             "SDR" /* set */
#define SHUTDOWN_TYPE                "SDT" /* poll/set */
#define RELAY_STATUS                 "SOL" /* poll/set */
#define SELECT_OUTPUT_VOLTAGE        "SOV" /* poll/set */
#define STATUS_ALARM                 "STA" /* poll */
#define STATUS_BATTERY               "STB" /* poll */
#define STATUS_INPUT                 "STI" /* poll */
#define STATUS_OUTPUT                "STO" /* poll */
#define STATUS_BYPASS                "STP" /* poll */
#define TELEPHONE                    "TEL" /* poll/set */
#define TEST_RESULT                  "TSR" /* poll */
#define TEST                         "TST" /* set */
#define TRANSFER_FREQUENCY           "TXF" /* poll/set */
#define TRANSFER_VOLTAGE             "TXV" /* poll/set */
#define BOOT_DELAY                   "UBD" /* poll/set */
#define BAUD_RATE                    "UBR" /* poll/set */
#define IDENTIFICATION               "UID" /* poll/set */
#define VERSION                      "VER" /* poll */
#define VOLTAGE_SENSITIVITY          "VSN" /* poll/set */
#define WATCHDOG                     "WDG" /* poll/set */


static int do_command(char type, const char *command,
                      const char *parameters, char *response)
{
      char buffer[5];
      int count;
      char *ptr;

      count = 0;
      ser_flush_in(upsfd, "", nut_debug_level);

      if (ser_send(upsfd, "~00%c%03d%s%s", type,
                  strlen(command) + strlen(parameters), command,
                  parameters) <= 0)
            return -1;

      if (ser_get_buf_len(upsfd, buffer, 4, 3, 0) <= 0)
            return -1;
      buffer[4] = '\0';

      if (!strcmp(buffer, "~00D")) {
            if (ser_get_buf_len(upsfd, buffer, 4, 3, 0) <= 0)
                  return -1;
            buffer[3] = '\0';
            count = atoi(buffer);
            if (count >= MAX_RESPONSE_LENGTH || (count && !response))
                  return -1;
            if (count == 0) {
                  if (response)
                        *response = '\0';
                  return 0;
            }

            if (ser_get_buf_len(upsfd, response, count, 3, 0) <= 0)
                  return -1;
            response[count] = '\0';
            /* Tripp Lite pads their string responses with spaces.
               I don't like that, so I remove them.  This is safe to
               do with all responses for this protocol, so I just
               do that here. */
            ptr = response + strlen(response) - 1;
            while (ptr > response && *ptr == ' ')
                  ptr--;
            *(ptr + 1) = '\0';
            ser_comm_good();
            return count;
      }
      if (!strcmp(buffer, "~00A")) {
            if (response)
                  *response = '\0';
            ser_comm_good();
            return count;
      }
      if (!strcmp(buffer, "~00R"))
            ser_comm_good();

      return -1;
}

static char *field(char *str, int fieldnum)
{

      while (str && fieldnum--) {
            str = strchr(str, ';');
            if (str)
                  str++;
      }
      if (str && *str == ';')
            return NULL;

      return str;
}

static int get_identification(void) {
      char response[MAX_RESPONSE_LENGTH];

      if (do_command(POLL, IDENTIFICATION, "", response) >= 0) {
            dstate_setinfo("ups.id", "%s", response);
            return 1;
      }

      return 0;
}

static void set_identification(const char *val) {
      char response[MAX_RESPONSE_LENGTH];

      if (do_command(POLL, IDENTIFICATION, "", response) < 0)
            return;
      if (strcmp(val, response)) {
            strncpy(response, val, MAX_RESPONSE_LENGTH);
            response[MAX_RESPONSE_LENGTH - 1] = '\0';
            do_command(SET, IDENTIFICATION, response, NULL);
      }
}

static int get_transfer_voltage_low(void) {
      char response[MAX_RESPONSE_LENGTH];
      char *ptr;

      if (do_command(POLL, TRANSFER_VOLTAGE, "", response) > 0) {
            ptr = field(response, 0);
            if (ptr)
                  dstate_setinfo("input.transfer.low", "%d", atoi(ptr));
            return 1;
      }

      return 0;
}

static void set_transfer_voltage_low(int val) {
      char response[MAX_RESPONSE_LENGTH];
      char *ptr;
      int high;

      if (do_command(POLL, TRANSFER_VOLTAGE, "", response) <= 0)
            return;
      ptr = field(response, 0);
      if (!ptr || val == atoi(ptr))
            return;
      ptr = field(response, 1);
      if (!ptr)
            return;
      high = atoi(ptr);
      sprintf(response, "%d;%d", val, high);
      do_command(SET, TRANSFER_VOLTAGE, response, NULL);
}

static int get_transfer_voltage_high(void) {
      char response[MAX_RESPONSE_LENGTH];
      char *ptr;

      if (do_command(POLL, TRANSFER_VOLTAGE, "", response) > 0) {
            ptr = field(response, 1);
            if (ptr)
                  dstate_setinfo("input.transfer.high", "%d", atoi(ptr));
            return 1;
      }

      return 0;
}

static void set_transfer_voltage_high(int val) {
      char response[MAX_RESPONSE_LENGTH];
      char *ptr;
      int low;

      if (do_command(POLL, TRANSFER_VOLTAGE, "", response) <= 0)
            return;
      ptr = field(response, 0);
      if (!ptr)
            return;
      low = atoi(ptr);
      ptr = field(response, 1);
      if (!ptr || val == atoi(ptr))
            return;
      sprintf(response, "%d;%d", low, val);
      do_command(SET, TRANSFER_VOLTAGE, response, NULL);
}

static int get_sensitivity(void) {
      char response[MAX_RESPONSE_LENGTH];
      unsigned int i;

      if (do_command(POLL, VOLTAGE_SENSITIVITY, "", response) <= 0)
            return 0;
      for (i = 0; i < sizeof(sensitivity) / sizeof(sensitivity[0]); i++) {
            if (sensitivity[i].code == atoi(response)) {
                  dstate_setinfo("input.sensitivity", "%s",
                                 sensitivity[i].name);
                  return 1;
            }
      }

      return 0;
}

static void set_sensitivity(const char *val) {
      char parm[20];
      unsigned int i;

      for (i = 0; i < sizeof(sensitivity) / sizeof(sensitivity[0]); i++) {
            if (!strcasecmp(val, sensitivity[i].name)) {
                  sprintf(parm, "%d", i);
                  do_command(SET, VOLTAGE_SENSITIVITY, parm, NULL);
                  break;
            }
      }
}

static void auto_reboot(int enable) {
      char parm[20];
      char response[MAX_RESPONSE_LENGTH];
      char *ptr;
      int mode;

      if (enable)
            mode = 1;
      else
            mode = 2;
      if (do_command(POLL, AUTO_REBOOT, "", response) <= 0)
            return;
      ptr = field(response, 0);
      if (!ptr || atoi(ptr) != mode) {
            sprintf(parm, "%d", mode);
            do_command(SET, AUTO_REBOOT, parm, NULL);
      }
}

static int instcmd(const char *cmdname, const char *extra)
{
      int i;
      char parm[20];

      if (!strcasecmp(cmdname, "load.off")) {
            for (i = 0; i < ups.outlet_banks; i++) {
                  sprintf(parm, "%d;1", i + 1);
                  do_command(SET, RELAY_OFF, parm, NULL);
            }
            return STAT_INSTCMD_HANDLED;
      }
      if (!strcasecmp(cmdname, "load.on")) {
            for (i = 0; i < ups.outlet_banks; i++) {
                  sprintf(parm, "%d;1", i + 1);
                  do_command(SET, RELAY_ON, parm, NULL);
            }
            return STAT_INSTCMD_HANDLED;
      }
      if (!strcasecmp(cmdname, "shutdown.reboot")) {
            auto_reboot(1);
            do_command(SET, SHUTDOWN_RESTART, "1", NULL);
            do_command(SET, SHUTDOWN_ACTION, "10", NULL);
            return STAT_INSTCMD_HANDLED;
      }
      if (!strcasecmp(cmdname, "shutdown.reboot.graceful")) {
            auto_reboot(1);
            do_command(SET, SHUTDOWN_RESTART, "1", NULL);
            do_command(SET, SHUTDOWN_ACTION, "60", NULL);
            return STAT_INSTCMD_HANDLED;
      }
      if (!strcasecmp(cmdname, "shutdown.return")) {
            auto_reboot(1);
            do_command(SET, SHUTDOWN_RESTART, "1", NULL);
            do_command(SET, SHUTDOWN_ACTION, "10", NULL);
            return STAT_INSTCMD_HANDLED;
      }
#if 0 /* doesn't seem to work */
      if (!strcasecmp(cmdname, "shutdown.stayoff")) {
            auto_reboot(0);
            do_command(SET, SHUTDOWN_ACTION, "10", NULL);
            return STAT_INSTCMD_HANDLED;
      }
#endif
      if (!strcasecmp(cmdname, "shutdown.stop")) {
            do_command(SET, SHUTDOWN_ACTION, "0", NULL);
            return STAT_INSTCMD_HANDLED;
      }
      if (!strcasecmp(cmdname, "test.battery.start")) {
            do_command(SET, TEST, "3", NULL);
            return STAT_INSTCMD_HANDLED;
      }
      if (!strcasecmp(cmdname, "test.battery.stop")) {
            do_command(SET, TEST, "0", NULL);
            return STAT_INSTCMD_HANDLED;
      }
      upslogx(LOG_NOTICE, "instcmd: unknown command [%s]", cmdname);
      return STAT_INSTCMD_UNKNOWN;
}

static int setvar(const char *varname, const char *val)
{

      if (!strcasecmp(varname, "ups.id")) {
            set_identification(val);
            get_identification();
            return STAT_SET_HANDLED;
      }
      if (!strcasecmp(varname, "input.transfer.low")) {
            set_transfer_voltage_low(atoi(val));
            get_transfer_voltage_low();
            return STAT_SET_HANDLED;
      }
      if (!strcasecmp(varname, "input.transfer.high")) {
            set_transfer_voltage_high(atoi(val));
            get_transfer_voltage_high();
            return STAT_SET_HANDLED;
      }
      if (!strcasecmp(varname, "input.sensitivity")) {
            set_sensitivity(val);
            get_sensitivity();
            return STAT_SET_HANDLED;
      }

      upslogx(LOG_NOTICE, "setvar: unknown var [%s]", varname);
      return STAT_SET_UNKNOWN;
}

static int init_comm(void)
{
      int i, bit;
      char response[MAX_RESPONSE_LENGTH];

      ups.commands_available = 0;
      if (do_command(POLL, AVAILABLE, "", response) <= 0)
            return 0;
      i = strlen(response);
      for (bit = 0; bit < i; bit++)
            if (response[i - bit - 1] == '1')
                  ups.commands_available |= (1UL << bit);

      if (do_command(POLL, MANUFACTURER, "", response) <= 0)
            return 0;
      if (strcmp(response, "Tripp Lite"))
            return 0;

      return 1;
}

void upsdrv_initinfo(void)
{
      char response[MAX_RESPONSE_LENGTH];
      unsigned int min_low_transfer, max_low_transfer;
      unsigned int min_high_transfer, max_high_transfer;
      unsigned int i;
      char *ptr;

      if (!init_comm())
            fatalx("Unable to detect Tripp Lite SmartOnline UPS on port %s\n",
                    device_path);
      min_low_transfer = max_low_transfer = 0;
      min_high_transfer = max_high_transfer = 0;
      dstate_setinfo("driver.version.internal", "%s", DRV_VERSION);

      /* get all the read-only fields here */
      if (do_command(POLL, MANUFACTURER, "", response) > 0)
            dstate_setinfo("ups.mfr", "%s", response);
      if (do_command(POLL, MODEL, "", response) > 0)
            dstate_setinfo("ups.model", "%s", response);
      if (do_command(POLL, VERSION, "", response) > 0)
            dstate_setinfo("ups.firmware", "%s", response);
      if (do_command(POLL, RATINGS, "", response) > 0) {
            ptr = field(response, 0);
            if (ptr)
                  dstate_setinfo("input.voltage.nominal", "%d",
                                 atoi(ptr));
            ptr = field(response, 2);
            if (ptr) {
                  dstate_setinfo("output.voltage.nominal", "%d",
                                 atoi(ptr));
            }
            ptr = field(response, 14);
            if (ptr)
                  dstate_setinfo("battery.voltage.nominal", "%d",
                                 atoi(ptr));
            ptr = field(response, 10);
            if (ptr)
                  min_low_transfer = atoi(ptr);
            ptr = field(response, 9);
            if (ptr)
                  max_low_transfer = atoi(ptr);
            ptr = field(response, 12);
            if (ptr)
                  min_high_transfer = atoi(ptr);
            ptr = field(response, 11);
            if (ptr)
                  max_high_transfer = atoi(ptr);
      }
      if (do_command(POLL, OUTLET_RELAYS, "", response) > 0)
            ups.outlet_banks = atoi(response);
      /* define things that are settable */
      if (get_identification()) {
            dstate_setflags("ups.id", ST_FLAG_RW | ST_FLAG_STRING);
            dstate_setaux("ups.id", 100);
      }
      if (get_transfer_voltage_low() && max_low_transfer) {
            dstate_setflags("input.transfer.low", ST_FLAG_RW);
            for (i = min_low_transfer; i <= max_low_transfer; i++)
                  dstate_addenum("input.transfer.low", "%d", i);
      }
      if (get_transfer_voltage_high() && max_low_transfer) {
            dstate_setflags("input.transfer.high", ST_FLAG_RW);
            for (i = min_high_transfer; i <= max_high_transfer; i++)
                  dstate_addenum("input.transfer.high", "%d", i);
      }
      if (get_sensitivity()) {
            dstate_setflags("input.sensitivity", ST_FLAG_RW);
            for (i = 0; i < sizeof(sensitivity) / sizeof(sensitivity[0]);
                 i++)
                  dstate_addenum("input.sensitivity", "%s",
                                 sensitivity[i].name);
      }
      if (ups.outlet_banks) {
            dstate_addcmd("load.off");
            dstate_addcmd("load.on");
      }
      dstate_addcmd("shutdown.reboot");
      dstate_addcmd("shutdown.reboot.graceful");
      dstate_addcmd("shutdown.return");
#if 0 /* doesn't work */
      dstate_addcmd("shutdown.stayoff");
#endif
      dstate_addcmd("shutdown.stop");
      dstate_addcmd("test.battery.start");
      dstate_addcmd("test.battery.stop");

      /* add all the variables that change regularly */
      upsdrv_updateinfo();

      upsh.instcmd = instcmd;
      upsh.setvar = setvar;

      printf("Detected %s %s on %s\n", dstate_getinfo("ups.mfr"),
             dstate_getinfo("ups.model"), device_path);
}

void upsdrv_updateinfo(void)
{
      char response[MAX_RESPONSE_LENGTH];
      char *ptr, *ptr2;
      int i;
      int flags;
      int contacts_set;
      int low_battery;

      status_init();
      if (do_command(POLL, STATUS_OUTPUT, "", response) <= 0) {
            dstate_datastale();
            return;
      }
      ptr = field(response, 0);
      /* require output status field to exist */
      if (!ptr) {
            dstate_datastale();
            return;
      }
      switch (atoi(ptr)) {
      case 0:
            status_set("OL");
            break;
      case 1:
            status_set("OB");
            break;
      case 2:
            status_set("BYPASS");
            break;
      case 3:
            status_set("OL");
            status_set("TRIM");
            break;
      case 4:
            status_set("OL");
            status_set("BOOST");
            break;
      case 5:
            status_set("BYPASS");
            break;
      case 6:
            break;
      case 7:
            status_set("OFF");
            break;
      default:
            break;
      }
      ptr = field(response, 6);
      if (ptr)
            dstate_setinfo("ups.load", "%d", atoi(ptr));
      ptr = field(response, 3);
      if (ptr)
            dstate_setinfo("output.voltage", "%03.1f",
                           (double) atoi(ptr) / 10.0);
      ptr = field(response, 1);
      if (ptr)
            dstate_setinfo("output.frequency", "%03.1f",
                           (double) atoi(ptr) / 10.0);
      ptr = field(response, 4);
      if (ptr)
            dstate_setinfo("output.current", "%03.1f",
                           (double) atoi(ptr) / 10.0);

      low_battery = 0;
      if (do_command(POLL, STATUS_BATTERY, "", response) <= 0) {
            dstate_datastale();
            return;
      }
      ptr = field(response, 0);
      if (ptr && atoi(ptr) == 2)
            status_set("RB");
      ptr = field(response, 1);
      if (ptr && atoi(ptr))
            low_battery = 1;
      ptr = field(response, 8);
      if (ptr)
            dstate_setinfo("battery.temperature", "%d", atoi(ptr));
      ptr = field(response, 9);
      if (ptr) {
            dstate_setinfo("battery.charge", "%d", atoi(ptr));
            ptr2 = getval("lowbatt");
            if (ptr2 && atoi(ptr2) > 0 && atoi(ptr2) <= 99 &&
                atoi(ptr) <= atoi(ptr2))
                  low_battery = 1;
      }
      ptr = field(response, 6);
      if (ptr)
            dstate_setinfo("battery.voltage", "%03.1f",
                           (double) atoi(ptr) / 10.0);
      ptr = field(response, 7);
      if (ptr)
            dstate_setinfo("battery.current", "%03.1f",
                           (double) atoi(ptr) / 10.0);
      if (low_battery)
            status_set("LB");

      if (do_command(POLL, STATUS_ALARM, "", response) <= 0) {
            dstate_datastale();
            return;
      }
      ptr = field(response, 3);
      if (ptr && atoi(ptr))
            status_set("OVER");

      if (do_command(POLL, STATUS_INPUT, "", response) > 0) {
            ptr = field(response, 2);
            if (ptr)
                  dstate_setinfo("input.voltage", "%03.1f",
                                 (double) atoi(ptr) / 10.0);
            ptr = field(response, 1);
            if (ptr)
                  dstate_setinfo("input.frequency",
                               "%03.1f", (double) atoi(ptr) / 10.0);
      }

      if (do_command(POLL, TEST_RESULT, "", response) > 0) {
            int   r;
            size_t      trsize;

            r = atoi(response);
            trsize = sizeof(test_result_names) / 
                  sizeof(test_result_names[0]);

            if ((r < 0) || (r >= (int) trsize))
                  r = 0;

            dstate_setinfo("ups.test.result", "%s", test_result_names[r]);
      }

      if (do_command(POLL, ENVIRONMENT_INFORMATION, "", response) > 0) {
            ptr = field(response, 0);
            if (ptr)
                  dstate_setinfo("ambient.temperature", "%d", atoi(ptr));
            ptr = field(response, 1);
            if (ptr)
                  dstate_setinfo("ambient.humidity", "%d", atoi(ptr));
            flags = 0;
            contacts_set = 0;
            for (i = 0; i < 4; i++) {
                  ptr = field(response, 2 + i);
                  if (ptr) {
                        contacts_set = 1;
                        if (*ptr == '1')
                              flags |= 1 << i;
                  }
            }
            if (contacts_set)
                  dstate_setinfo("ups.contacts", "%02X", flags);
      }

      /* if we are here, status is valid */
      status_commit();
      dstate_dataok();
}

void upsdrv_shutdown(void)
{
      char parm[20];

      if (!init_comm())
            printf("Status failed.  Assuming it's on battery and trying a shutdown anyway.\n");
      auto_reboot(1);
      /* in case the power is on, tell it to automatically reboot.  if
         it is off, this has no effect. */
      sprintf(parm, "%d", 1); /* delay before reboot, in minutes */
      do_command(SET, SHUTDOWN_RESTART, parm, NULL);
      sprintf(parm, "%d", 5); /* delay before shutdown, in seconds */
      do_command(SET, SHUTDOWN_ACTION, parm, NULL);
}

void upsdrv_help(void)
{
}

/* list flags and values that you want to receive via -x or ups.conf */
void upsdrv_makevartable(void)
{
      addvar(VAR_VALUE, "lowbatt", "Set low battery level, in percent");
}

void upsdrv_banner(void)
{
      printf("Network UPS Tools - Tripp Lite SmartOnline driver %s (%s)\n\n", 
             DRV_VERSION, UPS_VERSION);

      experimental_driver = 1;
}

void upsdrv_initups(void)
{
      upsfd = ser_open(device_path);
      ser_set_speed(upsfd, device_path, B2400);
}

void upsdrv_cleanup(void)
{
      ser_close(upsfd, device_path);
}

Generated by  Doxygen 1.6.0   Back to index