/* relais control program
 * Frederic Gaus   <relaictl@necroshine.de>
 * Daniel Willmann <mhnalpha@gmx.net>
 * E-Mails (other than spam) welcome :-)
 *
 * adapted from relais example code by
 * Copyright (C) 2003	Joachim Schiele 
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 */

#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 "relais.h"

/*
 * 'open_port()' - Open serial port 1.
 *
 * Returns the file descriptor on success or -1 on error.
 *
 * RS232-standard 
 * - 19200 baud
 * - 8 bits/byte
 * - no parity
 * - no handshake
 * - 1 stop bit
 */

/*
 *  Write to Port 
 *  Generates the xor
 *
 *  relay board gives a reply to the controller for each 
 *  executed command. The answer is also read here.
 */
int sndcmd(uchar cmd, uchar addr, uchar data, int fd)
{
	uchar wbuf[4];
	wbuf[0] = cmd;
	wbuf[1] = addr;
	wbuf[2] = data;
	wbuf[3] = wbuf[0]^wbuf[1]^wbuf[2];

#ifdef DEBUG
	printf(" -> send: %d %d %d %d\n", cmd,addr,data,wbuf[3]);
#endif

	if (!write(fd, wbuf, 4)) 
		return -EWRITEFAIL;

	return readcmd (fd);
}


/*
 * readcmd reads one return-command and checks for errors
 */
int readcmd (int fd)
{
    uchar rbuf[4];
	
    if (!read(fd, rbuf, 4))
		return -EREADFAIL;

#ifdef DEBUG
    printf(" <- recv: %d %d %d %d\n", rbuf[0], rbuf[1], rbuf[2], rbuf[3]);
#endif

    //Checksum is incorrect ECSUMINVAL 
    if (rbuf[3] != (rbuf[0]^rbuf[1]^rbuf[2]))
    	return -ECSUMINVAL;
    
    // If the return-command is 255, we got a transmission failure. (or NOP was send)
    if (rbuf[0] == 255)
    {
    	fprintf(stderr, "ERROR: Data corruption occurred on Board %i\nCommand has NOT been executed", rbuf[1]);
    	return -ETRANSFAIL;
    }
    
    // If the data-field in transmission is important, it gets the return-value 
    //if (rbuf[0] == 255 - cmd)
    	return rbuf[2];
    
    //return 0;
}



int init(int *fd, char *port)
{
	struct termios options;
	int retval=0;

	*fd = open(PORT, O_RDWR | O_NOCTTY | O_NDELAY);

	if (*fd == -1)
		perror("open_port: Unable to open /dev/ttyS?");
	
	fcntl(*fd, F_SETFL, 0);
		
	/* get the current options */
	tcgetattr(*fd, &options);
	
	/* set in and out speed */
	cfsetispeed(&options, B19200);
	cfsetospeed(&options, B19200);
	
	options.c_cflag &= ~PARENB;
	options.c_cflag &= ~CSTOPB;
	options.c_cflag &= ~CSIZE; /* Mask the character size bits */
	options.c_cflag |= CS8;    /* Select 8 data bits */
	
	/* set raw input, 1 second timeout */
	options.c_cflag     |= (CLOCAL | CREAD);
	options.c_lflag     &= ~(ICANON | ECHO | ECHOE | ISIG);
	options.c_oflag     &= ~OPOST;
	options.c_cc[VMIN]  = 0;
	options.c_cc[VTIME] = 10;
	
	/* set the options */
	tcsetattr(*fd, TCSAFLUSH, &options);

	retval = sndcmd(CMD_SETUP, 1, 0, *fd);
	//If no error has occured
	if (!(retval < 0))
		retval = readcmd(*fd);

	//fcntl(fd, F_SETFL, FNDELAY);
	//fcntl(fd, F_SETFL, 0); What do these do?
	switch (retval)
	{
		case -ECSUMINVAL:
			fprintf(stderr, "Error initializing!\n");
			exit(1);
		case -EREADFAIL:
			fprintf(stderr, "Error reading from port!\n");
			exit(1);
		case -EWRITEFAIL:
			fprintf(stderr, "Error writing to port!\n");
			exit(1);
		default:
			printf("Initialization successful. Returnvalue: %i\n", retval);
	}
	return 0;
}

/*
 * Executes CMD_GETPORT
 */
int getport(uchar addr, int fd)
{
	int retval;
	retval = sndcmd(CMD_GETPORT, addr, 0, fd);

#ifdef DEBUG
	printf(" <- current portstatus: %i\n", retval);
#endif

	switch (retval)
	{
		case -ECSUMINVAL:
			fprintf(stderr, "ERROR: Checksum incorrect - Transmissionerror\n");
			exit(1);
	    case -EREADFAIL:
			fprintf(stderr, "Error reading from port!\n");
			exit(1);
	    case -EWRITEFAIL:
			fprintf(stderr, "Error writing to port!\n");
			exit(1);
	}
		
	return retval;
}

/* 
 * Returns the stat of relay
 */
int getstats(uchar addr, uchar relay, int fd)
{
	uchar status;
	status = getport(addr, fd);
	return ((status &= relay) == 0)?(DEACTIVE):(ACTIVE); 	
}


int setport(uchar addr, uchar relay, int op, int fd)
{
	uchar buf[4];
	
	//get stats of relays
	buf[2] = getport(addr, fd);

	//create new stat of relays
	switch (op)
	{
		case ACTIVE : 
			buf[2] |= relay;
			break;
		case DEACTIVE :
			buf[2] &= ~relay;
			break;
		case TOGGLE :
			buf[2] ^= relay;
			break;
	}

#ifdef DEBUG
	printf(" -> writing portstatus: %d\n", buf[2]);
#endif
	
	// write new stats
	return sndcmd (CMD_SETPORT, addr, buf[2], fd);
}


int main(int argc)
{
	int fd; /* File descriptor for the port */
	int n;
	
	// Initialisation
	if (init(&fd, PORT) != 0)
	   exit(1);
	
     if ( setport(1,RELAY2,TOGGLE,fd ) < 0 )
		 exit(1);

	 if (

	close(fd);
	return 1;
}
