/*
* $Id: apc.c,v 2.0.1.5 1996/06/26 18:39:38 alexis Exp alexis $
*
* UPS Daemon
* The Wild Wind Communications, 1995, 1996
*
* See file LICENSE for the distribution terms of this software.
*/
#include "upsd.h"
#include "apc.h"
char apc_SmartWriteBuffer[MAXAPCWRITEBUFFER];
/*
* Polls APC SmartUPS value.
*
* Returns -1 on error, 1 if timed out or 0 if succeeded.
*/
int
apc_poll(val)
struct ups_val *val;
{
register int s;
char *t;
struct ups_reg *r;
if((r = REGISTERID(val->id)) == NULL) {
syslog(LOG_ERR, "apc_poll: incorrect register id");
return -1;
}
if((t = alloca(POLLBUFLEN)) == NULL) {
syslog(LOG_ERR, "apc_poll: alloca failed: %m");
return -1;
}
for(;;) {
flushport();
if((s = writeport(r->cmd_data, r->cmd_size)) != r->cmd_size) {
return -1; /* Can't write to the port. */
}
if(r->size == 0) {
return 0; /* We don't expect anything back. */
}
if((s = readport(t, r->size, 1)) == -1) {
return -1; /* Can't read the port. */
};
if(s != r->size) {
return 1; /* Timed out on readport. */
};
switch(r->type) {
case T_BINARY:
bcopy(t, val->val.binary, (size_t) r->size - r->prec);
((char *)val->val.binary)[r->size - r->prec] = '\0'; /* XXX: correct? */
return 0;
/* NOTREACHED */
case T_HEX:
val->val.number = (double)strtol(t, (char **)NULL, 16);
return 0;
/* NOTREACHED */
case T_DEC:
val->val.number = (double)strtol(t, (char **)NULL, 10);
return 0;
/* NOTREACHED */
case T_OCT:
val->val.number = (double)strtol(t, (char **)NULL, 8);
return 0;
/* NOTREACHED */
case T_NUMBER:
val->val.number = strtod(t, (char **)NULL);
return 0;
/* NOTREACHED */
default:
syslog(LOG_ERR, "apc_poll: incorrect value type");
return -1;
/* NOTREACHED */
}
/* NOTREACHED */
}
/* NOTREACHED */
return -1;
}
/*
* Tunes the value of APC SmartUPS.
*
* Returns -1 upon error, 1 if the string was not toggled, and zero
* if succeeded.
*/
int
apc_tune(val)
struct ups_val *val;
{
register struct ups_reg *r, *tr;
struct ups_val v0, v1, t;
if((r = REGISTERID(val->id)) == NULL) {
syslog(LOG_ERR, "apc_tune: incorrect value id to tune");
return -1;
}
switch(r->mode) {
case APC_TOGGLE:
t.id = SMART_MODIFY;
if((tr = REGISTERID(t.id)) == NULL) {
syslog(LOG_ERR, "apc_tune: cannot find modify register");
return -1;
}
if((t.val.binary = alloca(tr->size)) == NULL) {
syslog(LOG_ERR, "apc_tune: cannot allocate memory in stack for modifier: %m");
return -1;
}
v0.id = v1.id = r->id;
if((r->type & T_TYPE) == T_BINARY) {
if(((v0.val.binary = alloca(r->size)) == NULL) ||
((v1.val.binary = alloca(r->size)) == NULL)) {
syslog(LOG_ERR, "apc_tune: cannot allocate memory in stack for new values: %m");
return -1;
}
}
switch(apc_poll(&v0)) {
case 1:
return 1;
case -1:
return -1;
}
if((r->type & T_TYPE) == T_BINARY) {
bcopy(v0.val.binary, v1.val.binary, r->size);
} else {
v1.val.number = v0.val.number;
}
for(;;) {
if((r->type & T_TYPE) == T_BINARY) {
if(!bcmp(val->val.binary, v1.val.binary, r->size)) {
return 0;
}
} else {
if(val->val.number == v1.val.number) {
return 0;
}
}
switch(apc_poll(&t)) {
case 1:
return 1;
case -1:
return -1;
}
if(bcmp(t.val.binary, apc_SmartUPS_OK, 2)) {
syslog(LOG_ERR, "apc_tune: negative response: %*s",
r->size, t.val.binary);
return 1;
}
switch(apc_poll(&v1)) {
case 1:
return 1;
case -1:
return -1;
}
if((r->type & T_TYPE) == T_BINARY) {
if(!bcmp(v1.val.binary, v0.val.binary, r->size)) {
syslog(LOG_WARNING, "apc_tune: toggle wraparound register %s", r->name);
return 1;
}
} else {
if(v1.val.number == v0.val.number) {
syslog(LOG_WARNING, "apc_tune: toggle wraparound register %s", r->name);
return 1;
}
}
}
/* NOTREACHED */
break; /* APC_TOGGLE */
case APC_WRITE:
if((r->type & T_TYPE) != T_BINARY) {
syslog(LOG_ERR, "apc_tune: only binary values can be overwritten");
return -1;
}
t.id = SMART_WRITE;
if((tr = REGISTERID(t.id)) == NULL) {
syslog(LOG_ERR, "apc_tune: cannot find write register");
return -1;
}
if((t.val.binary = alloca(tr->size)) == NULL) {
syslog(LOG_ERR, "apc_tune: cannot allocate memory in stack for modifier: %m");
return -1;
}
v0.id = r->id;
if((v0.val.binary = alloca(r->size)) == NULL) {
syslog(LOG_ERR, "apc_tune: cannot allocate memory in stack for new value: %m");
return -1;
}
switch(apc_poll(&v0)) {
case 1:
return 1;
case -1:
return -1;
}
if(!bcmp(v0.val.binary, val->val.binary, r->size - r->prec)) {
return 0;
}
apc_SmartWriteBuffer[0] = '-';
bcopy(val->val.binary, &apc_SmartWriteBuffer[1], r->size);
tr->cmd_size = r->size - r->prec + 1;
switch(apc_poll(&t)) {
case 1:
return 1;
case -1:
return -1;
}
if(bcmp(t.val.binary, apc_SmartUPS_OK, 2)) {
syslog(LOG_ERR, "apc_tune: negative response");
return 1; /* the response was not OK */
}
{
struct timeval wd = APCWRITEDELAY;
(void) select(0, NULL, NULL, NULL, &wd);
}
return 0;
/* NOTREACHED */
break; /* MTHD_WRITE */
default:
syslog(LOG_ERR, "apc_tune: this register cannot be modified");
return -1;
/* NOTREACHED */
}
/* NOTREACHED */
return -1;
}
syntax highlighted by Code2HTML, v. 0.9.1