Chromium Code Reviews| 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..f3fdf7efffc0c51744b9807a17d25ae95d29b1f3 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; |
| } |
| + error_detect_state_ = ErrorDetectState::NO_ERROR; |
| + 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); |
|
Reilly Grant (use Gerrit)
2015/07/30 00:09:12
Sorry, I should have caught this earlier. ReadComp
juncai
2015/07/30 16:04:36
Done.
|
| + } |
| + |
| + 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,119 @@ bool SerialIoHandlerPosix::ClearBreak() { |
| return true; |
| } |
| +// break sequence: |
| +// '\377' --> ErrorDetectState::MARK_377_SEEN |
| +// '\0' --> ErrorDetectState::MARK_0_SEEN |
| +// '\0' --> break detected |
| +// |
| +// parity error sequence: |
| +// '\377' --> ErrorDetectState::MARK_377_SEEN |
| +// '\0' --> ErrorDetectState::MARK_0_SEEN |
| +// character with parity error --> 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 (error_detect_state_) { |
| + case ErrorDetectState::NO_ERROR: |
| + if (ch == '\377') { |
| + error_detect_state_ = ErrorDetectState::MARK_377_SEEN; |
| + } |
| + break; |
| + case ErrorDetectState::MARK_377_SEEN: |
| + if (ch == '\0') { |
| + error_detect_state_ = ErrorDetectState::MARK_0_SEEN; |
| + } 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 error_detect_state_ back to |
| + // ErrorDetectState::NO_ERROR. |
| + --new_bytes_read; |
| + } |
| + error_detect_state_ = ErrorDetectState::NO_ERROR; |
| + } |
| + break; |
| + case ErrorDetectState::MARK_0_SEEN: |
| + if (ch == '\0') { |
| + break_detected = true; |
| + new_bytes_read -= 3; |
| + error_detect_state_ = ErrorDetectState::NO_ERROR; |
| + } else { |
| + if (parity_check_enabled_) { |
| + parity_error_detected = true; |
| + new_bytes_read -= 3; |
| + error_detect_state_ = ErrorDetectState::NO_ERROR; |
| + } else if (ch == '\377') { |
| + error_detect_state_ = ErrorDetectState::MARK_377_SEEN; |
| + } else { |
| + error_detect_state_ = ErrorDetectState::NO_ERROR; |
| + } |
| + } |
| + 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 (error_detect_state_ == ErrorDetectState::MARK_0_SEEN || |
| + 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 (error_detect_state_ == ErrorDetectState::MARK_377_SEEN || |
| + 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; |
| } |