| Index: device/serial/serial_io_handler_posix.cc
|
| diff --git a/device/serial/serial_io_handler_posix.cc b/device/serial/serial_io_handler_posix.cc
|
| index b3685e011ac49aaf5bc5ef9ebe58b82df7374ceb..0244f92dea5c616a1034143ee3f29e540d93a90b 100644
|
| --- a/device/serial/serial_io_handler_posix.cc
|
| +++ b/device/serial/serial_io_handler_posix.cc
|
| @@ -186,8 +186,8 @@ bool SerialIoHandlerPosix::ConfigurePortImpl() {
|
|
|
| // Set flags for 'raw' operation
|
| config.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHONL | ISIG);
|
| - config.c_iflag &=
|
| - ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
|
| + config.c_iflag &= ~(IGNBRK | BRKINT | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
|
| + config.c_iflag |= PARMRK;
|
| config.c_oflag &= ~OPOST;
|
|
|
| // CLOCAL causes the system to disregard the DCD signal state.
|
| @@ -234,6 +234,19 @@ bool SerialIoHandlerPosix::ConfigurePortImpl() {
|
| break;
|
| }
|
|
|
| + byte_read_state_ = BYTEREAD_REGULAR;
|
| + num_chars_ignored_ = 0;
|
| +
|
| + if (config.c_cflag & PARENB) {
|
| + config.c_iflag &= ~IGNPAR;
|
| + config.c_iflag |= INPCK;
|
| + parity_check_enabled_ = true;
|
| + } else {
|
| + config.c_iflag |= IGNPAR;
|
| + config.c_iflag &= ~INPCK;
|
| + parity_check_enabled_ = false;
|
| + }
|
| +
|
| DCHECK(options().stop_bits != serial::STOP_BITS_NONE);
|
| switch (options().stop_bits) {
|
| case serial::STOP_BITS_TWO:
|
| @@ -287,7 +300,24 @@ void SerialIoHandlerPosix::OnFileCanReadWithoutBlocking(int fd) {
|
| } else if (bytes_read == 0) {
|
| ReadCompleted(0, serial::RECEIVE_ERROR_DEVICE_LOST);
|
| } else {
|
| - ReadCompleted(bytes_read, serial::RECEIVE_ERROR_NONE);
|
| + bool break_detected = false;
|
| + bool parity_error_detected = false;
|
| +
|
| + int new_bytes_read =
|
| + CheckReceiveError(pending_read_buffer(), pending_read_buffer_len(),
|
| + bytes_read, break_detected, parity_error_detected);
|
| +
|
| + if (new_bytes_read != 0) {
|
| + ReadCompleted(new_bytes_read, serial::RECEIVE_ERROR_NONE);
|
| + }
|
| +
|
| + if (break_detected) {
|
| + ReadCompleted(0, serial::RECEIVE_ERROR_BREAK);
|
| + }
|
| +
|
| + if (parity_error_detected) {
|
| + ReadCompleted(0, serial::RECEIVE_ERROR_PARITY_ERROR);
|
| + }
|
| }
|
| } else {
|
| // Stop watching the fd if we get notifications with no pending
|
| @@ -454,6 +484,116 @@ bool SerialIoHandlerPosix::ClearBreak() {
|
| return true;
|
| }
|
|
|
| +// break sequence:
|
| +// '\377' '\0' '\0'
|
| +// BYTEREAD_ALL_ONE BYTEREAD_ALL_ZERO break detected
|
| +//
|
| +// parity error sequence:
|
| +// '\377' '\0' character with parity error
|
| +// BYTEREAD_ALL_ONE BYTEREAD_ALL_ZERO parity error detected
|
| +//
|
| +// break/parity error sequences are removed from the byte stream
|
| +// '\377' '\377' sequence is replaced with '\377'
|
| +int SerialIoHandlerPosix::CheckReceiveError(char* buffer,
|
| + int buffer_len,
|
| + int bytes_read,
|
| + bool& break_detected,
|
| + bool& parity_error_detected) {
|
| + int new_bytes_read = num_chars_ignored_;
|
| +
|
| + for (int i = 0; i < bytes_read; ++i) {
|
| + char ch = buffer[i];
|
| + if (new_bytes_read == 0) {
|
| + chars_ignored_[0] = ch;
|
| + } else if (new_bytes_read == 1) {
|
| + chars_ignored_[1] = ch;
|
| + } else {
|
| + buffer[new_bytes_read - 2] = ch;
|
| + }
|
| + ++new_bytes_read;
|
| + switch (byte_read_state_) {
|
| + case BYTEREAD_REGULAR:
|
| + if (ch == '\377') {
|
| + byte_read_state_ = BYTEREAD_ALL_ONE;
|
| + }
|
| + break;
|
| + case BYTEREAD_ALL_ONE:
|
| + if (ch == '\0') {
|
| + byte_read_state_ = BYTEREAD_ALL_ZERO;
|
| + } else {
|
| + if (ch == '\377') {
|
| + // receive two bytes '\377' '\377', since ISTRIP is not set and
|
| + // PARMRK is set, a valid byte '\377' is passed to the program as
|
| + // two bytes, '\377' '\377'. Replace these two bytes with one byte
|
| + // of '\377', and set byte_read_state_ back to BYTEREAD_REGULAR.
|
| + --new_bytes_read;
|
| + }
|
| + byte_read_state_ = BYTEREAD_REGULAR;
|
| + }
|
| + break;
|
| + case BYTEREAD_ALL_ZERO:
|
| + if (ch == '\0') {
|
| + break_detected = true;
|
| + new_bytes_read -= 3;
|
| + byte_read_state_ = BYTEREAD_REGULAR;
|
| + } else {
|
| + if (parity_check_enabled_) {
|
| + parity_error_detected = true;
|
| + new_bytes_read -= 3;
|
| + byte_read_state_ = BYTEREAD_REGULAR;
|
| + } else if (ch == '\377') {
|
| + byte_read_state_ = BYTEREAD_ALL_ONE;
|
| + } else {
|
| + byte_read_state_ = BYTEREAD_REGULAR;
|
| + }
|
| + }
|
| + break;
|
| + }
|
| + }
|
| + // Now number of new_bytes_read bytes are read (including the previously
|
| + // ignored characters that were stored at chars_ignored_[]) and are stored at:
|
| + // chars_ignored_[0], chars_ignored_[1], buffer[...].
|
| +
|
| + // Ignore some characters that are potentially part of the break/parity error
|
| + // sequence or buffer is not large enough to store all the bytes.
|
| + // tmp[] stores the characters that need to be ignored for this read.
|
| + char tmp[2];
|
| + num_chars_ignored_ = 0;
|
| + if (byte_read_state_ == BYTEREAD_ALL_ZERO ||
|
| + new_bytes_read - buffer_len == 2) {
|
| + // need to ignore the last two characters
|
| + if (new_bytes_read == 2) {
|
| + memcpy(tmp, chars_ignored_, new_bytes_read);
|
| + } else {
|
| + if (new_bytes_read == 3) {
|
| + tmp[0] = chars_ignored_[1];
|
| + } else {
|
| + tmp[0] = buffer[new_bytes_read - 4];
|
| + }
|
| + tmp[1] = buffer[new_bytes_read - 3];
|
| + }
|
| + num_chars_ignored_ = 2;
|
| + } else if (byte_read_state_ == BYTEREAD_ALL_ONE ||
|
| + new_bytes_read - buffer_len == 1) {
|
| + // need to ignore the last character
|
| + if (new_bytes_read <= 2) {
|
| + tmp[0] = chars_ignored_[new_bytes_read - 1];
|
| + } else {
|
| + tmp[0] = buffer[new_bytes_read - 3];
|
| + }
|
| + num_chars_ignored_ = 1;
|
| + }
|
| +
|
| + new_bytes_read -= num_chars_ignored_;
|
| + if (new_bytes_read > 2) {
|
| + // right shift two bytes to store bytes from chars_ignored_[]
|
| + memmove(buffer + 2, buffer, new_bytes_read - 2);
|
| + }
|
| + memcpy(buffer, chars_ignored_, std::min(new_bytes_read, 2));
|
| + memcpy(chars_ignored_, tmp, num_chars_ignored_);
|
| + return new_bytes_read;
|
| +}
|
| +
|
| std::string SerialIoHandler::MaybeFixUpPortName(const std::string& port_name) {
|
| return port_name;
|
| }
|
|
|