winpr-comm: got IOCTL_SERIAL_SET_HANDFLOW / IOCTL_SERIAL_GET_HANDFLOW

This commit is contained in:
Emmanuel Ledoux 2014-05-06 16:08:58 +02:00
parent 494b7e8f93
commit c2b024512a
12 changed files with 970 additions and 72 deletions

View File

@ -298,7 +298,7 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp)
break;
case ERROR_NOT_SUPPORTED:
irp->IoStatus = STATUS_INVALID_PARAMETER;
irp->IoStatus = STATUS_NOT_SUPPORTED;
break;
case ERROR_INSUFFICIENT_BUFFER:
@ -309,6 +309,10 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp)
irp->IoStatus = STATUS_INVALID_PARAMETER;
break;
case ERROR_CALL_NOT_IMPLEMENTED:
irp->IoStatus = STATUS_NOT_IMPLEMENTED;
break;
default:
DEBUG_SVC("unexpected last-error: 0x%x", GetLastError());
irp->IoStatus = STATUS_UNSUCCESSFUL;

View File

@ -224,8 +224,67 @@ BOOL GetCommState(HANDLE hFile, LPDCB lpDCB)
lpLocalDcb->fParity = (currentState.c_iflag & INPCK) != 0;
/* TMP: TODO: */
/* (...) */
SERIAL_HANDFLOW handflow;
if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_HANDFLOW, NULL, 0, &handflow, sizeof(SERIAL_HANDFLOW), &bytesReturned, NULL))
{
DEBUG_WARN("GetCommState failure: could not get the handflow settings.");
goto error_handle;
}
lpLocalDcb->fOutxCtsFlow = (handflow.ControlHandShake & SERIAL_CTS_HANDSHAKE) != 0;
lpLocalDcb->fOutxDsrFlow = (handflow.ControlHandShake & SERIAL_DSR_HANDSHAKE) != 0;
if (handflow.ControlHandShake & SERIAL_DTR_HANDSHAKE)
{
lpLocalDcb->fDtrControl = DTR_CONTROL_HANDSHAKE;
}
else if (handflow.ControlHandShake & SERIAL_DTR_CONTROL)
{
lpLocalDcb->fDtrControl = DTR_CONTROL_ENABLE;
}
else
{
lpLocalDcb->fDtrControl = DTR_CONTROL_DISABLE;
}
lpLocalDcb->fDsrSensitivity = (handflow.ControlHandShake & SERIAL_DSR_SENSITIVITY) != 0;
lpLocalDcb->fTXContinueOnXoff = (handflow.FlowReplace & SERIAL_XOFF_CONTINUE) != 0;
lpLocalDcb->fOutX = (handflow.FlowReplace & SERIAL_AUTO_TRANSMIT) != 0;
lpLocalDcb->fInX = (handflow.FlowReplace & SERIAL_AUTO_RECEIVE) != 0;
lpLocalDcb->fErrorChar = (handflow.FlowReplace & SERIAL_ERROR_CHAR) != 0;
lpLocalDcb->fNull = (handflow.FlowReplace & SERIAL_NULL_STRIPPING) != 0;
if (handflow.FlowReplace & SERIAL_RTS_HANDSHAKE)
{
lpLocalDcb->fRtsControl = RTS_CONTROL_HANDSHAKE;
}
else if (handflow.FlowReplace & SERIAL_RTS_CONTROL)
{
lpLocalDcb->fRtsControl = RTS_CONTROL_ENABLE;
}
else
{
lpLocalDcb->fRtsControl = RTS_CONTROL_DISABLE;
}
// FIXME: how to get the RTS_CONTROL_TOGGLE state? Does it match the UART 16750's Autoflow Control Enabled bit in its Modem Control Register (MCR)
lpLocalDcb->fAbortOnError = (handflow.ControlHandShake & SERIAL_ERROR_ABORT) != 0;
/* lpLocalDcb->fDummy2 not used */
lpLocalDcb->wReserved = 0; /* must be zero */
lpLocalDcb->XonLim = handflow.XonLimit;
lpLocalDcb->XoffLim = handflow.XoffLimit;
SERIAL_LINE_CONTROL lineControl;
if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_LINE_CONTROL, NULL, 0, &lineControl, sizeof(SERIAL_LINE_CONTROL), &bytesReturned, NULL))
@ -316,7 +375,7 @@ BOOL SetCommState(HANDLE hFile, LPDCB lpDCB)
}
SERIAL_CHARS serialChars;
if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_CHARS, NULL, 0, &serialChars, sizeof(SERIAL_CHARS), &bytesReturned, NULL))
if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_GET_CHARS, NULL, 0, &serialChars, sizeof(SERIAL_CHARS), &bytesReturned, NULL)) /* as of today, required for BreakChar */
{
DEBUG_WARN("SetCommState failure: could not get the initial serial chars.");
return FALSE;
@ -325,7 +384,7 @@ BOOL SetCommState(HANDLE hFile, LPDCB lpDCB)
serialChars.XoffChar = lpDCB->XoffChar;
serialChars.ErrorChar = lpDCB->ErrorChar;
serialChars.EofChar = lpDCB->EofChar;
serialChars.EventChar = lpDCB->EvtChar;
serialChars.EventChar = lpDCB->EvtChar;
if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_CHARS, &serialChars, sizeof(SERIAL_CHARS), NULL, 0, &bytesReturned, NULL))
{
DEBUG_WARN("SetCommState failure: could not set the serial chars.");
@ -343,6 +402,113 @@ BOOL SetCommState(HANDLE hFile, LPDCB lpDCB)
}
SERIAL_HANDFLOW handflow;
ZeroMemory(&handflow, sizeof(SERIAL_HANDFLOW));
if (lpDCB->fOutxCtsFlow)
{
handflow.ControlHandShake |= SERIAL_CTS_HANDSHAKE;
}
if (lpDCB->fOutxDsrFlow)
{
handflow.ControlHandShake |= SERIAL_DSR_HANDSHAKE;
}
switch (lpDCB->fDtrControl)
{
case SERIAL_DTR_HANDSHAKE:
handflow.ControlHandShake |= DTR_CONTROL_HANDSHAKE;
break;
case SERIAL_DTR_CONTROL:
handflow.ControlHandShake |= DTR_CONTROL_ENABLE;
break;
case DTR_CONTROL_DISABLE:
/* do nothing since handflow is init-zeroed */
break;
default:
DEBUG_WARN("Unexpected fDtrControl value: %d\n", lpDCB->fDtrControl);
return FALSE;
}
if (lpDCB->fDsrSensitivity)
{
handflow.ControlHandShake |= SERIAL_DSR_SENSITIVITY;
}
if (lpDCB->fTXContinueOnXoff)
{
handflow.FlowReplace |= SERIAL_XOFF_CONTINUE;
}
if (lpDCB->fOutX)
{
handflow.FlowReplace |= SERIAL_AUTO_TRANSMIT;
}
if (lpDCB->fInX)
{
handflow.FlowReplace |= SERIAL_AUTO_RECEIVE;
}
if (lpDCB->fErrorChar)
{
handflow.FlowReplace |= SERIAL_ERROR_CHAR;
}
if (lpDCB->fNull)
{
handflow.FlowReplace |= SERIAL_NULL_STRIPPING;
}
switch (lpDCB->fRtsControl)
{
case RTS_CONTROL_TOGGLE:
DEBUG_WARN("Unsupported RTS_CONTROL_TOGGLE feature");
// FIXME: see also GetCommState()
return FALSE;
case RTS_CONTROL_HANDSHAKE:
handflow.FlowReplace |= SERIAL_RTS_HANDSHAKE;
break;
case RTS_CONTROL_ENABLE:
handflow.FlowReplace |= SERIAL_RTS_CONTROL;
break;
case RTS_CONTROL_DISABLE:
/* do nothing since handflow is init-zeroed */
break;
default:
DEBUG_WARN("Unexpected fRtsControl value: %d\n", lpDCB->fRtsControl);
return FALSE;
}
if (lpDCB->fAbortOnError)
{
handflow.ControlHandShake |= SERIAL_ERROR_ABORT;
}
/* lpDCB->fDummy2 not used */
/* lpLocalDcb->wReserved ignored */
handflow.XonLimit = lpDCB->XonLim;
handflow.XoffLimit = lpDCB->XoffLim;
if (!CommDeviceIoControl(pComm, IOCTL_SERIAL_SET_HANDFLOW, &handflow, sizeof(SERIAL_HANDFLOW), NULL, 0, &bytesReturned, NULL))
{
DEBUG_WARN("SetCommState failure: could not set the handflow settings.");
return FALSE;
}
/** upcomingTermios stage **/

View File

@ -135,6 +135,7 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe
return pRemoteSerialDriver->set_baud_rate(pComm, pBaudRate);
}
break;
}
case IOCTL_SERIAL_GET_BAUD_RATE:
{
@ -155,6 +156,7 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe
*lpBytesReturned = sizeof(SERIAL_BAUD_RATE);
return TRUE;
}
break;
}
case IOCTL_SERIAL_GET_PROPERTIES:
{
@ -175,6 +177,7 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe
*lpBytesReturned = sizeof(COMMPROP);
return TRUE;
}
break;
}
case IOCTL_SERIAL_SET_CHARS:
{
@ -191,6 +194,7 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe
return pRemoteSerialDriver->set_serial_chars(pComm, pSerialChars);
}
break;
}
case IOCTL_SERIAL_GET_CHARS:
{
@ -211,6 +215,7 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe
*lpBytesReturned = sizeof(SERIAL_CHARS);
return TRUE;
}
break;
}
case IOCTL_SERIAL_SET_LINE_CONTROL:
{
@ -227,6 +232,7 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe
return pRemoteSerialDriver->set_line_control(pComm, pLineControl);
}
break;
}
case IOCTL_SERIAL_GET_LINE_CONTROL:
{
@ -247,11 +253,50 @@ BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffe
*lpBytesReturned = sizeof(SERIAL_LINE_CONTROL);
return TRUE;
}
break;
}
case IOCTL_SERIAL_SET_HANDFLOW:
{
if (pRemoteSerialDriver->set_handflow)
{
SERIAL_HANDFLOW *pHandflow = (SERIAL_HANDFLOW*)lpInBuffer;
assert(nInBufferSize >= sizeof(SERIAL_HANDFLOW));
if (nInBufferSize < sizeof(SERIAL_HANDFLOW))
{
SetLastError(ERROR_INVALID_DATA);
return FALSE;
}
return pRemoteSerialDriver->set_handflow(pComm, pHandflow);
}
break;
}
case IOCTL_SERIAL_GET_HANDFLOW:
{
if (pRemoteSerialDriver->get_handflow)
{
SERIAL_HANDFLOW *pHandflow = (SERIAL_HANDFLOW*)lpOutBuffer;
assert(nOutBufferSize >= sizeof(SERIAL_HANDFLOW));
if (nOutBufferSize < sizeof(SERIAL_HANDFLOW))
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
if (!pRemoteSerialDriver->get_handflow(pComm, pHandflow))
return FALSE;
*lpBytesReturned = sizeof(SERIAL_HANDFLOW);
return TRUE;
}
break;
}
}
DEBUG_WARN(_T("unsupported IoControlCode: Ox%x (remote serial driver: %s)"), dwIoControlCode, pRemoteSerialDriver->name);
DEBUG_WARN(_T("unsupported IoControlCode: Ox%0.8x (remote serial driver: %s)"), dwIoControlCode, pRemoteSerialDriver->name);
return FALSE;
}

View File

@ -67,8 +67,8 @@ extern "C" {
/* IOCTL_SERIAL_WAIT_ON_MASK 0x001B0048 */
/* IOCTL_SERIAL_IMMEDIATE_CHAR 0x001B0018 */
/* IOCTL_SERIAL_PURGE 0x001B004C */
/* IOCTL_SERIAL_GET_HANDFLOW 0x001B0060 */
/* IOCTL_SERIAL_SET_HANDFLOW 0x001B0064 */
#define IOCTL_SERIAL_GET_HANDFLOW 0x001B0060
#define IOCTL_SERIAL_SET_HANDFLOW 0x001B0064
/* IOCTL_SERIAL_GET_MODEMSTATUS 0x001B0068 */
/* IOCTL_SERIAL_GET_DTRRTS 0x001B0078 */
/* IOCTL_SERIAL_GET_COMMSTATUS 0x001B0084 */
@ -132,6 +132,38 @@ typedef struct _SERIAL_LINE_CONTROL
} SERIAL_LINE_CONTROL, *PSERIAL_LINE_CONTROL;
typedef struct _SERIAL_HANDFLOW
{
ULONG ControlHandShake;
ULONG FlowReplace;
LONG XonLimit;
LONG XoffLimit;
} SERIAL_HANDFLOW, *PSERIAL_HANDFLOW;
#define SERIAL_DTR_MASK ((ULONG)0x03)
#define SERIAL_DTR_CONTROL ((ULONG)0x01)
#define SERIAL_DTR_HANDSHAKE ((ULONG)0x02)
#define SERIAL_CTS_HANDSHAKE ((ULONG)0x08)
#define SERIAL_DSR_HANDSHAKE ((ULONG)0x10)
#define SERIAL_DCD_HANDSHAKE ((ULONG)0x20)
#define SERIAL_OUT_HANDSHAKEMASK ((ULONG)0x38)
#define SERIAL_DSR_SENSITIVITY ((ULONG)0x40)
#define SERIAL_ERROR_ABORT ((ULONG)0x80000000)
#define SERIAL_CONTROL_INVALID ((ULONG)0x7fffff84)
#define SERIAL_AUTO_TRANSMIT ((ULONG)0x01)
#define SERIAL_AUTO_RECEIVE ((ULONG)0x02)
#define SERIAL_ERROR_CHAR ((ULONG)0x04)
#define SERIAL_NULL_STRIPPING ((ULONG)0x08)
#define SERIAL_BREAK_CHAR ((ULONG)0x10)
#define SERIAL_RTS_MASK ((ULONG)0xc0)
#define SERIAL_RTS_CONTROL ((ULONG)0x40)
#define SERIAL_RTS_HANDSHAKE ((ULONG)0x80)
#define SERIAL_TRANSMIT_TOGGLE ((ULONG)0xc0)
#define SERIAL_XOFF_CONTINUE ((ULONG)0x80000000)
#define SERIAL_FLOW_INVALID ((ULONG)0x7fffff20)
/**
* A function might be NULL if not supported by the underlying remote driver.
*
@ -148,6 +180,8 @@ typedef struct _REMOTE_SERIAL_DRIVER
BOOL (*get_serial_chars)(WINPR_COMM *pComm, SERIAL_CHARS *pSerialChars);
BOOL (*set_line_control)(WINPR_COMM *pComm, const SERIAL_LINE_CONTROL *pLineControl);
BOOL (*get_line_control)(WINPR_COMM *pComm, SERIAL_LINE_CONTROL *pLineControl);
BOOL (*set_handflow)(WINPR_COMM *pComm, const SERIAL_HANDFLOW *pHandflow);
BOOL (*get_handflow)(WINPR_COMM *pComm, SERIAL_HANDFLOW *pHandflow);
} REMOTE_SERIAL_DRIVER;

View File

@ -63,22 +63,31 @@ static REMOTE_SERIAL_DRIVER _SerCx2Sys =
.get_serial_chars = _get_serial_chars,
.set_line_control = NULL,
.get_line_control = NULL,
.set_handflow = NULL,
.get_handflow = NULL,
};
REMOTE_SERIAL_DRIVER* SerCx2Sys_s()
{
/* _SerCx2Sys completed with inherited functions from SerialSys or SerCxSys */
//REMOTE_SERIAL_DRIVER* pSerialSys = SerialSys_s();
REMOTE_SERIAL_DRIVER* pSerialSys = SerialSys_s();
REMOTE_SERIAL_DRIVER* pSerCxSys = SerCxSys_s();
_SerCx2Sys.set_baud_rate = pSerCxSys->set_baud_rate;
_SerCx2Sys.get_baud_rate = pSerCxSys->get_baud_rate;
_SerCx2Sys.get_properties = pSerCxSys->get_properties;
_SerCx2Sys.set_line_control = pSerCxSys->set_line_control;
_SerCx2Sys.get_line_control = pSerCxSys->get_line_control;
/* Only SERIAL_CTS_HANDSHAKE, SERIAL_RTS_CONTROL and SERIAL_RTS_HANDSHAKE flags are really required by SerCx2.sys
* http://msdn.microsoft.com/en-us/library/jj680685%28v=vs.85%29.aspx
*/
_SerCx2Sys.set_handflow = pSerialSys->set_handflow;
_SerCx2Sys.get_handflow = pSerialSys->get_handflow;
return &_SerCx2Sys;
}

View File

@ -231,6 +231,267 @@ static BOOL _get_baud_rate(WINPR_COMM *pComm, SERIAL_BAUD_RATE *pBaudRate)
return FALSE;
}
/* hard-coded in N_TTY */
#define TTY_THRESHOLD_THROTTLE 128 /* now based on remaining room */
#define TTY_THRESHOLD_UNTHROTTLE 128
/* FIXME: mostly copied/pasted from comm_serial_sys.c, better share this code */
static BOOL _set_handflow(WINPR_COMM *pComm, const SERIAL_HANDFLOW *pHandflow)
{
BOOL result = TRUE;
struct termios upcomingTermios;
/* logical XOR */
if ((!(pHandflow->ControlHandShake & SERIAL_DTR_CONTROL) && (pHandflow->FlowReplace & SERIAL_RTS_CONTROL)) ||
((pHandflow->ControlHandShake & SERIAL_DTR_CONTROL) && !(pHandflow->FlowReplace & SERIAL_RTS_CONTROL)))
{
DEBUG_WARN("SERIAL_DTR_CONTROL cannot be different SERIAL_RTS_CONTROL, HUPCL will be set according SERIAL_RTS_CONTROL.");
result = FALSE; /* but keep on */
}
ZeroMemory(&upcomingTermios, sizeof(struct termios));
if (tcgetattr(pComm->fd, &upcomingTermios) < 0)
{
SetLastError(ERROR_IO_DEVICE);
return FALSE;
}
/* ControlHandShake */
if (pHandflow->ControlHandShake & SERIAL_DTR_CONTROL)
{
upcomingTermios.c_cflag |= HUPCL;
}
else
{
upcomingTermios.c_cflag &= ~HUPCL;
/* FIXME: is the DTR line also needs to be forced to a disable state? */
}
if (pHandflow->ControlHandShake & SERIAL_DTR_HANDSHAKE)
{
/* DTR/DSR flow control not supported on Linux */
DEBUG_WARN("Attempt to use the unsupported SERIAL_DTR_HANDSHAKE feature.");
SetLastError(ERROR_NOT_SUPPORTED);
result = FALSE; /* but keep on */
}
if (pHandflow->ControlHandShake & SERIAL_CTS_HANDSHAKE)
{
upcomingTermios.c_cflag |= CRTSCTS;
}
else
{
upcomingTermios.c_cflag &= ~CRTSCTS;
}
if (pHandflow->ControlHandShake & SERIAL_DSR_HANDSHAKE)
{
/* DTR/DSR flow control not supported on Linux */
DEBUG_WARN("Attempt to use the unsupported SERIAL_DSR_HANDSHAKE feature.");
SetLastError(ERROR_NOT_SUPPORTED);
result = FALSE; /* but keep on */
}
/* SERIAL_DCD_HANDSHAKE unsupported by SerCx */
if (pHandflow->ControlHandShake & SERIAL_DCD_HANDSHAKE)
{
DEBUG_WARN("Attempt to set SERIAL_DCD_HANDSHAKE (not implemented)");
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
result = FALSE; /* but keep on */
}
/* SERIAL_DSR_SENSITIVITY unsupported by SerCx */
if (pHandflow->ControlHandShake & SERIAL_DSR_SENSITIVITY)
{
DEBUG_WARN("Attempt to set SERIAL_DSR_SENSITIVITY (not implemented)");
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
result = FALSE; /* but keep on */
}
/* SERIAL_ERROR_ABORT unsupported by SerCx */
if (pHandflow->ControlHandShake & SERIAL_ERROR_ABORT)
{
DEBUG_WARN("Attempt to set SERIAL_ERROR_ABORT (not implemented)");
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
result = FALSE; /* but keep on */
}
/* FlowReplace */
/* SERIAL_AUTO_TRANSMIT unsupported by SerCx */
if (pHandflow->FlowReplace & SERIAL_AUTO_TRANSMIT)
{
DEBUG_WARN("Attempt to set SERIAL_AUTO_TRANSMIT (not implemented)");
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
result = FALSE; /* but keep on */
}
/* SERIAL_AUTO_RECEIVE unsupported by SerCx */
if (pHandflow->FlowReplace & SERIAL_AUTO_RECEIVE)
{
DEBUG_WARN("Attempt to set SERIAL_AUTO_RECEIVE (not implemented)");
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
result = FALSE; /* but keep on */
}
/* SERIAL_ERROR_CHAR unsupported by SerCx */
if (pHandflow->FlowReplace & SERIAL_ERROR_CHAR)
{
DEBUG_WARN("Attempt to set SERIAL_ERROR_CHAR (not implemented)");
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
result = FALSE; /* but keep on */
}
/* SERIAL_NULL_STRIPPING unsupported by SerCx */
if (pHandflow->FlowReplace & SERIAL_NULL_STRIPPING)
{
DEBUG_WARN("Attempt to set SERIAL_NULL_STRIPPING (not implemented)");
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
result = FALSE; /* but keep on */
}
/* SERIAL_BREAK_CHAR unsupported by SerCx */
if (pHandflow->FlowReplace & SERIAL_BREAK_CHAR)
{
DEBUG_WARN("Attempt to set SERIAL_BREAK_CHAR (not implemented)");
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
result = FALSE; /* but keep on */
}
if (pHandflow->FlowReplace & SERIAL_RTS_CONTROL)
{
upcomingTermios.c_cflag |= HUPCL;
}
else
{
upcomingTermios.c_cflag &= ~HUPCL;
/* FIXME: is the RTS line also needs to be forced to a disable state? */
}
if (pHandflow->FlowReplace & SERIAL_RTS_HANDSHAKE)
{
upcomingTermios.c_cflag |= CRTSCTS;
}
else
{
upcomingTermios.c_cflag &= ~CRTSCTS;
}
/* SERIAL_XOFF_CONTINUE unsupported by SerCx */
if (pHandflow->FlowReplace & SERIAL_XOFF_CONTINUE)
{
DEBUG_WARN("Attempt to set SERIAL_XOFF_CONTINUE (not implemented)");
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
result = FALSE; /* but keep on */
}
/* XonLimit */
// FIXME: could be implemented during read/write I/O
if (pHandflow->XonLimit != TTY_THRESHOLD_UNTHROTTLE)
{
DEBUG_WARN("Attempt to set XonLimit with an unsupported value: %d", pHandflow->XonLimit);
SetLastError(ERROR_NOT_SUPPORTED);
result = FALSE; /* but keep on */
}
/* XoffChar */
// FIXME: could be implemented during read/write I/O
if (pHandflow->XoffLimit != TTY_THRESHOLD_THROTTLE)
{
DEBUG_WARN("Attempt to set XoffLimit with an unsupported value: %d", pHandflow->XoffLimit);
SetLastError(ERROR_NOT_SUPPORTED);
result = FALSE; /* but keep on */
}
if (_comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &upcomingTermios) < 0)
{
DEBUG_WARN("_comm_ioctl_tcsetattr failure: last-error: 0x0.8x", GetLastError());
return FALSE;
}
return result;
}
/* FIXME: mostly copied/pasted from comm_serial_sys.c, better share this code */
static BOOL _get_handflow(WINPR_COMM *pComm, SERIAL_HANDFLOW *pHandflow)
{
struct termios currentTermios;
ZeroMemory(&currentTermios, sizeof(struct termios));
if (tcgetattr(pComm->fd, &currentTermios) < 0)
{
SetLastError(ERROR_IO_DEVICE);
return FALSE;
}
/* ControlHandShake */
pHandflow->ControlHandShake = 0;
if (currentTermios.c_cflag & HUPCL)
pHandflow->ControlHandShake |= SERIAL_DTR_CONTROL;
/* SERIAL_DTR_HANDSHAKE unsupported */
if (currentTermios.c_cflag & CRTSCTS)
pHandflow->ControlHandShake |= SERIAL_CTS_HANDSHAKE;
/* SERIAL_DSR_HANDSHAKE unsupported */
/* SERIAL_DCD_HANDSHAKE unsupported by SerCx */
/* SERIAL_DSR_SENSITIVITY unsupported by SerCx */
/* SERIAL_ERROR_ABORT unsupported by SerCx */
/* FlowReplace */
pHandflow->FlowReplace = 0;
/* SERIAL_AUTO_TRANSMIT unsupported by SerCx */
/* SERIAL_AUTO_RECEIVE unsupported by SerCx */
/* SERIAL_ERROR_CHAR unsupported by SerCx */
/* SERIAL_NULL_STRIPPING unsupported by SerCx */
/* SERIAL_BREAK_CHAR unsupported by SerCx */
if (currentTermios.c_cflag & HUPCL)
pHandflow->FlowReplace |= SERIAL_RTS_CONTROL;
if (currentTermios.c_cflag & CRTSCTS)
pHandflow->FlowReplace |= SERIAL_RTS_HANDSHAKE;
/* SERIAL_XOFF_CONTINUE unsupported by SerCx */
/* XonLimit */
pHandflow->XonLimit = TTY_THRESHOLD_UNTHROTTLE;
/* XoffLimit */
pHandflow->XoffLimit = TTY_THRESHOLD_THROTTLE;
return TRUE;
}
/* specific functions only */
static REMOTE_SERIAL_DRIVER _SerCxSys =
@ -244,6 +505,8 @@ static REMOTE_SERIAL_DRIVER _SerCxSys =
.get_serial_chars = NULL,
.set_line_control = NULL,
.get_line_control = NULL,
.set_handflow = _set_handflow,
.get_handflow = _get_handflow,
};

View File

@ -148,6 +148,8 @@ static BOOL _get_properties(WINPR_COMM *pComm, COMMPROP *pProperties)
// TMP: TODO:
// TMP: COMMPROP_INITIALIZED ?
// TMP: required?
// ZeroMemory(pProperties, sizeof(COMMPROP);
@ -158,9 +160,17 @@ static BOOL _get_properties(WINPR_COMM *pComm, COMMPROP *pProperties)
/* pProperties->MaxTxQueue; */
/* pProperties->MaxRxQueue; */
pProperties->dwMaxBaud = SERIAL_BAUD_115200; /* _SERIAL_MAX_BAUD */
/* pProperties->ProvSubType; */
/* pProperties->ProvCapabilities; */
/* pProperties->SettableParams; */
/* FIXME: what about PST_RS232? */
pProperties->dwProvSubType = PST_UNSPECIFIED;
/* TMP: TODO: to be finalized */
pProperties->dwProvCapabilities =
/*PCF_16BITMODE | PCF_DTRDSR | PCF_INTTIMEOUTS |*/ PCF_PARITY_CHECK | /*PCF_RLSD | */
PCF_RTSCTS | PCF_SETXCHAR | /*PCF_SPECIALCHARS | PCF_TOTALTIMEOUTS |*/ PCF_XONXOFF;
/* TMP: TODO: double check SP_RLSD */
pProperties->dwSettableParams = SP_BAUD | SP_DATABITS | SP_HANDSHAKING | SP_PARITY | SP_PARITY_CHECK | /*SP_RLSD |*/ SP_STOPBITS;
pProperties->dwSettableBaud = 0;
for (i=0; _SERIAL_SYS_BAUD_TABLE[i][0]<=_SERIAL_MAX_BAUD; i++)
@ -251,15 +261,17 @@ static BOOL _get_baud_rate(WINPR_COMM *pComm, SERIAL_BAUD_RATE *pBaudRate)
}
/**
* NOTE: Only XonChar and XoffChar are plenty supported with Linux
* N_TTY line discipline.
* NOTE: Only XonChar and XoffChar are plenty supported with the Linux
* N_TTY line discipline.
*
* ERRORS:
* ERROR_IO_DEVICE
* ERROR_INVALID_PARAMETER when Xon and Xoff chars are the same;
* ERROR_NOT_SUPPORTED
*/
static BOOL _set_serial_chars(WINPR_COMM *pComm, const SERIAL_CHARS *pSerialChars)
{
BOOL result = TRUE;
struct termios upcomingTermios;
ZeroMemory(&upcomingTermios, sizeof(struct termios));
@ -282,55 +294,46 @@ static BOOL _set_serial_chars(WINPR_COMM *pComm, const SERIAL_CHARS *pSerialChar
* special character meaning is replaced by the timeout
* meaning.
*
* It doesn't seem the case of the Linux's implementation but
* in our context, the cannonical mode (fBinary=FALSE) should
* never be enabled.
* EofChar and c_cc[VEOF] are not quite the same, prefer to
* don't use c_cc[VEOF] at all.
*
* FIXME: might be implemented during read/write I/O
*/
if (upcomingTermios.c_lflag & ICANON)
if (pSerialChars->EofChar != '\0')
{
upcomingTermios.c_cc[VEOF] = pSerialChars->EofChar;
DEBUG_WARN("c_cc[VEOF] is not supposed to be modified!");
DEBUG_WARN("EofChar='%c' cannot be set\n", pSerialChars->EofChar);
SetLastError(ERROR_NOT_SUPPORTED);
result = FALSE; /* but keep on */
}
/* else let c_cc[VEOF] unchanged */
/* According the Linux's n_tty discipline, charaters with a
* parity error can only be let unchanged, replaced by \0 or
* get the prefix the prefix \377 \0
*/
if (pSerialChars->ErrorChar == '\0')
/* FIXME: see also: _set_handflow() */
if (pSerialChars->ErrorChar != '\0')
{
/* Also suppose PARENB !IGNPAR !PARMRK to be effective */
upcomingTermios.c_iflag |= INPCK;
}
else
{
/* FIXME: develop a line discipline dedicated to the
* RDP redirection. Erroneous characters might also be
* caught during read/write operations?
*/
DEBUG_WARN("ErrorChar='%c' cannot be set, characters with a parity error will be let unchanged.\n", pSerialChars->ErrorChar);
DEBUG_WARN("ErrorChar='%c' (0x%x) cannot be set (unsupported).\n", pSerialChars->ErrorChar, pSerialChars->ErrorChar);
SetLastError(ERROR_NOT_SUPPORTED);
result = FALSE; /* but keep on */
}
if (pSerialChars->BreakChar == '\0')
/* FIXME: see also: _set_handflow() */
if (pSerialChars->BreakChar != '\0')
{
upcomingTermios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK);
}
else
{
/* FIXME: develop a line discipline dedicated to the
* RDP redirection. Break characters might also be
* caught during read/write operations?
*/
DEBUG_WARN("BreakChar='%c' cannot be set.\n", pSerialChars->ErrorChar);
DEBUG_WARN("BreakChar='%c' (0x%x) cannot be set (unsupported).\n", pSerialChars->BreakChar, pSerialChars->BreakChar);
SetLastError(ERROR_NOT_SUPPORTED);
result = FALSE; /* but keep on */
}
/* FIXME: Didn't find anything similar inside N_TTY. Develop a
* line discipline dedicated to the RDP redirection.
*/
DEBUG_WARN("EventChar='%c' cannot be set\n", pSerialChars->EventChar);
/* TMP: FIXME: Didn't find anything similar yet on Linux */
if (pSerialChars->EventChar != '\0')
{
DEBUG_WARN("EventChar='%c' (0x%x) cannot be set\n", pSerialChars->EventChar, pSerialChars->EventChar);
SetLastError(ERROR_NOT_SUPPORTED);
result = FALSE; /* but keep on */
}
upcomingTermios.c_cc[VSTART] = pSerialChars->XonChar;
@ -343,7 +346,7 @@ static BOOL _set_serial_chars(WINPR_COMM *pComm, const SERIAL_CHARS *pSerialChar
return FALSE;
}
return TRUE;
return result;
}
@ -360,23 +363,14 @@ static BOOL _get_serial_chars(WINPR_COMM *pComm, SERIAL_CHARS *pSerialChars)
ZeroMemory(pSerialChars, sizeof(SERIAL_CHARS));
if (currentTermios.c_lflag & ICANON)
{
pSerialChars->EofChar = currentTermios.c_cc[VEOF];
}
/* EofChar unsupported */
/* FIXME: see also: _set_serial_chars() */
if (currentTermios.c_iflag & INPCK)
pSerialChars->ErrorChar = '\0';
/* else '\0' is currently used anyway */
/* ErrorChar unsupported */
/* BreakChar unsupported */
/* FIXME: see also: _set_serial_chars() */
if (currentTermios.c_iflag & ~IGNBRK & BRKINT)
pSerialChars->BreakChar = '\0';
/* else '\0' is currently used anyway */
/* FIXME: see also: _set_serial_chars() */
pSerialChars->EventChar = '\0';
/* TMP: FIXME: see also: _set_serial_chars() */
/* EventChar */
pSerialChars->XonChar = currentTermios.c_cc[VSTART];
@ -548,6 +542,279 @@ static BOOL _get_line_control(WINPR_COMM *pComm, SERIAL_LINE_CONTROL *pLineContr
}
/* hard-coded in N_TTY */
#define TTY_THRESHOLD_THROTTLE 128 /* now based on remaining room */
#define TTY_THRESHOLD_UNTHROTTLE 128
static BOOL _set_handflow(WINPR_COMM *pComm, const SERIAL_HANDFLOW *pHandflow)
{
BOOL result = TRUE;
struct termios upcomingTermios;
/* logical XOR */
if ((!(pHandflow->ControlHandShake & SERIAL_DTR_CONTROL) && (pHandflow->FlowReplace & SERIAL_RTS_CONTROL)) ||
((pHandflow->ControlHandShake & SERIAL_DTR_CONTROL) && !(pHandflow->FlowReplace & SERIAL_RTS_CONTROL)))
{
DEBUG_WARN("SERIAL_DTR_CONTROL cannot be different SERIAL_RTS_CONTROL, HUPCL will be set according SERIAL_RTS_CONTROL.");
result = FALSE; /* but keep on */
}
ZeroMemory(&upcomingTermios, sizeof(struct termios));
if (tcgetattr(pComm->fd, &upcomingTermios) < 0)
{
SetLastError(ERROR_IO_DEVICE);
return FALSE;
}
/* ControlHandShake */
if (pHandflow->ControlHandShake & SERIAL_DTR_CONTROL)
{
upcomingTermios.c_cflag |= HUPCL;
}
else
{
upcomingTermios.c_cflag &= ~HUPCL;
/* FIXME: is the DTR line also needs to be forced to a disable state? */
}
if (pHandflow->ControlHandShake & SERIAL_DTR_HANDSHAKE)
{
/* DTR/DSR flow control not supported on Linux */
DEBUG_WARN("Attempt to use the unsupported SERIAL_DTR_HANDSHAKE feature.");
SetLastError(ERROR_NOT_SUPPORTED);
result = FALSE; /* but keep on */
}
if (pHandflow->ControlHandShake & SERIAL_CTS_HANDSHAKE)
{
upcomingTermios.c_cflag |= CRTSCTS;
}
else
{
upcomingTermios.c_cflag &= ~CRTSCTS;
}
if (pHandflow->ControlHandShake & SERIAL_DSR_HANDSHAKE)
{
/* DTR/DSR flow control not supported on Linux */
DEBUG_WARN("Attempt to use the unsupported SERIAL_DSR_HANDSHAKE feature.");
SetLastError(ERROR_NOT_SUPPORTED);
result = FALSE; /* but keep on */
}
if (pHandflow->ControlHandShake & SERIAL_DCD_HANDSHAKE)
{
/* DCD flow control not supported on Linux */
DEBUG_WARN("Attempt to use the unsupported SERIAL_DCD_HANDSHAKE feature.");
SetLastError(ERROR_NOT_SUPPORTED);
result = FALSE; /* but keep on */
}
// TMP: FIXME: could be implemented during read/write I/O
if (pHandflow->ControlHandShake & SERIAL_DSR_SENSITIVITY)
{
/* DSR line control not supported on Linux */
DEBUG_WARN("Attempt to use the unsupported SERIAL_DSR_SENSITIVITY feature.");
SetLastError(ERROR_NOT_SUPPORTED);
result = FALSE; /* but keep on */
}
// TMP: FIXME: could be implemented during read/write I/O
if (pHandflow->ControlHandShake & SERIAL_ERROR_ABORT)
{
/* Aborting operations on error not supported on Linux */
DEBUG_WARN("Attempt to use the unsupported SERIAL_ERROR_ABORT feature.");
SetLastError(ERROR_NOT_SUPPORTED);
result = FALSE; /* but keep on */
}
/* FlowReplace */
if (pHandflow->FlowReplace & SERIAL_AUTO_TRANSMIT)
{
upcomingTermios.c_iflag |= IXON;
}
else
{
upcomingTermios.c_iflag &= ~IXON;
}
if (pHandflow->FlowReplace & SERIAL_AUTO_RECEIVE)
{
upcomingTermios.c_iflag |= IXOFF;
}
else
{
upcomingTermios.c_iflag &= ~IXOFF;
}
// TMP: FIXME: could be implemented during read/write I/O
if (pHandflow->FlowReplace & SERIAL_ERROR_CHAR)
{
DEBUG_WARN("Attempt to use the unsupported SERIAL_ERROR_CHAR feature. A character with a parity error or framing error will be read as \0");
/* errors will be replaced by the character '\0' */
upcomingTermios.c_iflag &= ~IGNPAR;
}
else
{
upcomingTermios.c_iflag |= IGNPAR;
}
if (pHandflow->FlowReplace & SERIAL_NULL_STRIPPING)
{
upcomingTermios.c_iflag |= IGNBRK;
}
else
{
upcomingTermios.c_iflag &= ~IGNBRK;
}
// TMP: FIXME: could be implemented during read/write I/O
if (pHandflow->FlowReplace & SERIAL_BREAK_CHAR)
{
DEBUG_WARN("Attempt to use the unsupported SERIAL_BREAK_CHAR feature.");
SetLastError(ERROR_NOT_SUPPORTED);
result = FALSE; /* but keep on */
}
if (pHandflow->FlowReplace & SERIAL_RTS_CONTROL)
{
upcomingTermios.c_cflag |= HUPCL;
}
else
{
upcomingTermios.c_cflag &= ~HUPCL;
/* FIXME: is the RTS line also needs to be forced to a disable state? */
}
if (pHandflow->FlowReplace & SERIAL_RTS_HANDSHAKE)
{
upcomingTermios.c_cflag |= CRTSCTS;
}
else
{
upcomingTermios.c_cflag &= ~CRTSCTS;
}
// FIXME: could be implemented during read/write I/O
if (pHandflow->FlowReplace & SERIAL_XOFF_CONTINUE)
{
/* not supported on Linux */
DEBUG_WARN("Attempt to use the unsupported SERIAL_XOFF_CONTINUE feature.");
SetLastError(ERROR_NOT_SUPPORTED);
result = FALSE; /* but keep on */
}
/* XonLimit */
// FIXME: could be implemented during read/write I/O
if (pHandflow->XonLimit != TTY_THRESHOLD_UNTHROTTLE)
{
DEBUG_WARN("Attempt to set XonLimit with an unsupported value: %d", pHandflow->XonLimit);
SetLastError(ERROR_NOT_SUPPORTED);
result = FALSE; /* but keep on */
}
/* XoffChar */
// FIXME: could be implemented during read/write I/O
if (pHandflow->XoffLimit != TTY_THRESHOLD_THROTTLE)
{
DEBUG_WARN("Attempt to set XoffLimit with an unsupported value: %d", pHandflow->XoffLimit);
SetLastError(ERROR_NOT_SUPPORTED);
result = FALSE; /* but keep on */
}
if (_comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &upcomingTermios) < 0)
{
DEBUG_WARN("_comm_ioctl_tcsetattr failure: last-error: 0x0.8x", GetLastError());
return FALSE;
}
return result;
}
static BOOL _get_handflow(WINPR_COMM *pComm, SERIAL_HANDFLOW *pHandflow)
{
struct termios currentTermios;
ZeroMemory(&currentTermios, sizeof(struct termios));
if (tcgetattr(pComm->fd, &currentTermios) < 0)
{
SetLastError(ERROR_IO_DEVICE);
return FALSE;
}
/* ControlHandShake */
pHandflow->ControlHandShake = 0;
if (currentTermios.c_cflag & HUPCL)
pHandflow->ControlHandShake |= SERIAL_DTR_CONTROL;
/* SERIAL_DTR_HANDSHAKE unsupported */
if (currentTermios.c_cflag & CRTSCTS)
pHandflow->ControlHandShake |= SERIAL_CTS_HANDSHAKE;
/* SERIAL_DSR_HANDSHAKE unsupported */
/* SERIAL_DCD_HANDSHAKE unsupported */
/* SERIAL_DSR_SENSITIVITY unsupported */
/* SERIAL_ERROR_ABORT unsupported */
/* FlowReplace */
pHandflow->FlowReplace = 0;
if (currentTermios.c_iflag & IXON)
pHandflow->FlowReplace |= SERIAL_AUTO_TRANSMIT;
if (currentTermios.c_iflag & IXOFF)
pHandflow->FlowReplace |= SERIAL_AUTO_RECEIVE;
if (!(currentTermios.c_iflag & IGNPAR))
pHandflow->FlowReplace |= SERIAL_ERROR_CHAR;
if (currentTermios.c_iflag & IGNBRK)
pHandflow->FlowReplace |= SERIAL_NULL_STRIPPING;
/* SERIAL_BREAK_CHAR unsupported */
if (currentTermios.c_cflag & HUPCL)
pHandflow->FlowReplace |= SERIAL_RTS_CONTROL;
if (currentTermios.c_cflag & CRTSCTS)
pHandflow->FlowReplace |= SERIAL_RTS_HANDSHAKE;
/* SERIAL_XOFF_CONTINUE unsupported */
/* XonLimit */
pHandflow->XonLimit = TTY_THRESHOLD_UNTHROTTLE;
/* XoffLimit */
pHandflow->XoffLimit = TTY_THRESHOLD_THROTTLE;
return TRUE;
}
static REMOTE_SERIAL_DRIVER _SerialSys =
{
@ -559,7 +826,9 @@ static REMOTE_SERIAL_DRIVER _SerialSys =
.set_serial_chars = _set_serial_chars,
.get_serial_chars = _get_serial_chars,
.set_line_control = _set_line_control,
.get_line_control = _get_line_control
.get_line_control = _get_line_control,
.set_handflow = _set_handflow,
.get_handflow = _get_handflow,
};

View File

@ -11,6 +11,7 @@ set(${MODULE_PREFIX}_TESTS
TestSetCommState.c
TestSerialChars.c
TestControlSettings.c
TestHandflow.c
TestCommMonitor.c)
create_test_sourcelist(${MODULE_PREFIX}_SRCS

View File

@ -108,8 +108,6 @@ int TestCommConfig(int argc, char* argv[])
return EXIT_FAILURE;
}
/* TODO: */
dcb.BaudRate = CBR_57600;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
@ -120,7 +118,7 @@ int TestCommConfig(int argc, char* argv[])
if (!success)
{
fprintf(stderr, "SetCommState failure: GetLastError() = 0x%x\n", (int) GetLastError());
return 0;
return EXIT_FAILURE;
}
success = GetCommState(hComm, &dcb);
@ -131,8 +129,11 @@ int TestCommConfig(int argc, char* argv[])
return 0;
}
fprintf(stderr, "BaudRate: %d ByteSize: %d Parity: %d StopBits: %d\n",
(int) dcb.BaudRate, (int) dcb.ByteSize, (int) dcb.Parity, (int) dcb.StopBits);
if ((dcb.BaudRate != CBR_57600) || (dcb.ByteSize != 8) || (dcb.Parity != NOPARITY) || (dcb.StopBits != ONESTOPBIT))
{
fprintf(stderr, "Got an unexpeted value among: BaudRate: %d ByteSize: %d Parity: %d StopBits: %d\n",
(int) dcb.BaudRate, (int) dcb.ByteSize, (int) dcb.Parity, (int) dcb.StopBits);
}
CloseHandle(hComm);

View File

@ -0,0 +1,86 @@
/**
* WinPR: Windows Portable Runtime
* Serial Communication API
*
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <termios.h>
#include <winpr/comm.h>
#include <winpr/crt.h>
#include "../comm.h"
static BOOL test_SerialSys(HANDLE hComm)
{
// TMP: TODO:
return TRUE;
}
int TestHandflow(int argc, char* argv[])
{
BOOL result;
HANDLE hComm;
// TMP: FIXME: check if we can proceed with tests on the actual device, skip and warn otherwise but don't fail
result = DefineCommDevice("COM1", "/dev/ttyS0");
if (!result)
{
fprintf(stderr, "DefineCommDevice failure: 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
hComm = CreateFile("COM1",
GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, 0, NULL);
if (hComm == INVALID_HANDLE_VALUE)
{
fprintf(stderr, "CreateFileA failure: 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
_comm_setRemoteSerialDriver(hComm, RemoteSerialDriverSerialSys);
if (!test_SerialSys(hComm))
{
fprintf(stderr, "test_SerCxSys failure\n");
return EXIT_FAILURE;
}
/* _comm_setRemoteSerialDriver(hComm, RemoteSerialDriverSerCxSys); */
/* if (!test_SerCxSys(hComm)) */
/* { */
/* fprintf(stderr, "test_SerCxSys failure\n"); */
/* return EXIT_FAILURE; */
/* } */
/* _comm_setRemoteSerialDriver(hComm, RemoteSerialDriverSerCx2Sys); */
/* if (!test_SerCx2Sys(hComm)) */
/* { */
/* fprintf(stderr, "test_SerCxSys failure\n"); */
/* return EXIT_FAILURE; */
/* } */
if (!CloseHandle(hComm))
{
fprintf(stderr, "CloseHandle failure, GetLastError()=%0.8x\n", GetLastError());
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

View File

@ -18,6 +18,7 @@
*/
#include <stdio.h>
#include <termios.h>
#include <winpr/comm.h>
#include <winpr/crt.h>
@ -29,6 +30,16 @@ static BOOL test_SerCxSys(HANDLE hComm)
DCB dcb;
UCHAR XonChar, XoffChar;
struct termios currentTermios;
ZeroMemory(&currentTermios, sizeof(struct termios));
if (tcgetattr(((WINPR_COMM*)hComm)->fd, &currentTermios) < 0)
{
fprintf(stderr, "tcgetattr failure.\n");
return FALSE;
}
ZeroMemory(&dcb, sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
if (!GetCommState(hComm, &dcb))
@ -43,6 +54,14 @@ static BOOL test_SerCxSys(HANDLE hComm)
return FALSE;
}
/* retrieve Xon/Xoff chars */
if ((dcb.XonChar != currentTermios.c_cc[VSTART]) || (dcb.XoffChar != currentTermios.c_cc[VSTOP]))
{
fprintf(stderr, "test_SerCxSys failure, could not retrieve XonChar and XoffChar\n");
return FALSE;
}
/* swap XonChar/XoffChar */
XonChar = dcb.XonChar;
@ -98,9 +117,9 @@ static BOOL test_SerCx2Sys(HANDLE hComm)
return FALSE;
}
if ((dcb.XonChar != '\0') || (dcb.XoffChar != '\0') || (dcb.ErrorChar != '\0') || (dcb.EofChar != '\0') || (dcb.EvtChar != '\0'))
if ((dcb.ErrorChar != '\0') || (dcb.EofChar != '\0') || (dcb.EvtChar != '\0') || (dcb.XonChar != '\0') || (dcb.XoffChar != '\0'))
{
fprintf(stderr, "test_SerCx2Sys failure, expected all characters to '\0'\n");
fprintf(stderr, "test_SerCx2Sys failure, expected all characters to be: '\\0'\n");
return FALSE;
}

View File

@ -314,6 +314,7 @@ static BOOL test_generic(HANDLE hComm)
return TRUE;
}
int TestSetCommState(int argc, char* argv[])
{
BOOL result;