/* test code for interface to Cypress CYWM6935 on the ATmega128

 * based on:

 * Version 1.0 - Curses visualizer
 * Mike Kershaw/Dragorn <dragorn@kismetwireless.net>
 *
 * This code 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 code 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.
 *
 *
 */
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#include <syslog.h>
#include <unistd.h>
#include <linux/types.h>
#include <errno.h>
#include <curses.h>

/* maximum number of samples */
#define CYWM_SAMPLES 82
#define CYWM_MINSIG 0
#define CYWM_AVGNUM 3

/* Graph height ...  LINES - borders - 2 for chnum */
//#define GRAPH_HEIGHT (LINES - 4)

#define GRAPH_HEIGHT LINES

#define BAUDRATE B9600

#define BUFSIZEE	256
#define DEFAULTSERIAL "/dev/ttyUSB1"

char serialdevice[257];         
int fdser;                      
struct termios oldtio, newtio;	
int char_valid;                 
char serialbuffer[BUFSIZ+1];    
int char_remaining;             
int char_index;                 
int byte_count;                 

char read_next_char(int fdser) {
   if (char_remaining == 0) {
      char_remaining = read(fdser, serialbuffer, BUFSIZEE);
      char_index = 0;
      if (char_remaining < 0) {
         char_remaining = 0;
      }
   }
   if (char_remaining) {
      char_remaining--;
      char_valid = 1;
      return(serialbuffer[char_index++]);
   }
   char_valid = 0;
   return(0);
}

int main(int argc, char *argv[]) {
	int arg;
	char buf[8];
	int a, x, graphperc, as, cursesdraw = 0, avgpos = 0;
	struct timeval tm;
	fd_set readset;
	char c ,last_c, cc, pos, lastpos;

	/* previous samples */
	int lastsignal[CYWM_SAMPLES];
	int peaksignal[CYWM_SAMPLES];
	int avgsignal[CYWM_AVGNUM][CYWM_SAMPLES];
	char line[CYWM_SAMPLES + 1];

	/* curses windows */
	WINDOW *window;
	WINDOW *sigwin;
	WINDOW *chwin;

	memset(buf, 0, sizeof(char) * 8);
	for (x = 0; x < CYWM_SAMPLES; x++) {
		lastsignal[x] = 0;
		peaksignal[x] = CYWM_MINSIG;
	}
	for (avgpos = 0; avgpos < CYWM_AVGNUM; avgpos++) {
		for (x = 0; x < CYWM_SAMPLES; x++)
			avgsignal[avgpos][x] = 0;
	}
	avgpos = 0;

	// initialise serial say ttyUSB0
	strcpy(serialdevice, DEFAULTSERIAL);

	fdser = open(serialdevice, O_RDWR | O_NOCTTY );
	if (fdser <= 0) {
	  perror("rng: Problem opening serial device; check device name.");
	  exit(1);
	}
	
	tcgetattr(fdser, &oldtio);	/* save previous port settings */
	
	bzero(&newtio, sizeof(newtio));
	newtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD;
	newtio.c_iflag = IGNPAR;
	newtio.c_oflag = 0;
	/* set serial device input mode (non-canonical, no echo,...) */
	newtio.c_lflag = 0;
	newtio.c_cc[VTIME]    = 30;	/* 3 second timeout */
	newtio.c_cc[VMIN]     = 0;	/* block until char or timeout */
	tcsetattr(fdser, TCSANOW, &newtio);
	
	char_remaining = 0;		/* Init serial buffer */
	char_index = 0;

	/* curses init */

	initscr();
	cbreak();
	noecho();

	if (COLS < CYWM_SAMPLES + 8) {
		printf("Terminal must be at least %d characters wide\n", CYWM_SAMPLES + 8);
		return 1;
	}

	if (LINES < 24) {
		printf("Terminal must be at least %d characters high\n", 24);
		return 1;
	}

	window = subwin(stdscr, LINES, CYWM_SAMPLES + 2, 0, 0);
	sigwin = subwin(stdscr, LINES, COLS - (CYWM_SAMPLES + 2), 0, CYWM_SAMPLES + 2);
	chwin = subwin(stdscr, 2, CYWM_SAMPLES + 2, LINES, 0);
	box(window, 0, 0);

	wrefresh(window);
	wrefresh(chwin);
	wrefresh(sigwin);
	refresh();

	while (1) {

	  // read serial - if it is a '.' last is position. next is value.
	  while (pos!=81){
	  c = read_next_char(fdser);
	  if (c==']')
	    {
	      pos=last_c;
	      cc = read_next_char(fdser);
	      lastsignal[pos]=cc;
		if (cc>peaksignal[pos]) peaksignal[pos]=cc;
		avgsignal[avgpos][pos] = cc;
		//fprintf(stderr,"pos:%d.val:%d\n",pos,cc);
	    }	  
	  else	  last_c=c;
	  }
	  avgpos++;
	  if (avgpos >= CYWM_AVGNUM) avgpos = 0;
	  pos=0;

	  /*		cursesdraw++;
			if (cursesdraw > 100) {*/
			int zed;
			for (zed = 0; zed < (GRAPH_HEIGHT); zed++) {
				memset(line, ' ', CYWM_SAMPLES);
				line[CYWM_SAMPLES] = 0;

				/* modify the line */
				for (x = 0; x < CYWM_SAMPLES; x++) {
				  as=0;
				  graphperc = LINES-peaksignal[x];
				    if (graphperc <= zed && graphperc != 0)
				    line[x] = ':';
				
				  for (a = 0; a < CYWM_AVGNUM; a++) {
				    as += avgsignal[a][x];
				  }
				  as = as / CYWM_AVGNUM;
				  graphperc = LINES-as; 
				    if (graphperc <= zed)
				      line[x] = '*';
							
				}

				mvwaddstr(window, zed + 1, 1, line);
					}

			cursesdraw = 0;
			wrefresh(window);
			refresh();
			
		tm.tv_sec = 0;
		tm.tv_usec = 80;

		FD_ZERO(&readset);
		FD_SET(fileno(stdin), &readset);

		select(fileno(stdin)+1, &readset, NULL, NULL, &tm);

		if (FD_ISSET(fileno(stdin), &readset)) {
			char c = getch();

			if (c == 'c') {
				for (x = 0; x < CYWM_SAMPLES; x++) {
					peaksignal[x] = CYWM_MINSIG;
				}
			} else if (c == 'q') {
				break;
			}
		}


	}

	endwin();
	tcdrain(fdser);
	tcflush(fdser, TCIFLUSH);
	tcsetattr(fdser, TCSANOW, &oldtio); /* restore previous port settings */
	return 0;
}	

