#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/select.h>

#include <libwr/shw_io.h>
#include "fpga_io.h"
#include <libwr/switch_hw.h>

#define UART_BASE 0x10800
#define UART_SR  0x00
#define UART_TDR 0x08
#define UART_RDR 0x0C
#define RDR_RDY_MSK 0x02
#define SR_TX_BUSY_MSK 0x01
#define RDR_DAT_MSK 0xff


int uart_tx(char *buf, int size)
{
	int tx_busy;
	while(size--)
		tx_busy = _fpga_readl(UART_BASE+UART_SR) & SR_TX_BUSY_MSK;
		if(!tx_busy){
            _fpga_writel(UART_BASE+UART_TDR, *buf++);
            usleep(10);
        }
	return 0;
}

int uart_rx(char *buf, int size)
{
	int n_rx = 0;
	int rdr, rx_rdy;

	while(size--) {
		rx_rdy = _fpga_readl(UART_BASE+UART_SR) & RDR_RDY_MSK;
		rdr = _fpga_readl(UART_BASE+UART_RDR);
		if(rx_rdy) {
			*buf++ = (rdr & RDR_DAT_MSK);
			++n_rx;
		} else
			return n_rx;
	}

	return n_rx;
}

static int transfer_byte(int from) {
	char c;
	int ret;
	do {
		ret = read(from, &c, 1);
	} while (ret < 0 && errno == EINTR);
	if(ret == 1) {
		uart_tx(&c, 1);
	} else {
		fprintf(stderr, "nothing to read. Port disconnected?\n");
		return -2;
	}
	return 0;
}


void term_main(void)
{
	while(1) {
		fd_set fds;
		int ret;
		char rx;
        int n_rx;
		struct timeval tv = {0, 10000};

		FD_ZERO(&fds);
		FD_SET(STDIN_FILENO, &fds);

		ret = select(STDIN_FILENO+1, &fds, NULL, NULL, &tv);
		if(ret == -1) {
			perror("select");
		} else if (ret > 0) {
			if(FD_ISSET(STDIN_FILENO, &fds)) {
				transfer_byte(STDIN_FILENO);
			}
		}

		while(uart_rx(&rx,1) == 1)
	 		fprintf(stderr,"%c", rx);
		 // usleep(1000); /* relief the CPU */
	}

}


int main(void)
{
	shw_fpga_mmap_init();
	term_main();

	return 0;
}



