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 |