Subject: Re: [netatalk-admins] pap and PAP issues; page counting [Was: toner low errors]
From: Andras Kadinger (bandit@freeside.elte.hu)
Date: Mon Aug 17 1998 - 21:51:38 EDT
Darren, List,
[Warning: long message follows; also please excuse the bits of infancy
scattered around; it's already 4AM; although those two are not
necessarily related...]
Darren Atkinson wrote:
> The result is coming back as 0xffff (-1 as a signed short).
That means 'printer is busy' by definition, which should also mean the
connection is not opened.
> My hack to the code is below. But, here's a strange thing. I just tried
> connecting to the printer using pap and it worked for a while. This
> is with the non-hacked version of pap:
>
> murdoch % pap -E -p paanini /usr/lib/atalk/pagecount.ps
> Trying 3841.134:157 ...
> status: PrinterError: toner is low; source: AppleTalk
> Connected to paanini:LaserWriter@CSE.
> Connection closed.
Hmm, might the flush operator be missing from pagecount.ps? No, it
doesn't. Then we seem to have a race: the last (and in this case, the
only) data packet from the printer might or might not get sent by the
printer before we close the connection (with -E, that is). It didn't in
the above case.
What do you see with an #EBUG compiled pap and with no -E? We might be
better off with making up some heuristics to allow at least some chance
for an eof (and the last piece of data) to be received from the printer
when -E, e.g. wait for it for a couple of seconds before closing the
connection. Depending on actual printer behaviour, that might make
everything happy (and lose only a couple of seconds per job in the worst
case).
[...]
> So, what can we learn from this behavior? I mean besides the fact
> that HP printers aren't the easiest things in the world to talk to.
> Here's my current scenario of what was happening:
> If you need to use -w to do accurate accounting, then we need to do
> some work it seems. First, add some signal handlers to pap so that it
> properly closes down the connection.
Yes, this is one thing I definitely wanted to do. However, since the
current atp implementation is not in the kernel, this would involve
blocking and unblocking signals around calls to the atp routines - or
maybe not? I'm not very experienced with signals, so I could need some
help with this.
> Second, reverse or otherwise change the logic in pap so that instead of
> checking if the status contains "waiting", it makes sure the status doesn't
> say "busy" or "printing". Does this sound plausible?
Well, that's a good idea. An even more flexible (but possibly overkill)
solution might be to parse the printer's PPD file, which should contain
a list of all possible printer messages. To no avail, as I checked the
PPD for our 4MV now and there is no indication of meaning for the
messages.
What do you get when there is a PrinterError: and the printer is busy
and/or printing? Do you get both messages, or does the error suppress
other indications? The latter may make it impossible to tell the actual
printer status based on the status reply. Otherwise it's simple, I
think.
> Thanks again for all your help!
Well, things seem to get in motion now, and that's good! :-)
I was glad to help! What's more, I'm still glad, so I help further! Ah,
you thought you wouldn't have to pay for it?! Wrong! :-)
> ----------------------------------------------------------------------
>
>
> if ( result != 0 ) {
That is, when the printer returns 'busy' for the open request...
>
> {
> char big_buf [16384];
>
> strncpy (big_buf, iov.iov_base + 9, iov.iov_len - 9);
>
> if (strstr (big_buf, "toner is low")) {
> printf ("ignoring error\n");
> bcopy( &nn.nn_sat, &sat, sizeof( struct sockaddr_at ));
> quantum = rbuf[ 5 ];
> break;
> }
You ignore the error and set the address.
> }
> sleep( 2 );
> } else {
But when the printer is not busy,
> bcopy( &nn.nn_sat, &sat, sizeof( struct sockaddr_at ));
> sat.sat_port = rbuf[ 4 ];
You (correctly) set the port as well.
> quantum = rbuf[ 5 ];
> break;
> }
>
> In the code above, rbuf[4] is always 0, which is why I'm not setting
> sat.sat_port to rbuf [4].
It seems reasonable for the printer to set the port number (rbuf[4]) to
0 when the reply indicates 'busy'.
> I looked and sat.sat_port does contain a value but I guess it isn't the
> right value to talk to the printer and you need to extract the right port
> number from the reply packet.
Initially (after the nbplkup but before the successful OPENREPLY), the
port in sat.sat_port is the port of the socket the printer is registered
under with NBP (you can see it with nbplkup). The PAP spec says, You
have to send an OPEN request to this port, and if and when your
connection request is accepted, you get an OPENREPLY packet back with
'ready' status indication, and with the actual port address you should
use in the future to send the actual data to the printer.
What I can imagine happening here is this: the printer probably handles
out the same port for each connection (since it can handle only one at a
time), and I bet You used the same port number You got in a previous
connection. PAP numbers request data packets, but does not number send
data packets, going further, it allows a sequence number of 0 to mean
'unnumbered', which practically disables sequence numbering checks. What
I thought up can happen, is that the printer probably has a process
bound to the 'connection' socket (whose address normally gets returned
in an OPENREPLY) running continously, and you don't have to issue an
OPEN to start that process. So that process might just sit there, and
accept and digest 'any' ATP/PAP packets sent to it, not strictly
enforcing the semantics of PAP. This may make it possible to send a
(possibly unnumbered) data packet to it and in this way actually 'force'
printing data into the printer even when it showed itself to be busy in
OPENREPLY for some reason. Since the HP probably (as most laserprinters
nowadays I guess) has a multitasking operating system, I can not see any
reason to stop and restart the RIP process or the network input process
just because the engine is printing - in fact, this is why You can get
back the page count too early: you can submit another job while the
pages of the previous one are still being printed by the engine from
raster memory (or I guess from display lists for that matter). I
personally consider this as a feature (it increases throughput,
substantially in some cases), but I agree that this is not very
practical when one tries to get back the page count with pagecount
(which in fact has the semantics of actual hard-copy printed pages by
the engine, and it seems to actually behave that way).
Hmm, a different approach would be to piggyback a page counting
mechanism either onto showpage (for level 1 I guess), or to EndPage (for
level 2); this in itself however doesn't account for #copies or Copies -
but that can be incorporated as well. Although handling of
interruption/cancellation issues gets even messier, since one would have
to put this page count to unencapsulated global PostScript VM to let it
be retained between jobs and thus make sure it doesn't get lost when
cancelling. Or mix 'page #n complete' or similar messages into other
(data) output coming from the printer through %stdout, which would make
handling of the channel unclean and possibly non-transparent - but could
work. The #copies/Copies issue needs handling here as well. But this
wouldn't correctly account: if someone turned the printer off while it
had unprinted pages in memory, those pages would be accounted for. Pages
with n-up printing should pose a problem as well.
[some PostScript tidbits (like MTV Europe does nowadays):
the first PostScript language specification (1985) was called Level 1;
many necessary enhancements were made as time went by, and the result
was PostScript Level 2 (1990), which standardized many real-life,
important facilities previously implemented in vendor-specific ways.
most PostScript procedures can be overridden, to change their behaviour
showpage: the PostScript procedure to tell the printer to 'show the
page',
that is, to print it out; we can enhance it to maintain a counter
EndPage: a PostScript procedure that gets called from each showpage;
it's
a placeholder for things, like n-up printing, where a physical page
receives the (usu reduced) images of multiple logical pages; only
in Level 2; also can be enhanced to increase a counter; problem is,
some n-up implementations however replace it, instead piggybacking
onto it, and this would disable the the counter for these jobs.
#copies: PostScript variable from the vendor-dependent Level 1 days;
should
be set to the number of copies needed from a page before calling
showpage
Copies: much like #copies, but the newer, standardized Level 2 flavour
VM: memory area used to store PostScript variables
local VM: used for short lifetime variables, similar to storage for
local
variables in other languages;
global VM: used for variables with longer lifetime, similar to storage
for
global variables in other languages;
the above two gets cleared between print jobs
unencapsulated (global) VM: VM which does not get cleaned between jobs;
a special operator has to be called with a password argument to
enable access to this memory area, which takes up time like context
switches in unix and also clears local and global VM
%stdin, %stdout: the PostScript interpreter has two devices with these
names; %stdin is where the interpreter reads the PostScript program
text from; %stdout can be used much like in any ordinary C program:
to report progress, results, etc. (the graphic output of course
does not go to %stdout; in a direct connection the Mac uses this
channel to receive results of the queries (questions) it sends to
the printer, otherwise mostly unused
]
Hope, this helps, [it would be a shame if it wouldn't, wouldn't it? :-)]
Sincerely,
Andras Kadinger
bandit@freeside.elte.hu
This archive was generated by hypermail 2b28 : Sat Dec 18 1999 - 16:33:08 EST