diff --git a/cores/arduino/HardwareSerial.cpp b/cores/arduino/HardwareSerial.cpp index dfa9b8d759..b938c360cc 100644 --- a/cores/arduino/HardwareSerial.cpp +++ b/cores/arduino/HardwareSerial.cpp @@ -327,7 +327,7 @@ int HardwareSerial::_tx_complete_irq(serial_t *obj) { // If interrupts are enabled, there must be more data in the output // buffer. Send the next byte - obj->tx_tail = (obj->tx_tail + 1) % SERIAL_TX_BUFFER_SIZE; + obj->tx_tail = (obj->tx_tail + obj->tx_size) % SERIAL_TX_BUFFER_SIZE; if (obj->tx_head == obj->tx_tail) { return -1; @@ -467,8 +467,12 @@ void HardwareSerial::flush() // the hardware finished tranmission (TXC is set). } -size_t HardwareSerial::write(uint8_t c) +size_t HardwareSerial::write(const uint8_t *buffer, size_t size) { + tx_buffer_index_t i; + size_t size_tmp; + size_t ret = size; + _written = true; if (isHalfDuplex()) { if (_rx_enabled) { @@ -477,22 +481,59 @@ size_t HardwareSerial::write(uint8_t c) } } - tx_buffer_index_t i = (_serial.tx_head + 1) % SERIAL_TX_BUFFER_SIZE; + // If necessary split transfert till end of TX buffer + while (_serial.tx_head + size > SERIAL_TX_BUFFER_SIZE) { + size_t size_intermediate = SERIAL_TX_BUFFER_SIZE - _serial.tx_head; - // If the output buffer is full, there's nothing for it other than to - // wait for the interrupt handler to empty it a bit - while (i == _serial.tx_tail) { - // nop, the interrupt handler will free up space for us + write(buffer, size_intermediate); + size -= size_intermediate; + buffer += size_intermediate; + } + + // Here size if less or equal to SERIAL_TX_BUFFER_SIZE, but SERIAL_TX_BUFFER_SIZE is not possible as tx_head = tx_tail is ambiguous empty or full + if (size == SERIAL_TX_BUFFER_SIZE) { + size_t size_intermediate = SERIAL_TX_BUFFER_SIZE - 1; + + write(buffer, size_intermediate); + size -= size_intermediate; + buffer += size_intermediate; + } + + size_tmp = size; + + while (size_tmp) { + i = (_serial.tx_head + 1) % SERIAL_TX_BUFFER_SIZE; + + + // If the output buffer is full, there's nothing for it other than to + // wait for the interrupt handler to empty it a bit + while (i == _serial.tx_tail) { + // nop, the interrupt handler will free up space for us + } + _serial.tx_buff[_serial.tx_head] = *buffer; + _serial.tx_head = i; + size_tmp --; + buffer ++; + } + + while ((_serial.tx_head != (_serial.tx_tail + size) % SERIAL_TX_BUFFER_SIZE)) { + // nop, previous transfert no yet completed } - _serial.tx_buff[_serial.tx_head] = c; - _serial.tx_head = i; + _serial.tx_size = size; if (!serial_tx_active(&_serial)) { - uart_attach_tx_callback(&_serial, _tx_complete_irq); + uart_attach_tx_callback(&_serial, _tx_complete_irq, size); } - return 1; + /* There is no real error management so just return transfer size requested*/ + return ret; +} + +size_t HardwareSerial::write(uint8_t c) +{ + uint8_t buff = c; + return write(&buff, 1); } void HardwareSerial::setRx(uint32_t _rx) diff --git a/cores/arduino/HardwareSerial.h b/cores/arduino/HardwareSerial.h index 3271ebade5..63b2022a7b 100644 --- a/cores/arduino/HardwareSerial.h +++ b/cores/arduino/HardwareSerial.h @@ -143,7 +143,8 @@ class HardwareSerial : public Stream { { return write((uint8_t)n); } - using Print::write; // pull in write(str) and write(buf, size) from Print + size_t write(const uint8_t *buffer, size_t size); + using Print::write; // pull in write(str) from Print operator bool() { return true; diff --git a/cores/arduino/stm32/uart.h b/cores/arduino/stm32/uart.h index 3a530bdb72..05f8436b84 100644 --- a/cores/arduino/stm32/uart.h +++ b/cores/arduino/stm32/uart.h @@ -80,6 +80,7 @@ struct serial_s { uint16_t tx_head; volatile uint16_t rx_head; volatile uint16_t tx_tail; + size_t tx_size; }; /* Exported constants --------------------------------------------------------*/ @@ -186,7 +187,7 @@ void uart_config_lowpower(serial_t *obj); size_t uart_write(serial_t *obj, uint8_t data, uint16_t size); int uart_getc(serial_t *obj, unsigned char *c); void uart_attach_rx_callback(serial_t *obj, void (*callback)(serial_t *)); -void uart_attach_tx_callback(serial_t *obj, int (*callback)(serial_t *)); +void uart_attach_tx_callback(serial_t *obj, int (*callback)(serial_t *), size_t size); uint8_t serial_tx_active(serial_t *obj); uint8_t serial_rx_active(serial_t *obj); diff --git a/libraries/SrcWrapper/src/stm32/uart.c b/libraries/SrcWrapper/src/stm32/uart.c index 32668b4b11..ae6f501c13 100644 --- a/libraries/SrcWrapper/src/stm32/uart.c +++ b/libraries/SrcWrapper/src/stm32/uart.c @@ -723,7 +723,7 @@ void uart_attach_rx_callback(serial_t *obj, void (*callback)(serial_t *)) * @param callback : function call at the end of transmission * @retval none */ -void uart_attach_tx_callback(serial_t *obj, int (*callback)(serial_t *)) +void uart_attach_tx_callback(serial_t *obj, int (*callback)(serial_t *), size_t size) { if (obj == NULL) { return; @@ -734,7 +734,7 @@ void uart_attach_tx_callback(serial_t *obj, int (*callback)(serial_t *)) HAL_NVIC_DisableIRQ(obj->irq); /* The following function will enable UART_IT_TXE and error interrupts */ - HAL_UART_Transmit_IT(uart_handlers[obj->index], &obj->tx_buff[obj->tx_tail], 1); + HAL_UART_Transmit_IT(uart_handlers[obj->index], &obj->tx_buff[obj->tx_tail], size); /* Enable interrupt */ HAL_NVIC_EnableIRQ(obj->irq); @@ -810,11 +810,8 @@ void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) { serial_t *obj = get_serial_obj(huart); - - if (obj && obj->tx_callback(obj) != -1) { - if (HAL_UART_Transmit_IT(huart, &obj->tx_buff[obj->tx_tail], 1) != HAL_OK) { - return; - } + if (obj) { + obj->tx_callback(obj); } }