Embed Printer Control Sequences into Spooled Files

Article ID: 57126

Q: I'm writing an RPG program that uses O-specs to send output to a Datamax printer, and I need to embed a x'02' in the print stream. Every time I try to do that, the x'02' gets stripped out. How can I make this work?

A: Anytime you want to embed ASCII hex codes in a print stream (it doesn't matter what type of printer) you can do so by using ASCII transparency support. I've used this support with HP Laserjets as well as thermal printers such as Datamax and Zebra.

Now, this technique is not foolproof. Whether it works or not will depend on how the data is translated from the IBM i spool to the printer's native language. So you'll have to test it out--but this technique works most of the time.

Background

Most of the time, when we write a spooled file using RPG's O-specs, the output is written to the spool in IBM's SNA Character String (SCS) format. Like most printer languages, SCS uses certain hex values as "control characters" or "escape sequences" that control how the printer behaves. When we write a record using O-specs, the system automatically inserts the appropriate control characters to make the output appear correctly on the page.

Back in the early days, most of the printers we used understood SCS directly, so the spooled file could be sent to the printer, and the printer would use the control sequences to render the output.

Nowadays, however, it's more likely that the SCS will be converted to the printer's language before the printout is printed. This step may be done by software on the system, such as the host print transform function, or by emulation software, or by a hardware adapter. How it works will depend on how your printer is configured and what sort of hardware is attached to it.

In any case, whatever is interpreting the SCS data stream will see the control characters and convert them to the right data for the printer. That translation process is doubtless what's messing up your x'02' sequence--it's being translated to something entirely different (or removed entirely!).

SCS has a particular control sequence called ASCII Transparency. It tells the system that the characters that follow are to be sent, as is, to the printer, without any sort of translation. Theoretically, if the SCS sees an ASCII transparency sequence, it will send the characters that follow it to the printer as is, without translation.

IBM documents the SCS data stream at the following link. In particular, you'll be interested in what it says about transparency on page 4-32:
http://publib.boulder.ibm.com/infocenter/systems/topic/books/sa413130.pdf

The Technique

The basic idea is that you're inserting an SCS code directly into the output stream. When the spooler reads your data, it thinks it's just print data, so it puts it into the spooled file unchanged. But when the SCS interpreter reads your spooled file, it'll see the ASCII transparency command and send the data that follows to the printer as is, thus letting you embed any ASCII escape sequence you like.

Because you're going to be sending unprintable hex data to the printer, it's important that you use CRTPRTF, CHGPRTF, or OVRPRTF to specify that the system not replace unprintable data with blanks. Otherwise, your hex values will be lost entirely.

OVRPRTF FILE(QSYSPRT) DEVTYPE(*SCS) RPLUNPRT(*NO)

Then, when you print your data, you need to send two special values. The first is x'03', which is the SCS command for ASCII transparency. The second is the length (in hex) of the ASCII data you want to be sent as is to the printer. Finally, this is followed by the actual ASCII data.

Here's an RPG example (for a Datamax Prodigy printer):

     FQSYSPRT   O    F   80        PRINTER

     D DMX_IMMCMD      c                   x'030101'
     D DMX_SYSCMD      c                   x'030102'

     D syscmds         s             80A   dim(3) CTDATA
     D label           s             80A   dim(17) CTDATA
     D x               s             10I 0

     D LabelData       ds
     D   data                        80A

      /free

           for x = 1 to %elem(syscmds);
               LabelData = DMX_SYSCMD
                         + syscmds(x);
               write QSYSPRT LabelData;
           endfor;

           for x = 1 to %elem(label);
               LabelData = label(x);
               write QSYSPRT LabelData;
           endfor;

           *inlr = *on;
      /end-free
**
M2280
O0255
L
**
H10
D11
PC
SC
W
Q0001
1542000034701011790
4022000030800719999999999
132200003010105OLIVE LOAF
402200000410071(01)90073608017902(3202)999999(15)999999(21)
122200001230091BATCH # 99999
132200000890141999999
122200000930091WGT:         LBS.
2e2205003540010C&G0190073608017902320299999915999999219999999999
122200000620091USE BY:
14220000001011199/99/99
E

As you can (hopefully) see, I'm inserting the ASCII x'02' needed by the Datamax printer by sending x'030102'. The x'03' is the SCS transparency code. The x'01' is the number of bytes that follow that are transparent ASCII data--in this case, only 1. Finally, I send the x'02' which is to be sent, as is, to the Datamax printer.

I can then send the data that needs to follow the x'02' (i.e., the printer sequences that control how the data is to be printed).

Why You Shouldn't Do This

This technique will certainly work (most of the time, at any rate) but it's often not a good idea. Why not? Because hard-coding printer control sequences into your programs means that your programs will only print properly on that particular type of printer. Down the road, when the printer becomes worn out and needs to be replaced, you're locked into purchasing a new one that speaks the same printer language. That's not a good situation.

Even worse: If they no longer make printers that speak that printer language, you're really in trouble! What will you do, then?

For one or two programs, it's not such a big deal to rewrite them. This technique can be really useful in a pinch to get something out the door quickly! But for hundreds or thousands of programs, it's important to avoid hard-coding printer control sequences.

Instead, use a label design software. There are some great ones available for the IBM i platform. They'll give you a very nice interface for laying out and designing your labels, and they'll let you design it in a printer-neutral fashion, so when the time comes to switch to another printer, you have only to use a different driver, and presto! Your existing labels will still work.

ProVIP Sponsors

ProVIP Sponsors