Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 56 additions & 49 deletions cores/arduino/Serial.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -583,62 +583,69 @@ void Uart::flush(uint32_t timeout)

size_t Uart::write(const uint8_t *buffer, size_t size)
{
size_t size_intermediate;
size_t ret = size;
size_t available = availableForWrite();
size_t available_till_buffer_end = SERIAL_TX_BUFFER_SIZE - _serial.tx_head;

_written = true;
if (isHalfDuplex()) {
if (_rx_enabled) {
_rx_enabled = false;
uart_enable_tx(&_serial);
// If begin() never brought the hardware up (e.g. the requested baud
// rate can't be reached from the configured kernel clock), the TX
// interrupt this function waits on below will never fire. Bail out
// instead of spinning forever once the TX buffer fills up.
if (!_ready) {
ret = 0;
} else {
size_t size_intermediate;
size_t available = availableForWrite();
size_t available_till_buffer_end = SERIAL_TX_BUFFER_SIZE - _serial.tx_head;

_written = true;
if (isHalfDuplex()) {
if (_rx_enabled) {
_rx_enabled = false;
uart_enable_tx(&_serial);
}
}
}

// If the output buffer is full, there's nothing for it other than to
// wait for the interrupt handler to free space
while (!availableForWrite()) {
// nop, the interrupt handler will free up space for us
}
// If the output buffer is full, there's nothing for it other than to
// wait for the interrupt handler to free space
while (!availableForWrite()) {
// nop, the interrupt handler will free up space for us
}

// HAL doesn't manage rollover, so split transfer till end of TX buffer
// Also, split transfer according to available space in buffer
while ((size > available_till_buffer_end) || (size > available)) {
size_intermediate = min(available, available_till_buffer_end);
write(buffer, size_intermediate);
size -= size_intermediate;
buffer += size_intermediate;
available = availableForWrite();
available_till_buffer_end = SERIAL_TX_BUFFER_SIZE - _serial.tx_head;
}
// HAL doesn't manage rollover, so split transfer till end of TX buffer
// Also, split transfer according to available space in buffer
while ((size > available_till_buffer_end) || (size > available)) {
size_intermediate = min(available, available_till_buffer_end);
write(buffer, size_intermediate);
size -= size_intermediate;
buffer += size_intermediate;
available = availableForWrite();
available_till_buffer_end = SERIAL_TX_BUFFER_SIZE - _serial.tx_head;
}

// Copy data to buffer. Take into account rollover if necessary.
if (_serial.tx_head + size <= SERIAL_TX_BUFFER_SIZE) {
memcpy(&_serial.tx_buff[_serial.tx_head], buffer, size);
size_intermediate = size;
} else {
// memcpy till end of buffer then continue memcpy from beginning of buffer
size_intermediate = SERIAL_TX_BUFFER_SIZE - _serial.tx_head;
memcpy(&_serial.tx_buff[_serial.tx_head], buffer, size_intermediate);
memcpy(&_serial.tx_buff[0], buffer + size_intermediate,
size - size_intermediate);
}
// Copy data to buffer. Take into account rollover if necessary.
if (_serial.tx_head + size <= SERIAL_TX_BUFFER_SIZE) {
memcpy(&_serial.tx_buff[_serial.tx_head], buffer, size);
size_intermediate = size;
} else {
// memcpy till end of buffer then continue memcpy from beginning of buffer
size_intermediate = SERIAL_TX_BUFFER_SIZE - _serial.tx_head;
memcpy(&_serial.tx_buff[_serial.tx_head], buffer, size_intermediate);
memcpy(&_serial.tx_buff[0], buffer + size_intermediate,
size - size_intermediate);
}

// Data are copied to buffer, move head pointer accordingly
_serial.tx_head = (_serial.tx_head + size) % SERIAL_TX_BUFFER_SIZE;

// Transfer data with HAL only is there is no TX data transfer ongoing
// otherwise, data transfer will be done asynchronously from callback
if (!serial_tx_active(&_serial)) {
// note: tx_size correspond to size of HAL data transfer,
// not the total amount of data in the buffer.
// To compute size of data in buffer compare head and tail
_serial.tx_size = size_intermediate;
uart_attach_tx_callback(&_serial, _tx_complete_irq, size_intermediate);
// Data are copied to buffer, move head pointer accordingly
_serial.tx_head = (_serial.tx_head + size) % SERIAL_TX_BUFFER_SIZE;

// Transfer data with HAL only is there is no TX data transfer ongoing
// otherwise, data transfer will be done asynchronously from callback
if (!serial_tx_active(&_serial)) {
// note: tx_size correspond to size of HAL data transfer,
// not the total amount of data in the buffer.
// To compute size of data in buffer compare head and tail
_serial.tx_size = size_intermediate;
uart_attach_tx_callback(&_serial, _tx_complete_irq, size_intermediate);
}
}

/* There is no real error management so just return transfer size requested*/
/* Return 0 if not ready else requested transfer size */
return ret;
}

Expand Down
Loading