#include <gtk/gtk.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <glib.h>

#include "serial.h"


struct termios oldtio;
char	rxbff[50];
int	rxlen = 0;
int	iowatch = -1;


gboolean
io_callback(GIOChannel *ioch, GIOCondition cond, gpointer data)
{
  int bytes_read;
  unsigned char chr;
  
  do {
    g_io_channel_read_chars(ioch, &chr, 1, &bytes_read, NULL);
    if (bytes_read) {
      process_char(chr);
      if (pref.diag_comm) printf("%02x\n", chr);
    }
  } while (bytes_read);
  return TRUE;
}


GIOChannel *
serial_open(char *port, int baud, int dlen, int stops)
{
  GIOChannel *ioch;
  struct termios newtio;
  int fd;
  
  fd = open(port, O_RDWR | O_NONBLOCK | O_NOCTTY);
  if (fd == -1) return NULL;

  tcgetattr(fd, &oldtio);
  bzero(&newtio, sizeof(newtio));

  newtio.c_cflag = CREAD | CLOCAL;
  switch (baud) {
    case 1200:  newtio.c_cflag |= B1200; break; 
    case 2400:  newtio.c_cflag |= B2400; break; 
    case 4800:  newtio.c_cflag |= B4800; break; 
    case 9600:  newtio.c_cflag |= B9600; break;
    case 19200: newtio.c_cflag |= B19200; break; 
    default:    return NULL;
  }
  
  switch (dlen) {
    case 8:  newtio.c_cflag |= CS8; break;
    default: return NULL;
  }
  
  switch (stops) {
    case 1:  break;
    case 2:  newtio.c_cflag |= CSTOPB; break;
    default: return NULL;
  }
  
  newtio.c_iflag = IGNPAR;
  newtio.c_oflag = 0;
  newtio.c_lflag = 0;
  
  newtio.c_cc[VTIME] = 0;
  newtio.c_cc[VMIN]  = 1;
  
  tcflush(fd, TCIFLUSH);
  tcsetattr(fd, TCSANOW, &newtio);
  
  rxbff[0] = '\0';
  ioch = g_io_channel_unix_new(fd);
  switch (g_io_channel_set_encoding(ioch, NULL, NULL)) {
    case G_IO_STATUS_NORMAL: break;
    default: printf("Port initialization: can't change coding\n");
  }
  return ioch;
}


void
serial_send_cmd(GIOChannel *ioch, char cmd)
{
  int written;
  GError *error = NULL;
  
  if (pref.diag_comm) printf("[%c]\n", cmd);
  g_io_channel_write_chars(ioch, &cmd, 1, &written, &error);
  g_io_channel_flush(ioch, NULL);
  if (error) {
    printf("%s\n", error->message);
  }
}


void
serial_start_watch(GIOChannel *ioch)
{
  iowatch = g_io_add_watch(ioch, G_IO_IN, io_callback, NULL);
}
