[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