Close

Wrapping it up? Not quite.

A project log for Modern HP5N

Dragging a mid 90's laser printer, kicking and screaming into the 21st century

timescaleTimescale 11/27/2019 at 16:577 Comments

After my log entry, star date 12345 yesterday, about my idea to simply inject PJL code at the beginning and the end of the stream, Ken Yap, again, gave some valuable pointers on what to look for.

He told me to look at the filters in cups, which I did and I found a massive amount of potential there. Examples of using PJL with PCL looked like what I wanted to try was perfectly possible. Here is a link to a site where a lot of examples are given : Using your own filters to print with cups


Looking into it further, I realized that a lot of examples would only work on older CUPS versions. The way filters work on the latest version is often somewhat different and the various degrees of up-to-date documents make it a bit confusing at times. Luckily, while trying to figure out how data is routed through CUPS (I have use cups for decades, but never dove in so deep), I figured out that the PPD file for the 5N held the target filter that outputs the data that the printer can read. In this case it was rastertogutenprint5.3 which is an binary executable.

Also in this folder /usr/lib/cups/filters/ were a number of wrapper scripts for various filters, most of them for legacy purposes, so I copied the code ( from rastertopclm ) of a wrapper file, put it in a script and after some trial and error, I got the wrapper file, which I set as the filter in the HP5's PPD file to pass though the data and get a good print.

#!/bin/sh

# Wrapper filter for PJL injection

echo "DEBUG: rastertopclm argv[$#] = $@" >&2
echo "DEBUG: PPD: $PPD" >&2

if [ -n "$6" ]; then
    exec <"$6"
fi

OUTFORMAT=PCLM $CUPS_SERVERBIN/filter/rastertogutenprint.5.3 "$1" "$2" "$3" "$4" "$5"

Bare in mind that I have no clue what I'm doing here, and the subsequent experiment will attest to that fact. After this script neatly passed the data from the wrapper to the filter, I thought to go for it and try and combine some of the stuff from the earlier link, for what I suspect were examples for cups < 2.0. So I took this command :

echo -en "\033%-12345X@PJL RDYMSG = Printing\n\033E"

And I just pasted it in there. It did not work! But it did do something. The print job was a success and the result was 1 page with "-en" on it and the second with the actually print on it. If it put this line after the OUTFORMAT line, the last page would be the "-en" page and unsurprisingly, two lines before and after resulted in 3 pages! "-en" - "Hello World" - "-en".

Without the "-en" flags, there is no effect at all. Perhaps the PJL arrived correctly but did not set the message, so I put this in :

echo "\033%-12345X@PJL INFO STATUS\n\033E"

Hoping to get a first page with the output of the INFO STATUS command.. No such page.

 
I guess it is a start, but I am still a bit in the dark by ECHO is behaving that like and frankly how the whole thing works. I have a basic understanding, but many key details and mechanisms elude me.

On another note, this wrapper could be a better way of turning on power to the printer, so even if I am completely mistaken, something rather good has come from this.

Thanks to Ken Yap for pointing me in this direction. Often a small nudge is what gets balls rolling, or printer drums in this case.

EDIT : Just tried to power up the printer from the wrapper with this code :

/home/pi/automation/./hs100.sh -i 192.168.1.4 on  > /dev/null
sleep 30s

The sleep command makes the spooler wait for the printer. Sometimes the job was lost without it. Of course this needs a bit more work with a check if the TP-Link device is already on. In which case, nothing has to be done.

Discussions

Ken Yap wrote 11/27/2019 at 22:44 point

Hi, more than one filter in the chain may have run. IIRC if the data looks like text it will invoke a generic filter that converts the text to PCL. This may have mangled your injected text. It depends on how the printer is declared in the queue. For example for the engineers here at work who needed to print the old 8-bit character set that includes box drawing characters and has been in HPLJ ROMs forever I had to create a raw queue. A printer can be in more than one queue.

  Are you sure? yes | no

Timescale wrote 11/29/2019 at 17:24 point

I think the rastertogutenprint is the last filter. The result looks like PCL proper so in theory I should be able to put a bit of PJL in front and at the end. I'm not surprized that my first attempt did not work as PJL is very finicky about escape and linefeed characters en such, but what confuses me is that the output of the "echo" were the flags and not the string.

The filter wrapper is a simple bash script and as I understand it, the character output of the script becomes the input of the filter. How then can it be that the flags for the echo command turn up as output in some way, but not the string it should output?

The code for the smart plug is far more involved and calling it from the filter has no apparent effect on the output of the filter chain. It is all very strange.

I didn't have time to play around with it the last couple of days, but I'll do some experiments this weekend.

  Are you sure? yes | no

Ken Yap wrote 11/29/2019 at 21:18 point

When a bare echo is run inside a bash script, this runs built-in echo of bash, which may for some reason may have disabled the options. Another possibility is that it wasn't bash interpreting the script, but sh, which is a somewhat less capable alter-ego of bash. It's only bash if the top line is #!/bin/bash.

Either way, to force the program echo to be run, call it as /bin/echo.

  Are you sure? yes | no

Timescale wrote 11/29/2019 at 21:26 point

Seeing as the wrapper runs as sh, not bash, you have a point. I did not even notice it was sh, but it's right there on top.. I'll have a fiddle with that!

Thanks a bunch!

EDIT : Making it a bash script did indeed take away the strange behavior. It still does not inject PJL in the stream, but it does not create extra pages. So it's just that I do not really understand how the stream is actually generated.

But with the odd nudge in the right direction...

  Are you sure? yes | no

Ken Yap wrote 11/29/2019 at 21:59 point

Has the script (or any file it may have included) done something sneaky like define echo to be a function that calls echo but writing to stderr rather than stdout? Unix/Linux is endlessly flexible like that.

  Are you sure? yes | no

Timescale wrote 11/30/2019 at 11:29 point

"Has the script (or any file it may have included) done something sneaky like define echo to be a function that calls echo but writing to stderr rather than stdout? Unix/Linux is endlessly flexible like that."

If it has, I have to look it up in the source code as those filters are all binary, but I do not think so. Seeing as the rastertoguternprint5.3 filter takes either 5 or 6 arguments depending how the input file is presented. In this case, I don't have to give the 6th argument which leads me to believe that the entire chain uses stdout. I read about this mechanism in CUPS filters in various documents.

I could try to use cat and see if that makes a difference.

  Are you sure? yes | no

Ken Yap wrote 11/30/2019 at 11:33 point

Another program you could use is printf(1).

  Are you sure? yes | no