VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/win/serialport-win.cpp@ 71028

Last change on this file since 71028 was 71028, checked in by vboxsync, 7 years ago

Runtime/RTSerialPort: Implement synchronous read/write methods for POSIX and Windows, allows the serial transport layer in TestExecService to work

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.4 KB
Line 
1/* $Id: serialport-win.cpp 71028 2018-02-15 15:28:14Z vboxsync $ */
2/** @file
3 * IPRT - Serial Port API, Windows Implementation.
4 */
5
6/*
7 * Copyright (C) 2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/serialport.h>
32#include "internal/iprt.h"
33
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <iprt/cdefs.h>
37#include <iprt/err.h>
38#include <iprt/mem.h>
39#include <iprt/string.h>
40#include <iprt/thread.h>
41#include <iprt/time.h>
42#include "internal/magics.h"
43
44#include <iprt/win/windows.h>
45
46
47/*********************************************************************************************************************************
48* Structures and Typedefs *
49*********************************************************************************************************************************/
50
51/**
52 * Internal serial port state.
53 */
54typedef struct RTSERIALPORTINTERNAL
55{
56 /** Magic value (RTSERIALPORT_MAGIC). */
57 uint32_t u32Magic;
58 /** Flags given while opening the serial port. */
59 uint32_t fOpenFlags;
60 /** The device handle. */
61 HANDLE hDev;
62 /** The overlapped I/O structure. */
63 OVERLAPPED Overlapped;
64 /** The event handle to wait on for the overlapped I/O operations of the device. */
65 HANDLE hEvtDev;
66 /** The event handle to wait on for waking up waiting threads externally. */
67 HANDLE hEvtIntr;
68 /** Events currently waited for. */
69 uint32_t fEvtMask;
70 /** Flag whether a write is currently pending. */
71 bool fWritePending;
72 /** Bounce buffer for writes. */
73 uint8_t *pbBounceBuf;
74 /** Amount of used buffer space. */
75 size_t cbBounceBufUsed;
76 /** Amount of allocated buffer space. */
77 size_t cbBounceBufAlloc;
78 /** The current active port config. */
79 DCB PortCfg;
80} RTSERIALPORTINTERNAL;
81/** Pointer to the internal serial port state. */
82typedef RTSERIALPORTINTERNAL *PRTSERIALPORTINTERNAL;
83
84
85
86/*********************************************************************************************************************************
87* Defined Constants And Macros *
88*********************************************************************************************************************************/
89/** The pipe buffer size we prefer. */
90#define RTSERIALPORT_NT_SIZE _32K
91
92
93
94/*********************************************************************************************************************************
95* Global variables *
96*********************************************************************************************************************************/
97
98
99
100/*********************************************************************************************************************************
101* Internal Functions *
102*********************************************************************************************************************************/
103
104/**
105 * Updatest the current event mask to wait for.
106 *
107 * @returns IPRT status code.
108 * @param pThis The internal serial port instance data.
109 * @param fEvtMask The new event mask to change to.
110 */
111static int rtSerialPortWinUpdateEvtMask(PRTSERIALPORTINTERNAL pThis, uint32_t fEvtMask)
112{
113 DWORD dwEvtMask = 0;
114
115 if (fEvtMask & RTSERIALPORT_EVT_F_DATA_RX)
116 dwEvtMask |= EV_RXCHAR;
117 if (fEvtMask & RTSERIALPORT_EVT_F_DATA_TX)
118 dwEvtMask |= EV_TXEMPTY;
119 if (fEvtMask & RTSERIALPORT_EVT_F_BREAK_DETECTED)
120 dwEvtMask |= EV_BREAK;
121 if (fEvtMask & RTSERIALPORT_EVT_F_STATUS_LINE_CHANGED)
122 dwEvtMask |= EV_CTS | EV_DSR | EV_RING | EV_RLSD;
123
124 int rc = VINF_SUCCESS;
125 if (!SetCommMask(pThis->hDev, dwEvtMask))
126 rc = RTErrConvertFromWin32(GetLastError());
127 else
128 pThis->fEvtMask = fEvtMask;
129
130 return rc;
131}
132
133
134/**
135 * Tries to set the default config on the given serial port.
136 *
137 * @returns IPRT status code.
138 * @param pThis The internal serial port instance data.
139 */
140static int rtSerialPortSetDefaultCfg(PRTSERIALPORTINTERNAL pThis)
141{
142 if (!PurgeComm(pThis->hDev, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR))
143 return RTErrConvertFromWin32(GetLastError());
144
145 pThis->PortCfg.DCBlength = sizeof(pThis->PortCfg);
146 if (!GetCommState(pThis->hDev, &pThis->PortCfg))
147 return RTErrConvertFromWin32(GetLastError());
148
149 pThis->PortCfg.BaudRate = CBR_9600;
150 pThis->PortCfg.fBinary = TRUE;
151 pThis->PortCfg.fParity = TRUE;
152 pThis->PortCfg.fDtrControl = DTR_CONTROL_DISABLE;
153 pThis->PortCfg.ByteSize = 8;
154 pThis->PortCfg.Parity = NOPARITY;
155
156 int rc = VINF_SUCCESS;
157 if (!SetCommState(pThis->hDev, &pThis->PortCfg))
158 rc = RTErrConvertFromWin32(GetLastError());
159
160 return rc;
161}
162
163
164/**
165 * Common worker for handling I/O completion.
166 *
167 * This is used by RTSerialPortClose, RTSerialPortWrite and RTPipeSerialPortNB.
168 *
169 * @returns IPRT status code.
170 * @param pThis The pipe instance handle.
171 */
172static int rtSerialPortWriteCheckCompletion(PRTSERIALPORTINTERNAL pThis)
173{
174 int rc = VINF_SUCCESS;
175 DWORD dwRc = WaitForSingleObject(pThis->Overlapped.hEvent, 0);
176 if (dwRc == WAIT_OBJECT_0)
177 {
178 DWORD cbWritten = 0;
179 if (GetOverlappedResult(pThis->hDev, &pThis->Overlapped, &cbWritten, TRUE))
180 {
181 for (;;)
182 {
183 if (cbWritten >= pThis->cbBounceBufUsed)
184 {
185 pThis->fWritePending = false;
186 rc = VINF_SUCCESS;
187 break;
188 }
189
190 /* resubmit the remainder of the buffer - can this actually happen? */
191 memmove(&pThis->pbBounceBuf[0], &pThis->pbBounceBuf[cbWritten], pThis->cbBounceBufUsed - cbWritten);
192 rc = ResetEvent(pThis->Overlapped.hEvent); Assert(rc == TRUE);
193 if (!WriteFile(pThis->hDev, pThis->pbBounceBuf, (DWORD)pThis->cbBounceBufUsed,
194 &cbWritten, &pThis->Overlapped))
195 {
196 if (GetLastError() == ERROR_IO_PENDING)
197 rc = VINF_TRY_AGAIN;
198 else
199 {
200 pThis->fWritePending = false;
201 rc = RTErrConvertFromWin32(GetLastError());
202 }
203 break;
204 }
205 Assert(cbWritten > 0);
206 }
207 }
208 else
209 {
210 pThis->fWritePending = false;
211 rc = RTErrConvertFromWin32(GetLastError());
212 }
213 }
214 else if (dwRc == WAIT_TIMEOUT)
215 rc = VINF_TRY_AGAIN;
216 else
217 {
218 pThis->fWritePending = false;
219 if (dwRc == WAIT_ABANDONED)
220 rc = VERR_INVALID_HANDLE;
221 else
222 rc = RTErrConvertFromWin32(GetLastError());
223 }
224 return rc;
225}
226
227
228RTDECL(int) RTSerialPortOpen(PRTSERIALPORT phSerialPort, const char *pszPortAddress, uint32_t fFlags)
229{
230 AssertPtrReturn(phSerialPort, VERR_INVALID_POINTER);
231 AssertReturn(VALID_PTR(pszPortAddress) && *pszPortAddress != '\0', VERR_INVALID_PARAMETER);
232 AssertReturn(!(fFlags & ~RTSERIALPORT_OPEN_F_VALID_MASK), VERR_INVALID_PARAMETER);
233 AssertReturn((fFlags & RTSERIALPORT_OPEN_F_READ) || (fFlags & RTSERIALPORT_OPEN_F_WRITE),
234 VERR_INVALID_PARAMETER);
235
236 int rc = VINF_SUCCESS;
237 PRTSERIALPORTINTERNAL pThis = (PRTSERIALPORTINTERNAL)RTMemAllocZ(sizeof(*pThis));
238 if (pThis)
239 {
240 pThis->u32Magic = RTSERIALPORT_MAGIC;
241 pThis->fOpenFlags = fFlags;
242 pThis->fEvtMask = 0;
243 pThis->fWritePending = false;
244 pThis->pbBounceBuf = NULL;
245 pThis->cbBounceBufUsed = 0;
246 pThis->cbBounceBufAlloc = 0;
247 pThis->hEvtDev = CreateEvent(NULL, FALSE, FALSE, NULL);
248 if (pThis->hEvtDev)
249 {
250 pThis->Overlapped.hEvent = pThis->hEvtDev,
251 pThis->hEvtIntr = CreateEvent(NULL, FALSE, FALSE, NULL);
252 if (pThis->hEvtIntr)
253 {
254 DWORD fWinFlags = 0;
255
256 if (fFlags & RTSERIALPORT_OPEN_F_WRITE)
257 fWinFlags |= GENERIC_WRITE;
258 if (fFlags & RTSERIALPORT_OPEN_F_READ)
259 fWinFlags |= GENERIC_READ;
260
261 pThis->hDev = CreateFile(pszPortAddress,
262 fWinFlags,
263 0, /* Must be opened with exclusive access. */
264 NULL, /* No SECURITY_ATTRIBUTES structure. */
265 OPEN_EXISTING, /* Must use OPEN_EXISTING. */
266 FILE_FLAG_OVERLAPPED, /* Overlapped I/O. */
267 NULL);
268 if (pThis->hDev)
269 rc = rtSerialPortSetDefaultCfg(pThis);
270 else
271 rc = RTErrConvertFromWin32(GetLastError());
272
273 CloseHandle(pThis->hEvtDev);
274 }
275 else
276 rc = RTErrConvertFromWin32(GetLastError());
277
278 CloseHandle(pThis->hEvtDev);
279 }
280 else
281 rc = RTErrConvertFromWin32(GetLastError());
282
283 RTMemFree(pThis);
284 }
285 else
286 rc = VERR_NO_MEMORY;
287
288 return rc;
289}
290
291
292RTDECL(int) RTSerialPortClose(RTSERIALPORT hSerialPort)
293{
294 PRTSERIALPORTINTERNAL pThis = hSerialPort;
295 if (pThis == NIL_RTSERIALPORT)
296 return VINF_SUCCESS;
297 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
298 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
299
300 /*
301 * Do the cleanup.
302 */
303 AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, RTSERIALPORT_MAGIC_DEAD, RTSERIALPORT_MAGIC), VERR_INVALID_HANDLE);
304
305 if (pThis->fWritePending)
306 rtSerialPortWriteCheckCompletion(pThis);
307
308 CloseHandle(pThis->hDev);
309 CloseHandle(pThis->hEvtDev);
310 CloseHandle(pThis->hEvtIntr);
311 pThis->hDev = NULL;
312 pThis->hEvtDev = NULL;
313 pThis->hEvtIntr = NULL;
314 RTMemFree(pThis);
315 return VINF_SUCCESS;
316}
317
318
319RTDECL(RTHCINTPTR) RTSerialPortToNative(RTSERIALPORT hSerialPort)
320{
321 PRTSERIALPORTINTERNAL pThis = hSerialPort;
322 AssertPtrReturn(pThis, -1);
323 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, -1);
324
325 return (RTHCINTPTR)pThis->hDev;
326}
327
328
329RTDECL(int) RTSerialPortRead(RTSERIALPORT hSerialPort, void *pvBuf, size_t cbToRead, size_t *pcbRead)
330{
331 PRTSERIALPORTINTERNAL pThis = hSerialPort;
332 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
333 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
334 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
335 AssertReturn(cbToRead > 0, VERR_INVALID_PARAMETER);
336
337 /*
338 * Kick of an overlapped read.
339 */
340 int rc = VINF_SUCCESS;
341 uint8_t *pbBuf = (uint8_t *)pvBuf;
342
343 while ( cbToRead > 0
344 && RT_SUCCESS(rc))
345 {
346 BOOL fSucc = ResetEvent(pThis->Overlapped.hEvent); Assert(fSucc == TRUE); RT_NOREF(fSucc);
347 DWORD cbRead = 0;
348 if (ReadFile(pThis->hDev, pbBuf,
349 cbToRead <= ~(DWORD)0 ? (DWORD)cbToRead : ~(DWORD)0,
350 &cbRead, &pThis->Overlapped))
351 {
352 if (pcbRead)
353 {
354 *pcbRead = cbRead;
355 break;
356 }
357 rc = VINF_SUCCESS;
358 }
359 else if (GetLastError() == ERROR_IO_PENDING)
360 {
361 DWORD dwWait = WaitForSingleObject(pThis->Overlapped.hEvent, INFINITE);
362 if (dwWait == WAIT_OBJECT_0)
363 {
364 if (GetOverlappedResult(pThis->hDev, &pThis->Overlapped, &cbRead, TRUE /*fWait*/))
365 {
366 if (pcbRead)
367 {
368 *pcbRead = cbRead;
369 break;
370 }
371 rc = VINF_SUCCESS;
372 }
373 else
374 rc = RTErrConvertFromWin32(GetLastError());
375 }
376 else
377 {
378 Assert(dwWait == WAIT_FAILED);
379 rc = RTErrConvertFromWin32(GetLastError());
380 }
381 }
382 else
383 rc = RTErrConvertFromWin32(GetLastError());
384
385 if (RT_SUCCESS(rc))
386 {
387 cbToRead -= cbRead;
388 pbBuf += cbRead;
389 }
390 }
391
392 return rc;
393}
394
395
396RTDECL(int) RTSerialPortReadNB(RTSERIALPORT hSerialPort, void *pvBuf, size_t cbToRead, size_t *pcbRead)
397{
398 PRTSERIALPORTINTERNAL pThis = hSerialPort;
399 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
400 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
401 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
402 AssertReturn(cbToRead > 0, VERR_INVALID_PARAMETER);
403 AssertPtrReturn(pcbRead, VERR_INVALID_POINTER);
404
405 *pcbRead = 0;
406
407 /*
408 * Kick of an overlapped read. It should return immediately if
409 * there is bytes in the buffer. If not, we'll cancel it and see
410 * what we get back.
411 */
412 int rc = VINF_SUCCESS;
413 BOOL fSucc = ResetEvent(pThis->Overlapped.hEvent); Assert(fSucc == TRUE); RT_NOREF(fSucc);
414 DWORD cbRead = 0;
415 if ( cbToRead == 0
416 || ReadFile(pThis->hDev, pvBuf,
417 cbToRead <= ~(DWORD)0 ? (DWORD)cbToRead : ~(DWORD)0,
418 &cbRead, &pThis->Overlapped))
419 {
420 *pcbRead = cbRead;
421 rc = VINF_SUCCESS;
422 }
423 else if (GetLastError() == ERROR_IO_PENDING)
424 {
425 if (!CancelIo(pThis->hDev))
426 WaitForSingleObject(pThis->Overlapped.hEvent, INFINITE);
427 if (GetOverlappedResult(pThis->hDev, &pThis->Overlapped, &cbRead, TRUE /*fWait*/))
428 {
429 *pcbRead = cbRead;
430 rc = VINF_SUCCESS;
431 }
432 else if (GetLastError() == ERROR_OPERATION_ABORTED)
433 {
434 *pcbRead = 0;
435 rc = VINF_TRY_AGAIN;
436 }
437 else
438 rc = RTErrConvertFromWin32(GetLastError());
439 }
440 else
441 rc = RTErrConvertFromWin32(GetLastError());
442
443 return rc;
444}
445
446
447RTDECL(int) RTSerialPortWrite(RTSERIALPORT hSerialPort, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
448{
449 PRTSERIALPORTINTERNAL pThis = hSerialPort;
450 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
451 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
452 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
453 AssertReturn(cbToWrite > 0, VERR_INVALID_PARAMETER);
454
455 /* If I/O is pending, check if it has completed. */
456 int rc = VINF_SUCCESS;
457 if (pThis->fWritePending)
458 rc = rtSerialPortWriteCheckCompletion(pThis);
459 if (rc == VINF_SUCCESS)
460 {
461 const uint8_t *pbBuf = (const uint8_t *)pvBuf;
462
463 while ( cbToWrite > 0
464 && RT_SUCCESS(rc))
465 {
466 BOOL fSucc = ResetEvent(pThis->Overlapped.hEvent); Assert(fSucc == TRUE); RT_NOREF(fSucc);
467 DWORD cbWritten = 0;
468 if (WriteFile(pThis->hDev, pbBuf,
469 cbToWrite <= ~(DWORD)0 ? (DWORD)cbToWrite : ~(DWORD)0,
470 &cbWritten, &pThis->Overlapped))
471 {
472 if (pcbWritten)
473 {
474 *pcbWritten = cbWritten;
475 break;
476 }
477 rc = VINF_SUCCESS;
478 }
479 else if (GetLastError() == ERROR_IO_PENDING)
480 {
481 DWORD dwWait = WaitForSingleObject(pThis->Overlapped.hEvent, INFINITE);
482 if (dwWait == WAIT_OBJECT_0)
483 {
484 if (GetOverlappedResult(pThis->hDev, &pThis->Overlapped, &cbWritten, TRUE /*fWait*/))
485 {
486 if (pcbWritten)
487 {
488 *pcbWritten = cbWritten;
489 break;
490 }
491 rc = VINF_SUCCESS;
492 }
493 else
494 rc = RTErrConvertFromWin32(GetLastError());
495 }
496 else
497 {
498 Assert(dwWait == WAIT_FAILED);
499 rc = RTErrConvertFromWin32(GetLastError());
500 }
501 }
502 else
503 rc = RTErrConvertFromWin32(GetLastError());
504
505 if (RT_SUCCESS(rc))
506 {
507 cbToWrite -= cbWritten;
508 pbBuf += cbWritten;
509 }
510 }
511 }
512
513 return rc;
514}
515
516
517RTDECL(int) RTSerialPortWriteNB(RTSERIALPORT hSerialPort, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
518{
519 PRTSERIALPORTINTERNAL pThis = hSerialPort;
520 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
521 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
522 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
523 AssertReturn(cbToWrite > 0, VERR_INVALID_PARAMETER);
524 AssertPtrReturn(pcbWritten, VERR_INVALID_POINTER);
525
526 /* If I/O is pending, check if it has completed. */
527 int rc = VINF_SUCCESS;
528 if (pThis->fWritePending)
529 rc = rtSerialPortWriteCheckCompletion(pThis);
530 if (rc == VINF_SUCCESS)
531 {
532 Assert(!pThis->fWritePending);
533
534 /* Do the bounce buffering. */
535 if ( pThis->cbBounceBufAlloc < cbToWrite
536 && pThis->cbBounceBufAlloc < RTSERIALPORT_NT_SIZE)
537 {
538 if (cbToWrite > RTSERIALPORT_NT_SIZE)
539 cbToWrite = RTSERIALPORT_NT_SIZE;
540 void *pv = RTMemRealloc(pThis->pbBounceBuf, RT_ALIGN_Z(cbToWrite, _1K));
541 if (pv)
542 {
543 pThis->pbBounceBuf = (uint8_t *)pv;
544 pThis->cbBounceBufAlloc = RT_ALIGN_Z(cbToWrite, _1K);
545 }
546 else
547 rc = VERR_NO_MEMORY;
548 }
549 else if (cbToWrite > RTSERIALPORT_NT_SIZE)
550 cbToWrite = RTSERIALPORT_NT_SIZE;
551 if (RT_SUCCESS(rc) && cbToWrite)
552 {
553 memcpy(pThis->pbBounceBuf, pvBuf, cbToWrite);
554 pThis->cbBounceBufUsed = (uint32_t)cbToWrite;
555
556 /* Submit the write. */
557 rc = ResetEvent(pThis->Overlapped.hEvent); Assert(rc == TRUE);
558 DWORD cbWritten = 0;
559 if (WriteFile(pThis->hDev, pThis->pbBounceBuf, (DWORD)pThis->cbBounceBufUsed,
560 &cbWritten, &pThis->Overlapped))
561 {
562 *pcbWritten = RT_MIN(cbWritten, cbToWrite); /* paranoia^3 */
563 rc = VINF_SUCCESS;
564 }
565 else if (GetLastError() == ERROR_IO_PENDING)
566 {
567 *pcbWritten = cbToWrite;
568 pThis->fWritePending = true;
569 rc = VINF_SUCCESS;
570 }
571 else
572 rc = RTErrConvertFromWin32(GetLastError());
573 }
574 else if (RT_SUCCESS(rc))
575 *pcbWritten = 0;
576 }
577 else if (RT_SUCCESS(rc))
578 *pcbWritten = 0;
579
580 return rc;
581}
582
583
584RTDECL(int) RTSerialPortCfgQueryCurrent(RTSERIALPORT hSerialPort, PRTSERIALPORTCFG pCfg)
585{
586 PRTSERIALPORTINTERNAL pThis = hSerialPort;
587 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
588 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
589
590 pCfg->uBaudRate = pThis->PortCfg.BaudRate;
591 switch (pThis->PortCfg.Parity)
592 {
593 case NOPARITY:
594 pCfg->enmParity = RTSERIALPORTPARITY_NONE;
595 break;
596 case EVENPARITY:
597 pCfg->enmParity = RTSERIALPORTPARITY_EVEN;
598 break;
599 case ODDPARITY:
600 pCfg->enmParity = RTSERIALPORTPARITY_ODD;
601 break;
602 case MARKPARITY:
603 pCfg->enmParity = RTSERIALPORTPARITY_MARK;
604 break;
605 case SPACEPARITY:
606 pCfg->enmParity = RTSERIALPORTPARITY_SPACE;
607 break;
608 default:
609 AssertFailed();
610 return VERR_INTERNAL_ERROR;
611 }
612
613 switch (pThis->PortCfg.ByteSize)
614 {
615 case 5:
616 pCfg->enmDataBitCount = RTSERIALPORTDATABITS_5BITS;
617 break;
618 case 6:
619 pCfg->enmDataBitCount = RTSERIALPORTDATABITS_6BITS;
620 break;
621 case 7:
622 pCfg->enmDataBitCount = RTSERIALPORTDATABITS_7BITS;
623 break;
624 case 8:
625 pCfg->enmDataBitCount = RTSERIALPORTDATABITS_8BITS;
626 break;
627 default:
628 AssertFailed();
629 return VERR_INTERNAL_ERROR;
630 }
631
632 switch (pThis->PortCfg.StopBits)
633 {
634 case ONESTOPBIT:
635 pCfg->enmStopBitCount = RTSERIALPORTSTOPBITS_ONE;
636 break;
637 case ONE5STOPBITS:
638 pCfg->enmStopBitCount = RTSERIALPORTSTOPBITS_ONEPOINTFIVE;
639 break;
640 case TWOSTOPBITS:
641 pCfg->enmStopBitCount = RTSERIALPORTSTOPBITS_TWO;
642 break;
643 default:
644 AssertFailed();
645 return VERR_INTERNAL_ERROR;
646 }
647
648 return VINF_SUCCESS;
649}
650
651
652RTDECL(int) RTSerialPortCfgSet(RTSERIALPORT hSerialPort, PCRTSERIALPORTCFG pCfg, PRTERRINFO pErrInfo)
653{
654 PRTSERIALPORTINTERNAL pThis = hSerialPort;
655 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
656 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
657
658 RT_NOREF(pErrInfo);
659
660 DCB DcbNew;
661 memcpy(&DcbNew, &pThis->PortCfg, sizeof(DcbNew));
662 DcbNew.BaudRate = pCfg->uBaudRate;
663
664 switch (pCfg->enmParity)
665 {
666 case RTSERIALPORTPARITY_NONE:
667 DcbNew.Parity = NOPARITY;
668 break;
669 case RTSERIALPORTPARITY_EVEN:
670 DcbNew.Parity = EVENPARITY;
671 break;
672 case RTSERIALPORTPARITY_ODD:
673 DcbNew.Parity = ODDPARITY;
674 break;
675 case RTSERIALPORTPARITY_MARK:
676 DcbNew.Parity = MARKPARITY;
677 break;
678 case RTSERIALPORTPARITY_SPACE:
679 DcbNew.Parity = SPACEPARITY;
680 break;
681 default:
682 AssertFailedReturn(VERR_INVALID_PARAMETER);
683 }
684
685 switch (pCfg->enmDataBitCount)
686 {
687 case RTSERIALPORTDATABITS_5BITS:
688 DcbNew.ByteSize = 5;
689 break;
690 case RTSERIALPORTDATABITS_6BITS:
691 DcbNew.ByteSize = 6;
692 break;
693 case RTSERIALPORTDATABITS_7BITS:
694 DcbNew.ByteSize = 7;
695 break;
696 case RTSERIALPORTDATABITS_8BITS:
697 DcbNew.ByteSize = 8;
698 break;
699 default:
700 AssertFailedReturn(VERR_INVALID_PARAMETER);
701 }
702
703 switch (pCfg->enmStopBitCount)
704 {
705 case RTSERIALPORTSTOPBITS_ONE:
706 DcbNew.StopBits = ONESTOPBIT;
707 break;
708 case RTSERIALPORTSTOPBITS_ONEPOINTFIVE:
709 AssertReturn(pCfg->enmDataBitCount == RTSERIALPORTDATABITS_5BITS, VERR_INVALID_PARAMETER);
710 DcbNew.StopBits = ONE5STOPBITS;
711 break;
712 case RTSERIALPORTSTOPBITS_TWO:
713 AssertReturn(pCfg->enmDataBitCount != RTSERIALPORTDATABITS_5BITS, VERR_INVALID_PARAMETER);
714 DcbNew.StopBits = TWOSTOPBITS;
715 break;
716 default:
717 AssertFailedReturn(VERR_INVALID_PARAMETER);
718 }
719
720 int rc = VINF_SUCCESS;
721 if (!SetCommState(pThis->hDev, &DcbNew))
722 rc = RTErrConvertFromWin32(GetLastError());
723 else
724 memcpy(&pThis->PortCfg, &DcbNew, sizeof(DcbNew));
725
726 return rc;
727}
728
729
730RTDECL(int) RTSerialPortEvtPoll(RTSERIALPORT hSerialPort, uint32_t fEvtMask, uint32_t *pfEvtsRecv,
731 RTMSINTERVAL msTimeout)
732{
733 PRTSERIALPORTINTERNAL pThis = hSerialPort;
734 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
735 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
736 AssertReturn(!(fEvtMask & ~RTSERIALPORT_EVT_F_VALID_MASK), VERR_INVALID_PARAMETER);
737 AssertPtrReturn(pfEvtsRecv, VERR_INVALID_POINTER);
738
739 *pfEvtsRecv = 0;
740
741 int rc = VINF_SUCCESS;
742 if (fEvtMask != pThis->fEvtMask)
743 rc = rtSerialPortWinUpdateEvtMask(pThis, fEvtMask);
744
745 if (RT_SUCCESS(rc))
746 {
747 DWORD dwEventMask = 0;
748 HANDLE ahWait[2];
749 ahWait[0] = pThis->hEvtDev;
750 ahWait[1] = pThis->hEvtIntr;
751
752 RT_ZERO(pThis->Overlapped);
753 pThis->Overlapped.hEvent = pThis->hEvtDev;
754
755 if (!WaitCommEvent(pThis->hDev, &dwEventMask, &pThis->Overlapped))
756 {
757 DWORD dwRet = GetLastError();
758 if (dwRet == ERROR_IO_PENDING)
759 {
760 dwRet = WaitForMultipleObjects(2, ahWait, FALSE, msTimeout == RT_INDEFINITE_WAIT ? INFINITE : msTimeout);
761 if (dwRet == WAIT_TIMEOUT)
762 rc = VERR_TIMEOUT;
763 else if (dwRet == WAIT_FAILED)
764 rc = RTErrConvertFromWin32(GetLastError());
765 else if (dwRet != WAIT_OBJECT_0)
766 rc = VERR_INTERRUPTED;
767 }
768 else
769 rc = RTErrConvertFromWin32(dwRet);
770 }
771
772 if (RT_SUCCESS(rc))
773 {
774 /* Check the event */
775 if (dwEventMask & EV_RXCHAR)
776 *pfEvtsRecv |= RTSERIALPORT_EVT_F_DATA_RX;
777 if (dwEventMask & EV_TXEMPTY)
778 {
779 if (pThis->fWritePending)
780 {
781 rc = rtSerialPortWriteCheckCompletion(pThis);
782 if (rc == VINF_SUCCESS)
783 *pfEvtsRecv |= RTSERIALPORT_EVT_F_DATA_TX;
784 else
785 rc = VINF_SUCCESS;
786 }
787 else
788 *pfEvtsRecv |= RTSERIALPORT_EVT_F_DATA_TX;
789 }
790 if (dwEventMask & EV_BREAK)
791 *pfEvtsRecv |= RTSERIALPORT_EVT_F_BREAK_DETECTED;
792 if (dwEventMask & (EV_CTS | EV_DSR | EV_RING | EV_RLSD))
793 *pfEvtsRecv |= RTSERIALPORT_EVT_F_STATUS_LINE_CHANGED;
794 }
795 }
796
797 return rc;
798}
799
800
801RTDECL(int) RTSerialPortEvtPollInterrupt(RTSERIALPORT hSerialPort)
802{
803 PRTSERIALPORTINTERNAL pThis = hSerialPort;
804 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
805 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
806
807 if (!SetEvent(pThis->hEvtIntr))
808 return RTErrConvertFromWin32(GetLastError());
809
810 return VINF_SUCCESS;
811}
812
813
814RTDECL(int) RTSerialPortChgBreakCondition(RTSERIALPORT hSerialPort, bool fSet)
815{
816 PRTSERIALPORTINTERNAL pThis = hSerialPort;
817 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
818 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
819
820 BOOL fSucc = FALSE;
821 if (fSet)
822 fSucc = SetCommBreak(pThis->hDev);
823 else
824 fSucc = ClearCommBreak(pThis->hDev);
825
826 int rc = VINF_SUCCESS;
827 if (!fSucc)
828 rc = RTErrConvertFromWin32(GetLastError());
829
830 return rc;
831}
832
833
834RTDECL(int) RTSerialPortChgStatusLines(RTSERIALPORT hSerialPort, uint32_t fClear, uint32_t fSet)
835{
836 PRTSERIALPORTINTERNAL pThis = hSerialPort;
837 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
838 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
839
840 BOOL fSucc = TRUE;
841 if (fSet & RTSERIALPORT_CHG_STS_LINES_F_DTR)
842 fSucc = EscapeCommFunction(pThis->hDev, SETDTR);
843 if ( fSucc
844 && (fSet & RTSERIALPORT_CHG_STS_LINES_F_RTS))
845 fSucc = EscapeCommFunction(pThis->hDev, SETRTS);
846
847 if ( fSucc
848 && (fClear & RTSERIALPORT_CHG_STS_LINES_F_DTR))
849 fSucc = EscapeCommFunction(pThis->hDev, CLRDTR);
850 if ( fSucc
851 && (fClear & RTSERIALPORT_CHG_STS_LINES_F_RTS))
852 fSucc = EscapeCommFunction(pThis->hDev, CLRRTS);
853
854 int rc = VINF_SUCCESS;
855 if (!fSucc)
856 rc = RTErrConvertFromWin32(GetLastError());
857
858 return rc;
859}
860
861
862RTDECL(int) RTSerialPortQueryStatusLines(RTSERIALPORT hSerialPort, uint32_t *pfStsLines)
863{
864 PRTSERIALPORTINTERNAL pThis = hSerialPort;
865 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
866 AssertReturn(pThis->u32Magic == RTSERIALPORT_MAGIC, VERR_INVALID_HANDLE);
867 AssertPtrReturn(pfStsLines, VERR_INVALID_POINTER);
868
869 *pfStsLines = 0;
870
871 int rc = VINF_SUCCESS;
872 DWORD fStsLinesQueried = 0;
873
874 /* Get the new state */
875 if (GetCommModemStatus(pThis->hDev, &fStsLinesQueried))
876 {
877 *pfStsLines |= (fStsLinesQueried & MS_RLSD_ON) ? RTSERIALPORT_STS_LINE_DCD : 0;
878 *pfStsLines |= (fStsLinesQueried & MS_RING_ON) ? RTSERIALPORT_STS_LINE_RI : 0;
879 *pfStsLines |= (fStsLinesQueried & MS_DSR_ON) ? RTSERIALPORT_STS_LINE_DSR : 0;
880 *pfStsLines |= (fStsLinesQueried & MS_CTS_ON) ? RTSERIALPORT_STS_LINE_CTS : 0;
881 }
882 else
883 rc = RTErrConvertFromWin32(GetLastError());
884
885 return rc;
886}
887
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette