Zum Inhalt springen

mit C den COM Port ansprechen


Empfohlene Beiträge

Geschrieben

moin leutz,

ich habe da ein kleines problem. und zwar habe ich da ein kleines programm, welches den eine serielle schnittstelle ansprechen soll. problem: wie spricht man die serielle schnittstelle an.

------------------

mfg maddin

Geschrieben

Ich hab auf einer Englischen Seite was dazu gesehen. Ist aber in VC++

/*

** FILENAME CSerialPort.h

**

** PURPOSE This class can read, write and watch one serial port.

** It sends messages to its owner when something happends on the port

** The class creates a thread for reading and writing so the main

** program is not blocked.

**

** CREATION DATE 15-09-1997

** LAST MODIFICATION 24-11-1998

**

** AUTHOR Remon Spekreijse

** MODIFIED BY Brian Koh Sze Hsian

**

*/

#ifndef __SERIALPORT_H__

#define __SERIALPORT_H__

#define WM_COMM_BREAK_DETECTED WM_USER+1 // A break was detected on input.

#define WM_COMM_CTS_DETECTED WM_USER+2 // The CTS (clear-to-send) signal changed state.

#define WM_COMM_DSR_DETECTED WM_USER+3 // The DSR (data-set-ready) signal changed state.

#define WM_COMM_ERR_DETECTED WM_USER+4 // A line-status error occurred. Line-status errors are CE_FRAME, CE_OVERRUN, and CE_RXPARITY.

#define WM_COMM_RING_DETECTED WM_USER+5 // A ring indicator was detected.

#define WM_COMM_RLSD_DETECTED WM_USER+6 // The RLSD (receive-line-signal-detect) signal changed state.

#define WM_COMM_RXCHAR WM_USER+7 // A character was received and placed in the input buffer.

#define WM_COMM_RXFLAG_DETECTED WM_USER+8 // The event character was received and placed in the input buffer.

#define WM_COMM_TXEMPTY_DETECTED WM_USER+9 // The last character in the output buffer was sent.

class CSerialPort

{

public:

// contruction and destruction

CSerialPort();

virtual ~CSerialPort();

// port initialisation

BOOL InitPort(CWnd* pPortOwner, UINT portnr = 1, UINT baud = 19200, char parity = 'N', UINT databits = 8, UINT stopsbits = 1, DWORD dwCommEvents = EV_RXCHAR | EV_CTS, UINT nBufferSize = 512);

// start/stop comm watching

BOOL StartMonitoring();

BOOL RestartMonitoring();

BOOL StopMonitoring();

DWORD GetWriteBufferSize();

DWORD GetCommEvents();

DCB GetDCB();

void WriteToPort(char* string);

void WriteToPort(char* string,int stringlength);

protected:

// protected memberfunctions

void ProcessErrorMessage(char* ErrorText);

static UINT CommThread(LPVOID pParam);

static void ReceiveChar(CSerialPort* port, COMSTAT comstat);

static void WriteChar(CSerialPort* port);

// thread

CWinThread* m_Thread;

// synchronisation objects

CRITICAL_SECTION m_csCommunicationSync;

BOOL m_bThreadAlive;

// handles

HANDLE m_hShutdownEvent;

HANDLE m_hComm;

HANDLE m_hWriteEvent;

HANDLE m_hWriteCompleteEvent;

// Event array.

// One element is used for each event. There are two event handles for each port.

// A Write event and a receive character event which is located in the overlapped structure (m_ov.hEvent).

// There is a general shutdown when the port is closed.

HANDLE m_hEventArray[3];

// structures

OVERLAPPED m_ov;

COMMTIMEOUTS m_CommTimeouts;

DCB m_dcb;

// owner window

CWnd* m_pOwner;

// misc

UINT m_nPortNr;

char* m_szWriteBuffer;

DWORD m_dwCommEvents;

DWORD m_nWriteBufferSize;

int m_nActualWriteBufferSize;

};

#endif __SERIALPORT_H__

/*

** FILENAME CSerialPort.cpp

**

** PURPOSE This class can read, write and watch one serial port.

** It sends messages to its owner when something happends on the port

** The class creates a thread for reading and writing so the main

** program is not blocked.

**

** CREATION DATE 15-09-1997

** LAST MODIFICATION 24-11-1998

**

** AUTHOR Remon Spekreijse

** MODIFIED BY Brian Koh Sze Hsian

**

*/

#include "stdafx.h"

#include "SerialPort.h"

#include <assert.h>

//

// Constructor

//

CSerialPort::CSerialPort()

{

m_hComm = NULL;

// initialize overlapped structure members to zero

m_ov.Offset = 0;

m_ov.OffsetHigh = 0;

// create events

m_ov.hEvent = NULL;

m_hWriteEvent = NULL;

m_hShutdownEvent = NULL;

m_szWriteBuffer = NULL;

m_bThreadAlive = FALSE;

m_hWriteCompleteEvent=NULL;

}

//

// Delete dynamic memory

//

CSerialPort::~CSerialPort()

{

// resume the thread if it was suspended. Needed to process m_hShutdownEvent!

if(m_Thread != NULL)

{

DWORD dwSuspendCount;

do

{

dwSuspendCount = m_Thread->ResumeThread();

}

while((dwSuspendCount != 0) && (dwSuspendCount != 0xffffffff) );

do

{

SetEvent(m_hShutdownEvent);

}

while (m_bThreadAlive);

TRACE("Thread ended\n");

}

// close handles to avoid memory leaks

CloseHandle(m_ov.hEvent);

CloseHandle(m_hWriteEvent);

CloseHandle(m_hComm);

CloseHandle(m_hShutdownEvent);

CloseHandle(m_hWriteCompleteEvent);

m_hComm = NULL;

m_ov.hEvent = NULL;

m_hWriteEvent = NULL;

m_hShutdownEvent = NULL;

m_hWriteCompleteEvent = NULL;

if (m_szWriteBuffer != NULL)

delete [] m_szWriteBuffer;

DeleteCriticalSection(&m_csCommunicationSync);

}

//

// Initialize the port. This can be port 1 to 4.

//

BOOL CSerialPort::InitPort(CWnd* pPortOwner, // the owner (CWnd) of the port (receives message)

UINT portnr, // portnumber (1..4)

UINT baud, // baudrate

char parity, // parity

UINT databits, // databits

UINT stopbits, // stopbits

DWORD dwCommEvents, // EV_RXCHAR, EV_CTS etc

UINT writebuffersize) // size to the writebuffer

{

assert(portnr > 0 && portnr < 5);

assert(pPortOwner != NULL);

// if the thread is alive: Kill

if (m_bThreadAlive)

{

do

{

SetEvent(m_hShutdownEvent);

} while (m_bThreadAlive);

TRACE("Thread ended\n");

}

// create events

if (m_ov.hEvent != NULL)

ResetEvent(m_ov.hEvent);

m_ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

if (m_hWriteEvent != NULL)

ResetEvent(m_hWriteEvent);

m_hWriteEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

if (m_hShutdownEvent != NULL)

ResetEvent(m_hShutdownEvent);

m_hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

if(m_hWriteCompleteEvent != NULL)

ResetEvent(m_hWriteCompleteEvent);

m_hWriteCompleteEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

// initialize the event objects

m_hEventArray[0] = m_hShutdownEvent; // highest priority

m_hEventArray[1] = m_ov.hEvent;

m_hEventArray[2] = m_hWriteEvent;

// initialize critical section

InitializeCriticalSection(&m_csCommunicationSync);

// set buffersize for writing and save the owner

m_pOwner = pPortOwner;

if (m_szWriteBuffer != NULL)

delete [] m_szWriteBuffer;

m_szWriteBuffer = new char[writebuffersize];

m_nPortNr = portnr;

m_nWriteBufferSize = writebuffersize;

m_dwCommEvents = dwCommEvents;

BOOL bResult = FALSE;

char *szPort = new char[50];

char *szBaud = new char[50];

// now it critical!

EnterCriticalSection(&m_csCommunicationSync);

// if the port is already opened: close it

if (m_hComm != NULL)

{

CloseHandle(m_hComm);

m_hComm = NULL;

}

// prepare port strings

sprintf(szPort, "COM%d", portnr);

sprintf(szBaud, "baud=%d parity=%c data=%d stop=%d", baud, parity, databits, stopbits);

// get a handle to the port

m_hComm = CreateFile(szPort, // communication port string (COMX)

GENERIC_READ | GENERIC_WRITE, // read/write types

0, // comm devices must be opened with exclusive access

NULL, // no security attributes

OPEN_EXISTING, // comm devices must use OPEN_EXISTING

FILE_FLAG_OVERLAPPED, // Async I/O

0); // template must be 0 for comm devices

if (m_hComm == INVALID_HANDLE_VALUE)

{

// port not found

delete [] szPort;

delete [] szBaud;

return FALSE;

}

// set the timeout values

m_CommTimeouts.ReadIntervalTimeout = 1000;

m_CommTimeouts.ReadTotalTimeoutMultiplier = 1000;

m_CommTimeouts.ReadTotalTimeoutConstant = 1000;

m_CommTimeouts.WriteTotalTimeoutMultiplier = 1000;

m_CommTimeouts.WriteTotalTimeoutConstant = 1000;

// configure

if (SetCommTimeouts(m_hComm, &m_CommTimeouts))

{

if (SetCommMask(m_hComm, dwCommEvents))

{

if (GetCommState(m_hComm, &m_dcb))

{

m_dcb.fRtsControl = RTS_CONTROL_ENABLE; // set RTS bit high!

if (BuildCommDCB(szBaud, &m_dcb))

{

if (SetCommState(m_hComm, &m_dcb))

; // normal operation... continue

else

ProcessErrorMessage("SetCommState()");

}

else

ProcessErrorMessage("BuildCommDCB()");

}

else

ProcessErrorMessage("GetCommState()");

}

else

ProcessErrorMessage("SetCommMask()");

}

else

ProcessErrorMessage("SetCommTimeouts()");

delete [] szPort;

delete [] szBaud;

// flush the port

PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);

// release critical section

LeaveCriticalSection(&m_csCommunicationSync);

TRACE("Initialisation for communicationport %d completed.\nUse Startmonitor to communicate.\n", portnr);

return TRUE;

}

//

// The CommThread Function.

//

UINT CSerialPort::CommThread(LPVOID pParam)

{

// Cast the void pointer passed to the thread back to

// a pointer of CSerialPort class

CSerialPort *port = (CSerialPort*)pParam;

// Set the status variable in the dialog class to

// TRUE to indicate the thread is running.

port->m_bThreadAlive = TRUE;

// Misc. variables

DWORD BytesTransfered = 0;

DWORD Event = 0;

DWORD CommEvent = 0;

DWORD dwError = 0;

COMSTAT comstat;

BOOL bResult = TRUE;

// Clear comm buffers at startup

if (port->m_hComm) // check if the port is opened

PurgeComm(port->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);

// begin forever loop. This loop will run as long as the thread is alive.

for (; wink.gif

{

// Make a call to WaitCommEvent(). This call will return immediatly

// because our port was created as an async port (FILE_FLAG_OVERLAPPED

// and an m_OverlappedStructerlapped structure specified). This call will cause the

// m_OverlappedStructerlapped element m_OverlappedStruct.hEvent, which is part of the m_hEventArray to

// be placed in a non-signeled state if there are no bytes available to be read,

// or to a signeled state if there are bytes available. If this event handle

// is set to the non-signeled state, it will be set to signeled when a

// character arrives at the port.

// we do this for each port!

bResult = WaitCommEvent(port->m_hComm, &Event, &port->m_ov);

if (!bResult)

{

// If WaitCommEvent() returns FALSE, process the last error to determin

// the reason..

switch (dwError = GetLastError())

{

case ERROR_IO_PENDING:

{

// This is a normal return value if there are no bytes

// to read at the port.

// Do nothing and continue

break;

}

case 87:

{

// Under Windows NT, this value is returned for some reason.

// I have not investigated why, but it is also a valid reply

// Also do nothing and continue.

break;

}

default:

{

// All other error codes indicate a serious error has

// occured. Process this error.

port->ProcessErrorMessage("WaitCommEvent()");

break;

}

}

}

else

{

// If WaitCommEvent() returns TRUE, check to be sure there are

// actually bytes in the buffer to read.

//

// If you are reading more than one byte at a time from the buffer

// (which this program does not do) you will have the situation occur

// where the first byte to arrive will cause the WaitForMultipleObjects()

// function to stop waiting. The WaitForMultipleObjects() function

// resets the event handle in m_OverlappedStruct.hEvent to the non-signelead state

// as it returns.

//

// If in the time between the reset of this event and the call to

// ReadFile() more bytes arrive, the m_OverlappedStruct.hEvent handle will be set again

// to the signeled state. When the call to ReadFile() occurs, it will

// read all of the bytes from the buffer, and the program will

// loop back around to WaitCommEvent().

//

// At this point you will be in the situation where m_OverlappedStruct.hEvent is set,

// but there are no bytes available to read. If you proceed and call

// ReadFile(), it will return immediatly due to the async port setup, but

// GetOverlappedResults() will not return until the next character arrives.

//

// It is not desirable for the GetOverlappedResults() function to be in

// this state. The thread shutdown event (event 0) and the WriteFile()

// event (Event2) will not work if the thread is blocked by GetOverlappedResults().

//

// The solution to this is to check the buffer with a call to ClearCommError().

// This call will reset the event handle, and if there are no bytes to read

// we can loop back through WaitCommEvent() again, then proceed.

// If there are really bytes to read, do nothing and proceed.

bResult = ClearCommError(port->m_hComm, &dwError, &comstat);

if (comstat.cbInQue == 0)

continue;

} // end if bResult

// Main wait function. This function will normally block the thread

// until one of nine events occur that require action.

Event = WaitForMultipleObjects(3, port->m_hEventArray, FALSE, INFINITE);

switch (Event)

{

case 0:

{

// Shutdown event. This is event zero so it will be

// the higest priority and be serviced first.

port->m_bThreadAlive = FALSE;

// Kill this thread. break is not needed, but makes me feel better.

AfxEndThread(100);

break;

}

case 1: // read event

{

GetCommMask(port->m_hComm, &CommEvent);

if (CommEvent & EV_CTS)

::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_CTS_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);

if (CommEvent & EV_RXFLAG)

::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_RXFLAG_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);

if (CommEvent & EV_BREAK)

::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_BREAK_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);

if (CommEvent & EV_ERR)

::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_ERR_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);

if (CommEvent & EV_RING)

::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_RING_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);

if (CommEvent & EV_RXCHAR)

// Receive character event from port.

ReceiveChar(port, comstat);

break;

}

case 2: // write event

{

// Write character event from port

WriteChar(port);

break;

}

} // end switch

} // close forever loop

return 0;

}

//

// start comm watching

//

BOOL CSerialPort::StartMonitoring()

{

if (!(m_Thread = AfxBeginThread(CommThread, this)))

return FALSE;

TRACE("Thread started\n");

return TRUE;

}

//

// Restart the comm thread

//

BOOL CSerialPort::RestartMonitoring()

{

TRACE("Thread resumed\n");

m_Thread->ResumeThread();

return TRUE;

}

//

// Suspend the comm thread

//

BOOL CSerialPort::StopMonitoring()

{

TRACE("Thread suspended\n");

m_Thread->SuspendThread();

return TRUE;

}

//

// If there is a error, give the right message

//

void CSerialPort::ProcessErrorMessage(char* ErrorText)

{

char *Temp = new char[200];

LPVOID lpMsgBuf;

FormatMessage(

FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,

NULL,

GetLastError(),

MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language

(LPTSTR) &lpMsgBuf,

0,

NULL

);

sprintf(Temp, "WARNING: %s Failed with the following error: \n%s\nPort: %d\n", (char*)ErrorText, lpMsgBuf, m_nPortNr);

MessageBox(NULL, Temp, "Application Error", MB_ICONSTOP);

LocalFree(lpMsgBuf);

delete[] Temp;

}

//

// Write a character.

//

void CSerialPort::WriteChar(CSerialPort* port)

{

BOOL bWrite = TRUE;

BOOL bResult = TRUE;

DWORD BytesSent = 0;

ResetEvent(port->m_hWriteEvent);

// Gain ownership of the critical section

EnterCriticalSection(&port->m_csCommunicationSync);

if (bWrite)

{

// Initailize variables

port->m_ov.Offset = 0;

port->m_ov.OffsetHigh = 0;

// Clear buffer

PurgeComm(port->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);

bResult = WriteFile(port->m_hComm, // Handle to COMM Port

port->m_szWriteBuffer, // Pointer to message buffer in calling finction

port->m_nActualWriteBufferSize,

// strlen(port->m_szWriteBuffer), // Length of message to send

&BytesSent, // Where to store the number of bytes sent

&port->m_ov); // Overlapped structure

// deal with any error codes

if (!bResult)

{

DWORD dwError = GetLastError();

switch (dwError)

{

case ERROR_IO_PENDING:

{

// continue to GetOverlappedResults()

BytesSent = 0;

bWrite = FALSE;

break;

}

default:

{

// all other error codes

port->ProcessErrorMessage("WriteFile()");

}

}

}

else

{

LeaveCriticalSection(&port->m_csCommunicationSync);

}

} // end if(bWrite)

if (!bWrite)

{

bWrite = TRUE;

bResult = GetOverlappedResult(port->m_hComm, // Handle to COMM port

&port->m_ov, // Overlapped structure

&BytesSent, // Stores number of bytes sent

TRUE); // Wait flag

LeaveCriticalSection(&port->m_csCommunicationSync);

// deal with the error code

if (!bResult)

{

port->ProcessErrorMessage("GetOverlappedResults() in WriteFile()");

}

} // end if (!bWrite)

// Verify that the data size send equals what we tried to send

if (BytesSent != strlen((char*)port->m_szWriteBuffer))

{

TRACE("WARNING: WriteFile() error.. Bytes Sent: %d; Message Length: %d\n", BytesSent, strlen((char*)port->m_szWriteBuffer));

}

SetEvent(port->m_hWriteCompleteEvent);

}

//

// Character received. Inform the owner

//

void CSerialPort::ReceiveChar(CSerialPort* port, COMSTAT comstat)

{

BOOL bRead = TRUE;

BOOL bResult = TRUE;

DWORD dwError = 0;

DWORD BytesRead = 0;

unsigned char RXBuff;

for (; wink.gif

{

// Gain ownership of the comm port critical section.

// This process guarantees no other part of this program

// is using the port object.

EnterCriticalSection(&port->m_csCommunicationSync);

// ClearCommError() will update the COMSTAT structure and

// clear any other errors.

bResult = ClearCommError(port->m_hComm, &dwError, &comstat);

LeaveCriticalSection(&port->m_csCommunicationSync);

// start forever loop. I use this type of loop because I

// do not know at runtime how many loops this will have to

// run. My solution is to start a forever loop and to

// break out of it when I have processed all of the

// data available. Be careful with this approach and

// be sure your loop will exit.

// My reasons for this are not as clear in this sample

// as it is in my production code, but I have found this

// solutiion to be the most efficient way to do this.

if (comstat.cbInQue == 0)

{

// break out when all bytes have been read

break;

}

EnterCriticalSection(&port->m_csCommunicationSync);

if (bRead)

{

bResult = ReadFile(port->m_hComm, // Handle to COMM port

&RXBuff, // RX Buffer Pointer

1, // Read one byte

&BytesRead, // Stores number of bytes read

&port->m_ov); // pointer to the m_ov structure

// deal with the error code

if (!bResult)

{

switch (dwError = GetLastError())

{

case ERROR_IO_PENDING:

{

// asynchronous i/o is still in progress

// Proceed on to GetOverlappedResults();

bRead = FALSE;

break;

}

default:

{

// Another error has occured. Process this error.

port->ProcessErrorMessage("ReadFile()");

break;

}

}

}

else

{

// ReadFile() returned complete. It is not necessary to call GetOverlappedResults()

bRead = TRUE;

}

} // close if (bRead)

if (!bRead)

{

bRead = TRUE;

bResult = GetOverlappedResult(port->m_hComm, // Handle to COMM port

&port->m_ov, // Overlapped structure

&BytesRead, // Stores number of bytes read

TRUE); // Wait flag

// deal with the error code

if (!bResult)

{

port->ProcessErrorMessage("GetOverlappedResults() in ReadFile()");

}

} // close if (!bRead)

LeaveCriticalSection(&port->m_csCommunicationSync);

// notify parent that a byte was received

::SendMessage((port->m_pOwner)->m_hWnd, WM_COMM_RXCHAR, (WPARAM) RXBuff, (LPARAM) port->m_nPortNr);

} // end forever loop

}

//

// Write a string to the port - This can write even NULL characters

//

void CSerialPort::WriteToPort(char* string, int stringlength)

{

assert(m_hComm != 0);

ResetEvent(m_hWriteCompleteEvent);

EnterCriticalSection(&m_csCommunicationSync);

memset(m_szWriteBuffer, 0, sizeof(m_szWriteBuffer));

for(int i=0;i<stringlength;i++)

m_szWriteBuffer=string;

m_nActualWriteBufferSize=stringlength;

LeaveCriticalSection(&m_csCommunicationSync);

// set event for write

SetEvent(m_hWriteEvent);

WaitForSingleObject(m_hWriteCompleteEvent,INFINITE);

}

//

// Return the device control block

//

DCB CSerialPort::GetDCB()

{

return m_dcb;

}

//

// Return the communication event masks

//

DWORD CSerialPort::GetCommEvents()

{

return m_dwCommEvents;

}

//

// Return the output buffer size

//

DWORD CSerialPort::GetWriteBufferSize()

{

return m_nWriteBufferSize;

}

Gast
Dieses Thema wurde nun für weitere Antworten gesperrt.

Fachinformatiker.de, 2024 by SE Internet Services

fidelogo_small.png

Schicke uns eine Nachricht!

Fachinformatiker.de ist die größte IT-Community
rund um Ausbildung, Job, Weiterbildung für IT-Fachkräfte.

Fachinformatiker.de App

Download on the App Store
Get it on Google Play

Kontakt

Hier werben?
Oder sende eine E-Mail an

Social media u. feeds

Jobboard für Fachinformatiker und IT-Fachkräfte

×
×
  • Neu erstellen...