Problem mit Get-Methode



  • Bei sowas

    o_Messwerte.SetMesswerte(F_Gaszaehler->GetEdu32fp()->ErfasseVolumen());
    

    Wunderst du dich über SegFaults?
    Wenn F_Gaszaehler->GetEdu32fp() NULL zurück liefert, passiert das ja.
    Du solltest da den Rückgabewert erst auf NULL prüfen (am besten speicherst du den) bevor du Funktionen darauf aufrufst.

    Wo hast du dich mit dem Debugger reingehängt, um das m_connect zu überprüfen?
    Im übrigen ist m_connect ein bool und kein int, den darf man dann direkt mit "false" statt "0" initialisieren. Find ich persönlich einfacher, da ich gleich sehe "Ah, bool".



  • Du kannst das z.B. so machen:

    o_Messwerte.SetMesswerte( 
          F_Gaszaehler->GetEdu32fp() 
        ? F_Gaszaehler->GetEdu32fp()->ErfasseVolumen()  // Wenn der zurück gegebene Zeiger nicht 0 ist, setze den Wert von ErfasseVolumen()
        : 0 // Wenn der Zeiger 0 ist dann setz 0 
    );
    

    Oder so, was das gleiche ist nur mit if else anstatt dem ternären operator

    if( F_Gaszaehler->GetEdu32fp() ) { 
       o_Messwerte.SetMesswerte( F_Gaszaehler->GetEdu32fp()->ErfasseVolumen() ); // Wenn der zurück gegebene Zeiger nicht 0 ist, setze den Wert von ErfasseVolumen()
    } else {
       o_Messwerte.SetMesswerte( 0 ); // Wenn der Zeiger 0 ist dann setz 0 
    }
    


  • ja ok, das mit dem bool leuchtet ein. Hab ich gleich mal geändert. Hab mich bei if (m_connect) mit dem Debugger reingehängt. Dann zeigt er an, dass m_connect==true obwohl kein Gerät verbunden ist.



  • rudpower schrieb:

    Dann zeigt er an, dass m_connect==true obwohl kein Gerät verbunden ist.

    Schau eine Zeile höher:

    m_connect = m_port.OpenComm(p_port.c_str());
    

    Da weist du dem m_connect einen neuen Wert zu. Wenn eine Zeile darunter m_connect nicht mehr false ist heißt das m_port.OpenComm() hat true zurück gegeben.
    Wenn also keine Verbindung besteht heißt das wiederum dass OpenComm Mist baut.
    Außer

    {
          m_port.SetDCB(9600);
          m_port.SetReadTimeouts(100, 10, 10);
       }
    

    machen m_port irgendwie ungültig. Da aber hier über comclass nichts bekannt ist kann man auch nichts darüber sagen.



  • hier ist die comclass:

    // Öffnet den Port und gibt ein Handle zurück
    bool comclass::OpenComm(char* port){
            hCom = CreateFile(port,// z.B. "COM1",
            GENERIC_READ|GENERIC_WRITE,//zum Senden und Empfangen
            0, // Für comm devices exclusive-access notwendig
            0, // Keine security attributes
            OPEN_EXISTING, // Für comm devices notwendig
            0, // Kein overlapped I/O
            0); // Für comm devices muss hTemplate NULL sein
    
            if(hCom == INVALID_HANDLE_VALUE) return false;
               else return true;
    }
    
    // setzen der Einstellungen
    void comclass::SetDCB(int baud){
            DCB dcb; // Device Control Block
            GetCommState(hCom, &dcb); // DCB lesen
    
            dcb.BaudRate = baud; // Baudrate z.B.:9600
            dcb.ByteSize = 8; // 8 Datenbits
            dcb.Parity = NOPARITY; // keine Parity
            dcb.StopBits = ONESTOPBIT; // 1 Stopbit
            dcb.fDtrControl = 1;
            // SetCommState konfiguriert die serielle Schnittstelle
            SetCommState(hCom, &dcb);
    }
    
    // setzen der Timeout-Zeiten
    void comclass::SetReadTimeouts(int intervalTO, int readSingleTO, int writeSingleTO){
            COMMTIMEOUTS t;
            // Alle Wert in Millisekunden
            // Werte für ReadFile:
            t.ReadIntervalTimeout=intervalTO; // Zeit zwischen zwei Zeichen
            t.ReadTotalTimeoutMultiplier=readSingleTO; // pro Zeichen
            t.ReadTotalTimeoutConstant=readSingleTO;
            // Werte für WriteFile: wenn beide 0 sind, kein Timeout
            // beim Schreiben
            t.WriteTotalTimeoutMultiplier=writeSingleTO;
            t.WriteTotalTimeoutConstant=writeSingleTO;
            SetCommTimeouts(hCom,&t);
    }
    
    // Daten senden
    int comclass::SendData(char Data[],int n){
            DWORD NumberOfBytesWritten; //Anzahl der gesendeten Bytes
            WriteFile(hCom, // handle des Com-Ports
            Data, // Adresse der Daten
            n, // Anzahl der zu sendenden Bytes
            &NumberOfBytesWritten, // Adresse übergeben
            0); // kein overlapped I/O
    
            return NumberOfBytesWritten;
    }
    
    // Daten empfangen
    DWORD comclass::ReceiveData(char* Data,int n){
            DWORD NumberOfBytesRead; // Anzahl der gelesenen Bytes
            ReadFile(hCom, // handle des Com-Ports
            Data, // Adresse des Datenpuffers
            n, // Anzahl der zu lesenden Bytes
            &NumberOfBytesRead, // Adresse übergeben
            0); // kein overlapped I/O
    
            return NumberOfBytesRead;
    }
    
    // schließen der seriellen Schnittstelle
    void comclass::CloseComm(void){
         try {
         if(hCom) CloseHandle(hCom);
         } catch(...) {
         ;
         }
    }
    


  • double c_Edu32fp::ErfasseVolumen()
    {
    	if (m_connect) //hier hatte ich den Haltepunkt gesetzt
            ....
    }
    

    Hier dürfte er ja gar nicht reinlaufen, da ich doch m_connect mit false im Konstruktor initialisiert habe.



  • Da er dort in die Schleife läuft gibt es denk ich mal meinen EConvertError "" ist kein gültiger Gleitkommawert.
    zeigt er in dieser Zeile an:
    "F_HO->HO_E_AnzeigeGaszaehlerVolumen->Text = FloatToStr(F_Gaszaehler->GetEdu32fp()->ErfasseVolumen());"



  • ich glaube, das Problem ist, dass er den Konstruktor gar nicht aufruft, da dieser ja erst mit dem Klick auf den Button Gaszaehler_B_PortOeffnen aufruft. Normalerweise würde ich ja das Objekt im Konstruktor der Form F_Gaszaehler erzeugen. Da aber der Konstruktor der Klasse c_Edu32fp einen Parameter erwartet (den Namen der Schnittstelle) kann ich das nicht machen. Wie kann ich das Problem beheben?



  • habe das Problem insoweit gelöst, dass ich nun in der Geräteklasse eine neue Methode erstellt hab, die den COM-Port öffnet und als Parameter diesen entgegennimmt. Den Konstruktor konnte ich so mit dem Konstruktor der Form aufrufen. So existiert das Objekt immer während der Laufzeit. Jetzt kann ich das Programm auch laufen lassen wenn das Gerät ausgeschaltet ist bzw man nicht den Button Port öffnen klickt, der ja die neue Methode öffnet. Verbindet man aber das Gerät (also ruft die Get Methode auf:

    void c_Messgeraet::PortOeffnen(AnsiString p_port)
    {
    	m_connect = m_port.OpenComm(p_port.c_str());
       if(m_connect)
       {
          m_port.SetDCB(9600);
          m_port.SetReadTimeouts(100, 10, 10);
       }
       else ShowMessage("Messgerät nicht verbunden!");
    }
    

    und schaltet dann das Gerät ab hab ich wieder eine Exception. Dann funktioniert die Umwandlung String in double nicht mehr. Er versucht dann "" in double zu wandeln (also einen Leerstring). Das ist nicht gut. Das gleiche passiert beim einschalten, da das Gerät dann als String die Typbezeichnung sendet und die natürlich nicht in double gewandelt werden kann.



  • nun funktioniert das soweit ganz gut. Hier meine Methode zur Erfassung:

    double c_Messgeraet::ErfasseVolumen()
    {
    	if (m_connect)
        {
    		char rec[50] = {0};
    		unsigned char send[] = {0x16};
    		while(m_port.ReceiveData(rec,1)>0); // Buffer leeren
    		m_port.SendData(send,1);
          m_port.ReceiveData(rec,50);
          try {return StrToFloat(AnsiString(rec).SubString(4,9).Trim());}
          catch(...)
          {
             m_connect = false;
             return 0;
          }
       }
       else return 0;
    }
    

    wenn das Gerät nicht verbunden ist, steht in dem Feld rec alles /0. Durch die Umwandlung in AnsiString und Trim bleibt dann nur ein Leerstring "".Da dies nicht in ein Float umgewandelt werden kann fange ich dies mit try/catch ab. Das funktioniert.
    Beim Aufruf der Methode in meinem Thread wird dann im Editfeld entweder der Messwert ausgegeben oder der AnsiString "getrennt":

    if (F_Messgeraet->GetMessgeraet()->GetConnect())
       F_HO->E_AnzeigeVolumen->Text = FloatToStr(F_Messgeraet->GetMessgeraet()->ErfasseVolumen());
    else F_HO->E_AnzeigeVolumen->Text = "getrennt";
    

    Problem gibt es in der PortOeffnen-Methode:

    void c_Messgeraet::PortOeffnen(AnsiString p_port)
    {
    	m_connect = m_port.OpenComm(p_port.c_str());
       if(m_connect)
       {
          m_port.SetDCB(9600);
          m_port.SetReadTimeouts(100,10,10);
       }
       else
       {
          m_port.CloseComm();
          ShowMessage("Messgerät nicht verbunden!");
       }
    }
    

    Gebe ich jetzt nachdem verbunden wurde und die Messwerte auch angezeigt werden hier

    void __fastcall TF_Messgeraet::B_OpenPortClick(TObject *Sender)
    {
       o_Messgeraet->SetConnect(false);
    	o_Messgeraet->PortOeffnen(E_SerialPort->Text); //Argument aus Editfeld
       Close();
    }
    

    einen anderen Port an zeigt er wie gewünscht "getrennt" an. Gebe ich nun wieder den richtigen Port an läuft er immer wieder in die else Verzweigung der PortOeffnen(AnsiString p_port)-Methode. Er setzt m_connect alo nicht auf true und verbindet nicht neu.
    Ich hab dann versucht einfach m_port.CloseComm(); vorher aufzurufen. Das gibt dann gleich eine "externe Exception C0000008".


Anmelden zum Antworten