Skip to content

Commit

Permalink
Merge pull request paparazzi#1110 from paparazzi/linux_uart_fix
Browse files Browse the repository at this point in the history
[arch/linux] fix uart driver

- make sure the output flags are properly reset for raw mode.
  Specifically OPOST, clear some others as well to be safe...
- put byte in queue if write was interrupted and only advance extract index if write was successful
  This solves the issue of some bytes not being written (at least on BBB with PREEMPT kernel)
  • Loading branch information
flixr committed Feb 20, 2015
2 parents b59b1d6 + f374efe commit e98128d
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 5 deletions.
18 changes: 13 additions & 5 deletions sw/airborne/arch/linux/mcu_periph/uart_arch.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include "serial_port.h"

Expand Down Expand Up @@ -88,6 +89,7 @@ void uart_transmit(struct uart_periph *periph, uint8_t data)
uint16_t temp = (periph->tx_insert_idx + 1) % UART_TX_BUFFER_SIZE;

if (temp == periph->tx_extract_idx) {
printf("uart tx queue full!\n");
return; // no room
}

Expand All @@ -100,12 +102,16 @@ void uart_transmit(struct uart_periph *periph, uint8_t data)
struct SerialPort *port = (struct SerialPort *)(periph->reg_addr);
int ret = write((int)(port->fd), &data, 1);
if (ret < 1) {
TRACE("w %x [%d]\n", data, ret);
TRACE("uart_transmit: write %d failed [%d: %s]\n", data, ret, strerror(errno));
/* if write was interrupted, put data into queue */
if (errno == EINTR) {
periph->tx_buf[periph->tx_insert_idx] = data;
periph->tx_insert_idx = temp;
}
}
}
}

#include <errno.h>

static inline void uart_handler(struct uart_periph *periph)
{
Expand All @@ -120,10 +126,12 @@ static inline void uart_handler(struct uart_periph *periph)
if (periph->tx_insert_idx != periph->tx_extract_idx) {
int ret = write(fd, &(periph->tx_buf[periph->tx_extract_idx]), 1);
if (ret < 1) {
TRACE("w %x [%d: %s]\n", periph->tx_buf[periph->tx_extract_idx], ret, strerror(errno));
TRACE("uart_handler: write %x failed [%d: %s]\n", periph->tx_buf[periph->tx_extract_idx], ret, strerror(errno));
}
else {
periph->tx_extract_idx++;
periph->tx_extract_idx %= UART_TX_BUFFER_SIZE;
}
periph->tx_extract_idx++;
periph->tx_extract_idx %= UART_TX_BUFFER_SIZE;
} else {
periph->tx_running = FALSE; // clear running flag
}
Expand Down
3 changes: 3 additions & 0 deletions sw/airborne/arch/linux/serial_port.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ int serial_port_open_raw(struct SerialPort *me, const char *device, speed_t spe
/* local modes */
me->cur_termios.c_lflag &= ~(ISIG | ICANON | IEXTEN | ECHO | FLUSHO | PENDIN);
me->cur_termios.c_lflag |= NOFLSH;
/* output modes */
me->cur_termios.c_oflag &=~(OPOST|ONLCR|OCRNL|ONOCR|ONLRET);

if (cfsetispeed(&me->cur_termios, speed)) {
TRACE(TRACE_ERROR, "%s, set term speed failed: %s (%d)\n", device, strerror(errno), errno);
close(me->fd);
Expand Down

0 comments on commit e98128d

Please sign in to comment.