[Nut-upsdev] ups emerson liebert GTX2 ESP-II serial protocol demo
Arnaud Quette
arnaud.quette at free.fr
Mon Jan 26 09:42:24 UTC 2009
2009/1/22 Spiros Ioannou <sivann at gmail.com>
> Cher Arnaud,
>
Hi Spiros,
> I send you a demo that reads info from an Emerson Liebert
> GXT2-10000T230 through the RS-232 port. This uses the "ESP-II (ESP 2)
> Protocol".
> Current supported data includes: measurements (voltage, temperature,
> etc) , ID strings (serial number, etc), status flags (inverter on,
> bypas on, battery charging, etc).
> As usual, the original vendor software is in java (Multilink), and really
> sucks.
> I saw in your acknowledgment pages that you have "serial test boxes"
> donated from liebert.
>
well, that donation was to Russell, and goes back many many years ago...
> The program I send you is more complicated than needed, to be able to
> support more commands in the future.
>
> 1) Can you make the driver?
> 2) if not, can you point me to a similar driver that I can copy?
>
> the protocol seems to include a lot more of useless status commands,
> unsupported by my ups, but these seem more than enough for a start.
>
well, I personally won't make the driver (no hardware and no time).
but we can help you in doing one, and it's not that hard.
have a look at the following docs:
http://svn.debian.org/wsvn/nut/trunk/docs/new-drivers.txt?op=file&rev=0&sc=0
http://svn.debian.org/wsvn/nut/trunk/drivers/skel.c?op=file&rev=0&sc=0
creating a new serial driver is not really hard, really!
I've seen in the header that you based your work on this:
http://www.csc.liv.ac.uk/~greg/projects/liebertserial/
maybe the author would help you, or join the project?
cheers,
Arnaud
--
Linux / Unix Expert R&D - Eaton - http://www.eaton.com/mgeops
Network UPS Tools (NUT) Project Leader - http://www.networkupstools.org/
Debian Developer -
http://people.debian.org/~aquette/<http://people.debian.org/%7Eaquette/>
Free Software Developer - http://arnaud.quette.free.fr/
sample output:
>
> BATTERY_TIME_REMAIN: 52.0
> BATTERY_VOLTAGE: 263.0
> BATTERY_VOLTAGE_NOMINAL: 275.0
> BATTERY_CURRENT: 0.0
> BATTERY_CAPACITY: 100.0
> BYPASS_VOLTAGE: 231.0
> MAX_LOAD: 10000.0
> LOAD_WATTS: 1033.0
> LOAD_VA: 1245.0
> LOAD_PERCENT: 14.0
> INPUT_FREQUENCY: 49.9
> OUTPUT_FREQUENCY: 49.9
> BYPASS_FREQUENCY: 49.9
> INVERTER_TEMP: 0.0
> BATTERY_TEMP: 0.0
> PFC_TEMP: 0.0
> AMBIENT_TEMP: 25.9
> EXPECTED_RUNTIME: 53.0
> OUTPUT_VOLTAGE: 230.0
> OUTPUT_CURRENT: 5.0
> MODEL_NAME: GXT2-10000T230
> FW_VER: GXT2-00896V04
> SN: 08009R0056BW932
> MANUF_DATE: 04JAN08
> PFC_ON: YES
> DC_DC_CONVERTER_STATE: NO
> ON_INVERTER: YES
> UTILITY_STATE: NO
> INRUSH_LIMIT_ON: NO
> OVERTEMP_WARNING: NO
> BATTERY_TEST_STATE: NO
> INPUT_OVERVOLTAGE: NO
> ON_BATTERY: NO
> ON_BYPASS: NO
> BATTERY_CHARGED: YES
> BATTERY_LIFE_ENHANCER_ON: NO
> REPLACE_BATTERY: NO
> BOOST_ON: NO
> DIAG_LINK_SET: NO
> BUCK_ON: NO
> UPS_OVERLOAD: NO
> BAD_INPUT_FREQ: NO
> SHUTDOWN_PENDING: NO
> CHARGER_FAIL: NO
> LOW_BATTERY: NO
> OUTPUT_UNDERVOLTAGE: NO
> OUTPUT_OVERVOLTAGE: NO
> BAD_BYPASS_PWR: NO
> CHECK_AIR_FILTER: NO
> AMBIENT_OVERTEMP: NO
> MAIN_CONTROL_MODULE_FAILED: NO
> REDUNDANT_CONTROL_MODULE_FAILED: NO
> UI_MODULE_FAILED: NO
> REDUNDANT_POWER_MODULE_ALARM: NO
> REDUNDANT_BATTERY_MODULE_ALARM: NO
> USER_MAX_LOAD_ALARM: NO
> TRANSFORMER_OVERTEMP_ALARM: NO
> INTERNAL_COMMS_LOST: NO
> PWR_MOD_FAILED: NO
> BAT_MOD_FAILED: NO
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.alioth.debian.org/pipermail/nut-upsdev/attachments/20090126/17184d8b/attachment-0001.htm
-------------- next part --------------
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#include <signal.h>
#include <errno.h>
/*
Version 1.0
based on liebert.c from R.Gregory (http://www.csc.liv.ac.uk/~greg/projects/liebertserial/)
Spiros Ioannou, sivann at gmail.com 2009
Compile with: gcc -O2 upsesp2.c -o upsesp2
Run with: ./upsesp2 /dev/ttyS0 Replace ttyS0 with your serial port (ttyS1, ...etc).
*/
#define BAUDRATE B2400
#define _POSIX_SOURCE 1 /* POSIX compliant source */
#define FALSE 0
#define TRUE 1
#define NCMD 100 /*max number of commands*/
#define MAXAGE 5 /*max seconds to accept data as current*/
#define IsBitSet(val, bit) ((val) & (1 << (bit)))
char str[128];
/***************************************************/
typedef struct
{
char descr[120];
unsigned char type; /*0:measurement, 1:ascii, 2:status*/
unsigned char length; /*for ascii, how many cmds*/
unsigned char rfmt; /*unit divider for measurement, bit position for status*/
unsigned char cmd[6]; /*UPS command bytes*/
unsigned char rbyteH; /*msb result*/
unsigned char rbyteL; /*lsb result*/
unsigned char rstr[256]; /*string result from multiple commands (lenght>1)*/
time_t when; /*time of last result*/
unsigned char init; /*used to check if struct block has something valid*/
unsigned char supported; /*if this feature is supported*/
} cmd_s;
//fill struct
//fs(0,&c[0],"lala1", 1,2,3,4,5,6, 11,22,33,44,55,66);
void fs( cmd_s * c,
char * descr,
unsigned char type,
unsigned char length,
unsigned int rfmt,
unsigned int c0, unsigned int c1,
unsigned int c2, unsigned int c3,
unsigned int c4, unsigned int c5)
{
int i;
strcpy(c->descr,descr);
c->cmd[0]=c0;c->cmd[1]=c1;c->cmd[2]=c2;c->cmd[3]=c3;c->cmd[4]=c4;c->cmd[5]=c5;
c->rstr[0]=0;
c->type=type;
c->when=0;
c->rfmt=rfmt;
c->length=length;
c->init=1;
c->supported=1; /*supported until proven otherwise (UPS doesn't repond) */
}
/* Initialize cmd_s structure with UPS commands and expected reply format */
initcmd(cmd_s *c)
{
int i;
/*Format:*/
/*STRINGID, type, length, rfmt, cmd*/
/*length:string length for ascii info*/
/*type:0 measurement, 1: ascii, 2: status */
/*rmft:unit divider (measurement), bit position (status) */
/*cmd: UPS commands. Checksums (last byte) will be recalculated on write */
//measurements
fs(c++,"BATTERY_TIME_REMAIN", 0,0,1, 1,149,2,1,1,161);
fs(c++,"BATTERY_VOLTAGE", 0,0,10, 1,149,2,1,2,161);
fs(c++,"BATTERY_VOLTAGE_NOMINAL", 0,0,10, 1,161,2,1,13,154);
fs(c++,"BATTERY_CURRENT", 0,0,1, 1,149,2,1,3,161);
fs(c++,"BATTERY_CAPACITY", 0,0,1, 1,149,2,1,4,161);
fs(c++,"BYPASS_VOLTAGE", 0,0,10, 1,144,2,1,1,149);
fs(c++,"MAX_LOAD", 0,0,1, 1,161,2,1,8,154);
fs(c++,"LOAD_WATTS", 0,0,1, 1,149,2,1,5,161);
fs(c++,"LOAD_VA", 0,0,1, 1,149,2,1,6,161);
fs(c++,"LOAD_PERCENT", 0,0,1, 1,149,2,1,7,161);
fs(c++,"INPUT_FREQUENCY", 0,0,10, 1,149,2,1,8,161);
fs(c++,"OUTPUT_FREQUENCY", 0,0,10, 1,149,2,1,9,161);
fs(c++,"BYPASS_FREQUENCY", 0,0,10, 1,149,2,1,10,161);
fs(c++,"INVERTER_TEMP", 0,0,10, 1,149,2,1,11,161);
fs(c++,"BATTERY_TEMP", 0,0,10, 1,149,2,1,12,161);
fs(c++,"PFC_TEMP", 0,0,10, 1,149,2,1,13,161);
fs(c++,"AMBIENT_TEMP", 0,0,10, 1,149,2,1,14,161);
fs(c++,"EXPECTED_RUNTIME", 0,0,1, 1,149,2,1,1,154);
fs(c++,"OUTPUT_VOLTAGE", 0,0,10, 1,144,2,1,3,151);
fs(c++,"OUTPUT_CURRENT", 0,0,10, 1,144,2,1,4,154);
//strings
fs(c++,"MODEL_NAME", 1,15,0, 1,136,2,1,4,144);
fs(c++,"FW_VER", 1,8,0, 1,136,2,1,19,144);
fs(c++,"SN", 1,10,0, 1,136,2,1,27,144);
fs(c++,"MANUF_DATE", 1,4,0, 1,136,2,1,37,144);
//status
fs(c++,"PFC_ON", 2,0,0, 1,148,2,1,1,000);
fs(c++,"DC_DC_CONVERTER_STATE", 2,0,1, 1,148,2,1,1,000);
fs(c++,"ON_INVERTER", 2,0,2, 1,148,2,1,1,000);
fs(c++,"UTILITY_STATE", 2,0,3, 1,148,2,1,1,000);
fs(c++,"INRUSH_LIMIT_ON", 2,0,4, 1,148,2,1,1,000);
fs(c++,"OVERTEMP_WARNING", 2,0,5, 1,148,2,1,1,000);
fs(c++,"BATTERY_TEST_STATE", 2,0,6, 1,148,2,1,1,000);
fs(c++,"INPUT_OVERVOLTAGE", 2,0,7, 1,148,2,1,1,000);
fs(c++,"ON_BATTERY", 2,0,8, 1,148,2,1,1,000);
fs(c++,"ON_BYPASS", 2,0,0, 1,148,2,1,2,000);
fs(c++,"BATTERY_CHARGED", 2,0,1, 1,148,2,1,2,000);
fs(c++,"BATTERY_LIFE_ENHANCER_ON", 2,0,4, 1,148,2,1,2,000);
fs(c++,"REPLACE_BATTERY", 2,0,5, 1,148,2,1,2,000);
fs(c++,"BOOST_ON", 2,0,6, 1,148,2,1,2,000);
fs(c++,"DIAG_LINK_SET", 2,0,7, 1,148,2,1,2,000);
fs(c++,"BUCK_ON", 2,0,9, 1,148,2,1,2,000);
fs(c++,"UPS_OVERLOAD", 2,0,0, 1,148,2,1,3,000);
fs(c++,"BAD_INPUT_FREQ", 2,0,1, 1,148,2,1,3,000);
fs(c++,"SHUTDOWN_PENDING", 2,0,2, 1,148,2,1,3,000);
fs(c++,"CHARGER_FAIL", 2,0,3, 1,148,2,1,3,000);
fs(c++,"LOW_BATTERY", 2,0,5, 1,148,2,1,3,000);
fs(c++,"OUTPUT_UNDERVOLTAGE", 2,0,6, 1,148,2,1,3,000);
fs(c++,"OUTPUT_OVERVOLTAGE", 2,0,7, 1,148,2,1,3,000);
fs(c++,"BAD_BYPASS_PWR", 2,0,8, 1,148,2,1,3,000);
fs(c++,"CHECK_AIR_FILTER", 2,0,10, 1,148,2,1,3,000);
fs(c++,"AMBIENT_OVERTEMP", 2,0,2, 1,148,2,1,7,000);
fs(c++,"MAIN_CONTROL_MODULE_FAILED", 2,0,0, 1,148,2,1,19,000);
fs(c++,"REDUNDANT_CONTROL_MODULE_FAILED", 2,0,1, 1,148,2,1,19,000);
fs(c++,"UI_MODULE_FAILED", 2,0,2, 1,148,2,1,19,000);
fs(c++,"REDUNDANT_POWER_MODULE_ALARM", 2,0,3, 1,148,2,1,19,000);
fs(c++,"REDUNDANT_BATTERY_MODULE_ALARM", 2,0,4, 1,148,2,1,19,000);
fs(c++,"USER_MAX_LOAD_ALARM", 2,0,5, 1,148,2,1,19,000);
fs(c++,"TRANSFORMER_OVERTEMP_ALARM", 2,0,6, 1,148,2,1,19,000);
fs(c++,"INTERNAL_COMMS_LOST", 2,0,7, 1,148,2,1,19,000);
fs(c++,"PWR_MOD_FAILED", 2,0,9, 1,148,2,1,19,000);
fs(c++,"BAT_MOD_FAILED", 2,0,10, 1,148,2,1,19,000);
fs(c++,"OPTION_CARD_FAIL_1", 2,0,0, 1,148,2,1,20,000);
fs(c++,"OPTION_CARD_FAIL_2", 2,0,1, 1,148,2,1,20,000);
fs(c++,"OPTION_CARD_FAIL_3", 2,0,2, 1,148,2,1,20,000);
fs(c++,"OPTION_CARD_FAIL_4", 2,0,3, 1,148,2,1,20,000);
fs(c++,"OPTION_CARD_FAIL_5", 2,0,4, 1,148,2,1,20,000);
fs(c++,"OPTION_CARD_FAIL_6", 2,0,5, 1,148,2,1,20,000);
fs(c++,"OPTION_CARD_FAIL_7", 2,0,6, 1,148,2,1,20,000);
fs(c++,"OPTION_CARD_FAIL_8", 2,0,7, 1,148,2,1,20,000);
fs(c++,"SUMMARY_ALARM", 2,0,0, 1,148,2,1,22,000);
fs(c++,"RECT_UV_STARTUP_FAIL", 2,0,0, 1,148,2,1,24,000);
fs(c++,"RECT_FAULT", 2,0,1, 1,148,2,1,24,000);
fs(c++,"RECT_OVER_CURRENT", 2,0,2, 1,148,2,1,24,000);
fs(c++,"RECT_OVER_TEMP", 2,0,3, 1,148,2,1,24,000);
fs(c++,"RECT_INDCTR_OVER_TEMP", 2,0,4, 1,148,2,1,24,000);
fs(c++,"RECT_COMM_FAIL", 2,0,5, 1,148,2,1,24,000);
fs(c++,"INV_SHUTDOWN_LOW_DC", 2,0,6, 1,148,2,1,24,000);
fs(c++,"INV_FAULT", 2,0,7, 1,148,2,1,24,000);
fs(c++,"INV_OVER_CURRENT", 2,0,8, 1,148,2,1,24,000);
fs(c++,"INV_OVER_TEMP", 2,0,9, 1,148,2,1,24,000);
fs(c++,"INV_INDCTR_OVER_TEMP", 2,0,10, 1,148,2,1,24,000);
fs(c++,"INV_COMM_FAIL", 2,0,11, 1,148,2,1,24,000);
fs(c++,"INV_DC_OFFSET_OVR", 2,0,12, 1,148,2,1,24,000);
fs(c++,"INV_CONTACTOR_FAIL", 2,0,13, 1,148,2,1,24,000);
fs(c++,"BAT_FAULT", 2,0,1, 1,148,2,1,25,000);
fs(c++,"BAT_CONTACTOR_FAIL", 2,0,2, 1,148,2,1,25,000);
fs(c++,"CONVERTER_OVER_TEMP", 2,0,4, 1,148,2,1,25,000);
fs(c++,"CONVERTER_OVER_AMPS", 2,0,5, 1,148,2,1,25,000);
fs(c++,"CONVERTER_FAIL", 2,0,6, 1,148,2,1,25,000);
fs(c++,"BALANCER_OVER_TEMP", 2,0,7, 1,148,2,1,25,000);
fs(c++,"BALANCER_FAULT", 2,0,8, 1,148,2,1,25,000);
fs(c++,"BALANCER_OVER_CURRENT", 2,0,9, 1,148,2,1,25,000);
fs(c++,"BY_CB_OPEN", 2,0,10, 1,148,2,1,25,000);
fs(c++,"LOAD_IMPACT_XFER", 2,0,11, 1,148,2,1,25,000);
fs(c++,"OPERATION_FAULT", 2,0,12, 1,148,2,1,25,000);
fs(c++,"OUT_FUSE_BLOWN", 2,0,13, 1,148,2,1,25,000);
fs(c++,"ON_JOINT_MODE", 2,0,14, 1,148,2,1,25,000);
fs(c++,"MAIN_NEUTRAL_LOST", 2,0,4, 1,148,2,1,26,000);
fs(c++,"PARALLEL_LOW_BAT_WARN", 2,0,4, 1,148,2,1,27,000);
fs(c++,"PARALLEL_LOAD_SHARE_FAULT", 2,0,5, 1,148,2,1,27,000);
fs(c++,"PARALLEL_FAULT", 2,0,6, 1,148,2,1,27,000);
fs(c++,"PARALLEL_CONNECT_FAULT", 2,0,7, 1,148,2,1,27,000);
fs(c++,"PARALLEL_COMM_FAIL", 2,0,8, 1,148,2,1,27,000);
fs(c++,"PARALLEL_SYS_OVER_LOAD", 2,0,9, 1,148,2,1,27,000);
fs(c++,"PARALLEL_SYS_XFER", 2,0,10, 1,148,2,1,27,000);
c->init=0; /*on first non-init element */
}
GetCmdCount(cmd_s * c)
{
int i;
for (i=0;(i<NCMD)&&c++->init;i++) ;
return i;
}
//return array position of command "descr"
GetCmdIdbyDesc(cmd_s * c,char *descr)
{
int i;
for (i=0;i<NCMD;i++) {
if (!strcmp(descr,c->descr)) return i;
//printf("%d: c->descr:%s\n",i,c->descr);
c++;
}
return -1;
}
//return array position of the same status command with the most recent data
GetRecentStatusId(cmd_s *c,unsigned char bit4,unsigned int ncmd)
{
int i,r=-1;
time_t maxt=0;
for (i=0;i<ncmd;i++,c++) {
if ((c->cmd[1]!=148) || (c->cmd[4]!=bit4))
continue;
else if (c->when>maxt) {
maxt=c->when;
r=i;
}
}
return r;
}
/***************************************************/
/* print byte in binary*/
void bin_prnt_byte(int x)
{
int n;
for(n=0; n<8; n++)
{
if((x & 0x80) !=0)
printf("1");
else
printf("0");
if (n==3)
printf(" "); /* insert a space between nibbles */
x = x<<1;
}
}
void sgnl_ignore(int status)
{
fprintf(stderr,"Signaled\n");
}
//calculate checksum
unsigned char cksum(unsigned char *buf, int len)
{
unsigned char sum=0;
while(len-->0)
sum+=*buf++;
return(sum);
}
int timedwrite(int fd, unsigned char *buf, int len, int msec)
{
fd_set wfds;
struct timeval tv;
int retval;
int writ=0;
while(writ<len) {
// Watch fd to see when won't block output.
FD_ZERO(&wfds);
FD_SET(fd, &wfds);
tv.tv_sec = msec/1000;
tv.tv_usec = (msec%1000)*1000;
retval = select(fd+1, NULL, &wfds, NULL, &tv);
if( retval>=0 && FD_ISSET(fd, &wfds) )
{
int res = write(fd,buf+writ,len-writ);
if( res>0 )
writ+=res;
else
return(-1);
}
if( retval<=0 )
return(-1);
}
return(writ);
}
int timedread(int fd, unsigned char *buf, int len, int msec)
{
fd_set rfds;
struct timeval tv;
int retval;
int red=0;
while(red<len) {
// Watch fd to see when it has input.
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
tv.tv_sec = msec/1000;
tv.tv_usec = (msec%1000)*1000;
retval = select(fd+1, &rfds, NULL, NULL, &tv);
if( retval>=0 && FD_ISSET(fd, &rfds) )
{
int res = read(fd,buf+red,len-red);
if( res>0 )
red+=res;
else
return(-1);
}
if( retval<=0 )
return(-1);
}
return(red);
}
/* Send a command and read a measurement */
unsigned int SendCmd_M(int fd, unsigned char *cmd, unsigned char *rbyteH, unsigned char *rbyteL)
{
unsigned char buf[8];
cmd[5]=cksum(cmd,5);
//printf("%03d,%03d,%03d,%03d,%03d,%03d\n",cmd[0],cmd[1],cmd[2],cmd[3],cmd[4],cmd[5]);
int res=timedwrite(fd,cmd,6,500);
if(res!=6){
fprintf(stderr,"port write error, cmd:");
fprintf(stderr,"%03d,%03d,%03d,%03d,%03d,%03d\n",cmd[0],cmd[1],cmd[2],cmd[3],cmd[4],cmd[5]);
return -1;
}
res=timedread(fd,buf,8,200);
if(res!=8){
fprintf(stderr,"read count error (%d<>8),cmd:",res);
fprintf(stderr,"%03d,%03d,%03d,%03d,%03d,%03d\n",cmd[0],cmd[1],cmd[2],cmd[3],cmd[4],cmd[5]);
return -1;
}
if(buf[7]!=cksum(buf,7)){
fprintf(stderr,"checksum error for cmd:");
fprintf(stderr,"%03d,%03d,%03d,%03d,%03d,%03d\n",cmd[0],cmd[1],cmd[2],cmd[3],cmd[4],cmd[5]);
return -1;
}
*rbyteH=buf[5];
*rbyteL=buf[6];
return ((unsigned short)buf[5])*256+buf[6];
}
/* Send a series of consecutive commands and read text response (2 chars each)*/
int SendCmd_T(int fd, unsigned char *cmd, unsigned char *chrs, int len)
{
unsigned char buf[8], lcmd[7];
int wres,rres;
memcpy(lcmd,cmd,6);
for(;len>0;len--)
{
lcmd[5]=cksum(lcmd,5);
wres=timedwrite(fd,lcmd,6,400);
if (wres!=6)
return -1;
rres=timedread(fd,buf,8,400);
if (rres!=8)
return -1;
*chrs++=buf[6];
*chrs++=buf[5];
if (buf[7]!=cksum(buf,7))
return -1;
lcmd[4]++;
}
*chrs=0;
return 1;
}
int main(int argc, char **argv)
{
int fd, res, i,j,r;
struct termios oldtio,newtio;
unsigned char buf[255],rbyteH,rbyteL;
unsigned int ncmd;
cmd_s c[NCMD];
initcmd(&c[0]);
ncmd=GetCmdCount(&c[0]);
if(argc!=2) {
fprintf(stderr,"upsesp2 <serial device>\n");
exit(1);
}
fd = open(argv[1], O_RDWR | O_NOCTTY );
if (fd < 0) {
sprintf(str,"%s:%s",argv[1],strerror(errno));
fprintf(stderr,"%s\n",str);
exit(errno);
}
tcgetattr(fd,&oldtio); /* save current port settings */
bzero(&newtio, sizeof(newtio));
newtio.c_cflag = BAUDRATE /*| CRTSCTS*/ | CS8 | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR | IGNBRK;
newtio.c_oflag = 0;
/* set input mode (non-canonical, no echo,...) */
newtio.c_lflag = 0;
newtio.c_cc[VTIME] = 0; /* inter-character timer unused */
newtio.c_cc[VMIN] = 1; /* blocking read until 5 chars received */
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);
signal( SIGALRM, &sgnl_ignore );
while (1) {
for (i=0;i<ncmd;i++) {
//printf("\n***%d:[%03s c0:%03d C1:%03d] init:%03d type:%03d\n",i, c[i].descr,c[i].cmd[0],c[i].cmd[1],c[i].init,c[i].type);
if (c[i].supported==0) { //read failed on 1st try, thus marked as not supported
//printf("UNSUPPORTED item %s:ignoring\n",c[i].descr);
continue;
}
if (c[i].type==0) { //measurement
//todo: check if time is fresh, and if not then SendCmd. Same for strings
res=SendCmd_M(fd, c[i].cmd, &rbyteH, &rbyteL);
if(res>=0) {
c[i].when=time(0);
c[i].rbyteL=rbyteL;
c[i].rbyteH=rbyteH;
printf("%s: %.1f\n",c[i].descr,(256.0*c[i].rbyteH+c[i].rbyteL)/c[i].rfmt);
}
else {
printf("Error getting %s:marking %d as not supported\n",c[i].descr,i);
c[i].supported=0;
}
}
else if (c[i].type==1) { //ascii
res=SendCmd_T(fd, c[i].cmd, buf, c[i].length);
if (res) {
strcpy(c[i].rstr,buf);
c[i].when=time(0);
printf("%s: %s\n",c[i].descr,c[i].rstr);
}
else {
printf("Error getting %s:marking %d as not supported\n",c[i].descr,i);
c[i].supported=0;
}
}
else if (c[i].type==2) { //status
r=GetRecentStatusId(&c[0],c[i].cmd[4],ncmd);
if ((r<0) || (c[i].when-time(0)>MAXAGE)) { //not previous data or old data
res=SendCmd_M(fd, c[i].cmd, &rbyteH, &rbyteL);
if (res>=0) {
c[i].when=time(0);
c[i].rbyteL=rbyteL;
c[i].rbyteH=rbyteH;
if (c[i].rfmt<8) (j=IsBitSet(c[i].rbyteL,c[i].rfmt));
else (j=IsBitSet(c[i].rbyteH,c[i].rfmt) );
if (j) printf("%s: YES\n",c[i].descr);
else printf("%s: NO\n",c[i].descr);
}
else {
printf("Error getting %s:marking %d as not supported\n",c[i].descr,i);
c[i].supported=0;
}
}
else { //found recent data from other poll
if (c[i].rfmt<8) (j=IsBitSet(c[r].rbyteL,c[i].rfmt));
else (j=IsBitSet(c[r].rbyteH,c[r].rfmt) );
if (j) printf("%s: YES\n",c[i].descr);
else printf("%s: NO\n",c[i].descr);
}
}
}
printf("Sleeping....\n\n");
sleep(2);
}
tcsetattr(fd,TCSANOW,&oldtio);
exit(0);
} /* main() */
More information about the Nut-upsdev
mailing list