📄 comm.c
字号:
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
* FILE: lib/kernel32/misc/comm.c
* PURPOSE: Comm functions
* PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
* modified from WINE [ Onno Hovers, (onno@stack.urc.tue.nl) ]
* Robert Dickenson (robd@mok.lvcom.com)
* Saveliy Tretiakov (saveliyt@mail.ru)
* Dmitry Philippov (shedon@mail.ru)
* UPDATE HISTORY:
* Created 01/11/98
* RDD (30/09/2002) implemented many function bodies to call serial driver.
* KJK (11/02/2003) implemented BuildCommDCB & BuildCommDCBAndTimeouts
* ST (21/03/2005) implemented GetCommProperties
* ST (24/03/2005) implemented ClearCommError. Corrected many functions.
* ST (05/04/2005) implemented CommConfigDialog
* DP (11/06/2005) implemented GetCommConfig
* DP (12/06/2005) implemented SetCommConfig
*
*/
#include <k32.h>
#undef SERIAL_LSRMST_ESCAPE
#undef SERIAL_LSRMST_LSR_DATA
#undef SERIAL_LSRMST_LSR_NODATA
#undef SERIAL_LSRMST_MST
#undef SERIAL_IOC_FCR_FIFO_ENABLE
#undef SERIAL_IOC_FCR_RCVR_RESET
#undef SERIAL_IOC_FCR_XMIT_RESET
#undef SERIAL_IOC_FCR_DMA_MODE
#undef SERIAL_IOC_FCR_RES1
#undef SERIAL_IOC_FCR_RES2
#undef SERIAL_IOC_FCR_RCVR_TRIGGER_LSB
#undef SERIAL_IOC_FCR_RCVR_TRIGGER_MSB
#undef SERIAL_IOC_MCR_DTR
#undef SERIAL_IOC_MCR_RTS
#undef SERIAL_IOC_MCR_OUT1
#undef SERIAL_IOC_MCR_OUT2
#undef SERIAL_IOC_MCR_LOOP
#include <ntddser.h>
#define NDEBUG
#include "../include/debug.h"
/* BUILDCOMMDCB & BUILDCOMMDCBANDTIMEOUTS */
/* TYPES */
/* Pointer to a callback that handles a particular parameter */
typedef BOOL (*COMMDCB_PARAM_CALLBACK)(DCB *, COMMTIMEOUTS *, BOOL *, LPWSTR *);
/* Symbolic flag of any length */
typedef struct _COMMDCB_PARAM_STRFLAG
{
UNICODE_STRING String;
ULONG_PTR Value;
} COMMDCB_PARAM_STRFLAG, *PCOMMDCB_PARAM_STRFLAG;
/* One char long symbolic flag */
typedef struct _COMMDCB_PARAM_CHARFLAG
{
WCHAR Char;
ULONG_PTR Value;
} COMMDCB_PARAM_CHARFLAG, *PCOMMDCB_PARAM_CHARFLAG;
/* MACROS */
/* Declare a parameter handler */
#define COMMDCB_PARAM_HANDLER(__P__) \
BOOL COMMDCB_ ## __P__ ## Param \
( \
DCB * Dcb, \
COMMTIMEOUTS * Timeouts, \
BOOL *StopBitsSet, \
LPWSTR *StrTail \
)
/* UTILITIES */
/*
Lookup a string flag and return its numerical value. The flags array must be
sorted - a dichotomycal search is performed
*/
static BOOL
COMMDCB_LookupStrFlag(PUNICODE_STRING Flag,
PCOMMDCB_PARAM_STRFLAG Flags,
int FlagCount,
PULONG_PTR Value)
{
/* Lower and upper bound for dichotomycal search */
int nLowerBound = 0;
int nUpperBound = FlagCount - 1;
do
{
LONG nComparison;
/* pick the element in the middle of the area of interest as the pivot */
int nCurFlag = nLowerBound + (nUpperBound - nLowerBound) / 2;
/* compare the string with the pivot */
nComparison = RtlCompareUnicodeString(Flag,
&Flags[nCurFlag].String,
TRUE);
/* string is equal */
if(nComparison == 0)
{
/* return the flag's value */
*Value = Flags[nCurFlag].Value;
/* success */
return TRUE;
}
else if(nComparison < 0)
{
/*
* restrict the search to the first half of the current slice, minus the pivot
*/
nUpperBound = nCurFlag - 1;
}
else
{
/*
* restrict the search to the second half of the current slice, minus the pivot
*/
nLowerBound = nCurFlag + 1;
}
} while(nLowerBound <= nUpperBound);
/* string not found: failure */
return FALSE;
}
/* PARSERS */
/*
Find the next character flag and return its numerical value. The flags array
must be sorted - a dichotomycal search is performed
*/
static BOOL
COMMDCB_ParseCharFlag(LPWSTR *StrTail,
PCOMMDCB_PARAM_CHARFLAG Flags,
int FlagCount,
PULONG_PTR Value)
{
/* Lower and upper bound for dichotomycal search */
int nLowerBound = 0;
int nUpperBound = FlagCount - 1;
/* get the first character as the flag */
WCHAR wcFlag = (*StrTail)[0];
/* premature end of string, or the character is whitespace */
if(!wcFlag || iswspace(wcFlag))
return FALSE;
/* uppercase the character for case-insensitive search */
wcFlag = towupper(wcFlag);
/* skip the character flag */
(*StrTail)++;
/* see COMMDCB_LookupStrFlag for a description of the algorithm */
do
{
LONG nComparison;
int nCurFlag = nLowerBound + (nUpperBound - nLowerBound) / 2;
nComparison = wcFlag - towupper(Flags[nCurFlag].Char);
if(nComparison == 0)
{
*Value = Flags[nCurFlag].Value;
return TRUE;
}
else if(nComparison < 0)
{
nUpperBound = nCurFlag - 1;
}
else
{
nLowerBound = nCurFlag + 1;
}
} while(nUpperBound >= nLowerBound);
/* flag not found: failure */
return FALSE;
}
/*
Find the next string flag and return its numerical value. The flags array must
be sorted - a dichotomycal search is performed
*/
static BOOL
COMMDCB_ParseStrFlag(LPWSTR *StrTail,
PCOMMDCB_PARAM_STRFLAG Flags,
int FlagCount,
PULONG_PTR Value)
{
LPWSTR pwcNewTail;
UNICODE_STRING wstrFlag;
/* scan the string until the first space character or the terminating null */
for(pwcNewTail = *StrTail;
pwcNewTail[0] && !iswspace(pwcNewTail[0]);
pwcNewTail++);
/* string flag empty */
if(pwcNewTail == *StrTail)
return FALSE;
/* build the UNICODE_STRING description of the string flag */
wstrFlag.Buffer = *StrTail;
wstrFlag.Length = (pwcNewTail - *StrTail) * sizeof(WCHAR);
wstrFlag.MaximumLength = wstrFlag.Length;
/* skip the string flag */
*StrTail = pwcNewTail;
/* lookup the string flag's value and return it */
return COMMDCB_LookupStrFlag(&wstrFlag, Flags, FlagCount, Value);
}
/*
Parse a boolean value in the symbolic form on/off
*/
static BOOL
COMMDCB_ParseBool(LPWSTR *StrTail,
PBOOL Value)
{
BOOL bRetVal;
ULONG_PTR nValue;
static COMMDCB_PARAM_STRFLAG a_BoolFlags[] = {
{ RTL_CONSTANT_STRING(L"off"), FALSE },
{ RTL_CONSTANT_STRING(L"on"), TRUE }
};
/* try to recognize the next flag as a boolean */
bRetVal = COMMDCB_ParseStrFlag(StrTail,
a_BoolFlags,
sizeof(a_BoolFlags) / sizeof(a_BoolFlags[0]),
&nValue);
if(!bRetVal)
return FALSE;
/* success */
*Value = (nValue ? TRUE : FALSE);
return TRUE;
}
/*
Parse a decimal integer
*/
static BOOL
COMMDCB_ParseInt(LPWSTR *StrTail,
DWORD *Value)
{
LPWSTR pwcPrevTail = *StrTail;
DWORD nValue = wcstoul(*StrTail, StrTail, 10);
/* no character was consumed: failure */
if(pwcPrevTail == *StrTail)
return FALSE;
/* success */
*Value = nValue;
return TRUE;
}
/* PARAMETER HANDLERS */
/* baud= */
COMMDCB_PARAM_HANDLER(baud)
{
DWORD nValue;
(void)Timeouts;
/* parse the baudrate */
if(!COMMDCB_ParseInt(StrTail, &nValue))
return FALSE;
switch(nValue)
{
/* documented abbreviations */
case 11:
Dcb->BaudRate = 110;
break;
case 15:
Dcb->BaudRate = 150;
break;
case 30:
Dcb->BaudRate = 300;
break;
case 60:
Dcb->BaudRate = 600;
break;
case 12:
Dcb->BaudRate = 1200;
break;
case 24:
Dcb->BaudRate = 2400;
break;
case 48:
Dcb->BaudRate = 4800;
break;
case 96:
Dcb->BaudRate = 9600;
break;
case 19:
Dcb->BaudRate = 19200;
break;
/* literal value */
default:
Dcb->BaudRate = nValue;
break;
}
/* if the stop bits haven't been specified explicitely */
if(!(*StopBitsSet))
{
/* default the stop bits to 2 for 110 baud */
if(Dcb->BaudRate == 110)
Dcb->StopBits = TWOSTOPBITS;
/* else, default the stop bits to 1 */
else
Dcb->StopBits = ONESTOPBIT;
}
/* success */
return TRUE;
}
/* data= */
COMMDCB_PARAM_HANDLER(data)
{
DWORD nValue;
(void)Timeouts;
(void)StopBitsSet;
/* parse the data bits */
if(!COMMDCB_ParseInt(StrTail, &nValue))
return FALSE;
/* value out of range: failure */
if(nValue < 5 || nValue > 8)
return FALSE;
/* success */
Dcb->ByteSize = (BYTE)nValue;
return TRUE;
}
/* dtr= */
COMMDCB_PARAM_HANDLER(dtr)
{
BOOL bRetVal;
ULONG_PTR nValue;
static COMMDCB_PARAM_STRFLAG a_DTRFlags[] = {
{ RTL_CONSTANT_STRING(L"hs"), DTR_CONTROL_HANDSHAKE },
{ RTL_CONSTANT_STRING(L"off"), DTR_CONTROL_DISABLE },
{ RTL_CONSTANT_STRING(L"on"), DTR_CONTROL_ENABLE }
};
(void)Timeouts;
(void)StopBitsSet;
/* parse the flag */
bRetVal = COMMDCB_ParseStrFlag(StrTail,
a_DTRFlags,
sizeof(a_DTRFlags) / sizeof(a_DTRFlags[0]),
&nValue);
/* failure */
if(!bRetVal)
return FALSE;
/* success */
Dcb->fDtrControl = nValue;
return TRUE;
}
/* idsr= */
COMMDCB_PARAM_HANDLER(idsr)
{
BOOL bValue;
(void)Timeouts;
(void)StopBitsSet;
/* parse the flag */
if(!COMMDCB_ParseBool(StrTail, &bValue))
return FALSE;
/* success */
Dcb->fDsrSensitivity = bValue;
return TRUE;
}
/* octs= */
COMMDCB_PARAM_HANDLER(octs)
{
BOOL bValue;
(void)Timeouts;
(void)StopBitsSet;
/* parse the flag */
if(!COMMDCB_ParseBool(StrTail, &bValue))
return FALSE;
/* success */
Dcb->fOutxCtsFlow = bValue;
return TRUE;
}
/* odsr= */
COMMDCB_PARAM_HANDLER(odsr)
{
BOOL bValue;
(void)Timeouts;
(void)StopBitsSet;
/* parse the flag */
if(!COMMDCB_ParseBool(StrTail, &bValue))
return FALSE;
/* success */
Dcb->fOutxDsrFlow = bValue;
return TRUE;
}
/* parity= */
COMMDCB_PARAM_HANDLER(parity)
{
BOOL bRetVal;
ULONG_PTR nValue;
static COMMDCB_PARAM_CHARFLAG a_ParityFlags[] = {
{ L'e', EVENPARITY },
{ L'm', MARKPARITY },
{ L'n', NOPARITY },
{ L'o', ODDPARITY },
{ L's', SPACEPARITY }
};
(void)Timeouts;
(void)StopBitsSet;
/* parse the flag */
bRetVal = COMMDCB_ParseCharFlag(StrTail,
a_ParityFlags,
sizeof(a_ParityFlags) / sizeof(a_ParityFlags[0]),
&nValue);
/* failure */
if(!bRetVal)
return FALSE;
/* success */
Dcb->Parity = (BYTE)nValue;
return TRUE;
}
/* rts= */
COMMDCB_PARAM_HANDLER(rts)
{
DWORD nRetVal;
ULONG_PTR nValue;
static COMMDCB_PARAM_STRFLAG a_RTSFlags[] = {
{ RTL_CONSTANT_STRING(L"hs"), RTS_CONTROL_HANDSHAKE },
{ RTL_CONSTANT_STRING(L"off"), RTS_CONTROL_DISABLE },
{ RTL_CONSTANT_STRING(L"on"), RTS_CONTROL_ENABLE },
{ RTL_CONSTANT_STRING(L"tg"), RTS_CONTROL_TOGGLE }
};
(void)Timeouts;
(void)StopBitsSet;
/* parse the flag */
nRetVal = COMMDCB_ParseStrFlag(StrTail,
a_RTSFlags,
sizeof(a_RTSFlags) / sizeof(a_RTSFlags[0]),
&nValue);
/* failure */
if(!nRetVal)
return FALSE;
/* success */
Dcb->fRtsControl = nValue;
return TRUE;
}
/* stop= */
COMMDCB_PARAM_HANDLER(stop)
{
BOOL bRetVal;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -