/*************************************************************************
    > File Name: uart.c
    > Created Time: Fri 23 Oct 2020 11:02:21 AM CST
 ************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <limits.h>
#include <errno.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "bsp.h"
#include "rt.h"
#include "uart_user.h"
#include "debug_print.h"


#define UART_MAX_FD	256 //noted by sunxi: 因为传进来的UART_CHANNEL[i]不一定是连续的。

//static int am335x_uarts_fd[CFG_UART_NUM_MAX];
static int am335x_uarts_fd[UART_MAX_FD] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
											-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
											-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
											-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
											-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
											-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
											-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
											-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
											-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
											-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
											-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
											-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
											-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
											-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
											-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
											-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,};


static void am335x_uarts_init(int channel)
{
	am335x_uarts_fd[channel] = -1;
}


static int set_port(int fd, int nSpeed, int nBits, char nEvent, int nStop)
{
	struct termios newtio, oldtio;
	
	memset(&oldtio, 0, sizeof(oldtio));
	/* save the old serial port configuration */
	if(tcgetattr(fd, &oldtio) != 0) {
		perror("set_port/tcgetattr");
		return -1;	
	}
	memset(&newtio, 0, sizeof(newtio));
	/* ignore modem control lines and enable receiver */
	newtio.c_cflag |= CLOCAL | CREAD;
	newtio.c_cflag &= ~CSIZE;	
	/* set character size */
	switch (nBits) {
		case 8: 
			newtio.c_cflag |= CS8;
			break;
		case 7: 
			newtio.c_cflag |= CS7;
			break;
		case 6: 
			newtio.c_cflag |= CS6;
			break;
		case 5: 
			newtio.c_cflag |= CS5;
			break;
		default:
			newtio.c_cflag |= CS8; 
			break;
	}
	/* set the parity */
	switch (nEvent) {

		default:
		case 'N':
		case 'n':
		{
			newtio.c_cflag &= ~PARENB; 	//清除校验位
			newtio.c_iflag &= ~(ICRNL|INPCK|IXON|IXOFF);	   //关闭奇偶校验  关闭软件流控
		
			break;
		}
		
		case 'o':
		case 'O':
		{
			newtio.c_cflag |= (PARODD | PARENB); //使用奇校验不是用偶校验
			newtio.c_iflag |= INPCK;
			break;
		}
		
		case 'e':
		case 'E':
		{
			newtio.c_cflag |= PARENB;
			newtio.c_cflag &= ~PARODD; 	//使用偶校验
			newtio.c_iflag |= INPCK;
			break;
		}
		
		case 's':
		case 'S':
		{
			newtio.c_cflag &= ~PARENB;
			newtio.c_cflag &= ~CSTOPB;
			break;
		}
		
	}
	/* set the stop bits */
	switch (nStop) {
		case 1:
			newtio.c_cflag &= ~CSTOPB;
			break;
		case 2:
			newtio.c_cflag |= CSTOPB;
			break;
		default:
			newtio.c_cflag &= ~CSTOPB; 
			break;	
	}	
	/* set output and input baud rate */
	switch (nSpeed) {
		case 0:
			cfsetospeed(&newtio, B0);
			cfsetispeed(&newtio, B0);
			break;
		case 50:
			cfsetospeed(&newtio, B50);
			cfsetispeed(&newtio, B50);
			break;
		case 75:
			cfsetospeed(&newtio, B75);
			cfsetispeed(&newtio, B75);
			break;
		case 110:
			cfsetospeed(&newtio, B110);
			cfsetispeed(&newtio, B110);
			break;
		case 134:
			cfsetospeed(&newtio, B134);
			cfsetispeed(&newtio, B134);
			break;
		case 150:
			cfsetospeed(&newtio, B150);
			cfsetispeed(&newtio, B150);
			break;
		case 200:
			cfsetospeed(&newtio, B200);
			cfsetispeed(&newtio, B200);
			break;
		case 300:
			cfsetospeed(&newtio, B300);
			cfsetispeed(&newtio, B300);
			break;
		case 600:
			cfsetospeed(&newtio, B600);
			cfsetispeed(&newtio, B600);
			break;
		case 1200:
			cfsetospeed(&newtio, B1200);
			cfsetispeed(&newtio, B1200);
			break;
		case 1800:
			cfsetospeed(&newtio, B1800);
			cfsetispeed(&newtio, B1800);
			break;
		case 2400:
			cfsetospeed(&newtio, B2400);
			cfsetispeed(&newtio, B2400);
			break;
		case 4800:
			cfsetospeed(&newtio, B4800);
			cfsetispeed(&newtio, B4800);
			break;
		case 9600:
			cfsetospeed(&newtio, B9600);
			cfsetispeed(&newtio, B9600);
			break;
		case 19200:
			cfsetospeed(&newtio, B19200);
			cfsetispeed(&newtio, B19200);
			break;
		case 38400:
			cfsetospeed(&newtio, B38400);
			cfsetispeed(&newtio, B38400);
			break;
		case 57600:
			cfsetospeed(&newtio, B57600);
			cfsetispeed(&newtio, B57600);
			break;
		case 115200:
			cfsetospeed(&newtio, B115200);
			cfsetispeed(&newtio, B115200);
			break;
		case 230400:
			cfsetospeed(&newtio, B230400);
			cfsetispeed(&newtio, B230400);
			break;
		default:
			cfsetospeed(&newtio, B115200);
			cfsetispeed(&newtio, B115200);
			break;	
	}
	/* set timeout in deciseconds for non-canonical read */
	newtio.c_cc[VTIME] = 0;
	/* set minimum number of characters for non-canonical read */
	newtio.c_cc[VMIN] = 0;
	/* flushes data received but not read */
	tcflush(fd, TCIFLUSH);
	/* set the parameters associated with the terminal from 
		the termios structure and the change occurs immediately */
	if((tcsetattr(fd, TCSANOW, &newtio))!=0)
	{
		perror("set_port/tcsetattr");
		return -1;
	}
	
	return 0;
}


int uart_open(int channel, uint32_t baudRate, int setting)
{
	/*
	 * Initialize UART for serial communications
	 */
	char tty_name[16] = {0x00};
	int ret;
	char parity;

	if(channel > (UART_MAX_FD - 1) || channel < 0)
	{
		return -1;
	}

	if (am335x_uarts_fd[channel] < 0)
	{
		am335x_uarts_init(channel);
		memset(tty_name,0,sizeof(tty_name));
		sprintf(tty_name, "/dev/ttyAS%d", channel);	//sprintf(tty_name, "/dev/ttyO%d", channel); by ygl 2025.6.13
		am335x_uarts_fd[channel] = open(tty_name, O_RDWR, 0);
		if(am335x_uarts_fd[channel] < 0)
		{
			dp_err_n_c("inside open %s failed!\n", tty_name);
			return am335x_uarts_fd[channel];
		}
	} 
	
	switch(setting)
	{
		case PARITY_EVEN://偶校验
			parity = 'E';
			break;
		case PARITY_ODD://奇校验
			parity = 'O';
			break;
		case PARITY_NONE://无校验
		default:
			parity = 'N';
			break;
	}

	ret = set_port(am335x_uarts_fd[channel], baudRate, 8, parity, 1);
	if(ret < 0)
	{
		close(am335x_uarts_fd[channel]);
		perror("set_port failed");
		return -2;

	}

	
	return 0;
}

void uart_close(int channel)
{
	if(channel > (UART_MAX_FD - 1))
	{
		return;
	}
	if(am335x_uarts_fd[channel] >= 0)
	{
		close(am335x_uarts_fd[channel]);
		am335x_uarts_fd[channel] = -1;
	}
}

int uart_write(int channel, const char *data, int count)
{
	int ret;

	if((channel > (UART_MAX_FD - 1)) || (data == NULL))
		return -1;

	if(am335x_uarts_fd[channel] < 0)
		return -2;

	ret = write(am335x_uarts_fd[channel], data, count);

	return ret;
}

void uart_puts (int channel, char *ch)
{
	int write_len;

	if(ch == NULL)
		return;

	write_len = strlen(ch);
	uart_write(channel, (const char *)ch, write_len);

}

int uart_read(int channel, char *data, int count)
{
	int ret;

	if((channel > (UART_MAX_FD - 1)) || (data == NULL))
		return -1;

	if(am335x_uarts_fd[channel] < 0)
		return -2;

	ret = read(am335x_uarts_fd[channel], data, count);

	return ret;
}

//noted by sunxi: 这个是read的select.
int uart_select(int channel)
{
	int ret;
	struct timeval tv;
	fd_set rset;
	tv.tv_sec = 0;
	tv.tv_usec = 10000;

	if(channel > (UART_MAX_FD - 1))
		return -1;

	if(am335x_uarts_fd[channel] < 0)
		return -2;
	
	FD_ZERO(&rset); 
	FD_SET(am335x_uarts_fd[channel], &rset);	

	ret = select(am335x_uarts_fd[channel]+1, &rset, NULL, NULL, &tv); 

	return ret;
}

/********************************************************************/
/*
 * Wait for a character to be received on the specified UART
 *
 * Return Values:
 *  the received character
 */
char uart_getchar (int channel)
{
    return 0;
}
int uart_getchar2 (int channel,char *ch)
{
	int ret = uart_read(channel, ch, 1);
    return ret;
}

/********************************************************************/
/*
 * Wait for space in the UART Tx FIFO and then send a character
 */
void uart_putchar (int channel, char ch)
{
}

void uart_putchar2 (int channel, char ch)
{
	uart_write(channel, (const char *)&ch, 1);
}

int uart_init(void)
{
	int i, ret;

	for(i = 0; i < CFG_UART_NUM_MAX; i++)
	{
		if((UART_CHANNEL[i]==g_con_uart_index) || (UART_CHANNEL[i]==CFG_UART_HMI))
		{
			continue;
		}

		ret = uart_open(i,115200,PARITY_NONE);
		if (ret < 0)
		{
			dp_err_n_c("%s: outside uart %d open failed!\n", __FUNCTION__, i);
		}
	}

	return 0;
}

void uart_exit(void)
{
	int i;
	printf("uart_exit\n");//sunxi for test

	for(i = 0; i < CFG_UART_NUM_MAX; i++)
	{
		if((UART_CHANNEL[i]==g_con_uart_index) || (UART_CHANNEL[i]==CFG_UART_HMI))
		{
			continue;
		}

		uart_close(i);
	}
}

int uart_test(void)
{
	char tmp[] = "hello sunxi!";
//	u8 c;
	int ret;
	static unsigned char buf[256];
	static int ret_cnt =0;
	int i;

	
	uart_open(1,9600,PARITY_EVEN);

	uart_write(1, (const char *)&tmp, strlen(tmp));

	for(i = 0; i < 500; i++)
	{

		ret = uart_select(1);

		//有数据可读
		if(ret > 0)
		{
			printf("\nch_%d have select.",1);
		
			//读取数据
			memset(buf,0,sizeof(buf));
			ret = uart_read(1, buf, sizeof(buf));			
			if(ret != -1)
			{

				//测试代码
				printf("\nch_%d RECV num=%d:",1,ret);
				for(i = 0; i < ret; i++)
				{
					printf("%02x ", (unsigned char)buf[i]); 
				}		
				printf("\n");

				if(++ret_cnt >= 3)
				{
					ret_cnt = 0;
					uart_write(1, buf, ret);

				}


			}
	
		}
			
	}

	return 0;
}



