Embed PJL Statements in a Workstation Customizing Object
November 5, 2008 Michael Sansoterra
Note: The code accompanying this article is available for download here.
Modern day printers are fabulous in all that they do. In addition to accepting basic ASCII text streams, modern general purpose laser printers usually process either postscript (PS) or printer command language (PCL) streams to generate ornate printouts. So what about using these printers with the IBM i? If the printer understands PCL (or a few other data streams such as IBM’s PPDS or Epson FX/LQ), then there is no problem because IBM’s host print transform functionality magically converts SCS/AFP spool files into one of the aforementioned data streams that the printer can understand. The host print transform function has made most of my life doing IBM i based printing has been very good–until recently.
Awhile back, a customer with a Ricoh copier inquired about enabling the copier’s stapling and hole-punch functions directly from their AS/400 OUTQ. I figured it would be no problem–just find out the hex commands required to perform these functions, embed the codes in a transparency within a printer file and we’re good to go! However, after doing a little research I discovered that the commands to staple and punch are supplied to the device via Printer Job Language (PJL) statements.
PJL is a language developed by HP for switching printer languages on a job by job basis, to retrieve feedback from a printer and to provide a way of performing other advanced functions not related to printing itself (such as layout, font, etc.). Typically, a print stream is composed of PJL statements (optional for job control) followed by PCL code (used for print layout and data).
I talked to IBM support and learned that there was no way to feed the PJL commands from the IBM i to the device (in other words, it is only capable of feeding PCL to the device). I glibly informed the customer that what they wanted to do couldn’t be done directly from the AS/400, so they continued to send their spool files through a Windows based printer emulator that in turn used the Ricoh Windows print driver to enable the staple and punch features.
This customer later obtained a Xerox WorkCentre copier and inquired with their Xerox sales rep if staple and hole-punch could be enabled directly from the AS/400. The sales rep told them it could! Knowing now that these functions were enabled using PJL commands, I called Xerox support to give them a “what for” since I knew this “couldn’t be done.” I ended up talking to a tech support rep who guided me through the process of embedding PJL statements in a workstation customizing object. I’m sharing that technique now.
Keep in mind that this is actually a very large topic being addressed in a small space. Therefore it is assumed that the reader has a fair bit of IBM i printing knowledge. If you don’t see your specific question answered, please review the Related References at the end of the tip. Also, this tip assumes that your printer device understands the PCL (sometimes pronounced “pickle”) data stream.
Getting a Workstation Customizing Object Source File
In order to send PJL commands to a print device, we need to create a workstation customizing object (WSCST) and add the hex values for our PJL commands. The Create Workstation Customizing Object (CRTWSCST) command is used to build a WSCST object from a source file.
So where do we get the source file? Some manufacturers that directly support the AS/400 will supply source for workstation customizing objects for their specific printers. (This was the case with the Xerox WorkCentre copier I worked on.) Other times you have to build your own, but building one from scratch is beyond the scope of this tip. (See the Related References at the end of this tip for how to get started).
A final option is to build and modify a source file based on a model that’s similar to one IBM supports in your version of the i operating system (formerly known as OS/400 and i5/OS). To see which models are available, prompt the Retrieve WSCST source (RTVWSCST) command. Enter a device type of *TRANSFORM and then press F4 on the “Manufacturer type and model” parameter. A list of all supported printer devices is displayed (this list will vary by OS level, with later OS versions offering more options.) Choose the Manufacturer type and model that is most closely compatible with your device and fill in the source file information to build a base WSCST object source file.
How do you know which IBM model is closest to yours? Well, IBM used to publish a Web page that listed popular printers and which workstation customizing object to use with it because IBM can’t create a *WSCST for every printer on the market. However, I have not been able to find that page recently. So the next best thing is to do a Google search to see if anyone else has your printer and an AS/400. Sometimes, sticking with a close model by the same manufacturer works as well. If all else fails, if you have a PCL device, stick with a general PCL driver such as *HP4 and just add features to the *WSCST source.
Author’s Note: Some Guru readers kindly supplied the following link to a printer support page on IBM’s website.
Here’s a sample of how to use the RTVWSCST command to get a source member to work with:
RTVWSCST DEVTYPE(*TRANSFORM) MFRTYPMDL(*RICOH2045) SRCMBR(RICOH2045) SRCFILE(QGPL/QTXTSRC) TEXT('Modified WSCST for Ricoh 2045')
Once you have a base source member you’re ready to modify it by adding PJL commands.
How Do I Know What PJL Commands To Use?
So how do you know what PJL commands to send to your printer? There are a few options. The first is to look in a general PJL reference guide (search Google or see Related References below). The second is to look in a device specific PJL guide supplied by the manufacturer (some devices accept custom PJL statements).
When all else fails, another option is to send a print stream to a file that can be opened with a text editor. For instance, if you’re using Windows to print to a device that can perform a hole-punch function, you can ascertain the proper PJL commands by doing the following:
So you know what it looks like, here are some PJL statements created by the Windows printer driver for the Xerox WorkCentre 7345 with stapling activated (the line breaks were inserted by me):
←%-12345X NOTE: The ← represents the ESCAPE character @PJL SET JOBATTR="@TRCH=ON" @PJL JOB MODE=PRINTER @PJL SET BINDING=LONGEDGE @PJL SET PAPERDIRECTION=LEF @PJL SET STAPLE=BOTTOMLEFT @PJL SET PUNCH=NONE @PJL ENTER LANGUAGE=PCL
How Do I Incorporate PJL Into My WSCST Source?
Once you have identified the PJL statements you need, you’re almost ready to put them in your WSCST source. But you must first convert the ASCII PJL commands to their hex equivalent. The hex codes should be ASCII based because this is what the printer will expect; do not send EBCDIC hex codes for the PJL statements. To remove the drudgery of looking up ASCII character codes and converting them to hex, I wrote a little VBA function to do the task, which you can download here. I actually used this code within an Excel macro as an easy way to paste statements into a cell and get the hex equivalents in an adjacent cell. There are also free Website utilities that will accept an ASCII stream and convert it to hex such as http://www.easycalculation.com/ascii-hex.php.
Once you have the hex equivalents of the PJL commands, place them in the :INITPRT section of your WSCST source. The data contained in INITPRT is the first thing sent to the printer. Since the PJL commands must come before the PCL stream, this is the logical place to put them.
Here is an excerpt from a WSCST object I created to perform an OUTBIN override, staple, and hole punch on a Xerox copier. Comments (/* */) are included to indicate what the hex codes mean.
:INITPRT DATA= /*
Notice that each data line is embedded in single quotes followed by an X. The very last line should also have a period to indicate the termination of the initialization data. When finished, save the source file and exit. Whenever a spool file is sent to a printer device attached to this WSCST, these PJL commands will automatically be sent first.
Create WSCST and Attach To a Printer Device
Once the source modifications have been completed and saved, issue the Create Workstation Customizing Object (CRTWSCST) command, assign a name and library for the *WSCST object, and specify the source file and member. If there are no errors in the source code a *WSCST object will be created.
Next, you must associate the newly created *WSCST with a printer device. If you’re creating a new printer device, issue the Create Device Description (Printer) (CRTDEVPRT) command and specify the following parameters:
TRANSFORM(*YES) MFRTYPMDL(*WSCST) WSCST(MYLIB/MYWSCST) /* Change this to your own WSCST */
These parameters specify that host print transform (HPT) is turned on (HPT will convert IBM print data streams to PCL), that the manufacture type and model will be a workstation customizing object, and the name of the workstation customizing object containing the PJL statements. Of course you’ll need to specify additional parameters on this command to complete the printer device creation.
Likewise, if you’re changing an existing printer device, you should end the writer (ENDWTR), vary off the device (VRYCFG) and then issue the CHGDEVPRT command and specify the same three parameters:
TRANSFORM(*YES) MFRTYPMDL(*WSCST) WSCST(MYLIB/MYWSCST)
When you’ve completed creating or changing a printer device, make sure that the device varied is on (VRYCFG) and that the printer writer is started (STRPRTWTR).
You now have a printer device description that will send PJL statements from the IBM i (a.k.a., AS/400, i5, System i, and iSeries) to your printer whenever a spool file is printed.
Additional PJL Commands
Many devices now have an LCD panel that can show things like the print job’s owner (i.e., user name), the document name, and the host that generated the job. (The Windows print spooler application shows this information as well.) Unfortunately, since the PJL hex codes will be embedded in a WSCST, we can’t tailor them for individual document names and users. However, we can embed the host name in PJL and we can put the name of the host OUTQ or print device in the user name area to help associate where the print job came from. Here are sample PJL commands along with their hex values:
@PJL SET JOBATTR="@LUNA=MYOUTQ" NOTE: This is the owner (user name) 40504A4C20534554204A4F42415454523D22404C554E413D4D594F55545122 @PJL SET JOBATTR="@CNAM=AS400" NOTE: This is the host name 40504A4C20534554204A4F42415454523D2240434E414D3D415334303022
Now when a print job is sent to the device, the LCD display will show MYOUTQ as the user name and AS400 as the host. How this information is displayed, if at all, varies from device to device.
Static Hex Codes and PJL Woes
As empowering as this technique is to send PJL codes to a printer, there is one major drawback: each *WSCST can have only one fixed set of PJL statements. So what happens when you want the printer to staple, to punch, or to staple and punch? The ugly answer? Create three separate WSCST objects with the appropriate PJL commands (one for staple, one for punch, one for staple and punch), and create three duplicate printer devices with each referencing its own WSCST.
For this Xerox copier, I ended up having five different workstation customizing objects and printer devices created to fulfill variations of staple, punch, staple and punch, staple with two copies and staple with nine copies! (For the record, combining the PJL staple statement with the PCL number of copies command as supplied by OVRPRTF COPIES(x) only made the copier attempt to staple all nine copies of the report with one staple! It turned out I needed a second PJL statement to set the print “quantity” in order to get nine copies stapled individually.) I ended up naming my printers as follows:
A second issue is that any problem in the PJL (such as a bad hex code or an invalid command) can cause the entire PJL stream to be ignored. My suggestion is to start small with the PJL. In other words, start with minimal PJL to get one function to work and then add additional PJL code from there. Save frequent copies of the WSCST source as your reach milestones in getting each additional PJL function to work correctly.
Given all this mess, I hope in the near future that IBM gives developers some kind of method to send PJL commands to the printer within an individual spool file. This could either be a long hex parameter on the OVRPRTF statement or a new parameter on the CHGSPLFA statement, or perhaps these commands could reference a source member containing PJL commands. Maybe even a DDS keyword could be used to attach PJL data to a spool file. This PJL hex would live in the spool file and only be sent to the printer device if it is a host print transform enabled device. Just a thought that would really expand the printing capabilities of the i! (Hint, hint, IBM!!!!) Sounds like a good idea, but I bet there are quite a few additional complexities involved. I do hope IBM will tackle this issue.
Embedding PJL in a workstation customizing object offers benefits of performing advanced functions that are not generally available in the PCL stream such as folding, stapling, and hole punching. It also allows job information such as the owner and host names to be included in the device’s LCD display. Use PJL to get the most out of your printer device’s features directly from the i!
Author’s Note: I would like to offer a special thanks to Charles at Xerox support for providing the info on how to use PJL with workstation customizing objects.
Michael Sansoterra is a programmer/analyst for i3 Business Solutions, an IT services firm based in Grand Rapids, Michigan. Send your questions or comments for Michael to Ted Holt via the IT Jungle Contact page.
Editor’s Note: This article has been corrected since it was originally published. [Changes made 11/08/08.]