#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/poll.h>
#include <sys/ioctl.h>
#include <time.h>
#include <errno.h>

int set_prop(int fd)
{
	struct termios newtio;

	memset (&newtio, 0, sizeof (newtio));
	/* Set the bitrate */
	cfsetospeed(&newtio, B115200);
	cfsetispeed(&newtio, B115200);
	
	newtio.c_cflag |= CS8;
	
	/* Set the parity */
	newtio.c_cflag &= ~PARENB;
	
	/* Set the number of stop bits */
	newtio.c_cflag &= (~CSTOPB);
	
	/* Selects raw (non-canonical) input and output */
	newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
	newtio.c_oflag &= ~OPOST;
	newtio.c_iflag |= IGNPAR;
	/* Ignore parity errors!!! Windows driver does so why shouldn't I? */
	/* Enable receiber, hang on close, ignore control line */
	newtio.c_cflag |= CREAD | HUPCL | CLOCAL;
	
	/* Read 1 byte minimun, no timeout specified */
	newtio.c_cc[VMIN] = 1;
	newtio.c_cc[VTIME] = 0;

	if (tcsetattr (fd, TCSANOW, &newtio) < 0)
		return 0;

	return 1;
}

static int serial_wait_read (int fd, unsigned timeout_ms)
{
	int rval;
	struct pollfd ufds;
	
	ufds.fd = fd;
	ufds.events = POLLIN;
	ufds.revents = 0x0000;
	
	rval = poll (&ufds, 1, timeout_ms);
	if (rval == -1)
		return (-1);
	
	return (((ufds.revents) & POLLIN) == POLLIN);
}

static void serial_flush(int fd)
{
	char 	b;
	int		rc;

	while(1)
	{
//		if(serial_wait_read(fd, 0)<=0)
		{
//			printf("errno = %d wait failed\n", errno);
//			break;
		}
		rc = read(fd, &b, 1);
		if(rc <= 0)
		{
			printf("rc = %d errno = %x exit\n", rc, errno);
			break;
		}
		printf("rc = %d\n", rc);
	}
}

void thread_serial_port(char *port)
{
	int		fd;
	int		rc;
	char	buf[10];

	fd = open (port, O_RDWR | O_NOCTTY | O_SYNC | O_NONBLOCK);
	if(fd < 0)
	{
		printf("open serial port failed\n");
		return;
	}
	set_prop (fd);

	usleep(10);
//	serial_flush(fd);
	tcflush(fd, TCIOFLUSH);
	write(fd, "hello world\n", strlen("hello world\n"));
	while(1)
	{
		rc = read(fd, buf, 1);
		if(rc>0)
		{
			printf("0x%02x \n", buf[0]);
			write(fd, &buf[0], 1);
//			if(buf[0] == 'c')
//				break;
		}
	}
}

void thread_serial_port1(char *port)
{
	int		fd;
	int		rc;
	char	buf[10];

	fd = open (port, O_RDWR | O_NOCTTY | O_SYNC | O_NONBLOCK);
	if(fd < 0)
	{
		printf("open serial port failed\n");
		return;
	}
	set_prop (fd);

	usleep(10);
//	serial_flush(fd);
	tcflush(fd, TCIOFLUSH);
	write(fd, "hello world\n", strlen("hello world\n"));
	while(1)
	{
		rc = read(fd, buf, 1);
		if(rc>0)
		{
			printf("0x%02x \n", buf[0]);
			write(fd, &buf[0], 1);
//			if(buf[0] == 'c')
//				break;
		}
	}
}
void thread_serial_port2(char *port)
{
	int		fd;
	int		rc;
	char	buf[10];

	fd = open (port, O_RDWR | O_NOCTTY | O_SYNC | O_NONBLOCK);
	if(fd < 0)
	{
		printf("open serial port failed\n");
		return;
	}
	set_prop (fd);

	usleep(10);
//	serial_flush(fd);
	tcflush(fd, TCIOFLUSH);
	write(fd, "hello world\n", strlen("hello world\n"));
	while(1)
	{
		rc = read(fd, buf, 1);
		if(rc>0)
		{
			printf("0x%02x \n", buf[0]);
			write(fd, &buf[0], 1);
//			if(buf[0] == 'c')
//				break;
		}
	}
}
void thread_serial_port3(char *port)
{
	int		fd;
	int		rc;
	char	buf[10];

	fd = open (port, O_RDWR | O_NOCTTY | O_NONBLOCK);
	if(fd < 0)
	{
		printf("open serial port failed\n");
		return;
	}
	set_prop (fd);

	usleep(10);
//	serial_flush(fd);
	tcflush(fd, TCIOFLUSH);
	write(fd, "hello world\n", strlen("hello world\n"));
	while(1)
	{
		if(serial_wait_read(fd, 1000)){
			rc = read(fd, buf, 1);
			if(rc>0)
			{
				printf("0x%02x \n", buf[0]);
				write(fd, &buf[0], 1);
//				if(buf[0] == 'c')
//					break;
			}
		}
	}
}

int	main(int argc, char **argv[])
{
    pthread_t thread_id = 0;
    pthread_t thread_id1 = 0;
    pthread_t thread_id2 = 0;
    pthread_t thread_id3 = 0;
    pthread_attr_t  attr;

    if(thread_id)
    {
        pthread_cancel(thread_id);
    }
    pthread_attr_init(&attr);
#if 0
    if (pthread_create(&thread_id, &attr, (void*)&thread_serial_port, "/dev/ttySAC0"))
    {
        printf("ERROR: can't create read_thread thread!\n");
    }
    else {
        printf("ttySAC0 started\n");
        pthread_detach(thread_id);
    }
#endif
    if (pthread_create(&thread_id1, &attr, (void*)&thread_serial_port1, "/dev/ttySAC0"))
    {
        printf("ERROR: can't create read_thread thread!\n");
    }
    else {
        printf("ttySAC1 started\n");
        pthread_detach(thread_id1);
    }
    if (pthread_create(&thread_id1, &attr, (void*)&thread_serial_port1, "/dev/ttySAC1"))
    {
        printf("ERROR: can't create read_thread thread!\n");
    }
    else {
        printf("ttySAC1 started\n");
        pthread_detach(thread_id1);
    }

    if (pthread_create(&thread_id2, &attr, (void*)&thread_serial_port2, "/dev/ttySAC2"))
    {
        printf("ERROR: can't create read_thread thread!\n");
    }
    else {
        printf("ttySAC2 started\n");
        pthread_detach(thread_id2);
    }

    if (pthread_create(&thread_id3, &attr, (void*)&thread_serial_port3, "/dev/ttySAC3"))
    {
        printf("ERROR: can't create read_thread thread!\n");
    }
    else {
        printf("ttySAC3 started\n");
        pthread_detach(thread_id3);
    }

    pthread_attr_destroy(&attr);
	printf("press q to exit\n");
	while(1)
	{
		int	ch;
		ch = getchar();
		if(ch == 'q' || ch == 'Q')
			break;
	}
	return 0;
}
