//------------------------------------------------------------------//
//  freezer.cc                                                      //
//  Latest revision: 06-10-2003                                     //
//------------------------------------------------------------------//

#include "freezer.h"
speed_t BAUDRATE = B300;             
Alarm *a;
Freezer *f;
int ALARM_COUNT=0;
enum{ OFF, READY, RINGING };
const int SLEEPTIME=10;  // seconds between successive readings

int main(void)
{
    int fd[MAX_PORTS];
    initialize_app_globals();
    ////  Open any additional ports here
    fd[0] = open_port(SERIAL_PORT_0);
    fd[1] = open_port(SERIAL_PORT_1);
    sleep(5);
    initialize_curses();
    clear_screen();
    monitor(fd);
    endwin();                    // reset terminal
    ////  Close any additional ports here
    close(fd[1]);
    close(fd[0]);
    exit(EXIT_SUCCESS);
}  


//------------------------------------------------------------------//
// initialize_app_globals                                           //
// Change alarm threshold and initial states here.                  //
//------------------------------------------------------------------//
void initialize_app_globals(void)
{
    int frzr,k,count=0,cmd_start,location=0,label_start,skip=0;
    a = new Alarm[ALARMS];
    f = new Freezer[FREEZERS];
    char tempstring[FILENAMELENGTH];
    char label[FILENAMELENGTH];
    FILE *fp;
    for(k=0;k<FREEZERS;k++) f[k].alarm_state = OFF;

    //// Temperature threshold above which alarm will sound 
    //// if alarm is active
    printf("\n");
    for(k=0; k<FREEZERS; k++) 
    {   f[k].location = new char[FILENAMELENGTH];
        f[k].alarm_state_string = new char[64];
        strcpy(f[k].alarm_state_string, "none");
        f[k].temperature = -200;
    }

    if((fp=fopen("locations","r"))==NULL)
    {   printf("Cant read locations\n");
        exit(1);
    }else
    {   printf("Locations:\n");
        while(!feof(fp) && count<100)
        {  f[location].location = new char[FILENAMELENGTH]; 
           fgets(tempstring, FILENAMELENGTH-1, fp);
           if(tempstring[0] == '#' || !strlen(tempstring)) continue;
           sscanf(tempstring, "%d", &f[location].port);
           if(feof(fp)) break;

           label_start = 0;
           skip = 0;
           for(k=0;k<(int)strlen(tempstring);k++)
           {    if(skip==0 && isdigit(tempstring[k])) skip=1;
                if(skip==1 && isspace(tempstring[k])) skip=2;
                if(skip==2 && !isspace(tempstring[k])){ label_start=k; break; }
           }
           strcpy(label, tempstring+label_start);          
           remove_terminal_cr(label);
           
           strcpy(f[location].location, label);
           printf("Location %d %d %s\n",location,strlen(f[location].location),f[location].location);
           location++;
        }
    }
    fclose(fp);


    if((fp=fopen("./alarm-commands","r"))==NULL)
    {   printf("Cant read alarm commands\n");
        exit(1);
    }else
    {   printf("Alarm commands:\n");
        while(!feof(fp) && count<100)
        {  a[count].command = new char[FILENAMELENGTH]; 
           fgets(tempstring, FILENAMELENGTH-1, fp);
           if(feof(fp)) break;
           if(tempstring[0] == '#' || !strlen(tempstring)) continue;
           if(strlen(tempstring)<3) continue;
           sscanf(tempstring, "%d %lf ", &a[count].freezer, &a[count].threshold);
           cmd_start = find_command_start(tempstring);
           if(cmd_start) strcpy(a[count].command, tempstring+cmd_start);
           if(!strlen(a[count].command)) break;
           sprintf(tempstring, "Alarm=%d freezer=%d  temperature=%f command=%s", 
               count,
               a[count].freezer, 
               a[count].threshold,
               a[count].command);
           tempstring[79] = 0;
           printf("%s\n", tempstring);
           a[count].state = READY;
           frzr = a[count].freezer;
           if(frzr >= FREEZERS) { printf("Error reading alarms\n"); exit(1); }
           f[frzr].alarm_state = READY;
           if(feof(fp)) break;
           count++;
           if(count >= ALARMS) { printf("Too many alarms\n"); exit(1); }
        }
        ALARM_COUNT = count;
        if(!count){ printf("No alarms\n"); exit(1); }
        fclose(fp);
    }
} 


//------------------------------------------------------------------//
// find_command_start                                               //
//------------------------------------------------------------------//
int find_command_start(char *string)
{
   int start=0,k,hit=0,inspace=0;
   for(k=0;k<(int)strlen(string);k++) 
   {    if(string[k]==' ' && !inspace){ inspace=1; hit++; }
        if(string[k]!=' ')
        {   inspace=0;
            if(hit==2){ start=k; break; }
        }
   }
   return start;
}         


//------------------------------------------------------------------//
// initialize_curses                                                //
//------------------------------------------------------------------//
void initialize_curses(void)
{
  initscr();                   // initialize curses
  cbreak();                    // put terminal in raw mode
  noecho();                    // no echo
  nonl();                      // no nl
  intrflush(stdscr, FALSE);    // no flush stdscr on ^C
  keypad(stdscr, TRUE);        // enable numeric keypad
  move(0,0);                   // moveto upper left
  nodelay(stdscr,TRUE);        // make getch() nonblocking
}


//------------------------------------------------------------------//
// open_port                                                        //
//------------------------------------------------------------------//
int open_port(const char *port_name)
{
  int fd;
  int port = 0x2e8;
  static struct serial_struct ss;
  static struct termios newtio;

  //// Open port
  if((fd = open(port_name, O_RDWR | O_NOCTTY | O_NDELAY )) < 0)
  {   printf("Cant open serial port %s\n", port_name);
      exit(1);
  }

  //// Find out what port and get permission to write to it
  if(ioctl(fd, TIOCGSERIAL, &ss)) 
  {   printf("ioctl(TIOCSERGSTRUCT) failed: -- exiting\n");
      exit(1);
  }

  //// Should be 3f8 for cua0, 2f8 for cua1, 3e8 for cua2, 0x2e8 for cua3
  port=ss.port;  
  printf("%s port %x\n" ,port_name, port);
 
  //// Enable asynchronous I/O
  if(fcntl(fd, F_SETFL, FNDELAY)) printf("fcntl didnt work\n");;
  printf("Opened port %s, fd = %d\n", port_name, fd);
  //// Obtain current port settings 
  tcgetattr(fd, &newtio); 

  //// Set new port settings 
  newtio.c_cflag |= (CLOCAL | CREAD);
  newtio.c_cflag &= ~PARENB;
  newtio.c_cflag &= ~CSTOPB;
  newtio.c_cflag &= ~CSIZE;
  newtio.c_cflag |= CS8;
  newtio.c_cflag &= ~CRTSCTS;

  newtio.c_lflag &= ~(ICANON | ECHO | ISIG);
  newtio.c_cc[VMIN]=1;
  newtio.c_cc[VTIME]=0;   // Tenths of seconds before timeout
  
  tcflush(fd, TCIFLUSH);
  tcsetattr(fd, TCSANOW, &newtio);

  //// Set baud rate
  cfsetispeed(&newtio, BAUDRATE);
  cfsetospeed(&newtio, BAUDRATE);
  tcflush(fd, TCIFLUSH);
  tcsetattr(fd, TCSANOW, &newtio);
  return fd;
}


//------------------------------------------------------------------//
// monitor                                                          //
// It is necessary to have getch() all over the place, otherwise    //
// ncurses won't update the screen.                                 //
//------------------------------------------------------------------//
void monitor(int file_descriptor[])
{
  int freezer,c=0,alarm,ringcount=0,port,fd,row,channel;
  clear_screen();
  print(1,0,"In monitor");
  char blank_string[81];
  memset(blank_string, ' ', 80);
  blank_string[79]=0;

  ////  NOTE: channels 0,1,2,3 are read using commands $1,$2,$3,and $4
  ////  respectively.

  char *command[FREEZERS_PER_PORT] = 
  { {  "$1RD\r\n" },
    {  "$2RD\r\n" },
    {  "$3RD\r\n" },
    {  "$4RD\r\n" }
  };
  int k=0,n;
  char tempstring[128];
  char answer[128];
  char *buffer;
  buffer = new char[128];
  print(1,0,"Entering loop");
  nodelay(stdscr,TRUE);        // make getch() nonblocking
  while((c=getch())!='q')  
  {
       if(c=='q') break;
       if((c=getch())=='q') break;
       if((c=getch())==27) break;
       for(freezer=0; freezer<FREEZERS; freezer++)
       {   
               port = f[freezer].port;
               fd = file_descriptor[port];
               channel = freezer % FREEZERS_PER_PORT;
               if(c=='q') break;
               if((c=getch())=='q') break;
               sprintf(tempstring,"Sending command %s                            ",command[channel]);
               print(2,0,tempstring);
               sleep(2);
               n = write(fd, command[channel], strlen(command[channel]));
               sprintf(tempstring,"Checking location no.%d  Port %d              \n",freezer, port);
               print(1,0,tempstring);

               sleep(1);
               if(c=='q') break;
               if((c=getch())=='q') break;
               if((c=getch())==27) break;
               n = read(fd, buffer, 25);   // 1st byte is a null
               sprintf(tempstring,"Received %d bytes from location no.%d port %d      \n",n,freezer,port);
               if(n<=0) 
               {    print(2,0,"Error reading thermocouple");
                    sleep(2);
               }
               for(k=0;k<=n;k++) answer[k] = buffer[k+1];
               print(2, 0, tempstring);
               row = 5 + freezer;
               print(row, 2, answer+1);
               print_status(freezer);
               print(row, 30, f[freezer].location);
               print(20,1," ");
               f[freezer].temperature = atof(answer+1);
               sleep(SLEEPTIME);
       }
       print(19,1," ");
       print(17,0,blank_string);
       print(18,0,blank_string);
       print(19,0,blank_string);
       print(20,0,blank_string);
       print(21,0,blank_string);
       print(22,0,blank_string);

       log_temperatures();

       ////  Check each alarm to see if its temperature is exceeded
       for(alarm=0; alarm<ALARM_COUNT; alarm++)
       {   if(a[alarm].state == READY)
           {    freezer = a[alarm].freezer;
                if(f[freezer].temperature >= a[alarm].threshold &&
                   f[freezer].alarm_state != OFF)
                {     alarm_ring(alarm);
                      f[freezer].alarm_state = RINGING;
                      a[alarm].state = RINGING;
                }
           }
       }

       ////  Reset alarms if temp is gone back down
       for(alarm=0; alarm<ALARM_COUNT; alarm++)
       {    freezer = a[alarm].freezer;
            {   if(f[freezer].temperature < a[alarm].threshold &&
                      a[alarm].state == RINGING)
                {     a[alarm].state = READY;
                      memset(tempstring, ' ', 75);
                      tempstring[75] = 0;
                      print(8+freezer, 0, tempstring);
                }
            }
       }

       ////  Reset freezer state if no alarms
       for(freezer=0; freezer<FREEZERS; freezer++)
       {    ringcount=0;
            if(f[freezer].alarm_state == RINGING)
            {   for(alarm=0; alarm<ALARM_COUNT; alarm++)
                {   if(a[alarm].state == RINGING) ringcount++;
                }
                if(ringcount==0) f[freezer].alarm_state = READY;
            }
       }
       print(19,1," ");
       print(17,0,blank_string);
       print(18,0,blank_string);
       print(19,0,blank_string);
       print(20,0,blank_string);
       print(21,0,blank_string);
       print(22,0,blank_string);

  }  
  delete[] buffer;
  printf("ending loop\n");
}


//--------------------------------------------------------------------// 
// log_temperatures                                                   //
//--------------------------------------------------------------------// 
void log_temperatures(void)
{
  print(20,1," ");
  FILE *fp;
  char tempstring[1024];
  int k;
  if((fp=fopen("temperatures","wt"))==NULL)
  {    endwin(); 
       printf("Cant open temperatures file\n"); 
       exit(1);
  }
  time_t current_time;
  time(&current_time);
  strcpy(tempstring,ctime(&current_time));
  for(k=0;k<(int)strlen(tempstring);k++) if(tempstring[k]=='\n') tempstring[k]=' ';
  fprintf(fp,"Freezer temperatures at %s  %ld\n",tempstring,current_time);
  fprintf(fp,"Temp.     \t Alarm state       \t Location\n");
  fprintf(fp,"--------- \t -------------     \t --------\n");
  for(k=0;k<FREEZERS;k++)
      fprintf(fp, "%+f \t %s \t %s\n",f[k].temperature, f[k].alarm_state_string, 
          f[k].location);
  fclose(fp);
 
 

  if((fp=fopen("temperatures.html","wt"))==NULL)
  {    endwin(); 
       printf("Cant open temperatures file\n"); 
       exit(1);
  }
  time(&current_time);
  strcpy(tempstring,ctime(&current_time));
  for(k=0;k<(int)strlen(tempstring);k++) if(tempstring[k]=='\n') tempstring[k]=' ';

  fprintf(fp,"<META HTTP-EQUIV=\"REFRESH\" CONTENT=\"40; index.html\">\n");
  fprintf(fp,"<HTML>\n<HEAD>\n<TITLE>Temperatures</TITLE>\n</HEAD>\n\
<BODY  background=\"cardboard.gif\">\n\
<H4>Freezer temperatures at %s </H4> \n\
Time stamp: %ld<BR>\n\
<table border>\n\
<tr><td> Temp.       </td><td>Alarm state          </td><td>Location</td>\n",
  tempstring,current_time);

  for(k=0;k<FREEZERS;k++)
      fprintf(fp,"<tr><td> %+f \t  </td><td> %s\t </td><td> %s </td></td>\n",
      f[k].temperature, f[k].alarm_state_string, 
      f[k].location);

  fprintf(fp,"</TABLE>\n</BODY>\n<HTML>\n");
  fclose(fp);

  print(20,1," ");
  system("/home/freezer/logcommands");
}


//--------------------------------------------------------------------// 
// print                                                              //
//--------------------------------------------------------------------// 
void print(int row, int col, int number)
{
    char tempstring[80];
    sprintf(tempstring,"%d        ",number);
    move(row,col);
    addstr(tempstring);
    getch();
}
void print(int row, int col, double number)
{
    char tempstring[80];
    move(row,col);
    sprintf(tempstring,"%.2f        ",number);
    addstr(tempstring);
    getch();
}
void print(int row, int col, char *string)
{
    int k;
    char s[strlen(string)+1];
    strcpy(s,string);
    for(k=0;k<(int)strlen(s);k++) if(s[k]<' ') s[k]=' ';
    move(row,col);
    addstr(s);
    getch();
}


//--------------------------------------------------------------------// 
// alarm_ring                                                         //
//--------------------------------------------------------------------// 
void alarm_ring(int alarm)
{
   char tempstring[FILENAMELENGTH];
   int freezer = a[alarm].freezer;
   f[freezer].alarm_state=RINGING;
   int status=0;

   print_status(freezer);
   log_temperatures();
   sprintf(tempstring, "Executing %s", a[alarm].command);
   tempstring[79]=0;
   print(20, 0, tempstring);
   getch();        //// Needed to make sure it prints
   sleep(1);

   sprintf(tempstring,"Freezer %d temperature %g alarm %d\n", freezer,
       f[freezer].temperature, alarm);
   syslog(LOG_WARNING, tempstring);    
   print(20,1," ");
   status = system(a[alarm].command);
   if(status!=0)
   {   sprintf(tempstring,"Error executing alarm command: \n%d %s\n",
             freezer, a[alarm].command);
       syslog(LOG_WARNING, tempstring);    
   }
}



//--------------------------------------------------------------------// 
// print_status                                                       //
//--------------------------------------------------------------------// 
void print_status(int freezer)
{ 
   int state;
   state = f[freezer].alarm_state;
   switch(state)
   {   case OFF:     strcpy(f[freezer].alarm_state_string,"Inactive        "); break;
       case READY:   strcpy(f[freezer].alarm_state_string,"Alarm ready     "); break;
       case RINGING: strcpy(f[freezer].alarm_state_string,"ALARM TRIGGERED "); break;    
   } 
   print(5+freezer, 14, f[freezer].alarm_state_string);
   print(20,1," ");
}


//--------------------------------------------------------------------// 
// clear_screen                                                       //
//--------------------------------------------------------------------// 
void clear_screen(void)
{
   clear();
   print(0,0,"Freezer temperature monitor");
   print(3,2,"Temp.       Alarm state     Location");
   print(4,2,"---------   -------------   --------");
}

//--------------------------------------------------------------------------//
//  remove_terminal_cr                                                      //
//--------------------------------------------------------------------------//
void remove_terminal_cr(char *s)
{
    int pos = max(0, (int)(strlen(s))-1);
    if(s[pos]=='\n') s[pos]=0;
}

//--------------------------------------------------------------------------//
// between    - returns 1 if a is between b and c                           //
//--------------------------------------------------------------------------//
int between(int a,int b,int c)
{   if((a>=b)&&(a<=c)) return(1);
    else return(0);
}
