/*  
 *  L.A. Riley 11/18/99
 *  
 *  This is a greatly modified miniterm.c 
 *  by Sven Goldt (goldt@math.tu-berlin.de) 
 *
 *  This program reads the serial interface expecting to find a Davis 
 *  Systems WeatherLink interface.  This interface provides an RS232
 *  port to a weather station console made by the same company.
 *
 *  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.
 *
 *  20-Nov-1999   Lew Riley       First release reading data from the 
 *                                Davis hardware.  
 * 
 *  24-Nov-1999   Charlie Peck    Cleaned-up a bit.  Removed terminal, 
 *                                process, and signal handling code that 
 *                                we don't need.
*/

#include <termios.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include "crc-table.h"

#define BUFFER_SIZE 100
#define BAUDRATE B9600
#define SERIALDEVICE "/dev/ttyS0"
#define FALSE 0
#define TRUE 1
#define ACK 6 

/* Danger Will Robinson, a global.
*/
unsigned char *receive_buffer;


int put_serial_char(int fd, int c, int debug_level);
int put_serial_string(int fd, char *s, int debug_level);
int send_unsigned(int fd, unsigned ui, int debug_level);
unsigned char get_serial_char(int fd, int debug_level);
static int get_acknowledge(int fd, int debug_level);
int fill_buffer(int fd, int n, int debug_level);
int get_buffer(int fd, int debug_level);
int fill_crc_buffer(int fd, int n, int debug_level);
    
main(int argc, char *argv[]) {
   int fd, c, i, record, debug_level = 0;
   struct termios oldtio, newtio, oldstdtio, newstdtio;
   unsigned char header;
   unsigned char comp[8];

 
   /* Set the debug level.  0 = off, 1 = messages from weather value 
      functions, 2 = 1 plus messages from the serial interface functions.
   */ 
   if (argc < 2) {
      debug_level = 0; 
   } else {
      debug_level = atoi(argv[1]); 
   } 
 
   if (debug_level > 0) {
      printf("getWeather: debug_level = %d\n", debug_level); 
   }

   if ((receive_buffer = (unsigned char *)malloc(BUFFER_SIZE)) == NULL) {
      printf("getWeather: error allocating receive buffer (%d bytes).\n", 
         BUFFER_SIZE);
      exit(-1);
   }

   /* Open serial port for reading and writing and not as controlling tty
      because we don't want to get killed if linenoise sends CTRL-C.  
   */

   fd = open(SERIALDEVICE, O_RDONLY | O_NOCTTY);
   if (fd < 0) {
      printf("getWeather: error opening serial device.\n");
      perror(SERIALDEVICE); 
      exit(-1); 
   }

 
   /* Save the current serial port settings.
   */
   tcgetattr(fd, &oldtio); 

   /* Set bps rate and hardware flow control and 8n1 (8bit,no parity,1 stopbit).
      Also don't hangup automatically and ignore modem status.  Finally enable 
      receiving characters.
   */
   newtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD;
 
   /* Don't echo characters, we just want output from the device.  Don't 
      generate signals.  This is the quick and dirty way to do this, we should 
      use the specific masks for ECHO and ISIG but since we don't care about 
      having any of the items in this vector enabled we can just zero it.
   */
   newtio.c_lflag = 0;
    
   /* Ignore bytes with parity errors and leave port raw and dumb.
   */
   newtio.c_iflag = IGNPAR;

   /* Flush the I/O queue for the port and enable the new settings.
   */
   tcflush(fd, TCIFLUSH);
   tcsetattr(fd, TCSANOW, &newtio);

   /* Save the old settings and then stop echo and buffering on stdin.
   */
   tcgetattr(0, &oldstdtio);
   tcgetattr(0, &newstdtio); /* get working stdtio definition */
   newstdtio.c_lflag &= ~(ICANON | ECHO); /* change the flags */ 
   tcsetattr(0, TCSANOW, &newstdtio); /* change the configuration */ 

   /* 
      Read in the info from the gps and look for 
    */
/*   while(1){*/
   put_serial_char(fd, 27, 2);
   put_serial_char(fd, 'G', 2);
   /*}*/
   
   while(1){
     memset(receive_buffer, 0, BUFFER_SIZE); 
     
     fill_buffer(fd, 1, debug_level);  // get the returned data (in bytes)
      
     /*     if(get_buffer(fd, debug_level)==-1){
       printf("unable to get data\n");
       break;
       }
     */
     printf("%s\n", receive_buffer);
   }

   
   /* Put the serial port and the terminal back the way the were when
      we started.
   */
   tcsetattr(fd, TCSANOW, &oldtio); 
   tcsetattr(0, TCSANOW, &oldstdtio); 

   close(fd);
   exit(0);
}


/* ---- Serial I/O functions based on templates from Davis ---- */

int put_serial_char(int fd, int c, int debug_level)  {
   unsigned char uc = c;

   if (debug_level > 1) {
      printf("put_serial_char: char = %x\n", uc);
   }

   return write(fd, &uc, 1);
}

int send_unsigned(int fd, unsigned ui, int debug_level) {
   unsigned char *uc;
   int j = 0; 
  
   uc = (unsigned char *)&ui;
   j += put_serial_char(fd, *uc, debug_level);
   j += put_serial_char(fd, *(uc+1), debug_level);
  
   return(j); 
}

int put_serial_string(int fd, char * s, int debug_level) {
   int i, j = 0;
   
   for (i = 0; s[i] != '\0'; i++)
      j += put_serial_char(fd, s[i], debug_level);
   
   return(j);
}

unsigned char get_serial_char(int fd, int debug_level) {
   unsigned char c;
  
   read(fd, &c, 1);
   
   
      printf("%d\n", c);
   
      
    return(c);
}

static int get_acknowledge(int fd, int debug_level) {
   int c;

   if ((c = get_serial_char(fd, debug_level)) == ACK) {

      if (debug_level > 1) {
         printf("get_acknowledge: got ACK!\n");
      }
      
      return(1);   
   
   } else { 
   
      printf("get_acknowledge: Looking for ACK and got %x\n", c);
      return(0);
   }
}

int fill_buffer(int fd, int n, int debug_level) {
   int i,c;
  
   for (i=0; i<n; i++) {

     c = get_serial_char(fd, debug_level);
      
     if (debug_level > 1) {
       printf("fill_buffer: position = %d, value = %x\n", i, c);
     }
     
     if (c >= 0) {
       
       receive_buffer[i] = c;
       
     } else {
       
       printf("fill_buffer: error reading serial port\n");
       return(-1);
       
     }
   }
   
   return(1);
}

int fill_crc_buffer(int fd, int n, int debug_level) { // n includes CRC bytes
   int i,c;
   int crc = 0;   // initialize the CRC checksum to 0
  
   for (i=0; i<n; i++) {

      c = get_serial_char(fd, debug_level);

      if (debug_level > 1) {
         printf("fill_crc_buffer: position = %d, value = %x\n", i, c);
      }
 
      if (c >= 0) {
	  
	     receive_buffer[i] = c;   // Store the data
	     crc = crc_table[(crc >> 8) ^ c] ^ (crc << 8);
	     
	  } else {
	  
	     printf("fill_crc_buffer: error reading serial port\n");
	     return(-1);
      }

      if (crc == 0) {
      
         return(1);         // we have read in n bytes and the CRC is OK
         
      } else {
      
         printf("fill_crc_buffer: checksum error\n");
         return(-1);       // The CRC check failed.
      }
   }
}

int get_buffer(int fd, int debug_level) {
    char c;
    int i=0;

    
    while(c = get_serial_char(fd, debug_level)){
      
      if (c >= 0){
	if(c != '\n'){
	  receive_buffer[i] = c;
	}else{
	  break;
	}
      } else {
	
	printf("fill_buffer: error reading serial port\n");
	return(-1);
	
      }
      i++;
      if (i>100) {printf("XXX - ERROR\n");}
      
    }
    return(1); 
}  















