Hallo! Nach stundenlangen Tests mal hier die Anfrage bei euch: Ich habe auf Basis der LUFA Library und einem USB-AVR eine Firmware mit zwei virtuellen Schnittstellen erstellt. eine dient der Kommunikation zw. AVR und PC. Jetzt habe ich das Problem, dass meine Applikation nicht funktioniert und ich weiß gerade nicht weiter: Ich verwende die WinAPI um über die serielle mit dem Gerät zu kommunizieren. Mittlerweile bin ich der Meinung, dass das Problem beim Windows eigenen USB-seriell Treiber oder im FileRead bzw. FileWrite liegt. Zum Programmablauf: Es werden mehrere Byte (zw. 2 und 20) an das Gerät geschickt und danach 1 Byte zurückgelesen. Hier ein "Code-Schnippel": // create file not overlapped flasher_port = CreateFile(strcat(buf, jtag_port), GENERIC_READ |GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); .... // write some bytes --> 2 .... 16 bytes if (!WriteFile(flasher_port, usb_cache, 2 + usb_cache_cnt + 3 / 4, &written, NULL)) { fprintf(stderr, "Sending BLOCK_DATA error!\n"); exit(1); } // read 1 byte if (!ReadFile(flasher_port, recbuf, sizeof (unsigned char), &read, NULL)) { fprintf(stderr, "Can't receive BLOCK_DATA response!\n"); exit(1); } Jetzt kann es passieren, dass ReadFile keinen Fehler zurückmeldet, aber statt 1 Byte (sizeof (unsigned char)) leider 0 in die read Variable schreibt. Das ganze natürlich obwohl das Gerät geantwortet hat, d.h. dieses Byte übertragen hat. Dadurch stürzt mein Programm in weiterer Folge ab. Ich habe nun eine Zeile eingefügt in der das Programm bevor es weiter macht überprüft, ob eh ein Byte gelesen wurde und falls nicht dann noch ein Mal liest. So funktioniert dieser Teil des Programmes dann. Leider aber gibt es da noch einen Fehler beim Schreiben, d.h. manchmal ist der Returnwert von WriteFile 0 und das Programm beendet wieder. Dieses Problem habe ich nur mit einem Rechner wirklich extrem (i5 CPU). Bei einem anderen, langsameren Rechner (Core2Duo) passiert das nicht. Beide sind XP-SP3 rechner mit gleichem Softwarestand. Jemand eine Idee? Kann es an irgendwelchen Buffern liegen? Oder hat jemand einen debug Ansatz? Danke im Vorhinein.
Ich habe zwar in der Doku auf die schnelle nichts gefunden, aber ich kann es sein das bei einem timeout dieses Verhalten auftritt?
Zoran St. schrieb: > if (!WriteFile(flasher_port, usb_cache, 2 + usb_cache_cnt + 3 / > 4, &written, NULL)) Das macht ziemlich sicher nicht das, was Du willst. Die Anzahl der zu schreibenden Bytes dürfte deutlich größer sein als das, was Du erwartest. Sieh Dir den Ausdruck 2 + usb_cache_cnt + 3 / 4 mal genau an. Was wird durch 4 geteilt?
Hallo! Danke f.d. schnellen Antworten. Zuerst : ja, es sollte 2 + (usb_cache_cnt + 3) / 4 heißen und Ja, es ist die Timeout Ausgabe von Readfile. Sorry, das hatte ich mittlerweile vergessen. Wenn ich das Timeout deaktiviere, dann bleibt die SW stehen. Mit dem Timeout konnte ich wenigstens Readfile noch ein Mal ausführen. Es scheint so als ob windows nicht mitkriegt, dass das Byte schon da ist. Den Errorcode von Writefile muss ich noch ermitteln. Danke, Zoran
Zoran St. schrieb: > Hier ein "Code-Schnippel": Ja, sieht grausig aus. Hier ein Schnippel von mir, bei dem weiß ich wenigstens, daß er funktioniert: { Write a string out the COM port, return true if all chars written } function TComPort.Write (const sData: String): DWORD; var dwCharsWritten: DWORD; i: longint; begin dwCharsWritten := 0; Result := 0; if hPort <> INVALID_HANDLE_VALUE then begin WriteFile(hPort, PChar(sData)^, Length(sData), dwCharsWritten, nil); result:= dwCharsWritten; end; end; bemerke bitte, daß mich der Rückgabewert von WriteFile nicht interessiert, sondern die Sache über dwCharsWritten geregelt wird. { Return the number of bytes waiting in the queue } function TComPort.GetInCount: LongInt; var statPort: TCOMSTAT; dwErrorCode: DWord; i: LongInt; begin i := 0; if hPort <> INVALID_HANDLE_VALUE then begin ClearCommError(hPort, dwErrorCode, @statPort); i:= statPort.cbInQue; end; if inPtr > outPtr then begin i:= i + inPtr - outPtr; end; Result:= i; end; function TComPort.Read: Char; var Ch_Cnt, Ch_Read: DWord; begin Result := #0; if inPtr > outPtr { Puffer ist nicht leer, also daraus lesen } then begin Result:= RxBuff[outPtr]; inc(outPtr); exit; end; { Puffer ist leer, also Windows bemühen... } if hPort = INVALID_HANDLE_VALUE then exit; Ch_Cnt:= GetInCount; if Ch_Cnt=0 then exit; { wenn nix vorhanden, Ende } if Ch_Cnt > buffermax then Ch_Cnt:= buffermax; ReadFile(hPort, RxBuff, Ch_Cnt, Ch_Read, nil); inPtr:= Ch_read; outPtr:= 0; if inPtr > 0 then begin Result:= RxBuff[0]; outPtr:= 1; end; end; Und hier wird der Stream programmintern gepuffert und wieder über die Anzahl gelesener Zeichen die Sache geregelt. W.S.
Ob unkommentierter Delphi-Code jemandem hilft, der in C programmieren möchte?
Das Comport ist bei Windows leider vermurkst. Die Ideen einem Characterdevice das Verhalten eines Block- oder Stream-devices ueberzustuelpen ist derart absurd von Beginn weg. Am Sinnvollsten nimmt man eine Library, die zur Sprache passt und das schoen versteckt.
Rufus Τ. Firefly schrieb: > Ob unkommentierter Delphi-Code jemandem hilft, der in C programmieren > möchte? Dann soll er "begin/end" durch "{}" ersetzen, den Code als symbolische Programmiersprache akzeptieren und das Ding zwischen den Ohren aktivieren.
Zweieinhalb Oschi schrieb: > Das Comport ist bei Windows leider vermurkst. Die Ideen einem > Characterdevice das Verhalten eines Block- oder Stream-devices > ueberzustuelpen ist derart absurd von Beginn weg. Am Sinnvollsten nimmt > man eine Library, die zur Sprache passt und das schoen versteckt. versteht nicht wo dein Problem ist. Wo wird dann etwas von BLock und Characterdevice device gemixt? Es gibt eine Read und eine Write funktion und die arbeiten so wie man es erwartet. Wenn es ein Blockdevice ist könnte man ja mit Seek arbeiten was aber nicht geht.
Hallo Allerseids! Danke für die Info, dass das delphi code ist. Damit hatte ich noch nichts zu tun. Leider verstehe ich deshalb auch nicht viel davon, aber versuchen wir es mal: Eigentlich scheint sich dein Programm nur darin zu unterscheiden, dass dich die Return Werte von Read- und Writefile nicht interessieren -> ich breche danach ab. Wieso (bzw. wann) wird ClearCommError aufgeführt? Mich würden auch die Einstellungen der COM Schnittstelle interessieren (Timeouts, DCB). Vielleicht ist dort der Hund drin. Ich habe schon einiges versucht: wenn BytesRead != BytesToRead dann wiederhole ich ReadFile bis zu 10 Mal. Meistens funktioniert es wenn ich einmalig wiederhole, dann liest das Programm den empfangenen Wert auch aus. Hier die beiden Funktionen die mir die Sorgen bereiten:
1 | void flush_serial_cache(void) { |
2 | int i; |
3 | if (serial_cache_cnt) { |
4 | countit++; |
5 | //Send the cache via SERIAL but update the cache header before
|
6 | serial_cache[0] = BLOCK_DATA | (serial_cache_cnt >> 8 & 0xf); |
7 | serial_cache[1] = serial_cache_cnt; |
8 | // the cached data is sent without '\n' a.k.a raw !!!
|
9 | DWORD readed, written; |
10 | // send cache to the device
|
11 | if (!WriteFile(flasher_port, serial_cache, 2 + (serial_cache_cnt + 3) / 4, &written, NULL)) |
12 | fprintf(stderr, "Sending BLOCK_DATA error!\n"), exit(1); |
13 | |
14 | if (written != 2 + (serial_cache_cnt + 3) / 4) { |
15 | fprintf(stderr, "Sending BLOCK_DATA error %d instead of %d\n", written, 2 + (serial_cache_cnt + 3) / 4); |
16 | exit(1); |
17 | }
|
18 | |
19 | // clear receivebuffer before reading new data to make sure to read new received data
|
20 | memset(recbuf, 0, sizeof (recbuf)); |
21 | |
22 | // Read 1 byte of data
|
23 | if (!ReadFile(flasher_port, recbuf, sizeof (unsigned char), &readed, NULL)) { |
24 | fprintf(stderr, "Can't receive BLOCK_DATA response!\n"); |
25 | exit(1); |
26 | }
|
27 | else { // check readed bytes value, if not as expected retry ReadFile max. 10 times |
28 | register unsigned char ntimes = 0; |
29 | while (readed != sizeof (unsigned char) && ntimes++<MAX_READ_RETRIES) |
30 | fprintf(stderr, "%hhd %s() read-retries: %d\n", ntimes, __FUNCTION__, readed), |
31 | memset(recbuf, 0, sizeof (recbuf)), |
32 | ReadFile(flasher_port, recbuf, sizeof (unsigned char), &readed, NULL); |
33 | }
|
34 | |
35 | if (*recbuf != BLOCK_DATA) { |
36 | fprintf(stderr, "Incorrect BLOCK_DATA response at %d: %x (%x)\n", countit, *recbuf, BLOCK_DATA); |
37 | exit(1); |
38 | }
|
39 | |
40 | serial_cache_cnt = 0; |
41 | }
|
42 | }
|
43 | |
44 | int single_data_with_read(register int tms_tdi) { |
45 | int res; |
46 | unsigned char single_with_read[] = {SINGLE_DATA_WITH_READ | (tms_tdi & 3), '\n'}; |
47 | |
48 | if (!WriteFile(flasher_port, single_with_read, sizeof (single_with_read), (DWORD *) & res, NULL)) |
49 | fprintf(stderr, "Can't write!\n"), exit(1); |
50 | |
51 | if (res != sizeof (single_with_read)) { |
52 | fprintf(stderr, "Send SINGLE_DATA_WITH_READ error %d instead of %d\n", res, sizeof (single_with_read)); |
53 | exit(1); |
54 | }
|
55 | |
56 | memset(recbuf, 0, sizeof (recbuf)); |
57 | |
58 | if (!ReadFile(flasher_port, recbuf, sizeof (unsigned char), (DWORD *) & res, NULL)) |
59 | res = -1; |
60 | |
61 | if (res < 0) { |
62 | fprintf(stderr, "Can't receive SINGLE_DATA_WITH_READ response!\n"); |
63 | exit(1); |
64 | }
|
65 | |
66 | register unsigned char ntimes = 0; |
67 | while (res != sizeof (unsigned char) && ntimes++<MAX_READ_RETRIES) { |
68 | fprintf(stderr, "%hhd %s() read-retries: %d\n", ntimes, __FUNCTION__, res); |
69 | memset(recbuf, 0, sizeof (recbuf)); |
70 | // Read 1 byte of data
|
71 | ReadFile(flasher_port, recbuf, sizeof (unsigned char), (DWORD *) & res, NULL); |
72 | }
|
73 | |
74 | if ((recbuf[0] & 0xfc) != SINGLE_DATA_WITH_READ) { |
75 | fprintf(stderr, "Incorrect SINGLE_DATA_WITH_READ response! %x instead of %x\n", *recbuf, SINGLE_DATA_WITH_READ); |
76 | exit(1); |
77 | } else if (verbose) |
78 | fprintf(stdout, ">> \t%x\n", *recbuf & 3); |
79 | |
80 | return recbuf[0] & 1; |
81 | }
|
Ich poste noch die Ausgaben von der Konsole ... Eine andere Frage/ Idee hätte ich noch: Wenn ich eine dll daraus mache, dann könnte ich das Programm über die GUI laufen lassen. Es soll nämlich das Programm von einer JAVA GUI aufgerufen werden. Ich habe die Serielle in JAVA so weit im Griff. wenn ich also statt über ReadFile und WriteFile einen anderen Weg hätte die Daten hin und her zu schaufeln, dann könnte ich mal versuchen ob es dann funktioniert. Hat jemand vielleicht einen Vorschlag, bzw. besser ein Beispiel dafür? Pipes, Queues, o.ä.? Danke, Zoran
Zoran S. schrieb: > Ich habe schon einiges versucht: > wenn BytesRead != BytesToRead dann wiederhole ich ReadFile bis zu 10 das ist unsinn, entweder geht es beim ersten mal oder die verwendest zu kurze timeouts. Arbeite doch erstmal ohne Timeouts (das sollte das default sein). Dann blockiert das Read bis etwas gelesen wird. auserdem muss BytesRead != BytesToRead nicht falsch sein, wenn man mehr als 1 byte erwarten, dann kann es auch sein das er die zeichen nicht auf einmal liefert.
@Zoran St.: Deinen Ansatz zum Senden und Empfangen halte ich für fehleranfällig. Richtig wäre das eventgetriggerte Empfangen von Bytes in einem eigenen Thread und Weiterleiten der Daten zu einem Haupt-Thread. Dort kann dann entschieden werden, wo die Daten (zeitlich) hingehören. Das Senden sollte auch eventgesteuert im Hintergrund in einem eigenen Thread ablaufen. Damit ist Senden und Empfangen entkoppelt, Verzögerungen durch das OS und der seriellen Gegenstelle sind nicht mehr relevant. Hier ein Beispiel, wie man auch ohne Threads einmal etwas senden kann und dann auf die Antwort wartet. Hier wird beim Senden im Hauptprogramm nicht auf den Abschluß der Aktion (das Ppysische Aussenden des letzten Bytes) gewartet, dafür wird die Zeit aber beim Empfangen durch eine Schleife wieder aufgebracht.
1 | // Consolen-Programm zum Senden/Empfangen von Bytes über COM (9600-8N1)
|
2 | // Es wird ein String als Start gesendet.
|
3 | // Alle empfangenen Bytes werden zurückgesendet.
|
4 | // OS: W95, W98, W98SE, WinME, WinNT, Win2000, WinXP (und höher)
|
5 | // Note: Fast keine Fehlerbehandlung implementiert!
|
6 | #include <windows.h> |
7 | #include <stdio.h> |
8 | |
9 | #define COM_BUFFER_SIZE 256 // Read- und Write-Buffer-Size
|
10 | #define BAUDRATE CBR_9600 // 9600 Baud
|
11 | #define BYTESIZE 8
|
12 | #define PARITY NOPARITY
|
13 | #define STOPBITS ONESTOPBIT
|
14 | #define HELP_STRING TEXT("Aufruf mit: progname <COM-Port-Nummer>\r\n")
|
15 | //char COMMAND1[] = {(0x02), (0x49), (0x05), (0x12), (0x03)};
|
16 | char COMMAND1[] = HELP_STRING; |
17 | |
18 | |
19 | // Hauptprogramm: Aufruf mit: progname <COM-Port-Nummer>
|
20 | int main (int argc, char **argv) |
21 | {
|
22 | DCB dcb; |
23 | DWORD iBytesWritten; |
24 | BOOL bRet = true; |
25 | DWORD dwRead = 0; |
26 | DWORD dwSetMask = EV_RXCHAR | EV_ERR; |
27 | DWORD dwEvtMask; |
28 | OVERLAPPED o; |
29 | COMMTIMEOUTS ct; |
30 | unsigned char InString[COM_BUFFER_SIZE + 1]; |
31 | TCHAR szCOM[6]; |
32 | |
33 | |
34 | if (argc == 2 && // progname + COM-Port-Nummer ? |
35 | atoi (argv[1]) > 0 && atoi (argv[1]) < 5) // COM1 ... COM4? |
36 | wsprintf (szCOM, TEXT("COM%s"), argv[1]); // String "basteln" ... |
37 | else
|
38 | {
|
39 | printf (TEXT("\r\nERROR:\t %s"), HELP_STRING); |
40 | return (1); // und tschüß ... |
41 | }
|
42 | |
43 | memset (&o, 0, sizeof (OVERLAPPED)); // Struktur mit 0en füllen |
44 | o.hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); // einen Event setzten |
45 | |
46 | HANDLE hCom = CreateFile (szCOM, GENERIC_WRITE | GENERIC_READ, 0, NULL, |
47 | OPEN_EXISTING, 0, NULL); |
48 | |
49 | if (hCom == INVALID_HANDLE_VALUE) |
50 | { // Fehlerausgabe: |
51 | LPVOID lpMsgBuf; |
52 | FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | |
53 | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), |
54 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL); |
55 | MessageBox (NULL, (LPCTSTR)lpMsgBuf, "Error: CreateFile", MB_OK | MB_ICONINFORMATION); |
56 | LocalFree (lpMsgBuf); |
57 | return (1); // und tschüß ... |
58 | }
|
59 | |
60 | dcb.DCBlength = sizeof(DCB); // Laenge des Blockes MUSS gesetzt sein! |
61 | GetCommState (hCom, &dcb); // COM-Einstellungen holen und aendern |
62 | dcb.BaudRate = BAUDRATE; // Baudrate |
63 | dcb.ByteSize = BYTESIZE; // Datenbits |
64 | dcb.Parity = PARITY; // Parität |
65 | dcb.StopBits = STOPBITS; // Stopbits |
66 | SetCommState (hCom, &dcb); // COM-Einstellungen speichern |
67 | |
68 | GetCommTimeouts (hCom, &ct); |
69 | // Warte-Zeit [ms] vom Beginn eines Bytes bis zum Beginn des nächsten Bytes
|
70 | ct.ReadIntervalTimeout = 1000 / BAUDRATE * (dcb.ByteSize + |
71 | (dcb.Parity == NOPARITY ? 0 : 1) + |
72 | (dcb.StopBits == ONESTOPBIT ? 1 : 2)) * RECVBYTES; |
73 | ct.ReadTotalTimeoutMultiplier = 0; // [ms] wird mit Read-Buffer-Size multipliziert |
74 | ct.ReadTotalTimeoutConstant = 50; // wird an ReadTotalTimeoutMultiplier angehängt |
75 | ct.WriteTotalTimeoutMultiplier = 0; |
76 | ct.WriteTotalTimeoutConstant = 0; |
77 | SetCommTimeouts (hCom, &ct); |
78 | |
79 | // Zwischenspeicher des serial-Drivers einstellen (für read und write):
|
80 | SetupComm (hCom, COM_BUFFER_SIZE, COM_BUFFER_SIZE); |
81 | SetCommMask (hCom, dwSetMask); // Empfangssignale definieren |
82 | |
83 | // Byte(s) senden:
|
84 | if (!WriteFile (hCom, &COMMAND1, strlen (COMMAND1), &iBytesWritten, NULL)) // Senden der Bytes |
85 | { // Fehlerausgabe: |
86 | LPVOID lpMsgBuf; |
87 | FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | |
88 | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), |
89 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL); |
90 | MessageBox (NULL, (LPCTSTR)lpMsgBuf, "Error: WriteFile", MB_OK | MB_ICONINFORMATION); |
91 | LocalFree (lpMsgBuf); |
92 | }
|
93 | else
|
94 | printf ("%d Byte(s) sent.", iBytesWritten); |
95 | |
96 | do // in Endlos-Schleife auf Empfangssignale warten: |
97 | {
|
98 | WaitCommEvent (hCom, &dwEvtMask, &o); // Event mit Empfangssignalen verknüpfen |
99 | |
100 | if (WAIT_OBJECT_0 == WaitForSingleObject (o.hEvent, INFINITE)) // warten bis Event |
101 | {
|
102 | if (dwEvtMask & EV_RXCHAR) // Zeichen an RxD empfangen: |
103 | {
|
104 | bRet = ReadFile (hCom, &InString, sizeof (InString), &dwRead, NULL); |
105 | |
106 | if (!bRet) |
107 | { // Fehlerausgabe: |
108 | LPVOID lpMsgBuf; |
109 | FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | |
110 | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), |
111 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), |
112 | (LPTSTR) &lpMsgBuf, 0, NULL); |
113 | MessageBox (NULL, (LPCTSTR)lpMsgBuf, "Error: ReadFile", |
114 | MB_OK | MB_ICONINFORMATION); |
115 | LocalFree (lpMsgBuf); |
116 | }
|
117 | else
|
118 | { // Ausgabe (oder Verarbeitung) der empfangenen Bytes: |
119 | InString[dwRead] = '\0'; // in "zero-ended"-String verwandeln |
120 | printf (TEXT("\r\n\tRxD (%d Byte(s)): %s"), dwRead, InString); |
121 | WriteFile (hCom, &InString, dwRead, &iBytesWritten, NULL); // Senden der Bytes |
122 | }
|
123 | }
|
124 | |
125 | if (dwEvtMask & EV_ERR) |
126 | {
|
127 | MessageBox (NULL, "Error empfangen", "Error: ReadFile", MB_OK); |
128 | break; // Schleifen-Abbruch |
129 | }
|
130 | }
|
131 | }
|
132 | while (1); |
133 | |
134 | CloseHandle (hCom); // COM schließen |
135 | CloseHandle (o.hEvent); // Event-Handle zurückgeben |
136 | |
137 | return (0); |
138 | }
|
Blackbird
Blackbird schrieb: > Richtig wäre das eventgetriggerte Empfangen von Bytes in einem eigenen > Thread und Weiterleiten der Daten zu einem Haupt-Thread. Dort kann dann > entschieden werden, wo die Daten (zeitlich) hingehören. Das Senden > sollte auch eventgesteuert im Hintergrund in einem eigenen Thread > ablaufen. ich halte von den event gesteuerten ansatz wenig. Dann die meisten anwendungen warten ja auf eine Antwort. Sende('Frage'); Antwort = Empfange(); wenn man jetzt mit events arbeitet, dann verkompilziert das die sache unnötig und bringt auch kein Vorteil. SendeAsyn('Frage'); WarteAufEntwort(); Anwwort = AsynAntwort; Das Programm blockiert in beiden Fälle an der Stelle, hier bringen events keine Vorteil. Klar könnte man jetzt das ganze noch als Statemaschine abbilden aber das finde ich viel schwerer zu warten. Lieber alles Synchron machen, wenn die Hauptprogramm nicht blockieren soll dann alles in einen Worker-Thread auslagern dieser arbeitet dann intern ohne events.
Peter II schrieb: > das ist unsinn, entweder geht es beim ersten mal oder die verwendest zu > kurze timeouts. Arbeite doch erstmal ohne Timeouts (das sollte das > default sein). Dann blockiert das Read bis etwas gelesen wird. > Das habe ich schon probiert. Wenn die Timeouts auf 0 gesetzt sind, dann bleibt das Programm hängen. Darum habe ich das Timeout gesetzt und falls nichts gelesen wurde wird wiederholt. Meistens funktioniert es dann auch beim zweiten Mal lesen. Da die Kommunikation eigentlich über USB geht (virtuelles COM) und dann ca. 1 MHz zwei Bytes geschickt werden, ist die Antwort auch schon innerhalb 2ms wieder da. Zur Info: Es wird der Windows eigene Treiber usbser.sys verwendet. > auserdem muss BytesRead != BytesToRead nicht falsch sein, wenn man mehr > als 1 byte erwarten, dann kann es auch sein das er die zeichen nicht auf > einmal liefert. ReadFile sollte eigentlich erst beenden wenn die gewünschte Anzahl an Bytes empfangen wurde, oder nicht?
Zoran S. schrieb: > ReadFile sollte eigentlich erst beenden wenn die gewünschte Anzahl an > Bytes empfangen wurde, oder nicht? da bin ich mir ebend nicht sicher, beim Netwerk ist es auf jeden fall so das das nicht immer alles ankommt. > Das habe ich schon probiert. Wenn die Timeouts auf 0 gesetzt sind, dann > bleibt das Programm hängen. Darum habe ich das Timeout gesetzt und falls > nichts gelesen wurde wird wiederholt. Meistens funktioniert es dann auch > beim zweiten Mal lesen. dann hast du ein anders Problem. Das muss auf jeden Fall gehen. Schreibe estmal ein Programm was 1 Zeichen senden und diesen wieder empfängt. Dann eine Bücke zwischen PIN 2 und 3 machen. while(1) WriteFile( .. 'A' .. ) ReadFile( ... ); // Prüfe ob ReadFile 1 zeichen gelsen hat was ein 'A' ist // print OK sonst ERRROR ) Dass muss erstmal ohne timeouts fehlerfrei durchlaufen.
Hallo! habe jetzt mal den code von Blackbird ausprobiert. Leider bleibt das Programm dann irgendwann stehen. Dann die Read-Write geschichte mit folgendem code:
1 | /*
|
2 | * File: main.c
|
3 | * Author: zst
|
4 | *
|
5 | * Created on 02. November 2011, 11:33
|
6 | */
|
7 | |
8 | #include <stdio.h> |
9 | #include <windows.h> |
10 | |
11 | HANDLE flasher_port; |
12 | char* com_port; |
13 | |
14 | /*
|
15 | *
|
16 | */
|
17 | void comport_init(void) { |
18 | int res; |
19 | DCB dcb; |
20 | unsigned char get_info[] = {'C', '5', '\n'}; |
21 | BYTE buf[30] = "\\\\.\\"; |
22 | COMMTIMEOUTS CommTimeouts; |
23 | fprintf(stdout, "Opening %s\n", com_port); |
24 | flasher_port = CreateFile(strcat(buf, com_port), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, |
25 | 0, NULL); |
26 | |
27 | if (flasher_port == INVALID_HANDLE_VALUE) fprintf(stderr, "opening failed\n"), exit(1); |
28 | |
29 | |
30 | // Initialize the DCB structure.
|
31 | // SecureZeroMemory(&dcb, sizeof(DCB));
|
32 | dcb.DCBlength = sizeof (DCB); |
33 | |
34 | if (GetCommState(flasher_port, &dcb)) { |
35 | dcb.BaudRate = /*CBR_9600,*/CBR_115200; |
36 | dcb.ByteSize = 8; //OCTET BYTE |
37 | dcb.Parity = NOPARITY; |
38 | dcb.StopBits = ONESTOPBIT; |
39 | dcb.fInX = FALSE; |
40 | dcb.fOutX = FALSE; |
41 | dcb.fRtsControl = RTS_CONTROL_DISABLE; |
42 | } else fprintf(stderr, "COM - mode set error\n"), exit(1); |
43 | |
44 | |
45 | if (!SetCommState(flasher_port, &dcb)) fprintf(stderr, "COM - mode set error\n"), exit(1); |
46 | |
47 | if (GetCommTimeouts(flasher_port, &CommTimeouts)) { |
48 | CommTimeouts.ReadIntervalTimeout = 0; |
49 | CommTimeouts.ReadTotalTimeoutConstant = 0; |
50 | CommTimeouts.ReadTotalTimeoutMultiplier = 300; |
51 | CommTimeouts.WriteTotalTimeoutConstant = 0; |
52 | CommTimeouts.WriteTotalTimeoutMultiplier = 300; |
53 | if (!SetCommTimeouts(flasher_port, &CommTimeouts)) fprintf(stderr, "Timeout set error\n"), exit(1); |
54 | }
|
55 | }
|
56 | |
57 | |
58 | |
59 | int main(int argc, char** argv) { |
60 | int arg = 0; |
61 | |
62 | for (arg = 1; arg < argc; arg++) { |
63 | switch (toupper(argv[arg][1])) { |
64 | case 'J': |
65 | com_port = &argv[arg][2]; |
66 | break; |
67 | default:
|
68 | break; |
69 | }
|
70 | }
|
71 | |
72 | comport_init(); |
73 | |
74 | int countit = 0; |
75 | unsigned char buffer = 'A'; |
76 | unsigned char recbuf; |
77 | DWORD rxcnt = 0,txcnt = 0; |
78 | int retValue = 0; |
79 | while(1) { |
80 | |
81 | if (!WriteFile(flasher_port, &buffer, sizeof (unsigned char), &txcnt, NULL)) { |
82 | fprintf(stderr, "Can't send Data!\n"); |
83 | retValue = 1; |
84 | break; |
85 | }
|
86 | else if (txcnt != sizeof (unsigned char)) { |
87 | fprintf(stdout, "Sent %i instead of %i charachters!\n", txcnt, sizeof (unsigned char)); |
88 | }
|
89 | |
90 | recbuf = 0; |
91 | if (!ReadFile(flasher_port, &recbuf, sizeof (unsigned char), &rxcnt, NULL)) { |
92 | retValue = 1; |
93 | break; |
94 | }
|
95 | else if (rxcnt != sizeof (unsigned char)) { |
96 | fprintf(stdout, "Received %i instead of %i charachters!\n", rxcnt, sizeof (unsigned char)); |
97 | }
|
98 | |
99 | if(recbuf != 'A') |
100 | fprintf(stdout, "Loop %i error %c\n", countit, recbuf); |
101 | |
102 | if (countit%10000 == 0) |
103 | fprintf(stdout, "%i Loops successfull!\n", countit); |
104 | |
105 | countit++; |
106 | }
|
107 | |
108 | fprintf(stdout, "Stopping at &i. Error %c\n", countit, recbuf); |
109 | return retValue; |
110 | }
|
Hier die Ausgabe: zst@zst-i5 /h/NetBeansProjects/LoopTest $ LoopTest -jCOM4 Opening COM4 0 Loops successfull! 10000 Loops successfull! 20000 Loops successfull! 30000 Loops successfull! 40000 Loops successfull! 50000 Loops successfull! 60000 Loops successfull! Received 0 instead of 1 charachters! Loop 67742 error 70000 Loops successfull! 80000 Loops successfull! Received 0 instead of 1 charachters! Loop 87764 error 90000 Loops successfull! 100000 Loops successfull! 110000 Loops successfull! 120000 Loops successfull! 130000 Loops successfull! 140000 Loops successfull! 150000 Loops successfull! 160000 Loops successfull! 170000 Loops successfull! Received 0 instead of 1 charachters! Loop 173465 error 180000 Loops successfull! Received 0 instead of 1 charachters! Loop 182742 error 190000 Loops successfull! 200000 Loops successfull! 210000 Loops successfull! 220000 Loops successfull! Received 0 instead of 1 charachters! Loop 229614 error 230000 Loops successfull! 240000 Loops successfull! 250000 Loops successfull! 260000 Loops successfull! 270000 Loops successfull! Received 0 instead of 1 charachters! Loop 271759 error 280000 Loops successfull! 290000 Loops successfull! 300000 Loops successfull! 310000 Loops successfull! 320000 Loops successfull! 330000 Loops successfull! 340000 Loops successfull! Received 0 instead of 1 charachters! Loop 342993 error ... usw. Was kann das sein? Ich könnte jetzt mal versuchen ein "retry" einzubauen. Vielleicht hilft das. Andere Vorschläge? Zoran
Opening (null) 0 Loops successfull! 10000 Loops successfull! 20000 Loops successfull! 30000 Loops successfull! 40000 Loops successfull! 50000 Loops successfull! 60000 Loops successfull! 70000 Loops successfull! 80000 Loops successfull! 90000 Loops successfull! 100000 Loops successfull! 110000 Loops successfull! 120000 Loops successfull! 130000 Loops successfull! 140000 Loops successfull! 150000 Loops successfull! 160000 Loops successfull! 170000 Loops successfull! 180000 Loops successfull! 190000 Loops successfull! 200000 Loops successfull! 210000 Loops successfull! 220000 Loops successfull! 230000 Loops successfull! 240000 Loops successfull! 250000 Loops successfull! 260000 Loops successfull! 270000 Loops successfull! 280000 Loops successfull! 290000 Loops successfull! 300000 Loops successfull! 310000 Loops successfull! 320000 Loops successfull! 330000 Loops successfull! 340000 Loops successfull! 350000 Loops successfull! also an dem Programm liegt es nicht. Du hast also ein Problem mit deiner Hardware order den Treibern. Was soll das hier in deinem code? BYTE buf[30] = "\\\\.\\"; für strings nimmt man char besser du machst es mit char buf[30]; snprintf(buf, "\\\\.\\%s",sizeof(buf)-1, com_port); CreateFile(buf,...)
Hallo! Ich glaube, ich geb's auf. bin gerade daheim und habe den LoopTest am Laptop getestet. Nach 1.38 Mio. Loops kein einziger Fehler. Ich habe noch zwei Rechner (1x XP und 1x Vista) an denen ich es morgen auch testen werde. Falls dort auch keine Fehler auftreten dann liegt es an diesem PC. Ob es das Chipset oder die CPU ist werde ich wohl nicht herauszufinden können. Ansonsten kann ich nur noch den Treiber neu installieren und wenn es dann nicht klappt den ganzen Rechner neu aufsetzen. Falls es dann immer noch nicht klappt wird Rechner getauscht. Morgen gebe ich noch die Ergebnisse bekannt. Danke euch allen für die Hilfe. Zoran
Warum ist das hier auskommentiert? // Initialize the DCB structure. // SecureZeroMemory(&dcb, sizeof(DCB)); dcb.DCBlength = sizeof (DCB); Wenn aus irgendeinem Grund SecureZeroMemory nicht verwendet werden kann, sollte memset verwendet werden.
viel mir gerade auf:
1 | if (!SetCommTimeouts(flasher_port, &CommTimeouts)) fprintf(stderr, "Timeout set error\n"), exit(1); |
das ist auch ein Syntax der jenseits von gut und böse ist.
Peter II schrieb: > viel mir gerade auf: > >
1 | > if (!SetCommTimeouts(flasher_port, &CommTimeouts)) fprintf(stderr, |
2 | > "Timeout set error\n"), exit(1); |
3 | >
|
> > das ist auch ein Syntax der jenseits von gut und böse ist. Weil ...?
Zoran S. schrieb: > Weil ...? komma operator, für soetwas kann man schon eine extra zeile und {} verwenden.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.