/*
 * Analogue TV Player plugin for VDR
 *
 * Copyright (C) 2003, 2005 Andreas Kool <akool@gmx.de>
 *
 * This code is distributed under the terms and conditions of the
 * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details.
 *
 * Version: $Id: redremote.c,v 1.4 2005/01/09 18:16:09 akool Exp $
 * Release: $Name:  $
 *
 */

/* Short bit of glue code for redremote stuff 
   Written by Dominic Morris <dom@suborbital.org.uk>
   serial line cooking is from code by Malcolm Smith
*/

#include "redremote.h"
#include "player-analogtv.h"


#include <unistd.h>
#include <stdio.h>   /* Standard input/output definitions */
#include <string.h>  /* String function definitions */
#include <unistd.h>  /* UNIX standard function definitions */
#include <fcntl.h>   /* File control definitions */
#include <errno.h>   /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
#include <stdlib.h>
#include <sys/ioctl.h>


cRedRemote::cRedRemote()
{
	fd = -1;
}

cRedRemote::~cRedRemote()
{
    close(fd);
    fd = -1;
    Cancel(3);
}

int cRedRemote::Open()
{
	struct termios options;

    cMutexLock MutexLock(&mutex);

    /* Close the file if it's already open */
    if ( fd != -1 ) {
        close(fd);
	fd = -1;
    }

    /* Save current remote state information */
    strcpy(devname,s.redremote_device);
    mode = s.enabledigibox;

    if ( (fd = open(s.redremote_device, O_WRONLY | O_NOCTTY | O_NDELAY) ) == -1 ) {
        d(0,"Cannot open device file %s",s.redremote_device);
        return -1;
    }

    d(2,"Successfully opened redremote at %s",s.redremote_device);

    fcntl(fd, F_SETFL, 0);

    /* Get the current options for the port */
    tcgetattr(fd, &options);

    /* Set the baud rates to 9600 */
    cfsetispeed(&options, B9600);
    cfsetospeed(&options, B9600);

    /* Enable the receiver and set local mode... */
    options.c_cflag |= (CLOCAL );

    options.c_cflag &= ~PARENB;
    options.c_cflag &= ~CSTOPB;
    options.c_cflag &= ~CSIZE;
    options.c_cflag |= CS8;
    options.c_cflag &= ~CREAD; 
    options.c_cflag &= ~CRTSCTS; 
    options.c_iflag &= ~(IXON | IXOFF | IXANY);
    /* And finally set the options */
    tcsetattr(fd, TCSANOW, &options);

    /* Now we must turn on RTS */
    int status;
    /*int bitset = TIOCM_RTS;
     *  It appears that the "RTS" line is actually the DTR line in
     *  Linux!!!
     *  */
    int bitset = TIOCM_DTR;

    ioctl(fd, TIOCMGET, &status);

    status |= bitset;

    ioctl(fd, TIOCMSET, &status);

    ioctl(fd, TIOCMGET, &status);
    if (status & bitset ) {
	    d(2,"RTS bit set ok");
    } else {
	    d(0,"FAILED to set RTS bit, continuing, but weird things may happen");
    }   

    sleep(2);   /* Wait for powerup */

    /* Now we must put the redremote device into the correct mode for
       our digibox 
    */
    char *mode = NULL;
    switch ( s.enabledigibox ) {
    case 1:  /* Sky */
	d(2,"Setting digibox to Sky mode");
        mode = "$";
        break;
    case 2:  /* Pace RC5 */
	d(2,"Setting digibox to Pace RC5 mode");
        mode = "&";
        break;
    case 3:  /* Pace IRDA */
	d(2,"Setting digibox to Pace IRDA mode");
        mode = "%";
        break;
    }

    if ( mode ) {
        Send(mode);

        sleep(1);  /* Wait a bit longer */
	Start();   /* Start the backup thread working - we don't know if we need it
		    but the thread does nothing much so no harm really in kicking
		    it off? */
    }
    return 0;
}


void cRedRemote::Send(char *text)
{
    cMutexLock MutexLock(&mutex);

    if ( !s.enabledigibox ) {
        /* We might have just been disabled, close descriptor if so */
        if ( fd != -1 ) {
            close(fd);
            fd = -1;
        }
        return;
    }

    /* Try to open it if we need it... */
    if ( fd == -1 ) {
        if ( Open() < 0 ) {
            return;
        }
    }


    /* If the modes don't match, then reopen the device */
    if ( mode != s.enabledigibox ) {
        d(1,"Redremote mode has changed - reopening\n");
        if ( Open() < 0 ) {
            return;
        }
    }
    
    /* Permit the device file to change on config */
    if ( strcmp(devname,s.redremote_device) ) {
        d(1,"Redremote device file has changed from %s to %s - reopening",devname,s.redremote_device);
        if ( Open() < 0 ) {
            return;
    }
    }

    write(fd,text,strlen(text));
}


void cRedRemote::Tune(int channel)
{
    char      buf[10];

    if ( s.fastdigibox_change ) {
        sprintf(buf,"=%d=%d=%d",channel/100,(channel % 100 ) / 10, channel % 10);
    } else {
    sprintf(buf,"%d",channel);
    }

    d(1,"Setting digibox to channel %d",channel);

    Send(buf);
}

/* Send a backup every 30 seconds to kill that annoying "Press red dot"
   interactive banner, sadly, it can't get rid of the channel DOGs...
*/
void cRedRemote::Action()
{
    d(1,"Redremote 'backup' thread started %d",getpid());
    while ( 1 ) {
        sleep(s.backupInterval);
        if ( s.backupHack ) {
	    d(2,"Sending backup to digibox");
            Send("K");
        }
    }
}
