Logo Search packages:      
Sourcecode: nut version File versions

mustek.c

/* mustek.c - model specific routines for mustek UPS models

   Based on blazer.c driver from nut 2.0.0.

   Modified to work with Mustek PowerMust by Martin Hajduch (martin@hajduch.de).
   If it does not work as expected, please send me a note.
   Well, you can send me a note even if it works as expected ;-)

   Copyright (C) 1999  Russell Kroll <rkroll@exploits.org>
   2002  Phil Hutton <mustek-driver@hutton.sh>
   2003  Arnaud Quette <arnaud.quette@free.fr>
   2004  Martin Hajduch <martin@hajduch.de>

   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
*/

#include "main.h"
#include "serial.h"
#include "mustek.h"

#define ENDCHAR         13    /* replies end with CR */
#define UPSDELAY  3
#define MAXTRIES  10
#define SENDDELAY 100000      /* 100 ms delay between chars on transmit */
#define SER_WAIT_SEC    2     /* allow 3.0 sec for responses */
#define SER_WAIT_USEC   0

static      float lowvolt = 0, highvolt = 0, voltrange = 0;
static      int   poll_failures = 0;
static      int   inverted_bypass_bit = 0;


static int instcmd(const char *cmdname, const char *extra)
{
  /* Stop battery test */
  if (!strcasecmp(cmdname, "test.battery.stop")) {
    ser_send_pace(upsfd, SENDDELAY, "CT\r");
    return STAT_INSTCMD_HANDLED;
  }
  
  /* Start battery test */
  if (!strcasecmp(cmdname, "test.battery.start")) {
    ser_send_pace(upsfd, SENDDELAY, "T\r");
    return STAT_INSTCMD_HANDLED;
  }
  
  upslogx(LOG_NOTICE, "instcmd: unknown command [%s]", cmdname);
  return STAT_INSTCMD_UNKNOWN;
}

void upsdrv_initinfo(void)
{
  dstate_setinfo("driver.version.internal", "%s", DRV_VERSION);
  dstate_setinfo("ups.mfr", "Mustek");
  dstate_setinfo("ups.model", "PowerMust");
  
  dstate_addcmd("test.battery.start");
  dstate_addcmd("test.battery.stop");
  
  printf("Detected UPS on %s\n", device_path);
  
  upsh.instcmd = instcmd;
  
  /* paranoia - cancel any shutdown that might already be running */
  ser_send_pace(upsfd, SENDDELAY, "C\r");
}

static void ups_sync(void)
{
  char      buf[256];
  int tries = 0, ret;
  
  printf("Syncing with UPS: ");
  fflush(stdout);
  
  for (;;) {
    tries++;
    if (tries > MAXTRIES) {
      fatalx("\nFailed - giving up...");
    }
    
    printf(".");
    fflush(stdout);
    
    ret = ser_send_pace(upsfd, SENDDELAY, "F\r");
    
    if (ret > 0) {
      
      ret = ser_get_line(upsfd, buf, sizeof(buf), ENDCHAR, "",
                   SER_WAIT_SEC, SER_WAIT_USEC);
      if (buf[0]=='#' && strlen(buf)>1) {
      /* F command successful ! */
      ret = ser_send_pace(upsfd, SENDDELAY, "Q1\r");
      
      if (ret > 0) {
        
        ret = ser_get_line(upsfd, buf, sizeof(buf), ENDCHAR, "",
                       SER_WAIT_SEC, SER_WAIT_USEC);
        if (buf[0]=='(' && strlen(buf)>2) {
          break;
        }
      }
      }
    }
    /* not successful ! */
    sleep(UPSDELAY);
    printf(".");
    fflush(stdout);
    
  }
  
  printf(" done\n");
}

void upsdrv_shutdown(void)
{
      ser_send_pace(upsfd, SENDDELAY, "S01R0001\r");
}

static void ups_ident(void)
{
  char      buf[256];
  int tries = 0, ret;
  int ratecurrent;
  float     ratevolt, ratefreq;
  
  printf("Identifying UPS: ");
  fflush (stdout);
  
  for (;;) {
    tries++;
    if (tries > MAXTRIES) {
      upsdebugx(2, "Failed - giving up...");
      exit (1);
    }
    
    printf(".");
    fflush(stdout);
    ret = ser_send_pace(upsfd, SENDDELAY, "F\r");
    
    if (ret>0) {
      
      ret = ser_get_line(upsfd, buf, sizeof(buf), ENDCHAR, "",
                   SER_WAIT_SEC, SER_WAIT_USEC);
      
      /* don't be so strict about the return,
       it should look reasonable, though */
      if ((ret > 0) && (buf[0] == '#') && (strlen(buf) > 15)) {
      break;
      }
    }
    sleep(UPSDELAY);
    printf(".");
    fflush(stdout);
  }
  
  printf(" done\n");
  
  sscanf(buf, "%*c %f %d %*f %f", &ratevolt, &ratecurrent, &ratefreq);
  upsdebugx(2, "UPS is rated at %.2fV, %dA, %.2fHz.\n",
          ratevolt, ratecurrent, ratefreq);
  
  /* Just some guess ... */
  lowvolt = 9.7;
  highvolt = 13.7;
  
  voltrange = highvolt - lowvolt;
}

static void pollfail(const char *why)
{
  poll_failures++;
  
  /* ignore the first few since these UPSes tend to drop characters */
  if (poll_failures == 3) {
    ser_comm_fail(why);
  }
  
  return;
}

void upsdrv_updateinfo(void)
{
  char      utility[16], outvolt[16], loadpct[16], acfreq[16], 
    battvolt[16], upstemp[16], pstat[16], buf[256];
  float     bvoltp;
  int ret;
  
  ret = ser_send_pace(upsfd, SENDDELAY, "Q1\r");
  
  if (ret < 1) {
    pollfail("Poll failed: send status request failed");
    dstate_datastale();
    return;
  }
  
  sleep(UPSDELAY); 
  
  ret = ser_get_line(upsfd, buf, sizeof(buf), ENDCHAR, "",
                 SER_WAIT_SEC, SER_WAIT_USEC);
  
  if (ret < 1) {
    pollfail("Poll failed: read failed");
    dstate_datastale();
    return;
  }
  
  if (strlen(buf) < 40) {
    pollfail("Poll failed: short read from UPS");
    dstate_datastale();
    return;
  }
  
  if (strlen(buf) > 50) {
    pollfail("Poll failed: oversized read from UPS");
    dstate_datastale();
    return;
  }
  
  if (buf[0] != '(') {
    pollfail("Poll failed: invalid start character");
    return;
  }
  
  /* only say this if it got high enough to log a failure note */
  if (poll_failures >= 3) {
    ser_comm_good();
  }
  
  poll_failures = 0;
  
  sscanf(buf, "%*c%s %*s %s %s %s %s %s %s", utility, outvolt, 
       loadpct, acfreq, battvolt, upstemp, pstat);
  
  bvoltp = ((atof (battvolt) - lowvolt) / voltrange) * 100.0;
  
  if (bvoltp > 100.0) {
    bvoltp = 100.0;
  }
  
  dstate_setinfo("input.voltage", "%s", utility);
  dstate_setinfo("input.frequency", "%s", acfreq);
  dstate_setinfo("output.voltage", "%s", outvolt);
  dstate_setinfo("battery.charge", "%02.1f", bvoltp);
  dstate_setinfo("battery.voltage", "%s", battvolt);
  dstate_setinfo("ups.load", "%s", loadpct);
  
  status_init();
  
  if (pstat[0] == '0') {
    status_set("OL");         /* on line */
    
    /* only allow these when OL since they're bogus when OB */
    
    if (pstat[2] == (inverted_bypass_bit ? '0' : '1')) {
      /* boost or trim in effect */
      if (atof(utility) < atof(outvolt))
      status_set("BOOST");
      
      if (atof(utility) > atof(outvolt))
      status_set("TRIM");
    }
    
  } else {
    status_set("OB");         /* on battery */
  }
  
  if (pstat[1] == '1') {
    status_set("LB");         /* low battery */
  }
  
  status_commit();
  dstate_dataok();
}

void upsdrv_help(void)
{
}

void upsdrv_makevartable(void)
{
}

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

      upslogx(LOG_WARNING, "This driver is obsolete and has been replaced by the \"megatec\""
                           " driver. It will be removed somewhere in the near future.");
}

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

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

Generated by  Doxygen 1.6.0   Back to index