Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(283)

Unified Diff: device/serial/serial_io_handler_posix.cc

Issue 1249933004: Add code to detect new added ReceiveError on Linux (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: updated comments, changed variable name. Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « device/serial/serial_io_handler_posix.h ('k') | device/serial/serial_io_handler_posix_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..6cf28984b6878680fb8ea5458ad6413fa5bdd24e 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_stashed_ = 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,19 @@ 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 (break_detected) {
+ ReadCompleted(new_bytes_read, serial::RECEIVE_ERROR_BREAK);
+ } else if (parity_error_detected) {
+ ReadCompleted(new_bytes_read, serial::RECEIVE_ERROR_PARITY_ERROR);
+ } else {
+ ReadCompleted(new_bytes_read, serial::RECEIVE_ERROR_NONE);
+ }
}
} else {
// Stop watching the fd if we get notifications with no pending
@@ -454,6 +479,122 @@ 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_stashed_;
+ DCHECK_LE(new_bytes_read, 2);
+
+ for (int i = 0; i < bytes_read; ++i) {
+ char ch = buffer[i];
+ if (new_bytes_read == 0) {
+ chars_stashed_[0] = ch;
+ } else if (new_bytes_read == 1) {
+ chars_stashed_[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:
+ DCHECK_GE(new_bytes_read, 2);
+ 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:
+ DCHECK_GE(new_bytes_read, 3);
+ 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 new_bytes_read bytes should be returned to the caller (including the
+ // previously stashed characters that were stored at chars_stashed_[]) and are
+ // now stored at: chars_stashed_[0], chars_stashed_[1], buffer[...].
+
+ // Stash up to 2 characters that are potentially part of a break/parity error
+ // sequence. The buffer may also not be large enough to store all the bytes.
+ // tmp[] stores the characters that need to be stashed for this read.
+ char tmp[2];
+ num_chars_stashed_ = 0;
+ if (error_detect_state_ == ErrorDetectState::MARK_0_SEEN ||
+ new_bytes_read - buffer_len == 2) {
+ // need to stash the last two characters
+ if (new_bytes_read == 2) {
+ memcpy(tmp, chars_stashed_, new_bytes_read);
+ } else {
+ if (new_bytes_read == 3) {
+ tmp[0] = chars_stashed_[1];
+ } else {
+ tmp[0] = buffer[new_bytes_read - 4];
+ }
+ tmp[1] = buffer[new_bytes_read - 3];
+ }
+ num_chars_stashed_ = 2;
+ } else if (error_detect_state_ == ErrorDetectState::MARK_377_SEEN ||
+ new_bytes_read - buffer_len == 1) {
+ // need to stash the last character
+ if (new_bytes_read <= 2) {
+ tmp[0] = chars_stashed_[new_bytes_read - 1];
+ } else {
+ tmp[0] = buffer[new_bytes_read - 3];
+ }
+ num_chars_stashed_ = 1;
+ }
+
+ new_bytes_read -= num_chars_stashed_;
+ if (new_bytes_read > 2) {
+ // right shift two bytes to store bytes from chars_stashed_[]
+ memmove(buffer + 2, buffer, new_bytes_read - 2);
+ }
+ memcpy(buffer, chars_stashed_, std::min(new_bytes_read, 2));
+ memcpy(chars_stashed_, tmp, num_chars_stashed_);
+ return new_bytes_read;
+}
+
std::string SerialIoHandler::MaybeFixUpPortName(const std::string& port_name) {
return port_name;
}
« no previous file with comments | « device/serial/serial_io_handler_posix.h ('k') | device/serial/serial_io_handler_posix_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698