Rob wrote:
I'm trying to get more information about the problems with the
CP1200AVR and am connecting to the device through the USB cable.
Since I haven't received the working driver yet (someone modified the
cpsups driver), I figured I'd start trying to play with some drivers
and ran them in debug mode. Here's the output from the newhidups run:
/lib/nut/newhidups -u root -a Lysander -DDDD
Network UPS Tools: 0.28 USB communication driver 0.28 - core 0.30 (2.1.0)
debug level is '4'
Checking device (0764/0005) (001/008)
- VendorID: 0764
- ProductID: 0005
- Manufacturer: unknown
- Product: unknown
- Serial Number: unknown
- Bus: 001
Trying to match device
Device matches
failed to claim USB device, trying 2 more time(s)...
detaching kernel driver from USB device...
trying again to claim USB device...
Unable to get HID descriptor (error sending control message:
Connection timed out)
Running the driver seems to cause issues with the 2.6.17 kernel as the
/dev/usb/hiddev0 device disappears after the failed attempt to access
the UPS. This doesn't happen with the 2.0.3 version of the driver
(but that version also doesn't even recognize the UPS.
The failure to claim the USB device seems troubling to me, unless that
error is because the device node is disappearing after the device
check (which itself it troubling).
I also tried the cpsups driver, but it complains thusly:
cpsups -a Lysander -u root -DDDD
Network UPS Tools - CyberPower text protocol UPS driver .04 (2.1.0)
Warning: This is an experimental driver.
Some features may not function correctly.
debug level is '4'
tcgetattr(/dev/usb/hiddev0): Invalid argument
genericups with usbtype=22 complains:
genericups -a Lysander -u root -DDDD
Network UPS Tools - Generic UPS driver 1.32 (2.1.0)
debug level is '4'
UPS type: Gamatronic UPSs with alarm interface
ioctl TIOCMSET: Invalid argument
So it looks like the newhidups is the most likely to get working. Is
that a fair assessment? Is the problem with the device node a known
problem? Is there a way to get the dump of the communication traffic
going on between the PC and the UPS? Any ideas on where to go next?
Rob
Rob wrote:
Yes, I'd be very interested in getting a copy of your driver which works
with the CP1200AVR. Does your cpsups driver support USB connections or
only serial? Also, which NUT release is it based on/work with (2.0.x or
2.1)?
Rob
-------- Original Message --------
Subject: Re: [Nut-upsuser] CyberPower CP1200AVR/BC1200D problems
From: doug reynolds <[EMAIL PROTECTED]>
Date: Thu, July 20, 2006 9:07 pm
To: Rob <[EMAIL PROTECTED]>
Cc: [email protected]
Rob wrote:
I recently purchased a CyberPower CP1200AVR UPS and am trying to
get NUT 2.0.3 or NUT 2.1.0 to work with the newhidups driver, but
am having little success. Before I purchased I did some googling
and saw people talking about problems so I'm guessing it may not be
supported yet? I did find some posts about people getting it to
(sort of) work with some hacks, but couldn't tell if they ever got
submitted to the NUT development team. I also found some posts
about the CyberPower 900AVR/BC900D having issues, and it looks like
I am having the same problems as the person trying to use that
UPS. Namely, I see these messages in syslog:
kernel: usb 1-2: usbfs: USBDEVFS_CONTROL failed cmd newhidups rqt
128 rq 6 len 255 ret -110
I don't have much experience in protocol decoding, but I am a
software engineer and I'd like to help get this UPS supported by
NUT. Does anyone know the status of the support for the CyberPower
CP1200AVR or have anything new to try?
i got mine working fairly well with the cpsups with a couple change
to the code... email me if you would like a copy of my driver.
oops. sorry, been busy.. here is the driver mods I came up with..
other than the type definition, I removed the leading \r's from the
commands sent to the UPS. seems to work pretty good.. haven't had a
whole lot of time to test thoroughly.. another gentleman on this list
mentioned what he did, so I went through the code and this is what I
came up with..
/* cpsups.c - model specific routines for CyberPower text protocol UPSes
Copyright (C) 2003 Walt Holman <[EMAIL PROTECTED]>
with thanks to Russell Kroll <[EMAIL PROTECTED]>
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
*/
/* This driver started out as the bestups.c driver from 1.5.11 -
* I've hacked it up every which way to get it to function
* with a CPS1100AVR. Thanks go to the guys at
* http://networkupstools.org for creating a very nice toolset.
*/
/* hack version for 1200VA
* by DJR
*/
#include "cpsups.h"
#define DRV_VERSION ".04"
static void model_set(const char *abbr, const char *rating)
{
/*
* Added: Brad Sawatzky <[EMAIL PROTECTED]> 02Jun04
* NOTE: I have no idea how to set the runtime parameter... I
basically
* scaled up linearly from the 1100 and 500 entries based on the
* 'voltage'. The realtime runtime calculated under load looks
* reasonable.
*/
if (!strcmp(abbr, "#1500VA ")) {
dstate_setinfo("ups.mfr", "%s", "CyberPower");
dstate_setinfo("ups.model", "CPS1500AVR %s", rating);
dstate_setinfo("ups.runtime", "%s", "90");
dstate_setinfo("ups.power.nominal", "%s", "1500");
return;
}
// define the type of ups, and match it to the string returned, #BC1200
if (!strcmp(abbr, "#BC1200 ")) {
dstate_setinfo("ups.mfr", "%s", "CyberPower");
dstate_setinfo("ups.model", "CPS1200VA %s", rating);
dstate_setinfo("ups.runtime", "%s", "70");
dstate_setinfo("ups.power.nominal", "%s", "1200");
return;
}
if (!strcmp(abbr, "#1100VA ")) {
dstate_setinfo("ups.mfr", "%s", "CyberPower");
dstate_setinfo("ups.model", "CPS1100VA %s", rating);
dstate_setinfo("ups.runtime", "%s", "60");
dstate_setinfo("ups.power.nominal", "%s", "1100");
return;
}
/* Added: Armin Diehl <[EMAIL PROTECTED]> 14Dec04 */
if (!strcmp(abbr, "#1000VA ")) {
dstate_setinfo("ups.mfr", "%s", "MicroDowell");
dstate_setinfo("ups.model", "B.Box BP 1000 %s", rating);
dstate_setinfo("ups.runtime", "%s", "50");
dstate_setinfo("ups.voltage", "%s", "1000");
return;
}
if (!strcmp(abbr, "#825VA ")) {
dstate_setinfo("ups.mfr", "%s", "CyberPower");
dstate_setinfo("ups.model", "CPS825VA %s", rating);
dstate_setinfo("ups.runtime", "%s", "29");
dstate_setinfo("ups.power.nominal", "%s", "825");
return;
}
/* Added: Armin Diehl <[EMAIL PROTECTED]> 14Dec04 */
if (!strcmp(abbr, "#750VA ")) {
dstate_setinfo("ups.mfr", "%s", "MicroDowell");
dstate_setinfo("ups.model", "B.Box BP 750 %s", rating);
dstate_setinfo("ups.runtime", "%s", "29");
dstate_setinfo("ups.voltage", "%s", "825");
return;
}
if (!strcmp(abbr, "#500VA ")) {
dstate_setinfo("ups.mfr", "%s", "CyberPower");
dstate_setinfo("ups.model", "OP500TE %s", rating);
dstate_setinfo("ups.runtime", "%s", "16.5");
dstate_setinfo("ups.power.nominal", "%s", "500");
return;
}
dstate_setinfo("ups.mfr", "%s", "Unknown");
dstate_setinfo("ups.model", "Unknown %s (%s)", abbr, rating);
dstate_setinfo("ups.runtime", "%s", "1");
dstate_setinfo("ups.power.nominal", "%s", "1");
printf("Unknown model detected - please report this ID: '%s'\n", abbr);
}
static int instcmd(const char *cmdname, const char *extra)
{
/* The following commands also appear to be valid on the CPS1100 */
if (!strcasecmp(cmdname, "test.battery.stop")) {
ser_send_pace(upsfd, UPSDELAY, "CT\r");
return STAT_INSTCMD_HANDLED;
}
if (!strcasecmp(cmdname, "test.battery.start")) {
ser_send_pace(upsfd, UPSDELAY, "T\r");
return STAT_INSTCMD_HANDLED;
}
upslogx(LOG_NOTICE, "instcmd: unknown command [%s]", cmdname);
return STAT_INSTCMD_UNKNOWN;
}
static int get_ident(char *buf, size_t bufsize)
{
int i, ret;
for (i = 0; i < MAXTRIES; i++) {
ser_send_pace(upsfd, UPSDELAY, "P4\r");
ret = ser_get_line(upsfd, buf, bufsize, ENDCHAR, "",
SER_WAIT_SEC, SER_WAIT_USEC);
if (ret > 0)
upsdebugx(2, "get_ident: got [%s]", buf);
/* buf must start with # and be in the range [25-27] */
if ((ret > 0) && (buf[0] == '#') && (strlen(buf) >= 25) &&
(strlen(buf) <= 50))
return 1;
sleep(1);
}
upslogx(LOG_INFO, "Giving up on hardware detection after %d tries",
MAXTRIES);
return 0;
}
static int scan_poll_values(char *buf)
{
char values[20][200], *pos;
int i = 0, battremain, length, rseconds;
double rminutes;
/* These are used to hold status of UPS.
* val1 = online/onbattery status
*/
char temp1=values[6][0];
char *tmp1=&temp1;
while ((pollstatusmap[i].end != 0))
{
pos = &buf[pollstatusmap[i].begin];
length = pollstatusmap[i].end + 1 - pollstatusmap[i].begin;
strncpy(values[i],pos,length);
i++;
}
if ((*tmp1 & CPS_STAT_OL) && !(*tmp1 & CPS_STAT_OB))
status_set("OL");
if (*tmp1 & CPS_STAT_OB)
status_set("OB");
if (*tmp1 & CPS_STAT_CAL)
status_set("CAL");
if (*tmp1 & CPS_STAT_LB)
status_set("LB");
if (*tmp1 == 0)
status_set("OFF");
pos = values[3];
battremain = strtol(dstate_getinfo("ups.power.nominal"),NULL,10)
* (strtod(pos,NULL)/100);
/* Figure out runtime minutes */
rminutes = strtod(dstate_getinfo("ups.runtime"),NULL) *
((battremain * ( 1 - (strtod (values[2],NULL) / 100 ))) /
strtol(dstate_getinfo("ups.power.nominal"),NULL,10));
rseconds = ((int)(rminutes*100) - ((int)rminutes)*100) * 0.6 ;
dstate_setinfo("input.voltage", "%g", strtod(values[0],NULL));
dstate_setinfo("output.voltage", "%g", strtod(values[1],NULL));
dstate_setinfo("ups.load", "%li", strtol(values[2],NULL,10));
dstate_setinfo("input.frequency", "%g", strtod(values[5],NULL));
dstate_setinfo("ups.temperature", "%li", strtol(values[4],NULL,10));
dstate_setinfo("battery.charge", "%02.1f", strtod(values[3],NULL));
dstate_setinfo("battery.runtime", "%2.0f:%02d", rminutes, rseconds);
status_commit();
dstate_dataok();
return 0;
}
static void ups_ident(void)
{
char buf[256], *ptr, *com, *model, *rating;
int i;
if (!get_ident(buf, sizeof(buf)))
fatalx("Unable to detect a CyberPower text protocol UPS");
model = rating = NULL;
ptr = buf;
/* Leaving this in place for future */
for (i = 0; i < 2; i++) {
com = strchr(ptr, ',');
if (com)
*com = '\0';
switch (i) {
case 0: model = ptr;
break;
case 1: rating = ptr;
break;
default:
break;
}
if (com)
ptr = com + 1;
}
if (!model)
fatalx("Didn't get a valid ident string");
model_set(model, rating);
}
static void ups_sync(void)
{
char buf[256];
int i, ret;
for (i = 0; i < MAXTRIES; i++) {
ser_send_pace(upsfd, UPSDELAY, "P4\r");
upsdebugx(3, "ups_sync: send [%s]", "\P4\\r");
ret = ser_get_line(upsfd, buf, sizeof(buf), ENDCHAR, "",
SER_WAIT_SEC, SER_WAIT_USEC);
upsdebugx(3, "ups_sync: got ret %d [%s]", ret, buf);
/* return once we get something that looks usable */
if ((ret > 0) && (buf[0] == '#')) {
upsdebugx(3, "ups_sync: got line beginning with #, looks
usable, returning");
return;
}
usleep(250000);
}
fatalx("Unable to detect a CyberPower text protocol UPS");
}
void upsdrv_initinfo(void)
{
int ret;
char temp[256];
ups_sync();
ups_ident();
printf("Detected %s %s on %s\n", dstate_getinfo("ups.mfr"),
dstate_getinfo("ups.model"), device_path);
/* paranoia - cancel any shutdown that might already be running */
ser_send_pace(upsfd, UPSDELAY, "C\r"); /* Need a readback so the
first poll doesn't fail */
ret = ser_get_line(upsfd, temp, sizeof(temp), ENDCHAR, "",
SER_WAIT_SEC, SER_WAIT_USEC);
upsh.instcmd = instcmd;
dstate_setinfo("driver.version.internal", "%s", DRV_VERSION);
dstate_addcmd("test.battery.start");
dstate_addcmd("test.battery.stop");
}
static int ups_on_line(void)
{
int i, ret;
char temp[256];
for (i = 0; i < MAXTRIES; i++) {
ser_send_pace(upsfd, UPSDELAY, "D\r");
ret = ser_get_line(upsfd, temp, sizeof(temp), ENDCHAR, "",
SER_WAIT_SEC, SER_WAIT_USEC);
/* D must return 34 bytes starting with a # */
if ((ret > 0) && (temp[0] == '#') && (strlen(temp) == 34)) {
char * pos = &temp[pollstatusmap[POLL_UPSSTATUS].begin];
if ((*pos & CPS_STAT_OL) && !(*pos & CPS_STAT_OB))
return(1); /* on line */
return 0; /* on battery */
}
sleep(1);
}
upslogx(LOG_ERR, "Status read failed: assuming on battery");
return 0; /* on battery */
}
void upsdrv_shutdown(void)
{
int ret;
char buf[256];
ups_sync();
printf("The UPS will shut down in approximately one minute.\n");
if (ups_on_line())
printf("The UPS will restart in about one minute.\n");
else
printf("The UPS will restart when power returns.\n");
/* Although this is straight from the bestups.c driver, the UPS
* does indeed shutdown correctly. */
ser_send_pace(upsfd, UPSDELAY, "S01R0001\r");
ret = ser_get_line(upsfd, buf, sizeof(buf), ENDCHAR, "",
SER_WAIT_SEC, SER_WAIT_USEC);
if ((ret < 1) || (buf[0] != '#'))
printf ("Warning: got unexpected reply to shutdown command,
shutdown may fail\n");
}
void upsdrv_updateinfo(void)
{
char buf[256];
int ret;
ret = ser_send_pace(upsfd, UPSDELAY, "D\r");
if (ret < 1) {
ser_comm_fail("ser_send_pace failed");
dstate_datastale();
return;
}
/* these things need a long time to respond completely */
usleep(200000);
ret = ser_get_line(upsfd, buf, sizeof(buf), ENDCHAR, "",
SER_WAIT_SEC, SER_WAIT_USEC);
if (ret < 1) {
ser_comm_fail(NULL);
dstate_datastale();
return;
}
if (ret < 34) {
if (ret == 2) /* We need to retry this read right away */
{
ret = ser_get_line(upsfd, buf, sizeof(buf), ENDCHAR, "",
SER_WAIT_SEC, SER_WAIT_USEC);
if (ret < 34) {
ser_comm_fail("Poll failed: short read (got %d bytes)",
ret);
dstate_datastale();
return;
}
} else {
ser_comm_fail("Poll failed: short read (got %d bytes)", ret);
dstate_datastale();
return;
}
}
if (ret > 34) {
upslogx(LOG_INFO, "String too long...");
ser_comm_fail("Poll failed: response too long (got %d bytes)",
ret);
dstate_datastale();
return;
}
if (buf[0] != '#') {
ser_comm_fail("Poll failed: invalid start character (got %02x)",
buf[0]);
dstate_datastale();
return;
}
ser_comm_good();
scan_poll_values(buf);
status_init();
}
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);
}
_______________________________________________
Nut-upsuser mailing list
[email protected]
http://lists.alioth.debian.org/mailman/listinfo/nut-upsuser