TCP Socket



  • habs mal versucht mit der Klasse:

    class Awi
    {
    private:
       unsigned char send[SENDBYTES];
       unsigned char rec[RECBYTES];
       TClientSocket* ClientSocket;
       const enum Messkanal {alle=0x0,K1=0x1,K2=0x2,K3=0x4,K4=0x8,K5=0x10,K12=0x3,
       	K13=0x5,K14=0x6,K123=0x7,K23=0x9,K24=0xA,K124=0xB,K34=0xC,K134=0xD,K234=0xE,
          K1234=0xF}; // K14 steht zB für Kanal 1 und 4
    public:
    	Awi();
    	~Awi();
    	MessungAusloesen(enum Messkanal);
    };
    
    Awi::Awi()
    {
    	memset(send,0,SENDBYTES); // Initialisierung des Arrays mit 0-Bits
    }
    
    Awi::~Awi()
    {
    	//TODO: Hier Ihren Quelltext einfügen
    }
    
    Awi::MessungAusloesen(enum Messkanal)
    {
    	send[14] = 0x50;
       send[15] = 0x50;
    }
    

    Kann man das so machen?
    Wollte im Konstruktor in der Initialisierungsliste eigentlich das TClientSocket Objekt erzeugen, aber er kannte den Typ nicht.

    Awi::Awi() : ClientSocket(new TClientSocket) // das funktioniert nicht
    {
    	memset(send,0,SENDBYTES); // Initialisierung des Arrays mit 0-Bits
    }
    

    Fehlermeldung: [C++ Fehler] Unit2.cpp(13): E2285 Keine Übereinstimmung für 'TClientSocket::TClientSocket()' gefunden



  • Hallo

    Die Fehlermeldung sagt aus, das es keinen parameterlosen Konstruktor von TClientSocket gibt. Schau in der Builder-Hilfe nach, welcher Parameter noch benötigt wird, und was du daraus schließen kannst.

    bis bald
    akari



  • owner wird als Parameter erwartet. Da das ja eine Klasse ist weiss ich gar nicht was ich da eintrage. Bei einer Formularanwendung ist ja immer die Form selbst der Eigentümer. Wie ist es hier wo ich keine Form hab sondern eine Klasse schreibe?

    Das mit dem enum funktioniert bei mir so auch nicht.

    Awi::MessungAusloesen(enum Messkanal)
    {
        send[14] = 0x50;
        send[15] = 0x50;
        send [19] = Messkanal; // das funktioniert so nicht
    }
    

    Beim Aufruf der Methode soll als Parameter zB "alle" eingegeben werden und er weist automatisch send[19] den Ausdruck 0x5 zu.



  • Hallo

    rudpower schrieb:

    owner wird als Parameter erwartet. Da das ja eine Klasse ist weiss ich gar nicht was ich da eintrage. Bei einer Formularanwendung ist ja immer die Form selbst der Eigentümer. Wie ist es hier wo ich keine Form hab sondern eine Klasse schreibe?

    Du kannst statt einem konkreten Owner-Objekt auch NULL übergeben, dann wird das erstellte Objekt nicht automatisch gelöscht. Sondern du must selber die TClientSocket-Instanz löschen, nachdem du sie nicht mehr brauchst. Spätestens der Destruktor von Awi sollte das also machen.

    Das mit dem enum funktioniert bei mir so auch nicht.

    Awi::MessungAusloesen(enum Messkanal)
    {
        send[14] = 0x50;
        send[15] = 0x50;
        send [19] = Messkanal; // das funktioniert so nicht
    }
    

    Beim Aufruf der Methode soll als Parameter zB "alle" eingegeben werden und er weist automatisch send[19] den Ausdruck 0x5 zu.

    Die Deklaration des Parameters im Konstruktor ist nicht ganz richtig :

    Awi::MessungAusloesen(Messkanal mk)
    {
        send[14] = 0x50;
        send[15] = 0x50;
        send [19] = mk; 
    }
    

    Ansonsten : "Funktioniert nicht" ist keine ausreichende Fehlerbeschreibung

    bis bald
    akari



  • ok beim Aufruf der Methode MessungAuslosen muss ich nun den enum Parameter angeben. Nun will ich zum Beispiel alle als Parameter eintragen, damit der charWert 0x0 genommen wird. Das man o_Awi->MessungAusloesen(alle); nicht schreiben kann war mir klar. Wie trag ich jetzt das enum dort ein?



  • Versuche mal Awi::alle.

    * Awi::Messkanal sollte dann public sein.
    * Du kannst enums auch zusammensetzen. Du musst nicht für jede Combo ein Eintrag erzeugen:

    Awi a;
        a.MessungAusloesen(Awi::K1 | Awi::K2);
    


  • dann kommt die Meldung: "Zugriff auf 'Awi::alle' nicht möglich". Macht denn so ein enum hier überhaupt Sinn?

    Edit: grad zu spät gelesen. Ich versuch das mal... danke für die Hilfe



  • kompilieren lässt sich der Code jetzt fehlerfrei. Nur das Gerät macht nichts wenn ich die Messung starte. In dem Anwendungsbeispiel vom handbuch steht ja das ich in Byte 14 und 15 den Integer-Wert 80 schreiben soll. Warscheinlich muss ich da wohl doch ein int-Array nehmen. Vielleicht will er aber auch den binären Code. Hab ich auch schon probiert aber das Gerät macht nichts. IP und Port sind richtig, da ich das Gerät unter dieser Ip auch Problemlos anpingen kann. Ändere ich den Port gibts auch einen Socket Error. Also wird das richtig sein.



  • Tja, da wird dir wohl keiner helfen können da wir die Doku und das Gerät nicht kennen. Ich würde mit dem Debugger prüfen ob die Daten vor dem Verschicken korrekt gesetzt sind. Du solltest auch erst mal einfachste Operationen ausführen und die Fehlerquellen einzugrenzen (was passiert beispielsweise wenn nur leere bytes gesendet wurden? Antwortet das Gerät?).

    steht ja das ich in Byte 14 und 15 den Integer-Wert 80 schreiben soll

    Klar, probier doch mal nur in einem Byte den Wert zu schreiben.
    Viel Erfolg.



  • Hallo

    Für den Fall, das du nicht weißt wie du einzelne Bytes/Bits setzten kannst : Hier ist eine Übersicht zum Thema Bitoperatoren.

    bis bald
    akari



  • ja das bekomm ich noch hin 🙂
    Nein das Gerät antwortet leider auch nicht wenn ich nur Null Bytes sende. Werd mich morgen mal mit dem Hersteller in Verbindung setzen. Habs mal mit der TClientSocket Komponente versucht und bei Service "ftp" eingegeben. Dann bekomm ich plötzlich Werte in den einzelnen Bytes. Da dies immer die gleichen sind, denk ich mal das es die falschen sind. Was hat es mit der Service Eigenschaft auf sich?



  • Installier´ mal nen Netzwerk Sniffer (Wireshark, Microsoft Net Mon, etc) und guck dir an, was über die Leitung geht. Vielleicht gibt´s sogar ein Tool des Messgerätherstellers, das einige Demofunktionen des Messgeräts abruft, dann kannst du dir die Pakete genau angucken.



  • habs mir mal mit dem Debugger angeschaut und mal einfach flg. gesendet:

    Button Ereignis:

    ClientSocket->Active=true;
    char send[32]={0};
    char rec[0]={0};
    ClientSocket->Socket->SendBuf(send,32);
    ClientSocket->Socket->ReceiveBuf(rec,128);
    

    Schau ich mir das Array mit dem Debugger an, steht da was drin. Hab noch was erkannt, dass die Messwerte immer 2Byte Wörter sind (vorzeichenbehaftet). Diese solen ab Adresse 16 bzw 48 stehen. So sieht die Tabelle aus:
    Nr.: relative Adresse (byte): Messgröße: Messstelle: Einheit:
    1 16 Kohlendioxid 1 %
    2 18 Sauerstoff 1 1/100%
    ...
    man sieht bei der Adresse schon das es immer 2 Byte sind.
    Nun muss ich das noch umwandeln.



  • wie initialisiere ich das Array am besten mit 0-Bytes? Ist das mit memset ok? Normal kenn ich ja char send[32]={0};
    Ich hab aber send in der Klasse im Header deklariert. Wie initialisier ich nun das Array im Konstruktor? send[32]={0}; geht jeden Falls nicht. Mit einer for-Schleife geht ja auch aber vll geht ja auch einfacher.



  • Hallo

    Da dürfte memset das kürzeste sein, und auch schneller als eine Schleife. Da char ja ein POD ist, brauchst du dir um nichtaufgerufene Konstruktoren von char keine Sorgen machen.

    bis bald
    akari



  • blöd gefragt: was ist ein POD?



  • Hallo

    Plain Old Datatype : Ein Datentyp der genauso wie in C behandelt wird : also z.B. int, bool, float, C-Arrays, aber auch struct, wenn es keine Methoden und nur Datenelemente besitzt, die selber PODs sind. Vorteil : Diese Datentypen brauchen keine Konstruktoren und können z.B. mit memset auf 0 gesetzt werden, auch in Form eines Arrays. Bei einem std::vectorstd::string dürfte man das nicht machen.

    bis bald
    akari



  • ah ok alles klar. Ich hab immer elementare Datentypen dazu gesagt.

    Hab ein paar Probleme mit dem Auslesen der Messwerte. Mit dem Debugger kann ich die Daten bereits mit der Ausdrucksüberwachung sehen. Nun will ich sie noch ausgeben können als AnsiString zB in ein Editfeld oder Memo. Ich zeig einfach mal meine Klasse:

    class c_Awi{
       private:
          unsigned char send[32];
          unsigned char rec[128];
          TClientSocket* socket;
       public:
    	c_Awi(AnsiString IP, int Port);
    	~c_Awi();
    	char* ReceiveData(int Adresse); 
    };
    c_Awi::c_Awi(AnsiString IP, int Port):socket(new TClientSocket(NULL)) {
       memset(send,0,32);
       memset(rec,0,128);
       socket->Host = IP;
       socket->Port = Port;
    	socket->Active = true;
    }
    //---------------------------------------------------------------------------
    c_Awi::~c_Awi() {delete socket;}
    //---------------------------------------------------------------------------
    //in dieser Methode wollt ich eigentlich das Feld angeben, das dann ausgegeben werden soll. Ich denke das muss ich anders machen: 
    char* c_Awi::ReceiveData(int Adresse) {
    	socket->Socket->SendBuf(send,32);
       socket->Socket->ReceiveBuf(rec,128);
       return &rec[Adresse]; 
    }
    

    und hier meine Formklasse:

    class TForm1 : public TForm {
    __published:
    	TMemo *Memo;
    private:	
    	c_Awi* o_Awi; //hier meine Deklaration 
    public:	
    	__fastcall TForm1(TComponent* Owner);
    	__fastcall ~TForm1();
    };
    TForm1 *Form1;
    //---------------------------------------------------------------------------
    __fastcall TForm1::TForm1(TComponent* Owner)
    	: TForm(Owner), o_Awi(new c_Awi("192.168.0.37",2080)) {} //hier erzeug ich mein Objekt in der Konstruktorliste
    //---------------------------------------------------------------------------
    __fastcall TForm1::~TForm1() {delete o_Awi;}
    

    Da ja ein Messwert immer aus 2 Byte (also 2 Feldelementen besteht) muss ich diese dann noch irgendwie kombinieren. Aber erst mal wollt ich die einzelnen Felder auslesen können



  • * Du kannst mal BinToHex() anschauen um die Dtaen roh auszugeben.
    * Du kannst zwei Bytes die zusammen einen Wert bilden beispielsweise so zusammensetzen:

    int value = (rec[14] << 8) + rec[15];
    

    Allerdings musst du die Endianness klären, also welches Byte höherwertig ist.



  • ist mein code oben soweit erst mal ok?

    Laut Handbuch gilt das Big Endian Format. Das höherwertige Bit steht an niederen Adresse. In Feld 50 steht zB 0x80 und in Feld 51 steht 0x08. Wie komm ich nun an den Messwert 21.8? (Der steht auf der Anzeige des Geräts, daher kenn ich den)


Anmelden zum Antworten