⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 win32serial.c

📁 vxworks源码源码解读是学习vxworks的最佳途径
💻 C
字号:
/* win32Serial.c - Serial communications routines using WIN32 API functions  */

/*
Modification History
--------------------
01f,25jan99,elg  Add Flow Control on Serial Backend (SPR 22159)
01e,18nov98,c_c  Worked around a problem with WaitCommEvent ().
		 + added a mutex to synchronize all driver accesses.
01d,28oct98,c_c  Rewritten to be fully supported by WIN95.
01c,13feb98,c_c  Solved some timeout Pb.
01b,21jan98,c_c  Now using asynchronous mechanism for I/O.
		 Implemented select-like API. to pause the thread.
1a 17jan95 wmd  written.

*/

/* 
 * We will use the asynchronous notification which can be set with the overlap
 * mechanism under NT. With this, we can put a thread into a sleep while
 * waiting for incoming char.
 */

/* includes */

#include <windows.h>
#include <stdio.h>
#include "win32Serial.h"

/* defines */

#define TIMEOUT_VALUE		10	/* timeout default value */

#define MULTIPLIER(time, nbytes)	(time/nbytes * 1000)

/* typedefs */

/* externals */

/* locals */

static HANDLE		hComm = NULL;	/* COMM handle */
static OVERLAPPED	overlappedRead;	/* overlap struct for read ops  */
static OVERLAPPED	overlappedWrite;/* overlap struct for write ops */
static HANDLE		char2readEvent;	/* Characters to read Event */
static HANDLE		want2writeEvent;/* A thread want to write */
static HANDLE		writtenEvent;	/* all chars written Event */
static HANDLE		driverMutex;	/* Serial driver Mutex */
static char		InputBuffer[1800];/* input buffer (at least one MTU) */
static DWORD		ReadIndex;/* Index of fisrt char to read in buffer */
static DWORD		nbByteRead;	/* nb char read in a call */
static BOOL		pendingChar;	/* Is there something pending ? */
static BOOL		charWritten=FALSE;	/* char have been written */

/* Forward declarations */

static int win32FlushOutput
    (
    HANDLE hcom
    );

static int win32FlushInput
    (
    HANDLE hcom
    );


/*****************************************************************************
*
* win32SerialRead - Reads characters from the serial line.
*
* This routine reads len bytes from the serial communications device.
*
* RETURNS :
*	number of read chars,
*	-1 on error;
*/
int win32SerialRead
    (
    HANDLE hcom, 			/* where to read from ... */
    char *buf,				/* placeholder */ 
    DWORD len				/* length of buffer */
    )
    {
    DWORD buflen = 0;
    BOOL status;

    /* If we have no chars presents in our buffer do a read op. */

    if (!pendingChar)
	{
	if (WaitForSingleObject (driverMutex, INFINITE) != WAIT_OBJECT_0)
	    {
	    return -1;
	    }

	ReadIndex  = 0;
	nbByteRead = 0;
	ResetEvent (char2readEvent);
	status = ReadFile (hcom, 
			  InputBuffer, 
			  len<sizeof (InputBuffer)?len:sizeof (InputBuffer),
			  &nbByteRead, 
			  &overlappedRead);

	if (status == FALSE)
	    {
	    if (GetLastError ()!= ERROR_IO_PENDING)
		{
		ReleaseMutex (driverMutex);
		return -1;		/* error during read op */
		}
	    
	    status = GetOverlappedResult (hcom, &overlappedRead,
						&nbByteRead, TRUE);
	    if (status == FALSE)
		{
		ReleaseMutex (driverMutex);
		return -1;		/* error during read op */
		}
	    }
	ResetEvent (char2readEvent);
	ReleaseMutex (driverMutex);
	}

    /* Now we have something to read */

    /* compute number char to copy */

    buflen = (nbByteRead < len?nbByteRead:len);
    memcpy (buf, &InputBuffer[ReadIndex], buflen );

    /* adjust index */

    if (len < nbByteRead)		/* still bytes to read */
	{
	pendingChar = TRUE;
	nbByteRead -= len;
	ReadIndex  += len;
	}
    else				/* buffer empty */
	{
	pendingChar = FALSE;
	ReadIndex  = 0;
	nbByteRead = 0;
	}

    return buflen;
    }

/*****************************************************************************
*
* win32SerialWrite - Write bytes on the serial line.
*
* This routine writes len chars from str to the serial port.
*
* RETURNS :
*       number of chars written,
*       -1 on error;
*/

int win32SerialWrite 
    (
    HANDLE hcom, 			/* where to send the data */
    const char *str, 			/* data buffer */
    DWORD len				/* length of data */
    )
    {
    BOOL	status;
    DWORD	writtenBytes;
    DWORD	totalWrittenBytes = 0;


    /* 
     * Release the eventual thread blocked in the win32SerialSelect (), just to
     * be sure that we are now the only thead dealing with the serial line
     */

    PulseEvent (want2writeEvent);
    
    if (WaitForSingleObject (driverMutex, INFINITE) != WAIT_OBJECT_0)
	{
	return -1;
	}

    /* write data to the line... */

    do
	{
	ResetEvent (writtenEvent);		/* clear the event */
	status = WriteFile (hcom, &str[totalWrittenBytes],
	                    len-totalWrittenBytes, &writtenBytes,
			    &overlappedWrite);

	/* ...and wait till last char is sent. */

	if (status == FALSE)
	    {
	    if (GetLastError () == ERROR_IO_PENDING)
		{
		status = GetOverlappedResult (hcom, &overlappedWrite,
					      &writtenBytes, TRUE);
		 if (!status)
		    {
		    ReleaseMutex (driverMutex);
		    return 0;
		    }
		}
	    else
		{
		ReleaseMutex (driverMutex);
		return -1;
		}
	    }
	    totalWrittenBytes += writtenBytes;
	} while (totalWrittenBytes < len);

    ReleaseMutex (driverMutex);
    ResetEvent (writtenEvent);
    charWritten = TRUE;

    return totalWrittenBytes;
    }



/*****************************************************************************
*
* win32SerialOpen - Opens a serial communications channel,
*
* This routine opens the given serial device for reading and writting.
* <baudRate> specifies the speed of the serial link with the target.
* <hardFlowControl> specifies if there is a CTS/RTS flow control.
* 
* RETURNS: the handle on the open device on success, or -1 otherwise.
*
*/

HANDLE win32SerialOpen 
    (
    char *	devname, 			/* device to open (COM1, ...) */
    int 	baudRate,			/* line speed */
    BOOL	hardFlowControl			/* CTS/RTS flow control */
    )
    {
    DCB dcb;
    COMMTIMEOUTS timeouts;

    HANDLE hCom;
    BOOL    fSuccess;
    char deviceName[] = "COMX";

    deviceName[3] = devname[3];

    /* Serial driver Mutex creation */

    driverMutex = CreateMutex (
				NULL,	// pointer to security attributes 
				FALSE,	// not owned
				NULL	// no name
				); 

    /* End select event creation */

    want2writeEvent = CreateEvent (
				NULL,	// pointer to security attributes 
				TRUE,	// Manual reset 
				FALSE,	// No char present
				NULL	// no name
				); 

    /* Char presence Event creation */

    char2readEvent = CreateEvent (
				NULL,	// pointer to security attributes 
				TRUE,	// Manual reset 
				FALSE,	// No char present
				NULL	// no name
				); 

    /* Written chars Event creation */

    writtenEvent = CreateEvent (
				NULL,	// pointer to security attributes 
				TRUE,	// Manual reset 
				FALSE,	// No char present
				NULL	// no name
				); 

    if ((char2readEvent == (HANDLE)INVALID_HANDLE_VALUE)||
	(writtenEvent == (HANDLE)INVALID_HANDLE_VALUE)	||
	(want2writeEvent == (HANDLE)INVALID_HANDLE_VALUE))
	{
	/* too bad !!*/
	return  (HANDLE) -1;
	}

    /* afterward, open the device */

    hCom = CreateFile (deviceName,
		       GENERIC_READ | GENERIC_WRITE,
		       0,	/* share: Must be zero for comm resouces */
		       NULL,	/* no security attrs */
		       OPEN_EXISTING,	/* must use for comm devices */
		       FILE_FLAG_OVERLAPPED,	/* we will process async I/O */
		       (void*)NULL);	/* hTemplate */

    if (hCom == (HANDLE)INVALID_HANDLE_VALUE)
	{
	/* unlucky */
	return  (HANDLE) -1;
	}


    /* get the current configuration */

    if ( (fSuccess = GetCommState (hCom, &dcb)) == FALSE)
	{
	return (HANDLE) -1;
	}

    /*
     * fill in DCB with:
     * - baud = baudRate (9600 is the default),
     * - 8 data bits, 
     * -  no parity,
     * - 1 stop bit
     * no special signal handled (DTR, CTS, DSR)
     */

    dcb.BaudRate	= baudRate;
    dcb.ByteSize	= 8;
    dcb.Parity		= NOPARITY;
    dcb.StopBits	= ONESTOPBIT;
    dcb.fOutX		= FALSE;
    dcb.fInX		= FALSE;
    dcb.fOutxCtsFlow	= FALSE;
    dcb.fOutxDsrFlow	= FALSE;
    dcb.fDtrControl	= DTR_CONTROL_DISABLE;
    dcb.fDsrSensitivity = FALSE;
    dcb.fRtsControl	= RTS_CONTROL_DISABLE;
    
    /* set the CTS/RTS flow control */

    if (hardFlowControl)
	{
    	dcb.fOutxCtsFlow = TRUE;		/* CTS output flow control */
	dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;	/* RTS handshaking */
	dcb.fDtrControl = DTR_CONTROL_ENABLE;	/* set DTR signal */
	}

    if ((fSuccess = SetCommState (hCom, &dcb)) == FALSE)
	{
	return (HANDLE) -1;
	}

    /* 
     * Init the timeout value  :
     *    Set a timeout of 2s max for synchronous read.
     */

    GetCommTimeouts (hCom, &timeouts);
    timeouts.ReadIntervalTimeout = 0;
    timeouts.ReadTotalTimeoutMultiplier = MULTIPLIER (TIMEOUT_VALUE, 1);
    timeouts.ReadTotalTimeoutConstant = 2000;	/* set a timeout of 2s max */
    timeouts.WriteTotalTimeoutMultiplier = 0;
    timeouts.WriteTotalTimeoutConstant = 0;
    SetCommTimeouts (hCom, &timeouts);

    ReadIndex = 0;			/* init the index */

    memset (&overlappedRead, 0, sizeof (overlappedRead));
    overlappedRead.hEvent = char2readEvent;
    memset (&overlappedWrite, 0, sizeof (overlappedWrite));
    overlappedWrite.hEvent = writtenEvent;
    pendingChar = FALSE;
    SetCommMask (hCom, EV_RXCHAR);	/* we will poll the Rx line */

    /* OK !! */
    hComm = hCom;			/* save the Handle */
    return hCom;
    }

/*****************************************************************************
*
*  win32SerialSelect - Select-like routine for WIN32 serial.
*
*  Routine to poll the serial port for waitval seconds.
*	If waitval = -1 blocks infinitely.
*   
* RETURNS: 
*	 1 : serial port has character(s) for input.
*	 0 : nothing to read within the timeout. 
*	-1 : error.
*/

int win32SerialSelect 
    (
    int waitval				/* timeout (in second) */
    )
    {
    int		status, returnedStatus;
    DWORD	commEvent;		/* expected event */
    HANDLE	objects2Wait4[2];	/* objects to wait for array */

    /* Check if we have characters left in our internal buffer */

    if (pendingChar)
	{
	return 1;
	}

    /* adjust for milliseconds */

    if (waitval != -1)			/* polling forever */
	waitval *= 1000;

    /* prevent other to perform I/O */

    if (WaitForSingleObject (driverMutex, INFINITE) != WAIT_OBJECT_0)
	{
	return -1;
	}

    /* Check if we are receiving some characters... */

select_again :

    ResetEvent (char2readEvent);
    status = WaitCommEvent (hComm, &commEvent, &overlappedRead);

    if ( (!status) && (GetLastError ()!= ERROR_IO_PENDING) )
	{
	ReleaseMutex (driverMutex);	/* other can write */
	return -1;			/* error during wait op */
	}

    /*
     * wait till :
     *	- timeout,
     *	- char incomes,
     *	- another thread wants to write
     */

    objects2Wait4[0] = want2writeEvent;
    objects2Wait4[1] = char2readEvent;

    switch ( WaitForMultipleObjects (2, objects2Wait4, FALSE, waitval) )
    	{
	case WAIT_OBJECT_0 :		/* Another thread wants the line !! */

	case WAIT_TIMEOUT :
	    /*
	     * On timeout or want2writeEvent, dont'consider that we
	     * have something to read
	     * We will cancel the posted request, to make sure
	     * that another thread write request can succeed.
	     * resetting the event mask will make the GetOverlappedResult call
	     * to set the commEvent to 0. This will be interpreted as
	     * nothing to read.
	     */

	    SetCommMask (hComm, EV_RXCHAR);	/* fall through the next case */

	case (WAIT_OBJECT_0+1) :	/* We have received something. */

	    status = GetOverlappedResult (hComm, &overlappedRead,
					      &nbByteRead, TRUE);
	    if (status)
		{

		returnedStatus = (commEvent&EV_RXCHAR)?1:0;

		// For some unknown reasons, we may be awaken although there's 
		// no pending char in the buffer. It seems to happen after a
		// write Op has been issued. If the select occurs after a write
		// Op (charWritten flag) will will retry once the select Op to
		// work around this error.

		if (returnedStatus)
		    {
		    DWORD	commErrors;
		    COMSTAT	commStatus;// To get the pending input bytes

		    if (ClearCommError (hComm, &commErrors, &commStatus))
			{
			returnedStatus = (commStatus.cbInQue>0)?1:0;

			// Retry once if this select comes after a write Op

			if ((!returnedStatus) && (charWritten))
			    {
			    charWritten = FALSE;
			    goto select_again;
			    }
			}
		    }
		break;
		}

	default :			/* Problem !! */
		returnedStatus = -1;
	}

    /*
     * Three reasons can bring us here :
     *	- Char have been read,
     *	- Timeout occured,
     *	- win32SerialWrite pulsed want2write event.
     * Anyway, we will clear the event to be coordonated with the current state.
     */

    charWritten = FALSE;
    ResetEvent (char2readEvent);
    ReleaseMutex (driverMutex);	/* other can write */

    return returnedStatus;
    }

/*****************************************************************************
*
* win32SerialClose - close the handle for the communications resource.
*
*/
void win32SerialClose 
    (
    HANDLE hcom				/* device to close */
    )
    {
    win32FlushOutput (hcom);
    win32FlushInput (hcom);
    CloseHandle (hcom);
    CloseHandle (char2readEvent);
    CloseHandle (want2writeEvent);
    CloseHandle (writtenEvent);
    CloseHandle (driverMutex);
    }

/*****************************************************************************
*
* win32FlushOutput - Flush pending output.
*
*/
int win32FlushOutput
    (
    HANDLE hcom
    )
    {
    return (FlushFileBuffers (hcom));
    }
 
 
/*****************************************************************************
*
* win32FlushInput - Flush pending input buffer, the data is lost.
*
*/
int win32FlushInput
    (
    HANDLE hcom
    )
    {
    return (PurgeComm (hcom, PURGE_RXCLEAR));
    }
 
 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -