ReadFile mit Timeout
-
Hallo,
Ich versuche schon verzweifelt etwas zu finden, wie ich auf einer Comm-Schnittstelle ein "ReadFile" mit timeout machen kann. Dabei soll der timeout nicht erst aktiv werden, wenn ein Bit schon gelesen wurde(Wie es, so wie ich es verstehe, mit der "COMMTIMEOUTS" Struktur und "SetCommTimeouts" gemacht wird), sondern "ReadFile" soll nur dann aufgerufen werden, wenn es etwas zu lesen gibt.
Bem. : unter Linux lässt sich das ganze mit "select" erreichen, doch bei Windows ist "select" wohl ausschließlich für "sockets" gedacht.
Bim um eure Hilfe sehr dankbar
Grüße
lberger
-
SetCommMask mit EV_RXCHAR und WaitCommEvent verwenden.
Blackbird
-
Guck dir mal Overlapped IOan:
- file mit Flag_FILE_OVERLAPPED initialisieren
- OVERLAPPED-struktur bei ReadFile mit angeben (dort gibst du auch ein Event mit an, das gesetzt wird wenn das read beendet ist)
- mit WaitForSingle / Multiple Objects auf das Event warten
- wenn dabei einen Timeout gibt, den Transfer mit CancelIO abbrechen
- das Ergebnis mit GetOverlappedResult auswerten
-
1. mit SetCommMask() ein Event festlegen
1a. mit SetCommTimeouts() Timeout fuer ReadFile() festlegen
2. mit WaitCommEvent() warten, bis was da ist
3. mit ReadFile() lesenAm besten das Ganze in einen Minithread verpacken, dann kann das im Hintergrund werkeln.
-
SetCommTimeouts()
*patsch* Ich wußte doch, daß es für die serielle was einfacheres gibt
-
Hi,
Folgenden Code habe ich mir von der MSDN Seite kopiert und etwas abgeändert,
so daß bei einem Read-event gelesen werden sollte. Funktioniert so aber nicht.
Wenn ich mich mit dem Hyperteminal dranhänge, und über ein Nullmodemkabel Zeichen an COMM1 sende, werden weitehin nur "Punkte" gezeichnet!!!
Und nicht wie erwartet, dass eingegebende Zeichen.
Wie gesagt, einfach mit CommTimeouts geht das wohl auch nicht, da hierzu erst einmal ein bit gelesen werden muss, und wenn dann Innerhalb des "Timeouts" kein Zeichen mehr kommt, kehrt ReadFile zurück, natürlich mit weniger gelesenen Bits als angefordert.#include <windows.h> #include <assert.h> #include <stdio.h> void main( ) { HANDLE hCom; OVERLAPPED o; BOOL fSuccess; DWORD dwEvtMask; char c = '\0'; unsigned long X; DCB dcb; COMMTIMEOUTS ctout; dcb.DCBlength = sizeof(dcb); dcb.BaudRate = 9600; dcb.Parity = NOPARITY; dcb.ByteSize = 8; dcb.StopBits = ONESTOPBIT; ctout.ReadTotalTimeoutConstant = 50; hCom = CreateFile( "COM1", GENERIC_READ | GENERIC_WRITE, 0, // exclusive access NULL, // default security attributes OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL ); if (hCom == INVALID_HANDLE_VALUE) { // Handle the error. printf("CreateFile failed with error %d.\n", GetLastError()); return; } SetCommTimeouts(hCom, &ctout); SetCommState(hCom, &dcb); // Set the event mask. fSuccess = SetCommMask(hCom, EV_RXCHAR); // Create an event object for use by WaitCommEvent. o.hEvent = CreateEvent( NULL, // default security attributes FALSE, // auto reset event FALSE, // not signaled NULL // no name ); // Intialize the rest of the OVERLAPPED structure to zero. o.Internal = 0; o.InternalHigh = 0; o.Offset = 0; o.OffsetHigh = 0; assert(o.hEvent); while (1) { fSuccess = SetCommMask(hCom, EV_RXCHAR); if (!fSuccess) { // Handle the error. printf("SetCommMask failed with error %d.\n", GetLastError()); return; } WaitForSingleObject(hCom, 1000); if (WaitCommEvent(hCom, &dwEvtMask, &o)) { if (dwEvtMask & EV_RXCHAR) { ReadFile(hCom, &c, 1, &X, &o); printf("%c", c); } } else { DWORD dwRet = GetLastError(); if( ERROR_IO_PENDING == dwRet) { printf("."); // To do. } else printf("Wait failed with error %d.\n", GetLastError()); } }//while (1) }
Was habe ich nicht richtig verstanden?
-
Möglicherweise WaitCommEvent und WaitForSingleObject in der Reihenfolge vertauscht?
Hier ist ein Code-Schnipsel, mußt noch ReadFile einbauen:
/********************************************************************** ** Testprogramm: Wartet auf eine Pegeländerung an DSR, CTS, ... an COM1 ** ** Getestet: OK ab 12/2002! **********************************************************************/ #include <windows.h> #include <stdio.h> #define TIMELIMIT 100000 // Programm läuft 100 Sekunden // zusätzliche Events (DDK) #define SERIAL_EV_RXCHAR 0x0001 // Any Character received #define SERIAL_EV_RXFLAG 0x0002 // Received certain character #define SERIAL_EV_TXEMPTY 0x0004 // Transmitt Queue Empty #define SERIAL_EV_CTS 0x0008 // CTS changed state #define SERIAL_EV_DSR 0x0010 // DSR changed state #define SERIAL_EV_RLSD 0x0020 // RLSD changed state #define SERIAL_EV_BREAK 0x0040 // BREAK received #define SERIAL_EV_ERR 0x0080 // Line status error occurred #define SERIAL_EV_RING 0x0100 // Ring signal detected #define SERIAL_EV_PERR 0x0200 // Printer error occured #define SERIAL_EV_RX80FULL 0x0400 // Receive buffer is 80 percent full #define SERIAL_EV_EVENT1 0x0800 // Provider specific event 1 #define SERIAL_EV_EVENT2 0x1000 // Provider specific event 2 // Prototypes const char* decimalToBinary (const long value, const unsigned length, char* pszBuffer); /******************************************************************** ** DOS32-programm läuft TIMELIMIT / 1000 Sekunden und zeigt alle ** Pegeländerungen an COM 1 an ********************************************************************/ int main (void) { HANDLE hCom; OVERLAPPED o; DWORD dwStart; DWORD dwEvtMaskIn = EV_CTS | EV_DSR | EV_BREAK | EV_RING | EV_RXCHAR | EV_RLSD | EV_ERR | EV_RXFLAG | EV_TXEMPTY | SERIAL_EV_PERR | SERIAL_EV_RX80FULL | SERIAL_EV_EVENT1 | SERIAL_EV_EVENT2; DWORD dwEvtMask = 0; char szString[] = ("\r\nWarte auf Events (Pegelaenderungen) an COM 1:\r\n\ EV_RXCHAR =0x%04x\r\nEV_RXFLAG =0x%04x\r\nEV_TXEMPTY =0x%04x\r\n\ EV_CTS =0x%04x\r\nEV_DSR =0x%04x\r\nEV_RLSD =0x%04x\r\n\ EV_BREAK =0x%04x\r\nEV_ERR =0x%04x\r\nEV_RING =0x%04x\r\n\ EV_PERR =0x%04x\r\nEV_RX80FULL=0x%04x\r\nEV_EVENT1 =0x%04x\r\n\ EV_EVENT2 =0x%04x"); char szBuf[sizeof (DWORD) * 8] = ""; // für decimalToBinary-Funktion SYSTEMTIME SystemTime; // system time TCHAR lpszMsg[127] = ""; printf (szString, EV_RXCHAR, EV_RXFLAG, EV_TXEMPTY, EV_CTS, EV_DSR, EV_RLSD, EV_BREAK, EV_ERR, EV_RING, SERIAL_EV_PERR, SERIAL_EV_RX80FULL, SERIAL_EV_EVENT1, SERIAL_EV_EVENT2); hCom = CreateFile ("COM1", GENERIC_READ | GENERIC_WRITE, 0, // exclusive access NULL, // no security attributes OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (hCom == INVALID_HANDLE_VALUE) return printf ("\r\nCOM1 kann nicht geöffnet werden"); if (!SetCommMask (hCom, dwEvtMaskIn)) return printf ("\r\nSetCommMask fehlgeschlagen"); // 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 dwStart = GetTickCount (); while (GetTickCount () - dwStart < TIMELIMIT) { WaitCommEvent (hCom, &dwEvtMask, &o); if (WAIT_OBJECT_0 == WaitForSingleObject (o.hEvent, INFINITE)) { GetLocalTime (&SystemTime); printf ("\r\nEvents: %s - ", decimalToBinary (dwEvtMask, sizeof (DWORD) * 8, szBuf)); if (dwEvtMask & EV_DSR) printf ("DSR "); if (dwEvtMask & EV_CTS) printf ("CTS "); if (dwEvtMask & EV_BREAK) printf ("BREAK "); if (dwEvtMask & EV_RING) printf ("RING "); if (dwEvtMask & EV_RXCHAR) printf ("RXCHAR "); if (dwEvtMask & EV_RLSD) printf ("RLSD "); if (dwEvtMask & EV_ERR) printf ("ERR "); if (dwEvtMask & EV_RXFLAG) printf ("RXFLAG "); if (dwEvtMask & EV_TXEMPTY) printf ("TXEMPTY "); if (dwEvtMask & SERIAL_EV_PERR) printf ("PERR "); if (dwEvtMask & SERIAL_EV_RX80FULL) printf ("RX80FULL "); if (dwEvtMask & SERIAL_EV_EVENT1) printf ("EVENT1 "); if (dwEvtMask & SERIAL_EV_EVENT2) printf ("EVENT2 "); wsprintf (lpszMsg, "%s, den %02d.%02d.%04d um %d:%d Uhr %d,%d Sek.", SystemTime.wDayOfWeek == 1 ? "Mo" : (SystemTime.wDayOfWeek == 2 ? "Di" : (SystemTime.wDayOfWeek == 3 ? "Mi" : (SystemTime.wDayOfWeek == 4 ? "Do" : (SystemTime.wDayOfWeek == 5 ? "Fr" : (SystemTime.wDayOfWeek == 6 ? "Sa" : (SystemTime.wDayOfWeek == 7 ? "So" : "Heute")))))), SystemTime.wDay, SystemTime.wMonth, SystemTime.wYear, SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond, SystemTime.wMilliseconds); printf (": %s", lpszMsg); } } CloseHandle (o.hEvent); CloseHandle (hCom); return printf ("\r\n!ENDE! %d Sekunden sind um!\r\n", TIMELIMIT / 1000); } /***************************************************************************** ** Umwandlung: Dezimal zu Binär ** ** 1. Param: die Zahl ** 2. Param: Anzahl der Binärstellen (von 1..32) ** 3. Param: Zeiger auf ein char-Array, das den String aufnehmen kann *****************************************************************************/ const char* decimalToBinary (const long value, const unsigned length, char* pszBuffer) { if ((length == 0) || (length > 32)) { pszBuffer = '\0'; return pszBuffer; } unsigned digit = 1 << (length - 1); char* pszCurrent = pszBuffer; do { if (value & digit) *pszCurrent = '1'; else *pszCurrent = '0'; pszCurrent++; digit /= 2; } while (digit != 0); *pszCurrent = '\0'; return pszBuffer; }
Blackbird
-
Hey vielen Dank,
Ich habe den Code jetzt foldendermaßen abgeändert, es besteht aber noch das Problem, daß die eingegebenen Bytes nicht richtig Empfangen werden. Manchnal kommt garnichts, und ein anderesmal immer ein "o" mit "Tilde" ("~"), unabhängig, welchen key ich drücke.Hier der abgeänderte Code, mit dem zumindest das Timeout funktioniert:
/********************************************************************** ** Testprogramm: Wartet auf eine Pegeländerung an DSR, CTS, ... an COM1 ** ** Getestet LB: OK ab 05/2005! **********************************************************************/ #include <windows.h> #include <stdio.h> #define TIMELIMIT 100000 // Programm läuft 100 Sekunden // zusätzliche Events (DDK) #define SERIAL_EV_RXCHAR 0x0001 // Any Character received #define SERIAL_EV_RXFLAG 0x0002 // Received certain character #define SERIAL_EV_TXEMPTY 0x0004 // Transmitt Queue Empty #define SERIAL_EV_CTS 0x0008 // CTS changed state #define SERIAL_EV_DSR 0x0010 // DSR changed state #define SERIAL_EV_RLSD 0x0020 // RLSD changed state #define SERIAL_EV_BREAK 0x0040 // BREAK received #define SERIAL_EV_ERR 0x0080 // Line status error occurred #define SERIAL_EV_RING 0x0100 // Ring signal detected #define SERIAL_EV_PERR 0x0200 // Printer error occured #define SERIAL_EV_RX80FULL 0x0400 // Receive buffer is 80 percent full #define SERIAL_EV_EVENT1 0x0800 // Provider specific event 1 #define SERIAL_EV_EVENT2 0x1000 // Provider specific event 2 // Prototypes const char* decimalToBinary (const long value, const unsigned length, char* pszBuffer); /******************************************************************** ** DOS32-programm läuft TIMELIMIT / 1000 Sekunden und zeigt alle ** Pegeländerungen an COM 1 an ********************************************************************/ int main (void) { HANDLE hCom; OVERLAPPED o; DWORD dwStart; DWORD rv; char c = '\0'; unsigned long X; DWORD dwEvtMaskIn = EV_CTS | EV_DSR | EV_BREAK | EV_RING | EV_RXCHAR | EV_RLSD | EV_ERR | EV_RXFLAG | EV_TXEMPTY | SERIAL_EV_PERR | SERIAL_EV_RX80FULL | SERIAL_EV_EVENT1 | SERIAL_EV_EVENT2; DWORD dwEvtMask = 0; char szString[] = ("\r\nWarte auf Events (Pegelaenderungen) an COM 1:\r\n\ EV_RXCHAR =0x%04x\r\nEV_RXFLAG =0x%04x\r\nEV_TXEMPTY =0x%04x\r\n\ EV_CTS =0x%04x\r\nEV_DSR =0x%04x\r\nEV_RLSD =0x%04x\r\n\ EV_BREAK =0x%04x\r\nEV_ERR =0x%04x\r\nEV_RING =0x%04x\r\n\ EV_PERR =0x%04x\r\nEV_RX80FULL=0x%04x\r\nEV_EVENT1 =0x%04x\r\n\ EV_EVENT2 =0x%04x"); char szBuf[sizeof (DWORD) * 8] = ""; // für decimalToBinary-Funktion SYSTEMTIME SystemTime; // system time TCHAR lpszMsg[127] = ""; printf (szString, EV_RXCHAR, EV_RXFLAG, EV_TXEMPTY, EV_CTS, EV_DSR, EV_RLSD, EV_BREAK, EV_ERR, EV_RING, SERIAL_EV_PERR, SERIAL_EV_RX80FULL, SERIAL_EV_EVENT1, SERIAL_EV_EVENT2); hCom = CreateFile ("COM1", GENERIC_READ | GENERIC_WRITE, 0, // exclusive access NULL, // no security attributes OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (hCom == INVALID_HANDLE_VALUE) return printf ("\r\nCOM1 kann nicht geöffnet werden"); if (!SetCommMask (hCom, dwEvtMaskIn)) return printf ("\r\nSetCommMask fehlgeschlagen"); // 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 dwStart = GetTickCount (); while (GetTickCount () - dwStart < TIMELIMIT) { WaitCommEvent (hCom, &dwEvtMask, &o); rv = WaitForSingleObject (o.hEvent, 1000); //geändert LB if (WAIT_OBJECT_0 == rv ) { GetLocalTime (&SystemTime); printf ("\r\nEvents: %s - ", decimalToBinary (dwEvtMask, sizeof (DWORD) * 8, szBuf)); if (dwEvtMask & EV_DSR) printf ("DSR "); if (dwEvtMask & EV_CTS) printf ("CTS "); if (dwEvtMask & EV_BREAK) printf ("BREAK "); if (dwEvtMask & EV_RING) printf ("RING "); if (dwEvtMask & EV_RXCHAR) { //geändert LB printf("**********************************\n"); ReadFile(hCom, &c, 1, &X, &o); printf("Read char: %c\n"); printf("**********************************\n"); printf ("RXCHAR "); } if (dwEvtMask & EV_RLSD) printf ("RLSD "); if (dwEvtMask & EV_ERR) printf ("ERR "); if (dwEvtMask & EV_RXFLAG) printf ("RXFLAG "); if (dwEvtMask & EV_TXEMPTY) printf ("TXEMPTY "); if (dwEvtMask & SERIAL_EV_PERR) printf ("PERR "); if (dwEvtMask & SERIAL_EV_RX80FULL) printf ("RX80FULL "); if (dwEvtMask & SERIAL_EV_EVENT1) printf ("EVENT1 "); if (dwEvtMask & SERIAL_EV_EVENT2) printf ("EVENT2 "); wsprintf (lpszMsg, "%s, den %02d.%02d.%04d um %d:%d Uhr %d,%d Sek.", SystemTime.wDayOfWeek == 1 ? "Mo" : (SystemTime.wDayOfWeek == 2 ? "Di" : (SystemTime.wDayOfWeek == 3 ? "Mi" : (SystemTime.wDayOfWeek == 4 ? "Do" : (SystemTime.wDayOfWeek == 5 ? "Fr" : (SystemTime.wDayOfWeek == 6 ? "Sa" : (SystemTime.wDayOfWeek == 7 ? "So" : "Heute")))))), SystemTime.wDay, SystemTime.wMonth, SystemTime.wYear, SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond, SystemTime.wMilliseconds); printf (": %s", lpszMsg); } if (rv == WAIT_TIMEOUT) { //geändert LB printf("."); } } CloseHandle (o.hEvent); CloseHandle (hCom); return printf ("\r\n!ENDE! %d Sekunden sind um!\r\n", TIMELIMIT / 1000); } /***************************************************************************** ** Umwandlung: Dezimal zu Binär ** ** 1. Param: die Zahl ** 2. Param: Anzahl der Binärstellen (von 1..32) ** 3. Param: Zeiger auf ein char-Array, das den String aufnehmen kann *****************************************************************************/ const char* decimalToBinary (const long value, const unsigned length, char* pszBuffer) { if ((length == 0) || (length > 32)) { pszBuffer = '\0'; return pszBuffer; } unsigned digit = 1 << (length - 1); char* pszCurrent = pszBuffer; do { if (value & digit) *pszCurrent = '1'; else *pszCurrent = '0'; pszCurrent++; digit /= 2; } while (digit != 0); *pszCurrent = '\0'; return pszBuffer; }
-
Ich habe jetzt auch noch versucht die Baudrate neu zu setzen,
daß Problem bleibt aber dasgleiche:DCB dcb; : : GetCommState(hCom, &dcb); dcb.DCBlength = sizeof(DCB); dcb.BaudRate = 9600; dcb.Parity = NOPARITY; dcb.ByteSize = 8; dcb.StopBits = ONESTOPBIT; if (!SetCommState(hCom, &dcb) ) return printf("\r\nSetCommState fehlgeschlagen"); : :
-
Ein Dummer Fehler, habe bei printf vergessen die char variable c anzugeben. Doch dennoch wurden die Zeichen nicht richtig interpretiert. Du hast noch vergessen, den Rest der OVERLAPPED struktur zu initialisieren:
// Intialize the rest of the OVERLAPPED structure to zero. o.Internal = 0; o.InternalHigh = 0; o.Offset = 0; o.OffsetHigh = 0;
Grüße
lberger
-
Hm, ja - hast recht, explizit initialisieren wäre besser.
Hab' den code umgeschrieben, von allen Ballast befreit:
// DOS32-Programm zum Senden/Empfangen von Bytes über COM (9600-8N1) // Alle empfangenen Bytes werden zurückgesendet. // OS: W95, W98, W98SE, WinME, WinNT, Win2000, WinXP // Note: Keine Fehlerbehandlung implementiert! #include <windows.h> #include <stdio.h> #define COM_BUFFER_SIZE 256 // Read- und Write-Buffer-Size #define BD_RATE CBR_9600 // 9600 Baud #define HELP_STRING TEXT("Aufruf mit: progname <COM-Port-Nummer>\r\n") // Hauptprogramm: Aufruf mit: progname <COM-Port-Nummer> int main (int argc, char **argv) { DCB dcb; DWORD iBytesWritten; BOOL bRet = true; DWORD dwRead = 0; DWORD dwSetMask = EV_RXCHAR | EV_ERR; DWORD dwEvtMask; OVERLAPPED o; COMMTIMEOUTS ct; unsigned char InString[COM_BUFFER_SIZE + 1]; TCHAR szCOM[6]; if (argc == 2 && // progname + COM-Port-Nummer ? atoi (argv[1]) > 0 && atoi (argv[1]) < 5) // COM1 ... COM4? wsprintf (szCOM, TEXT("COM%s"), argv[1]); // String "basteln" ... else { printf (TEXT("\r\nERROR:\t %s"), HELP_STRING); return (1); // und tschüß ... } memset (&o, 0, sizeof (OVERLAPPED)); // Struktur mit 0en füllen o.hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); // einen Event setzten HANDLE hCom = CreateFile (szCOM, GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); if (hCom == INVALID_HANDLE_VALUE) { // Fehlerausgabe: 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, "Error: CreateFile", MB_OK | MB_ICONINFORMATION); LocalFree (lpMsgBuf); return (1); // und tschüß ... } dcb.DCBlength = sizeof(DCB); // Laenge des Blockes MUSS gesetzt sein! GetCommState (hCom, &dcb); // COM-Einstellungen holen und aendern dcb.BaudRate = BD_RATE; // Baudrate dcb.ByteSize = 8; // Datenbits dcb.Parity = NOPARITY; // Parität dcb.StopBits = ONESTOPBIT; // Stopbits SetCommState (hCom, &dcb); // COM-Einstellungen speichern GetCommTimeouts (hCom, &ct); // Warte-Zeit [ms] vom Beginn eines Bytes bis zum Beginn des nächsten Bytes ct.ReadIntervalTimeout = 1000 / BD_RATE * (dcb.ByteSize + (dcb.Parity == NOPARITY ? 0 : 1) + (dcb.StopBits == ONESTOPBIT ? 1 : 2)) * 2; ct.ReadTotalTimeoutMultiplier = 0; // [ms] wird mit Read-Buffer-Size multipliziert ct.ReadTotalTimeoutConstant = 50; // wird an ReadTotalTimeoutMultiplier angehängt ct.WriteTotalTimeoutMultiplier = 0; ct.WriteTotalTimeoutConstant = 0; SetCommTimeouts (hCom, &ct); // Zwischenspeicher des serial-Drivers einstellen (für read und write): SetupComm (hCom, COM_BUFFER_SIZE, COM_BUFFER_SIZE); SetCommMask (hCom, dwSetMask); // Empfangssignale definieren do // in Endlos-Schleife auf Empfangssignale warten: { WaitCommEvent (hCom, &dwEvtMask, &o); // Event mit Empfangssignalen verknüpfen if (WAIT_OBJECT_0 == WaitForSingleObject (o.hEvent, INFINITE)) // warten bis Event { if (dwEvtMask & EV_RXCHAR) // Zeichen an RxD empfangen: { bRet = ReadFile (hCom, &InString, sizeof (InString), &dwRead, NULL); if (!bRet) { // Fehlerausgabe: 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, "Error: ReadFile", MB_OK | MB_ICONINFORMATION); LocalFree (lpMsgBuf); } else { // Ausgabe (oder Verarbeitung) der empfangenen Bytes: InString[dwRead] = '\0'; // in "zero-ended"-String verwandeln printf (TEXT("\r\n\tRxD (%d Byte(s)): %s"), dwRead, InString); WriteFile (hCom, &InString, dwRead, &iBytesWritten, NULL); // Senden der Bytes } } if (dwEvtMask & EV_ERR) { MessageBox (NULL, "Error empfangen", "Error: ReadFile", MB_OK); break; // Schleifen-Abbruch } } } while (1); CloseHandle (hCom); // COM schließen CloseHandle (o.hEvent); // Event-Handle zurückgeben return (0); }
So geht's. Ist getestet.
Blackbird
PS: hab' schon wieder vergessen die OVERLAPPED struct explizit zu setzen - mußt Du noch einfügen?
-
Ja, super, das ging ja schnell.
Ich habe noch eine Verständnissfrage:
Was soll das mit den Commtimeouts? Zuerst dachte ich ja, super, damit wird alles ganz einfach. Setze "ct.ReadTotalTimeoutConstant" auf einen Wert, wie z.B 50 ms, dann kehrt ReadFile schon automatisch nach 50 ms zurueck. Aber so einfach geht das scheinbar nicht.
In deinem letzten Code wird ja eigentlich die Timeoutzeit mit "WaitForSingleObject" gesetzt, was nuetzt da "SetCommTimeOuts()"???Vielen Dank fuer Klaerung.
-
Das sind die Warte-Zeiten zwischen einzelnen Frames, also wenn die Frames (StartBit,Daten,Stopbit(s)) nicht unmittelbar aneineandergereiht sind, sondern Pausen dazwischen sind. Die Zeiten in der Struct bestimmen, wann ein "Datenstrom" beginnt und endet und damit die Verarbeitung beginnen kann. Sonst wird nach jedem Zeichen im read buffer die "Verarbeitung" angestoßen.
Blackbird
-
Also das ganze geht doch tatsächlich viel einfacher, die Timeouts haben wohl doch tatsächlich die Bedeutung, wie ich zuerst gedacht habe! Also mit folgender initialisierung des Comports:
int init_com() { DCB dcb; COMMTIMEOUTS ct; com = CreateFile(COM_PORT, GENERIC_READ | GENERIC_WRITE,0,NULL, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0); if (com == INVALID_HANDLE_VALUE) { return -1; } GetCommState(com, &dcb); dcb.DCBlength = sizeof(DCB); dcb.BaudRate = 9600; dcb.Parity = NOPARITY; dcb.ByteSize = 8; dcb.StopBits = ONESTOPBIT; if (!SetCommState(com, &dcb) ) { MessageBeep(1); } GetCommTimeouts(com, &ct); // Warte-Zeit [ms] vom Beginn eines Bytes bis zum Beginn des nächsten Bytes ct.ReadIntervalTimeout = 1000 / 9600 * (dcb.ByteSize + (dcb.Parity == NOPARITY ? 0 : 1) + (dcb.StopBits == ONESTOPBIT ? 1 : 2)) * 2; ct.ReadTotalTimeoutMultiplier = 0; // [ms] wird mit Read-Buffer-Size multipliziert ct.ReadTotalTimeoutConstant = 1000; // wird an ReadTotalTimeoutMultiplier angehängt ct.WriteTotalTimeoutMultiplier = 0; ct.WriteTotalTimeoutConstant = 0; SetCommTimeouts(com, &ct); return 0; }
und anschließendem Readaufruf in der MainfunktionÖ
int main() { unsigned int X; unsigned char c; char buff[256]; int i = 0; char end_char; FILE *stream; init_com(); while (1) { ReadFile(com, &c, 1, &X, NULL); if (X == 0) { printf("."); continue; } else if (c != ' ' && c != '\r') { printf("%c", c); buff[i++] = c; continue; } }
erhalte ich das gewünschte timeout verhalten: ReadFile kehrt nach 1s zurück, ohne ein Zeichen gelesen zu haben, d.h X == 0, wenns nicht's zu lesen gibt, ließt den entprechenden char, wenns was zu lesen gibt.
Na ja, oft muss man erst komplizierte Wege gehen, um die Einfachen zu verstehen.
Also nochmals vielen Dank für deine Hilfe
-
hi,
gibt es hier jemanden, der mir das mit dem overlapped erklären hat?
ich verstehe die sache nicht wirklich.mein problem ist folgendes,
ich habe ein gerät am comm, dass mir ständig daten schickt, ich muß aber trotzem ab und zu mal was hinschicken, um zB den status zu erfragen.CreateFile( cPort, GENERIC_READ|GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_WRITE_THROUGH,//|FILE_FLAG_OVERLAPPED, NULL);
dcb.DCBlength = sizeof(dcb); dcb.fBinary = TRUE; dcb.fParity = FALSE; dcb.fOutxCtsFlow = FALSE; dcb.fOutxDsrFlow = FALSE; dcb.fDtrControl = DTR_CONTROL_DISABLE; dcb.fDsrSensitivity = FALSE; dcb.fTXContinueOnXoff = FALSE; dcb.fOutX = FALSE; dcb.fInX = FALSE; dcb.fErrorChar = FALSE; dcb.fNull = FALSE; dcb.fRtsControl = RTS_CONTROL_DISABLE; dcb.fAbortOnError = FALSE; dcb.wReserved = 0; dcb.BaudRate = iBaud; dcb.ByteSize = (BYTE)iBits; dcb.Parity = (BYTE)iParity; dcb.StopBits = (BYTE)iStop; dcb.fParity = (dcb.Parity != NOPARITY);
COMMTIMEOUTS timeouts; timeouts.ReadIntervalTimeout = 10; timeouts.ReadTotalTimeoutConstant = 0; timeouts.ReadTotalTimeoutMultiplier = 10; timeouts.WriteTotalTimeoutConstant = 50; timeouts.WriteTotalTimeoutMultiplier = 50;
wenn ich auf diese weise nur mit ReadFile und WriteFile arbeite dann funktioniert es, außer dass sich das programm manchmal nicht nachvollziehbar beim senden aufhängt, sieht so aus als würde ReadFile nach dem timeout nicht beendet... ?
wenn ich overlapped arbeite, dann funktioniert es fast gar nicht?
OVERLAPPED osStatus={0}; osStatus.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
WORD WaitComm() { DWORD dwCommEvent; // result from WaitCommEvent DWORD dwOvRes; // result from GetOverlappedResult DWORD dwRes; // result from WaitForSingleObject BOOL fWaitingOnStat = FALSE; DWORD StatusTimeout = 100; DWORD dw_Tmp = EV_RXCHAR; if(!SetCommMask(GetHandle(), dw_Tmp)) { MessageBox(0, "error", "error", MB_OK); CloseHandle(osStatus.hEvent); // osStatus außerhalb angelegt return 1; } if (!WaitCommEvent(GetHandle(), &dwCommEvent, &osStatus)) { if (GetLastError() != ERROR_IO_PENDING) { // Wait not delayed? ResetEvent(osStatus.hEvent); return 1; } else fWaitingOnStat = TRUE; } else { ResetEvent(osStatus.hEvent); return 0; } switch(dwCommEvent) { case EV_RXCHAR: // // wait for pending operation to complete // if( fWaitingOnStat) { dwRes = WaitForSingleObject(osStatus.hEvent ,StatusTimeout); switch(dwRes) { // // status completed // case WAIT_OBJECT_0: if (!GetOverlappedResult(GetHandle(), &osStatus, &dwOvRes, TRUE)) { MessageBox(0, "error thickness sensor wait event", "error", MB_OK); } else { // status check completed successfully fWaitingOnStat = FALSE; // // reset event handles // ResetEvent(osStatus.hEvent); return 0; } break; case WAIT_TIMEOUT: // timeout occured // no new characters are placed in input buffer // // ResetEvent(osStatus.hEvent); return 1; default: ResetEvent(osStatus.hEvent); return 2; } } break; } return 3;
read und write func:
int SendData(char *buffer, int iBytesToWrite ) //Daten senden { DWORD dwRes; if(GetHandle() == INVALID_HANDLE_VALUE) { ResetEvent(this->osStatus.hEvent); return(0); } DWORD dwBytesWritten=0, dwRet=0; if(!PurgeComm(GetHandle(), PURGE_TXCLEAR | PURGE_RXCLEAR )) { ResetEvent(osStatus.hEvent); return 0; } for(int i=0; i<iBytesToWrite; i++) { if(i == iBytesToWrite-1) if(!PurgeComm(hCom, PURGE_RXCLEAR)) // um antwort besser filtern zu können { ResetEvent(osStatus.hEvent); return 0; } if(!WriteFile(GetHandle(), &buffer[i], 1, &dwBytesWritten, &osStatus)) // string an com senden { // Sleep(1); if (GetLastError() != ERROR_IO_PENDING) { ResetEvent(osStatus.hEvent); return 0; } else { // // write is delayed // dwRes = WaitForSingleObject(osStatus.hEvent, 100); switch(dwRes) { // // write event set // case WAIT_OBJECT_0: if (!GetOverlappedResult(GetHandle(), &osStatus, &dwBytesWritten, TRUE)) { // fRes = TRUE; } /* if (dwWritten != dwToWrite) { fRes = TRUE; } else fRes = FALSE; */ ResetEvent(osStatus.hEvent); ++dwRet; break; // // wait timed out // break; case WAIT_TIMEOUT: ResetEvent(osStatus.hEvent); return 0; default:// ResetEvent(osStatus.hEvent); // return 0; } } } else { // // writefile returned immediately // ResetEvent(osStatus.hEvent); ++dwRet; } } return((int)dwRet); }
int ReadData(char *buffer, int iBytesToRead) { // Sleep(1); // <-- ohne WaitForSingleObject bekomme ich an dieser stelle ohne das sleep fast nur "mist" ausgelesen if(GetHandle()== INVALID_HANDLE_VALUE) { return(0); } DWORD dwRead =0; char cRead[2]={0}; int i=0; bool fWaitingOnRead; if(ReadFile(GetHandle(), cRead, 1, &dwRead, &osStatus)) // jedes zeichen einzeln von der com abholen { if(dwRead !=1 ) { ResetEvent(osStatus.hEvent); return -1; } else { buffer[i++] = cRead[0]; if(i>=iBytesToRead-1) { ResetEvent(osStatus.hEvent); return(dwRead); } } } else { if (GetLastError() != ERROR_IO_PENDING) { // read not delayed? ResetEvent(osStatus.hEvent); return -1; } else { fWaitingOnRead = TRUE; // while (!HasOverlappedIoCompleted(&this->osStatus));// <-- funktioniert auch nicht besser } // wait for pending operations to complete // if (fWaitingOnRead ) { dwRead = WaitForSingleObject(osStatus.hEvent, 100); switch(dwRead) { // // read completed // case WAIT_OBJECT_0: if (!GetOverlappedResult(GetHandle(), &osStatus, &dwRead, TRUE)) { ResetEvent(osStatus.hEvent); return -1; } else { // read completed successfully ResetEvent(osStatus.hEvent); return dwRead; } case WAIT_TIMEOUT: // // timeout, no character comes from comm ResetEvent(osStatus.hEvent); return -1; default: ResetEvent(osStatus.hEvent); return -1; } } } ResetEvent(osStatus.hEvent); return -1; }
wenn ich im main soowas mache wie:
while(1) { Wait(); while(ReadData()>0) // mach was mit den sachen }
wenn ich mir die ereignisse mitlogge, dann habe ich das Wait, dann read und irgendwann kommt aber wait und dann wieder wait, aber mit INVALID_PARAMETER und beim overlapped nur das ReadFile mit dem timeout liest nicht das von der comm was ankommt???
hat jemand ne idee?
gruß
Tommi
-
hmm...
kann da keiner helfen?
hab mal etwas an den timeouts rumgestellt, das hilft gar nichlaut msdn ist
BOOL GetOverlappedResult( HANDLE hFile, // handle to file, pipe, or comm device LPOVERLAPPED lpOverlapped, // pointer to overlapped structure LPDWORD lpNumberOfBytesTransferred, // pointer to actual bytes count BOOL bWait // wait flag ); Parameters hFile bWait Specifies whether the function should wait for the pending overlapped operation to be completed. If TRUE, the function does not return until the operation has been completed. If FALSE and the operation is still pending, the function returns FALSE and the GetLastError function returns ERROR_IO_INCOMPLETE.
wenn ich das richtig verstanden habe sollte die anwendung an dieser stelle "warten" bis sie fertig ist?
wie kann es dann aber sein, dass WaitCommEvent mehrmals hintereinander (erst "normal" und dann mit INVALID_PARAMETER) aufgerufen wird?
was mache ich falsch?
mfg