/*
  Monitor Best Fortress UPS

  init_port(char *tty)                initialize tty port
  close_port()                        close down tty port

  fatal(char *message)                display a message and then die()
  die()                               print last error and then halt
*/

#define TTY                "/dev/tty05"
#define MONITOR_INTERVAL   60    /* seconds */
#define LOG_FILE           "/var/log/ups.log"

#include <stdio.h>
#include <sys/types.h>
#include <time.h>
#include <sys/time.h>
#include <fcntl.h>
#include <signal.h>

#include <termios.h>
#include <sys/ioctl.h>
#define TCGETS TIOCGETA
#define TCSETS TIOCSETA

extern int errno;

int ftty;       /* tty file descriptor  */
FILE *tfp;
FILE *logp;

char status[128];

int ac_input_volts;
int ac_output_volts;
float battery_volts;
int temperature;
float ac_output_amps;
int ac_load_va;
int runtime;

void boing();

main()
{
  init_port(TTY);
  open_log();
  signal(SIGALRM,boing);
  boing();
  for (;;)
  {
    if (fgets(status,128,tfp) == NULL)
    {
      fprintf(logp,"fgets failed\n");
      continue;
    }
    if (strlen(status) == 82)
      process_status();
    else if (*status == '{')
      process_alarm();    
    else if (*status == '[')
      process_alarm();    
  }
  close_port();
}

open_log()
{
  if ((logp = fopen(LOG_FILE,"a")) == NULL)
  {
    fprintf(stderr,"monups: can't open log file %s\n",LOG_FILE);
    exit(1);
  }
}


process_status()
{
  char buf[16];
  time_t now;

/* 
***************** test checksum
 */


  strncpy(buf,status+24,4); buf[4] = '\0';
  ac_input_volts = atoi(buf);
  strncpy(buf,status+28,4); buf[4] = '\0';
  ac_output_volts = atoi(buf);
  strncpy(buf,status+36,4); buf[4] = '\0';
  ac_output_amps = atoi(buf) / 10.0;
  strncpy(buf,status+40,6); buf[6] = '\0';
  ac_load_va = atoi(buf);
  strncpy(buf,status+50,4); buf[4] = '\0';
  battery_volts = atoi(buf) / 10.0;
  strncpy(buf,status+58,4); buf[4] = '\0';
  runtime = atoi(buf);
  strncpy(buf,status+62,4); buf[4] = '\0';
  temperature = atoi(buf);


  time(&now);
  fprintf(logp,"%.15s ",ctime(&now)+4);
  fprintf(logp,"in %03dV out %03dV ",ac_input_volts,ac_output_volts);
  fprintf(logp,"out %04.1fA load %03dVA ",ac_output_amps,ac_load_va);
  fprintf(logp,"bat %03.1fV run %02d temp %02dC",
	 battery_volts,runtime,temperature);
  fprintf(logp,"\n");
  fflush(logp);
}

process_alarm()
{
  time_t now;

  time(&now);
  fprintf(logp,"%.15s ",ctime(&now)+4);
  fprintf(logp,"alarm %s\n",status);
  fflush(logp);
}

void boing()
{
  struct itimerval tv;

  fprintf(tfp,"f\r"); fflush(tfp);

  /* set next alarm */
  tv.it_interval.tv_sec = MONITOR_INTERVAL;
  tv.it_interval.tv_usec = 0;
  tv.it_value.tv_sec = MONITOR_INTERVAL;
  tv.it_value.tv_usec = 0;
  setitimer(ITIMER_REAL,&tv,NULL);
}


/*
 Initialize or open comm port
 Arg is tty or port designation string.
*/
init_port(tty)
  char *tty;
{
  struct termios ttyargs;

  if ((ftty = open(tty,O_RDWR)) == -1)
  {
    fprintf(stderr,"?Can't open tty '%s'.\n",tty);
    die();
  }

  if ((ioctl(ftty, TCGETS, (char *) &ttyargs)) == -1)
  {
    fprintf(stderr,"?Can't do ioctl TCGETS on tty '%s'.\n",tty);
    die();
  }
  ttyargs.c_iflag = 0;
  ttyargs.c_oflag = 0;
  ttyargs.c_cflag = (CS8 | CREAD | CLOCAL);
  ttyargs.c_ispeed = B1200;
  ttyargs.c_ospeed = B1200;
  ttyargs.c_lflag = 0;
  if ((ioctl(ftty, TCSETS, (char *) &ttyargs)) == -1)
  {
    fprintf(stderr,"?Can't do ioctl TSETS on tty '%s'.\n",tty);
    die();
  }
  if ((tfp = fdopen(ftty,"r+")) == NULL)
  {
    fprintf(stderr,"?Can't fdopen tty '%s'.\n",tty);
    die();
  }
}

/* close tty port */
close_port()
{
  fclose(tfp);
}


fatal(line)
  char *line;
{
  fprintf(stderr,"?%s\n",line);
  die();
}

die()
{
  if (errno)
    perror("Last error");
  exit(1);
}
