Logo Search packages:      
Sourcecode: nut version File versions

isbmex.c

/* isbmex.c - model specific routines for SOLA/BASIC Mexico (ISBMEX) models

   Copyright (C) 2005 Ricardo Martinezgarza <ricardo@nexxis.com.mx>
   Copyright (C) 2002 Edscott Wilson Garcia <edscott@imp.mx>
   Copyright (C) 1999 Russell Kroll <rkroll@exploits.org>

   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

*/

#include "main.h"
#include "serial.h"
#include "isbmex.h"

#include <math.h>       /* for sqrt */
#include <string.h>

#define xDEBUG

#ifdef DEBUG
#define D(x) x
#else
#define D(x)
#endif

/*#define ENDCHAR '&'*/
#define MAXTRIES 15
/* #define IGNCHARS     ""    */

float lagrange(unsigned int vbyte)
{
      float f0, f1, f2, f3, f4, f5, f6;
      float a, b, c, d, e, g, h;
      const float x0=144.0, x1=154.0, x2=184.0, x3=195.0, x4=215.0, x5=228.0, x6=249.0;
      const float fX0=95.1, fX1=98.3, fX2=112.6, fX3=116.5, fX4=126.0, fX5=131.0, fX6=140.3;

      if(vbyte < 144) return 0.0;

      f0 = vbyte - x0;
      f1 = vbyte - x1;
      f2 = vbyte - x2;
      f3 = vbyte - x3;
      f4 = vbyte - x4;
      f5 = vbyte - x5;
      f6 = vbyte - x6;

      b = (f1 * f2 * f3 * f4 * f5 * f6 * fX0)/((x0 - x1) * (x0 - x2));
      b = b / ((x0 - x3) * (x0 - x4));
      b = b / ((x0 - x5) * (x0 - x6));

      c = (f0 * f2 * f3 * f4 * f5 * f6 * fX1)/((x1 - x0) * (x1 - x2));
      c = c / ((x1 - x3) * (x1 - x4));
      c = c / ((x1 - x5) * (x1 - x6));

      d = (f0 * f1 * f3 * f4 * f5 * f6 * fX2)/((x2 - x0) * (x2 - x1));
      d = d / ((x2 - x3) * (x2 - x4));
      d = d / ((x2 - x5) * (x2 - x6));

      e = (f0 * f1 * f2 * f4 * f5 * f6 * fX3)/((x3 - x0) * (x3 - x1));
      e = e / ((x3 - x2) * (x3 - x4));
      e = e / ((x3 - x5) * (x3 - x6));

      a = (f0 * f1 * f2 * f3 * f5 * f6 * fX4)/((x4 - x0) * (x4 - x1));
      a = a / ((x4 - x2) * (x4 - x3));
      a = a / ((x4 - x5) * (x4 - x6));

      g = (f0 * f1 * f2 * f3 * f4 * f6 * fX5)/((x5 - x0) * (x5 - x1));
      g = g / ((x5 - x2) * (x5 - x3));
      g = g / ((x5 - x4) * (x5 - x6));

      h = (f0 * f1 * f2 * f3 * f4 * f5 * fX6)/((x6 - x0) * (x6 - x1));
      h = h / ((x6 - x2) * (x6 - x3));
      h = h / ((x6 - x4) * (x6 - x5));

      return a + b + c + d + e + g + h;
}

float interpol(float vbytes)
{
      const int x[7]={75,83,87,98,103,118,145};
      const float f[7]={96.0,102.0,105.0,113.0,116.0,124.0,140.0};
      float l[7];
      float t, volts;
      const int n=6;
      int i, j;

      if(vbytes < x[0]) return 0.0;
      if(vbytes > x[6]) return f[6];
      for(i=0; i<=n; i++)
      {
            if((int)vbytes == x[i]) return f[i];
      }
      for(i=0; i<=n; i++)
      {
            l[i] = 1.0;
            for(j=0; j<=n; j++)
            {
                  if(j!=i) l[i] *= (float)(x[i] - x[j]);
            }
            l[i] = f[i] / l[i];
      }
      t = 1.0;
      for(i=0; i<=n; i++) t *= (vbytes - (float)x[i]);
      volts = 0.0;
      for(i=0; i<=n; i++) volts += (l[i] * t / (vbytes - (float)x[i]));
      return volts;
}

void upsdrv_initinfo(void)
{
      dstate_setinfo("ups.mfr", "Sola/Basic Mexico");
      dstate_setinfo("ups.model", "SR-Inet 280/300/400/480/500/800/1000");

      /* high/low voltage */
      dstate_setinfo("input.transfer.low", "102.0");  /* defined */
      dstate_setinfo("input.transfer.high", "140.0"); /* defined */

      dstate_setinfo("output.voltage", "120.0");      /* defined */
       
       /* addinfo(INFO_, "", 0, 0); */
       /*printf("Using %s %s on %s\n", getdata(INFO_MFR), getdata(INFO_MODEL), device_path);*/

      dstate_setinfo("driver.version.internal", "%s", DRV_VERSION);
}

static const char *getpacket(int *we_know){
  fd_set readfds;
  struct timeval tv;
  int bytes_per_packet=0;
  int ret;
  static const char *packet_id=NULL;
  static char buf[256];
  const char *s;
  ssize_t r;

  
  bytes_per_packet=*we_know;
  D(printf("getpacket with %d\n",bytes_per_packet);)
  
  FD_ZERO(&readfds);
  FD_SET(upsfd,&readfds);
      /* Wait up to 2 seconds. */
  tv.tv_sec = 5;
  tv.tv_usec = 0;
 
  ret=select(upsfd+1,  &readfds, NULL, NULL, &tv);
  if (!ret) {
      s="Nothing received from UPS. Check cable conexion";
      upslogx(LOG_ERR, "%s", s);
      D(printf("%s\n",s);)
      return NULL;
  }

  r=read(upsfd,buf,255);
  D(printf("%d bytes read: ",r);)
  buf[r]=0;
  if (bytes_per_packet && r < bytes_per_packet){
           ssize_t rr;
           D(printf("short read...\n");)
           usleep(500000);
             tv.tv_sec = 2;
             tv.tv_usec = 0;
             ret=select(upsfd+1,  &readfds, NULL, NULL, &tv);
             if (!ret) return NULL;
           rr=read(upsfd,buf+r,255-r);
           r += rr;
           if (r < bytes_per_packet) return NULL;
  }
           
  if (!bytes_per_packet){ /* packet size determination */ 
       /* if (r%10 && r%9) {
         printf("disregarding incomplete packet\n");
         return NULL;
      }*/
      if (r%10==0) *we_know=10;
      else if (r%9==0)  *we_know=9;
      return NULL;
  }
     
     /* by here we have bytes_per_packet and a complete packet */
     /* lets check if within the complete packet we have a valid packet */
 if (bytes_per_packet == 10) packet_id="&&&";  else  packet_id="***";
 s=strstr(buf,packet_id);
     /* check validity of packet */
 if (!s) {
      s="isbmex: no valid packet signature!";
      upslogx(LOG_ERR, "%s", s);
      D(printf("%s\n",s);)
      *we_know=0;
      return NULL;
 }
 D(if (s != buf) printf("overlapping packet received\n");)
 if ((int) strlen(s) < bytes_per_packet) {
                D(printf("incomplete packet information\n");)
                return NULL; 
 }
#ifdef DEBUG
    printf("Got signal:");
    {int i;for (i=0;i<strlen(s);i++) printf(" <%d>",(unsigned char)s[i]);}
    printf("\n");
#endif
    
 return s;
}

void upsdrv_updateinfo(void)
{
  static  float high_volt=-1, low_volt=999;
  const char      *buf=NULL;
  char buf2[17];
  int i;
  static int bytes_per_packet=0;

  for (i=0;i<5;i++) {
        if ((buf=getpacket(&bytes_per_packet)) != NULL) break;
  }
  if (!bytes_per_packet || !buf) {
      dstate_datastale();
      return;
  }
        
  /* do the parsing */
  {
     float in_volt,battpct,acfreq;
     double d;
     D(printf("parsing (%d bytes per packet)\n",bytes_per_packet);)
     /* input voltage :*/
     if (bytes_per_packet==9) {
       in_volt = lagrange((unsigned char)buf[3]);    
     } else {
       in_volt = interpol(sqrt((float)((unsigned char)buf[3]*256+(unsigned char)buf[4])));    
     }
     snprintf(buf2,16,"%5.1f",in_volt);
     D(printf("utility=%s\n",buf2);)
     dstate_setinfo("input.voltage", "%s", buf2);     
     
     if (in_volt >= high_volt) high_volt=in_volt;
     snprintf(buf2,16,"%5.1f",high_volt);
     D(printf("highvolt=%s\n",buf2);)
     dstate_setinfo("input.voltage.maximum", "%s", buf2);       
     
     if (in_volt <= low_volt)  low_volt=in_volt;
     snprintf(buf2,16,"%5.1f",low_volt);
     D(printf("lowvolt=%s\n",buf2);)
     dstate_setinfo("input.voltage.minimum", "%s", buf2);      
 
     battpct = ((double)((unsigned char)buf[(bytes_per_packet==10)?5:4])-168.0)*(100.0/(215.0-168.0));
     snprintf(buf2,16,"%5.1f",battpct);
     D(printf("battpct=%s\n",buf2);)
     dstate_setinfo("battery.charge", "%s", buf2);    
 
     d=(unsigned char)buf[(bytes_per_packet==10)?6:5]*256
           + (unsigned char)buf[(bytes_per_packet==10)?7:6];    
     acfreq = 1000000/d;
     snprintf(buf2,16,"%5.2f",acfreq);
     D(printf("acfreq=%s\n",buf2);)
     dstate_setinfo("input.frequency", "%s", buf2);    

     D(printf("status: ");)
     status_init();
     switch (buf[(bytes_per_packet==10)?8:7]){
       case 48: break; /* normal operation */
       case 49: D(printf("BOOST ");)
              status_set("BOOST");
              break;
       case 50: D(printf("TRIM ");)
              status_set("TRIM");
       default: break;
     }
     switch (buf[(bytes_per_packet==10)?9:8]){
       case 48: D(printf("OL ");)
              status_set("OL");
              break; 
       case 50: D(printf("LB ");)
              status_set("LB");
       case 49: D(printf("OB ");)
              status_set("OB");
              break;
       default: break;
     }
     D(printf("\n");)
     status_commit();        
                          
           
   } 
   dstate_dataok();
   return;
}

void upsdrv_shutdown(void)
{
      /* shutdown is supported on models with
       * contact closure. Some ISB models with serial
       * support support contact closure, some don't.
       * If yours does support it, then a 12V signal
       * on pin 9 does the trick (only when ups is 
       * on OB condition) */
      /* 
       * here try to do the pin 9 trick, if it does not
       * work, else:*/
/*    fatalx(EXIT_FAILURE, "Shutdown only supported with the Generic Driver, type 6 and special cable");  */
      /*fatalx(EXIT_FAILURE, "shutdown not supported");*/
      int i, ret;
      for(i=0;i<=5;i++)
      {
            ret = ser_send_char(upsfd, '#');
            usleep(50000);
      }
}


void upsdrv_help(void)
{
}

/* list flags and values that you want to receive via -x */
void upsdrv_makevartable(void)
{
}

void upsdrv_banner(void)
{
      printf("Network UPS Tools - ISBMEX UPS driver %s (%s)\n\n",
            DRV_VERSION, UPS_VERSION);
}

void upsdrv_initups(void)
{
      upsfd = ser_open(device_path);
      ser_set_speed(upsfd, device_path, B9600);
}

void upsdrv_cleanup(void)
{
      ser_close(upsfd, device_path);
}

Generated by  Doxygen 1.6.0   Back to index