/*
* File : uart.c
* Copyright (C) 2013 - 2016, Espressif Systems
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of version 3 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program 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.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
#include "ets_sys.h"
#include "osapi.h"
#include "driver/uart.h"
#include "osapi.h"
#include "driver/uart_register.h"
#include "mem.h"
#include "os_type.h"
#ifdef _ENABLE_RING_BUFFER
static ringbuf_t rxBuff;
static ringbuf_t txBuff;
#endif
#ifdef _ENABLE_CONSOLE_INTEGRATION
uint8_t linked_to_console = 0;
uint8_t echo_on = 1;
#endif
extern UartDevice UartDev;
/* Local variables */
static uint8 uart_recvTaskPrio = 0;
/* Internal Functions */
static void ICACHE_FLASH_ATTR uart_config(uint8 uart_no);
static void uart0_rx_intr_handler(void *para);
/* Public APIs */
void ICACHE_FLASH_ATTR UART_init(UartBautRate uart0_br, UartBautRate uart1_br, uint8 recv_task_priority);
#define ENABLE_DEBUG
#ifdef ENABLE_DEBUG
#define DBG
#define DBG1 os_printf
#define DBG2 os_printf
#else
#define DBG
#define DBG1
#define DBG2
#endif
#if _ENABLE_CONSOLE_INTEGRATION == 1
void ICACHE_FLASH_ATTR UART_init_console(UartBautRate uart0_br,
uint8 recv_task_priority,
ringbuf_t rxbuffer,
ringbuf_t txBuffer)
{
/* Set the task which should receive the signals once the data is received */
uart_recvTaskPrio = recv_task_priority;
UartDev.baut_rate = uart0_br;
rxBuff = rxbuffer;
txBuff = txBuffer;
linked_to_console = 1;
echo_on = 1;
uart_config(UART0);
UART_SetPrintPort(UART0);
UartDev.baut_rate = uart0_br;
uart_config(UART1);
ETS_UART_INTR_ENABLE();
}
#endif
void ICACHE_FLASH_ATTR UART_init(UartBautRate uart0_br, UartBautRate uart1_br, uint8 recv_task_priority)
{
/* Set the task which should receive the signals once the data is received */
uart_recvTaskPrio = recv_task_priority;
UartDev.baut_rate = uart0_br;
uart_config(UART0);
UART_SetPrintPort(UART0);
UartDev.baut_rate = uart1_br;
uart_config(UART1);
ETS_UART_INTR_ENABLE();
#if _ENABLE_CONSOLE_INTEGRATION == 0
#if _ENABLE_RING_BUFFER == 1
rxBuff = ringbuf_new(RX_RING_BUFFER_SIZE);
#endif
#endif
}
/******************************************************************************
* FunctionName : uart_config
* Description : Internal used function
* UART0 used for data TX/RX, RX buffer size is 0x100, interrupt enabled
* UART1 just used for debug output
* Parameters : uart_no, use UART0 or UART1 defined ahead
* Returns : NONE
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR uart_config(uint8 uart_no)
{
if (uart_no == UART1)
{
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK);
}
else
{
/* rcv_buff size if 0x100 */
ETS_UART_INTR_ATTACH(uart0_rx_intr_handler, &(UartDev.rcv_buff));
PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD);
#if UART_HW_RTS
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_U0RTS); //HW FLOW CONTROL RTS PIN
#endif
#if UART_HW_CTS
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_U0CTS); //HW FLOW CONTROL CTS PIN
#endif
}
uart_div_modify(uart_no, UART_CLK_FREQ / (UartDev.baut_rate));//SET BAUDRATE
WRITE_PERI_REG(UART_CONF0(uart_no), ((UartDev.exist_parity & UART_PARITY_EN_M) << UART_PARITY_EN_S) //SET BIT AND PARITY MODE
| ((UartDev.parity & UART_PARITY_M) <>UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT;
if (fifo_len)
{
max_unload = (fifo_len>UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT;
//DBG1("RX FIFO FULL [%d]\r\n", fifo_len );
if (fifo_len)
{
//DBG1("Rx Fifo contains %d characters have to unload\r\n", fifo_len);
for (index=0;index>UART_RXFIFO_CNT_S)& UART_RXFIFO_CNT);
uart_rx_intr_disable(UART0);
WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_FULL_INT_CLR);
system_os_post(uart_recvTaskPrio, SIG_UART0, 0);
#endif
goto end_int_handler;
}
if(UART_RXFIFO_TOUT_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_TOUT_INT_ST))
{
/* The Time out threshold for Rx/Tx is being execeeded */
DBG1("Rx Timeout Threshold not being met \r\n");
uart_rx_intr_disable(UART0);
WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_TOUT_INT_CLR);
system_os_post(uart_recvTaskPrio, SIG_UART0, 0);
goto end_int_handler;
}
if(UART_TXFIFO_EMPTY_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_TXFIFO_EMPTY_INT_ST))
{
/* The Tx FIFO is empty, the FIFO needs to be fed with new data */
DBG1("Tx FIFO is empty\r\n");
CLEAR_PERI_REG_MASK(UART_INT_ENA(UART0), UART_TXFIFO_EMPTY_INT_ENA);
#if UART_BUFF_EN
tx_start_uart_buffer(UART0);
#endif
//system_os_post(uart_recvTaskPrio, 1, 0);
WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_TXFIFO_EMPTY_INT_CLR);
}
end_int_handler:
return;
}
/******************************************************************************
* FunctionName : uart_tx_one_char_no_wait
* Description : uart tx a single char without waiting for fifo
* Parameters : uint8 uart - uart port
* uint8 TxChar - char to tx
* Returns : STATUS
*******************************************************************************/
STATUS uart_tx_one_char(uint8 uart, uint8 TxChar)
{
while (true)
{
uint32 fifo_cnt = READ_PERI_REG(UART_STATUS(uart)) & (UART_TXFIFO_CNT<> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) < 126) {
break;
}
}
WRITE_PERI_REG(UART_FIFO(uart) , TxChar);
return OK;
}
/******************************************************************************
* FunctionName : uart_tx_one_char_no_wait
* Description : uart tx a single char without waiting for fifo
* Parameters : uint8 uart - uart port
* uint8 TxChar - char to tx
* Returns : STATUS
*******************************************************************************/
STATUS uart_tx_one_char_no_wait(uint8 uart, uint8 TxChar)
{
uint8 fifo_cnt = (( READ_PERI_REG(UART_STATUS(uart))>>UART_TXFIFO_CNT_S)& UART_TXFIFO_CNT);
if (fifo_cnt < 126)
{
WRITE_PERI_REG(UART_FIFO(uart) , TxChar);
}
return OK;
}
/******************************************************************************
* FunctionName : uart0_write_char_no_wait
* Description : tx a single char without waiting for uart 0.
helper function for os_printf output to fifo or tx buffer
* Parameters : uint8 uart - uart port
* uint8 TxChar - char to tx
* Returns : STATUS
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR uart0_write_char_no_wait(char c)
{
#if UART_BUFF_EN //send to uart0 fifo but do not wait
uint8 chr;
if (c == '\n'){
chr = '\r';
tx_buff_enq(&chr, 1);
chr = '\n';
tx_buff_enq(&chr, 1);
}else if (c == '\r'){
}else{
tx_buff_enq(&c,1);
}
#else //send to uart tx buffer
if (c == '\n')
{
uart_tx_one_char(UART0, '\r');
uart_tx_one_char(UART0, '\n');
//uart_tx_one_char_no_wait(UART0, '\r');
//uart_tx_one_char_no_wait(UART0, '\n');
}
else
if (c == '\r')
{
uart_tx_one_char(UART0, c);
}
else
{
uart_tx_one_char(UART0, c);
//uart_tx_one_char_no_wait(UART0, c);
}
#endif
}
/******************************************************************************
* FunctionName : UART_SetPrintPort
* Description :
*
* Parameters :
* Returns : NONE
*******************************************************************************/
void ICACHE_FLASH_ATTR UART_SetPrintPort(uint8 uart_no)
{
if(uart_no==1)
{
//os_install_putc1(uart1_write_char);
}
else
{
/*option 1: do not wait if uart fifo is full,drop current character*/
//os_install_putc1(uart0_write_char_no_wait);
/*option 2: wait for a while if uart fifo is full*/
//os_install_putc1(uart0_write_char);
}
}