Serielle Schnittstelle - Je ein Thread für lesen/schreiben



  • Guten Morgen,
    ich habe ein Programm das in einem eigenen Thread bis jetzt im Hintergrund auf an der seriellen Schnittstelle eintreffenden Daten wartet.
    D.h. ich habe die Schnittstelle als Overlapped mit:

    SetCommMask(hComm, EV_RXCHAR);
    ol.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
    

    usw. geöffnet.

    Mein Read-Thread wartet dann mit

    if( ERROR_IO_PENDING == GetLastError() )
    {
       if( WAIT_OBJECT_0 == WaitForSingleObject( ol.hEvent, 1000 ) )
       {
    

    auf eintreffende Daten.

    Dies funktioniert auch soweit.
    Nun sollen aber auch noch Daten gesendet werden. Starte ich dann einen zweiten Thread, in dem ich dann mit WriteFile() etwas senden möchte, schlägt dieses fehl.
    Wie komme ich mit meinem Write-Thread denn zwischen den Lesevorgang, ohne diesen zu unterbrechen? Die Schnittstelle soll Voll-Duplex arbeiten.

    Ich weiß nicht ob es geht, aber am einfachsten wäre es doch, die Schnittstelle zweimal zu öffnen.

    Danke und Grüße



  • Dieser Thread wurde von Moderator/in HumeSikkins aus dem Forum C++ in das Forum WinAPI verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.


  • Mod

    Warum schlägt das fehl?

    1. Du musst das selbe File Handle benutzten und nicht einen neuen Port öffnen.
    2. Du musst eine eigene Overlapped Struktur aufbauen und ein eigenes Eventhandle für den Overlapped IO verwenden.

    Das ist IMHO alles.
    Eine nette Diskussion zu dem Thema gibt es hier (allerdings ist etwas MFC Code dabei, den man aber auch vergessen kann).
    http://www.flounder.com/serial.htm



  • Martin Richter schrieb:

    2. Du musst eine eigene Overlapped Struktur aufbauen und ein eigenes Eventhandle für den Overlapped IO verwenden.

    Ah, ich hatte die gleiche Overlapped-Struktur für das Lesen und Schreiben verwendet. Ich schau' mal ob es daran schon gelegen hat.
    Danke für den Link, untern den zig Serielle Schnittstelle Artikeln ist der meinem Prinzip ja ähnlich.



  • Ein Problem habe ich noch. Ich habe das vom Prinzip her jetzt so wie auf der Seite http://www.flounder.com/serial.htm
    Das Phänomen das ich habe ist, dass immer das erste Zeichen das auf der seriellen hereinkommt verschluckt wird. Das ist wohl das erste Zeichen, das in der Zeit während WaitForSingleObject wartet.

    for(;;)
    {
      ok = ReadFile(hComm, buf, sizeof(buf) - 1, &dwRead, &ol);
      if(!ok)
      { // error
        // Es konnten keine Daten gelesen werden, dann auf Event warten
        if( ERROR_IO_PENDING != GetLastError() )
        {
          // Grober Fehler, abbrechen
          m_endReadThread = true;
        }
        else
        {
          if(WaitForSingleObject(ol.hEvent, WAIT_SINGLE_OBJ_TIMEOUT_MS ) == WAIT_OBJECT_0)
          {
            ok = GetOverlappedResult(hComm, &ol, &dwRead, TRUE);
            if(!ok)
            { // GetOverlappedResult failed
              printf("GetOverlappedResult failed");
            }
            // else -> Daten sind da
          }
          else
          { // Timeout					
            timeout_to_flush += WAIT_SINGLE_OBJ_TIMEOUT_MS;
            if (timeout_to_flush >= m_packingAlgoTransmit_ms)
            {
              timeout_to_flush = 0;
              flush_buffer = true;
            }
          }
        }
      }
    }
    

    WAIT_SINGLE_OBJ_TIMEOUT_MS habe ich auf 100 stehen. Kommen nun 2 Zeichen auf der Seriellen herein, so kommt das ReadFile mit dwRead = 0 zurück, bei GetOverlappedResult dwRead anschließend mit 1 anstatt 2.
    Schicke ich nur ein einzelnes Zeichen, so kommt dieses auch direkt heraus. Äußerst seltsam.

    WaitCommEvent kann ich nicht verwenden, da in einem anderen Thread die Daten mittels WriteFile geschrieben werden.

    Hat vielleicht jemand noch einen Hinweis?


  • Mod

    1. Wie groß ist buf?
    2. Wenn GetOverlappedResult OK angibt, solltest Du auch die Schleife beenden, denn Du hast ja dann Dein Byte(s).



  • Hi,
    1)
    buf hat 1500 Bytes.
    Aber es werden bei mir unabhängig von Baudrate und Zeiten nie mehr als 13 Bytes am Stück gelesen.

    Am Ende der Schleife wird noch das Telegramm zusammengebaut. Dieses ist etwas größer darum habe ich das oben nicht hineinkopiert.

    Ich habe mir aber zu Testzwecken direkt unter GetOverlappedResult den Wert von dwRead ausgeben lassen, und dort kommt wirklich eine 1 auch wenn ich zwei Zeichen schicke.

    Mache ich die Zeit für WaitForSingleObject länger auf z.B. 1000 ms, so passiert dieses nicht. Bei 100 ms wird wie geschrieben immer ein Zeichen eines Aufrufes verschluckt.

    Aber ich kann erstens nicht so lange auf den Event warten, und zweitens kann das ja eigentlich nicht an der Zeit, sondern an irgendeinem Programmfehler liegen.



  • Beim Testen habe ich eben noch festgestellt, dass es auch irgendwie mit den Read-Timeouts die ich mittels SetCommTimeouts setze zusammenhängt.
    Mache ich den Wert ganz klein auf 1 ms werden Zeichen verschluckt. Bei großen Werten z.B. 1000 ms ebenso.

    Haben die Timeouts überhaupt noch eine Funktion wenn ich Overlapped I/O verwende?

    Um Fehler in der Thread-Geschichte auszuschließen, habe ich das in ein eigenes kleines Programm geschrieben, dort tritt das ebenso auf.



  • Irgendwie ist das mit den Timeouts doch kompliziert. Ist denn das Prinzip das ich habe verkehrt?

    Einstellungen die ich getestet habe:

    timeouts.ReadIntervalTimeout        = MAXDWORD;
    timeouts.ReadTotalTimeoutMultiplier = 0;
    timeouts.ReadTotalTimeoutConstant   = 0;
    

    ReadFile kehrt unmittelbar zurück, auch wenn kein Zeichen gelesen werden konnte. Da der Rückgabewert aber 0 ist, kann
    ich nicht mittels GetLastError() auf ERROR_IO_PENDING prüfen.
    Diese Seite hier:
    http://www.lookrs232.com/com_port_programming/api_timeout.htm
    sagt zwar dass dies die Einstellungen für Event-basierende Abfragen sein sollen, aber dem ist ja eigentlich nicht so.

    timeouts.ReadIntervalTimeout        = MAXDWORD;
    timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;;
    timeouts.ReadTotalTimeoutConstant   = 10;
    

    Hier sollte eigentlich ReadFile(), wenn nach 10 ms kein Zeichen gelesen werden konnte, mit einem Timeout zurückgehren.
    Es gibt aber != 0 zurück auch wenn kein Zeichen ankommt.

    timeouts.ReadIntervalTimeout        = MAXDWORD;
    timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;;
    timeouts.ReadTotalTimeoutConstant   = 100;
    

    Bei der Zeit kehrt ReadFile() wie gedacht mit einem Timeout zurück, sodass man mit WaitForSingleObject() warten kann.
    Wenn ich dann bei WaitForSingleObject aber weniger als 100 ms warten möchte, gehen Zeichen verloren.

    Diese Zeit ist mir aber zu lange, und aufgrund dessen dass ich die Schnittstellen Timeouts nicht verkürzen kann schließt sich das
    gegenseitig irgendwie aus.

    Wäre schön wenn hier doch noch jemand Licht ins Dunkel bringen kann.



  • Warum machst Du das mit threads? Viel mehr Möglichkeiten hat man mit
    eigenständigen Prozessen (gleich verschiedene Programme), einer zum Lesen und
    einer zum Bearbeiten der Daten. Hierfür müssen beide Prozesse über die Fensterhandles miteinander kommunizieren. Die Daten tauscht man schnell und bequem mit SendMessage(hwndProc,ID_XXX,idWas,iDatum) aus. Die Daten müssen natürlich integers sein. Eine besondere Synchronisation ist gewöhnlich nicht erforderlich.



  • berniebutt schrieb:

    Warum machst Du das mit threads? Viel mehr Möglichkeiten hat man mit
    eigenständigen Prozessen (gleich verschiedene Programme), einer zum Lesen und
    einer zum Bearbeiten der Daten. Hierfür müssen beide Prozesse über die Fensterhandles miteinander kommunizieren. Die Daten tauscht man schnell und bequem mit SendMessage(hwndProc,ID_XXX,idWas,iDatum) aus. Die Daten müssen natürlich integers sein. Eine besondere Synchronisation ist gewöhnlich nicht erforderlich.

    rofl


Anmelden zum Antworten