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; |
} |