/*****************************************************************************/

/*
 *      linuxremote.c -- REALmagic remote control client linux specific functions
 *
 *      Copyright (C) 1999-2001 Sigma Designs
 *                   written by Emmanuel Michon <emmanuel_michon@sdesigns.com>
 *
 *      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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/*****************************************************************************/
#include "define.h"
#include "remote.h"

char *SerialPortDevice;
int get_out = 0;

//------------------------------------------------------------------------//
// OSOpenPort - This function Opens and intializes the COM1/2 serial port.//
//------------------------------------------------------------------------//

struct termios oldtermios;

int ttyraw(int fd)
{
        struct termios newtermios;

        if (tcgetattr(fd,&oldtermios)<0) return -1;
	newtermios=oldtermios;

	// all the basic magic for raw mode
	cfmakeraw(&newtermios);

	// input speed setting
	if (cfsetispeed(&newtermios,B1200)<0) return -1;

	// receive byte per byte
	newtermios.c_cc[VMIN] = 1;
        newtermios.c_cc[VTIME] = 0;
	
        /* You tell me why TCSAFLUSH. */
        if(tcsetattr(fd, TCSAFLUSH, &newtermios) < 0) return -1;
	
        return 0;
}

int ttyreset(int fd)
{
        if(tcsetattr(fd, TCSAFLUSH, &oldtermios) < 0) return -1;

        return(0);
}

PORTHANDLE OSOpenPort(const char *name)
{
	int fd;

	// if no name specified use default
	if (name==NULL) name=SerialPortDevice;

	// 0644 is -rw-r--r--
	// NOCTTY because TTY is raw
	fd = open(name,O_RDWR|O_NOCTTY|O_NONBLOCK,0644);
	if (fd==-1) {
		perror("Could not open serial port");
		return FALSE;
	}

	if (ttyraw(fd)!=0) {
		perror("Cannot set raw mode");
		return FALSE;
	}
	
	return (PORTHANDLE)fd;
}

BOOL OSClosePort(PORTHANDLE hPort)
{
	ttyreset((int)hPort);

	return (close((int)hPort)!=-1);
}

//-----------------------------------------------------------------------//
// OSReadPort - Reads 1 character from the Com Port			 //
//-----------------------------------------------------------------------//

int OSReadPort(INFO *info)
{
	unsigned char buf;
	
	while (!get_out && read(info->hPort,&buf,1)==-1) {
		// signal reception cause harmless read failures
		if (errno != EINTR &&
		    errno != EAGAIN) {
			perror("Could not read");
			return -1;
		}
		
		usleep(20000);
	}
	
	if(get_out)
	  return -1;
	return (int)buf;   
}

//---------------------------------------------------------//
// OSPurge - When a valid key is found, purge the com port //
//---------------------------------------------------------//

void OSPurge(PORTHANDLE fd)
{

#define MINREPEAT 300000

	// FIXME tcflush should be protected against EINTR too!

	usleep(MINREPEAT);
	if (tcflush(fd,TCIOFLUSH)==-1) {
		perror("Could not flush");
		return;
	}
}


void OSSetPortHandle(PORTHANDLE p)
{
	// do nothing.
}

//-------------------------------------------------------------------------------//
//	GetSymbol - Reads the port until a valid sequence is detected - then returns //
//   the symbol read								  //
//-------------------------------------------------------------------------------//
void GetSymbol(INFO * info)
{
  int test;
  int symbol, symbol_2;

  do
    {
      test = 0;
      symbol = OSReadPort(info);	// read one character
      if  (symbol == 131)
	{
	  symbol = OSReadPort(info);
	  symbol_2 = OSReadPort(info);
	  if (symbol == symbol_2)
	    {
	      test = 1;
	    }
	  else if(symbol == -1 ||
		  symbol_2 == -1)
	    {
	      test = 1;
	    }
	}
      else if(symbol == -1)
	{
	  test = 1;
	}
    }
  while (test == 0);
  
  info->symbol = symbol;
}

BOOL start_listening_to_remote(INFO * info)
{
  char defaultSerialPortDevice[]="/dev/ttyS0";
  
  SerialPortDevice = getenv("REMOTECONTROLPORT");
  if (SerialPortDevice == NULL) 
    SerialPortDevice=defaultSerialPortDevice;
  
  G_MESSAGE("Using serial port %s",SerialPortDevice);
  
  G_MESSAGE("Open com port ...");
  info->hPort = OSOpenPort(NULL); /* Opens and initialize default COM port */
  if (info->hPort == FALSE) 
    {
      G_WARNING("Open com port has failed !");
      return FALSE;
    }
  OSSetPortHandle(info->hPort);
  
  G_MESSAGE("purge com port\n");
  OSPurge(info->hPort); /* empties COM port before first reading */
  get_out = 0;
  return TRUE;
}

void handle_listening_to_remote(INFO *local_info)
{
  while(1)
    {
      GetSymbol(local_info);  /* Reads until a good sequence is found */
      if (local_info->symbol == 141 ||
	  local_info->symbol == -1)
	{	
	  OSClosePort (local_info->hPort); 
	  local_info->pRemoteListener = NULL;
	  if(local_info->symbol == 141)
	    gtk_main_quit();
	  G_PRINT("\n*****\nEXITING REMOTE LISTENER\n*****\n");
	  pthread_exit(NULL);
	  return;
	}
      else
	ReadLibrary(local_info); /* identifies known keys */
      if(local_info->test) 
	OSPurge(local_info->hPort); /* If a known key was found, empties Com port */
      // usleep(250000);
    }
  
}

void spawnRemoteListener(INFO * info)
{
  info->pRemoteListener = OSCreateThread("RemoteListenerThread",UNUSED_ARG,
					 (FUNCPTR)handle_listening_to_remote,(int)info);
}

void stopRemoteListener(INFO * info)
{
  if(info->pRemoteListener != NULL)
    get_out = 1;
}
