Serielle Schnittstelle in C



  • Halli Hallo!

    Bin absoluter Newbie, habe vorher schon mal bei BCB gepostet, habe mich jetzt etwas mit der Win API beschäftigt, um der Lösung für folgendes Problem näher zu kommen:
    Ich soll ein Programm schreiben, dass automatisch ein Modem anruft und dann das Datum abfragt, zwecks Überprüfung der Verbindung. Kann leider nur ANSI C auf einem Anfänger Level, bin deshalb echt überfordert. Habe folgendes geschrieben (nur erstmal als Ansatz, um überhaupt Zeichen zu lesen und zu schreiben):

    #include <windows.h>
    #include <stdio.h>
    
    main()
    {
            char szBefehl[]="AT"; char szPrint[3];
            unsigned long NumBytesWritten; unsigned long NumberOfBytesRead;
            HANDLE comm=CreateFile("COM2",GENERIC_WRITE+GENERIC_READ,0,0,OPEN_EXISTING,0,0);
            if (comm)
            {
                    WriteFile(comm, &szBefehl, 1, &NumBytesWritten, NULL);
                    ReadFile(comm, &szPrint, 2, &NumberOfBytesRead, NULL);
                    printf("%s",szPrint);
                    CloseHandle(comm);
            }
            else
            {
                    fprintf(stderr, "Schnittstelle belegt!");
                    exit (1);
            }
            return 0;
    }
    

    Irgendwie funktioniert das aber nicht, eigentlich sollte AT ans Modem gesendet werden und dann OK auf dem Bildschirm gezeigt werden, stattdessen passiert einfach nichts, die DTR und RTS LEDs gehen zwar an, aber sonst muss man mit STRG-C aus dem Programm aussteigen. Woran liegt das? 😕
    Andere Frage: Was passiert eigentlich, wenn ich Zeichen lesen will, die das ferne Modem sendet und das Modem sendet einfach nichts? Wie kann ich in dem Fall einen Programmabsturz vermeiden, kann man ReadFile ein Delay geben?

    Danke im Voraus
    maxx21



  • Schau dir mal den FAQ-Thread dazu an 😉

    GENERIC_WRITE+GENERIC_READ
    

    Nimm da mal lieber | 🙂



  • Hi!

    Das mit dem | hab ich gestern noch rausgefunden, krieg jetzt auch ne Leitung aber komischerweise nur, wenn ich vorher über HyperTerminal einmal AT gesendet hab, sosnt passiert wieder nix. Hab schon alle FAQs durchforstet, da hab ich den Grossteil her, aber so im speziellen find ich weiter nix. Kennst du vielleicht eine Funktion, mit der man eine festgelegte Zeit in sek. warten kann? denn das Programm steigt schon aus, bevor es was gemacht hat. 🙄

    Gruss
    maxx21



  • hasts schon mal mit sleep() probiert? In den Klammern kannst deine Wartezeit in ms eingeben.. dann legt sich dein Prog. (bzw Thread) für diese Zeit "schlafen" 😉



  • Cool, danke das hat mir schon viel weitergeholfen. Habe nur noch ein klitzekleines Problem (ich weiss ich nerve):
    Soll ja sone Art automatisiertes Anmeldeskript werden, und ReadText braucht ja immer etwas, wo es reinschreiben kann. Wie kann ich aber vermeiden, ständig neue Strings zu nehmen? Ich habs mal mit *szPrint=NULL nach der Ausgabe und vor dem nächsten Lesen probiert, aber soweit mein Basisverständnis für Zeiger geht, schicke ich damit ja nur den Zeiger auf das erste Element ins Nirwana, der eigentliche Inhalt bleibt ja da. Ich denke, dass das auch der Grund dafür ist, dass später im Programm auf einmal Zeichenketten auftauchen, die vorher schonmal da waren. Aber szPrint[]="" akzeptiert der Compiler nicht. Was kann ich dagegen tun? 😕
    Ausserdem funktioniert das Anmeldeskript so, dass das ferne Modem sofort wieder auflegt, zurückruft und noch mal nach dem Passwort fragt, ich hatte mir überlegt, ReadText in eine Schleife zu packen, die immer wieder prüft, ob Text im Puffer ist, der "Passwort:" enthält, wurde aber jäh enttäuscht, da ReadText wohl automatisch wartet, bis es was zum ausgeben hat, wie kann ich das unterbinden? 😕 Könnte ja sein, das Modem ruft gar nicht zurück, dann hängt sich ja alles auf... 😞

    Gruss
    maxx21



  • 1.) OVERLAPPDED - kannst du bei den File-Funktionen angeben
    2.) was genau ist szPrint und was willst du damit machen? den Speicher wieder freigeben? leeren? 😕



  • Hi!

    Also dass mit dem Aufhängen habe ich über SetCommTimeouts jetzt hinbekommen, aber was meintest du mit OVERLAPPED? Sorry, mit dem szPrint hatte ich ganz vergessen dazuzuschreiben 🙄 : Das ist mein Puffer String, in den ReadText schreibt, der soll aber nachdem etwas von COM2 gelesen und mit printf ausgegeben worden ist wieder geleert werden, damit beim nächsten Lesevorgang nichts mehr drin ist.

    Gruss
    maxx21



  • zu 1.) Schau dir mal den letzten Parameter von ReadFile bzw. WriteFile an 🙂
    Bei CreateFile musst du dann FILE_FLAG_OVERLAPPED in dwFlagsAndAttributes mit angeben.

    zu 2.) Vielleicht hilft dir ZeroMemory - verstehe aber das Problem nicht so ganz 🙄



  • Hi,
    also bei comm Schnittstellen hab ich auch noch so meine Probleme...
    aber wenn ich deine source richtig interpretiere dann sendest du in WriteFile
    das char Array "AT" (2 Byte lang). Im Funktionsaufruf (dritter Parameter) aber sagst du der Funktion das nur 1 Byte ("A") gesendet werden soll.

    ...
    WriteFile(comm, &szBefehl, 1, &NumBytesWritten, NULL); 
    ...
    

    versuch mal zum senden:

    ...
    WriteFile(comm, &szBefehl, sizeof(szBefehl), &NumBytesWritten, NULL); 
    ...
    

    Vieleicht bringt dich das etwas weiter...

    Mfg
    Riker



  • Hi!

    Ist mir auch aufgefallen, die Idee mit sizeof hatte ich auch, funktioniert, danke aber trotzdem! 👍

    Gruss
    maxx21



  • Hi nochmal an alle!

    Also, ich bin jetzt schon ein gehöriges Stück weiter, das Anmeldeskript steht und im Prinzip läuft auch alles, bis auf folgendes:
    Wenn das Programm zum ersten Mal nach dem Hochfahren aufgerufen wird, spuckt es anstelle des in szBefehl gespeicherten Befehls einfach eine leere Zeile aus und es passiert nichts. Ruft man dann das HyperTerminal auf und verbindet sich nur kurz mit dem Modem, legt wieder auf und geht wieder raus, dann funktioniert das Programm meistens, bis man runterfährt, manchmal kommt zwischendurch auch nochmal eine leere Zeile anstatt dem Befehl, woran kann das liegen? Habe ich beim öffnen/schliessen des Handles irgendeinen Fehler gemacht oder muss die Schnittstelle noch irgendwie initialisiert werden?
    Skript sieht jetzt so aus:

    void auflegen(HANDLE comm);
    //Parameter dieser Funktion sind das Passwort und die Nummer sowie die
    //Länge des Passworts (sizeof(szPass))
    int check(char *szNummer, char *szPass, int nLength)
    {
            //Variablendefinition
            char szPrint[160]=""; char szBefehl[]="AT\r";
            unsigned long NumBytesWritten; unsigned long NumberOfBytesRead;
            //COM Port über die Windows API öffnen
            HANDLE comm=CreateFile("COM2",GENERIC_WRITE|GENERIC_READ,0,0,OPEN_EXISTING,0,0);
            //Struktur für Timeoutzeiten
            typedef struct _COMMTIMEOUTS    // ctmo
            {
                DWORD ReadIntervalTimeout;
                DWORD ReadTotalTimeoutMultiplier;
                DWORD ReadTotalTimeoutConstant;
                DWORD WriteTotalTimeoutMultiplier;
                DWORD WriteTotalTimeoutConstant;
            } COMMTIMEOUTS,*LPCOMMTIMEOUTS;
            COMMTIMEOUTS timeout;
            //Timeouts werden so gesetzt, damit falls das Modem nicht zurückruft, das
            //Programm nicht abstürzt
            timeout.ReadIntervalTimeout=0;
            timeout.ReadTotalTimeoutMultiplier=0;
            timeout.ReadTotalTimeoutConstant=1000;
            timeout.WriteTotalTimeoutMultiplier=0;
            timeout.WriteTotalTimeoutConstant=1000;
            strset(szPrint,'\0');
            if (comm==INVALID_HANDLE_VALUE)         //Ist der Port korrekt geöffnet?
            {
                    fprintf(stderr, "Schnittstelle belegt!");
                    CloseHandle(comm);
                    exit (1);
            }
    
            SetCommTimeouts(comm,&timeout);  //obige Struktur findet Anwendung
            //Evtl. verbleibende Zeichen im Modem Puffer löschen
            ReadFile(comm, &szPrint, 159, &NumberOfBytesRead, NULL);
            strset(szPrint,'\0');
            //Modem mit "AT" initialisieren
            WriteFile(comm, &szBefehl, sizeof(szBefehl), &NumBytesWritten, NULL);
            if(NumBytesWritten==0)
            {
                    fprintf(stderr, "Es ist ein Fehler aufgetreten.\nBitte "
                            "pr\201fen Sie, ob das Modem angeschlossen und eingeschaltet "
                            "ist!");
                    CloseHandle(comm);
                    exit (2);
            }
            ReadFile(comm, &szPrint, 159, &NumberOfBytesRead, NULL);
            printf("%s\n",szPrint);
    ...
    
    void auflegen(HANDLE comm)
    {
            char szAuflegen[]="ATH0\r"; unsigned long bla;
            char szPrint[160]="";
            strset(szPrint,'\0');
            //Verbindung trennen, Handle schliessen
            WriteFile(comm, &szAuflegen, sizeof(szAuflegen), &bla, NULL);
            /*ReadFile(comm, &szPrint, 159, &NumberOfBytesRead, NULL);*/
            printf("%s\n",szPrint);
            strset(szPrint,'\0');
            CloseHandle(comm);
    }
    

    Wäre nett, wenn mir nochmal jemand helfen könnte 😃 😃


Anmelden zum Antworten