ralphi: Netzwerkdrucker ansprechen exec('echo "text"> /?')

Hallo Leute,

eigentlich müsste ich mit der Frage in ein Linuxforum. Ihr könnt mir aber bestimmt helfen ;-)

Nun, ich habe einen Bixolon Bon-Drucker und einen Raspi (arm 64) mit Debian. Nachdem ich verzweifelt und erfolglos (mehrere Tage) versucht habe den Treiber unter cups zum laufen zu bringen, bin ich auf die einfachste Möglichkeit gekommen, text unter Linux auszudrucken:

echo “text” > /dev/usb/lp0

bzw. mit exec() unter php

da ein Zeile 42 (gleich große)  Zeichen hat, kann ich einen Zeilenumbruch durch füllen mit Leerzeichen machen.

So weit so gut.
Jetzt sollte allerdings der Drucker nicht über USB am Raspi hängen, sondern übers LAN angesprochen werden: Der Bixolon SRP-F310 ist auch ein Netzwerkdrucker und unter x.x.x.x:9100 erreichbar.
Gibt es eine Möglichkeit den Drucker  mit echo .. auch über LAN anzusprechen?

Viele Grüße aus LA

--
ralphi
  1. Mit lpr. Parameter -P gibt den Zieldrucker an. Ohne Parameter wird der Standarddrucker genommen.

    Bildschirmausgabe in eine Datei ausgeben z.B. echo test | tee test.txt und diese Datei dann zum Drucker schicken.

    1. Mit lpr. Parameter -P gibt den Zieldrucker an. Ohne Parameter wird der Standarddrucker genommen.

      Standarddrucker setzt einen Treiber (raster file) vorraus. Unter ARM 64 zur Zeit noch sehr schwierig.

      Viele Grüße aus LA

      --
      ralphi
      1. Hallo,

        Standarddrucker setzt einen Treiber (raster file) vorraus.

        autsch, schmerrzt jedesmal wiederr beim Lesen.

        Ciao,
         Martin

        --
        Zwei Kumpels sitzen vor dem Computer. "Welche Suchmaschine benutzt du eigentlich meistens?" - "Prima Vera." - "Hmm, kenn' ich gar nicht." Dann geht die Tür auf: "Schatz ich habe deine Sonnenbrille wiedergefunden!" - "Prima, Vera!"
        Selfcode: fo:) ch:{ rl:| br:< n4:( ie:| mo:| va:) de:] zu:) fl:{ ss:) ls:µ js:(
  2. Moin Moin!

    Jetzt sollte allerdings der Drucker nicht über USB am Raspi hängen, sondern übers LAN angesprochen werden: Der Bixolon SRP-F310 ist auch ein Netzwerkdrucker und unter x.x.x.x:9100 erreichbar.
    Gibt es eine Möglichkeit den Drucker  mit echo .. auch über LAN anzusprechen?

    Tipp mal "netcat" in eine Suchmaschine Deiner Wahl ein.

    Port 9100 ist mit 99,999%iger Sicherheit eine Jetdirect-Emulation, sprich: Du öffnest eine TCP-Connection, schiebst den Druckjob über den TCP-Socket in den Drucker, und schließt die TCP-Connection nach Ende des Jobs. CUPS unter Unixen und MacOS X steuert solche Drucker über das AppSocket-Protokoll an, Windows nennt das "Standard-TCP/IP-Port".

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".
    1. Hi Alex,

      du bist klasse,
      genau so was hab ich gesucht :-)

      exec ( 'echo "text" | netcat -C -D 192.168.123.40 9100');

      Viele Grüße aus LA

      --
      ralphi
      Aufgeschnappter Spruch:
      Was hat ein U-Boot und Windows gemeinsam ?
      Wenn man ein Fenster öffnet, gehn die Probleme los ;-)
      1. Vergessen gelöst dazuzuschreiben ;-)

        Hi Alex,

        du bist klasse,
        genau so was hab ich gesucht :-)

        exec ( 'echo "text" | netcat -C -D 192.168.123.40 9100');

        Viele Grüße aus LA

        --
        ralphi
      2. Moin Moin!

        genau so was hab ich gesucht :-)

        exec ( 'echo "text" | netcat -C -D 192.168.123.40 9100');

        Wahrscheinlich geht's auch ohne drei neue Prozesse anzustoßen (shell, echo und netcat), einfach indem Du innerhalb Deines Programms einen Socket öffnest, statt das an netcat zu delegieren. Ich tippe mal auf PHP (weil in so ziemlich jeder anderen Sprache, die auf Unixen läuft, exec() den aktuellen Prozess durch einen anderen ersetzt und deswegen exakt einmal "funktioniert", während PHPs exec() das macht, was allgemein mit system() oder spawn() bezeichnet wird), da findest Du einen Einstieg bei socket_create(), noch besser bei dem Client-Beispiel. Vergiß das ganze HTTP-Theater, schreib einfach "Hallo Welt" in den Socket, das Lesen einer Antwort kannst Du ebenfalls vergessen, der Drucker antwortet in aller Regel mit Text oder Grafik auf Papier, nicht mit Bytes im Socket.

        Perl hat Sockets in perlipc dokumentiert, die Beispiel-Clients lesen aber aus dem Socket, statt zu schreiben. Ein einfacher Test könnte so aussehen (ungetestet):

          
        #!/usr/bin/perl  
        use strict;  
        use warnings;  
        use IO::Socket;  
          
        my $sock=IO::Socket::INET->new(  
            Proto => 'TCP',  
            PeerAddr => 'drucker42.local.lan',  
            PeerPort => 9100,  
        ) or die "Can't open socket: $!";  
        $sock->print("Hallo Welt!\nDieser Text fällt aus dem Drucker\n");  
        $sock->close();  
        
        

        PHP müßte ungefähr so aussehen -- ungetestet, ohne Fehlerprüfungen, frei nach dem Beispiel 2 aus dem Manual:

          
        $sock=socket_create(AF_INET,SOCK_STREAM,SOL_TCP);  
        socket_connect($sock,"drucker42.local.lan",9100);  
        $printjob="Hallo Welt!\nDieser Text fällt aus dem Drucker\n");  
        socket_write($sock,$printjob,strlen($printjob));  
        socket_close($sock);  
        
        

        Und wenn ich aus dem Beispiel die $-Zeichen und den "socket_"-Prefix streiche, sieht das schon fast aus wie C (insbesondere das strlen()-Theater. Als ob PHP nicht wüßte, wie lang $printjob ist):

          
        #include <sys/socket.h>  
        #include <netinet/in.h>  
          
        static const char printjob[]="Hallo Welt!\nDieser Text fällt aus dem Drucker\n");  
          
        int main(int argc, char**argv)  
        {  
           int sockfd;  
           struct sockaddr_in servaddr;  
           sockfd=socket(AF_INET,SOCK_STREAM,0);  
           bzero(&servaddr,sizeof(servaddr));  
           servaddr.sin_family = AF_INET;  
           servaddr.sin_addr.s_addr=inet_addr("drucker42.local.lan");  
           servaddr.sin_port=htons(9100);  
           connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));  
           write(sockfd,printjob,strlen(printjob));  
           close(sockfd);  
        }  
        
        

        Alexander

        --
        Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".
        1. Hi Alex,

          exec ( 'echo "text" | netcat -C -D 192.168.123.40 9100');

          du hast mir gleich noch mal geholfen ohne das ich weiter gefragt habe ;-)

          die obige netcat lösung hab ich NUR unter php-cli zum laufen gebracht. Obwohl ich in der php.ini, die Einträge "disable_functions" beim Apache2 gelöscht habe, wollte er nicht drucken.

          PHP müßte ungefähr so aussehen -- ungetestet, ohne Fehlerprüfungen, frei nach dem Beispiel 2 aus dem Manual:

          $sock=socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
          socket_connect($sock,"drucker42.local.lan",9100);
          $printjob="Hallo Welt!\nDieser Text fällt aus dem Drucker\n");
          socket_write($sock,$printjob,strlen($printjob));
          socket_close($sock);

          
          >   
          
          ich wäre nicht auf die Idee gekommen, dem Drucker einfach nur Text auf den Port zu legen. Dachte immer das wäre ein Druckerspezifisches Kaudawelsch von Steuerbefehlen, bis der überhaupt was macht.  
            
          ~~~php
          // drucken		  
          if(!($sock = socket_create(AF_INET, SOCK_STREAM, 0)))  
          {  fehler( socket_strerror(socket_last_error())  ) ;	}  		// Fehler  
          if(!socket_connect($sock , '192.168.123.40' , 9100))  
          {  fehler( socket_strerror(socket_last_error()) ) ;	}  		// Fehler  
            
          for ($i=0 ; $i< count($zeile); $i++) {  
          	if( ! socket_send ( $sock , $zeile[$i] , strlen($zeile[$i]) , 0))		// schreiben  
          	{  fehler( socket_strerror(socket_last_error()) ) ;	     }  		// Fehler  
          }	  
            
          socket_close($sock);
          

          Jetzt druckt er anstandslos - hiphip.. Dank dir :-).
          Auch \n\r (Zeilenumbruch) kann er.
          Kennst du noch eine Möglichkeit, Umlaute darzustellen 'äöü' ?

          Viele Grüße aus LA

          --
          ralphi
          1. Moin Moin!

            ich wäre nicht auf die Idee gekommen, dem Drucker einfach nur Text auf den Port zu legen. Dachte immer das wäre ein Druckerspezifisches Kaudawelsch von Steuerbefehlen, bis der überhaupt was macht.

            Das kommt sehr auf den Drucker an. Die meisten Drucker, die Normalpapier bedrucken, können "einfach so" reingedrückten Text auch "einfach so" drucken. Das stammt noch aus der Zeit vor DOS. (GDI-Krüppel können das natürlich nicht.) Extras wie Fettdruck, Schriften, Grafikmodus etc. gibt es über druckerspezifische Steuersequenzen, mittlerweile aber sehr oft auch über Industrie-Standards wie PCL, Postscript oder ESC/P2. Die Befehlssätze von IBM Proprinter und Epson FX80 werden auch gerne noch genommen.

            Spezialdrucker, die z.B. Etiketten drucken, wollen oft tatsächlich erst einmal Steuerzeichen sehen. Die Etikettendrucker, mit denen ich mich nebenbei beruflich beschäftige, brauchen z.B. erst einmal eine Erklärung, wie groß das Etikett ist, an welche Stellen gedruckt werden soll, und was (Text oder Barcode). Dazu gibt es ein ungefähr hundert Seiten starkes Handbuch, in dem im wesentlichen pro Seite ein Steuercode erklärt wird. Bei diesen speziellen Druckern definiert man erstmal ein Layout, danach schiebt man nur noch die Daten in den Drucker, die in dieses Layout gefüllt werden sollen, und die Anzahl der zu druckenden Etiketten.

            Sinngemäß also:
            1. Start Layout
            2. Etikett ist 800 x 600 Zehntelmillimeter groß
            3. Feld 1 ist Text fett Schriftart 23 an Position 100,100
            4. Feld 2 ist Barcode Typ Codabar Größe 3 an Position 300,100
            5. Ende Layout
            6. Start Daten
            7. Feld 1 ist "Hallo Welt"
            8. Feld 2 ist "12345"
            9. Ende Daten
            10. Drucke 10.000 Stück

            Und schon fallen 10.000 Etiketten mit dem Text "Hallo Welt" und einem Barcode "12345" raus.

            Danach, ohne ein neues Layout zu definieren:

            11. Start Daten
            12. Feld 1 ist "Murks"
            13. Feld 2 ist "00000"
            14. Ende Daten
            15. Drucke 5.000 Stück

            Und weitere 5.000 Etiketten im selben Layout, aber mit Inhalt "Murks" bzw. "00000" fallen aus dem Drucker.

            Man kann auch noch Zähler, Datumsangaben und ähnliches einbauen. Das nutzen wir aber nicht, wir drucken bis auf ein oder zwei Spezialfälle auch immer nur ein Exemplar eines Etiketts.

            Wie gesagt, so ticken UNSERE Etikettendrucker. Dein Drucker benimmt sich offensichtlich anders, den Plain Text ohne Steuerzeichen ignorieren unsere Drucker völlig (oder sie fangen an zu quaken, dass der Datenmüll kein gültiger Druckjob ist).

            Jetzt druckt er anstandslos - hiphip.. Dank dir :-).
            Auch \n\r (Zeilenumbruch) kann er.
            Kennst du noch eine Möglichkeit, Umlaute darzustellen 'äöü' ?

            Das ist wieder sehr druckerspezifisch. Handbuch lesen hilft definitiv.

            Viele Drucker sind, was Umlaute angeht, bei DOS stehen geblieben, sprich CP437, gerne auch als "IBM PC" oder ähnliches bezeichnet. Erst eine Steuersequenz stellt die Zeichentabelle des Druckers auf ISO-8859-1, ISO-8859-15 oder Windows-1252 um. Bei PCL braucht man dazu <ESC> ( 0 N <ESC> ) 0 N (Hexadezimal: 1B 28 30 4E 1B 29 30 4E), andere Druckersprachen brauchen andere Sequenzen. Manche Drucker können auch einfach nicht umgestellt werden, dann muß man sich die Zeichen außerhalb des ASCII-Bereichs (32 bis 126) selbst umcodieren, sinnigerweise erst unmittelbar vor dem Druck, damit der Rest des Systems nicht mit verdrehten Zeichen arbeiten muß.

            Unsere richtig alten Etikettendrucker KENNEN keine Umlaute. Man bekommt ums Verrecken keine Umlaute aus den Kisten, egal was man anstellt. Man kann keinen Grafikmodus einstellen, man kann keine Punkte über zusätzliche Layout-Felder setzen, weil sich Felder nicht überlappen dürfen, man kann keine eigenen Zeichen definieren. So bleibt nur, Umlaute in ae, oe, ue umzuschreiben. Für unsere Zwecke reicht das.

            Alexander

            --
            Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".
            1. Moin Moin!

              Das ist wieder sehr druckerspezifisch. Handbuch lesen hilft definitiv.

              Wobei das erste von Google ausgespuckte "User's Manual" kaum mehr als eine Auspackanleitung ist. 19 Seiten, nicht eine Silbe über Steuercodes. Das Command Manual hat 145 Seiten und sieht sehr übersichtlich aus. Ich denke, damit könnte ich unsere Druckprogramme in so etwa einer Stunde auf den Drucker umgestellen. Ich muß allerdings zugeben, dass in dem Command Manual nicht viel erklärt wird, sondern der Umgang mit ähnlichen Geräten als bekannt vorausgesetzt wird.

              Auf jeden Fall hat der Drucker die Möglichkeit, eigene Zeichensätze zu laden, Umlaute sind also definitiv möglich, notfalls über selbstgemalte Buchstaben. Grafikmodus hat der Drucker auch. "Specify International Character Set" auf S. 37 dürfte allerdings irreführend sein, ich vermute, damit wird zwischen ASCII und einer prähistoren DIN-Codierung mit 7 Bit umgeschaltet, die []{|}~ zu Umlauten umdefiniert. "Select Character Code Table" auf Seite 49 paßt schon eher, CP 437 ist DOS, CP 850 ist eingedeutschtes DOS, CP 1252 ist Windows-1252 (ein Superset von ISO-8859-1 und ISO-8859-15) und ziemlich sicher, was Du haben willst.

              Spiel mal rum, sende eine Steuercode pro Test, und vor jedem Test erst einmal die härtestmögliche Reset-Sequenz, damit die Steuercodes vom letzten Test nicht in den aktuellen Test reinlaufen. Notfalls zwischen den Testläufen den Drucker vom Strom trennen.

              Alexander

              --
              Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".
              1. hi

                Wobei das erste von Google ausgespuckte "User's Manual" kaum mehr als eine Auspackanleitung ist. 19 Seiten, nicht eine Silbe über Steuercodes. Das Command Manual hat 145 Seiten und sieht sehr übersichtlich aus. Ich denke, damit könnte ich unsere Druckprogramme in so etwa einer Stunde auf den Drucker umgestellen. Ich muß allerdings zugeben, dass in dem Command Manual nicht viel erklärt wird, sondern der Umgang mit ähnlichen Geräten als bekannt vorausgesetzt wird.

                hey - du hast ein Handbuch mit steuerbefehlen gefunden ;-)
                anscheinend bist du vom fach - kannst du mir sagen, wie man die befehle verpackt, dass sie nicht als text ausgegeben werden?
                arbeitest du bei einem hersteller?

                Viele Grüße aus LA

                --
                ralphi
                1. Moin Moin!

                  hey - du hast ein Handbuch mit steuerbefehlen gefunden ;-)

                  Ja, die hohe Kunst, Druckermodell und "Manual" in Googles Suchformular zu kopieren.

                  anscheinend bist du vom fach -

                  Das könnte man so sagen.

                  kannst du mir sagen, wie man die befehle verpackt, dass sie nicht als text ausgegeben werden?

                  Indem Du die Bytes an den Drucker schickst, die im Handbuch stehen. Wenn Du sinngemäß echo "ESC @" ausführst, wird der Drucker die fünf Zeichen E, S, C, Leerzeichen, @ ausgeben. echo "\x1B@" wird den Drucker zurücksetzen. Die erforderlichen Bytes stehen auf jeder Handbuchseite mit ASCII-Namen, hexadezimalem und dezimalem Wert.

                  Beachte auch, dass der Drucker zwei Betriebsarten hat: Standard Mode (nach ESC S, nach FF und nach ESC @), und Page Mode (nach ESC L). Zu den Unterschieden siehe Seite 35. Page Mode erwartet, dass Du erst einmal die komplette Seite definierst, während im Standard Mode offenbar ohne weitere Diskussion losgedruckt wird.

                  arbeitest du bei einem hersteller?

                  Nein. Aber mein Arbeitgeber verklebt tonnenweise Etiketten auf alles, was sich nicht schnell genug selbst in Sicherheit bringen kann.

                  Alexander

                  --
                  Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".
                  1. hi

                    Indem Du die Bytes an den Drucker schickst, die im Handbuch stehen. Wenn Du sinngemäß echo "ESC @" ausführst, wird der Drucker die fünf Zeichen E, S, C, Leerzeichen, @ ausgeben. echo "\x1B@" wird den Drucker zurücksetzen. Die erforderlichen Bytes stehen auf jeder Handbuchseite mit ASCII-Namen, hexadezimalem und dezimalem Wert.

                    dank dir für die info.
                    leider erwischte mich dabei, das ich mir programmieren sehr unkoordiniert beigebracht habe.
                    Mir fehlen einfach die Basics
                    Als Beispiel hab ich mir cut ausgesucht (läuft auch mit einem win-treiber problemlos, ist also aktiviert)
                    $zeile = "\x08566548"; //hex code
                    $zeile = "\x08\x56\x65\x48";
                    und andere varianten mit anderen codes funktionieren nicht.

                    irgendwie mach ich grundsätzlich was falsch.
                    reines ASCII und \n\r\t etc. druckt er problemlos.
                    Kannst du mir bitte ein paar string-zeilen als Beispiel (php)vorgeben?
                    zB. revers drucken
                    Hex 1D 42 n -> n zw. 0 - 255
                    "text"
                    Danke.
                    Viele Grüße aus LA

                    --
                    ralphi
                    1. Moin Moin!

                      leider erwischte mich dabei, das ich mir programmieren sehr unkoordiniert beigebracht habe.
                      Mir fehlen einfach die Basics
                      Als Beispiel hab ich mir cut ausgesucht (läuft auch mit einem win-treiber problemlos, ist also aktiviert)
                      $zeile = "\x08566548"; //hex code
                      $zeile = "\x08\x56\x65\x48";
                      und andere varianten mit anderen codes funktionieren nicht.

                      Die beiden Zeilen sind deutlich unterschiedlich und liefern unterschiedliche Ergebnisse.

                      Tipp: Schreib mal einen Dreizeiler, der die beiden Varianten mit \r\n getrennt in eine Datei schreibt, und sieh Dir das Ergebnis an.

                      Verstehst Du, was \x in PHP-Strings bedeutet? Hast Du im PHP-Handbuch nachgelesen?

                      So, wie ich das Command Manual verstehe, wird Dein Kommando nicht schneiden. Auf Seite 138 steht explizit, dass nur geschnitten wird, wenn n=0. Du sendest nicht 0, sondern 72 (\x48) als letztes Byte. 48 wäre der dezimale(!) ASCII-Code des Zeichens "0", hexadezimal wäre das \x30. Das ist aber immer noch nicht 0.

                      irgendwie mach ich grundsätzlich was falsch.

                      Ja. Du liest zu wenig.

                      reines ASCII und \n\r\t etc. druckt er problemlos.
                      Kannst du mir bitte ein paar string-zeilen als Beispiel (php)vorgeben?

                      Nein. Das kannst Du selbst.

                      Schreib Dein Programm so um, dass es erst einmal den Druckjob in eine Datei schreibt statt direkt zum Drucker. Schau Dir den Dateiinhalt an und vergleiche das mit dem, was Du dem Drucker wirklich schicken wolltest.

                      Eine ASCII-Tabelle ist dafür extrem hilfreich, die Tabelle  aus dem Wikipedia-Artikel ASCII reicht für's erste. Ein Viewer oder Editor, der Dateien hexadezimal anzeigen kann, macht die Sache einfacher.

                      Seite 17 im User's Manual (nicht im Command Manual) kennst Du? Wenn nicht, lies sie, und versuch zu begreifen, was der Hersteller Dir da anbietet.

                      Alexander

                      --
                      Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".