////////////////////////////////////////////////////////////////////////////////////////////
//
//	   Xbow reader for linux on the ipaq
//
//			   by Kristof Van Laerhoven, kristof@comp.lancs.ac.uk
//
//	   version history: its too simple.. thanks to the serial programming howto
//
////////////////////////////////////////////////////////////////////////////////////////////

///// includes /////////////////////////////////////////////////////////////////////////////

#include <stdio.h>
#include <errno.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/signal.h>
#include <sys/types.h>

///// defines //////////////////////////////////////////////////////////////////////////////

#define MODEMDEVICE "/dev/ttySA0"	 

#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE  1
#endif

///// globals //////////////////////////////////////////////////////////////////////////////

struct termios	orig, new_t;			// new and old terminal

static int	peek = -1;					// kbhit/getch

////// check for a key-pressed event //////////////////////////////////////////////////////

int  kbhit(void)
{
	char ch;
	int nread;

	if (peek != -1) {
		return 1;
	}

	new_t.c_cc[VMIN]=0;
	tcsetattr(0,TCSANOW, &new_t);
	nread = read(0, &ch, 1);
	new_t.c_cc[VMIN]=1;
	tcsetattr(0, TCSANOW, &new_t);

	if (nread==1) {
		peek = ch;
			return 1;
	}

	return 0;
}

////// get character from input ///////////////////////////////////////////////////////////

int  getch(void)
{
	char ch;

		if (peek != -1) {
		   ch = peek;
		   peek = -1;
		   return ch;
		}

		read(0,&ch,1);
		return ch;
}

////// main function //////////////////////////////////////////////////////////////////////

int main(int ac, char **args) {

	 int fd,c,i, res, baudrate;
	 unsigned char ch;
	 FILE *fp;
	 unsigned int bufsize,interval;

	 struct termios oldtio,newtio;

	 if (ac>1)
		interval = atoi(args[1]);
	 else
		interval = 0;

	 // terminal input properties (for getch & kbhit)
	  tcgetattr(0, &orig);
	  new_t = orig;
	  new_t.c_lflag &= ~ICANON; 		// no canonical input
	  new_t.c_lflag &= ~ECHO;		// no echo
	  new_t.c_lflag &= ~ISIG;		// no ISIG
	  new_t.c_cc[VMIN] = 1;
	  new_t.c_cc[VTIME] = 0;
	  tcsetattr(0, TCSANOW, &new_t);

	 baudrate = B38400; // default
	 bufsize = 1024;

	 unsigned char *buf;
	 buf = new unsigned char [bufsize];

	 // open the device to be non-blocking (read will return immediatly)
	 printf("Opening the serial port... ");
	 fd = open(MODEMDEVICE, O_RDWR | O_NDELAY);
	 if (fd <0) {
			perror(MODEMDEVICE);
			exit(-1);
	 }
	 else {
			printf("Success.\n\r");
	 }

	 tcgetattr(fd,&oldtio); // save current port settings
	 printf("Saved current port settings.\n\r");

 	 tcgetattr(fd,&newtio);
	 // set new port settings for canonical input processing
	 newtio.c_cflag = CS8 | CLOCAL | CREAD | HUPCL;
	 newtio.c_iflag = IGNPAR | IGNBRK;
	 newtio.c_oflag = 0;
	 newtio.c_lflag = 0;
	 newtio.c_cc[VMIN]=1;
	 newtio.c_cc[VTIME]=0;

	 res = cfsetispeed(&newtio, baudrate);	printf("cfsetispeed returned %i.\n\r",res);
	 res = cfsetospeed(&newtio, baudrate);	printf("cfsetospeed returned %i.\n\r",res);

	 res = tcflush(fd, TCIFLUSH);			printf("flush returned %i.\n\r",res);
	 res = tcsetattr(fd,TCSANOW,&newtio);	printf("set attr returned %i.\n\r",res);

	 ch = 0;

	 while (ch!='q' && ch!='Q') {

		 // send a 'G' (asking for data)
		 res = write(fd,"G",1);
				 usleep(interval); // wait a while
				 printf("?");
		 // read values from serial port
		 res = read(fd,buf,bufsize);		// read buffer

		 if (res==-1) {
			//debug: perror(MODEMDEVICE);
						printf("-\n\r");
		 }
		 else {
			 if (res>3) {
				// see the xbow datasheet for these formula:
				 printf("%3.2f ", (float)(256*buf[0]+buf[1])/100);
				 printf("%3.2f \n\r", (float)(256*buf[2]+buf[3])/100);
			 }
		 }

		 // check for input
		 if (kbhit()) {
			ch = getch();
		 }

	 } //while no q or Q has been typed

	 // restore old settings
	 tcsetattr(fd,TCSANOW,&oldtio);
	 tcsetattr(0, TCSANOW, &orig);

	 delete []buf;

}