@@ -334,15 +334,23 @@ void HardwareSerial::_rx_complete_irq(serial_t *obj)
334334 }
335335}
336336
337- // Actual interrupt handlers //////////////////////////////////////////////////////////////
337+ // Actual interrupt handlers //////////////////////////////////////////////////
338338
339339int HardwareSerial::_tx_complete_irq (serial_t *obj)
340340{
341- // If interrupts are enabled, there must be more data in the output
342- // buffer. Send the next byte
341+ size_t remaining_data;
342+ // previous HAL transfer is finished, move tail pointer accordingly
343343 obj->tx_tail = (obj->tx_tail + obj->tx_size ) % SERIAL_TX_BUFFER_SIZE;
344344
345- if (obj->tx_head == obj->tx_tail ) {
345+ // If buffer is not empty (head != tail), send remaining data
346+ if (obj->tx_head != obj->tx_tail ) {
347+ remaining_data = (SERIAL_TX_BUFFER_SIZE + obj->tx_head - obj->tx_tail )
348+ % SERIAL_TX_BUFFER_SIZE;
349+ // Limit the next transmission to the buffer end
350+ // because HAL is not able to manage rollover
351+ obj->tx_size = min (remaining_data,
352+ (size_t )(SERIAL_TX_BUFFER_SIZE - obj->tx_tail ));
353+ uart_attach_tx_callback (obj, _tx_complete_irq, obj->tx_size );
346354 return -1 ;
347355 }
348356
@@ -482,9 +490,10 @@ void HardwareSerial::flush()
482490
483491size_t HardwareSerial::write (const uint8_t *buffer, size_t size)
484492{
485- tx_buffer_index_t i;
486- size_t size_tmp;
493+ size_t size_intermediate;
487494 size_t ret = size;
495+ size_t available = availableForWrite ();
496+ size_t available_till_buffer_end = SERIAL_TX_BUFFER_SIZE - _serial.tx_head ;
488497
489498 _written = true ;
490499 if (isHalfDuplex ()) {
@@ -494,49 +503,46 @@ size_t HardwareSerial::write(const uint8_t *buffer, size_t size)
494503 }
495504 }
496505
497- // If necessary split transfert till end of TX buffer
498- while (_serial.tx_head + size > SERIAL_TX_BUFFER_SIZE) {
499- size_t size_intermediate = SERIAL_TX_BUFFER_SIZE - _serial.tx_head ;
500-
501- write (buffer, size_intermediate);
502- size -= size_intermediate;
503- buffer += size_intermediate;
506+ // If the output buffer is full, there's nothing for it other than to
507+ // wait for the interrupt handler to free space
508+ while (!availableForWrite ()) {
509+ // nop, the interrupt handler will free up space for us
504510 }
505511
506- // 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
507- if (size == SERIAL_TX_BUFFER_SIZE) {
508- size_t size_intermediate = SERIAL_TX_BUFFER_SIZE - 1 ;
509-
512+ // HAL doesn't manage rollover, so split transfer till end of TX buffer
513+ // Also, split transfer according to available space in buffer
514+ while ((size > available_till_buffer_end) || (size > available)) {
515+ size_intermediate = min (available, available_till_buffer_end);
510516 write (buffer, size_intermediate);
511517 size -= size_intermediate;
512518 buffer += size_intermediate;
519+ available = availableForWrite ();
520+ available_till_buffer_end = SERIAL_TX_BUFFER_SIZE - _serial.tx_head ;
513521 }
514522
515- size_tmp = size;
516-
517- while (size_tmp) {
518- i = (_serial.tx_head + 1 ) % SERIAL_TX_BUFFER_SIZE;
519-
520-
521- // If the output buffer is full, there's nothing for it other than to
522- // wait for the interrupt handler to empty it a bit
523- while (i == _serial.tx_tail ) {
524- // nop, the interrupt handler will free up space for us
525- }
526- _serial.tx_buff [_serial.tx_head ] = *buffer;
527- _serial.tx_head = i;
528- size_tmp --;
529- buffer ++;
530- }
531-
532- while ((_serial.tx_head != (_serial.tx_tail + size) % SERIAL_TX_BUFFER_SIZE)) {
533- // nop, previous transfert no yet completed
523+ // Copy data to buffer. Take into account rollover if necessary.
524+ if (_serial.tx_head + size <= SERIAL_TX_BUFFER_SIZE) {
525+ memcpy (&_serial.tx_buff [_serial.tx_head ], buffer, size);
526+ size_intermediate = size;
527+ } else {
528+ // memcpy till end of buffer then continue memcpy from beginning of buffer
529+ size_intermediate = SERIAL_TX_BUFFER_SIZE - _serial.tx_head ;
530+ memcpy (&_serial.tx_buff [_serial.tx_head ], buffer, size_intermediate);
531+ memcpy (&_serial.tx_buff [0 ], buffer + size_intermediate,
532+ size - size_intermediate);
534533 }
535534
536- _serial.tx_size = size;
535+ // Data are copied to buffer, move head pointer accordingly
536+ _serial.tx_head = (_serial.tx_head + size) % SERIAL_TX_BUFFER_SIZE;
537537
538+ // Transfer data with HAL only is there is no TX data transfer ongoing
539+ // otherwise, data transfer will be done asynchronously from callback
538540 if (!serial_tx_active (&_serial)) {
539- uart_attach_tx_callback (&_serial, _tx_complete_irq, size);
541+ // note: tx_size correspond to size of HAL data transfer,
542+ // not the total amount of data in the buffer.
543+ // To compute size of data in buffer compare head and tail
544+ _serial.tx_size = size_intermediate;
545+ uart_attach_tx_callback (&_serial, _tx_complete_irq, size_intermediate);
540546 }
541547
542548 /* There is no real error management so just return transfer size requested*/
0 commit comments