#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 <sys/types.h>
#include <sys/time.h>
#include <sys/select.h>
#include <signal.h>
#include <pthread.h>

#define TIMEVAL struct timeval

//globals:
int bRunning=1;
int bRun=1;
//static const char *pHelloToken="hey laptop i just got: ";

//FD:
int ttyFD=-1; //global for this module
pthread_t thrid;

//open-tuning:
int tty_open(const char *pDevName, unsigned int nBaud)
{
	int fd;
	struct termios options;
	
	//open:
	fd = open(pDevName, O_RDWR | O_NOCTTY | O_NDELAY);
	if(-1 == fd)
		return fd;
		
	//tune:
	fcntl(fd, F_SETFL, 0);
	
	tcgetattr(fd, &options);
	
		options.c_cflag &= ~PARENB;
		options.c_cflag &= ~CSTOPB;
		options.c_cflag &= ~CSIZE;
		options.c_cflag |= CS8;
		
		
		if(cfsetispeed(&options, nBaud)<0) //B115200); //B3000000);
		{
			printf("failed to set input speed to %d\n", nBaud);
		}
		if(cfsetospeed(&options, nBaud)<0) //B115200); //B3000000);
		{
			printf("failed to set output speed to %d\n", nBaud);
		}
		
		/*options.c_cflag &= ~CBAUD;    //Remove current BAUD rate
		options.c_cflag |= BOTHER;    //Allow custom BAUD rate using int input
		options.c_ispeed = 3000000;    //Set the input BAUD rate
		options.c_ospeed = 3000000;    //Set the output BAUD rate*/


		options.c_cflag |= (CLOCAL | CREAD);
		
		options.c_cflag     |= (CLOCAL | CREAD);
//		options.c_cflag &= ~CNEW_RTSCTS;
		
		
		options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); //raw mode!!!
		options.c_iflag &= ~(IXON | IXOFF | IXANY); //no soft flow
		options.c_oflag &= ~OPOST;	//raw output also
	
	tcsetattr(fd, TCSAFLUSH, &options);	
	
	return fd; //!!!!!!
}

int tty_blread(int nFD, char *pBuf, int nBufSize, int tmt_mS)
{
	fd_set fd;
    TIMEVAL tv;
    int bytes_read;
    
        
    //read all from port:
    bytes_read=0;
		
	FD_ZERO(&fd);
    tv.tv_sec = 0;
    tv.tv_usec =tmt_mS*1000; //mS

	FD_SET(nFD, &fd);

	if(0==select(nFD+1, &fd, NULL, NULL, &tv)) //wait for data
          return bytes_read;
        
    bytes_read+=read(nFD, pBuf+bytes_read, nBufSize-bytes_read);
	return bytes_read;
}

void *upd_loop(void *parg)
{
	int nRead;
	char in_buf[1024];
	
	if(ttyFD<0)
	{
		pthread_exit(0); 
	}
	
	printf("entering listening thread...\n");
	while(bRun){
	
		nRead=tty_blread(ttyFD, in_buf, sizeof(in_buf), 500);
		if(nRead>0)
		{
#ifdef DIAG_MSG
	in_buf[nRead-1]='\0';
    printf("->%s", in_buf); printf("\r\n");
#endif	
		}
		usleep(100000); 
	}
	printf("exiting listening thread...\n");
	pthread_exit(0);
}

int init_at_comm(void)
{
	return pthread_create(&thrid, NULL, upd_loop, NULL);
}
void destroy_at_comm(void)
{
	bRun=0;
	pthread_join(thrid, NULL);
}

static void sigexit_handler(int signum) {
   bRunning=0;  
}

int main(void)
{
	struct termios tios;
	speed_t ispeed;
	speed_t ospeed;
	
	signal(SIGQUIT, sigexit_handler);
    signal(SIGINT, sigexit_handler);
    signal(SIGTERM, sigexit_handler);
	
	ttyFD=tty_open("/dev/ttyS1", 3000000); //B9600); 
	if(ttyFD<0)
	{
		printf("failed to open ttyS1\n");
		return 1;
	}
	
    
    tcgetattr(0, &tios);
	ispeed = cfgetispeed(&tios);
	ospeed = cfgetospeed(&tios);
	printf("baud rate in: %d\n", tios.c_ispeed);
	printf("baud rate out: %d\n", tios.c_ospeed);
    
    init_at_comm();
    
    while(bRunning)
    {
		usleep(50000); 
	}
		
	destroy_at_comm();
	close(ttyFD);
	
	return 0;
}
