| 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 <windows.h> | 5 #include <windows.h> |
| 6 | 6 |
| 7 #include "device/serial/serial_io_handler_win.h" | 7 #include "device/serial/serial_io_handler_win.h" |
| 8 | 8 |
| 9 namespace device { | 9 namespace device { |
| 10 | 10 |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 160 write_context_->handler = this; | 160 write_context_->handler = this; |
| 161 memset(&write_context_->overlapped, 0, sizeof(write_context_->overlapped)); | 161 memset(&write_context_->overlapped, 0, sizeof(write_context_->overlapped)); |
| 162 | 162 |
| 163 // A ReadIntervalTimeout of MAXDWORD will cause async reads to complete | 163 // A ReadIntervalTimeout of MAXDWORD will cause async reads to complete |
| 164 // immediately with any data that's available, even if there is none. | 164 // immediately with any data that's available, even if there is none. |
| 165 // This is OK because we never issue a read request until WaitCommEvent | 165 // This is OK because we never issue a read request until WaitCommEvent |
| 166 // signals that data is available. | 166 // signals that data is available. |
| 167 COMMTIMEOUTS timeouts = {0}; | 167 COMMTIMEOUTS timeouts = {0}; |
| 168 timeouts.ReadIntervalTimeout = MAXDWORD; | 168 timeouts.ReadIntervalTimeout = MAXDWORD; |
| 169 if (!::SetCommTimeouts(file().GetPlatformFile(), &timeouts)) { | 169 if (!::SetCommTimeouts(file().GetPlatformFile(), &timeouts)) { |
| 170 VPLOG(1) << "Failed to set serial timeouts"; |
| 170 return false; | 171 return false; |
| 171 } | 172 } |
| 172 | 173 |
| 173 DCB config = {0}; | 174 return true; |
| 174 config.DCBlength = sizeof(config); | |
| 175 if (!GetCommState(file().GetPlatformFile(), &config)) { | |
| 176 return false; | |
| 177 } | |
| 178 // Setup some sane default state. | |
| 179 config.fBinary = TRUE; | |
| 180 config.fParity = FALSE; | |
| 181 config.fAbortOnError = TRUE; | |
| 182 config.fOutxCtsFlow = FALSE; | |
| 183 config.fOutxDsrFlow = FALSE; | |
| 184 config.fRtsControl = RTS_CONTROL_ENABLE; | |
| 185 config.fDtrControl = DTR_CONTROL_ENABLE; | |
| 186 config.fDsrSensitivity = FALSE; | |
| 187 config.fOutX = FALSE; | |
| 188 config.fInX = FALSE; | |
| 189 return SetCommState(file().GetPlatformFile(), &config) != 0; | |
| 190 } | 175 } |
| 191 | 176 |
| 192 void SerialIoHandlerWin::ReadImpl() { | 177 void SerialIoHandlerWin::ReadImpl() { |
| 193 DCHECK(CalledOnValidThread()); | 178 DCHECK(CalledOnValidThread()); |
| 194 DCHECK(pending_read_buffer()); | 179 DCHECK(pending_read_buffer()); |
| 195 DCHECK(file().IsValid()); | 180 DCHECK(file().IsValid()); |
| 196 | 181 |
| 197 DWORD errors; | 182 DWORD errors; |
| 198 COMSTAT status; | 183 COMSTAT status; |
| 199 if (!ClearCommError(file().GetPlatformFile(), &errors, &status) || | 184 if (!ClearCommError(file().GetPlatformFile(), &errors, &status) || |
| 200 errors != 0) { | 185 errors != 0) { |
| 201 QueueReadCompleted(0, serial::RECEIVE_ERROR_SYSTEM_ERROR); | 186 QueueReadCompleted(0, serial::RECEIVE_ERROR_SYSTEM_ERROR); |
| 202 return; | 187 return; |
| 203 } | 188 } |
| 204 | 189 |
| 205 SetCommMask(file().GetPlatformFile(), EV_RXCHAR); | 190 if (!SetCommMask(file().GetPlatformFile(), EV_RXCHAR)) { |
| 191 VPLOG(1) << "Failed to set serial event flags"; |
| 192 } |
| 206 | 193 |
| 207 event_mask_ = 0; | 194 event_mask_ = 0; |
| 208 BOOL ok = ::WaitCommEvent( | 195 BOOL ok = ::WaitCommEvent( |
| 209 file().GetPlatformFile(), &event_mask_, &comm_context_->overlapped); | 196 file().GetPlatformFile(), &event_mask_, &comm_context_->overlapped); |
| 210 if (!ok && GetLastError() != ERROR_IO_PENDING) { | 197 if (!ok && GetLastError() != ERROR_IO_PENDING) { |
| 198 VPLOG(1) << "Failed to receive serial event"; |
| 211 QueueReadCompleted(0, serial::RECEIVE_ERROR_SYSTEM_ERROR); | 199 QueueReadCompleted(0, serial::RECEIVE_ERROR_SYSTEM_ERROR); |
| 212 } | 200 } |
| 213 is_comm_pending_ = true; | 201 is_comm_pending_ = true; |
| 214 } | 202 } |
| 215 | 203 |
| 216 void SerialIoHandlerWin::WriteImpl() { | 204 void SerialIoHandlerWin::WriteImpl() { |
| 217 DCHECK(CalledOnValidThread()); | 205 DCHECK(CalledOnValidThread()); |
| 218 DCHECK(pending_write_buffer()); | 206 DCHECK(pending_write_buffer()); |
| 219 DCHECK(file().IsValid()); | 207 DCHECK(file().IsValid()); |
| 220 | 208 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 233 DCHECK(file().IsValid()); | 221 DCHECK(file().IsValid()); |
| 234 ::CancelIo(file().GetPlatformFile()); | 222 ::CancelIo(file().GetPlatformFile()); |
| 235 } | 223 } |
| 236 | 224 |
| 237 void SerialIoHandlerWin::CancelWriteImpl() { | 225 void SerialIoHandlerWin::CancelWriteImpl() { |
| 238 DCHECK(CalledOnValidThread()); | 226 DCHECK(CalledOnValidThread()); |
| 239 DCHECK(file().IsValid()); | 227 DCHECK(file().IsValid()); |
| 240 ::CancelIo(file().GetPlatformFile()); | 228 ::CancelIo(file().GetPlatformFile()); |
| 241 } | 229 } |
| 242 | 230 |
| 231 bool SerialIoHandlerWin::ConfigurePortImpl() { |
| 232 DCB config = {0}; |
| 233 config.DCBlength = sizeof(config); |
| 234 if (!GetCommState(file().GetPlatformFile(), &config)) { |
| 235 VPLOG(1) << "Failed to get serial port info"; |
| 236 return false; |
| 237 } |
| 238 |
| 239 // Set up some sane default options that are not configurable. |
| 240 config.fBinary = TRUE; |
| 241 config.fParity = FALSE; |
| 242 config.fAbortOnError = TRUE; |
| 243 config.fOutxDsrFlow = FALSE; |
| 244 config.fDtrControl = DTR_CONTROL_ENABLE; |
| 245 config.fDsrSensitivity = FALSE; |
| 246 config.fOutX = FALSE; |
| 247 config.fInX = FALSE; |
| 248 |
| 249 DCHECK(options().bitrate); |
| 250 config.BaudRate = BitrateToSpeedConstant(options().bitrate); |
| 251 |
| 252 DCHECK(options().data_bits != serial::DATA_BITS_NONE); |
| 253 config.ByteSize = DataBitsEnumToConstant(options().data_bits); |
| 254 |
| 255 DCHECK(options().parity_bit != serial::PARITY_BIT_NONE); |
| 256 config.Parity = ParityBitEnumToConstant(options().parity_bit); |
| 257 |
| 258 DCHECK(options().stop_bits != serial::STOP_BITS_NONE); |
| 259 config.StopBits = StopBitsEnumToConstant(options().stop_bits); |
| 260 |
| 261 DCHECK(options().has_cts_flow_control); |
| 262 if (options().cts_flow_control) { |
| 263 config.fOutxCtsFlow = TRUE; |
| 264 config.fRtsControl = RTS_CONTROL_HANDSHAKE; |
| 265 } else { |
| 266 config.fOutxCtsFlow = FALSE; |
| 267 config.fRtsControl = RTS_CONTROL_ENABLE; |
| 268 } |
| 269 |
| 270 if (!SetCommState(file().GetPlatformFile(), &config)) { |
| 271 VPLOG(1) << "Failed to set serial port info"; |
| 272 return false; |
| 273 } |
| 274 return true; |
| 275 } |
| 276 |
| 243 SerialIoHandlerWin::SerialIoHandlerWin( | 277 SerialIoHandlerWin::SerialIoHandlerWin( |
| 244 scoped_refptr<base::MessageLoopProxy> file_thread_message_loop, | 278 scoped_refptr<base::MessageLoopProxy> file_thread_message_loop, |
| 245 scoped_refptr<base::MessageLoopProxy> ui_thread_message_loop) | 279 scoped_refptr<base::MessageLoopProxy> ui_thread_message_loop) |
| 246 : SerialIoHandler(file_thread_message_loop, ui_thread_message_loop), | 280 : SerialIoHandler(file_thread_message_loop, ui_thread_message_loop), |
| 247 event_mask_(0), | 281 event_mask_(0), |
| 248 is_comm_pending_(false) { | 282 is_comm_pending_(false) { |
| 249 } | 283 } |
| 250 | 284 |
| 251 SerialIoHandlerWin::~SerialIoHandlerWin() { | 285 SerialIoHandlerWin::~SerialIoHandlerWin() { |
| 252 } | 286 } |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 291 } else { | 325 } else { |
| 292 WriteCompleted(bytes_transferred, | 326 WriteCompleted(bytes_transferred, |
| 293 error == ERROR_SUCCESS ? serial::SEND_ERROR_NONE | 327 error == ERROR_SUCCESS ? serial::SEND_ERROR_NONE |
| 294 : serial::SEND_ERROR_SYSTEM_ERROR); | 328 : serial::SEND_ERROR_SYSTEM_ERROR); |
| 295 } | 329 } |
| 296 } else { | 330 } else { |
| 297 NOTREACHED() << "Invalid IOContext"; | 331 NOTREACHED() << "Invalid IOContext"; |
| 298 } | 332 } |
| 299 } | 333 } |
| 300 | 334 |
| 301 bool SerialIoHandlerWin::ConfigurePort( | 335 bool SerialIoHandlerWin::Flush() const { |
| 302 const serial::ConnectionOptions& options) { | 336 if (!PurgeComm(file().GetPlatformFile(), PURGE_RXCLEAR | PURGE_TXCLEAR)) { |
| 303 DCB config = {0}; | 337 VPLOG(1) << "Failed to flush serial port"; |
| 304 config.DCBlength = sizeof(config); | |
| 305 if (!GetCommState(file().GetPlatformFile(), &config)) { | |
| 306 return false; | 338 return false; |
| 307 } | 339 } |
| 308 if (options.bitrate) | 340 return true; |
| 309 config.BaudRate = BitrateToSpeedConstant(options.bitrate); | |
| 310 if (options.data_bits != serial::DATA_BITS_NONE) | |
| 311 config.ByteSize = DataBitsEnumToConstant(options.data_bits); | |
| 312 if (options.parity_bit != serial::PARITY_BIT_NONE) | |
| 313 config.Parity = ParityBitEnumToConstant(options.parity_bit); | |
| 314 if (options.stop_bits != serial::STOP_BITS_NONE) | |
| 315 config.StopBits = StopBitsEnumToConstant(options.stop_bits); | |
| 316 if (options.has_cts_flow_control) { | |
| 317 if (options.cts_flow_control) { | |
| 318 config.fOutxCtsFlow = TRUE; | |
| 319 config.fRtsControl = RTS_CONTROL_HANDSHAKE; | |
| 320 } else { | |
| 321 config.fOutxCtsFlow = FALSE; | |
| 322 config.fRtsControl = RTS_CONTROL_ENABLE; | |
| 323 } | |
| 324 } | |
| 325 return SetCommState(file().GetPlatformFile(), &config) != 0; | |
| 326 } | |
| 327 | |
| 328 bool SerialIoHandlerWin::Flush() const { | |
| 329 return PurgeComm(file().GetPlatformFile(), PURGE_RXCLEAR | PURGE_TXCLEAR) != | |
| 330 0; | |
| 331 } | 341 } |
| 332 | 342 |
| 333 serial::DeviceControlSignalsPtr SerialIoHandlerWin::GetControlSignals() const { | 343 serial::DeviceControlSignalsPtr SerialIoHandlerWin::GetControlSignals() const { |
| 334 DWORD status; | 344 DWORD status; |
| 335 if (!GetCommModemStatus(file().GetPlatformFile(), &status)) { | 345 if (!GetCommModemStatus(file().GetPlatformFile(), &status)) { |
| 346 VPLOG(1) << "Failed to get port control signals"; |
| 336 return serial::DeviceControlSignalsPtr(); | 347 return serial::DeviceControlSignalsPtr(); |
| 337 } | 348 } |
| 338 | 349 |
| 339 serial::DeviceControlSignalsPtr signals(serial::DeviceControlSignals::New()); | 350 serial::DeviceControlSignalsPtr signals(serial::DeviceControlSignals::New()); |
| 340 signals->dcd = (status & MS_RLSD_ON) != 0; | 351 signals->dcd = (status & MS_RLSD_ON) != 0; |
| 341 signals->cts = (status & MS_CTS_ON) != 0; | 352 signals->cts = (status & MS_CTS_ON) != 0; |
| 342 signals->dsr = (status & MS_DSR_ON) != 0; | 353 signals->dsr = (status & MS_DSR_ON) != 0; |
| 343 signals->ri = (status & MS_RING_ON) != 0; | 354 signals->ri = (status & MS_RING_ON) != 0; |
| 344 return signals.Pass(); | 355 return signals.Pass(); |
| 345 } | 356 } |
| 346 | 357 |
| 347 bool SerialIoHandlerWin::SetControlSignals( | 358 bool SerialIoHandlerWin::SetControlSignals( |
| 348 const serial::HostControlSignals& signals) { | 359 const serial::HostControlSignals& signals) { |
| 349 if (signals.has_dtr) { | 360 if (signals.has_dtr) { |
| 350 if (!EscapeCommFunction(file().GetPlatformFile(), | 361 if (!EscapeCommFunction(file().GetPlatformFile(), |
| 351 signals.dtr ? SETDTR : CLRDTR)) { | 362 signals.dtr ? SETDTR : CLRDTR)) { |
| 363 VPLOG(1) << "Failed to configure DTR signal"; |
| 352 return false; | 364 return false; |
| 353 } | 365 } |
| 354 } | 366 } |
| 355 if (signals.has_rts) { | 367 if (signals.has_rts) { |
| 356 if (!EscapeCommFunction(file().GetPlatformFile(), | 368 if (!EscapeCommFunction(file().GetPlatformFile(), |
| 357 signals.rts ? SETRTS : CLRRTS)) { | 369 signals.rts ? SETRTS : CLRRTS)) { |
| 370 VPLOG(1) << "Failed to configure RTS signal"; |
| 358 return false; | 371 return false; |
| 359 } | 372 } |
| 360 } | 373 } |
| 361 return true; | 374 return true; |
| 362 } | 375 } |
| 363 | 376 |
| 364 serial::ConnectionInfoPtr SerialIoHandlerWin::GetPortInfo() const { | 377 serial::ConnectionInfoPtr SerialIoHandlerWin::GetPortInfo() const { |
| 365 DCB config = {0}; | 378 DCB config = {0}; |
| 366 config.DCBlength = sizeof(config); | 379 config.DCBlength = sizeof(config); |
| 367 if (!GetCommState(file().GetPlatformFile(), &config)) { | 380 if (!GetCommState(file().GetPlatformFile(), &config)) { |
| 381 VPLOG(1) << "Failed to get serial port info"; |
| 368 return serial::ConnectionInfoPtr(); | 382 return serial::ConnectionInfoPtr(); |
| 369 } | 383 } |
| 370 serial::ConnectionInfoPtr info(serial::ConnectionInfo::New()); | 384 serial::ConnectionInfoPtr info(serial::ConnectionInfo::New()); |
| 371 info->bitrate = SpeedConstantToBitrate(config.BaudRate); | 385 info->bitrate = SpeedConstantToBitrate(config.BaudRate); |
| 372 info->data_bits = DataBitsConstantToEnum(config.ByteSize); | 386 info->data_bits = DataBitsConstantToEnum(config.ByteSize); |
| 373 info->parity_bit = ParityBitConstantToEnum(config.Parity); | 387 info->parity_bit = ParityBitConstantToEnum(config.Parity); |
| 374 info->stop_bits = StopBitsConstantToEnum(config.StopBits); | 388 info->stop_bits = StopBitsConstantToEnum(config.StopBits); |
| 375 info->cts_flow_control = config.fOutxCtsFlow != 0; | 389 info->cts_flow_control = config.fOutxCtsFlow != 0; |
| 376 return info.Pass(); | 390 return info.Pass(); |
| 377 } | 391 } |
| 378 | 392 |
| 379 std::string SerialIoHandler::MaybeFixUpPortName(const std::string& port_name) { | 393 std::string SerialIoHandler::MaybeFixUpPortName(const std::string& port_name) { |
| 380 // For COM numbers less than 9, CreateFile is called with a string such as | 394 // For COM numbers less than 9, CreateFile is called with a string such as |
| 381 // "COM1". For numbers greater than 9, a prefix of "\\\\.\\" must be added. | 395 // "COM1". For numbers greater than 9, a prefix of "\\\\.\\" must be added. |
| 382 if (port_name.length() > std::string("COM9").length()) | 396 if (port_name.length() > std::string("COM9").length()) |
| 383 return std::string("\\\\.\\").append(port_name); | 397 return std::string("\\\\.\\").append(port_name); |
| 384 | 398 |
| 385 return port_name; | 399 return port_name; |
| 386 } | 400 } |
| 387 | 401 |
| 388 } // namespace device | 402 } // namespace device |
| OLD | NEW |