Ankündigung

Einklappen
Keine Ankündigung bisher.

Hilfe zu Perl Device::Serial gesucht

Einklappen
Dieses Thema ist geschlossen.
X
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

    [wiregate] Hilfe zu Perl Device::Serial gesucht

    Guten Tag liebe Gemeinde,

    bzgl. der Auslesung von Zählern:

    brauch ich mal Hilfe mit meinem Code. Ein neuer Thread deshalb weil ich hier speziell Hilfe von Perl-Kennern suche die sich mit Device::Serial auskennen.

    Der Code soll erstmal nur den Zähler Abfragen, ohne parsing. Es geht mir darum erstmal die Geschwindigkeit zu ändern, dann kann man da weiter aufsetzen.

    Vielen Dank schonmal an alle die sich bemühen und helfen können.
    Die Kernfrage: Wie wechsele ich in Perl die Geschwindigkeit eines seriellen Ports?

    Code:
    #!/usr/bin/perl
    
    #
    # (m)ein Stromz0hler mit IR-Schnittstelle blubbert nach einem "Anforderung-
    # telegramm" Daten raus. Das Telegramm ist mit 300 Baud, 7 Bit, 1 Stoppbit
    # und gerader Parit0t zu senden. Das ist der Initialmodus von Ger0ten,
    # die das Protokoll IEC 62056-21 implementieren.
    #
    # Autor: Andreas Schulze
    # Bugfix: Eric Schanze
    # Datum: 20120302
    #
    
    
    
    use warnings;
    use strict;
    use Device::SerialPort;
    use RRDs;
    
    ### KONFIGURATION ###
    my $device="/dev/ttyUSB-2-4.1";		#Port
    my $conf4800="/var/tmp/conf4800";	#Konfigurationsdatei
    my $endsign="!";					#Letztes Zeichen im Protokoll vom Zähler
    
    my $data="2f3f210d0a";				#Anfrage als HEX "/?!<CR><LF>"
    my $request = pack('H*',$data);
    						
    my $ga = "0/0/4";								
    
    my $data2="063034300d0a";			#ACK und neue Geschwindigkeit in HEX "<ACK>040<CR><LF>"
    my $baudwechsel = pack('H*',$data2);
    
    
    ### Seriellen Port initialisieren
    
    ####4800baud
    my $port = new Device::SerialPort($device) || die "can't open $device: $!";
    $port->baudrate(4800)      || die 'fail setting baudrate';
    $port->databits(7)        || die 'fail setting databits';
    $port->stopbits(1)        || die 'fail setting stopbits';
    $port->parity("even")     || die 'fail setting parity';
    $port->rts_active(1);
    $port->dtr_active(1);
    $port->read_char_time(500);     # 0.5 seconds for each character
    $port->read_const_time(1000);   # 1 second per unfulfilled "read" call
    $port->write_settings     || die 'fail write settings';
    
    
    $port->save($conf4800) 	|| warn "Can't save $conf4800: $!\n";
    
    ####START 300baud
    $port->baudrate(300)      || die 'fail setting baudrate';
    $port->databits(7)        || die 'fail setting databits';
    $port->stopbits(1)        || die 'fail setting stopbits';
    $port->parity("even")     || die 'fail setting parity';
    $port->dtr_active(1);
    $port->rts_active(1);
    $port->read_char_time(500);     # 0.5 seconds for each character
    $port->read_const_time(1000);   # 1 second per unfulfilled "read" call
    $port->write_settings     || die 'fail write settings';
    
    
    ### Anforderungstelegramm senden
    
    my $num_out = $port->write($request);
    print $request;
    die "write failed\n" unless ($num_out);
    die "write inclomplete\n" unless ($num_out == length($request));
    print "$num_out Bytes written\n";
    
    ### Warte auf Zählerkennung
    
    sleep (2);	
    
    ### Telegram mit ACK und neuer Geschwindigkeit senden
    
    my $num_out2 = $port->write($baudwechsel);
    print $baudwechsel;
    die "write failed\n" unless ($num_out2);
    die "write inclomplete\n" unless ($num_out2 == length($baudwechsel));
    print "$num_out2 Bytes written\n";
    
    ### Port mit neuer Geschwindigkeit intialisieren
    
    $port->restart($conf4800)  || warn "Can't restart $conf4800: $!\n"; ;
    
    #$port->baudrate(300); 
    #$port->write_settings;
    
    ### AUSLESEN
    
    my $STALL_DEFAULT=5; # how many seconds to wait for new input
    my $timeout=$STALL_DEFAULT; 
    my $chars=0;
    my $buffer="";
    
    while ($timeout>0) {
            my ($count,$saw)=$port->read(25); 	# Liest 25 Zeichen je Durchlauf aus
            if ($count > 0) {
                    $chars+=$count;
                    $buffer.=$saw;
    		print ($buffer,"\n");			# Ausgabe der eingelesenen Daten
     
    ### FILTER FOR END
    if ($buffer =~ /\Q$endsign\E/)			# \Q \E entwertet alle Sonderzeichen dazwischen
    {	
    $port->close || die "can't close $device: $!";	# Port schlieflen
    last;							# Schleife verlassen
    }
    ### ENDE FILTER FOR END
    	
            
    }
            else {
                    $timeout--;
            }
    }
    
    if ($timeout<=0) {
    $port->close || die "can't close $device: $!";        
    print "Waited $STALL_DEFAULT seconds and never saw what I wanted\n";
    		}
    Der Zähler wechselt auf jeden Fall mit dem entsprechenden Telegramm die richtige Geschwindigkeit, nur mein Port gibt nur was aus wenn er auf 300 baud steht. Kommen die Daten schneller kommen dann eben nur noch kryptische Zeichen an.
    Umgezogen? Ja! ... Fertig? Nein!
    Baustelle 2.0 !

    #2
    kurze Frage...

    Wäre es nicht einfacher, die gesammte serielle Komunikation über einen soket zu lösen, und aus dem Plugin nur auf den Soket zu zugreiffen? Dort lässt sich auch die geschwindigkeit problemlos einstellen und das Plugin braucht wehniger Ausführungszeit. Dass ist besonders dann wichtig, wenn mehrere Plugins paralell laufen
    Gruss Patrik alias swiss

    Kommentar


      #3
      Hat Makki auch schon gesagt
      Dann muss ich doch noch ran und das verstehen lernen
      Umgezogen? Ja! ... Fertig? Nein!
      Baustelle 2.0 !

      Kommentar


        #4
        Ist im grunde nicht so kompliziert. Dass kannst auch in einem Crashkurs in kurzer Zeit lernen
        Gruss Patrik alias swiss

        Kommentar


          #5
          Kannst du mal kurz auf die Sprünge helfen?
          Ich muss 7e1 300baud lesen und schreiben, dann umschalten und mit 7e1 4800baud lesen.
          Wieviel socat brauch ich dafür? Im Zweifel würde es auch reichen 7e1 300baud nur zu schreiben.
          Umgezogen? Ja! ... Fertig? Nein!
          Baustelle 2.0 !

          Kommentar


            #6
            Also ein kurzer crashkurs:

            Im Webmin unter Seriell/LAN/Socketverbindungen einen neuen Soket mit folgenden Eigenschaften anlegen:

            Name: z.B. EHZ

            bei Aktiv und Bidirektional einen Hacken

            Unter Socket1:
            • -
            • Socket: /dev/ttyUSB-2-4.1
            • optionen: raw,b300,cs7

            Unter Socket2:
            • udp-datagram
            • Socket: localhost:50134
            • optionen: bind=localhost:50135,reuseaddr

            Damit steht schonmal die Verbindung mit 300Baud


            Dann noch der Aufruf im Plugin...


            In den configzeilen:


            Code:
            my $socknum = 121; # Eindeutige Nummer des Sockets +1 
            my $send_ip = "localhost"; # Sendeport (UDP, siehe in Socket-Einstellungen)
            my $send_port = "50135"; # Sendeport (UDP, siehe in Socket-Einstellungen)
            my $recv_ip = "localhost"; # Empfangsport (UDP, siehe in Socket-Einstellungen)
            my $recv_port = "50134"; # Empfangsport (UDP, siehe in Socket-Einstellungen)
            Dann erst mal den Soket im Plugin aufrufen:

            Code:
            if (!$socket[$socknum]) { # socket erstellen
                     $socket[$socknum] = IO::Socket::INET->new(LocalPort => $recv_port,
                                               Proto => "udp",
                                               LocalAddr => $recv_ip,
                                               PeerPort  => $send_port,
                                               PeerAddr  => $send_ip,
                                               ReuseAddr => 1
                                                )
                 or return ("open of $recv_ip : $recv_port failed: $!");
                  $socksel->add($socket[$socknum]); # add socket to select
                  $plugin_socket_subscribe{$socket[$socknum]} = $plugname; # subscribe plugin
                 return "opened Socket $socknum";
                 plugin_log($plugname,'Soket verbunden. Soketnummer: ' . $socknum);
             }
            Dann noch die Befehle zum senden und empfangen:

            Um einen Befehl zu senden...

            $command enthält den zu übertragenden Befehl


            Code:
            syswrite($socket[$socknum], $command);
            Wenn du eine Rückmeldung empfangen willst:


            Code:
            if (){ #Normale Verarbeitung
             ....
             ....
             } elsif ($fh) { # Wenn der Zähler ein Antworttelegramm sendet, ab hier auswerten
             my $buf = <$fh>;
             ...Hier den Inhalt von $buf weiter verarbeiten...
             }
            Ich hoffe ich habe mich da nirgend's vertippt und konnte dir auf die Schnelle helfen
            Gruss Patrik alias swiss

            Kommentar


              #7
              SUPER !!!

              Aber heute Abend nicht mehr ;-) Da werd ich wohl morgen mal früh aufstehen wenn alles noch schläft...da hab ich wenigstens Ruhe ;-)

              Danke!
              Umgezogen? Ja! ... Fertig? Nein!
              Baustelle 2.0 !

              Kommentar

              Lädt...
              X