Code:
/************************************************************
** CommThread : Öffnet, schließt und liest den Port,
** sendet die Zeiten per PostThreadMessage
** an den MonitorThread
************************************************************/
#include <windows.h>
#include <process.h>
#include <stdio.h>
// Prototypes:
DWORD WINAPI ComThread (LPVOID lpParam);
DWORD WINAPI MonitorThread (LPVOID lpParam);
HANDLE StartComThread (DWORD iPortNum, HWND hEdit);
long queryPrecisionTime (void);
long queryPrecisionTimeStamp (void);
// Globals:
HANDLE hCom = INVALID_HANDLE_VALUE;
// global struc contains parameter for threads
typedef struct
{
volatile BOOL ThreadStoppen;
volatile int iComPortNum;
volatile DWORD dwMonitorThreadId;
} PARAMS, *PPARAMS;
static HANDLE hEvent;
// Message types
#define MSG_MIN_RANGE 0
// Der Message-Type für PostThreadMessage setzt sich aus
// QS_ALLPOSTMESSAGE (=256) und dem eigenem Message-Type
// (siehe MSG_xxxxxxx) zusammen.
// Mit MSG_MIN_RANGE können verschiedene Gruppen bei
// Bedarf gebildet werden.
#define MSG_TIME MSG_MIN_RANGE + 1000 // vom ComThread
#define MSG_TRIG MSG_MIN_RANGE + 2000 // reserviert
#define MSG_COMOPEN MSG_TRIG + 4
#define MSG_COMCLOSE MSG_TRIG + 5
#define QEVENT "QueueEvent"
//--------------------------------------------------------------------
// COMThread
//
// erstellt eine Queue, setzt danach den Event ("Queue ist ready").
// Schließt eine geöffneten COM-Port und öffnet den neuen (Nummer ist
// in der Strukur, auf die lpParam zeigt).
// liest die queue aus.
//
// Thread Funktion
// Liest eventgesteuert den Status von CTS, DSR, ... ein und
// sendet in dwEvtMask alle zum Event gehörenden Ereignisse
// zum Monitor-Thread.
//
//--------------------------------------------------------------------
DWORD WINAPI ComThread (LPVOID lpParam)
{
long lTime;
volatile PPARAMS pparams; // struct-Instanz
pparams = (PPARAMS) lpParam; // Zuweisung zu lpParam
int iPortNum = pparams->iComPortNum; // ...
DWORD dwMonitorThreadId = pparams->dwMonitorThreadId; // ...
char szPort[15];
static OVERLAPPED o;
// Maske für SetCommMask, die bestimmt, welche Ereignisse auftreten können
DWORD dwEvtMaskIn = EV_CTS | EV_DSR | EV_BREAK | EV_RING | EV_RXCHAR |
EV_RLSD | EV_ERR | EV_RXFLAG | EV_TXEMPTY;
DWORD dwEvtMask = 0; // Maske, in die WaitCommEvent aktuelle Werte schreibt
BOOL bRet;
CloseHandle (hCom); // "alten" COM-Port schließen
// Com Port öffnen
wsprintf (szPort, "COM%d", iPortNum);
hCom = CreateFile (szPort,
GENERIC_READ | GENERIC_WRITE,
0, // exclusive access
NULL, // no security attributes
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
if (hCom == INVALID_HANDLE_VALUE)
{
LPVOID lpMsgBuf;
FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError (), MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf, 0, NULL);
MessageBox (NULL, (LPCTSTR)lpMsgBuf, TEXT("ComThread: error: CreateFile()"),
MB_OK | MB_ICONINFORMATION);
LocalFree (lpMsgBuf);
pparams->ThreadStoppen = TRUE;
}
else
{
if (!SetCommMask (hCom, dwEvtMaskIn))
MessageBox (NULL, "SetCommMask fehlgeschlagen", "COM Port:", MB_OK | MB_ICONSTOP);
// Create an event object for use in WaitCommEvent.
o.hEvent = CreateEvent (NULL, // no security attributes
FALSE, // auto reset event
FALSE, // not signaled
NULL); // no name
}
// Setzt die Priorität "RealTime" für das Programm
DWORD dwProcessId; // own process identifier
HANDLE hProcess; // handle to the own process
DWORD dwDesiredAccess = PROCESS_SET_INFORMATION; // access flag
BOOL bInheritHandle = TRUE; // handle inheritance flag
BOOL bReturn; // If the SetPriorityClass succeeds, then nonzero
DWORD dwPriorityClass = HIGH_PRIORITY_CLASS;
dwProcessId = GetCurrentProcessId ();
hProcess = OpenProcess (dwDesiredAccess, bInheritHandle, dwProcessId);
bReturn = SetPriorityClass (hProcess, dwPriorityClass);
printf ("\r\nComThread: %s geöffnet, warte auf Events ...", szPort);
// eine message zum Monitor-Thread senden:
bRet = PostThreadMessage (dwMonitorThreadId, (QS_ALLPOSTMESSAGE + MSG_COMOPEN),
(WPARAM)iPortNum , (LPARAM)0);
// Auf Events warten:
while (!pparams->ThreadStoppen) // solange weitermachen bis TRUE
{
WaitCommEvent (hCom, &dwEvtMask, &o); // EventMask "scharf machen"
// kommt der Event, ist auch die dwEvtMask geladen und es kann weitergehen
if (WAIT_OBJECT_0 == WaitForSingleObject (o.hEvent, INFINITE)) // warten bis Event
{
lTime = queryPrecisionTimeStamp (); // Zeit holen
// Message senden. In dwEvtMask können mehrere Ereignisse gesetzt sein
bRet = PostThreadMessage (dwMonitorThreadId, (QS_ALLPOSTMESSAGE + MSG_TIME),
(WPARAM)dwEvtMask , (LPARAM)lTime);
} // end of: if (WAIT_OBJECT_0 == ...
} // end of: while (...
CloseHandle (o.hEvent);
CloseHandle (hCom); // COM-Port schließen
printf ("\r\nComThread: %s geschlossen", szPort);
bRet = PostThreadMessage (dwMonitorThreadId, (QS_ALLPOSTMESSAGE + MSG_COMCLOSE),
(WPARAM)iPortNum , (LPARAM)0);
return (0);
}
//----------------------------------------------------------------------------
// MonitorThread
//
// erstellt eine Queue, setzt danach den Event und liest
// die queue aus
//----------------------------------------------------------------------------
DWORD WINAPI MonitorThread (LPVOID lpParam)
{
static char szMsg[255] = "";
static char szMsgTmp[30] = "";
int i = 0;
BOOL bRet;
MSG msg;
volatile PPARAMS pparams; // struct-Instanz
pparams = (PPARAMS) lpParam; // Zuweisung zu lpParam
DWORD COMStatus;
// create a queue for the thread
PeekMessage ((LPMSG)&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
// sent event after queue creation back to the threads creator
bRet = SetEvent (hEvent);
printf ("\r\nMonitorThread: warte auf Events ...");
// get messages by message from threads local queue
while ((bRet = GetMessage (&msg, NULL, 0, 0)) != 0)
{
if (bRet == -1)
{ // handle the error and possibly exit
MessageBox (NULL, "MonitorThread: GetMessage error", "COM Port:", MB_OK | MB_ICONSTOP);
return NULL; // error!
}
else
{ // a valid message is received
switch (msg.message)
{
case (QS_ALLPOSTMESSAGE + MSG_COMOPEN):
printf ("\r\nMonitorThread: MSG_COMOPEN: lParam=0x%08x wParam=0x%08x",
msg.lParam, msg.wParam);
break;
case (QS_ALLPOSTMESSAGE + MSG_COMCLOSE):
printf ("\r\nMonitorThread: MSG_COMCLOSE: lParam=0x%08x wParam=0x%08x",
msg.lParam, msg.wParam);
break;
case (QS_ALLPOSTMESSAGE + MSG_TIME):
// Time stamp message: lParam=time, wParam=dwEvtMask
szMsg[0] = '\0';
if (DWORD(msg.wParam) & EV_CTS)
{
GetCommModemStatus (hCom, &COMStatus);
if (COMStatus & MS_CTS_ON)
{ // CTS (Pin8) activated
wsprintf (szMsgTmp, "\r\nCTS_ON : %lu µs", msg.lParam);
}
else
{ // CTS (Pin8) deactivated
wsprintf (szMsgTmp, "\r\nCTS_OFF: %lu µs", msg.lParam);
}
strcat (szMsg, szMsgTmp);
}
if (DWORD(msg.wParam) & EV_DSR)
{
GetCommModemStatus (hCom, &COMStatus);
if (COMStatus & MS_DSR_ON)
{ // DSR (Pin6) activated
wsprintf (szMsgTmp, "\r\nDSR_ON : %lu µs", msg.lParam);
}
else
{ // DSR (Pin6) deactivated
wsprintf (szMsgTmp, "\r\nDSR_OFF: %lu µs", msg.lParam);
}
strcat (szMsg, szMsgTmp);
}
if (DWORD(msg.wParam) & EV_RLSD)
{
GetCommModemStatus (hCom, &COMStatus);
if (COMStatus & MS_RLSD_ON)
{ // DCD (Pin1) activated
wsprintf (szMsgTmp, "\r\nRLSD_ON: %lu µs", msg.lParam);
}
else
{ // DCD (Pin1) deactivated
wsprintf (szMsgTmp, "\r\nRLSD_OFF: %lu µs ", msg.lParam);
}
strcat (szMsg, szMsgTmp);
}
if (DWORD(msg.wParam) & EV_RING)
{
GetCommModemStatus (hCom, &COMStatus);
if ((COMStatus & MS_RING_ON))
{ // RI (Pin9) activated
wsprintf (szMsgTmp, "\r\nRING_ON: %lu µs", msg.lParam);
}
else
{ // RI (Pin9) deactivated
wsprintf (szMsgTmp, "\r\nRING_OFF: %lu µs", msg.lParam);
}
strcat (szMsg, szMsgTmp);
}
printf (szMsg);
break;
default:
wsprintf (szMsg, "\r\nMonitorThread: default: lParam=0x%08x wParam=0x%08x message=0x%08x",
msg.lParam, msg.wParam, msg.message);
MessageBox (NULL, (LPCTSTR)szMsg, "COM Port:", MB_OK | MB_ICONSTOP);
break;
} // end of: switch (msg.message)
} // end of: if (bRet == -1) else ...
} // end of: while((bRet = GetMessage(...
printf ("\r\nMonitorThread: beendet");
return 0;
}
// Globale Variablen
// struct für Zeitmessung
union ut_LargeInteger
{
LARGE_INTEGER o_WinPart;
ULONGLONG l_MyPart;
};
int i_ResetPrecisionTime = 0;
ULONGLONG l_PerfFrequ;
ut_LargeInteger uo_PerfCount;
/************************************************************************
Die Funktion queryPrecisionTimeStamp () liefert die seit dem Start des PC
verstrichene Zeit in Mikrosekunden.
************************************************************************/
long queryPrecisionTimeStamp (void)
{
if (i_ResetPrecisionTime == 0)
{
i_ResetPrecisionTime = 1;
QueryPerformanceFrequency (&uo_PerfCount.o_WinPart);
l_PerfFrequ = uo_PerfCount.l_MyPart;
}
ut_LargeInteger uo_perfCount;
QueryPerformanceCounter (&uo_perfCount.o_WinPart);
return (long) (uo_perfCount.l_MyPart * 1000000 / l_PerfFrequ);
}
// *********************************************************************
int main (void)
{
DWORD dwMonThreadId;
DWORD dwComThreadId;
HANDLE hMonThread;
HANDLE hComThread;
DWORD dwState;
PARAMS p;
// MonitorThread erstellen:
// Erstellt den Event für die Thread Queue
hEvent = CreateEvent (NULL, false, true, QEVENT);
// Thread starten und uMonThreadID für ComThread merken
hMonThread = CreateThread ( // Handle des Threads
NULL, // no security attributes
0, // use default stack size
MonitorThread, // thread function
&p, // argument to thread function
0, // use default creation flags
&dwMonThreadId); // returns the thread identifier
if (hMonThread == NULL)
printf ("\r\nCreateThread (MonitorThread) fehlgeschlagen");
p.dwMonitorThreadId = dwMonThreadId; // merken, für ComThread
// wait for queue completition
dwState = WaitForSingleObject (hEvent, 100);
CloseHandle (hEvent);
// "alten" Thread stoppen
p.ThreadStoppen = TRUE;
CloseHandle (hComThread); // "alten" Thread stoppen
p.iComPortNum = 1;
// ComThread: Starten und Parameterstruct übergeben
p.ThreadStoppen = FALSE;
hComThread = CreateThread ( // Handle des Threads
NULL, // no security attributes
0, // use default stack size
ComThread, // thread function
&p, // argument to thread function
0, // use default creation flags
&dwComThreadId); // returns the thread identifier
if (hComThread == NULL)
printf ("\r\nCreateThread (ComThread) fehlgeschlagen");
Sleep (30000); // nur so zum Test
CloseHandle (hMonThread); // MonitorThread beenden
CloseHandle (hComThread); // ComThread beenden
return (0);
}
Anpassen an die Borland-Sytax/Notation sollte nicht schwer sein.
Lesezeichen