2 Copyright (c) 2008 KJK::Hyperion
4 Permission is hereby granted, free of charge, to any person obtaining a
5 copy of this software and associated documentation files (the "Software"),
6 to deal in the Software without restriction, including without limitation
7 the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 and/or sell copies of the Software, and to permit persons to whom the
9 Software is furnished to do so, subject to the following conditions:
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 DEALINGS IN THE SOFTWARE.
23 /* Parses a mode string for a serial port, in the same syntax as the mode.com command */
25 #if defined(__REACTOS__) && defined(_KERNEL32_)
28 #define DCB_BuildCommDCBA BuildCommDCBA
29 #define DCB_BuildCommDCBAndTimeoutsA BuildCommDCBAndTimeoutsA
30 #define DCB_BuildCommDCBW BuildCommDCBW
31 #define DCB_BuildCommDCBAndTimeoutsW BuildCommDCBAndTimeoutsW
37 #define WIN32_LEAN_AND_MEAN
42 void DCB_SkipSpace(const char ** ppTail
)
44 while(**ppTail
&& isspace(**ppTail
))
49 size_t DCB_SkipNonSpace(const char ** ppTail
)
51 const char * pOriginal
= *ppTail
;
53 while(**ppTail
&& !isspace(**ppTail
))
56 return *ppTail
- pOriginal
;
60 BOOL
DCB_SetBaudRate(unsigned long baudRate
, LPDCB lpDCB
)
64 case 11: lpDCB
->BaudRate
= 110; break;
65 case 15: lpDCB
->BaudRate
= 150; break;
66 case 30: lpDCB
->BaudRate
= 300; break;
67 case 60: lpDCB
->BaudRate
= 600; break;
68 case 12: lpDCB
->BaudRate
= 1200; break;
69 case 24: lpDCB
->BaudRate
= 2400; break;
70 case 48: lpDCB
->BaudRate
= 4800; break;
71 case 96: lpDCB
->BaudRate
= 9600; break;
72 case 19: lpDCB
->BaudRate
= 19200; break;
73 default: lpDCB
->BaudRate
= baudRate
; break;
80 BYTE
DCB_SetParity(char parity
, LPDCB lpDCB
)
117 BYTE
DCB_SetDataBits(unsigned long dataBits
, LPDCB lpDCB
)
121 bRet
= dataBits
>= 5 && dataBits
<= 8;
126 lpDCB
->ByteSize
= (BYTE
)dataBits
;
131 BOOL
DCB_ParseOldSeparator(const char ** ppTail
)
135 bRet
= **ppTail
== 0;
140 bRet
= **ppTail
== ',';
152 unsigned long DCB_ParseOldNumber(const char ** ppTail
, unsigned long nDefault
)
155 unsigned long number
;
157 DCB_SkipSpace(ppTail
);
159 if(!isdigit(**ppTail
))
162 number
= strtoul(*ppTail
, &pNumTail
, 10);
165 DCB_SkipSpace(ppTail
);
170 char DCB_ParseOldCharacter(const char ** ppTail
, char cDefault
)
174 DCB_SkipSpace(ppTail
);
176 if(**ppTail
== 0 || **ppTail
== ',')
179 character
= **ppTail
;
182 DCB_SkipSpace(ppTail
);
187 const char * DCB_ParseOldString(const char ** ppTail
, const char * pDefault
, size_t * pLength
)
191 DCB_SkipSpace(ppTail
);
193 if(**ppTail
== 0 || **ppTail
== ',')
200 while(**ppTail
!= 0 && **ppTail
!= ',' && !isspace(**ppTail
))
206 DCB_SkipSpace(ppTail
);
212 DCB_ParseOldMode(const char * pTail
, LPDCB lpDCB
, LPCOMMTIMEOUTS lpCommTimeouts
)
216 unsigned long baudRate
;
218 unsigned long dataBits
;
219 size_t stopBitsLength
;
220 const char * stopBits
;
224 baudRate
= DCB_ParseOldNumber(&pTail
, 0);
225 bRet
= DCB_ParseOldSeparator(&pTail
);
226 bRet
= bRet
&& DCB_SetBaudRate(baudRate
, lpDCB
);
232 parity
= DCB_ParseOldCharacter(&pTail
, 'E');
233 bRet
= DCB_ParseOldSeparator(&pTail
);
234 bRet
= bRet
&& DCB_SetParity(parity
, lpDCB
);
240 dataBits
= DCB_ParseOldNumber(&pTail
, 7);
241 bRet
= DCB_ParseOldSeparator(&pTail
);
242 bRet
= bRet
&& DCB_SetDataBits(dataBits
, lpDCB
);
249 stopBits
= DCB_ParseOldString(&pTail
, baudRate
== 110 ? "2" : "1", &stopBitsLength
);
250 bRet
= DCB_ParseOldSeparator(&pTail
);
255 if(strncmp(stopBits
, "1", stopBitsLength
) == 0)
257 else if(strncmp(stopBits
, "1.5", stopBitsLength
) == 0)
259 else if(strncmp(stopBits
, "2", stopBitsLength
) == 0)
265 retry
= DCB_ParseOldCharacter(&pTail
, 0);
275 lpDCB
->fOutX
= FALSE
;
276 lpDCB
->fOutxCtsFlow
= FALSE
;
277 lpDCB
->fOutxDsrFlow
= FALSE
;
278 lpDCB
->fDtrControl
= DTR_CONTROL_ENABLE
;
279 lpDCB
->fRtsControl
= RTS_CONTROL_ENABLE
;
285 lpDCB
->fOutX
= FALSE
;
286 lpDCB
->fOutxCtsFlow
= TRUE
;
287 lpDCB
->fOutxDsrFlow
= TRUE
;
288 lpDCB
->fDtrControl
= DTR_CONTROL_HANDSHAKE
;
289 lpDCB
->fRtsControl
= RTS_CONTROL_HANDSHAKE
;
296 lpDCB
->fOutxCtsFlow
= FALSE
;
297 lpDCB
->fOutxDsrFlow
= FALSE
;
298 lpDCB
->fDtrControl
= DTR_CONTROL_ENABLE
;
299 lpDCB
->fRtsControl
= RTS_CONTROL_ENABLE
;
310 BOOL
DCB_ParseNewNumber(const char * pString
, size_t cchString
, unsigned long * pNumber
)
314 unsigned long number
;
316 bRet
= cchString
> 0;
321 number
= strtoul(pString
, &pStringEnd
, 10);
323 bRet
= pStringEnd
- pString
== cchString
;
333 BOOL
DCB_ParseNewBoolean(const char * pString
, size_t cchString
, BOOL
* pBoolean
)
337 bRet
= _strnicmp(pString
, "on", cchString
) == 0;
345 bRet
= _strnicmp(pString
, "off", cchString
) == 0;
358 DCB_ParseNewMode(const char * pTail
, LPDCB lpDCB
, LPCOMMTIMEOUTS lpCommTimeouts
)
361 BOOL stopBitsSet
= FALSE
;
371 const char * pArgName
;
372 const char * pArgValue
;
373 unsigned long nArgValue
;
377 cchArg
= DCB_SkipNonSpace(&pTail
);
378 DCB_SkipSpace(&pTail
);
380 for(cchArgName
= 0; cchArgName
< cchArg
; ++ cchArgName
)
382 if(pArg
[cchArgName
] == '=')
386 bRet
= cchArgName
< cchArg
;
391 cchArgValue
= cchArg
- cchArgName
- 1;
393 pArgValue
= pArg
+ cchArgName
+ 1;
395 if(_strnicmp(pArgName
, "baud", cchArgName
) == 0)
397 bRet
= DCB_ParseNewNumber(pArgValue
, cchArgValue
, &nArgValue
);
398 bRet
= bRet
&& DCB_SetBaudRate(nArgValue
, lpDCB
);
402 if(lpDCB
->BaudRate
== 110 && !stopBitsSet
)
408 else if(_strnicmp(pArgName
, "parity", cchArgName
) == 0)
410 bRet
= cchArgValue
== 1;
411 bRet
= bRet
&& DCB_SetParity(pArgValue
[0], lpDCB
);
413 else if(_strnicmp(pArgName
, "data", cchArgName
) == 0)
415 bRet
= DCB_ParseNewNumber(pArgValue
, cchArgValue
, &nArgValue
);
416 bRet
= bRet
&& DCB_SetDataBits(nArgValue
, lpDCB
);
418 else if(_strnicmp(pArgName
, "stop", cchArgName
) == 0)
422 if(strncmp(pArgValue
, "1", cchArgValue
) == 0)
424 else if(strncmp(pArgValue
, "1.5", cchArgValue
) == 0)
426 else if(strncmp(pArgValue
, "2", cchArgValue
) == 0)
431 else if(_strnicmp(pArgName
, "to", cchArgName
) == 0)
433 bRet
= DCB_ParseNewBoolean(pArgValue
, cchArgValue
, &fArgValue
);
439 memset(lpCommTimeouts
, 0, sizeof(*lpCommTimeouts
));
442 lpCommTimeouts
->WriteTotalTimeoutConstant
= 60000;
446 else if(_strnicmp(pArgName
, "xon", cchArgName
) == 0)
448 bRet
= DCB_ParseNewBoolean(pArgValue
, cchArgValue
, &fArgValue
);
452 lpDCB
->fInX
= !!fArgValue
;
453 lpDCB
->fOutX
= !!fArgValue
;
456 else if(_strnicmp(pArgName
, "odsr", cchArgName
) == 0)
458 bRet
= DCB_ParseNewBoolean(pArgValue
, cchArgValue
, &fArgValue
);
461 lpDCB
->fOutxDsrFlow
= !!fArgValue
;
463 else if(_strnicmp(pArgName
, "octs", cchArgName
) == 0)
465 bRet
= DCB_ParseNewBoolean(pArgValue
, cchArgValue
, &fArgValue
);
468 lpDCB
->fOutxCtsFlow
= !!fArgValue
;
470 else if(_strnicmp(pArgName
, "dtr", cchArgName
) == 0)
472 bRet
= DCB_ParseNewBoolean(pArgValue
, cchArgValue
, &fArgValue
);
477 lpDCB
->fDtrControl
= DTR_CONTROL_ENABLE
;
479 lpDCB
->fDtrControl
= DTR_CONTROL_DISABLE
;
483 bRet
= _strnicmp(pArgValue
, "hs", cchArgValue
) == 0;
486 lpDCB
->fDtrControl
= DTR_CONTROL_HANDSHAKE
;
489 else if(_strnicmp(pArgName
, "rts", cchArgName
) == 0)
491 bRet
= DCB_ParseNewBoolean(pArgValue
, cchArgValue
, &fArgValue
);
496 lpDCB
->fRtsControl
= RTS_CONTROL_ENABLE
;
498 lpDCB
->fRtsControl
= RTS_CONTROL_DISABLE
;
502 bRet
= _strnicmp(pArgValue
, "hs", cchArgValue
) == 0;
505 lpDCB
->fRtsControl
= RTS_CONTROL_HANDSHAKE
;
508 bRet
= _strnicmp(pArgValue
, "tg", cchArgValue
) == 0;
511 lpDCB
->fRtsControl
= RTS_CONTROL_TOGGLE
;
515 else if(_strnicmp(pArgName
, "idsr", cchArgName
) == 0)
517 bRet
= DCB_ParseNewBoolean(pArgValue
, cchArgValue
, &fArgValue
);
520 lpDCB
->fDsrSensitivity
= !!fArgValue
;
534 DCB_ValidPort(unsigned long nPort
)
538 WCHAR szPort
[3 + 10 + 1];
540 dwErr
= GetLastError();
542 _snwprintf(szPort
, sizeof(szPort
) / sizeof(szPort
[0]), L
"COM%lu", nPort
);
544 bRet
= QueryDosDeviceW(szPort
, NULL
, 0) == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER
;
547 dwErr
= ERROR_INVALID_PARAMETER
;
558 DCB_BuildCommDCBAndTimeoutsA(LPCSTR lpDef
, LPDCB lpDCB
, LPCOMMTIMEOUTS lpCommTimeouts
)
561 LPCSTR pTail
= lpDef
;
564 if(_strnicmp(pTail
, "COM", 3) == 0)
574 nPort
= strtoul(pTail
, &pNumTail
, 10);
577 bRet
= DCB_ValidPort(nPort
);
582 DCB_SkipSpace(&pTail
);
587 DCB_SkipSpace(&pTail
);
593 bRet
= DCB_ParseOldMode(pTail
, &DCBCopy
, lpCommTimeouts
);
595 bRet
= DCB_ParseNewMode(pTail
, &DCBCopy
, lpCommTimeouts
);
598 SetLastError(ERROR_INVALID_PARAMETER
);
610 DCB_BuildCommDCBA(LPCSTR lpDef
, LPDCB lpDCB
)
612 return DCB_BuildCommDCBAndTimeoutsA(lpDef
, lpDCB
, NULL
);
620 DCB_BuildCommDCBAndTimeoutsW(LPCWSTR lpDef
, LPDCB lpDCB
, LPCOMMTIMEOUTS lpCommTimeouts
)
629 dwErr
= ERROR_INVALID_PARAMETER
;
630 cchAscii
= WideCharToMultiByte(20127, 0, lpDef
, -1, NULL
, 0, NULL
, NULL
);
636 hHeap
= GetProcessHeap();
637 pszAscii
= HeapAlloc(hHeap
, 0, cchAscii
);
639 bRet
= pszAscii
!= NULL
;
643 bInvalidChars
= FALSE
;
644 cchAscii
= WideCharToMultiByte(20127, 0, lpDef
, -1, pszAscii
, cchAscii
, NULL
, &bInvalidChars
);
646 bRet
= cchAscii
> 0 && !bInvalidChars
;
649 bRet
= DCB_BuildCommDCBAndTimeoutsA(pszAscii
, lpDCB
, lpCommTimeouts
);
651 HeapFree(hHeap
, 0, pszAscii
);
654 dwErr
= ERROR_OUTOFMEMORY
;
668 DCB_BuildCommDCBW(LPCWSTR lpDef
, LPDCB lpDCB
)
670 return DCB_BuildCommDCBAndTimeoutsW(lpDef
, lpDCB
, NULL
);