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

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 test code. 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
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;
}

Powered by Google App Engine
This is Rietveld 408576698