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

Side by Side 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, 4 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 unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "device/serial/serial_io_handler_posix.h" 5 #include "device/serial/serial_io_handler_posix.h"
6 6
7 #include <sys/ioctl.h> 7 #include <sys/ioctl.h>
8 #include <termios.h> 8 #include <termios.h>
9 9
10 #include "base/posix/eintr_wrapper.h" 10 #include "base/posix/eintr_wrapper.h"
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after
179 179
180 bool SerialIoHandlerPosix::ConfigurePortImpl() { 180 bool SerialIoHandlerPosix::ConfigurePortImpl() {
181 struct termios config; 181 struct termios config;
182 if (tcgetattr(file().GetPlatformFile(), &config) != 0) { 182 if (tcgetattr(file().GetPlatformFile(), &config) != 0) {
183 VPLOG(1) << "Failed to get port attributes"; 183 VPLOG(1) << "Failed to get port attributes";
184 return false; 184 return false;
185 } 185 }
186 186
187 // Set flags for 'raw' operation 187 // Set flags for 'raw' operation
188 config.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHONL | ISIG); 188 config.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHONL | ISIG);
189 config.c_iflag &= 189 config.c_iflag &= ~(IGNBRK | BRKINT | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
190 ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); 190 config.c_iflag |= PARMRK;
191 config.c_oflag &= ~OPOST; 191 config.c_oflag &= ~OPOST;
192 192
193 // CLOCAL causes the system to disregard the DCD signal state. 193 // CLOCAL causes the system to disregard the DCD signal state.
194 // CREAD enables reading from the port. 194 // CREAD enables reading from the port.
195 config.c_cflag |= (CLOCAL | CREAD); 195 config.c_cflag |= (CLOCAL | CREAD);
196 196
197 DCHECK(options().bitrate); 197 DCHECK(options().bitrate);
198 speed_t bitrate_opt = B0; 198 speed_t bitrate_opt = B0;
199 if (BitrateToSpeedConstant(options().bitrate, &bitrate_opt)) { 199 if (BitrateToSpeedConstant(options().bitrate, &bitrate_opt)) {
200 cfsetispeed(&config, bitrate_opt); 200 cfsetispeed(&config, bitrate_opt);
(...skipping 26 matching lines...) Expand all
227 break; 227 break;
228 case serial::PARITY_BIT_ODD: 228 case serial::PARITY_BIT_ODD:
229 config.c_cflag |= (PARODD | PARENB); 229 config.c_cflag |= (PARODD | PARENB);
230 break; 230 break;
231 case serial::PARITY_BIT_NO: 231 case serial::PARITY_BIT_NO:
232 default: 232 default:
233 config.c_cflag &= ~(PARODD | PARENB); 233 config.c_cflag &= ~(PARODD | PARENB);
234 break; 234 break;
235 } 235 }
236 236
237 error_detect_state_ = ErrorDetectState::NO_ERROR;
238 num_chars_stashed_ = 0;
239
240 if (config.c_cflag & PARENB) {
241 config.c_iflag &= ~IGNPAR;
242 config.c_iflag |= INPCK;
243 parity_check_enabled_ = true;
244 } else {
245 config.c_iflag |= IGNPAR;
246 config.c_iflag &= ~INPCK;
247 parity_check_enabled_ = false;
248 }
249
237 DCHECK(options().stop_bits != serial::STOP_BITS_NONE); 250 DCHECK(options().stop_bits != serial::STOP_BITS_NONE);
238 switch (options().stop_bits) { 251 switch (options().stop_bits) {
239 case serial::STOP_BITS_TWO: 252 case serial::STOP_BITS_TWO:
240 config.c_cflag |= CSTOPB; 253 config.c_cflag |= CSTOPB;
241 break; 254 break;
242 case serial::STOP_BITS_ONE: 255 case serial::STOP_BITS_ONE:
243 default: 256 default:
244 config.c_cflag &= ~CSTOPB; 257 config.c_cflag &= ~CSTOPB;
245 break; 258 break;
246 } 259 }
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
280 pending_read_buffer_len())); 293 pending_read_buffer_len()));
281 if (bytes_read < 0) { 294 if (bytes_read < 0) {
282 if (errno == ENXIO) { 295 if (errno == ENXIO) {
283 ReadCompleted(0, serial::RECEIVE_ERROR_DEVICE_LOST); 296 ReadCompleted(0, serial::RECEIVE_ERROR_DEVICE_LOST);
284 } else { 297 } else {
285 ReadCompleted(0, serial::RECEIVE_ERROR_SYSTEM_ERROR); 298 ReadCompleted(0, serial::RECEIVE_ERROR_SYSTEM_ERROR);
286 } 299 }
287 } else if (bytes_read == 0) { 300 } else if (bytes_read == 0) {
288 ReadCompleted(0, serial::RECEIVE_ERROR_DEVICE_LOST); 301 ReadCompleted(0, serial::RECEIVE_ERROR_DEVICE_LOST);
289 } else { 302 } else {
290 ReadCompleted(bytes_read, serial::RECEIVE_ERROR_NONE); 303 bool break_detected = false;
304 bool parity_error_detected = false;
305 int new_bytes_read =
306 CheckReceiveError(pending_read_buffer(), pending_read_buffer_len(),
307 bytes_read, break_detected, parity_error_detected);
308
309 if (break_detected) {
310 ReadCompleted(new_bytes_read, serial::RECEIVE_ERROR_BREAK);
311 } else if (parity_error_detected) {
312 ReadCompleted(new_bytes_read, serial::RECEIVE_ERROR_PARITY_ERROR);
313 } else {
314 ReadCompleted(new_bytes_read, serial::RECEIVE_ERROR_NONE);
315 }
291 } 316 }
292 } else { 317 } else {
293 // Stop watching the fd if we get notifications with no pending 318 // Stop watching the fd if we get notifications with no pending
294 // reads or writes to avoid starving the message loop. 319 // reads or writes to avoid starving the message loop.
295 is_watching_reads_ = false; 320 is_watching_reads_ = false;
296 file_read_watcher_.StopWatchingFileDescriptor(); 321 file_read_watcher_.StopWatchingFileDescriptor();
297 } 322 }
298 } 323 }
299 324
300 void SerialIoHandlerPosix::OnFileCanWriteWithoutBlocking(int fd) { 325 void SerialIoHandlerPosix::OnFileCanWriteWithoutBlocking(int fd) {
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
447 } 472 }
448 473
449 bool SerialIoHandlerPosix::ClearBreak() { 474 bool SerialIoHandlerPosix::ClearBreak() {
450 if (ioctl(file().GetPlatformFile(), TIOCCBRK, 0) != 0) { 475 if (ioctl(file().GetPlatformFile(), TIOCCBRK, 0) != 0) {
451 VPLOG(1) << "Failed to clear break"; 476 VPLOG(1) << "Failed to clear break";
452 return false; 477 return false;
453 } 478 }
454 return true; 479 return true;
455 } 480 }
456 481
482 // break sequence:
483 // '\377' --> ErrorDetectState::MARK_377_SEEN
484 // '\0' --> ErrorDetectState::MARK_0_SEEN
485 // '\0' --> break detected
486 //
487 // parity error sequence:
488 // '\377' --> ErrorDetectState::MARK_377_SEEN
489 // '\0' --> ErrorDetectState::MARK_0_SEEN
490 // character with parity error --> parity error detected
491 //
492 // break/parity error sequences are removed from the byte stream
493 // '\377' '\377' sequence is replaced with '\377'
494 int SerialIoHandlerPosix::CheckReceiveError(char* buffer,
495 int buffer_len,
496 int bytes_read,
497 bool& break_detected,
498 bool& parity_error_detected) {
499 int new_bytes_read = num_chars_stashed_;
500 DCHECK_LE(new_bytes_read, 2);
501
502 for (int i = 0; i < bytes_read; ++i) {
503 char ch = buffer[i];
504 if (new_bytes_read == 0) {
505 chars_stashed_[0] = ch;
506 } else if (new_bytes_read == 1) {
507 chars_stashed_[1] = ch;
508 } else {
509 buffer[new_bytes_read - 2] = ch;
510 }
511 ++new_bytes_read;
512 switch (error_detect_state_) {
513 case ErrorDetectState::NO_ERROR:
514 if (ch == '\377') {
515 error_detect_state_ = ErrorDetectState::MARK_377_SEEN;
516 }
517 break;
518 case ErrorDetectState::MARK_377_SEEN:
519 DCHECK_GE(new_bytes_read, 2);
520 if (ch == '\0') {
521 error_detect_state_ = ErrorDetectState::MARK_0_SEEN;
522 } else {
523 if (ch == '\377') {
524 // receive two bytes '\377' '\377', since ISTRIP is not set and
525 // PARMRK is set, a valid byte '\377' is passed to the program as
526 // two bytes, '\377' '\377'. Replace these two bytes with one byte
527 // of '\377', and set error_detect_state_ back to
528 // ErrorDetectState::NO_ERROR.
529 --new_bytes_read;
530 }
531 error_detect_state_ = ErrorDetectState::NO_ERROR;
532 }
533 break;
534 case ErrorDetectState::MARK_0_SEEN:
535 DCHECK_GE(new_bytes_read, 3);
536 if (ch == '\0') {
537 break_detected = true;
538 new_bytes_read -= 3;
539 error_detect_state_ = ErrorDetectState::NO_ERROR;
540 } else {
541 if (parity_check_enabled_) {
542 parity_error_detected = true;
543 new_bytes_read -= 3;
544 error_detect_state_ = ErrorDetectState::NO_ERROR;
545 } else if (ch == '\377') {
546 error_detect_state_ = ErrorDetectState::MARK_377_SEEN;
547 } else {
548 error_detect_state_ = ErrorDetectState::NO_ERROR;
549 }
550 }
551 break;
552 }
553 }
554 // Now new_bytes_read bytes should be returned to the caller (including the
555 // previously stashed characters that were stored at chars_stashed_[]) and are
556 // now stored at: chars_stashed_[0], chars_stashed_[1], buffer[...].
557
558 // Stash up to 2 characters that are potentially part of a break/parity error
559 // sequence. The buffer may also not be large enough to store all the bytes.
560 // tmp[] stores the characters that need to be stashed for this read.
561 char tmp[2];
562 num_chars_stashed_ = 0;
563 if (error_detect_state_ == ErrorDetectState::MARK_0_SEEN ||
564 new_bytes_read - buffer_len == 2) {
565 // need to stash the last two characters
566 if (new_bytes_read == 2) {
567 memcpy(tmp, chars_stashed_, new_bytes_read);
568 } else {
569 if (new_bytes_read == 3) {
570 tmp[0] = chars_stashed_[1];
571 } else {
572 tmp[0] = buffer[new_bytes_read - 4];
573 }
574 tmp[1] = buffer[new_bytes_read - 3];
575 }
576 num_chars_stashed_ = 2;
577 } else if (error_detect_state_ == ErrorDetectState::MARK_377_SEEN ||
578 new_bytes_read - buffer_len == 1) {
579 // need to stash the last character
580 if (new_bytes_read <= 2) {
581 tmp[0] = chars_stashed_[new_bytes_read - 1];
582 } else {
583 tmp[0] = buffer[new_bytes_read - 3];
584 }
585 num_chars_stashed_ = 1;
586 }
587
588 new_bytes_read -= num_chars_stashed_;
589 if (new_bytes_read > 2) {
590 // right shift two bytes to store bytes from chars_stashed_[]
591 memmove(buffer + 2, buffer, new_bytes_read - 2);
592 }
593 memcpy(buffer, chars_stashed_, std::min(new_bytes_read, 2));
594 memcpy(chars_stashed_, tmp, num_chars_stashed_);
595 return new_bytes_read;
596 }
597
457 std::string SerialIoHandler::MaybeFixUpPortName(const std::string& port_name) { 598 std::string SerialIoHandler::MaybeFixUpPortName(const std::string& port_name) {
458 return port_name; 599 return port_name;
459 } 600 }
460 601
461 } // namespace device 602 } // namespace device
OLDNEW
« 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