mirror of
https://github.com/esp8266/Arduino.git
synced 2025-04-27 21:16:50 +03:00
Implement Serial RX Buffer (#2239)
In connection with: https://github.com/esp8266/Arduino/issues/2237 https://github.com/esp8266/Arduino/issues/2037 https://github.com/esp8266/Arduino/issues/1683
This commit is contained in:
parent
edba2d2829
commit
f8a8a2a359
@ -32,21 +32,13 @@
|
||||
|
||||
|
||||
HardwareSerial::HardwareSerial(int uart_nr)
|
||||
: _uart_nr(uart_nr)
|
||||
: _uart_nr(uart_nr), _rx_size(256)
|
||||
{}
|
||||
|
||||
void HardwareSerial::begin(unsigned long baud, SerialConfig config, SerialMode mode, uint8_t tx_pin)
|
||||
{
|
||||
if(uart_get_debug() == _uart_nr) {
|
||||
uart_set_debug(UART_NO);
|
||||
}
|
||||
|
||||
if (_uart) {
|
||||
free(_uart);
|
||||
}
|
||||
|
||||
_uart = uart_init(_uart_nr, baud, (int) config, (int) mode, tx_pin);
|
||||
_peek_char = -1;
|
||||
end();
|
||||
_uart = uart_init(_uart_nr, baud, (int) config, (int) mode, tx_pin, _rx_size);
|
||||
}
|
||||
|
||||
void HardwareSerial::end()
|
||||
@ -55,8 +47,19 @@ void HardwareSerial::end()
|
||||
uart_set_debug(UART_NO);
|
||||
}
|
||||
|
||||
uart_uninit(_uart);
|
||||
_uart = NULL;
|
||||
if (_uart) {
|
||||
uart_uninit(_uart);
|
||||
_uart = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
size_t HardwareSerial::setRxBufferSize(size_t size){
|
||||
if(_uart) {
|
||||
_rx_size = uart_resize_rx_buffer(_uart, size);
|
||||
} else {
|
||||
_rx_size = size;
|
||||
}
|
||||
return _rx_size;
|
||||
}
|
||||
|
||||
void HardwareSerial::swap(uint8_t tx_pin)
|
||||
@ -114,14 +117,7 @@ bool HardwareSerial::isRxEnabled(void)
|
||||
|
||||
int HardwareSerial::available(void)
|
||||
{
|
||||
if(!_uart || !uart_rx_enabled(_uart)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int result = static_cast<int>(uart_rx_available(_uart));
|
||||
if (_peek_char != -1) {
|
||||
result += 1;
|
||||
}
|
||||
if (!result) {
|
||||
optimistic_yield(10000);
|
||||
}
|
||||
@ -130,25 +126,13 @@ int HardwareSerial::available(void)
|
||||
|
||||
int HardwareSerial::peek(void)
|
||||
{
|
||||
if (_peek_char != -1) {
|
||||
return _peek_char;
|
||||
}
|
||||
// this may return -1, but that's okay
|
||||
_peek_char = uart_read_char(_uart);
|
||||
return _peek_char;
|
||||
return uart_peek_char(_uart);
|
||||
}
|
||||
|
||||
int HardwareSerial::read(void)
|
||||
{
|
||||
if(!_uart || !uart_rx_enabled(_uart)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (_peek_char != -1) {
|
||||
auto tmp = _peek_char;
|
||||
_peek_char = -1;
|
||||
return tmp;
|
||||
}
|
||||
// this may return -1, but that's okay
|
||||
return uart_read_char(_uart);
|
||||
}
|
||||
|
||||
|
@ -87,6 +87,8 @@ public:
|
||||
|
||||
void end();
|
||||
|
||||
size_t setRxBufferSize(size_t size);
|
||||
|
||||
void swap()
|
||||
{
|
||||
swap(1);
|
||||
@ -138,7 +140,7 @@ public:
|
||||
protected:
|
||||
int _uart_nr;
|
||||
uart_t* _uart = nullptr;
|
||||
int _peek_char = -1;
|
||||
size_t _rx_size;
|
||||
};
|
||||
|
||||
extern HardwareSerial Serial;
|
||||
|
@ -47,6 +47,13 @@
|
||||
|
||||
static int s_uart_debug_nr = UART0;
|
||||
|
||||
struct uart_rx_buffer_ {
|
||||
size_t size;
|
||||
size_t rpos;
|
||||
size_t wpos;
|
||||
uint8_t * buffer;
|
||||
};
|
||||
|
||||
struct uart_ {
|
||||
int uart_nr;
|
||||
int baud_rate;
|
||||
@ -54,8 +61,132 @@ struct uart_ {
|
||||
bool tx_enabled;
|
||||
uint8_t rx_pin;
|
||||
uint8_t tx_pin;
|
||||
struct uart_rx_buffer_ * rx_buffer;
|
||||
};
|
||||
|
||||
size_t uart_resize_rx_buffer(uart_t* uart, size_t new_size)
|
||||
{
|
||||
if(uart == NULL || !uart->rx_enabled) {
|
||||
return 0;
|
||||
}
|
||||
if(uart->rx_buffer->size == new_size) {
|
||||
return uart->rx_buffer->size;
|
||||
}
|
||||
uint8_t * new_buf = (uint8_t*)malloc(new_size);
|
||||
if(!new_buf) {
|
||||
return uart->rx_buffer->size;
|
||||
}
|
||||
size_t new_wpos = 0;
|
||||
ETS_UART_INTR_DISABLE();
|
||||
while(uart_rx_available(uart) && new_wpos < new_size) {
|
||||
new_buf[new_wpos++] = uart_read_char(uart);
|
||||
}
|
||||
uint8_t * old_buf = uart->rx_buffer->buffer;
|
||||
uart->rx_buffer->rpos = 0;
|
||||
uart->rx_buffer->wpos = new_wpos;
|
||||
uart->rx_buffer->size = new_size;
|
||||
uart->rx_buffer->buffer = new_buf;
|
||||
free(old_buf);
|
||||
ETS_UART_INTR_ENABLE();
|
||||
return uart->rx_buffer->size;
|
||||
}
|
||||
|
||||
int uart_peek_char(uart_t* uart)
|
||||
{
|
||||
if(uart == NULL || !uart->rx_enabled) {
|
||||
return -1;
|
||||
}
|
||||
if (!uart_rx_available(uart)) {
|
||||
return -1;
|
||||
}
|
||||
return uart->rx_buffer->buffer[uart->rx_buffer->rpos];
|
||||
}
|
||||
|
||||
int uart_read_char(uart_t* uart)
|
||||
{
|
||||
int data = uart_peek_char(uart);
|
||||
if(data != -1) {
|
||||
uart->rx_buffer->rpos = (uart->rx_buffer->rpos + 1) % uart->rx_buffer->size;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
size_t uart_rx_available(uart_t* uart)
|
||||
{
|
||||
if(uart == NULL || !uart->rx_enabled) {
|
||||
return 0;
|
||||
}
|
||||
if(uart->rx_buffer->wpos < uart->rx_buffer->rpos) {
|
||||
return (uart->rx_buffer->wpos + uart->rx_buffer->size) - uart->rx_buffer->rpos;
|
||||
}
|
||||
return uart->rx_buffer->wpos - uart->rx_buffer->rpos;
|
||||
}
|
||||
|
||||
|
||||
void ICACHE_RAM_ATTR uart_isr(void * arg)
|
||||
{
|
||||
uart_t* uart = (uart_t*)arg;
|
||||
if(uart == NULL || !uart->rx_enabled) {
|
||||
USIC(uart->uart_nr) = 0xffff;
|
||||
ETS_UART_INTR_DISABLE();
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t int_status = USIS(uart->uart_nr);
|
||||
|
||||
if(int_status & (1 << UIFR)) {
|
||||
USIC(uart->uart_nr) = (1 << UIFR);//clear any frame error
|
||||
}
|
||||
|
||||
if(int_status & (1 << UIFF) || int_status & (1 << UITO)){
|
||||
ETS_UART_INTR_DISABLE();
|
||||
while(((USS(uart->uart_nr) >> USRXC) & 0x7F) != 0){
|
||||
uint8_t data = USF(uart->uart_nr);
|
||||
size_t nextPos = (uart->rx_buffer->wpos + 1) % uart->rx_buffer->size;
|
||||
if(nextPos != uart->rx_buffer->rpos) {
|
||||
uart->rx_buffer->buffer[uart->rx_buffer->wpos] = data;
|
||||
uart->rx_buffer->wpos = nextPos;
|
||||
} else {
|
||||
//rx buffer OverFlow
|
||||
//maybe stop the loop and try later?
|
||||
}
|
||||
}
|
||||
int_status = USIS(uart->uart_nr);
|
||||
if(int_status & (1 << UIFF)) {
|
||||
USIC(uart->uart_nr) = (1 << UIFF);//clear any FIFO FULL error
|
||||
}
|
||||
if(int_status & (1 << UITO)) {
|
||||
USIC(uart->uart_nr) = (1 << UITO);//clear any TimeOut error
|
||||
}
|
||||
ETS_UART_INTR_ENABLE();
|
||||
}
|
||||
}
|
||||
|
||||
void uart_start_isr(uart_t* uart)
|
||||
{
|
||||
if(uart == NULL || !uart->rx_enabled) {
|
||||
return;
|
||||
}
|
||||
USC1(uart->uart_nr) = (127 << UCFFT) | (0x02 << UCTOT) | (1 <<UCTOE );
|
||||
USIC(uart->uart_nr) = 0xffff;
|
||||
USIE(uart->uart_nr) = (1 << UIFF) | (1 << UIFR) | (1 << UITO);
|
||||
ETS_UART_INTR_ATTACH(uart_isr, (void *)uart);
|
||||
ETS_UART_INTR_ENABLE();
|
||||
}
|
||||
|
||||
void uart_stop_isr(uart_t* uart)
|
||||
{
|
||||
if(uart == NULL || !uart->rx_enabled) {
|
||||
return;
|
||||
}
|
||||
ETS_UART_INTR_DISABLE();
|
||||
USC1(uart->uart_nr) = 0;
|
||||
USIC(uart->uart_nr) = 0xffff;
|
||||
USIE(uart->uart_nr) = 0;
|
||||
ETS_UART_INTR_ATTACH(NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
void uart_write_char(uart_t* uart, char c)
|
||||
{
|
||||
if(uart == NULL || !uart->tx_enabled) {
|
||||
@ -75,25 +206,6 @@ void uart_write(uart_t* uart, const char* buf, size_t size)
|
||||
}
|
||||
}
|
||||
|
||||
int uart_read_char(uart_t* uart)
|
||||
{
|
||||
if(uart == NULL || !uart->rx_enabled) {
|
||||
return -1;
|
||||
}
|
||||
if (!uart_rx_available(uart)) {
|
||||
return -1;
|
||||
}
|
||||
return USF(uart->uart_nr) & 0xff;
|
||||
}
|
||||
|
||||
size_t uart_rx_available(uart_t* uart)
|
||||
{
|
||||
if(uart == NULL || !uart->rx_enabled) {
|
||||
return -1;
|
||||
}
|
||||
return (USS(uart->uart_nr) >> USRXC) & 0xff;
|
||||
}
|
||||
|
||||
size_t uart_tx_free(uart_t* uart)
|
||||
{
|
||||
if(uart == NULL || !uart->tx_enabled) {
|
||||
@ -121,6 +233,10 @@ void uart_flush(uart_t* uart)
|
||||
uint32_t tmp = 0x00000000;
|
||||
if(uart->rx_enabled) {
|
||||
tmp |= (1 << UCRXRST);
|
||||
ETS_UART_INTR_DISABLE();
|
||||
uart->rx_buffer->rpos = 0;
|
||||
uart->rx_buffer->wpos = 0;
|
||||
ETS_UART_INTR_ENABLE();
|
||||
}
|
||||
|
||||
if(uart->tx_enabled) {
|
||||
@ -148,7 +264,7 @@ int uart_get_baudrate(uart_t* uart)
|
||||
return uart->baud_rate;
|
||||
}
|
||||
|
||||
uart_t* uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin)
|
||||
uart_t* uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin, size_t rx_size)
|
||||
{
|
||||
uart_t* uart = (uart_t*) malloc(sizeof(uart_t));
|
||||
if(uart == NULL) {
|
||||
@ -159,9 +275,29 @@ uart_t* uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin)
|
||||
|
||||
switch(uart->uart_nr) {
|
||||
case UART0:
|
||||
ETS_UART_INTR_DISABLE();
|
||||
ETS_UART_INTR_ATTACH(NULL, NULL);
|
||||
uart->rx_enabled = (mode != UART_TX_ONLY);
|
||||
uart->tx_enabled = (mode != UART_RX_ONLY);
|
||||
uart->rx_pin = (uart->rx_enabled)?3:255;
|
||||
if(uart->rx_enabled) {
|
||||
struct uart_rx_buffer_ * rx_buffer = (struct uart_rx_buffer_ *)malloc(sizeof(struct uart_rx_buffer_));
|
||||
if(rx_buffer == NULL) {
|
||||
free(uart);
|
||||
return NULL;
|
||||
}
|
||||
rx_buffer->size = rx_size;//var this
|
||||
rx_buffer->rpos = 0;
|
||||
rx_buffer->wpos = 0;
|
||||
rx_buffer->buffer = (uint8_t *)malloc(rx_buffer->size);
|
||||
if(rx_buffer->buffer == NULL) {
|
||||
free(rx_buffer);
|
||||
free(uart);
|
||||
return NULL;
|
||||
}
|
||||
uart->rx_buffer = rx_buffer;
|
||||
pinMode(uart->rx_pin, SPECIAL);
|
||||
}
|
||||
if(uart->tx_enabled) {
|
||||
if (tx_pin == 2) {
|
||||
uart->tx_pin = 2;
|
||||
@ -173,9 +309,6 @@ uart_t* uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin)
|
||||
} else {
|
||||
uart->tx_pin = 255;
|
||||
}
|
||||
if(uart->rx_enabled) {
|
||||
pinMode(uart->rx_pin, SPECIAL);
|
||||
}
|
||||
IOSWAP &= ~(1 << IOSWAPU0);
|
||||
break;
|
||||
case UART1:
|
||||
@ -199,6 +332,11 @@ uart_t* uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin)
|
||||
USC0(uart->uart_nr) = config;
|
||||
uart_flush(uart);
|
||||
USC1(uart->uart_nr) = 0;
|
||||
USIC(uart->uart_nr) = 0xffff;
|
||||
USIE(uart->uart_nr) = 0;
|
||||
if(uart->uart_nr == UART0 && uart->rx_enabled) {
|
||||
uart_start_isr(uart);
|
||||
}
|
||||
|
||||
return uart;
|
||||
}
|
||||
@ -230,6 +368,11 @@ void uart_uninit(uart_t* uart)
|
||||
break;
|
||||
}
|
||||
|
||||
if(uart->rx_enabled){
|
||||
free(uart->rx_buffer->buffer);
|
||||
free(uart->rx_buffer);
|
||||
//uart_stop_isr(uart);
|
||||
}
|
||||
free(uart);
|
||||
}
|
||||
|
||||
|
@ -113,7 +113,7 @@ extern "C" {
|
||||
struct uart_;
|
||||
typedef struct uart_ uart_t;
|
||||
|
||||
uart_t* uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin);
|
||||
uart_t* uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin, size_t rx_size);
|
||||
void uart_uninit(uart_t* uart);
|
||||
|
||||
void uart_swap(uart_t* uart, int tx_pin);
|
||||
@ -125,9 +125,12 @@ bool uart_rx_enabled(uart_t* uart);
|
||||
void uart_set_baudrate(uart_t* uart, int baud_rate);
|
||||
int uart_get_baudrate(uart_t* uart);
|
||||
|
||||
size_t uart_resize_rx_buffer(uart_t* uart, size_t new_size);
|
||||
|
||||
void uart_write_char(uart_t* uart, char c);
|
||||
void uart_write(uart_t* uart, const char* buf, size_t size);
|
||||
int uart_read_char(uart_t* uart);
|
||||
int uart_peek_char(uart_t* uart);
|
||||
size_t uart_rx_available(uart_t* uart);
|
||||
size_t uart_tx_free(uart_t* uart);
|
||||
void uart_wait_tx_empty(uart_t* uart);
|
||||
|
Loading…
x
Reference in New Issue
Block a user