[Nut-upsdev] Cpsups driver with a CyberPower OP1000E
Doug Reynolds
mav at wastegate.net
Tue Jan 2 23:45:45 CET 2007
Marcel Ziswiler wrote:
>> please, if you can, download the newest trunk and try the new
>> 'powerpanel' driver. the last cpsups driver submitted is/was slightly
>> broken. the new powerpanel driver is the new, working one. I am
>> building it now myself.
>>
>> If you are still having trouble, I can send you the last good update to
>> cpsups.c cpsups.h
>>
>
> Sorry, still no luck:
> # drivers/powerpanel -a myups -DDD
> Network UPS Tools - CyberPower text protocol UPS driver 0.10 (2.1.0)
> Warning: This is an experimental driver.
> Some features may not function correctly.
>
> debug level is '3'
> command:
> reply : <none>
> command:
> reply : <none>
> command:
> reply : <none>
> command:
> reply : <none>
> command:
> reply : <none>
> Unable to detect a CyberPower text protocol UPS
>
> Can you please send me the latest cpsups one you have. I am wondering whether it has something todo with me using a serial to USB converter, but then that stuff should all be standard by now.
>
>
it is rumored that the serial<->usb converters sometimes work, and
sometimes don't... i've attached these the last cpsups drivers, give
them a try. is it possible to use a direct serial cable?
-------------- next part --------------
/* cpsups.h - Lookup tables for CyberPower text protocol UPSes
Copyright (C) 2003 Walt Holman <waltabbyh at comcast.net>
with thanks to Russell Kroll <rkroll at exploits.org>
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
*/
/*
* Offsets within the buffer that is returned after a "D\r" command
*/
#define POLL_INPUTVOLT 2 /* input voltage */
#define POLL_OUTPUTVOLT 8 /* output voltage */
#define POLL_LOAD 14 /* load percentage */
#define POLL_BATTCHARGE 18 /* battery charge */
#define POLL_TEMP 22 /* temperature */
#define POLL_FREQUENCY 26 /* frequency */
#define POLL_STATUS 32 /* status byte */
#define ENDCHAR '\r' /* replies end with CR */
#define MAXTRIES 5
#define UPSDELAY 50000 /* 50 ms delay required for reliable operation */
#define SER_WAIT_SEC 3 /* allow 3 sec for ser_get calls */
#define SER_WAIT_USEC 0
#define CPS_STAT_CAL 0x08
#define CPS_STAT_LB 0x20
#define CPS_STAT_OB 0x40
#define CPS_STAT_OL 0x90
-------------- next part --------------
/* cpsups.c - model specific routines for CyberPower text protocol UPSes
Copyright (C) 2007 Arjen de Korte <arjen at de-korte.org>
Doug Reynolds <mav at wastegate.net>
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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/ioctl.h>
#include "main.h"
#include "serial.h"
#include "cpsups.h"
#define DRV_VERSION "0.08"
static char cpsups_reply[SMALLBUF];
static int cpsups_command(const char *command)
{
int dtr_bit = TIOCM_DTR;
int ret = -1;
upsdebugx(3, "command: %s", command);
ioctl(upsfd, TIOCMBIS, &dtr_bit);
tcflush(upsfd, TCIOFLUSH);
if (ser_send_pace(upsfd, UPSDELAY, command) == strlen(command))
{
ret = ser_get_line(upsfd, cpsups_reply, sizeof(cpsups_reply), ENDCHAR, "",
SER_WAIT_SEC, SER_WAIT_USEC);
}
ioctl(upsfd, TIOCMBIC, &dtr_bit);
if (ret > 0)
upsdebug_hex(3, "reply ", (unsigned char *)cpsups_reply, ret);
else
upsdebugx(3, "reply : <none>");
if (cpsups_reply[0] != '#')
return 0;
return ret;
}
static int instcmd(const char *cmdname, const char *extra)
{
int ret = -1;
if (!strcasecmp(cmdname, "test.battery.start"))
ret = cpsups_command("T\r");
if (!strcasecmp(cmdname, "test.battery.stop"))
ret = cpsups_command("CT\r");
if (!strcasecmp(cmdname, "beeper.on"))
ret = cpsups_command("C7:1\r");
if (!strcasecmp(cmdname, "beeper.off"))
ret = cpsups_command("C7:0\r");
if (ret > 0)
return STAT_INSTCMD_HANDLED;
upslogx(LOG_NOTICE, "instcmd: command [%s] failed", cmdname);
return STAT_INSTCMD_UNKNOWN;
}
static int setvar(const char *varname, const char *val)
{
char command[SMALLBUF];
if (!strcasecmp(varname, "input.transfer.high"))
{
snprintf(command, sizeof(command), "C2:%s\r", val);
if ((cpsups_command(command) > 0) && !strcasecmp(cpsups_reply, "#0"))
{
dstate_setinfo("input.transfer.high", val);
return STAT_SET_HANDLED;
}
}
if (!strcasecmp(varname, "input.transfer.low"))
{
snprintf(command, sizeof(command), "C3:%s\r", val);
if ((cpsups_command(command) > 0) && !strcasecmp(cpsups_reply, "#0"))
{
dstate_setinfo("input.transfer.low", val);
return STAT_SET_HANDLED;
}
}
if (!strcasecmp(varname, "battery.charge.low"))
{
snprintf(command, sizeof(command), "C4:%s\r", val);
if ((cpsups_command(command) > 0) && !strcasecmp(cpsups_reply, "#0"))
{
dstate_setinfo("battery.charge.low", val);
return STAT_SET_HANDLED;
}
}
upslogx(LOG_NOTICE, "setvar: setting variable [%s] to [%s] failed", varname, val);
return STAT_SET_UNKNOWN;
}
static int get_ident(void)
{
char *s;
int retry = MAXTRIES;
while (retry--)
{
if ((cpsups_command("\r") > 0) && (cpsups_reply[1] == '2') && (cpsups_command("P4\r") > 0))
{
if ((s = strtok(cpsups_reply+1, ",")) != NULL)
dstate_setinfo("ups.model", s);
if ((s = strtok(NULL, ",")) != NULL)
dstate_setinfo("ups.firmware", s);
if ((s = strtok(NULL, ",")) != NULL)
upsdebugx(1, "serial number (?) %s", s);
if ((s = strtok(NULL, ",")) != NULL)
dstate_setinfo("ups.mfr", s);
return 1;
}
}
return 0;
}
static int get_settings(void)
{
char *s;
int ret = 0;
/*
* WRITE P3\r
* READ #12.0,002,008.0,00\r
*/
if (cpsups_command("P3\r") > 0)
{
if ((s = strtok(cpsups_reply+1, ",")) != NULL)
dstate_setinfo("battery.voltage.nominal", s);
if ((s = strtok(NULL, ",")) != NULL)
dstate_setinfo("battery.packs", s);
if ((s = strtok(NULL, ",")) != NULL)
dstate_setinfo("battery.capacity.nominal", s);
ret++;
}
/*
* WRITE P2\r
* READ #1200,0720,120,47,63\r
*/
if (cpsups_command("P2\r") > 0)
{
if ((s = strtok(cpsups_reply+1, ",")) != NULL)
dstate_setinfo("ups.power.nominal", s);
if ((s = strtok(NULL, ",")) != NULL)
dstate_setinfo("ups.watts.nominal", s);
if ((s = strtok(NULL, ",")) != NULL)
dstate_setinfo("input.voltage.nominal", s);
if ((s = strtok(NULL, ",")) != NULL)
dstate_setinfo("input.frequency.low", s);
if ((s = strtok(NULL, ",")) != NULL)
dstate_setinfo("input.frequency.high", s);
ret++;
}
/*
* WRITE P1\r
* READ #120,138,088,20\r
*/
if (cpsups_command("P1\r") > 0)
{
if ((s = strtok(cpsups_reply+1, ",")) != NULL)
dstate_setinfo("input.voltage.nominal", s);
if ((s = strtok(NULL, ",")) != NULL)
dstate_setinfo("input.transfer.high", s);
if ((s = strtok(NULL, ",")) != NULL)
dstate_setinfo("input.transfer.low", s);
if ((s = strtok(NULL, ",")) != NULL)
dstate_setinfo("battery.charge.low", s);
ret++;
}
/*
* WRITE P6\r
* READ #130,131,132,133,134,135,136,137,138,139,140\r
*/
if (dstate_getinfo("input.transfer.high") && (cpsups_command("P6\r") > 0))
{
if ((s = strtok(cpsups_reply+1, ",")) != NULL)
{
dstate_addenum("input.transfer.high", s);
dstate_setflags("input.transfer.high", ST_FLAG_STRING | ST_FLAG_RW);
dstate_setaux("input.transfer.high", 3);
}
while ((s = strtok(NULL, ",")) != NULL)
dstate_addenum("input.transfer.high", s);
ret++;
}
/*
* WRITE P7\r
* READ #080,081,082,083,084,085,086,087,088,089,090\r
*/
if (dstate_getinfo("input.transfer.low") && (cpsups_command("P7\r") > 0))
{
if ((s = strtok(cpsups_reply+1, ",")) != NULL)
{
dstate_addenum("input.transfer.low", s);
dstate_setflags("input.transfer.low", ST_FLAG_STRING | ST_FLAG_RW);
dstate_setaux("input.transfer.low", 3);
}
while ((s = strtok(NULL, ",")) != NULL)
dstate_addenum("input.transfer.low", s);
ret++;
}
/*
* WRITE P8\r\
* READ #20,25,30,35,40,45,50,55,60,65\r
*/
if (dstate_getinfo("battery.charge.low") && (cpsups_command("P8\r") > 0))
{
if ((s = strtok(cpsups_reply+1, ",")) != NULL)
{
dstate_addenum("battery.charge.low", s);
dstate_setflags("battery.charge.low", ST_FLAG_STRING | ST_FLAG_RW);
dstate_setaux("battery.charge.low", 2);
}
while ((s = strtok(NULL, ",")) != NULL)
dstate_addenum("battery.charge.low", s);
ret++;
}
return ret;
}
void upsdrv_initinfo(void)
{
char *s;
dstate_setinfo("driver.version.internal", "%s", DRV_VERSION);
if (get_ident() == 0)
fatalx("Unable to detect a CyberPower text protocol UPS");
printf("Detected %s %s on %s\n", dstate_getinfo("ups.mfr"),
dstate_getinfo("ups.model"), device_path);
if (get_settings() == 0)
upslogx(LOG_WARNING, "Can't read settings from CyberPower text protocol UPS");
/* paranoia - cancel any shutdown that might already be running */
cpsups_command("D\r");
cpsups_command("C\r");
/*
* allow to override the following parameters
*/
if ((s = getval("manufacturer")) != NULL)
dstate_setinfo("ups.mfr", s);
if ((s = getval("model")) != NULL)
dstate_setinfo("ups.model", s);
if ((s = getval("serial")) != NULL)
dstate_setinfo("ups.serial", s);
dstate_addcmd("test.battery.start");
dstate_addcmd("test.battery.stop");
dstate_addcmd("beeper.on");
dstate_addcmd("beeper.off");
/* dstate_addcmd("shutdown.return"); */
/* dstate_addcmd("shutdown.reboot"); */
upsh.instcmd = instcmd;
upsh.setvar = setvar;
}
void upsdrv_shutdown(void)
{
int retry = MAXTRIES;
if (get_ident() == 0)
fatalx("Unable to detect a CyberPower text protocol UPS");
/*
* Don't abort on the first try
*/
while (retry--)
{
if (cpsups_command("Z02\r") > 0)
{
upslogx(LOG_INFO, "Shutdown in progress");
return;
}
}
upslogx(LOG_ERR, "Shutdown command returned with an error!");
}
void upsdrv_updateinfo(void)
{
/*
* The "D\r" command should return exactly 34 characters
*/
if (cpsups_command("D\r") != 34)
{
ser_comm_fail("Status read failed");
dstate_datastale();
}
status_init();
if ((cpsups_reply[POLL_STATUS] & CPS_STAT_OL) && !(cpsups_reply[POLL_STATUS] & CPS_STAT_OB))
status_set("OL");
if (cpsups_reply[POLL_STATUS] & CPS_STAT_OB)
status_set("OB");
if (cpsups_reply[POLL_STATUS] & CPS_STAT_LB)
status_set("LB");
if (cpsups_reply[POLL_STATUS] & CPS_STAT_CAL)
status_set("CAL");
if (cpsups_reply[POLL_STATUS] == 0)
status_set("OFF");
status_commit();
dstate_setinfo("input.voltage", "%g", strtod(&cpsups_reply[POLL_INPUTVOLT], NULL));
dstate_setinfo("output.voltage", "%g", strtod(&cpsups_reply[POLL_OUTPUTVOLT], NULL));
dstate_setinfo("ups.load", "%li", strtol(&cpsups_reply[POLL_LOAD], NULL, 10));
dstate_setinfo("input.frequency", "%g", strtod(&cpsups_reply[POLL_FREQUENCY], NULL));
dstate_setinfo("ups.temperature", "%li", strtol(&cpsups_reply[POLL_TEMP], NULL,10));
dstate_setinfo("battery.charge", "%02.1f", strtod(&cpsups_reply[POLL_BATTCHARGE], NULL));
ser_comm_good();
dstate_dataok();
return;
}
void upsdrv_help(void)
{
}
void upsdrv_makevartable(void)
{
}
void upsdrv_banner(void)
{
printf("Network UPS Tools - CyberPower text protocol UPS driver %s (%s)\n",
DRV_VERSION, UPS_VERSION);
experimental_driver = 1; /* Causes a warning message to be printed */
}
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);
}
More information about the Nut-upsdev
mailing list