Comunicazione tramite seriale

di il
30 risposte

30 Risposte - Pagina 2

  • Re: Comunicazione tramite seriale

    No cambia di poco. Ma quello lo guardiamo poi. In tanto procurati i dati.
    A dopo
  • Re: Comunicazione tramite seriale

    Eccomi qui con le info:
    - baud 115200
    - data size va a 8 bit
    - parity none
    - handshake off

    Se servono altre informazioni dimmi pure che chiedo.
  • Re: Comunicazione tramite seriale

    Ok prendendo adesso il mio esempio.
    
          CSerial serial;
           LONG lastError = serial.Open("COM2");
           if(lastError == ERROR_SUCCESS)
           {
              serial.Setup(CSerial::EBaud115200,CSerial::EData8,CSerial::EParNone,CSerial::EStop1);
               serial.SetupHandshaking(CSerial::EHandshakeOff);
               serial.SetupReadTimeouts(CSerial::EReadTimeoutNonblocking);
              //prosegui con la scrittura dei dati
              for(int i = 0; i < r; i++)
                  serial.Write(mat[i],3); //scrivo 3 dati della i-esima riga
           }
           else
           //Messaggio errore
        }
    
    Così dovrebbe funzionare. Manca il bit di stop nelle tue info.Ho assunto un bit di stop pari ad uno.
  • Re: Comunicazione tramite seriale

    Mi da molti errori di compilazione, perchè sembra che molti dei termini usati non vengano riconosciuti come appartenenti alla classe CSerial.
    I parametri non riconosciuti sono: EBaud115200, EData8, EParNone, EStop1, SetupHandshaking, EHandshakeOff, SetupReadTimeouts, EReadTimeoutNonblocking, Write. Sinceramente non capisco perchè.
    Se hai bisgono di vedere il file .h e quello .cpp relativo alla classe CSerial dimmelo pure che te li posto.

    Grazie ancora
  • Re: Comunicazione tramite seriale

    Posta il codice completo che facciamo prima.
  • Re: Comunicazione tramite seriale

    Serial.h
    
    // Serial.h
    
    #ifndef __SERIAL_H__
    #define __SERIAL_H__
    
    #define FC_DTRDSR       0x01
    #define FC_RTSCTS       0x02
    #define FC_XONXOFF      0x04
    #define ASCII_BEL       0x07
    #define ASCII_BS        0x08
    #define ASCII_LF        0x0A
    #define ASCII_CR        0x0D
    #define ASCII_XON       0x11
    #define ASCII_XOFF      0x13
    
    class CSerial
    {
    
    public:
    	CSerial();
    	~CSerial();
    
    	BOOL Open(int nPort = 2, int nBaud = 9600);
    	BOOL Close(void);
    
    	int ReadData(void *, int);
    	int SendData(const char *, int);
    	int ReadDataWaiting(void);
    
    	BOOL IsOpened(void){ return(m_bOpened); }
    
    protected:
    	BOOL WriteCommByte(unsigned char);
    
    	HANDLE m_hIDComDev;
    	OVERLAPPED m_OverlappedRead, m_OverlappedWrite;
    	BOOL m_bOpened;
    
    };
    
    #endif
    

    Serial.cpp
    
    // Serial.cpp
    
    #include "stdafx.h"
    #include <iostream>
    #include <crtdbg.h>
    #include <tchar.h>
    #include <windows.h>
    #include "Serial.h"
    
    CSerial::CSerial()
    {
    
    	memset(&m_OverlappedRead, 0, sizeof(OVERLAPPED));
    	memset(&m_OverlappedWrite, 0, sizeof(OVERLAPPED));
    	m_hIDComDev = NULL;
    	m_bOpened = FALSE;
    
    }
    
    CSerial::~CSerial()
    {
    
    	Close();
    
    }
    
    BOOL CSerial::Open(int nPort, int nBaud)
    {
    
    	if (m_bOpened) return(TRUE);
    
    	char szPort[15];
    	char szComParams[50];
    	DCB dcb;
    
    	wsprintf(szPort, "COM%d", nPort);
    	m_hIDComDev = CreateFile(szPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
    	if (m_hIDComDev == NULL) return(FALSE);
    
    	memset(&m_OverlappedRead, 0, sizeof(OVERLAPPED));
    	memset(&m_OverlappedWrite, 0, sizeof(OVERLAPPED));
    
    	COMMTIMEOUTS CommTimeOuts;
    	CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF;
    	CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
    	CommTimeOuts.ReadTotalTimeoutConstant = 0;
    	CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
    	CommTimeOuts.WriteTotalTimeoutConstant = 5000;
    	SetCommTimeouts(m_hIDComDev, &CommTimeOuts);
    
    	wsprintf(szComParams, "COM%d:%d,n,8,1", nPort, nBaud);
    
    	m_OverlappedRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    	m_OverlappedWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    
    	dcb.DCBlength = sizeof(DCB);
    	GetCommState(m_hIDComDev, &dcb);
    	dcb.BaudRate = nBaud;
    	dcb.ByteSize = 8;
    	unsigned char ucSet;
    	ucSet = (unsigned char)((FC_RTSCTS & FC_DTRDSR) != 0);
    	ucSet = (unsigned char)((FC_RTSCTS & FC_RTSCTS) != 0);
    	ucSet = (unsigned char)((FC_RTSCTS & FC_XONXOFF) != 0);
    	if (!SetCommState(m_hIDComDev, &dcb) ||
    		!SetupComm(m_hIDComDev, 10000, 10000) ||
    		m_OverlappedRead.hEvent == NULL ||
    		m_OverlappedWrite.hEvent == NULL){
    		DWORD dwError = GetLastError();
    		if (m_OverlappedRead.hEvent != NULL) CloseHandle(m_OverlappedRead.hEvent);
    		if (m_OverlappedWrite.hEvent != NULL) CloseHandle(m_OverlappedWrite.hEvent);
    		CloseHandle(m_hIDComDev);
    		return(FALSE);
    	}
    
    	m_bOpened = TRUE;
    
    	return(m_bOpened);
    
    }
    
    BOOL CSerial::Close(void)
    {
    
    	if (!m_bOpened || m_hIDComDev == NULL) return(TRUE);
    
    	if (m_OverlappedRead.hEvent != NULL) CloseHandle(m_OverlappedRead.hEvent);
    	if (m_OverlappedWrite.hEvent != NULL) CloseHandle(m_OverlappedWrite.hEvent);
    	CloseHandle(m_hIDComDev);
    	m_bOpened = FALSE;
    	m_hIDComDev = NULL;
    
    	return(TRUE);
    
    }
    
    BOOL CSerial::WriteCommByte(unsigned char ucByte)
    {
    	BOOL bWriteStat;
    	DWORD dwBytesWritten;
    
    	bWriteStat = WriteFile(m_hIDComDev, (LPSTR)&ucByte, 1, &dwBytesWritten, &m_OverlappedWrite);
    	if (!bWriteStat && (GetLastError() == ERROR_IO_PENDING)){
    		if (WaitForSingleObject(m_OverlappedWrite.hEvent, 1000)) dwBytesWritten = 0;
    		else{
    			GetOverlappedResult(m_hIDComDev, &m_OverlappedWrite, &dwBytesWritten, FALSE);
    			m_OverlappedWrite.Offset += dwBytesWritten;
    		}
    	}
    
    	return(TRUE);
    
    }
    
    int CSerial::SendData(const char *buffer, int size)
    {
    
    	if (!m_bOpened || m_hIDComDev == NULL) return(0);
    
    	DWORD dwBytesWritten = 0;
    	int i;
    	for (i = 0; i<size; i++){
    		WriteCommByte(buffer[i]);
    		dwBytesWritten++;
    	}
    
    	return((int)dwBytesWritten);
    
    }
    
    int CSerial::ReadDataWaiting(void)
    {
    
    	if (!m_bOpened || m_hIDComDev == NULL) return(0);
    
    	DWORD dwErrorFlags;
    	COMSTAT ComStat;
    
    	ClearCommError(m_hIDComDev, &dwErrorFlags, &ComStat);
    
    	return((int)ComStat.cbInQue);
    
    }
    
    int CSerial::ReadData(void *buffer, int limit)
    {
    
    	if (!m_bOpened || m_hIDComDev == NULL) return(0);
    
    	BOOL bReadStatus;
    	DWORD dwBytesRead, dwErrorFlags;
    	COMSTAT ComStat;
    
    	ClearCommError(m_hIDComDev, &dwErrorFlags, &ComStat);
    	if (!ComStat.cbInQue) return(0);
    
    	dwBytesRead = (DWORD)ComStat.cbInQue;
    	if (limit < (int)dwBytesRead) dwBytesRead = (DWORD)limit;
    
    	bReadStatus = ReadFile(m_hIDComDev, buffer, dwBytesRead, &dwBytesRead, &m_OverlappedRead);
    	if (!bReadStatus){
    		if (GetLastError() == ERROR_IO_PENDING){
    			WaitForSingleObject(m_OverlappedRead.hEvent, 2000);
    			return((int)dwBytesRead);
    		}
    		return(0);
    	}
    
    	return((int)dwBytesRead);
    
    }
    
    Il file Main è quello che ho postato prima.
  • Re: Comunicazione tramite seriale

    Credo di aver capito il problema. La mia classe CSerial è diversa dalla tua. Forse ho trovato quella a cui fai riferimento tu. Ora provo.
  • Re: Comunicazione tramite seriale

    Ok ho trovato la classe corretta, infatti tutti quegli errori di prima non li ho più.
    Adesso ho un solo errore di compilazione, ed è nel file Serial.h. Riguarda il termine "SERIAL_DEFAULT_OVERLAPPED", che mi dice non essere stato definito.

    Lascia perdere i codici che ti ho postato prima. Ora ti posto il file Serial.h corretto, dove èerò compare questo strano errore.

    Serial.h
    
    // The following serial classes are available:
    //
    // CSerial      - Serial communication support.
    // CSerialEx    - Serial communication with listener thread for events
    // CSerialSync  - Serial communication with synchronized event handler
    // CSerialWnd   - Asynchronous serial support, which uses the Win32
    //                message queue for event notification.
    // CSerialMFC   - Preferred class to use in MFC-based GUI windows.
    // 
    //
    // Pros:
    // -----
    //	- Easy to use (hides a lot of nasty Win32 stuff)
    //	- Fully ANSI and Unicode aware
    //
    // Cons:
    // -----
    //  - Little less flexibility then native Win32 API, however you can
    //    use this API at the same time for features which are missing
    //    from this class.
    //  - Incompatible with Windows 95 or Windows NT v3.51 (or earlier),
    //    because CancelIo isn't support on these platforms. Define the
    //	  SERIAL_NO_CANCELIO macro for support of these platforms as
    //	  well. When this macro is defined, then only time-out values of
    //	  0 or INFINITE are valid.
    //
    //
    // Copyright (C) 1999-2003 Ramon de Klein
    //                         (Ramon.de.Klein@ict.nl)
    #ifndef _CSERIAL_
    #define _CSERIAL_
    class CSerial
    {
    	// Class enumerations
    public:
    	// Communication event
    	typedef enum
    	{
    		EEventUnknown = -1,			// Unknown event
    		EEventNone = 0,				// Event trigged without cause
    		EEventBreak = EV_BREAK,		// A break was detected on input
    		EEventCTS = EV_CTS,		// The CTS signal changed state
    		EEventDSR = EV_DSR,		// The DSR signal changed state
    		EEventError = EV_ERR,		// A line-status error occurred
    		EEventRing = EV_RING,		// A ring indicator was detected
    		EEventRLSD = EV_RLSD,		// The RLSD signal changed state
    		EEventRecv = EV_RXCHAR,		// Data is received on input
    		EEventRcvEv = EV_RXFLAG,		// Event character was received on input
    		EEventSend = EV_TXEMPTY,	// Last character on output was sent
    		EEventPrinterError = EV_PERR,		// Printer error occured
    		EEventRx80Full = EV_RX80FULL,	// Receive buffer is 80 percent full
    		EEventProviderEvt1 = EV_EVENT1,		// Provider specific event 1
    		EEventProviderEvt2 = EV_EVENT2,		// Provider specific event 2
    	}
    	EEvent;
    
    	// Baudrate
    	typedef enum
    	{
    		EBaudUnknown = -1,			// Unknown
    		EBaud110 = CBR_110,		// 110 bits/sec
    		EBaud300 = CBR_300,		// 300 bits/sec
    		EBaud600 = CBR_600,		// 600 bits/sec
    		EBaud1200 = CBR_1200,	// 1200 bits/sec
    		EBaud2400 = CBR_2400,	// 2400 bits/sec
    		EBaud4800 = CBR_4800,	// 4800 bits/sec
    		EBaud9600 = CBR_9600,	// 9600 bits/sec
    		EBaud14400 = CBR_14400,	// 14400 bits/sec
    		EBaud19200 = CBR_19200,	// 19200 bits/sec (default)
    		EBaud38400 = CBR_38400,	// 38400 bits/sec
    		EBaud56000 = CBR_56000,	// 56000 bits/sec
    		EBaud57600 = CBR_57600,	// 57600 bits/sec
    		EBaud115200 = CBR_115200,	// 115200 bits/sec
    		EBaud128000 = CBR_128000,	// 128000 bits/sec
    		EBaud256000 = CBR_256000,	// 256000 bits/sec
    	}
    	EBaudrate;
    
    	// Data bits (5-8)
    	typedef enum
    	{
    		EDataUnknown = -1,			// Unknown
    		EData5 = 5,			// 5 bits per byte
    		EData6 = 6,			// 6 bits per byte
    		EData7 = 7,			// 7 bits per byte
    		EData8 = 8			// 8 bits per byte (default)
    	}
    	EDataBits;
    
    	// Parity scheme
    	typedef enum
    	{
    		EParUnknown = -1,			// Unknown
    		EParNone = NOPARITY,		// No parity (default)
    		EParOdd = ODDPARITY,	// Odd parity
    		EParEven = EVENPARITY,	// Even parity
    		EParMark = MARKPARITY,	// Mark parity
    		EParSpace = SPACEPARITY	// Space parity
    	}
    	EParity;
    
    	// Stop bits
    	typedef enum
    	{
    		EStopUnknown = -1,			// Unknown
    		EStop1 = ONESTOPBIT,	// 1 stopbit (default)
    		EStop1_5 = ONE5STOPBITS,// 1.5 stopbit
    		EStop2 = TWOSTOPBITS	// 2 stopbits
    	}
    	EStopBits;
    
    	// Handshaking
    	typedef enum
    	{
    		EHandshakeUnknown = -1,	// Unknown
    		EHandshakeOff = 0,	// No handshaking
    		EHandshakeHardware = 1,	// Hardware handshaking (RTS/CTS)
    		EHandshakeSoftware = 2	// Software handshaking (XON/XOFF)
    	}
    	EHandshake;
    
    	// Timeout settings
    	typedef enum
    	{
    		EReadTimeoutUnknown = -1,	// Unknown
    		EReadTimeoutNonblocking = 0,	// Always return immediately
    		EReadTimeoutBlocking = 1	// Block until everything is retrieved
    	}
    	EReadTimeout;
    
    	// Communication errors
    	typedef enum
    	{
    		EErrorUnknown = 0,			// Unknown
    		EErrorBreak = CE_BREAK,	// Break condition detected
    		EErrorFrame = CE_FRAME,	// Framing error
    		EErrorIOE = CE_IOE,		// I/O device error
    		EErrorMode = CE_MODE,	// Unsupported mode
    		EErrorOverrun = CE_OVERRUN,	// Character buffer overrun, next byte is lost
    		EErrorRxOver = CE_RXOVER,	// Input buffer overflow, byte lost
    		EErrorParity = CE_RXPARITY,// Input parity error
    		EErrorTxFull = CE_TXFULL	// Output buffer full
    	}
    	EError;
    
    	// Port availability
    	typedef enum
    	{
    		EPortUnknownError = -1,		// Unknown error occurred
    		EPortAvailable = 0,		// Port is available
    		EPortNotAvailable = 1,		// Port is not present
    		EPortInUse = 2		// Port is in use
    
    	}
    	EPort;
    
    	// Construction
    public:
    	CSerial();
    	virtual ~CSerial();
    
    	// Operations
    public:
    	// Check if particular COM-port is available (static method).
    	static EPort CheckPort(LPCTSTR lpszDevice);
    
    	// Open the serial communications for a particular COM port. You
    	// need to use the full devicename (i.e. "COM1") to open the port.
    	// It's possible to specify the size of the input/output queues.
    	virtual LONG Open(LPCTSTR lpszDevice, DWORD dwInQueue = 0, DWORD dwOutQueue = 0, bool fOverlapped = SERIAL_DEFAULT_OVERLAPPED);
    
    	// Close the serial port.
    	virtual LONG Close(void);
    
    	// Setup the communication settings such as baudrate, databits,
    	// parity and stopbits. The default settings are applied when the
    	// device has been opened. Call this function if these settings do
    	// not apply for your application. If you prefer to use integers
    	// instead of the enumerated types then just cast the integer to
    	// the required type. So the following two initializations are
    	// equivalent:
    	//
    	//   Setup(EBaud9600,EData8,EParNone,EStop1)
    	//
    	// or
    	//
    	//   Setup(EBaudrate(9600),EDataBits(8),EParity(NOPARITY),EStopBits(ONESTOPBIT))
    	//
    	// In the latter case, the types are not validated. So make sure
    	// that you specify the appropriate values.
    	virtual LONG Setup(EBaudrate eBaudrate = EBaud9600,
    		EDataBits eDataBits = EData8,
    		EParity   eParity = EParNone,
    		EStopBits eStopBits = EStop1);
    
    	// Set/clear the event character. When this byte is being received
    	// on the serial port then the EEventRcvEv event is signalled,
    	// when the mask has been set appropriately. If the fAdjustMask flag
    	// has been set, then the event mask is automatically adjusted.
    	virtual LONG SetEventChar(BYTE bEventChar, bool fAdjustMask = true);
    
    	// Set the event mask, which indicates what events should be
    	// monitored. The WaitEvent method can only monitor events that
    	// have been enabled. The default setting only monitors the
    	// error events and data events. An application may choose to
    	// monitor CTS. DSR, RLSD, etc as well.
    	virtual LONG SetMask(DWORD dwMask = EEventBreak | EEventError | EEventRecv);
    
    	// The WaitEvent method waits for one of the events that are
    	// enabled (see SetMask).
    	virtual LONG WaitEvent(LPOVERLAPPED lpOverlapped = 0, DWORD dwTimeout = INFINITE);
    
    	// Setup the handshaking protocol. There are three forms of
    	// handshaking:
    	//
    	// 1) No handshaking, so data is always send even if the receiver
    	//    cannot handle the data anymore. This can lead to data loss,
    	//    when the sender is able to transmit data faster then the
    	//    receiver can handle.
    	// 2) Hardware handshaking, where the RTS/CTS lines are used to
    	//    indicate if data can be sent. This mode requires that both
    	//    ports and the cable support hardware handshaking. Hardware
    	//    handshaking is the most reliable and efficient form of
    	//    handshaking available, but is hardware dependant.
    	// 3) Software handshaking, where the XON/XOFF characters are used
    	//    to throttle the data. A major drawback of this method is that
    	//    these characters cannot be used for data anymore.
    	virtual LONG SetupHandshaking(EHandshake eHandshake);
    
    	// Read operations can be blocking or non-blocking. You can use
    	// this method to setup wether to use blocking or non-blocking
    	// reads. Non-blocking reads is the default, which is required
    	// for most applications.
    	//
    	// 1) Blocking reads, which will cause the 'Read' method to block
    	//    until the requested number of bytes have been read. This is
    	//    useful if you know how many data you will receive.
    	// 2) Non-blocking reads, which will read as many bytes into your
    	//    buffer and returns almost immediately. This is often the
    	//    preferred setting.
    	virtual LONG SetupReadTimeouts(EReadTimeout eReadTimeout);
    
    	// Obtain communication settings
    	virtual EBaudrate  GetBaudrate(void);
    	virtual EDataBits  GetDataBits(void);
    	virtual EParity    GetParity(void);
    	virtual EStopBits  GetStopBits(void);
    	virtual EHandshake GetHandshaking(void);
    	virtual DWORD      GetEventMask(void);
    	virtual BYTE       GetEventChar(void);
    
    	// Write data to the serial port. Note that we are only able to
    	// send ANSI strings, because it probably doesn't make sense to
    	// transmit Unicode strings to an application.
    	virtual LONG Write(const void* pData, size_t iLen, DWORD* pdwWritten = 0, LPOVERLAPPED lpOverlapped = 0, DWORD dwTimeout = INFINITE);
    	virtual LONG Write(LPCSTR pString, DWORD* pdwWritten = 0, LPOVERLAPPED lpOverlapped = 0, DWORD dwTimeout = INFINITE);
    
    	// Read data from the serial port. Refer to the description of
    	// the 'SetupReadTimeouts' for an explanation about (non) blocking
    	// reads and how to use this.
    	virtual LONG Read(void* pData, size_t iLen, DWORD* pdwRead = 0, LPOVERLAPPED lpOverlapped = 0, DWORD dwTimeout = INFINITE);
    
    	// Send a break
    	LONG Break(void);
    
    	// Determine what caused the event to trigger
    	EEvent GetEventType(void);
    
    	// Obtain the error
    	EError GetError(void);
    
    	// Obtain the COMM and event handle
    	HANDLE GetCommHandle(void)		{ return m_hFile; }
    
    	// Check if com-port is opened
    	bool IsOpen(void) const		{ return (m_hFile != 0); }
    
    	// Obtain last error status
    	LONG GetLastError(void) const	{ return m_lLastError; }
    
    	// Obtain CTS/DSR/RING/RLSD settings
    	bool GetCTS(void);
    	bool GetDSR(void);
    	bool GetRing(void);
    	bool GetRLSD(void);
    
    	// Purge all buffers
    	LONG Purge(void);
    
    protected:
    	// Internal helper class which wraps DCB structure
    	class CDCB : public DCB
    	{
    	public:
    		CDCB() { DCBlength = sizeof(DCB); }
    	};
    
    	// Attributes
    protected:
    	LONG	m_lLastError;		// Last serial error
    	HANDLE	m_hFile;			// File handle
    	EEvent	m_eEvent;			// Event type
    	DWORD	m_dwEventMask;		// Event mask
    
    #ifndef SERIAL_NO_OVERLAPPED
    	HANDLE	m_hevtOverlapped;	// Event handle for internal overlapped operations
    #endif
    
    protected:
    	// Check the requirements
    	void CheckRequirements(LPOVERLAPPED lpOverlapped, DWORD dwTimeout) const;
    
    	// CancelIo wrapper (for Win95 compatibility)
    	BOOL CancelCommIo(void);
    };
    
    #endif	// __SERIAL_H
    
    
  • Re: Comunicazione tramite seriale

    Non so cosa hai combinato col copia incolla ma l'originale sta così

    Serial.h
    //	Serial.h - Definition of the CSerial class
    //
    //	Copyright (C) 1999-2003 Ramon de Klein (Ramon.de.Klein@ict.nl)
    //
    // This library is free software; you can redistribute it and/or
    // modify it under the terms of the GNU Lesser General Public
    // License as published by the Free Software Foundation; either
    // version 2.1 of the License, or (at your option) any later version.
    // 
    // This library is distributed in the hope that it will be useful,
    // but WITHOUT ANY WARRANTY; without even the implied warranty of
    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    // Lesser General Public License for more details.
    // 
    // You should have received a copy of the GNU Lesser General Public
    // License along with this library; if not, write to the Free Software
    // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    
    
    #ifndef __SERIAL_H
    #define __SERIAL_H
    
    
    //////////////////////////////////////////////////////////////////////
    // The SERIAL_DEFAULT_OVERLAPPED defines if the default open mode uses
    // overlapped I/O. When overlapped I/O is available (normal Win32
    // platforms) it uses overlapped I/O. Windows CE doesn't allow the use
    // of overlapped I/O, so it is disabled there by default.
    
    #ifndef SERIAL_DEFAULT_OVERLAPPED
    #ifndef SERIAL_NO_OVERLAPPED
    #define SERIAL_DEFAULT_OVERLAPPED	true
    #else
    #define SERIAL_DEFAULT_OVERLAPPED	false
    #endif
    #endif
    
    
    //////////////////////////////////////////////////////////////////////
    //
    // CSerial - Win32 wrapper for serial communications
    //
    // Serial communication often causes a lot of problems. This class
    // tries to supply an easy to use interface to deal with serial
    // devices.
    //
    // The class is actually pretty ease to use. You only need to open
    // the COM-port, where you need to specify the basic serial
    // communication parameters. You can also choose to setup handshaking
    // and read timeout behaviour.
    //
    // The following serial classes are available:
    //
    // CSerial      - Serial communication support.
    // CSerialEx    - Serial communication with listener thread for events
    // CSerialSync  - Serial communication with synchronized event handler
    // CSerialWnd   - Asynchronous serial support, which uses the Win32
    //                message queue for event notification.
    // CSerialMFC   - Preferred class to use in MFC-based GUI windows.
    // 
    //
    // Pros:
    // -----
    //	- Easy to use (hides a lot of nasty Win32 stuff)
    //	- Fully ANSI and Unicode aware
    //
    // Cons:
    // -----
    //  - Little less flexibility then native Win32 API, however you can
    //    use this API at the same time for features which are missing
    //    from this class.
    //  - Incompatible with Windows 95 or Windows NT v3.51 (or earlier),
    //    because CancelIo isn't support on these platforms. Define the
    //	  SERIAL_NO_CANCELIO macro for support of these platforms as
    //	  well. When this macro is defined, then only time-out values of
    //	  0 or INFINITE are valid.
    //
    //
    // Copyright (C) 1999-2003 Ramon de Klein
    //                         (Ramon.de.Klein@ict.nl)
    
    class CSerial
    {
    // Class enumerations
    public:
    	// Communication event
    	typedef enum
    	{
    		EEventUnknown  	   = -1,			// Unknown event
    		EEventNone  	   = 0,				// Event trigged without cause
    		EEventBreak 	   = EV_BREAK,		// A break was detected on input
    		EEventCTS   	   = EV_CTS,		// The CTS signal changed state
    		EEventDSR   	   = EV_DSR,		// The DSR signal changed state
    		EEventError 	   = EV_ERR,		// A line-status error occurred
    		EEventRing  	   = EV_RING,		// A ring indicator was detected
    		EEventRLSD  	   = EV_RLSD,		// The RLSD signal changed state
    		EEventRecv  	   = EV_RXCHAR,		// Data is received on input
    		EEventRcvEv 	   = EV_RXFLAG,		// Event character was received on input
    		EEventSend		   = EV_TXEMPTY,	// Last character on output was sent
    		EEventPrinterError = EV_PERR,		// Printer error occured
    		EEventRx80Full	   = EV_RX80FULL,	// Receive buffer is 80 percent full
    		EEventProviderEvt1 = EV_EVENT1,		// Provider specific event 1
    		EEventProviderEvt2 = EV_EVENT2,		// Provider specific event 2
    	} 
    	EEvent;
    
    	// Baudrate
    	typedef enum
    	{
    		EBaudUnknown = -1,			// Unknown
    		EBaud110     = CBR_110,		// 110 bits/sec
    		EBaud300     = CBR_300,		// 300 bits/sec
    		EBaud600     = CBR_600,		// 600 bits/sec
    		EBaud1200    = CBR_1200,	// 1200 bits/sec
    		EBaud2400    = CBR_2400,	// 2400 bits/sec
    		EBaud4800    = CBR_4800,	// 4800 bits/sec
    		EBaud9600    = CBR_9600,	// 9600 bits/sec
    		EBaud14400   = CBR_14400,	// 14400 bits/sec
    		EBaud19200   = CBR_19200,	// 19200 bits/sec (default)
    		EBaud38400   = CBR_38400,	// 38400 bits/sec
    		EBaud56000   = CBR_56000,	// 56000 bits/sec
    		EBaud57600   = CBR_57600,	// 57600 bits/sec
    		EBaud115200  = CBR_115200,	// 115200 bits/sec
    		EBaud128000  = CBR_128000,	// 128000 bits/sec
    		EBaud256000  = CBR_256000,	// 256000 bits/sec
    	}
    	EBaudrate;
    
    	// Data bits (5-8)
    	typedef enum
    	{
    		EDataUnknown = -1,			// Unknown
    		EData5       =  5,			// 5 bits per byte
    		EData6       =  6,			// 6 bits per byte
    		EData7       =  7,			// 7 bits per byte
    		EData8       =  8			// 8 bits per byte (default)
    	}
    	EDataBits;
    
    	// Parity scheme
    	typedef enum
    	{
    		EParUnknown = -1,			// Unknown
    		EParNone    = NOPARITY,		// No parity (default)
    		EParOdd     = ODDPARITY,	// Odd parity
    		EParEven    = EVENPARITY,	// Even parity
    		EParMark    = MARKPARITY,	// Mark parity
    		EParSpace   = SPACEPARITY	// Space parity
    	}
    	EParity;
    
    	// Stop bits
    	typedef enum
    	{
    		EStopUnknown = -1,			// Unknown
    		EStop1       = ONESTOPBIT,	// 1 stopbit (default)
    		EStop1_5     = ONE5STOPBITS,// 1.5 stopbit
    		EStop2       = TWOSTOPBITS	// 2 stopbits
    	} 
    	EStopBits;
    
    	// Handshaking
    	typedef enum
    	{
    		EHandshakeUnknown		= -1,	// Unknown
    		EHandshakeOff			=  0,	// No handshaking
    		EHandshakeHardware		=  1,	// Hardware handshaking (RTS/CTS)
    		EHandshakeSoftware		=  2	// Software handshaking (XON/XOFF)
    	} 
    	EHandshake;
    
    	// Timeout settings
    	typedef enum
    	{
    		EReadTimeoutUnknown		= -1,	// Unknown
    		EReadTimeoutNonblocking	=  0,	// Always return immediately
    		EReadTimeoutBlocking	=  1	// Block until everything is retrieved
    	}
    	EReadTimeout;
    
    	// Communication errors
    	typedef enum
    	{
    		EErrorUnknown = 0,			// Unknown
    		EErrorBreak   = CE_BREAK,	// Break condition detected
    		EErrorFrame   = CE_FRAME,	// Framing error
    		EErrorIOE     = CE_IOE,		// I/O device error
    		EErrorMode    = CE_MODE,	// Unsupported mode
    		EErrorOverrun = CE_OVERRUN,	// Character buffer overrun, next byte is lost
    		EErrorRxOver  = CE_RXOVER,	// Input buffer overflow, byte lost
    		EErrorParity  = CE_RXPARITY,// Input parity error
    		EErrorTxFull  = CE_TXFULL	// Output buffer full
    	}
    	EError;
    
    	// Port availability
    	typedef enum
    	{
    		EPortUnknownError = -1,		// Unknown error occurred
    		EPortAvailable    =  0,		// Port is available
    		EPortNotAvailable =  1,		// Port is not present
    		EPortInUse        =  2		// Port is in use
    
    	} 
    	EPort;
    
    // Construction
    public:
    	CSerial();
    	virtual ~CSerial();
    
    // Operations
    public:
    	// Check if particular COM-port is available (static method).
    	static EPort CheckPort (LPCTSTR lpszDevice);
    
    	// Open the serial communications for a particular COM port. You
    	// need to use the full devicename (i.e. "COM1") to open the port.
    	// It's possible to specify the size of the input/output queues.
    	virtual LONG Open (LPCTSTR lpszDevice, DWORD dwInQueue = 0, DWORD dwOutQueue = 0, bool fOverlapped = SERIAL_DEFAULT_OVERLAPPED);
    
    	// Close the serial port.
    	virtual LONG Close ();
    
    	// Setup the communication settings such as baudrate, databits,
    	// parity and stopbits. The default settings are applied when the
    	// device has been opened. Call this function if these settings do
    	// not apply for your application. If you prefer to use integers
    	// instead of the enumerated types then just cast the integer to
    	// the required type. So the following two initializations are
    	// equivalent:
    	//
    	//   Setup(EBaud9600,EData8,EParNone,EStop1)
    	//
    	// or
    	//
    	//   Setup(EBaudrate(9600),EDataBits(8),EParity(NOPARITY),EStopBits(ONESTOPBIT))
    	//
    	// In the latter case, the types are not validated. So make sure
    	// that you specify the appropriate values.
    	virtual LONG Setup (EBaudrate eBaudrate = EBaud9600,
    						EDataBits eDataBits = EData8,
    						EParity   eParity   = EParNone,
    						EStopBits eStopBits = EStop1);
    
    	// Set/clear the event character. When this byte is being received
    	// on the serial port then the EEventRcvEv event is signalled,
    	// when the mask has been set appropriately. If the fAdjustMask flag
    	// has been set, then the event mask is automatically adjusted.
    	virtual LONG SetEventChar (BYTE bEventChar, bool fAdjustMask = true);
    
    	// Set the event mask, which indicates what events should be
    	// monitored. The WaitEvent method can only monitor events that
    	// have been enabled. The default setting only monitors the
    	// error events and data events. An application may choose to
    	// monitor CTS. DSR, RLSD, etc as well.
    	virtual LONG SetMask (DWORD dwMask = EEventBreak|EEventError|EEventRecv);
    
    	// The WaitEvent method waits for one of the events that are
    	// enabled (see SetMask).
    	virtual LONG WaitEvent (LPOVERLAPPED lpOverlapped = 0, DWORD dwTimeout = INFINITE);
    
    	// Setup the handshaking protocol. There are three forms of
    	// handshaking:
    	//
    	// 1) No handshaking, so data is always send even if the receiver
    	//    cannot handle the data anymore. This can lead to data loss,
    	//    when the sender is able to transmit data faster then the
    	//    receiver can handle.
    	// 2) Hardware handshaking, where the RTS/CTS lines are used to
    	//    indicate if data can be sent. This mode requires that both
    	//    ports and the cable support hardware handshaking. Hardware
    	//    handshaking is the most reliable and efficient form of
    	//    handshaking available, but is hardware dependant.
    	// 3) Software handshaking, where the XON/XOFF characters are used
    	//    to throttle the data. A major drawback of this method is that
    	//    these characters cannot be used for data anymore.
    	virtual LONG SetupHandshaking (EHandshake eHandshake);
    
    	// Read operations can be blocking or non-blocking. You can use
    	// this method to setup wether to use blocking or non-blocking
    	// reads. Non-blocking reads is the default, which is required
    	// for most applications.
    	//
    	// 1) Blocking reads, which will cause the 'Read' method to block
    	//    until the requested number of bytes have been read. This is
    	//    useful if you know how many data you will receive.
    	// 2) Non-blocking reads, which will read as many bytes into your
    	//    buffer and returns almost immediately. This is often the
    	//    preferred setting.
    	virtual LONG SetupReadTimeouts (EReadTimeout eReadTimeout);
    
    	// Obtain communication settings
    	virtual EBaudrate  GetBaudrate    ();
    	virtual EDataBits  GetDataBits    ();
    	virtual EParity    GetParity      ();
    	virtual EStopBits  GetStopBits    ();
    	virtual EHandshake GetHandshaking ();
    	virtual DWORD      GetEventMask   ();
    	virtual BYTE       GetEventChar   ();
    
    	// Write data to the serial port. Note that we are only able to
    	// send ANSI strings, because it probably doesn't make sense to
    	// transmit Unicode strings to an application.
    	virtual LONG Write (const void* pData, size_t iLen, DWORD* pdwWritten = 0, LPOVERLAPPED lpOverlapped = 0, DWORD dwTimeout = INFINITE);
    	virtual LONG Write (LPCSTR pString, DWORD* pdwWritten = 0, LPOVERLAPPED lpOverlapped = 0, DWORD dwTimeout = INFINITE);
    
    	// Read data from the serial port. Refer to the description of
    	// the 'SetupReadTimeouts' for an explanation about (non) blocking
    	// reads and how to use this.
    	virtual LONG Read (void* pData, size_t iLen, DWORD* pdwRead = 0, LPOVERLAPPED lpOverlapped = 0, DWORD dwTimeout = INFINITE);
    
    	// Send a break
    	LONG Break ();
    
    	// Determine what caused the event to trigger
    	EEvent GetEventType ();
    
    	// Obtain the error
    	EError GetError ();
    
    	// Obtain the COMM and event handle
    	HANDLE GetCommHandle ()		{ return m_hFile; }
    
    	// Check if com-port is opened
    	bool IsOpen () const		{ return (m_hFile != 0); }
    
    	// Obtain last error status
    	LONG GetLastError () const	{ return m_lLastError; }
    
    	// Obtain CTS/DSR/RING/RLSD settings
    	bool GetCTS ();
    	bool GetDSR ();
    	bool GetRing ();
    	bool GetRLSD ();
    
    	// Purge all buffers
    	LONG Purge ();
    
    protected:
    	// Internal helper class which wraps DCB structure
    	class CDCB : public DCB
    	{
    	public:
    		CDCB() { DCBlength = sizeof(DCB); }
    	};
    
    // Attributes
    protected:
    	LONG	m_lLastError;		// Last serial error
    	HANDLE	m_hFile;			// File handle
    	EEvent	m_eEvent;			// Event type
    	DWORD	m_dwEventMask;		// Event mask
    
    #ifndef SERIAL_NO_OVERLAPPED
    	HANDLE	m_hevtOverlapped;	// Event handle for internal overlapped operations
    #endif
    
    protected:
    	// Check the requirements
    	void CheckRequirements (LPOVERLAPPED lpOverlapped, DWORD dwTimeout) const;
    
    	// CancelIo wrapper (for Win95 compatibility)
    	BOOL CancelCommIo ();
    };
    
    #endif	// __SERIAL_H
    
    Serial.cpp
    //	Serial.cpp - Implementation of the CSerial class
    //
    //	Copyright (C) 1999-2003 Ramon de Klein (Ramon.de.Klein@ict.nl)
    //
    // This library is free software; you can redistribute it and/or
    // modify it under the terms of the GNU Lesser General Public
    // License as published by the Free Software Foundation; either
    // version 2.1 of the License, or (at your option) any later version.
    // 
    // This library is distributed in the hope that it will be useful,
    // but WITHOUT ANY WARRANTY; without even the implied warranty of
    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    // Lesser General Public License for more details.
    // 
    // You should have received a copy of the GNU Lesser General Public
    // License along with this library; if not, write to the Free Software
    // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    
    
    //////////////////////////////////////////////////////////////////////
    // Include the standard header files
    
    #include "stdafx.h"
    
    //////////////////////////////////////////////////////////////////////
    // Include module headerfile
    
    #include "Serial.h"
    
    
    //////////////////////////////////////////////////////////////////////
    // Disable warning C4127: conditional expression is constant, which
    // is generated when using the _RPTF and _ASSERTE macros.
    
    #pragma warning(disable: 4127)
    
    
    //////////////////////////////////////////////////////////////////////
    // Enable debug memory manager
    
    #ifdef _DEBUG
    
    #ifdef THIS_FILE
    #undef THIS_FILE
    #endif
    
    static const char THIS_FILE[] = __FILE__;
    #define new DEBUG_NEW
    
    #endif
    
    
    //////////////////////////////////////////////////////////////////////
    // Helper methods
    
    inline void CSerial::CheckRequirements (LPOVERLAPPED lpOverlapped, DWORD dwTimeout) const
    {
    #ifdef SERIAL_NO_OVERLAPPED
    
    	// Check if an overlapped structure has been specified
    	if (lpOverlapped || (dwTimeout != INFINITE))
    	{
    		// Quit application
    		::MessageBox(0,_T("Overlapped I/O and time-outs are not supported, when overlapped I/O is disabled."),_T("Serial library"), MB_ICONERROR | MB_TASKMODAL);
    		::DebugBreak();
    		::ExitProcess(0xFFFFFFF);
    	}
    
    #endif
    
    #ifdef SERIAL_NO_CANCELIO
    
    	// Check if 0 or INFINITE time-out has been specified, because
    	// the communication I/O cannot be cancelled.
    	if ((dwTimeout != 0) && (dwTimeout != INFINITE))
    	{
    		// Quit application
    		::MessageBox(0,_T("Timeouts are not supported, when SERIAL_NO_CANCELIO is defined"),_T("Serial library"), MB_ICONERROR | MB_TASKMODAL);
    		::DebugBreak();
    		::ExitProcess(0xFFFFFFF);
    	}
    
    #endif	// SERIAL_NO_CANCELIO
    
    	// Avoid warnings
    	(void) dwTimeout;
    	(void) lpOverlapped;
    }
    
    inline BOOL CSerial::CancelCommIo ()
    {
    #ifdef SERIAL_NO_CANCELIO
    	// CancelIo shouldn't have been called at this point
    	::DebugBreak();
    	return FALSE;
    #else
    
    	// Cancel the I/O request
    	return ::CancelIo(m_hFile);
    
    #endif	// SERIAL_NO_CANCELIO
    }
    
    
    //////////////////////////////////////////////////////////////////////
    // Code
    
    CSerial::CSerial ()
    	: m_lLastError(ERROR_SUCCESS)
    	, m_hFile(0)
    	, m_eEvent(EEventNone)
    	, m_dwEventMask(0)
    #ifndef SERIAL_NO_OVERLAPPED
    	, m_hevtOverlapped(0)
    #endif
    {
    }
    
    CSerial::~CSerial ()
    {
    	// If the device is already closed,
    	// then we don't need to do anything.
    	if (m_hFile)
    	{
    		// Display a warning
    		_RPTF0(_CRT_WARN,"CSerial::~CSerial - Serial port not closed\n");
    
    		// Close implicitly
    		Close();
    	}
    }
    
    CSerial::EPort CSerial::CheckPort (LPCTSTR lpszDevice)
    {
    	// Try to open the device
    	HANDLE hFile = ::CreateFile(lpszDevice, 
    						   GENERIC_READ|GENERIC_WRITE, 
    						   0, 
    						   0, 
    						   OPEN_EXISTING, 
    						   0,
    						   0);
    
    	// Check if we could open the device
    	if (hFile == INVALID_HANDLE_VALUE)
    	{
    		// Display error
    		switch (::GetLastError())
    		{
    		case ERROR_FILE_NOT_FOUND:
    			// The specified COM-port does not exist
    			return EPortNotAvailable;
    
    		case ERROR_ACCESS_DENIED:
    			// The specified COM-port is in use
    			return EPortInUse;
    
    		default:
    			// Something else is wrong
    			return EPortUnknownError;
    		}
    	}
    
    	// Close handle
    	::CloseHandle(hFile);
    
    	// Port is available
    	return EPortAvailable;
    }
    
    LONG CSerial::Open (LPCTSTR lpszDevice, DWORD dwInQueue, DWORD dwOutQueue, bool fOverlapped)
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Check if the port isn't already opened
    	if (m_hFile)
    	{
    		m_lLastError = ERROR_ALREADY_INITIALIZED;
    		_RPTF0(_CRT_WARN,"CSerial::Open - Port already opened\n");
    		return m_lLastError;
    	}
    
    	// Open the device
    	m_hFile = ::CreateFile(lpszDevice,
    						   GENERIC_READ|GENERIC_WRITE,
    						   0,
    						   0,
    						   OPEN_EXISTING,
    						   fOverlapped?FILE_FLAG_OVERLAPPED:0,
    						   0);
    	if (m_hFile == INVALID_HANDLE_VALUE)
    	{
    		// Reset file handle
    		m_hFile = 0;
    
    		// Display error
    		m_lLastError = ::GetLastError();
    		_RPTF0(_CRT_WARN, "CSerial::Open - Unable to open port\n");
    		return m_lLastError;
    	}
    
    #ifndef SERIAL_NO_OVERLAPPED
    	// We cannot have an event handle yet
    	_ASSERTE(m_hevtOverlapped == 0);
    
    	// Create the event handle for internal overlapped operations (manual reset)
    	if (fOverlapped)
    	{
    		m_hevtOverlapped = ::CreateEvent(0,true,false,0);
    		if (m_hevtOverlapped == 0)
    		{
    			// Obtain the error information
    			m_lLastError = ::GetLastError();
    			_RPTF0(_CRT_WARN,"CSerial::Open - Unable to create event\n");
    
    			// Close the port
    			::CloseHandle(m_hFile);
    			m_hFile = 0;
    
    			// Return the error
    			return m_lLastError;
    		}
    	}
    #else
    	
    	// Overlapped flag shouldn't be specified
    	_ASSERTE(!fOverlapped);
    
    #endif
    
    	// Setup the COM-port
    	if (dwInQueue || dwOutQueue)
    	{
    		// Make sure the queue-sizes are reasonable sized. Win9X systems crash
    		// if the input queue-size is zero. Both queues need to be at least
    		// 16 bytes large.
    		_ASSERTE(dwInQueue >= 16);
    		_ASSERTE(dwOutQueue >= 16);
    
    		if (!::SetupComm(m_hFile,dwInQueue,dwOutQueue))
    		{
    			// Display a warning
    			long lLastError = ::GetLastError();
    			_RPTF0(_CRT_WARN,"CSerial::Open - Unable to setup the COM-port\n");
    
    			// Close the port
    			Close();
    
    			// Save last error from SetupComm
    			m_lLastError = lLastError;
    			return m_lLastError;	
    		}
    	}
    
    	// Setup the default communication mask
    	SetMask();
    
    	// Non-blocking reads is default
    	SetupReadTimeouts(EReadTimeoutNonblocking);
    
    	// Setup the device for default settings
    	COMMCONFIG commConfig = {0};
    	DWORD dwSize = sizeof(commConfig);
    	commConfig.dwSize = dwSize;
    	if (::GetDefaultCommConfig(lpszDevice,&commConfig,&dwSize))
    	{
    		// Set the default communication configuration
    		if (!::SetCommConfig(m_hFile,&commConfig,dwSize))
    		{
    			// Display a warning
    			_RPTF0(_CRT_WARN,"CSerial::Open - Unable to set default communication configuration.\n");
    		}
    	}
    	else
    	{
    		// Display a warning
    		_RPTF0(_CRT_WARN,"CSerial::Open - Unable to obtain default communication configuration.\n");
    	}
    
    	// Return successful
    	return m_lLastError;
    }
    
    LONG CSerial::Close ()
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// If the device is already closed,
    	// then we don't need to do anything.
    	if (m_hFile == 0)
    	{
    		// Display a warning
    		_RPTF0(_CRT_WARN,"CSerial::Close - Method called when device is not open\n");
    		return m_lLastError;
    	}
    
    #ifndef SERIAL_NO_OVERLAPPED
    	// Free event handle
    	if (m_hevtOverlapped)
    	{
    		::CloseHandle(m_hevtOverlapped);
    		m_hevtOverlapped = 0;
    	}
    #endif
    
    	// Close COM port
    	::CloseHandle(m_hFile);
    	m_hFile = 0;
    
    	// Return successful
    	return m_lLastError;
    }
    
    LONG CSerial::Setup (EBaudrate eBaudrate, EDataBits eDataBits, EParity eParity, EStopBits eStopBits)
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Check if the device is open
    	if (m_hFile == 0)
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_HANDLE;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN,"CSerial::Setup - Device is not opened\n");
    		return m_lLastError;
    	}
    
    	// Obtain the DCB structure for the device
    	CDCB dcb;
    	if (!::GetCommState(m_hFile,&dcb))
    	{
    		// Obtain the error code
    		m_lLastError = ::	GetLastError();
    
    		// Display a warning
    		_RPTF0(_CRT_WARN,"CSerial::Setup - Unable to obtain DCB information\n");
    		return m_lLastError;
    	}
    
    	// Set the new data
    	dcb.BaudRate = DWORD(eBaudrate);
    	dcb.ByteSize = BYTE(eDataBits);
    	dcb.Parity   = BYTE(eParity);
    	dcb.StopBits = BYTE(eStopBits);
    
    	// Determine if parity is used
    	dcb.fParity  = (eParity != EParNone);
    
    	// Set the new DCB structure
    	if (!::SetCommState(m_hFile,&dcb))
    	{
    		// Obtain the error code
    		m_lLastError = ::GetLastError();
    
    		// Display a warning
    		_RPTF0(_CRT_WARN,"CSerial::Setup - Unable to set DCB information\n");
    		return m_lLastError;
    	}
    
    	// Return successful
    	return m_lLastError;
    }
    
    LONG CSerial::SetEventChar (BYTE bEventChar, bool fAdjustMask)
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Check if the device is open
    	if (m_hFile == 0)
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_HANDLE;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN,"CSerial::SetEventChar - Device is not opened\n");
    		return m_lLastError;
    	}
    
    	// Obtain the DCB structure for the device
    	CDCB dcb;
    	if (!::GetCommState(m_hFile,&dcb))
    	{
    		// Obtain the error code
    		m_lLastError = ::GetLastError();
    
    		// Display a warning
    		_RPTF0(_CRT_WARN,"CSerial::SetEventChar - Unable to obtain DCB information\n");
    		return m_lLastError;
    	}
    
    	// Set the new event character
    	dcb.EvtChar = char(bEventChar);
    
    	// Adjust the event mask, to make sure the event will be received
    	if (fAdjustMask)
    	{
    		// Enable 'receive event character' event.  Note that this
    		// will generate an EEventNone if there is an asynchronous
    		// WaitCommEvent pending.
    		SetMask(GetEventMask() | EEventRcvEv);
    	}
    
    	// Set the new DCB structure
    	if (!::SetCommState(m_hFile,&dcb))
    	{
    		// Obtain the error code
    		m_lLastError = ::GetLastError();
    
    		// Display a warning
    		_RPTF0(_CRT_WARN,"CSerial::SetEventChar - Unable to set DCB information\n");
    		return m_lLastError;
    	}
    
    	// Return successful
    	return m_lLastError;
    }
    
    LONG CSerial::SetMask (DWORD dwEventMask)
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Check if the device is open
    	if (m_hFile == 0)
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_HANDLE;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN,"CSerial::SetMask - Device is not opened\n");
    		return m_lLastError;
    	}
    
    	// Set the new mask. Note that this will generate an EEventNone
    	// if there is an asynchronous WaitCommEvent pending.
    	if (!::SetCommMask(m_hFile,dwEventMask))
    	{
    		// Obtain the error code
    		m_lLastError = ::GetLastError();
    
    		// Display a warning
    		_RPTF0(_CRT_WARN,"CSerial::SetMask - Unable to set event mask\n");
    		return m_lLastError;
    	}
    
    	// Save event mask and return successful
    	m_dwEventMask = dwEventMask;
    	return m_lLastError;
    }
    
    LONG CSerial::WaitEvent (LPOVERLAPPED lpOverlapped, DWORD dwTimeout)
    {
    	// Check if time-outs are supported
    	CheckRequirements(lpOverlapped,dwTimeout);
    
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Check if the device is open
    	if (m_hFile == 0)
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_HANDLE;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN,"CSerial::WaitEvent - Device is not opened\n");
    		return m_lLastError;
    	}
    
    #ifndef SERIAL_NO_OVERLAPPED
    
    	// Check if an overlapped structure has been specified
    	if (!m_hevtOverlapped && (lpOverlapped || (dwTimeout != INFINITE)))
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_FUNCTION;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN,"CSerial::WaitEvent - Overlapped I/O is disabled, specified parameters are illegal.\n");
    		return m_lLastError;
    	}
    
    	// Wait for the event to happen
    	OVERLAPPED ovInternal;
    	if (!lpOverlapped && m_hevtOverlapped)
    	{
    		// Setup our own overlapped structure
    		memset(&ovInternal,0,sizeof(ovInternal));
    		ovInternal.hEvent = m_hevtOverlapped;
    
    		// Use our internal overlapped structure
    		lpOverlapped = &ovInternal;
    	}
    
    	// Make sure the overlapped structure isn't busy
    	_ASSERTE(!m_hevtOverlapped || HasOverlappedIoCompleted(lpOverlapped));
    
    	// Wait for the COM event
    	if (!::WaitCommEvent(m_hFile,LPDWORD(&m_eEvent),lpOverlapped))
    	{
    		// Set the internal error code
    		long lLastError = ::GetLastError();
    
    		// Overlapped operation in progress is not an actual error
    		if (lLastError != ERROR_IO_PENDING)
    		{
    			// Save the error
    			m_lLastError = lLastError;
    
    			// Issue an error and quit
    			_RPTF0(_CRT_WARN,"CSerial::WaitEvent - Unable to wait for COM event\n");
    			return m_lLastError;
    		}
    
    		// We need to block if the client didn't specify an overlapped structure
    		if (lpOverlapped == &ovInternal)
    		{
    			// Wait for the overlapped operation to complete
    			switch (::WaitForSingleObject(lpOverlapped->hEvent,dwTimeout))
    			{
    			case WAIT_OBJECT_0:
    				// The overlapped operation has completed
    				break;
    
    			case WAIT_TIMEOUT:
    				// Cancel the I/O operation
    				CancelCommIo();
    
    				// The operation timed out. Set the internal error code and quit
    				m_lLastError = ERROR_TIMEOUT;
    				return m_lLastError;
    
    			default:
    				// Set the internal error code
    				m_lLastError = ::GetLastError();
    
    				// Issue an error and quit
    				_RPTF0(_CRT_WARN,"CSerial::WaitEvent - Unable to wait until COM event has arrived\n");
    				return m_lLastError;
    			}
    		}
    	}
    	else
    	{
    		// The operation completed immediatly. Just to be sure
    		// we'll set the overlapped structure's event handle.
    		if (lpOverlapped)
    			::SetEvent(lpOverlapped->hEvent);
    	}
    #else
    
    	// Wait for the COM event
    	if (!::WaitCommEvent(m_hFile,LPDWORD(&m_eEvent),0))
    	{
    		// Set the internal error code
    		m_lLastError = ::GetLastError();
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN,"CSerial::WaitEvent - Unable to wait for COM event\n");
    		return m_lLastError;
    	}
    
    #endif
    
    	// Return successfully
    	return m_lLastError;
    }
    
    
    LONG CSerial::SetupHandshaking (EHandshake eHandshake)
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Check if the device is open
    	if (m_hFile == 0)
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_HANDLE;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN,"CSerial::SetupHandshaking - Device is not opened\n");
    		return m_lLastError;
    	}
    
    	// Obtain the DCB structure for the device
    	CDCB dcb;
    	if (!::GetCommState(m_hFile,&dcb))
    	{
    		// Obtain the error code
    		m_lLastError = ::GetLastError();
    
    		// Display a warning
    		_RPTF0(_CRT_WARN,"CSerial::SetupHandshaking - Unable to obtain DCB information\n");
    		return m_lLastError;
    	}
    
    	// Set the handshaking flags
    	switch (eHandshake)
    	{
    	case EHandshakeOff:
    		dcb.fOutxCtsFlow = false;					// Disable CTS monitoring
    		dcb.fOutxDsrFlow = false;					// Disable DSR monitoring
    		dcb.fDtrControl = DTR_CONTROL_DISABLE;		// Disable DTR monitoring
    		dcb.fOutX = false;							// Disable XON/XOFF for transmission
    		dcb.fInX = false;							// Disable XON/XOFF for receiving
    		dcb.fRtsControl = RTS_CONTROL_DISABLE;		// Disable RTS (Ready To Send)
    		break;
    
    	case EHandshakeHardware:
    		dcb.fOutxCtsFlow = true;					// Enable CTS monitoring
    		dcb.fOutxDsrFlow = true;					// Enable DSR monitoring
    		dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;	// Enable DTR handshaking
    		dcb.fOutX = false;							// Disable XON/XOFF for transmission
    		dcb.fInX = false;							// Disable XON/XOFF for receiving
    		dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;	// Enable RTS handshaking
    		break;
    
    	case EHandshakeSoftware:
    		dcb.fOutxCtsFlow = false;					// Disable CTS (Clear To Send)
    		dcb.fOutxDsrFlow = false;					// Disable DSR (Data Set Ready)
    		dcb.fDtrControl = DTR_CONTROL_DISABLE;		// Disable DTR (Data Terminal Ready)
    		dcb.fOutX = true;							// Enable XON/XOFF for transmission
    		dcb.fInX = true;							// Enable XON/XOFF for receiving
    		dcb.fRtsControl = RTS_CONTROL_DISABLE;		// Disable RTS (Ready To Send)
    		break;
    
    	default:
    		// This shouldn't be possible
    		_ASSERTE(false);
    		m_lLastError = E_INVALIDARG;
    		return m_lLastError;
    	}
    
    	// Set the new DCB structure
    	if (!::SetCommState(m_hFile,&dcb))
    	{
    		// Obtain the error code
    		m_lLastError = ::GetLastError();
    
    		// Display a warning
    		_RPTF0(_CRT_WARN,"CSerial::SetupHandshaking - Unable to set DCB information\n");
    		return m_lLastError;
    	}
    
    	// Return successful
    	return m_lLastError;
    }
    
    LONG CSerial::SetupReadTimeouts (EReadTimeout eReadTimeout)
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Check if the device is open
    	if (m_hFile == 0)
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_HANDLE;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN,"CSerial::SetupReadTimeouts - Device is not opened\n");
    		return m_lLastError;
    	}
    
    	// Determine the time-outs
    	COMMTIMEOUTS cto;
    	if (!::GetCommTimeouts(m_hFile,&cto))
    	{
    		// Obtain the error code
    		m_lLastError = ::GetLastError();
    
    		// Display a warning
    		_RPTF0(_CRT_WARN,"CSerial::SetupReadTimeouts - Unable to obtain timeout information\n");
    		return m_lLastError;
    	}
    
    	// Set the new timeouts
    	switch (eReadTimeout)
    	{
    	case EReadTimeoutBlocking:
    		cto.ReadIntervalTimeout = 0;
    		cto.ReadTotalTimeoutConstant = 0;
    		cto.ReadTotalTimeoutMultiplier = 0;
    		break;
    	case EReadTimeoutNonblocking:
    		cto.ReadIntervalTimeout = MAXDWORD;
    		cto.ReadTotalTimeoutConstant = 0;
    		cto.ReadTotalTimeoutMultiplier = 0;
    		break;
    	default:
    		// This shouldn't be possible
    		_ASSERTE(false);
    		m_lLastError = E_INVALIDARG;
    		return m_lLastError;
    	}
    
    	// Set the new DCB structure
    	if (!::SetCommTimeouts(m_hFile,&cto))
    	{
    		// Obtain the error code
    		m_lLastError = ::GetLastError();
    
    		// Display a warning
    		_RPTF0(_CRT_WARN,"CSerial::SetupReadTimeouts - Unable to set timeout information\n");
    		return m_lLastError;
    	}
    
    	// Return successful
    	return m_lLastError;
    }
    
    CSerial::EBaudrate CSerial::GetBaudrate ()
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Check if the device is open
    	if (m_hFile == 0)
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_HANDLE;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN,"CSerial::GetBaudrate - Device is not opened\n");
    		return EBaudUnknown;
    	}
    
    	// Obtain the DCB structure for the device
    	CDCB dcb;
    	if (!::GetCommState(m_hFile,&dcb))
    	{
    		// Obtain the error code
    		m_lLastError = ::GetLastError();
    
    		// Display a warning
    		_RPTF0(_CRT_WARN,"CSerial::GetBaudrate - Unable to obtain DCB information\n");
    		return EBaudUnknown;
    	}
    
    	// Return the appropriate baudrate
    	return EBaudrate(dcb.BaudRate);
    }
    
    CSerial::EDataBits CSerial::GetDataBits ()
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Check if the device is open
    	if (m_hFile == 0)
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_HANDLE;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN,"CSerial::GetDataBits - Device is not opened\n");
    		return EDataUnknown;
    	}
    
    	// Obtain the DCB structure for the device
    	CDCB dcb;
    	if (!::GetCommState(m_hFile,&dcb))
    	{
    		// Obtain the error code
    		m_lLastError = ::GetLastError();
    
    		// Display a warning
    		_RPTF0(_CRT_WARN,"CSerial::GetDataBits - Unable to obtain DCB information\n");
    		return EDataUnknown;
    	}
    
    	// Return the appropriate bytesize
    	return EDataBits(dcb.ByteSize);
    }
    
    CSerial::EParity CSerial::GetParity ()
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Check if the device is open
    	if (m_hFile == 0)
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_HANDLE;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN,"CSerial::GetParity - Device is not opened\n");
    		return EParUnknown;
    	}
    
    	// Obtain the DCB structure for the device
    	CDCB dcb;
    	if (!::GetCommState(m_hFile,&dcb))
    	{
    		// Obtain the error code
    		m_lLastError = ::GetLastError();
    
    		// Display a warning
    		_RPTF0(_CRT_WARN,"CSerial::GetParity - Unable to obtain DCB information\n");
    		return EParUnknown;
    	}
    
    	// Check if parity is used
    	if (!dcb.fParity)
    	{
    		// No parity
    		return EParNone;
    	}
    
    	// Return the appropriate parity setting
    	return EParity(dcb.Parity);
    }
    
    CSerial::EStopBits CSerial::GetStopBits ()
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Check if the device is open
    	if (m_hFile == 0)
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_HANDLE;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN,"CSerial::GetStopBits - Device is not opened\n");
    		return EStopUnknown;
    	}
    
    	// Obtain the DCB structure for the device
    	CDCB dcb;
    	if (!::GetCommState(m_hFile,&dcb))
    	{
    		// Obtain the error code
    		m_lLastError = ::GetLastError();
    
    		// Display a warning
    		_RPTF0(_CRT_WARN,"CSerial::GetStopBits - Unable to obtain DCB information\n");
    		return EStopUnknown;
    	}
    
    	// Return the appropriate stopbits
    	return EStopBits(dcb.StopBits);
    }
    
    DWORD CSerial::GetEventMask ()
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Check if the device is open
    	if (m_hFile == 0)
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_HANDLE;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN,"CSerial::GetEventMask - Device is not opened\n");
    		return 0;
    	}
    
    	// Return the event mask
    	return m_dwEventMask;
    }
    
    BYTE CSerial::GetEventChar ()
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Check if the device is open
    	if (m_hFile == 0)
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_HANDLE;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN,"CSerial::GetEventChar - Device is not opened\n");
    		return 0;
    	}
    
    	// Obtain the DCB structure for the device
    	CDCB dcb;
    	if (!::GetCommState(m_hFile,&dcb))
    	{
    		// Obtain the error code
    		m_lLastError = ::GetLastError();
    
    		// Display a warning
    		_RPTF0(_CRT_WARN,"CSerial::GetEventChar - Unable to obtain DCB information\n");
    		return 0;
    	}
    
    	// Set the new event character
    	return BYTE(dcb.EvtChar);
    }
    
    CSerial::EHandshake CSerial::GetHandshaking ()
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Check if the device is open
    	if (m_hFile == 0)
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_HANDLE;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN,"CSerial::GetHandshaking - Device is not opened\n");
    		return EHandshakeUnknown;
    	}
    
    	// Obtain the DCB structure for the device
    	CDCB dcb;
    	if (!::GetCommState(m_hFile,&dcb))
    	{
    		// Obtain the error code
    		m_lLastError = ::GetLastError();
    
    		// Display a warning
    		_RPTF0(_CRT_WARN,"CSerial::GetHandshaking - Unable to obtain DCB information\n");
    		return EHandshakeUnknown;
    	}
    
    	// Check if hardware handshaking is being used
    	if ((dcb.fDtrControl == DTR_CONTROL_HANDSHAKE) && (dcb.fRtsControl == RTS_CONTROL_HANDSHAKE))
    		return EHandshakeHardware;
    
    	// Check if software handshaking is being used
    	if (dcb.fOutX && dcb.fInX)
    		return EHandshakeSoftware;
    
    	// No handshaking is being used
    	return EHandshakeOff;
    }
    
    LONG CSerial::Write (const void* pData, size_t iLen, DWORD* pdwWritten, LPOVERLAPPED lpOverlapped, DWORD dwTimeout)
    {
    	// Check if time-outs are supported
    	CheckRequirements(lpOverlapped,dwTimeout);
    
    	// Overlapped operation should specify the pdwWritten variable
    	_ASSERTE(!lpOverlapped || pdwWritten);
    
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Use our own variable for read count
    	DWORD dwWritten;
    	if (pdwWritten == 0)
    	{
    		pdwWritten = &dwWritten;
    	}
    
    	// Reset the number of bytes written
    	*pdwWritten = 0;
    
    	// Check if the device is open
    	if (m_hFile == 0)
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_HANDLE;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN,"CSerial::Write - Device is not opened\n");
    		return m_lLastError;
    	}
    
    #ifndef SERIAL_NO_OVERLAPPED
    
    	// Check if an overlapped structure has been specified
    	if (!m_hevtOverlapped && (lpOverlapped || (dwTimeout != INFINITE)))
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_FUNCTION;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN,"CSerial::Write - Overlapped I/O is disabled, specified parameters are illegal.\n");
    		return m_lLastError;
    	}
    
    	// Wait for the event to happen
    	OVERLAPPED ovInternal;
    	if (!lpOverlapped && m_hevtOverlapped)
    	{
    		// Setup our own overlapped structure
    		memset(&ovInternal,0,sizeof(ovInternal));
    		ovInternal.hEvent = m_hevtOverlapped;
    
    		// Use our internal overlapped structure
    		lpOverlapped = &ovInternal;
    	}
    
    	// Make sure the overlapped structure isn't busy
    	_ASSERTE(!m_hevtOverlapped || HasOverlappedIoCompleted(lpOverlapped));
    
    	// Write the data
    	if (!::WriteFile(m_hFile,pData,iLen,pdwWritten,lpOverlapped))
    	{
    		// Set the internal error code
    		long lLastError = ::GetLastError();
    
    		// Overlapped operation in progress is not an actual error
    		if (lLastError != ERROR_IO_PENDING)
    		{
    			// Save the error
    			m_lLastError = lLastError;
    
    			// Issue an error and quit
    			_RPTF0(_CRT_WARN,"CSerial::Write - Unable to write the data\n");
    			return m_lLastError;
    		}
    
    		// We need to block if the client didn't specify an overlapped structure
    		if (lpOverlapped == &ovInternal)
    		{
    			// Wait for the overlapped operation to complete
    			switch (::WaitForSingleObject(lpOverlapped->hEvent,dwTimeout))
    			{
    			case WAIT_OBJECT_0:
    				// The overlapped operation has completed
    				if (!::GetOverlappedResult(m_hFile,lpOverlapped,pdwWritten,FALSE))
    				{
    					// Set the internal error code
    					m_lLastError = ::GetLastError();
    
    					_RPTF0(_CRT_WARN,"CSerial::Write - Overlapped completed without result\n");
    					return m_lLastError;
    				}
    				break;
    
    			case WAIT_TIMEOUT:
    				// Cancel the I/O operation
    				CancelCommIo();
    
    				// The operation timed out. Set the internal error code and quit
    				m_lLastError = ERROR_TIMEOUT;
    				return m_lLastError;
    
    			default:
    				// Set the internal error code
    				m_lLastError = ::GetLastError();
    
    				// Issue an error and quit
    				_RPTF0(_CRT_WARN,"CSerial::Write - Unable to wait until data has been sent\n");
    				return m_lLastError;
    			}
    		}
    	}
    	else
    	{
    		// The operation completed immediatly. Just to be sure
    		// we'll set the overlapped structure's event handle.
    		if (lpOverlapped)
    			::SetEvent(lpOverlapped->hEvent);
    	}
    
    #else
    
    	// Write the data
    	if (!::WriteFile(m_hFile,pData,iLen,pdwWritten,0))
    	{
    		// Set the internal error code
    		m_lLastError = ::GetLastError();
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN,"CSerial::Write - Unable to write the data\n");
    		return m_lLastError;
    	}
    
    #endif
    
    	// Return successfully
    	return m_lLastError;
    }
    
    LONG CSerial::Write (LPCSTR pString, DWORD* pdwWritten, LPOVERLAPPED lpOverlapped, DWORD dwTimeout)
    {
    	// Check if time-outs are supported
    	CheckRequirements(lpOverlapped,dwTimeout);
    
    	// Determine the length of the string
    	return Write(pString,strlen(pString),pdwWritten,lpOverlapped,dwTimeout);
    }
    
    LONG CSerial::Read (void* pData, size_t iLen, DWORD* pdwRead, LPOVERLAPPED lpOverlapped, DWORD dwTimeout)
    {
    	// Check if time-outs are supported
    	CheckRequirements(lpOverlapped,dwTimeout);
    
    	// Overlapped operation should specify the pdwRead variable
    	_ASSERTE(!lpOverlapped || pdwRead);
    
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Use our own variable for read count
    	DWORD dwRead;
    	if (pdwRead == 0)
    	{
    		pdwRead = &dwRead;
    	}
    
    	// Reset the number of bytes read
    	*pdwRead = 0;
    
    	// Check if the device is open
    	if (m_hFile == 0)
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_HANDLE;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN,"CSerial::Read - Device is not opened\n");
    		return m_lLastError;
    	}
    
    #ifdef _DEBUG
    	// The debug version fills the entire data structure with
    	// 0xDC bytes, to catch buffer errors as soon as possible.
    	memset(pData,0xDC,iLen);
    #endif
    
    #ifndef SERIAL_NO_OVERLAPPED
    
    	// Check if an overlapped structure has been specified
    	if (!m_hevtOverlapped && (lpOverlapped || (dwTimeout != INFINITE)))
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_FUNCTION;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN,"CSerial::Read - Overlapped I/O is disabled, specified parameters are illegal.\n");
    		return m_lLastError;
    	}
    
    	// Wait for the event to happen
    	OVERLAPPED ovInternal;
    	if (lpOverlapped == 0)
    	{
    		// Setup our own overlapped structure
    		memset(&ovInternal,0,sizeof(ovInternal));
    		ovInternal.hEvent = m_hevtOverlapped;
    
    		// Use our internal overlapped structure
    		lpOverlapped = &ovInternal;
    	}
    
    	// Make sure the overlapped structure isn't busy
    	_ASSERTE(!m_hevtOverlapped || HasOverlappedIoCompleted(lpOverlapped));
    	
    	// Read the data
    	if (!::ReadFile(m_hFile,pData,iLen,pdwRead,lpOverlapped))
    	{
    		// Set the internal error code
    		long lLastError = ::GetLastError();
    
    		// Overlapped operation in progress is not an actual error
    		if (lLastError != ERROR_IO_PENDING)
    		{
    			// Save the error
    			m_lLastError = lLastError;
    
    			// Issue an error and quit
    			_RPTF0(_CRT_WARN,"CSerial::Read - Unable to read the data\n");
    			return m_lLastError;
    		}
    
    		// We need to block if the client didn't specify an overlapped structure
    		if (lpOverlapped == &ovInternal)
    		{
    			// Wait for the overlapped operation to complete
    			switch (::WaitForSingleObject(lpOverlapped->hEvent,dwTimeout))
    			{
    			case WAIT_OBJECT_0:
    				// The overlapped operation has completed
    				if (!::GetOverlappedResult(m_hFile,lpOverlapped,pdwRead,FALSE))
    				{
    					// Set the internal error code
    					m_lLastError = ::GetLastError();
    
    					_RPTF0(_CRT_WARN,"CSerial::Read - Overlapped completed without result\n");
    					return m_lLastError;
    				}
    				break;
    
    			case WAIT_TIMEOUT:
    				// Cancel the I/O operation
    				CancelCommIo();
    
    				// The operation timed out. Set the internal error code and quit
    				m_lLastError = ERROR_TIMEOUT;
    				return m_lLastError;
    
    			default:
    				// Set the internal error code
    				m_lLastError = ::GetLastError();
    
    				// Issue an error and quit
    				_RPTF0(_CRT_WARN,"CSerial::Read - Unable to wait until data has been read\n");
    				return m_lLastError;
    			}
    		}
    	}
    	else
    	{
    		// The operation completed immediatly. Just to be sure
    		// we'll set the overlapped structure's event handle.
    		if (lpOverlapped)
    			::SetEvent(lpOverlapped->hEvent);
    	}
    
    #else
    	
    	// Read the data
    	if (!::ReadFile(m_hFile,pData,iLen,pdwRead,0))
    	{
    		// Set the internal error code
    		m_lLastError = ::GetLastError();
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN,"CSerial::Read - Unable to read the data\n");
    		return m_lLastError;
    	}
    
    #endif
    
    	// Return successfully
    	return m_lLastError;
    }
    
    LONG CSerial::Purge()
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Check if the device is open
    	if (m_hFile == 0)
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_HANDLE;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN,"CSerial::Purge - Device is not opened\n");
    		return m_lLastError;
    	}
    
    	if (!::PurgeComm(m_hFile, PURGE_TXCLEAR | PURGE_RXCLEAR))
    	{
    		// Set the internal error code
    		m_lLastError = ::GetLastError();
    		_RPTF0(_CRT_WARN,"CSerial::Purge - Overlapped completed without result\n");
    	}
    	
    	// Return successfully
    	return m_lLastError;
    }
    
    LONG CSerial::Break ()
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Check if the device is open
    	if (m_hFile == 0)
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_HANDLE;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN,"CSerial::Break - Device is not opened\n");
    		return m_lLastError;
    	}
    
    	// Set the RS-232 port in break mode for a little while
    	::SetCommBreak(m_hFile);
    	::Sleep(100);
    	::ClearCommBreak(m_hFile);
    
    	// Return successfully
    	return m_lLastError;
    }
    
    CSerial::EEvent CSerial::GetEventType ()
    {
    #ifdef _DEBUG
    	// Check if the event is within the mask
    	if ((m_eEvent & m_dwEventMask) == 0)
    		_RPTF2(_CRT_WARN,"CSerial::GetEventType - Event %08Xh not within mask %08Xh.\n", m_eEvent, m_dwEventMask);
    #endif
    
    	// Obtain the event (mask unwanted events out)
    	EEvent eEvent = EEvent(m_eEvent & m_dwEventMask);
    
    	// Reset internal event type
    	m_eEvent = EEventNone;
    
    	// Return the current cause
    	return eEvent;
    }
    
    CSerial::EError CSerial::GetError ()
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Check if the device is open
    	if (m_hFile == 0)
    	{
    		// Set the internal error code
    		m_lLastError = ERROR_INVALID_HANDLE;
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN,"CSerial::GetError - Device is not opened\n");
    		return EErrorUnknown;
    	}
    
    	// Obtain COM status
    	DWORD dwErrors = 0;
    	if (!::ClearCommError(m_hFile,&dwErrors,0))
    	{
    		// Set the internal error code
    		m_lLastError = ::GetLastError();
    
    		// Issue an error and quit
    		_RPTF0(_CRT_WARN,"CSerial::GetError - Unable to obtain COM status\n");
    		return EErrorUnknown;
    	}
    
    	// Return the error
    	return EError(dwErrors);
    }
    
    bool CSerial::GetCTS ()
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Obtain the modem status
    	DWORD dwModemStat = 0;
    	if (!::GetCommModemStatus(m_hFile,&dwModemStat))
    	{
    		// Obtain the error code
    		m_lLastError = ::GetLastError();
    
    		// Display a warning
    		_RPTF0(_CRT_WARN,"CSerial::GetCTS - Unable to obtain the modem status\n");
    		return false;
    	}
    
    	// Determine if CTS is on
    	return (dwModemStat & MS_CTS_ON) != 0;
    }
    
    bool CSerial::GetDSR ()
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Obtain the modem status
    	DWORD dwModemStat = 0;
    	if (!::GetCommModemStatus(m_hFile,&dwModemStat))
    	{
    		// Obtain the error code
    		m_lLastError = ::GetLastError();
    
    		// Display a warning
    		_RPTF0(_CRT_WARN,"CSerial::GetDSR - Unable to obtain the modem status\n");
    		return false;
    	}
    
    	// Determine if DSR is on
    	return (dwModemStat & MS_DSR_ON) != 0;
    }
    
    bool CSerial::GetRing ()
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Obtain the modem status
    	DWORD dwModemStat = 0;
    	if (!::GetCommModemStatus(m_hFile,&dwModemStat))
    	{
    		// Obtain the error code
    		m_lLastError = ::GetLastError();
    
    		// Display a warning
    		_RPTF0(_CRT_WARN,"CSerial::GetRing - Unable to obtain the modem status");
    		return false;
    	}
    
    	// Determine if Ring is on
    	return (dwModemStat & MS_RING_ON) != 0;
    }
    
    bool CSerial::GetRLSD ()
    {
    	// Reset error state
    	m_lLastError = ERROR_SUCCESS;
    
    	// Obtain the modem status
    	DWORD dwModemStat = 0;
    	if (!::GetCommModemStatus(m_hFile,&dwModemStat))
    	{
    		// Obtain the error code
    		m_lLastError = ::GetLastError();
    
    		// Display a warning
    		_RPTF0(_CRT_WARN,"CSerial::GetRLSD - Unable to obtain the modem status");
    		return false;
    	}
    
    	// Determine if RLSD is on
    	return (dwModemStat & MS_RLSD_ON) != 0;
    }
    
    Infatti non ho errori io.
  • Re: Comunicazione tramite seriale

    Il tuo main modificato
    #include "stdafx.h"
    #include <iostream>
    #include <fstream>
    #include "Serial.h"
    
    
    using namespace std;
    
    #define MAXR 100
    
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    
    	float mat[MAXR][3];
    
    	// legge dati dal file txt
    	ifstream dati("C:\\Users\\ALESSANDRO\\Desktop\\Parte1.txt");
    	int r = 0;
    	while (!dati.eof())
    	{
    		dati >> mat[r][0] >> mat[r][1] >> mat[r][2];
    		r++;
    	}
    	dati.close();
    
    	CSerial serial;
    	LONG lastError = serial.Open("COM2");
    	if(lastError == ERROR_SUCCESS)
    	{
    		serial.Setup(CSerial::EBaud115200,CSerial::EData8,CSerial::EParNone,CSerial::EStop1);
    		serial.SetupHandshaking(CSerial::EHandshakeOff);
    		serial.SetupReadTimeouts(CSerial::EReadTimeoutNonblocking);
    		//prosegui con la scrittura dei dati
    		for(int i = 0; i < r; i++)
    			serial.Write(mat[i],3); //scrivo 3 dati della i-esima riga
    	}
    	else
    		MessageBox(HWND_DESKTOP, "Failed to open port!", "Error", MB_OK);
    	return 0;
    }
  • Re: Comunicazione tramite seriale

    Si adesso compila anche a me! Ti ringrazio molto . Sarei ancora in alto mare se non mi avessi aiutato tu!
  • Re: Comunicazione tramite seriale

    Ma funziona? Cioé manda qualcosa al micro?
  • Re: Comunicazione tramite seriale

    Eh quello lo devo provare una volta che avrò davanti a me il micro. Però almeno adesso non ho errori di compilazione, ed è già un buon primo passo.
    Me lo chiedi perchè hai rilevato altre imprecisioni nel mio codice?
  • Re: Comunicazione tramite seriale

    Non sapiamo ancora i bit di stop. Se è 1, 1.5 oppure 2 per quello chiedevo. Comunque mo stacco che é tardi. Notte.
  • Re: Comunicazione tramite seriale

    Eccomi di nuovo qui per chiedere un'altra spiegazione!!...il programma funziona correttamente ma risulta essere un po' "statico". Mi spiego: con un programma così scritto, ogni volta che voglio cambiare la porta seriale (COM1,COM2,etc...) sono costretto a ricompilare tutto, ed è una cosa molto scomoda. C'è un modo per far si che almeno la porta seriale e il baudrate possano essere inseriti a priori di volta in volta senza dover andare a compilare tutto ogni volta?

    Grazie mille
Devi accedere o registrarti per scrivere nel forum
30 risposte