2016-12-15 09:45:40 +08:00
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include "esp_types.h"
#include "esp_attr.h"
#include "esp_intr.h"
#include "esp_intr_alloc.h"
#include "esp_log.h"
#include "esp_err.h"
2017-08-21 22:30:23 +08:00
#include "esp_clk.h"
2016-12-15 09:45:40 +08:00
#include "malloc.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/xtensa_api.h"
#include "freertos/task.h"
#include "freertos/ringbuf.h"
#include "soc/dport_reg.h"
#include "soc/uart_struct.h"
#include "driver/uart.h"
#include "driver/gpio.h"
2018-05-03 10:41:10 +02:00
#include "driver/uart_select.h"
2016-12-15 09:45:40 +08:00
2017-08-01 16:02:44 +01:00
#define XOFF (char)0x13
#define XON (char)0x11
2016-12-15 09:45:40 +08:00
static const char * UART_TAG = "uart" ;
#define UART_CHECK(a, str, ret_val) \
if (!(a)) { \
ESP_LOGE(UART_TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \
return (ret_val); \
}
#define UART_EMPTY_THRESH_DEFAULT (10)
#define UART_FULL_THRESH_DEFAULT (120)
#define UART_TOUT_THRESH_DEFAULT (10)
2018-07-13 21:55:54 +08:00
#define UART_CLKDIV_FRAG_BIT_WIDTH (3)
#define UART_TOUT_REF_FACTOR_DEFAULT (UART_CLK_FREQ/(REF_CLK_FREQ<<UART_CLKDIV_FRAG_BIT_WIDTH))
2017-10-18 12:04:59 +08:00
#define UART_TX_IDLE_NUM_DEFAULT (0)
2017-08-25 21:04:13 +08:00
#define UART_PATTERN_DET_QLEN_DEFAULT (10)
2018-08-14 03:40:31 +03:00
#define UART_MIN_WAKEUP_THRESH (2)
2017-08-25 21:04:13 +08:00
2016-12-15 09:45:40 +08:00
#define UART_ENTER_CRITICAL_ISR(mux) portENTER_CRITICAL_ISR(mux)
#define UART_EXIT_CRITICAL_ISR(mux) portEXIT_CRITICAL_ISR(mux)
#define UART_ENTER_CRITICAL(mux) portENTER_CRITICAL(mux)
#define UART_EXIT_CRITICAL(mux) portEXIT_CRITICAL(mux)
2018-04-11 11:56:00 +05:00
// Check actual UART mode set
#define UART_IS_MODE_SET(uart_number, mode) ((p_uart_obj[uart_number]->uart_mode == mode))
2016-12-15 09:45:40 +08:00
typedef struct {
uart_event_type_t type ; /*!< UART TX data type */
struct {
int brk_len ;
size_t size ;
uint8_t data [ 0 ];
} tx_data ;
} uart_tx_data_t ;
2017-08-25 21:04:13 +08:00
typedef struct {
int wr ;
int rd ;
int len ;
int * data ;
} uart_pat_rb_t ;
2016-12-15 09:45:40 +08:00
typedef struct {
uart_port_t uart_num ; /*!< UART port number*/
int queue_size ; /*!< UART event queue size*/
QueueHandle_t xQueueUart ; /*!< UART queue handler*/
intr_handle_t intr_handle ; /*!< UART interrupt handle*/
2018-04-11 11:56:00 +05:00
uart_mode_t uart_mode ; /*!< UART controller actual mode set by uart_set_mode() */
bool coll_det_flg ; /*!< UART collision detection flag */
2016-12-15 09:45:40 +08:00
//rx parameters
2016-12-19 12:52:10 +08:00
int rx_buffered_len ; /*!< UART cached data length */
2016-12-15 09:45:40 +08:00
SemaphoreHandle_t rx_mux ; /*!< UART RX data mutex*/
int rx_buf_size ; /*!< RX ring buffer size */
RingbufHandle_t rx_ring_buf ; /*!< RX ring buffer handler*/
bool rx_buffer_full_flg ; /*!< RX ring buffer full flag. */
int rx_cur_remain ; /*!< Data number that waiting to be read out in ring buffer item*/
uint8_t * rx_ptr ; /*!< pointer to the current data in ring buffer*/
uint8_t * rx_head_ptr ; /*!< pointer to the head of RX item*/
uint8_t rx_data_buf [ UART_FIFO_LEN ]; /*!< Data buffer to stash FIFO data*/
uint8_t rx_stash_len ; /*!< stashed data length.(When using flow control, after reading out FIFO data, if we fail to push to buffer, we can just stash them.) */
2017-08-25 21:04:13 +08:00
uart_pat_rb_t rx_pattern_pos ;
2016-12-15 09:45:40 +08:00
//tx parameters
SemaphoreHandle_t tx_fifo_sem ; /*!< UART TX FIFO semaphore*/
SemaphoreHandle_t tx_mux ; /*!< UART TX mutex*/
SemaphoreHandle_t tx_done_sem ; /*!< UART TX done semaphore*/
SemaphoreHandle_t tx_brk_sem ; /*!< UART TX send break done semaphore*/
int tx_buf_size ; /*!< TX ring buffer size */
RingbufHandle_t tx_ring_buf ; /*!< TX ring buffer handler*/
bool tx_waiting_fifo ; /*!< this flag indicates that some task is waiting for FIFO empty interrupt, used to send all data without any data buffer*/
uint8_t * tx_ptr ; /*!< TX data pointer to push to FIFO in TX buffer mode*/
uart_tx_data_t * tx_head ; /*!< TX data pointer to head of the current buffer in TX ring buffer*/
uint32_t tx_len_tot ; /*!< Total length of current item in ring buffer*/
uint32_t tx_len_cur ;
uint8_t tx_brk_flg ; /*!< Flag to indicate to send a break signal in the end of the item sending procedure */
uint8_t tx_brk_len ; /*!< TX break signal cycle length/number */
uint8_t tx_waiting_brk ; /*!< Flag to indicate that TX FIFO is ready to send break signal after FIFO is empty, do not push data into TX FIFO right now.*/
2018-05-03 10:41:10 +02:00
uart_select_notif_callback_t uart_select_notif_callback ; /*!< Notification about select() events */
2016-12-15 09:45:40 +08:00
} uart_obj_t ;
static uart_obj_t * p_uart_obj [ UART_NUM_MAX ] = { 0 };
/* DRAM_ATTR is required to avoid UART array placed in flash, due to accessed from ISR */
static DRAM_ATTR uart_dev_t * const UART [ UART_NUM_MAX ] = { & UART0 , & UART1 , & UART2 };
static portMUX_TYPE uart_spinlock [ UART_NUM_MAX ] = { portMUX_INITIALIZER_UNLOCKED , portMUX_INITIALIZER_UNLOCKED , portMUX_INITIALIZER_UNLOCKED };
2018-05-03 10:41:10 +02:00
static portMUX_TYPE uart_selectlock = portMUX_INITIALIZER_UNLOCKED ;
2016-12-15 09:45:40 +08:00
esp_err_t uart_set_word_length ( uart_port_t uart_num , uart_word_length_t data_bit )
{
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ESP_FAIL );
UART_CHECK (( data_bit < UART_DATA_BITS_MAX ), "data bit error" , ESP_FAIL );
UART_ENTER_CRITICAL ( & uart_spinlock [ uart_num ]);
UART [ uart_num ] -> conf0 . bit_num = data_bit ;
UART_EXIT_CRITICAL ( & uart_spinlock [ uart_num ]);
return ESP_OK ;
}
esp_err_t uart_get_word_length ( uart_port_t uart_num , uart_word_length_t * data_bit )
{
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ESP_FAIL );
* ( data_bit ) = UART [ uart_num ] -> conf0 . bit_num ;
return ESP_OK ;
}
esp_err_t uart_set_stop_bits ( uart_port_t uart_num , uart_stop_bits_t stop_bit )
{
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ESP_FAIL );
UART_CHECK (( stop_bit < UART_STOP_BITS_MAX ), "stop bit error" , ESP_FAIL );
2017-03-02 13:41:32 +08:00
2016-12-15 09:45:40 +08:00
UART_ENTER_CRITICAL ( & uart_spinlock [ uart_num ]);
2017-03-02 13:41:32 +08:00
//workaround for hardware bug, when uart stop bit set as 2-bit mode.
if ( stop_bit == UART_STOP_BITS_2 ) {
stop_bit = UART_STOP_BITS_1 ;
UART [ uart_num ] -> rs485_conf . dl1_en = 1 ;
} else {
UART [ uart_num ] -> rs485_conf . dl1_en = 0 ;
}
2016-12-15 09:45:40 +08:00
UART [ uart_num ] -> conf0 . stop_bit_num = stop_bit ;
UART_EXIT_CRITICAL ( & uart_spinlock [ uart_num ]);
return ESP_OK ;
}
esp_err_t uart_get_stop_bits ( uart_port_t uart_num , uart_stop_bits_t * stop_bit )
{
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ESP_FAIL );
2017-03-02 13:41:32 +08:00
//workaround for hardware bug, when uart stop bit set as 2-bit mode.
if ( UART [ uart_num ] -> rs485_conf . dl1_en == 1 && UART [ uart_num ] -> conf0 . stop_bit_num == UART_STOP_BITS_1 ) {
( * stop_bit ) = UART_STOP_BITS_2 ;
} else {
( * stop_bit ) = UART [ uart_num ] -> conf0 . stop_bit_num ;
}
2016-12-15 09:45:40 +08:00
return ESP_OK ;
}
esp_err_t uart_set_parity ( uart_port_t uart_num , uart_parity_t parity_mode )
{
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ESP_FAIL );
UART_ENTER_CRITICAL ( & uart_spinlock [ uart_num ]);
UART [ uart_num ] -> conf0 . parity = parity_mode & 0x1 ;
UART [ uart_num ] -> conf0 . parity_en = ( parity_mode >> 1 ) & 0x1 ;
UART_EXIT_CRITICAL ( & uart_spinlock [ uart_num ]);
return ESP_OK ;
}
esp_err_t uart_get_parity ( uart_port_t uart_num , uart_parity_t * parity_mode )
{
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ESP_FAIL );
int val = UART [ uart_num ] -> conf0 . val ;
if ( val & UART_PARITY_EN_M ) {
if ( val & UART_PARITY_M ) {
( * parity_mode ) = UART_PARITY_ODD ;
} else {
( * parity_mode ) = UART_PARITY_EVEN ;
}
} else {
( * parity_mode ) = UART_PARITY_DISABLE ;
}
return ESP_OK ;
}
esp_err_t uart_set_baudrate ( uart_port_t uart_num , uint32_t baud_rate )
{
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ESP_FAIL );
2017-08-21 22:30:23 +08:00
esp_err_t ret = ESP_OK ;
2016-12-15 09:45:40 +08:00
UART_ENTER_CRITICAL ( & uart_spinlock [ uart_num ]);
2017-08-21 22:30:23 +08:00
int uart_clk_freq ;
if ( UART [ uart_num ] -> conf0 . tick_ref_always_on == 0 ) {
/* this UART has been configured to use REF_TICK */
uart_clk_freq = REF_CLK_FREQ ;
} else {
uart_clk_freq = esp_clk_apb_freq ();
}
uint32_t clk_div = ((( uart_clk_freq ) << 4 ) / baud_rate );
if ( clk_div < 16 ) {
/* baud rate is too high for this clock frequency */
ret = ESP_ERR_INVALID_ARG ;
} else {
UART [ uart_num ] -> clk_div . div_int = clk_div >> 4 ;
UART [ uart_num ] -> clk_div . div_frag = clk_div & 0xf ;
}
2016-12-15 09:45:40 +08:00
UART_EXIT_CRITICAL ( & uart_spinlock [ uart_num ]);
2017-08-21 22:30:23 +08:00
return ret ;
2016-12-15 09:45:40 +08:00
}
esp_err_t uart_get_baudrate ( uart_port_t uart_num , uint32_t * baudrate )
{
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ESP_FAIL );
UART_ENTER_CRITICAL ( & uart_spinlock [ uart_num ]);
uint32_t clk_div = ( UART [ uart_num ] -> clk_div . div_int << 4 ) | UART [ uart_num ] -> clk_div . div_frag ;
UART_EXIT_CRITICAL ( & uart_spinlock [ uart_num ]);
2018-04-24 16:11:02 +08:00
uint32_t uart_clk_freq = esp_clk_apb_freq ();
if ( UART [ uart_num ] -> conf0 . tick_ref_always_on == 0 ) {
uart_clk_freq = REF_CLK_FREQ ;
}
( * baudrate ) = (( uart_clk_freq ) << 4 ) / clk_div ;
2016-12-15 09:45:40 +08:00
return ESP_OK ;
}
esp_err_t uart_set_line_inverse ( uart_port_t uart_num , uint32_t inverse_mask )
{
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ESP_FAIL );
2017-06-27 16:41:59 +08:00
UART_CHECK (((( inverse_mask & ~ UART_LINE_INV_MASK ) == 0 ) || ( inverse_mask == 0 )), "inverse_mask error" , ESP_FAIL );
2016-12-15 09:45:40 +08:00
UART_ENTER_CRITICAL ( & uart_spinlock [ uart_num ]);
CLEAR_PERI_REG_MASK ( UART_CONF0_REG ( uart_num ), UART_LINE_INV_MASK );
SET_PERI_REG_MASK ( UART_CONF0_REG ( uart_num ), inverse_mask );
UART_EXIT_CRITICAL ( & uart_spinlock [ uart_num ]);
return ESP_OK ;
}
2017-08-01 16:02:44 +01:00
esp_err_t uart_set_sw_flow_ctrl ( uart_port_t uart_num , bool enable , uint8_t rx_thresh_xon , uint8_t rx_thresh_xoff )
{
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ESP_FAIL );
UART_CHECK (( rx_thresh_xon < UART_FIFO_LEN ), "rx flow xon thresh error" , ESP_FAIL );
UART_CHECK (( rx_thresh_xoff < UART_FIFO_LEN ), "rx flow xon thresh error" , ESP_FAIL );
UART_ENTER_CRITICAL ( & uart_spinlock [ uart_num ]);
UART [ uart_num ] -> flow_conf . sw_flow_con_en = enable ? 1 : 0 ;
UART [ uart_num ] -> flow_conf . xonoff_del = enable ? 1 : 0 ;
UART [ uart_num ] -> swfc_conf . xon_threshold = rx_thresh_xon ;
UART [ uart_num ] -> swfc_conf . xoff_threshold = rx_thresh_xoff ;
UART [ uart_num ] -> swfc_conf . xon_char = XON ;
UART [ uart_num ] -> swfc_conf . xoff_char = XOFF ;
UART_EXIT_CRITICAL ( & uart_spinlock [ uart_num ]);
return ESP_OK ;
}
2016-12-15 09:45:40 +08:00
//only when UART_HW_FLOWCTRL_RTS is set , will the rx_thresh value be set.
esp_err_t uart_set_hw_flow_ctrl ( uart_port_t uart_num , uart_hw_flowcontrol_t flow_ctrl , uint8_t rx_thresh )
{
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ESP_FAIL );
UART_CHECK (( rx_thresh < UART_FIFO_LEN ), "rx flow thresh error" , ESP_FAIL );
UART_CHECK (( flow_ctrl < UART_HW_FLOWCTRL_MAX ), "hw_flowctrl mode error" , ESP_FAIL );
UART_ENTER_CRITICAL ( & uart_spinlock [ uart_num ]);
if ( flow_ctrl & UART_HW_FLOWCTRL_RTS ) {
UART [ uart_num ] -> conf1 . rx_flow_thrhd = rx_thresh ;
UART [ uart_num ] -> conf1 . rx_flow_en = 1 ;
} else {
UART [ uart_num ] -> conf1 . rx_flow_en = 0 ;
}
if ( flow_ctrl & UART_HW_FLOWCTRL_CTS ) {
UART [ uart_num ] -> conf0 . tx_flow_en = 1 ;
} else {
UART [ uart_num ] -> conf0 . tx_flow_en = 0 ;
}
UART_EXIT_CRITICAL ( & uart_spinlock [ uart_num ]);
return ESP_OK ;
}
esp_err_t uart_get_hw_flow_ctrl ( uart_port_t uart_num , uart_hw_flowcontrol_t * flow_ctrl )
{
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ESP_FAIL );
uart_hw_flowcontrol_t val = UART_HW_FLOWCTRL_DISABLE ;
if ( UART [ uart_num ] -> conf1 . rx_flow_en ) {
val |= UART_HW_FLOWCTRL_RTS ;
}
if ( UART [ uart_num ] -> conf0 . tx_flow_en ) {
val |= UART_HW_FLOWCTRL_CTS ;
}
( * flow_ctrl ) = val ;
return ESP_OK ;
}
2017-11-07 18:19:23 +08:00
static esp_err_t uart_reset_rx_fifo ( uart_port_t uart_num )
2016-12-15 09:45:40 +08:00
{
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ESP_FAIL );
2018-01-03 17:18:32 +08:00
//Due to hardware issue, we can not use fifo_rst to reset uart fifo.
//See description about UART_TXFIFO_RST and UART_RXFIFO_RST in <<esp32_technical_reference_manual>> v2.6 or later.
// we read the data out and make `fifo_len == 0 && rd_addr == wr_addr`.
while ( UART [ uart_num ] -> status . rxfifo_cnt != 0 || ( UART [ uart_num ] -> mem_rx_status . wr_addr != UART [ uart_num ] -> mem_rx_status . rd_addr )) {
2017-11-07 18:19:23 +08:00
READ_PERI_REG ( UART_FIFO_REG ( uart_num ));
}
2016-12-15 09:45:40 +08:00
return ESP_OK ;
}
esp_err_t uart_clear_intr_status ( uart_port_t uart_num , uint32_t clr_mask )
{
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ESP_FAIL );
//intr_clr register is write-only
UART [ uart_num ] -> int_clr . val = clr_mask ;
return ESP_OK ;
}
esp_err_t uart_enable_intr_mask ( uart_port_t uart_num , uint32_t enable_mask )
{
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ESP_FAIL );
UART_ENTER_CRITICAL ( & uart_spinlock [ uart_num ]);
SET_PERI_REG_MASK ( UART_INT_CLR_REG ( uart_num ), enable_mask );
SET_PERI_REG_MASK ( UART_INT_ENA_REG ( uart_num ), enable_mask );
UART_EXIT_CRITICAL ( & uart_spinlock [ uart_num ]);
return ESP_OK ;
}
esp_err_t uart_disable_intr_mask ( uart_port_t uart_num , uint32_t disable_mask )
{
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ESP_FAIL );
UART_ENTER_CRITICAL ( & uart_spinlock [ uart_num ]);
CLEAR_PERI_REG_MASK ( UART_INT_ENA_REG ( uart_num ), disable_mask );
UART_EXIT_CRITICAL ( & uart_spinlock [ uart_num ]);
return ESP_OK ;
}
2017-08-25 21:04:13 +08:00
static esp_err_t uart_pattern_link_free ( uart_port_t uart_num )
{
UART_CHECK (( p_uart_obj [ uart_num ]), "uart driver error" , ESP_FAIL );
if ( p_uart_obj [ uart_num ] -> rx_pattern_pos . data != NULL ) {
int * pdata = p_uart_obj [ uart_num ] -> rx_pattern_pos . data ;
UART_ENTER_CRITICAL ( & uart_spinlock [ uart_num ]);
p_uart_obj [ uart_num ] -> rx_pattern_pos . data = NULL ;
p_uart_obj [ uart_num ] -> rx_pattern_pos . wr = 0 ;
p_uart_obj [ uart_num ] -> rx_pattern_pos . rd = 0 ;
UART_EXIT_CRITICAL ( & uart_spinlock [ uart_num ]);
free ( pdata );
}
return ESP_OK ;
}
static esp_err_t uart_pattern_enqueue ( uart_port_t uart_num , int pos )
{
UART_CHECK (( p_uart_obj [ uart_num ]), "uart driver error" , ESP_FAIL );
esp_err_t ret = ESP_OK ;
UART_ENTER_CRITICAL ( & uart_spinlock [ uart_num ]);
uart_pat_rb_t * p_pos = & p_uart_obj [ uart_num ] -> rx_pattern_pos ;
int next = p_pos -> wr + 1 ;
if ( next >= p_pos -> len ) {
next = 0 ;
}
if ( next == p_pos -> rd ) {
ESP_EARLY_LOGW ( UART_TAG , "Fail to enqueue pattern position, pattern queue is full." );
ret = ESP_FAIL ;
} else {
p_pos -> data [ p_pos -> wr ] = pos ;
p_pos -> wr = next ;
ret = ESP_OK ;
}
UART_EXIT_CRITICAL ( & uart_spinlock [ uart_num ]);
return ret ;
}
static esp_err_t uart_pattern_dequeue ( uart_port_t uart_num )
{
UART_CHECK (( p_uart_obj [ uart_num ]), "uart driver error" , ESP_FAIL );
if ( p_uart_obj [ uart_num ] -> rx_pattern_pos . data == NULL ) {
return ESP_ERR_INVALID_STATE ;
} else {
esp_err_t ret = ESP_OK ;
UART_ENTER_CRITICAL ( & uart_spinlock [ uart_num ]);
uart_pat_rb_t * p_pos = & p_uart_obj [ uart_num ] -> rx_pattern_pos ;
if ( p_pos -> rd == p_pos -> wr ) {
ret = ESP_FAIL ;
} else {
p_pos -> rd ++ ;
}
if ( p_pos -> rd >= p_pos -> len ) {
p_pos -> rd = 0 ;
}
UART_EXIT_CRITICAL ( & uart_spinlock [ uart_num ]);
return ret ;
}
}
static esp_err_t uart_pattern_queue_update ( uart_port_t uart_num , int diff_len )
{
UART_CHECK (( p_uart_obj [ uart_num ]), "uart driver error" , ESP_FAIL );
UART_ENTER_CRITICAL ( & uart_spinlock [ uart_num ]);
uart_pat_rb_t * p_pos = & p_uart_obj [ uart_num ] -> rx_pattern_pos ;
int rd = p_pos -> rd ;
while ( rd != p_pos -> wr ) {
p_pos -> data [ rd ] -= diff_len ;
int rd_rec = rd ;
rd ++ ;
if ( rd >= p_pos -> len ) {
rd = 0 ;
}
if ( p_pos -> data [ rd_rec ] < 0 ) {
p_pos -> rd = rd ;
}
}
UART_EXIT_CRITICAL ( & uart_spinlock [ uart_num ]);
return ESP_OK ;
}
int uart_pattern_pop_pos ( uart_port_t uart_num )
{
UART_CHECK (( p_uart_obj [ uart_num ]), "uart driver error" , ( - 1 ));
UART_ENTER_CRITICAL ( & uart_spinlock [ uart_num ]);
uart_pat_rb_t * pat_pos = & p_uart_obj [ uart_num ] -> rx_pattern_pos ;
int pos = - 1 ;
if ( pat_pos != NULL && pat_pos -> rd != pat_pos -> wr ) {
pos = pat_pos -> data [ pat_pos -> rd ];
uart_pattern_dequeue ( uart_num );
}
UART_EXIT_CRITICAL ( & uart_spinlock [ uart_num ]);
return pos ;
}
2018-04-03 12:34:16 +08:00
int uart_pattern_get_pos ( uart_port_t uart_num )
{
UART_CHECK (( p_uart_obj [ uart_num ]), "uart driver error" , ( - 1 ));
UART_ENTER_CRITICAL ( & uart_spinlock [ uart_num ]);
uart_pat_rb_t * pat_pos = & p_uart_obj [ uart_num ] -> rx_pattern_pos ;
int pos = - 1 ;
if ( pat_pos != NULL && pat_pos -> rd != pat_pos -> wr ) {
pos = pat_pos -> data [ pat_pos -> rd ];
}
UART_EXIT_CRITICAL ( & uart_spinlock [ uart_num ]);
return pos ;
}
2017-08-25 21:04:13 +08:00
esp_err_t uart_pattern_queue_reset ( uart_port_t uart_num , int queue_length )
{
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ESP_FAIL );
UART_CHECK (( p_uart_obj [ uart_num ]), "uart driver error" , ESP_ERR_INVALID_STATE );
int * pdata = ( int * ) malloc ( queue_length * sizeof ( int ));
if ( pdata == NULL ) {
return ESP_ERR_NO_MEM ;
}
UART_ENTER_CRITICAL ( & uart_spinlock [ uart_num ]);
int * ptmp = p_uart_obj [ uart_num ] -> rx_pattern_pos . data ;
p_uart_obj [ uart_num ] -> rx_pattern_pos . data = pdata ;
p_uart_obj [ uart_num ] -> rx_pattern_pos . len = queue_length ;
p_uart_obj [ uart_num ] -> rx_pattern_pos . rd = 0 ;
p_uart_obj [ uart_num ] -> rx_pattern_pos . wr = 0 ;
UART_EXIT_CRITICAL ( & uart_spinlock [ uart_num ]);
free ( ptmp );
return ESP_OK ;
}
2016-12-19 12:52:10 +08:00
esp_err_t uart_enable_pattern_det_intr ( uart_port_t uart_num , char pattern_chr , uint8_t chr_num , int chr_tout , int post_idle , int pre_idle )
{
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ESP_FAIL );
UART_CHECK ( chr_tout >= 0 && chr_tout <= UART_RX_GAP_TOUT_V , "uart pattern set error \n " , ESP_FAIL );
UART_CHECK ( post_idle >= 0 && post_idle <= UART_POST_IDLE_NUM_V , "uart pattern set error \n " , ESP_FAIL );
UART_CHECK ( pre_idle >= 0 && pre_idle <= UART_PRE_IDLE_NUM_V , "uart pattern set error \n " , ESP_FAIL );
UART [ uart_num ] -> at_cmd_char . data = pattern_chr ;
UART [ uart_num ] -> at_cmd_char . char_num = chr_num ;
UART [ uart_num ] -> at_cmd_gaptout . rx_gap_tout = chr_tout ;
UART [ uart_num ] -> at_cmd_postcnt . post_idle_num = post_idle ;
UART [ uart_num ] -> at_cmd_precnt . pre_idle_num = pre_idle ;
return uart_enable_intr_mask ( uart_num , UART_AT_CMD_CHAR_DET_INT_ENA_M );
}
esp_err_t uart_disable_pattern_det_intr ( uart_port_t uart_num )
{
return uart_disable_intr_mask ( uart_num , UART_AT_CMD_CHAR_DET_INT_ENA_M );
}
2016-12-15 09:45:40 +08:00
esp_err_t uart_enable_rx_intr ( uart_port_t uart_num )
{
2016-12-19 12:52:10 +08:00
return uart_enable_intr_mask ( uart_num , UART_RXFIFO_FULL_INT_ENA | UART_RXFIFO_TOUT_INT_ENA );
2016-12-15 09:45:40 +08:00
}
esp_err_t uart_disable_rx_intr ( uart_port_t uart_num )
{
2016-12-19 12:52:10 +08:00
return uart_disable_intr_mask ( uart_num , UART_RXFIFO_FULL_INT_ENA | UART_RXFIFO_TOUT_INT_ENA );
2016-12-15 09:45:40 +08:00
}
esp_err_t uart_disable_tx_intr ( uart_port_t uart_num )
{
2016-12-19 12:52:10 +08:00
return uart_disable_intr_mask ( uart_num , UART_TXFIFO_EMPTY_INT_ENA );
2016-12-15 09:45:40 +08:00
}
esp_err_t uart_enable_tx_intr ( uart_port_t uart_num , int enable , int thresh )
{
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ESP_FAIL );
UART_CHECK (( thresh < UART_FIFO_LEN ), "empty intr threshold error" , ESP_FAIL );
UART_ENTER_CRITICAL ( & uart_spinlock [ uart_num ]);
UART [ uart_num ] -> int_clr . txfifo_empty = 1 ;
UART [ uart_num ] -> conf1 . txfifo_empty_thrhd = thresh & UART_TXFIFO_EMPTY_THRHD_V ;
UART [ uart_num ] -> int_ena . txfifo_empty = enable & 0x1 ;
UART_EXIT_CRITICAL ( & uart_spinlock [ uart_num ]);
return ESP_OK ;
}
2016-12-19 12:52:10 +08:00
esp_err_t uart_isr_register ( uart_port_t uart_num , void ( * fn )( void * ), void * arg , int intr_alloc_flags , uart_isr_handle_t * handle )
2016-12-15 09:45:40 +08:00
{
2016-11-25 17:33:51 +08:00
int ret ;
2016-12-15 09:45:40 +08:00
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ESP_FAIL );
UART_ENTER_CRITICAL ( & uart_spinlock [ uart_num ]);
switch ( uart_num ) {
case UART_NUM_1 :
2016-12-19 12:52:10 +08:00
ret = esp_intr_alloc ( ETS_UART1_INTR_SOURCE , intr_alloc_flags , fn , arg , handle );
2016-12-15 09:45:40 +08:00
break ;
case UART_NUM_2 :
2016-12-19 12:52:10 +08:00
ret = esp_intr_alloc ( ETS_UART2_INTR_SOURCE , intr_alloc_flags , fn , arg , handle );
2016-12-15 09:45:40 +08:00
break ;
case UART_NUM_0 :
default :
2016-12-19 12:52:10 +08:00
ret = esp_intr_alloc ( ETS_UART0_INTR_SOURCE , intr_alloc_flags , fn , arg , handle );
2016-12-15 09:45:40 +08:00
break ;
}
UART_EXIT_CRITICAL ( & uart_spinlock [ uart_num ]);
return ret ;
}
esp_err_t uart_isr_free ( uart_port_t uart_num )
{
2016-12-08 12:38:22 +08:00
esp_err_t ret ;
2016-12-15 09:45:40 +08:00
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ESP_FAIL );
if ( p_uart_obj [ uart_num ] -> intr_handle == NULL ) return ESP_ERR_INVALID_ARG ;
UART_ENTER_CRITICAL ( & uart_spinlock [ uart_num ]);
ret = esp_intr_free ( p_uart_obj [ uart_num ] -> intr_handle );
p_uart_obj [ uart_num ] -> intr_handle = NULL ;
UART_EXIT_CRITICAL ( & uart_spinlock [ uart_num ]);
return ret ;
}
//internal signal can be output to multiple GPIO pads
//only one GPIO pad can connect with input signal
esp_err_t uart_set_pin ( uart_port_t uart_num , int tx_io_num , int rx_io_num , int rts_io_num , int cts_io_num )
{
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ESP_FAIL );
UART_CHECK (( tx_io_num < 0 || ( GPIO_IS_VALID_OUTPUT_GPIO ( tx_io_num ))), "tx_io_num error" , ESP_FAIL );
UART_CHECK (( rx_io_num < 0 || ( GPIO_IS_VALID_GPIO ( rx_io_num ))), "rx_io_num error" , ESP_FAIL );
UART_CHECK (( rts_io_num < 0 || ( GPIO_IS_VALID_OUTPUT_GPIO ( rts_io_num ))), "rts_io_num error" , ESP_FAIL );
UART_CHECK (( cts_io_num < 0 || ( GPIO_IS_VALID_GPIO ( cts_io_num ))), "cts_io_num error" , ESP_FAIL );
int tx_sig , rx_sig , rts_sig , cts_sig ;
switch ( uart_num ) {
case UART_NUM_0 :
tx_sig = U0TXD_OUT_IDX ;
rx_sig = U0RXD_IN_IDX ;
rts_sig = U0RTS_OUT_IDX ;
cts_sig = U0CTS_IN_IDX ;
break ;
case UART_NUM_1 :
tx_sig = U1TXD_OUT_IDX ;
rx_sig = U1RXD_IN_IDX ;
rts_sig = U1RTS_OUT_IDX ;
cts_sig = U1CTS_IN_IDX ;
break ;
case UART_NUM_2 :
tx_sig = U2TXD_OUT_IDX ;
rx_sig = U2RXD_IN_IDX ;
rts_sig = U2RTS_OUT_IDX ;
cts_sig = U2CTS_IN_IDX ;
break ;
case UART_NUM_MAX :
default :
tx_sig = U0TXD_OUT_IDX ;
rx_sig = U0RXD_IN_IDX ;
rts_sig = U0RTS_OUT_IDX ;
cts_sig = U0CTS_IN_IDX ;
break ;
}
if ( tx_io_num >= 0 ) {
PIN_FUNC_SELECT ( GPIO_PIN_MUX_REG [ tx_io_num ], PIN_FUNC_GPIO );
2017-07-20 14:34:11 +08:00
gpio_set_level ( tx_io_num , 1 );
2016-12-15 09:45:40 +08:00
gpio_matrix_out ( tx_io_num , tx_sig , 0 , 0 );
}
if ( rx_io_num >= 0 ) {
PIN_FUNC_SELECT ( GPIO_PIN_MUX_REG [ rx_io_num ], PIN_FUNC_GPIO );
2016-12-22 12:08:15 +08:00
gpio_set_pull_mode ( rx_io_num , GPIO_PULLUP_ONLY );
2016-12-15 09:45:40 +08:00
gpio_set_direction ( rx_io_num , GPIO_MODE_INPUT );
gpio_matrix_in ( rx_io_num , rx_sig , 0 );
}
if ( rts_io_num >= 0 ) {
PIN_FUNC_SELECT ( GPIO_PIN_MUX_REG [ rts_io_num ], PIN_FUNC_GPIO );
gpio_set_direction ( rts_io_num , GPIO_MODE_OUTPUT );
gpio_matrix_out ( rts_io_num , rts_sig , 0 , 0 );
}
if ( cts_io_num >= 0 ) {
PIN_FUNC_SELECT ( GPIO_PIN_MUX_REG [ cts_io_num ], PIN_FUNC_GPIO );
2016-12-22 12:08:15 +08:00
gpio_set_pull_mode ( cts_io_num , GPIO_PULLUP_ONLY );
2016-12-15 09:45:40 +08:00
gpio_set_direction ( cts_io_num , GPIO_MODE_INPUT );
gpio_matrix_in ( cts_io_num , cts_sig , 0 );
}
return ESP_OK ;
}
esp_err_t uart_set_rts ( uart_port_t uart_num , int level )
{
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ESP_FAIL );
UART_CHECK (( UART [ uart_num ] -> conf1 . rx_flow_en != 1 ), "disable hw flowctrl before using sw control" , ESP_FAIL );
UART_ENTER_CRITICAL ( & uart_spinlock [ uart_num ]);
UART [ uart_num ] -> conf0 . sw_rts = level & 0x1 ;
2017-05-30 17:05:36 +10:00
UART_EXIT_CRITICAL ( & uart_spinlock [ uart_num ]);
2016-12-15 09:45:40 +08:00
return ESP_OK ;
}
esp_err_t uart_set_dtr ( uart_port_t uart_num , int level )
{
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ESP_FAIL );
UART_ENTER_CRITICAL ( & uart_spinlock [ uart_num ]);
UART [ uart_num ] -> conf0 . sw_dtr = level & 0x1 ;
2017-05-30 17:05:36 +10:00
UART_EXIT_CRITICAL ( & uart_spinlock [ uart_num ]);
2016-12-15 09:45:40 +08:00
return ESP_OK ;
}
2017-10-18 12:04:59 +08:00
esp_err_t uart_set_tx_idle_num ( uart_port_t uart_num , uint16_t idle_num )
{
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ESP_FAIL );
UART_CHECK (( idle_num <= UART_TX_IDLE_NUM_V ), "uart idle num error" , ESP_FAIL );
UART_ENTER_CRITICAL ( & uart_spinlock [ uart_num ]);
UART [ uart_num ] -> idle_conf . tx_idle_num = idle_num ;
UART_EXIT_CRITICAL ( & uart_spinlock [ uart_num ]);
return ESP_OK ;
}
2016-12-15 09:45:40 +08:00
esp_err_t uart_param_config ( uart_port_t uart_num , const uart_config_t * uart_config )
{
2017-08-31 11:29:12 +08:00
esp_err_t r ;
2016-12-15 09:45:40 +08:00
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ESP_FAIL );
UART_CHECK (( uart_config ), "param null" , ESP_FAIL );
if ( uart_num == UART_NUM_0 ) {
periph_module_enable ( PERIPH_UART0_MODULE );
} else if ( uart_num == UART_NUM_1 ) {
periph_module_enable ( PERIPH_UART1_MODULE );
} else if ( uart_num == UART_NUM_2 ) {
periph_module_enable ( PERIPH_UART2_MODULE );
}
2017-08-21 22:30:23 +08:00
r = uart_set_hw_flow_ctrl ( uart_num , uart_config -> flow_ctrl , uart_config -> rx_flow_ctrl_thresh );
if ( r != ESP_OK ) return r ;
2017-03-02 13:41:32 +08:00
2017-08-21 22:30:23 +08:00
UART [ uart_num ] -> conf0 . val =
( uart_config -> parity << UART_PARITY_S )
| ( uart_config -> data_bits << UART_BIT_NUM_S )
| (( uart_config -> flow_ctrl & UART_HW_FLOWCTRL_CTS ) ? UART_TX_FLOW_EN : 0x0 )
| ( uart_config -> use_ref_tick ? 0 : UART_TICK_REF_ALWAYS_ON_M );
r = uart_set_baudrate ( uart_num , uart_config -> baud_rate );
if ( r != ESP_OK ) return r ;
2017-10-18 12:04:59 +08:00
r = uart_set_tx_idle_num ( uart_num , UART_TX_IDLE_NUM_DEFAULT );
if ( r != ESP_OK ) return r ;
2017-08-21 22:30:23 +08:00
r = uart_set_stop_bits ( uart_num , uart_config -> stop_bits );
2018-05-18 11:12:19 +08:00
//A hardware reset does not reset the fifo,
//so we need to reset the fifo manually.
uart_reset_rx_fifo ( uart_num );
2017-08-31 11:29:12 +08:00
return r ;
2016-12-15 09:45:40 +08:00
}
esp_err_t uart_intr_config ( uart_port_t uart_num , const uart_intr_config_t * intr_conf )
{
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ESP_FAIL );
UART_CHECK (( intr_conf ), "param null" , ESP_FAIL );
UART_ENTER_CRITICAL ( & uart_spinlock [ uart_num ]);
UART [ uart_num ] -> int_clr . val = UART_INTR_MASK ;
if ( intr_conf -> intr_enable_mask & UART_RXFIFO_TOUT_INT_ENA_M ) {
2018-07-13 21:55:54 +08:00
//Hardware issue workaround: when using ref_tick, the rx timeout threshold needs increase to 10 times.
//T_ref = T_apb * APB_CLK/(REF_TICK << CLKDIV_FRAG_BIT_WIDTH)
if ( UART [ uart_num ] -> conf0 . tick_ref_always_on == 0 ) {
UART [ uart_num ] -> conf1 . rx_tout_thrhd = (( intr_conf -> rx_timeout_thresh * UART_TOUT_REF_FACTOR_DEFAULT ) & UART_RX_TOUT_THRHD_V );
} else {
UART [ uart_num ] -> conf1 . rx_tout_thrhd = (( intr_conf -> rx_timeout_thresh ) & UART_RX_TOUT_THRHD_V );
}
2016-12-15 09:45:40 +08:00
UART [ uart_num ] -> conf1 . rx_tout_en = 1 ;
} else {
UART [ uart_num ] -> conf1 . rx_tout_en = 0 ;
}
if ( intr_conf -> intr_enable_mask & UART_RXFIFO_FULL_INT_ENA_M ) {
UART [ uart_num ] -> conf1 . rxfifo_full_thrhd = intr_conf -> rxfifo_full_thresh ;
}
if ( intr_conf -> intr_enable_mask & UART_TXFIFO_EMPTY_INT_ENA_M ) {
UART [ uart_num ] -> conf1 . txfifo_empty_thrhd = intr_conf -> txfifo_empty_intr_thresh ;
}
UART [ uart_num ] -> int_ena . val = intr_conf -> intr_enable_mask ;
UART_EXIT_CRITICAL ( & uart_spinlock [ uart_num ]);
2016-12-16 22:27:45 +00:00
return ESP_OK ;
2016-12-15 09:45:40 +08:00
}
2017-08-25 21:04:13 +08:00
static int uart_find_pattern_from_last ( uint8_t * buf , int length , uint8_t pat_chr , int pat_num )
{
int cnt = 0 ;
int len = length ;
while ( len >= 0 ) {
if ( buf [ len ] == pat_chr ) {
cnt ++ ;
} else {
cnt = 0 ;
}
if ( cnt >= pat_num ) {
break ;
}
len -- ;
}
return len ;
}
2016-12-15 09:45:40 +08:00
//internal isr handler for default driver code.
2017-02-07 15:05:18 +11:00
static void uart_rx_intr_handler_default ( void * param )
2016-12-15 09:45:40 +08:00
{
uart_obj_t * p_uart = ( uart_obj_t * ) param ;
uint8_t uart_num = p_uart -> uart_num ;
uart_dev_t * uart_reg = UART [ uart_num ];
2017-08-25 21:04:13 +08:00
int rx_fifo_len = uart_reg -> status . rxfifo_cnt ;
2016-12-15 09:45:40 +08:00
uint8_t buf_idx = 0 ;
uint32_t uart_intr_status = UART [ uart_num ] -> int_st . val ;
uart_event_t uart_event ;
portBASE_TYPE HPTaskAwoken = 0 ;
2017-08-25 21:04:13 +08:00
static uint8_t pat_flg = 0 ;
2016-12-15 09:45:40 +08:00
while ( uart_intr_status != 0x0 ) {
buf_idx = 0 ;
uart_event . type = UART_EVENT_MAX ;
if ( uart_intr_status & UART_TXFIFO_EMPTY_INT_ST_M ) {
2017-08-25 21:04:13 +08:00
uart_clear_intr_status ( uart_num , UART_TXFIFO_EMPTY_INT_CLR_M );
uart_disable_intr_mask ( uart_num , UART_TXFIFO_EMPTY_INT_ENA_M );
2016-12-15 09:45:40 +08:00
if ( p_uart -> tx_waiting_brk ) {
continue ;
}
//TX semaphore will only be used when tx_buf_size is zero.
if ( p_uart -> tx_waiting_fifo == true && p_uart -> tx_buf_size == 0 ) {
p_uart -> tx_waiting_fifo = false ;
xSemaphoreGiveFromISR ( p_uart -> tx_fifo_sem , & HPTaskAwoken );
if ( HPTaskAwoken == pdTRUE ) {
2018-04-11 11:56:00 +05:00
portYIELD_FROM_ISR ();
2016-12-15 09:45:40 +08:00
}
2017-08-25 21:04:13 +08:00
} else {
2016-12-15 09:45:40 +08:00
//We don't use TX ring buffer, because the size is zero.
if ( p_uart -> tx_buf_size == 0 ) {
continue ;
}
int tx_fifo_rem = UART_FIFO_LEN - UART [ uart_num ] -> status . txfifo_cnt ;
bool en_tx_flg = false ;
//We need to put a loop here, in case all the buffer items are very short.
//That would cause a watch_dog reset because empty interrupt happens so often.
//Although this is a loop in ISR, this loop will execute at most 128 turns.
while ( tx_fifo_rem ) {
if ( p_uart -> tx_len_tot == 0 || p_uart -> tx_ptr == NULL || p_uart -> tx_len_cur == 0 ) {
size_t size ;
p_uart -> tx_head = ( uart_tx_data_t * ) xRingbufferReceiveFromISR ( p_uart -> tx_ring_buf , & size );
if ( p_uart -> tx_head ) {
//The first item is the data description
//Get the first item to get the data information
if ( p_uart -> tx_len_tot == 0 ) {
p_uart -> tx_ptr = NULL ;
p_uart -> tx_len_tot = p_uart -> tx_head -> tx_data . size ;
if ( p_uart -> tx_head -> type == UART_DATA_BREAK ) {
p_uart -> tx_brk_flg = 1 ;
p_uart -> tx_brk_len = p_uart -> tx_head -> tx_data . brk_len ;
}
//We have saved the data description from the 1st item, return buffer.
vRingbufferReturnItemFromISR ( p_uart -> tx_ring_buf , p_uart -> tx_head , & HPTaskAwoken );
if ( HPTaskAwoken == pdTRUE ) {
2018-04-11 11:56:00 +05:00
portYIELD_FROM_ISR ();
2016-12-15 09:45:40 +08:00
}
} else if ( p_uart -> tx_ptr == NULL ) {
//Update the TX item pointer, we will need this to return item to buffer.
p_uart -> tx_ptr = ( uint8_t * ) p_uart -> tx_head ;
en_tx_flg = true ;
p_uart -> tx_len_cur = size ;
}
}
else {
//Can not get data from ring buffer, return;
break ;
}
}
2017-08-25 21:04:13 +08:00
if ( p_uart -> tx_len_tot > 0 && p_uart -> tx_ptr && p_uart -> tx_len_cur > 0 ) {
2016-12-15 09:45:40 +08:00
//To fill the TX FIFO.
int send_len = p_uart -> tx_len_cur > tx_fifo_rem ? tx_fifo_rem : p_uart -> tx_len_cur ;
2018-04-11 11:56:00 +05:00
// Set RS485 RTS pin before transmission if the half duplex mode is enabled
if ( UART_IS_MODE_SET ( uart_num , UART_MODE_RS485_HALF_DUPLEX )) {
UART_ENTER_CRITICAL_ISR ( & uart_spinlock [ uart_num ]);
uart_reg -> conf0 . sw_rts = 0 ;
uart_reg -> int_ena . tx_done = 1 ;
UART_EXIT_CRITICAL_ISR ( & uart_spinlock [ uart_num ]);
}
for ( buf_idx = 0 ; buf_idx < send_len ; buf_idx ++ ) {
WRITE_PERI_REG ( UART_FIFO_AHB_REG ( uart_num ),
* ( p_uart -> tx_ptr ++ ) & 0xff );
2016-12-15 09:45:40 +08:00
}
p_uart -> tx_len_tot -= send_len ;
p_uart -> tx_len_cur -= send_len ;
tx_fifo_rem -= send_len ;
2017-08-25 21:04:13 +08:00
if ( p_uart -> tx_len_cur == 0 ) {
2016-12-15 09:45:40 +08:00
//Return item to ring buffer.
vRingbufferReturnItemFromISR ( p_uart -> tx_ring_buf , p_uart -> tx_head , & HPTaskAwoken );
if ( HPTaskAwoken == pdTRUE ) {
2018-04-11 11:56:00 +05:00
portYIELD_FROM_ISR ();
2016-12-15 09:45:40 +08:00
}
p_uart -> tx_head = NULL ;
p_uart -> tx_ptr = NULL ;
//Sending item done, now we need to send break if there is a record.
//Set TX break signal after FIFO is empty
2018-07-19 21:41:35 +08:00
if ( p_uart -> tx_len_tot == 0 && p_uart -> tx_brk_flg == 1 ) {
2016-12-15 09:45:40 +08:00
UART_ENTER_CRITICAL_ISR ( & uart_spinlock [ uart_num ]);
uart_reg -> int_ena . tx_brk_done = 0 ;
uart_reg -> idle_conf . tx_brk_num = p_uart -> tx_brk_len ;
uart_reg -> conf0 . txd_brk = 1 ;
uart_reg -> int_clr . tx_brk_done = 1 ;
uart_reg -> int_ena . tx_brk_done = 1 ;
UART_EXIT_CRITICAL_ISR ( & uart_spinlock [ uart_num ]);
p_uart -> tx_waiting_brk = 1 ;
2018-07-19 21:41:35 +08:00
//do not enable TX empty interrupt
en_tx_flg = false ;
2016-12-15 09:45:40 +08:00
} else {
//enable TX empty interrupt
en_tx_flg = true ;
}
} else {
//enable TX empty interrupt
en_tx_flg = true ;
}
}
}
2017-08-25 21:04:13 +08:00
if ( en_tx_flg ) {
uart_clear_intr_status ( uart_num , UART_TXFIFO_EMPTY_INT_CLR_M );
uart_enable_intr_mask ( uart_num , UART_TXFIFO_EMPTY_INT_ENA_M );
2016-12-15 09:45:40 +08:00
}
}
}
2017-08-25 21:04:13 +08:00
else if (( uart_intr_status & UART_RXFIFO_TOUT_INT_ST_M )
|| ( uart_intr_status & UART_RXFIFO_FULL_INT_ST_M )
|| ( uart_intr_status & UART_AT_CMD_CHAR_DET_INT_ST_M )
) {
rx_fifo_len = uart_reg -> status . rxfifo_cnt ;
if ( pat_flg == 1 ) {
uart_intr_status |= UART_AT_CMD_CHAR_DET_INT_ST_M ;
pat_flg = 0 ;
}
if ( p_uart -> rx_buffer_full_flg == false ) {
2016-12-15 09:45:40 +08:00
//We have to read out all data in RX FIFO to clear the interrupt signal
2017-08-25 21:04:13 +08:00
while ( buf_idx < rx_fifo_len ) {
2016-12-15 09:45:40 +08:00
p_uart -> rx_data_buf [ buf_idx ++ ] = uart_reg -> fifo . rw_byte ;
}
2017-08-25 21:04:13 +08:00
uint8_t pat_chr = uart_reg -> at_cmd_char . data ;
int pat_num = uart_reg -> at_cmd_char . char_num ;
int pat_idx = - 1 ;
//Get the buffer from the FIFO
if ( uart_intr_status & UART_AT_CMD_CHAR_DET_INT_ST_M ) {
uart_clear_intr_status ( uart_num , UART_AT_CMD_CHAR_DET_INT_CLR_M );
uart_event . type = UART_PATTERN_DET ;
uart_event . size = rx_fifo_len ;
pat_idx = uart_find_pattern_from_last ( p_uart -> rx_data_buf , rx_fifo_len - 1 , pat_chr , pat_num );
} else {
//After Copying the Data From FIFO ,Clear intr_status
uart_clear_intr_status ( uart_num , UART_RXFIFO_TOUT_INT_CLR_M | UART_RXFIFO_FULL_INT_CLR_M );
uart_event . type = UART_DATA ;
uart_event . size = rx_fifo_len ;
2018-05-03 10:41:10 +02:00
UART_ENTER_CRITICAL_ISR ( & uart_selectlock );
if ( p_uart -> uart_select_notif_callback ) {
p_uart -> uart_select_notif_callback ( uart_num , UART_SELECT_READ_NOTIF , & HPTaskAwoken );
}
UART_EXIT_CRITICAL_ISR ( & uart_selectlock );
2017-08-25 21:04:13 +08:00
}
p_uart -> rx_stash_len = rx_fifo_len ;
2016-12-15 09:45:40 +08:00
//If we fail to push data to ring buffer, we will have to stash the data, and send next time.
//Mainly for applications that uses flow control or small ring buffer.
if ( pdFALSE == xRingbufferSendFromISR ( p_uart -> rx_ring_buf , p_uart -> rx_data_buf , p_uart -> rx_stash_len , & HPTaskAwoken )) {
2017-08-25 21:04:13 +08:00
uart_disable_intr_mask ( uart_num , UART_RXFIFO_TOUT_INT_ENA_M | UART_RXFIFO_FULL_INT_ENA_M );
if ( uart_event . type == UART_PATTERN_DET ) {
if ( rx_fifo_len < pat_num ) {
//some of the characters are read out in last interrupt
uart_pattern_enqueue ( uart_num , p_uart -> rx_buffered_len - ( pat_num - rx_fifo_len ));
} else {
uart_pattern_enqueue ( uart_num ,
pat_idx <= - 1 ?
//can not find the pattern in buffer,
p_uart -> rx_buffered_len + p_uart -> rx_stash_len :
// find the pattern in buffer
p_uart -> rx_buffered_len + pat_idx );
}
if (( p_uart -> xQueueUart != NULL ) && ( pdFALSE == xQueueSendFromISR ( p_uart -> xQueueUart , ( void * ) & uart_event , & HPTaskAwoken ))) {
2018-03-13 15:57:33 +08:00
ESP_EARLY_LOGV ( UART_TAG , "UART event queue full" );
2017-08-25 21:04:13 +08:00
}
}
2016-12-15 09:45:40 +08:00
uart_event . type = UART_BUFFER_FULL ;
2017-08-25 21:04:13 +08:00
p_uart -> rx_buffer_full_flg = true ;
2016-12-15 09:45:40 +08:00
} else {
2016-12-19 12:52:10 +08:00
UART_ENTER_CRITICAL_ISR ( & uart_spinlock [ uart_num ]);
2017-08-25 21:04:13 +08:00
if ( uart_intr_status & UART_AT_CMD_CHAR_DET_INT_ST_M ) {
if ( rx_fifo_len < pat_num ) {
//some of the characters are read out in last interrupt
uart_pattern_enqueue ( uart_num , p_uart -> rx_buffered_len - ( pat_num - rx_fifo_len ));
} else if ( pat_idx >= 0 ) {
// find pattern in statsh buffer.
uart_pattern_enqueue ( uart_num , p_uart -> rx_buffered_len + pat_idx );
}
}
2016-12-19 12:52:10 +08:00
p_uart -> rx_buffered_len += p_uart -> rx_stash_len ;
UART_EXIT_CRITICAL_ISR ( & uart_spinlock [ uart_num ]);
2016-12-15 09:45:40 +08:00
}
if ( HPTaskAwoken == pdTRUE ) {
2018-04-11 11:56:00 +05:00
portYIELD_FROM_ISR ();
2016-12-15 09:45:40 +08:00
}
} else {
2017-08-25 21:04:13 +08:00
uart_disable_intr_mask ( uart_num , UART_RXFIFO_FULL_INT_ENA_M | UART_RXFIFO_TOUT_INT_ENA_M );
uart_clear_intr_status ( uart_num , UART_RXFIFO_FULL_INT_CLR_M | UART_RXFIFO_TOUT_INT_CLR_M );
if ( uart_intr_status & UART_AT_CMD_CHAR_DET_INT_ST_M ) {
uart_reg -> int_clr . at_cmd_char_det = 1 ;
uart_event . type = UART_PATTERN_DET ;
uart_event . size = rx_fifo_len ;
pat_flg = 1 ;
}
}
} else if ( uart_intr_status & UART_RXFIFO_OVF_INT_ST_M ) {
// When fifo overflows, we reset the fifo.
2016-12-15 09:45:40 +08:00
UART_ENTER_CRITICAL_ISR ( & uart_spinlock [ uart_num ]);
2018-01-03 17:18:32 +08:00
uart_reset_rx_fifo ( uart_num );
2016-12-15 09:45:40 +08:00
uart_reg -> int_clr . rxfifo_ovf = 1 ;
UART_EXIT_CRITICAL_ISR ( & uart_spinlock [ uart_num ]);
uart_event . type = UART_FIFO_OVF ;
2018-05-03 10:41:10 +02:00
UART_ENTER_CRITICAL_ISR ( & uart_selectlock );
if ( p_uart -> uart_select_notif_callback ) {
p_uart -> uart_select_notif_callback ( uart_num , UART_SELECT_ERROR_NOTIF , & HPTaskAwoken );
}
UART_EXIT_CRITICAL_ISR ( & uart_selectlock );
2016-12-15 09:45:40 +08:00
} else if ( uart_intr_status & UART_BRK_DET_INT_ST_M ) {
uart_reg -> int_clr . brk_det = 1 ;
uart_event . type = UART_BREAK ;
2016-12-19 12:52:10 +08:00
} else if ( uart_intr_status & UART_FRM_ERR_INT_ST_M ) {
2016-12-22 12:08:15 +08:00
uart_reg -> int_clr . frm_err = 1 ;
2016-12-15 09:45:40 +08:00
uart_event . type = UART_FRAME_ERR ;
2018-05-03 10:41:10 +02:00
UART_ENTER_CRITICAL_ISR ( & uart_selectlock );
if ( p_uart -> uart_select_notif_callback ) {
p_uart -> uart_select_notif_callback ( uart_num , UART_SELECT_ERROR_NOTIF , & HPTaskAwoken );
}
UART_EXIT_CRITICAL_ISR ( & uart_selectlock );
2016-12-19 12:52:10 +08:00
} else if ( uart_intr_status & UART_PARITY_ERR_INT_ST_M ) {
2016-12-22 12:08:15 +08:00
uart_reg -> int_clr . parity_err = 1 ;
2016-12-15 09:45:40 +08:00
uart_event . type = UART_PARITY_ERR ;
2018-05-03 10:41:10 +02:00
UART_ENTER_CRITICAL_ISR ( & uart_selectlock );
if ( p_uart -> uart_select_notif_callback ) {
p_uart -> uart_select_notif_callback ( uart_num , UART_SELECT_ERROR_NOTIF , & HPTaskAwoken );
}
UART_EXIT_CRITICAL_ISR ( & uart_selectlock );
2016-12-15 09:45:40 +08:00
} else if ( uart_intr_status & UART_TX_BRK_DONE_INT_ST_M ) {
UART_ENTER_CRITICAL_ISR ( & uart_spinlock [ uart_num ]);
uart_reg -> conf0 . txd_brk = 0 ;
uart_reg -> int_ena . tx_brk_done = 0 ;
uart_reg -> int_clr . tx_brk_done = 1 ;
if ( p_uart -> tx_brk_flg == 1 ) {
uart_reg -> int_ena . txfifo_empty = 1 ;
}
UART_EXIT_CRITICAL_ISR ( & uart_spinlock [ uart_num ]);
if ( p_uart -> tx_brk_flg == 1 ) {
p_uart -> tx_brk_flg = 0 ;
p_uart -> tx_waiting_brk = 0 ;
} else {
xSemaphoreGiveFromISR ( p_uart -> tx_brk_sem , & HPTaskAwoken );
if ( HPTaskAwoken == pdTRUE ) {
2018-04-11 11:56:00 +05:00
portYIELD_FROM_ISR ();
2016-12-15 09:45:40 +08:00
}
}
} else if ( uart_intr_status & UART_TX_BRK_IDLE_DONE_INT_ST_M ) {
2017-08-25 21:04:13 +08:00
uart_disable_intr_mask ( uart_num , UART_TX_BRK_IDLE_DONE_INT_ENA_M );
uart_clear_intr_status ( uart_num , UART_TX_BRK_IDLE_DONE_INT_CLR_M );
2016-12-19 12:52:10 +08:00
} else if ( uart_intr_status & UART_AT_CMD_CHAR_DET_INT_ST_M ) {
uart_reg -> int_clr . at_cmd_char_det = 1 ;
uart_event . type = UART_PATTERN_DET ;
2018-04-11 11:56:00 +05:00
} else if (( uart_intr_status & UART_RS485_CLASH_INT_ST_M )
|| ( uart_intr_status & UART_RS485_FRM_ERR_INT_ENA )
|| ( uart_intr_status & UART_RS485_PARITY_ERR_INT_ENA )) {
// RS485 collision or frame error interrupt triggered
uart_clear_intr_status ( uart_num , UART_RS485_CLASH_INT_CLR_M );
UART_ENTER_CRITICAL_ISR ( & uart_spinlock [ uart_num ]);
uart_reset_rx_fifo ( uart_num );
// Set collision detection flag
p_uart_obj [ uart_num ] -> coll_det_flg = true ;
UART_EXIT_CRITICAL_ISR ( & uart_spinlock [ uart_num ]);
uart_event . type = UART_EVENT_MAX ;
2016-12-15 09:45:40 +08:00
} else if ( uart_intr_status & UART_TX_DONE_INT_ST_M ) {
2017-08-25 21:04:13 +08:00
uart_disable_intr_mask ( uart_num , UART_TX_DONE_INT_ENA_M );
uart_clear_intr_status ( uart_num , UART_TX_DONE_INT_CLR_M );
2018-04-11 11:56:00 +05:00
// If RS485 half duplex mode is enable then reset FIFO and
// reset RTS pin to start receiver driver
if ( UART_IS_MODE_SET ( uart_num , UART_MODE_RS485_HALF_DUPLEX )) {
UART_ENTER_CRITICAL_ISR ( & uart_spinlock [ uart_num ]);
uart_reset_rx_fifo ( uart_num ); // Allows to avoid hardware issue with the RXFIFO reset
uart_reg -> conf0 . sw_rts = 1 ;
UART_EXIT_CRITICAL_ISR ( & uart_spinlock [ uart_num ]);
}
2016-12-15 09:45:40 +08:00
xSemaphoreGiveFromISR ( p_uart_obj [ uart_num ] -> tx_done_sem , & HPTaskAwoken );
2018-04-11 11:56:00 +05:00
if ( HPTaskAwoken == pdTRUE ) {
portYIELD_FROM_ISR ();
2016-12-15 09:45:40 +08:00
}
2016-12-19 12:52:10 +08:00
} else {
2016-12-15 09:45:40 +08:00
uart_reg -> int_clr . val = uart_intr_status ; /*simply clear all other intr status*/
uart_event . type = UART_EVENT_MAX ;
}
if ( uart_event . type != UART_EVENT_MAX && p_uart -> xQueueUart ) {
2017-08-25 21:04:13 +08:00
if ( pdFALSE == xQueueSendFromISR ( p_uart -> xQueueUart , ( void * ) & uart_event , & HPTaskAwoken )) {
2018-03-13 15:57:33 +08:00
ESP_EARLY_LOGV ( UART_TAG , "UART event queue full" );
2017-08-25 21:04:13 +08:00
}
2016-12-15 09:45:40 +08:00
if ( HPTaskAwoken == pdTRUE ) {
2018-04-11 11:56:00 +05:00
portYIELD_FROM_ISR ();
2016-12-15 09:45:40 +08:00
}
}
uart_intr_status = uart_reg -> int_st . val ;
}
}
/**************************************************************/
esp_err_t uart_wait_tx_done ( uart_port_t uart_num , TickType_t ticks_to_wait )
{
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ESP_FAIL );
UART_CHECK (( p_uart_obj [ uart_num ]), "uart driver error" , ESP_FAIL );
BaseType_t res ;
portTickType ticks_end = xTaskGetTickCount () + ticks_to_wait ;
//Take tx_mux
res = xSemaphoreTake ( p_uart_obj [ uart_num ] -> tx_mux , ( portTickType ) ticks_to_wait );
if ( res == pdFALSE ) {
return ESP_ERR_TIMEOUT ;
}
ticks_to_wait = ticks_end - xTaskGetTickCount ();
xSemaphoreTake ( p_uart_obj [ uart_num ] -> tx_done_sem , 0 );
ticks_to_wait = ticks_end - xTaskGetTickCount ();
if ( UART [ uart_num ] -> status . txfifo_cnt == 0 ) {
xSemaphoreGive ( p_uart_obj [ uart_num ] -> tx_mux );
return ESP_OK ;
}
uart_enable_intr_mask ( uart_num , UART_TX_DONE_INT_ENA_M );
//take 2nd tx_done_sem, wait given from ISR
res = xSemaphoreTake ( p_uart_obj [ uart_num ] -> tx_done_sem , ( portTickType ) ticks_to_wait );
if ( res == pdFALSE ) {
uart_disable_intr_mask ( uart_num , UART_TX_DONE_INT_ENA_M );
xSemaphoreGive ( p_uart_obj [ uart_num ] -> tx_mux );
return ESP_ERR_TIMEOUT ;
}
xSemaphoreGive ( p_uart_obj [ uart_num ] -> tx_mux );
return ESP_OK ;
}
static esp_err_t uart_set_break ( uart_port_t uart_num , int break_num )
{
UART_ENTER_CRITICAL ( & uart_spinlock [ uart_num ]);
UART [ uart_num ] -> idle_conf . tx_brk_num = break_num ;
UART [ uart_num ] -> conf0 . txd_brk = 1 ;
UART [ uart_num ] -> int_clr . tx_brk_done = 1 ;
UART [ uart_num ] -> int_ena . tx_brk_done = 1 ;
UART_EXIT_CRITICAL ( & uart_spinlock [ uart_num ]);
return ESP_OK ;
}
//Fill UART tx_fifo and return a number,
//This function by itself is not thread-safe, always call from within a muxed section.
static int uart_fill_fifo ( uart_port_t uart_num , const char * buffer , uint32_t len )
{
uint8_t i = 0 ;
uint8_t tx_fifo_cnt = UART [ uart_num ] -> status . txfifo_cnt ;
uint8_t tx_remain_fifo_cnt = ( UART_FIFO_LEN - tx_fifo_cnt );
uint8_t copy_cnt = ( len >= tx_remain_fifo_cnt ? tx_remain_fifo_cnt : len );
2018-04-11 11:56:00 +05:00
// Set the RTS pin if RS485 mode is enabled
if ( UART_IS_MODE_SET ( uart_num , UART_MODE_RS485_HALF_DUPLEX )) {
UART [ uart_num ] -> conf0 . sw_rts = 0 ;
UART [ uart_num ] -> int_ena . tx_done = 1 ;
}
for ( i = 0 ; i < copy_cnt ; i ++ ) {
2016-12-15 09:45:40 +08:00
WRITE_PERI_REG ( UART_FIFO_AHB_REG ( uart_num ), buffer [ i ]);
}
return copy_cnt ;
}
int uart_tx_chars ( uart_port_t uart_num , const char * buffer , uint32_t len )
{
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ( - 1 ));
UART_CHECK (( p_uart_obj [ uart_num ]), "uart driver error" , ( - 1 ));
UART_CHECK ( buffer , "buffer null" , ( - 1 ));
if ( len == 0 ) {
return 0 ;
}
xSemaphoreTake ( p_uart_obj [ uart_num ] -> tx_mux , ( portTickType ) portMAX_DELAY );
int tx_len = uart_fill_fifo ( uart_num , ( const char * ) buffer , len );
xSemaphoreGive ( p_uart_obj [ uart_num ] -> tx_mux );
return tx_len ;
}
static int uart_tx_all ( uart_port_t uart_num , const char * src , size_t size , bool brk_en , int brk_len )
{
if ( size == 0 ) {
return 0 ;
}
size_t original_size = size ;
//lock for uart_tx
xSemaphoreTake ( p_uart_obj [ uart_num ] -> tx_mux , ( portTickType ) portMAX_DELAY );
2018-04-11 11:56:00 +05:00
p_uart_obj [ uart_num ] -> coll_det_flg = false ;
2016-12-15 09:45:40 +08:00
if ( p_uart_obj [ uart_num ] -> tx_buf_size > 0 ) {
int max_size = xRingbufferGetMaxItemSize ( p_uart_obj [ uart_num ] -> tx_ring_buf );
int offset = 0 ;
uart_tx_data_t evt ;
evt . tx_data . size = size ;
evt . tx_data . brk_len = brk_len ;
if ( brk_en ) {
evt . type = UART_DATA_BREAK ;
} else {
evt . type = UART_DATA ;
}
xRingbufferSend ( p_uart_obj [ uart_num ] -> tx_ring_buf , ( void * ) & evt , sizeof ( uart_tx_data_t ), portMAX_DELAY );
while ( size > 0 ) {
int send_size = size > max_size / 2 ? max_size / 2 : size ;
xRingbufferSend ( p_uart_obj [ uart_num ] -> tx_ring_buf , ( void * ) ( src + offset ), send_size , portMAX_DELAY );
size -= send_size ;
offset += send_size ;
2017-04-12 16:57:37 +08:00
uart_enable_tx_intr ( uart_num , 1 , UART_EMPTY_THRESH_DEFAULT );
2016-12-15 09:45:40 +08:00
}
} else {
while ( size ) {
//semaphore for tx_fifo available
if ( pdTRUE == xSemaphoreTake ( p_uart_obj [ uart_num ] -> tx_fifo_sem , ( portTickType ) portMAX_DELAY )) {
size_t sent = uart_fill_fifo ( uart_num , ( char * ) src , size );
if ( sent < size ) {
p_uart_obj [ uart_num ] -> tx_waiting_fifo = true ;
uart_enable_tx_intr ( uart_num , 1 , UART_EMPTY_THRESH_DEFAULT );
}
size -= sent ;
src += sent ;
}
}
if ( brk_en ) {
uart_set_break ( uart_num , brk_len );
xSemaphoreTake ( p_uart_obj [ uart_num ] -> tx_brk_sem , ( portTickType ) portMAX_DELAY );
}
xSemaphoreGive ( p_uart_obj [ uart_num ] -> tx_fifo_sem );
}
xSemaphoreGive ( p_uart_obj [ uart_num ] -> tx_mux );
return original_size ;
}
int uart_write_bytes ( uart_port_t uart_num , const char * src , size_t size )
{
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ( - 1 ));
UART_CHECK (( p_uart_obj [ uart_num ] != NULL ), "uart driver error" , ( - 1 ));
UART_CHECK ( src , "buffer null" , ( - 1 ));
return uart_tx_all ( uart_num , src , size , 0 , 0 );
}
int uart_write_bytes_with_break ( uart_port_t uart_num , const char * src , size_t size , int brk_len )
{
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ( - 1 ));
UART_CHECK (( p_uart_obj [ uart_num ]), "uart driver error" , ( - 1 ));
UART_CHECK (( size > 0 ), "uart size error" , ( - 1 ));
UART_CHECK (( src ), "uart data null" , ( - 1 ));
UART_CHECK (( brk_len > 0 && brk_len < 256 ), "break_num error" , ( - 1 ));
return uart_tx_all ( uart_num , src , size , 1 , brk_len );
}
int uart_read_bytes ( uart_port_t uart_num , uint8_t * buf , uint32_t length , TickType_t ticks_to_wait )
{
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ( - 1 ));
2017-09-27 22:03:22 +02:00
UART_CHECK (( buf ), "uart data null" , ( - 1 ));
2016-12-15 09:45:40 +08:00
UART_CHECK (( p_uart_obj [ uart_num ]), "uart driver error" , ( - 1 ));
uint8_t * data = NULL ;
size_t size ;
size_t copy_len = 0 ;
int len_tmp ;
if ( xSemaphoreTake ( p_uart_obj [ uart_num ] -> rx_mux ,( portTickType ) ticks_to_wait ) != pdTRUE ) {
return - 1 ;
}
while ( length ) {
if ( p_uart_obj [ uart_num ] -> rx_cur_remain == 0 ) {
data = ( uint8_t * ) xRingbufferReceive ( p_uart_obj [ uart_num ] -> rx_ring_buf , & size , ( portTickType ) ticks_to_wait );
if ( data ) {
p_uart_obj [ uart_num ] -> rx_head_ptr = data ;
p_uart_obj [ uart_num ] -> rx_ptr = data ;
p_uart_obj [ uart_num ] -> rx_cur_remain = size ;
} else {
xSemaphoreGive ( p_uart_obj [ uart_num ] -> rx_mux );
return copy_len ;
}
}
if ( p_uart_obj [ uart_num ] -> rx_cur_remain > length ) {
len_tmp = length ;
} else {
len_tmp = p_uart_obj [ uart_num ] -> rx_cur_remain ;
}
memcpy ( buf + copy_len , p_uart_obj [ uart_num ] -> rx_ptr , len_tmp );
2017-08-25 21:04:13 +08:00
UART_ENTER_CRITICAL ( & uart_spinlock [ uart_num ]);
p_uart_obj [ uart_num ] -> rx_buffered_len -= len_tmp ;
uart_pattern_queue_update ( uart_num , len_tmp );
2016-12-15 09:45:40 +08:00
p_uart_obj [ uart_num ] -> rx_ptr += len_tmp ;
2017-08-25 21:04:13 +08:00
UART_EXIT_CRITICAL ( & uart_spinlock [ uart_num ]);
2016-12-15 09:45:40 +08:00
p_uart_obj [ uart_num ] -> rx_cur_remain -= len_tmp ;
copy_len += len_tmp ;
length -= len_tmp ;
if ( p_uart_obj [ uart_num ] -> rx_cur_remain == 0 ) {
vRingbufferReturnItem ( p_uart_obj [ uart_num ] -> rx_ring_buf , p_uart_obj [ uart_num ] -> rx_head_ptr );
p_uart_obj [ uart_num ] -> rx_head_ptr = NULL ;
p_uart_obj [ uart_num ] -> rx_ptr = NULL ;
if ( p_uart_obj [ uart_num ] -> rx_buffer_full_flg ) {
BaseType_t res = xRingbufferSend ( p_uart_obj [ uart_num ] -> rx_ring_buf , p_uart_obj [ uart_num ] -> rx_data_buf , p_uart_obj [ uart_num ] -> rx_stash_len , 1 );
if ( res == pdTRUE ) {
2016-12-19 12:52:10 +08:00
UART_ENTER_CRITICAL ( & uart_spinlock [ uart_num ]);
p_uart_obj [ uart_num ] -> rx_buffered_len += p_uart_obj [ uart_num ] -> rx_stash_len ;
2016-12-15 09:45:40 +08:00
p_uart_obj [ uart_num ] -> rx_buffer_full_flg = false ;
2018-05-18 15:47:02 +08:00
UART_EXIT_CRITICAL ( & uart_spinlock [ uart_num ]);
2016-12-15 09:45:40 +08:00
uart_enable_rx_intr ( p_uart_obj [ uart_num ] -> uart_num );
}
}
}
}
2017-08-25 21:04:13 +08:00
2016-12-15 09:45:40 +08:00
xSemaphoreGive ( p_uart_obj [ uart_num ] -> rx_mux );
return copy_len ;
}
2016-12-19 12:52:10 +08:00
esp_err_t uart_get_buffered_data_len ( uart_port_t uart_num , size_t * size )
{
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ESP_FAIL );
UART_CHECK (( p_uart_obj [ uart_num ]), "uart driver error" , ESP_FAIL );
* size = p_uart_obj [ uart_num ] -> rx_buffered_len ;
return ESP_OK ;
}
2017-08-25 21:04:13 +08:00
esp_err_t uart_flush ( uart_port_t uart_num ) __attribute__ (( alias ( "uart_flush_input" )));
esp_err_t uart_flush_input ( uart_port_t uart_num )
2016-12-15 09:45:40 +08:00
{
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ESP_FAIL );
UART_CHECK (( p_uart_obj [ uart_num ]), "uart driver error" , ESP_FAIL );
uart_obj_t * p_uart = p_uart_obj [ uart_num ];
uint8_t * data ;
size_t size ;
//rx sem protect the ring buffer read related functions
xSemaphoreTake ( p_uart -> rx_mux , ( portTickType ) portMAX_DELAY );
2016-12-19 12:52:10 +08:00
uart_disable_rx_intr ( p_uart_obj [ uart_num ] -> uart_num );
2016-12-15 09:45:40 +08:00
while ( true ) {
if ( p_uart -> rx_head_ptr ) {
vRingbufferReturnItem ( p_uart -> rx_ring_buf , p_uart -> rx_head_ptr );
2016-12-19 12:52:10 +08:00
UART_ENTER_CRITICAL ( & uart_spinlock [ uart_num ]);
p_uart_obj [ uart_num ] -> rx_buffered_len -= p_uart -> rx_cur_remain ;
2017-08-25 21:04:13 +08:00
uart_pattern_queue_update ( uart_num , p_uart -> rx_cur_remain );
2016-12-19 12:52:10 +08:00
UART_EXIT_CRITICAL ( & uart_spinlock [ uart_num ]);
2016-12-15 09:45:40 +08:00
p_uart -> rx_ptr = NULL ;
p_uart -> rx_cur_remain = 0 ;
p_uart -> rx_head_ptr = NULL ;
}
data = ( uint8_t * ) xRingbufferReceive ( p_uart -> rx_ring_buf , & size , ( portTickType ) 0 );
if ( data == NULL ) {
2018-05-18 15:47:02 +08:00
if ( p_uart_obj [ uart_num ] -> rx_buffered_len != 0 ) {
ESP_LOGE ( UART_TAG , "rx_buffered_len error" );
p_uart_obj [ uart_num ] -> rx_buffered_len = 0 ;
}
//We also need to clear the `rx_buffer_full_flg` here.
UART_ENTER_CRITICAL ( & uart_spinlock [ uart_num ]);
p_uart_obj [ uart_num ] -> rx_buffer_full_flg = false ;
UART_EXIT_CRITICAL ( & uart_spinlock [ uart_num ]);
2016-12-15 09:45:40 +08:00
break ;
}
2016-12-19 12:52:10 +08:00
UART_ENTER_CRITICAL ( & uart_spinlock [ uart_num ]);
p_uart_obj [ uart_num ] -> rx_buffered_len -= size ;
2017-08-25 21:04:13 +08:00
uart_pattern_queue_update ( uart_num , size );
2016-12-19 12:52:10 +08:00
UART_EXIT_CRITICAL ( & uart_spinlock [ uart_num ]);
2016-12-15 09:45:40 +08:00
vRingbufferReturnItem ( p_uart -> rx_ring_buf , data );
2016-12-19 12:52:10 +08:00
if ( p_uart_obj [ uart_num ] -> rx_buffer_full_flg ) {
BaseType_t res = xRingbufferSend ( p_uart_obj [ uart_num ] -> rx_ring_buf , p_uart_obj [ uart_num ] -> rx_data_buf , p_uart_obj [ uart_num ] -> rx_stash_len , 1 );
if ( res == pdTRUE ) {
UART_ENTER_CRITICAL ( & uart_spinlock [ uart_num ]);
p_uart_obj [ uart_num ] -> rx_buffered_len += p_uart_obj [ uart_num ] -> rx_stash_len ;
p_uart_obj [ uart_num ] -> rx_buffer_full_flg = false ;
2018-05-18 15:47:02 +08:00
UART_EXIT_CRITICAL ( & uart_spinlock [ uart_num ]);
2016-12-19 12:52:10 +08:00
}
}
2016-12-15 09:45:40 +08:00
}
p_uart -> rx_ptr = NULL ;
p_uart -> rx_cur_remain = 0 ;
p_uart -> rx_head_ptr = NULL ;
2017-11-07 18:19:23 +08:00
uart_reset_rx_fifo ( uart_num );
2016-12-19 12:52:10 +08:00
uart_enable_rx_intr ( p_uart_obj [ uart_num ] -> uart_num );
xSemaphoreGive ( p_uart -> rx_mux );
2016-12-15 09:45:40 +08:00
return ESP_OK ;
}
2016-12-22 13:43:42 +11:00
esp_err_t uart_driver_install ( uart_port_t uart_num , int rx_buffer_size , int tx_buffer_size , int queue_size , QueueHandle_t * uart_queue , int intr_alloc_flags )
2016-12-15 09:45:40 +08:00
{
2017-08-31 11:29:12 +08:00
esp_err_t r ;
2016-12-15 09:45:40 +08:00
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ESP_FAIL );
2016-12-19 12:52:10 +08:00
UART_CHECK (( rx_buffer_size > UART_FIFO_LEN ), "uart rx buffer length error(>128)" , ESP_FAIL );
2017-06-27 16:41:59 +08:00
UART_CHECK (( tx_buffer_size > UART_FIFO_LEN ) || ( tx_buffer_size == 0 ), "uart tx buffer length error(>128 or 0)" , ESP_FAIL );
2017-08-31 11:29:12 +08:00
UART_CHECK (( intr_alloc_flags & ESP_INTR_FLAG_IRAM ) == 0 , "ESP_INTR_FLAG_IRAM set in intr_alloc_flags" , ESP_FAIL ); /* uart_rx_intr_handler_default is not in IRAM */
2016-12-15 09:45:40 +08:00
if ( p_uart_obj [ uart_num ] == NULL ) {
2017-08-25 21:04:13 +08:00
p_uart_obj [ uart_num ] = ( uart_obj_t * ) calloc ( 1 , sizeof ( uart_obj_t ));
2016-12-15 09:45:40 +08:00
if ( p_uart_obj [ uart_num ] == NULL ) {
ESP_LOGE ( UART_TAG , "UART driver malloc error" );
return ESP_FAIL ;
}
p_uart_obj [ uart_num ] -> uart_num = uart_num ;
2018-04-11 11:56:00 +05:00
p_uart_obj [ uart_num ] -> uart_mode = UART_MODE_UART ;
p_uart_obj [ uart_num ] -> coll_det_flg = false ;
2016-12-15 09:45:40 +08:00
p_uart_obj [ uart_num ] -> tx_fifo_sem = xSemaphoreCreateBinary ();
xSemaphoreGive ( p_uart_obj [ uart_num ] -> tx_fifo_sem );
p_uart_obj [ uart_num ] -> tx_done_sem = xSemaphoreCreateBinary ();
p_uart_obj [ uart_num ] -> tx_brk_sem = xSemaphoreCreateBinary ();
p_uart_obj [ uart_num ] -> tx_mux = xSemaphoreCreateMutex ();
p_uart_obj [ uart_num ] -> rx_mux = xSemaphoreCreateMutex ();
p_uart_obj [ uart_num ] -> queue_size = queue_size ;
p_uart_obj [ uart_num ] -> tx_ptr = NULL ;
p_uart_obj [ uart_num ] -> tx_head = NULL ;
p_uart_obj [ uart_num ] -> tx_len_tot = 0 ;
p_uart_obj [ uart_num ] -> tx_brk_flg = 0 ;
p_uart_obj [ uart_num ] -> tx_brk_len = 0 ;
p_uart_obj [ uart_num ] -> tx_waiting_brk = 0 ;
2016-12-19 12:52:10 +08:00
p_uart_obj [ uart_num ] -> rx_buffered_len = 0 ;
2017-08-25 21:04:13 +08:00
uart_pattern_queue_reset ( uart_num , UART_PATTERN_DET_QLEN_DEFAULT );
2016-12-15 09:45:40 +08:00
if ( uart_queue ) {
p_uart_obj [ uart_num ] -> xQueueUart = xQueueCreate ( queue_size , sizeof ( uart_event_t ));
2016-12-22 13:43:42 +11:00
* uart_queue = p_uart_obj [ uart_num ] -> xQueueUart ;
2016-12-15 09:45:40 +08:00
ESP_LOGI ( UART_TAG , "queue free spaces: %d" , uxQueueSpacesAvailable ( p_uart_obj [ uart_num ] -> xQueueUart ));
} else {
p_uart_obj [ uart_num ] -> xQueueUart = NULL ;
}
p_uart_obj [ uart_num ] -> rx_buffer_full_flg = false ;
p_uart_obj [ uart_num ] -> tx_waiting_fifo = false ;
p_uart_obj [ uart_num ] -> rx_ptr = NULL ;
p_uart_obj [ uart_num ] -> rx_cur_remain = 0 ;
p_uart_obj [ uart_num ] -> rx_head_ptr = NULL ;
p_uart_obj [ uart_num ] -> rx_ring_buf = xRingbufferCreate ( rx_buffer_size , RINGBUF_TYPE_BYTEBUF );
if ( tx_buffer_size > 0 ) {
p_uart_obj [ uart_num ] -> tx_ring_buf = xRingbufferCreate ( tx_buffer_size , RINGBUF_TYPE_NOSPLIT );
p_uart_obj [ uart_num ] -> tx_buf_size = tx_buffer_size ;
} else {
p_uart_obj [ uart_num ] -> tx_ring_buf = NULL ;
p_uart_obj [ uart_num ] -> tx_buf_size = 0 ;
}
2018-05-03 10:41:10 +02:00
p_uart_obj [ uart_num ] -> uart_select_notif_callback = NULL ;
2016-12-15 09:45:40 +08:00
} else {
ESP_LOGE ( UART_TAG , "UART driver already installed" );
return ESP_FAIL ;
}
2017-02-07 15:05:18 +11:00
2017-08-31 11:29:12 +08:00
r = uart_isr_register ( uart_num , uart_rx_intr_handler_default , p_uart_obj [ uart_num ], intr_alloc_flags , & p_uart_obj [ uart_num ] -> intr_handle );
if ( r != ESP_OK ) goto err ;
2016-12-15 09:45:40 +08:00
uart_intr_config_t uart_intr = {
. intr_enable_mask = UART_RXFIFO_FULL_INT_ENA_M
| UART_RXFIFO_TOUT_INT_ENA_M
| UART_FRM_ERR_INT_ENA_M
| UART_RXFIFO_OVF_INT_ENA_M
| UART_BRK_DET_INT_ENA_M
| UART_PARITY_ERR_INT_ENA_M ,
. rxfifo_full_thresh = UART_FULL_THRESH_DEFAULT ,
. rx_timeout_thresh = UART_TOUT_THRESH_DEFAULT ,
. txfifo_empty_intr_thresh = UART_EMPTY_THRESH_DEFAULT
};
2017-08-31 11:29:12 +08:00
r = uart_intr_config ( uart_num , & uart_intr );
if ( r != ESP_OK ) goto err ;
return r ;
err :
uart_driver_delete ( uart_num );
return r ;
2016-12-15 09:45:40 +08:00
}
//Make sure no other tasks are still using UART before you call this function
esp_err_t uart_driver_delete ( uart_port_t uart_num )
{
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ESP_FAIL );
if ( p_uart_obj [ uart_num ] == NULL ) {
ESP_LOGI ( UART_TAG , "ALREADY NULL" );
return ESP_OK ;
}
2016-11-25 17:33:51 +08:00
esp_intr_free ( p_uart_obj [ uart_num ] -> intr_handle );
2016-12-15 09:45:40 +08:00
uart_disable_rx_intr ( uart_num );
uart_disable_tx_intr ( uart_num );
2017-08-25 21:04:13 +08:00
uart_pattern_link_free ( uart_num );
2016-12-15 09:45:40 +08:00
if ( p_uart_obj [ uart_num ] -> tx_fifo_sem ) {
vSemaphoreDelete ( p_uart_obj [ uart_num ] -> tx_fifo_sem );
p_uart_obj [ uart_num ] -> tx_fifo_sem = NULL ;
}
if ( p_uart_obj [ uart_num ] -> tx_done_sem ) {
vSemaphoreDelete ( p_uart_obj [ uart_num ] -> tx_done_sem );
p_uart_obj [ uart_num ] -> tx_done_sem = NULL ;
}
if ( p_uart_obj [ uart_num ] -> tx_brk_sem ) {
vSemaphoreDelete ( p_uart_obj [ uart_num ] -> tx_brk_sem );
p_uart_obj [ uart_num ] -> tx_brk_sem = NULL ;
}
if ( p_uart_obj [ uart_num ] -> tx_mux ) {
vSemaphoreDelete ( p_uart_obj [ uart_num ] -> tx_mux );
p_uart_obj [ uart_num ] -> tx_mux = NULL ;
}
if ( p_uart_obj [ uart_num ] -> rx_mux ) {
vSemaphoreDelete ( p_uart_obj [ uart_num ] -> rx_mux );
p_uart_obj [ uart_num ] -> rx_mux = NULL ;
}
if ( p_uart_obj [ uart_num ] -> xQueueUart ) {
vQueueDelete ( p_uart_obj [ uart_num ] -> xQueueUart );
p_uart_obj [ uart_num ] -> xQueueUart = NULL ;
}
if ( p_uart_obj [ uart_num ] -> rx_ring_buf ) {
vRingbufferDelete ( p_uart_obj [ uart_num ] -> rx_ring_buf );
p_uart_obj [ uart_num ] -> rx_ring_buf = NULL ;
}
if ( p_uart_obj [ uart_num ] -> tx_ring_buf ) {
vRingbufferDelete ( p_uart_obj [ uart_num ] -> tx_ring_buf );
p_uart_obj [ uart_num ] -> tx_ring_buf = NULL ;
}
free ( p_uart_obj [ uart_num ]);
p_uart_obj [ uart_num ] = NULL ;
2017-10-18 12:04:59 +08:00
2017-10-26 17:18:08 +08:00
if ( uart_num != CONFIG_CONSOLE_UART_NUM ) {
if ( uart_num == UART_NUM_0 ) {
periph_module_disable ( PERIPH_UART0_MODULE );
} else if ( uart_num == UART_NUM_1 ) {
periph_module_disable ( PERIPH_UART1_MODULE );
} else if ( uart_num == UART_NUM_2 ) {
periph_module_disable ( PERIPH_UART2_MODULE );
}
2017-10-18 12:04:59 +08:00
}
2016-12-15 09:45:40 +08:00
return ESP_OK ;
}
2018-05-03 10:41:10 +02:00
void uart_set_select_notif_callback ( uart_port_t uart_num , uart_select_notif_callback_t uart_select_notif_callback )
{
if ( uart_num < UART_NUM_MAX && p_uart_obj [ uart_num ]) {
p_uart_obj [ uart_num ] -> uart_select_notif_callback = ( uart_select_notif_callback_t ) uart_select_notif_callback ;
}
}
portMUX_TYPE * uart_get_selectlock ()
{
return & uart_selectlock ;
}
2018-04-11 11:56:00 +05:00
// Set UART mode
esp_err_t uart_set_mode ( uart_port_t uart_num , uart_mode_t mode )
{
UART_CHECK (( p_uart_obj [ uart_num ]), "uart driver error" , ESP_ERR_INVALID_STATE );
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ESP_ERR_INVALID_ARG );
2018-06-27 16:48:14 +02:00
if (( mode == UART_MODE_RS485_COLLISION_DETECT ) || ( mode == UART_MODE_RS485_APP_CTRL )
2018-04-11 11:56:00 +05:00
|| ( mode == UART_MODE_RS485_HALF_DUPLEX )) {
UART_CHECK (( UART [ uart_num ] -> conf1 . rx_flow_en != 1 ),
"disable hw flowctrl before using RS485 mode" , ESP_ERR_INVALID_ARG );
}
UART_ENTER_CRITICAL ( & uart_spinlock [ uart_num ]);
UART [ uart_num ] -> rs485_conf . en = 0 ;
UART [ uart_num ] -> rs485_conf . tx_rx_en = 0 ;
UART [ uart_num ] -> rs485_conf . rx_busy_tx_en = 0 ;
UART [ uart_num ] -> conf0 . irda_en = 0 ;
UART [ uart_num ] -> conf0 . sw_rts = 0 ;
switch ( mode ) {
case UART_MODE_UART :
break ;
2018-06-27 16:48:14 +02:00
case UART_MODE_RS485_COLLISION_DETECT :
2018-04-11 11:56:00 +05:00
// This mode allows read while transmitting that allows collision detection
p_uart_obj [ uart_num ] -> coll_det_flg = false ;
2018-07-19 13:58:57 +02:00
// Transmitters output signal loop back to the receivers input signal
2018-04-11 11:56:00 +05:00
UART [ uart_num ] -> rs485_conf . tx_rx_en = 0 ;
// Transmitter should send data when its receiver is busy
UART [ uart_num ] -> rs485_conf . rx_busy_tx_en = 1 ;
UART [ uart_num ] -> rs485_conf . en = 1 ;
// Enable collision detection interrupts
uart_enable_intr_mask ( uart_num , UART_RXFIFO_TOUT_INT_ENA
| UART_RXFIFO_FULL_INT_ENA
| UART_RS485_CLASH_INT_ENA
| UART_RS485_FRM_ERR_INT_ENA
| UART_RS485_PARITY_ERR_INT_ENA );
break ;
2018-06-27 16:48:14 +02:00
case UART_MODE_RS485_APP_CTRL :
2018-04-11 11:56:00 +05:00
// Application software control, remove echo
UART [ uart_num ] -> rs485_conf . rx_busy_tx_en = 1 ;
UART [ uart_num ] -> rs485_conf . en = 1 ;
break ;
case UART_MODE_RS485_HALF_DUPLEX :
// Enable receiver, sw_rts = 1 generates low level on RTS pin
UART [ uart_num ] -> conf0 . sw_rts = 1 ;
UART [ uart_num ] -> rs485_conf . en = 1 ;
// Must be set to 0 to automatically remove echo
UART [ uart_num ] -> rs485_conf . tx_rx_en = 0 ;
// This is to void collision
UART [ uart_num ] -> rs485_conf . rx_busy_tx_en = 1 ;
break ;
case UART_MODE_IRDA :
UART [ uart_num ] -> conf0 . irda_en = 1 ;
break ;
default :
2018-06-27 16:48:14 +02:00
UART_CHECK ( 1 , "unsupported uart mode" , ESP_ERR_INVALID_ARG );
2018-04-11 11:56:00 +05:00
break ;
}
p_uart_obj [ uart_num ] -> uart_mode = mode ;
UART_EXIT_CRITICAL ( & uart_spinlock [ uart_num ]);
return ESP_OK ;
}
esp_err_t uart_set_rx_timeout ( uart_port_t uart_num , const uint8_t tout_thresh )
{
2018-06-27 16:48:14 +02:00
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ESP_ERR_INVALID_ARG );
UART_CHECK (( tout_thresh < 127 ), "tout_thresh max value is 126" , ESP_ERR_INVALID_ARG );
2018-04-11 11:56:00 +05:00
UART_ENTER_CRITICAL ( & uart_spinlock [ uart_num ]);
// The tout_thresh = 1, defines TOUT interrupt timeout equal to
// transmission time of one symbol (~11 bit) on current baudrate
if ( tout_thresh > 0 ) {
UART [ uart_num ] -> conf1 . rx_tout_thrhd = ( tout_thresh & UART_RX_TOUT_THRHD_V );
UART [ uart_num ] -> conf1 . rx_tout_en = 1 ;
} else {
UART [ uart_num ] -> conf1 . rx_tout_en = 0 ;
}
UART_EXIT_CRITICAL ( & uart_spinlock [ uart_num ]);
return ESP_OK ;
}
esp_err_t uart_get_collision_flag ( uart_port_t uart_num , bool * collision_flag )
{
2018-06-27 16:48:14 +02:00
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ESP_ERR_INVALID_ARG );
UART_CHECK (( collision_flag != NULL ), "wrong parameter pointer" , ESP_ERR_INVALID_ARG );
2018-04-11 11:56:00 +05:00
UART_CHECK (( UART_IS_MODE_SET ( uart_num , UART_MODE_RS485_HALF_DUPLEX )
2018-06-27 16:48:14 +02:00
|| UART_IS_MODE_SET ( uart_num , UART_MODE_RS485_COLLISION_DETECT )),
"wrong mode" , ESP_ERR_INVALID_ARG );
2018-04-11 11:56:00 +05:00
* collision_flag = p_uart_obj [ uart_num ] -> coll_det_flg ;
return ESP_OK ;
}
2018-08-14 03:40:31 +03:00
esp_err_t uart_set_wakeup_threshold ( uart_port_t uart_num , int wakeup_threshold )
{
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ESP_ERR_INVALID_ARG );
UART_CHECK (( wakeup_threshold <= UART_ACTIVE_THRESHOLD_V &&
wakeup_threshold > UART_MIN_WAKEUP_THRESH ),
"wakeup_threshold out of bounds" , ESP_ERR_INVALID_ARG );
UART [ uart_num ] -> sleep_conf . active_threshold = wakeup_threshold - UART_MIN_WAKEUP_THRESH ;
return ESP_OK ;
}
esp_err_t uart_get_wakeup_threshold ( uart_port_t uart_num , int * out_wakeup_threshold )
{
UART_CHECK (( uart_num < UART_NUM_MAX ), "uart_num error" , ESP_ERR_INVALID_ARG );
UART_CHECK (( out_wakeup_threshold != NULL ), "argument is NULL" , ESP_ERR_INVALID_ARG );
* out_wakeup_threshold = UART [ uart_num ] -> sleep_conf . active_threshold + UART_MIN_WAKEUP_THRESH ;
return ESP_OK ;
}