ref: 4c00d0c740471b7310e3fb7348f9b3562944f70a
dir: /main.c/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <thread.h>
#include <usb.h>
typedef struct Ups Ups;
struct Ups
{
Dev *ctrl;
Dev *intr;
Biobuf *out;
char *id;
uint va;
uint ncpus;
uint nmaps;
uint nalarms;
uint cfgblksz;
uint statmapsz;
uint almlogsz;
uint evtlogsz;
uint topblksz;
uint cmdlstsz;
uint outblksz;
uint almblksz;
};
static void
usage(void)
{
fprint(2, "usage: %s dev\n", argv0);
threadexitsall("usage");
}
static uchar
chksum(uchar *buf)
{
int i;
uchar c;
c = 0;
for(i = 0; i < buf[1]+2; i++)
c -= buf[i];
return c;
}
static int
setdesc(Dev *d, int val, int idx, uchar *buf, int len)
{
return usbcmd(d, Rh2d|Rstd|Rdev, Rsetdesc, (val<<8)+idx, 0, buf, len);
}
static int
sendrdcmd(Dev *d, uchar cmd)
{
uchar buf[4];
buf[0] = 0xab;
buf[1] = 1;
buf[2] = cmd;
buf[3] = chksum(buf);
return setdesc(d, Dstr, 4, buf, 4);
}
static int
validpkt(uchar *pkt)
{
int i;
uchar c;
c = 0;
for(i = 0; i < 5+pkt[2]; i++)
c += pkt[i];
return c == 0;
}
static int
readresp(Biobuf *bio, uchar cmd, uchar *buf, int buflen)
{
uchar sum, seq;
int c, pktlen;
uchar *bp, *bend;
bp = buf;
bend = buf + buflen;
Next:
for(;;){
if((c = Bgetc(bio)) < 0)
return -1;
if(c == 0xab)
break;
}
sum = 0xab;
if((c = Bgetc(bio)) < 0)
return -1;
if(c != cmd - 0x30)
goto Next;
sum += c;
if((c = Bgetc(bio)) < 0)
return -1;
pktlen = c;
sum += c;
if((c = Bgetc(bio)) < 0)
return -1;
seq = c;
sum += c;
while(pktlen-- > 0){
if(bp >= bend)
return -1;
if((c = Bgetc(bio)) < 0)
return -1;
*bp++ = c;
sum += c;
}
if((c = Bgetc(bio)) < 0)
return -1;
sum += c;
if(sum != 0)
return -1;
if((seq & 0x80) == 0)
goto Next;
return bp - buf;
}
int
pwread(Ups *ups, uchar cmd, uchar *buf, int len)
{
if(sendrdcmd(ups->ctrl, cmd) < 0)
return -1;
return readresp(ups->out, cmd, buf, len);
}
static int
sendwrcmd(Dev *d, uchar *cmd, int cmdlen)
{
uchar buf[128];
buf[0] = 0xab;
buf[1] = cmdlen;
memmove(&buf[2], cmd, cmdlen);
*(buf+2+cmdlen) = chksum(buf);
return setdesc(d, Dstr, 4, buf, 2+cmdlen+1);
}
static char*
overallstatus(uchar v)
{
switch(v){
case 0xF0:
return "ON BATTERY";
case 0xE0:
return "OUTPUT OVERLOAD";
case 0xD0:
return "RECTIFIER OVERLOAD";
case 0x90:
return "INVERTER RAMPING UP";
case 0x80:
return "SYNCING TO BYPASS";
case 0x70:
return "RECTIFIER RAMPING";
case 0x64:
return "ON MAINTENANCE BYPASS";
case 0x63:
return "ON BUCK/REDUCER";
case 0x62:
return "ON BOOST/STEP UP";
case 0x61:
return "ON DOUBLE BOOST";
case 0x60:
return "ON BYPASS";
case 0x51:
return "HIGH EFFICIENCY MODE";
case 0x50:
return "SYSTEM NORMAL";
case 0x40:
return "UPS SUPPORTING LOAD";
case 0x30:
return "UPS ON";
case 0x21:
return "OUTLET SWITCH OPEN";
case 0x20:
return "OUTLET BREAKER OPEN";
case 0x11:
return "MODULE FAILURE";
case 0x10:
return "UPS OFF";
default:
break;
}
return "UNKNOWN";
}
static char *topbits[8] = {
"bypass-installed",
"output-breaker-closed",
"on-bypass",
"on-battery",
"inverter-on",
"low-battery",
"rectifier-on",
"utility-present",
};
static char*
topologystr(uchar v)
{
static char buf[1024];
int i;
char *s, *e;
s = buf;
e = buf + sizeof(buf);
*s = 0;
for(i = 0; i < 8; i++){
if((v&(1<<i)) == 0)
continue;
s = seprint(s, e, ",%s", topbits[i]);
}
return buf+1;
}
static ushort
getu16(uchar *b)
{
ushort s;
s = b[1];
s <<= 8;
s |= b[0];
return s;
}
static void
init(Ups *ups)
{
int i, n;
uint v;
uchar buf[4096];
n = pwread(ups, 0x31, buf, sizeof(buf));
if(n < 0)
sysfatal("pwread: %r");
i = 0;
ups->ncpus = buf[i];
print("#cpus=%uhhd\n", buf[i]);
i += 2*buf[i]+1;
if(buf[i++] != 0){
v = buf[i];
}else{
v = getu16(buf+i);
i += 2;
}
ups->va = 50*v;
print("%udVA\n", ups->va);
//print("%uhhd output phase(s)°\n", buf[i]);
i += 2;
v = buf[i++];
ups->id = mallocz(v+1, 1);
strncpy(ups->id, (char*)buf+i, v);
i += v;
v = buf[i++];
ups->nmaps = v;
print("#maps=%uhhd\n", v);
i += v;
v = buf[i++];
ups->nalarms = v;
print("#alarms=%uhhd\n", v);
i += v;
v = getu16(buf+i);
ups->cfgblksz = v;
print("%uhd byte config block\n", v);
i += 2;
v = buf[i];
ups->statmapsz = v;
print("%uhhd byte statistics map\n", v);
i += buf[i] + 1;
v = getu16(buf+i);
ups->almlogsz = v;
print("%ud byte alarm log\n", v);
i += 2;
v = getu16(buf+i);
ups->evtlogsz = v;
print("%ud byte custom event log\n", v);
i += 2;
v = getu16(buf+i);
ups->topblksz = v;
print("%ud byte topology block\n", v);
i += 2;
i += 1;
v = getu16(buf+i);
ups->cmdlstsz = v;
print("%ud byte command list block\n", v);
i += 2;
v = getu16(buf+i);
ups->outblksz = v;
print("%ud byte outlet monitoring block\n", v);
i += 2;
v = getu16(buf+i);
ups->almblksz = v;
print("%ud byte alarm block\n", v);
i += 2;
assert(i == n);
}
static void
stats(Ups *ups)
{
int n;
uchar buf[128];
n = pwread(ups, 0x40, buf, sizeof(buf));
if(n < 0)
sysfatal("pwread: %r");
/*
fprint(2, "#cmds=%uhhd\n", buf[0]);
for(i = 0; i < n; i++){
fprint(2, "cmd[%d] = 0x%uhhx\n", i, buf[2+i]);
}
*/
n = pwread(ups, 0x33, buf, sizeof(buf));
if(n < 0)
sysfatal("pwread: %r");
print("Overall Status: %s\n", overallstatus(buf[0]));
print("Topology Status: %s\n", topologystr(buf[1]));
n = pwread(ups, 0x34, buf, sizeof(buf));
if(n < 0)
sysfatal("pwread: %r");
}
void
threadmain(int argc, char **argv)
{
int i;
Ups ups;
Ep *ep;
Usbdev *ud;
ARGBEGIN{
default:
usage();
}ARGEND;
if(argc != 1)
usage();
ups.ctrl = getdev(*argv);
if(ups.ctrl == nil)
sysfatal("getdev: %r");
ud = ups.ctrl->usb;
ups.intr = nil;
for(i = 0; i < nelem(ud->ep); i++){
if((ep = ud->ep[i]) == nil)
continue;
if(ep->type == Eintr && ep->dir == Ein)
ups.intr = openep(ups.ctrl, ep);
}
if(ups.intr == nil)
sysfatal("could not find interrupt endpoint");
if(opendevdata(ups.intr, OREAD) < 0)
sysfatal("could not open interrupt endpoint: %r");
ups.out = Bfdopen(ups.intr->dfd, OREAD);
if(ups.out == nil)
sysfatal("open: %r");
//init(&ups);
stats(&ups);
}