OLD | NEW |
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 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
189 QueueReadCompleted(0, read_cancel_reason()); | 189 QueueReadCompleted(0, read_cancel_reason()); |
190 } | 190 } |
191 | 191 |
192 void SerialIoHandlerPosix::CancelWriteImpl() { | 192 void SerialIoHandlerPosix::CancelWriteImpl() { |
193 DCHECK(CalledOnValidThread()); | 193 DCHECK(CalledOnValidThread()); |
194 is_watching_writes_ = false; | 194 is_watching_writes_ = false; |
195 file_write_watcher_.StopWatchingFileDescriptor(); | 195 file_write_watcher_.StopWatchingFileDescriptor(); |
196 QueueWriteCompleted(0, write_cancel_reason()); | 196 QueueWriteCompleted(0, write_cancel_reason()); |
197 } | 197 } |
198 | 198 |
| 199 bool SerialIoHandlerPosix::ConfigurePortImpl() { |
| 200 struct termios config; |
| 201 if (tcgetattr(file().GetPlatformFile(), &config) != 0) { |
| 202 VPLOG(1) << "Failed to get port attributes"; |
| 203 return false; |
| 204 } |
| 205 |
| 206 // Set flags for 'raw' operation |
| 207 config.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHONL | ISIG); |
| 208 config.c_iflag &= |
| 209 ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); |
| 210 config.c_oflag &= ~OPOST; |
| 211 |
| 212 // CLOCAL causes the system to disregard the DCD signal state. |
| 213 // CREAD enables reading from the port. |
| 214 config.c_cflag |= (CLOCAL | CREAD); |
| 215 |
| 216 DCHECK(options().bitrate); |
| 217 speed_t bitrate_opt = B0; |
| 218 if (BitrateToSpeedConstant(options().bitrate, &bitrate_opt)) { |
| 219 cfsetispeed(&config, bitrate_opt); |
| 220 cfsetospeed(&config, bitrate_opt); |
| 221 } else { |
| 222 // Attempt to set a custom speed. |
| 223 if (!SetCustomBitrate(file().GetPlatformFile(), &config, |
| 224 options().bitrate)) { |
| 225 return false; |
| 226 } |
| 227 } |
| 228 |
| 229 DCHECK(options().data_bits != serial::DATA_BITS_NONE); |
| 230 config.c_cflag &= ~CSIZE; |
| 231 switch (options().data_bits) { |
| 232 case serial::DATA_BITS_SEVEN: |
| 233 config.c_cflag |= CS7; |
| 234 break; |
| 235 case serial::DATA_BITS_EIGHT: |
| 236 default: |
| 237 config.c_cflag |= CS8; |
| 238 break; |
| 239 } |
| 240 |
| 241 DCHECK(options().parity_bit != serial::PARITY_BIT_NONE); |
| 242 switch (options().parity_bit) { |
| 243 case serial::PARITY_BIT_EVEN: |
| 244 config.c_cflag |= PARENB; |
| 245 config.c_cflag &= ~PARODD; |
| 246 break; |
| 247 case serial::PARITY_BIT_ODD: |
| 248 config.c_cflag |= (PARODD | PARENB); |
| 249 break; |
| 250 case serial::PARITY_BIT_NO: |
| 251 default: |
| 252 config.c_cflag &= ~(PARODD | PARENB); |
| 253 break; |
| 254 } |
| 255 |
| 256 DCHECK(options().stop_bits != serial::STOP_BITS_NONE); |
| 257 switch (options().stop_bits) { |
| 258 case serial::STOP_BITS_TWO: |
| 259 config.c_cflag |= CSTOPB; |
| 260 break; |
| 261 case serial::STOP_BITS_ONE: |
| 262 default: |
| 263 config.c_cflag &= ~CSTOPB; |
| 264 break; |
| 265 } |
| 266 |
| 267 DCHECK(options().has_cts_flow_control); |
| 268 if (options().cts_flow_control) { |
| 269 config.c_cflag |= CRTSCTS; |
| 270 } else { |
| 271 config.c_cflag &= ~CRTSCTS; |
| 272 } |
| 273 |
| 274 if (tcsetattr(file().GetPlatformFile(), TCSANOW, &config) != 0) { |
| 275 VPLOG(1) << "Failed to set port attributes"; |
| 276 return false; |
| 277 } |
| 278 return true; |
| 279 } |
| 280 |
199 SerialIoHandlerPosix::SerialIoHandlerPosix( | 281 SerialIoHandlerPosix::SerialIoHandlerPosix( |
200 scoped_refptr<base::MessageLoopProxy> file_thread_message_loop, | 282 scoped_refptr<base::MessageLoopProxy> file_thread_message_loop, |
201 scoped_refptr<base::MessageLoopProxy> ui_thread_message_loop) | 283 scoped_refptr<base::MessageLoopProxy> ui_thread_message_loop) |
202 : SerialIoHandler(file_thread_message_loop, ui_thread_message_loop), | 284 : SerialIoHandler(file_thread_message_loop, ui_thread_message_loop), |
203 is_watching_reads_(false), | 285 is_watching_reads_(false), |
204 is_watching_writes_(false) { | 286 is_watching_writes_(false) { |
205 } | 287 } |
206 | 288 |
207 SerialIoHandlerPosix::~SerialIoHandlerPosix() { | 289 SerialIoHandlerPosix::~SerialIoHandlerPosix() { |
208 } | 290 } |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
275 is_watching_writes_ = | 357 is_watching_writes_ = |
276 base::MessageLoopForIO::current()->WatchFileDescriptor( | 358 base::MessageLoopForIO::current()->WatchFileDescriptor( |
277 file().GetPlatformFile(), | 359 file().GetPlatformFile(), |
278 true, | 360 true, |
279 base::MessageLoopForIO::WATCH_WRITE, | 361 base::MessageLoopForIO::WATCH_WRITE, |
280 &file_write_watcher_, | 362 &file_write_watcher_, |
281 this); | 363 this); |
282 } | 364 } |
283 } | 365 } |
284 | 366 |
285 bool SerialIoHandlerPosix::ConfigurePort( | 367 bool SerialIoHandlerPosix::Flush() const { |
286 const serial::ConnectionOptions& options) { | 368 if (tcflush(file().GetPlatformFile(), TCIOFLUSH) != 0) { |
287 struct termios config; | 369 VPLOG(1) << "Failed to flush port"; |
288 tcgetattr(file().GetPlatformFile(), &config); | 370 return false; |
289 if (options.bitrate) { | |
290 speed_t bitrate_opt = B0; | |
291 if (BitrateToSpeedConstant(options.bitrate, &bitrate_opt)) { | |
292 cfsetispeed(&config, bitrate_opt); | |
293 cfsetospeed(&config, bitrate_opt); | |
294 } else { | |
295 // Attempt to set a custom speed. | |
296 if (!SetCustomBitrate( | |
297 file().GetPlatformFile(), &config, options.bitrate)) { | |
298 return false; | |
299 } | |
300 } | |
301 } | 371 } |
302 if (options.data_bits != serial::DATA_BITS_NONE) { | 372 return true; |
303 config.c_cflag &= ~CSIZE; | |
304 switch (options.data_bits) { | |
305 case serial::DATA_BITS_SEVEN: | |
306 config.c_cflag |= CS7; | |
307 break; | |
308 case serial::DATA_BITS_EIGHT: | |
309 default: | |
310 config.c_cflag |= CS8; | |
311 break; | |
312 } | |
313 } | |
314 if (options.parity_bit != serial::PARITY_BIT_NONE) { | |
315 switch (options.parity_bit) { | |
316 case serial::PARITY_BIT_EVEN: | |
317 config.c_cflag |= PARENB; | |
318 config.c_cflag &= ~PARODD; | |
319 break; | |
320 case serial::PARITY_BIT_ODD: | |
321 config.c_cflag |= (PARODD | PARENB); | |
322 break; | |
323 case serial::PARITY_BIT_NO: | |
324 default: | |
325 config.c_cflag &= ~(PARODD | PARENB); | |
326 break; | |
327 } | |
328 } | |
329 if (options.stop_bits != serial::STOP_BITS_NONE) { | |
330 switch (options.stop_bits) { | |
331 case serial::STOP_BITS_TWO: | |
332 config.c_cflag |= CSTOPB; | |
333 break; | |
334 case serial::STOP_BITS_ONE: | |
335 default: | |
336 config.c_cflag &= ~CSTOPB; | |
337 break; | |
338 } | |
339 } | |
340 if (options.has_cts_flow_control) { | |
341 if (options.cts_flow_control) { | |
342 config.c_cflag |= CRTSCTS; | |
343 } else { | |
344 config.c_cflag &= ~CRTSCTS; | |
345 } | |
346 } | |
347 return tcsetattr(file().GetPlatformFile(), TCSANOW, &config) == 0; | |
348 } | |
349 | |
350 bool SerialIoHandlerPosix::PostOpen() { | |
351 struct termios config; | |
352 tcgetattr(file().GetPlatformFile(), &config); | |
353 | |
354 // Set flags for 'raw' operation | |
355 config.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHONL | ISIG); | |
356 config.c_iflag &= | |
357 ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); | |
358 config.c_oflag &= ~OPOST; | |
359 | |
360 // CLOCAL causes the system to disregard the DCD signal state. | |
361 // CREAD enables reading from the port. | |
362 config.c_cflag |= (CLOCAL | CREAD); | |
363 | |
364 return tcsetattr(file().GetPlatformFile(), TCSANOW, &config) == 0; | |
365 } | |
366 | |
367 bool SerialIoHandlerPosix::Flush() const { | |
368 return tcflush(file().GetPlatformFile(), TCIOFLUSH) == 0; | |
369 } | 373 } |
370 | 374 |
371 serial::DeviceControlSignalsPtr SerialIoHandlerPosix::GetControlSignals() | 375 serial::DeviceControlSignalsPtr SerialIoHandlerPosix::GetControlSignals() |
372 const { | 376 const { |
373 int status; | 377 int status; |
374 if (ioctl(file().GetPlatformFile(), TIOCMGET, &status) == -1) { | 378 if (ioctl(file().GetPlatformFile(), TIOCMGET, &status) == -1) { |
| 379 VPLOG(1) << "Failed to get port control signals"; |
375 return serial::DeviceControlSignalsPtr(); | 380 return serial::DeviceControlSignalsPtr(); |
376 } | 381 } |
377 | 382 |
378 serial::DeviceControlSignalsPtr signals(serial::DeviceControlSignals::New()); | 383 serial::DeviceControlSignalsPtr signals(serial::DeviceControlSignals::New()); |
379 signals->dcd = (status & TIOCM_CAR) != 0; | 384 signals->dcd = (status & TIOCM_CAR) != 0; |
380 signals->cts = (status & TIOCM_CTS) != 0; | 385 signals->cts = (status & TIOCM_CTS) != 0; |
381 signals->dsr = (status & TIOCM_DSR) != 0; | 386 signals->dsr = (status & TIOCM_DSR) != 0; |
382 signals->ri = (status & TIOCM_RI) != 0; | 387 signals->ri = (status & TIOCM_RI) != 0; |
383 return signals.Pass(); | 388 return signals.Pass(); |
384 } | 389 } |
385 | 390 |
386 bool SerialIoHandlerPosix::SetControlSignals( | 391 bool SerialIoHandlerPosix::SetControlSignals( |
387 const serial::HostControlSignals& signals) { | 392 const serial::HostControlSignals& signals) { |
388 int status; | 393 int status; |
389 | 394 |
390 if (ioctl(file().GetPlatformFile(), TIOCMGET, &status) == -1) { | 395 if (ioctl(file().GetPlatformFile(), TIOCMGET, &status) == -1) { |
| 396 VPLOG(1) << "Failed to get port control signals"; |
391 return false; | 397 return false; |
392 } | 398 } |
393 | 399 |
394 if (signals.has_dtr) { | 400 if (signals.has_dtr) { |
395 if (signals.dtr) { | 401 if (signals.dtr) { |
396 status |= TIOCM_DTR; | 402 status |= TIOCM_DTR; |
397 } else { | 403 } else { |
398 status &= ~TIOCM_DTR; | 404 status &= ~TIOCM_DTR; |
399 } | 405 } |
400 } | 406 } |
401 | 407 |
402 if (signals.has_rts) { | 408 if (signals.has_rts) { |
403 if (signals.rts) { | 409 if (signals.rts) { |
404 status |= TIOCM_RTS; | 410 status |= TIOCM_RTS; |
405 } else { | 411 } else { |
406 status &= ~TIOCM_RTS; | 412 status &= ~TIOCM_RTS; |
407 } | 413 } |
408 } | 414 } |
409 | 415 |
410 return ioctl(file().GetPlatformFile(), TIOCMSET, &status) == 0; | 416 if (ioctl(file().GetPlatformFile(), TIOCMSET, &status) != 0) { |
| 417 VPLOG(1) << "Failed to set port control signals"; |
| 418 return false; |
| 419 } |
| 420 return true; |
411 } | 421 } |
412 | 422 |
413 serial::ConnectionInfoPtr SerialIoHandlerPosix::GetPortInfo() const { | 423 serial::ConnectionInfoPtr SerialIoHandlerPosix::GetPortInfo() const { |
414 struct termios config; | 424 struct termios config; |
415 if (tcgetattr(file().GetPlatformFile(), &config) == -1) { | 425 if (tcgetattr(file().GetPlatformFile(), &config) == -1) { |
| 426 VPLOG(1) << "Failed to get port info"; |
416 return serial::ConnectionInfoPtr(); | 427 return serial::ConnectionInfoPtr(); |
417 } | 428 } |
418 serial::ConnectionInfoPtr info(serial::ConnectionInfo::New()); | 429 serial::ConnectionInfoPtr info(serial::ConnectionInfo::New()); |
419 speed_t ispeed = cfgetispeed(&config); | 430 speed_t ispeed = cfgetispeed(&config); |
420 speed_t ospeed = cfgetospeed(&config); | 431 speed_t ospeed = cfgetospeed(&config); |
421 if (ispeed == ospeed) { | 432 if (ispeed == ospeed) { |
422 int bitrate = 0; | 433 int bitrate = 0; |
423 if (SpeedConstantToBitrate(ispeed, &bitrate)) { | 434 if (SpeedConstantToBitrate(ispeed, &bitrate)) { |
424 info->bitrate = bitrate; | 435 info->bitrate = bitrate; |
425 } else if (ispeed > 0) { | 436 } else if (ispeed > 0) { |
(...skipping 17 matching lines...) Expand all Loading... |
443 (config.c_cflag & CSTOPB) ? serial::STOP_BITS_TWO : serial::STOP_BITS_ONE; | 454 (config.c_cflag & CSTOPB) ? serial::STOP_BITS_TWO : serial::STOP_BITS_ONE; |
444 info->cts_flow_control = (config.c_cflag & CRTSCTS) != 0; | 455 info->cts_flow_control = (config.c_cflag & CRTSCTS) != 0; |
445 return info.Pass(); | 456 return info.Pass(); |
446 } | 457 } |
447 | 458 |
448 std::string SerialIoHandler::MaybeFixUpPortName(const std::string& port_name) { | 459 std::string SerialIoHandler::MaybeFixUpPortName(const std::string& port_name) { |
449 return port_name; | 460 return port_name; |
450 } | 461 } |
451 | 462 |
452 } // namespace device | 463 } // namespace device |
OLD | NEW |