LPRng-HOWTO: Installing your printer

Next Previous Contents

## 3. Installing your printer

In the following text, I will assume that your printer itself is working properly. I.e., you are able to send data to the printer in such a way that it responds by - well, printing the text :)

How to ensure this is highly system-dependent and falls outside the scope of this document. However, here are some hints.

## 3.1 Parallel Printers

Gordon Haverland `<haverlan@agric.gov.ab.ca`> supplied this little script, that will put you on the right track:

    #!/bin/sh
    #set -v -x              # uncomment for debugging
    PATH=/bin:/usr/bin
    printer=
    for $i in $*;
    do
        case $i in
            /dev/*) printer=$i ;;
            *) ;;
        esac
    done

    if test -z "$printer";
    then
        echo USAGE: $0 device_name ;
        exit 1;
    fi;

    echo PRINTER TEST to $printer 1>&2
    for i in 1 2 3 4 5 6 7 8 9;
    do
        echo $i > $printer;
    done
    echo -e \\r\\f > $printer
    exit 0;

If your printer is connected to the device name you provided, then you should get a page of something out. If the output suffers from the ``staircase'' effect, you will see the numbers ``marching'' across the page, otherwise the numbers will all be in a single column.

## 3.2 Serial Printers

If your printer is attached by a serial line, then you may need to set the serial line characteristictics before sending the job to the printer. Here are a set of guidelines to following when attaching a serial port printer to a serial line.

1. Check to make sure that the line is not enabled for login. Logins are usually managed by the `getty` (BSD) or `ttymon` (Solaris, SystemV). Check your system documentation and make sure that these daemons are not managing the serial line.

2. Check the permissions and ownership of the serial line. For the most easy testing, set the permissions to 0666 (everybody can open for reading and writing). After you have made sure that you can send jobs to the printer, you might want to change the ownership of the serial line to the LPD server and change the permissions to 0600.

3. Make sure that you can print a test file on the printer via the serial port. This may require setting the line characteristictics and then sending a file to the printer. You should try to use 8 bit, no parity, with hardware flow control and no special character interpretation, and definitely no LF to CR/LF translation. The problem is that different versions of UNIX systems have different sets of stty(1) commands to do this. The following simple test script can help in this.

    #!/bin/sh
    # 9600, no echo, no CR
    FLAGS= 9600 -raw -parenb cs8 crtscts
    DEV= /dev/tty01
    (stty $FLAGS; stty 1>&2; cat $1 ) <$DEV >$DEV

This shows using stty to set the flags, then to print the current settings, and then using cat a file to the output. If you attach a dumb terminal to the serial port, you can even use this script to ensure that input from the device is echoed to the output with the correct speed, parity, etc.

### Converting BSD `fc,fs,xc,xs` To LPRng `sy`

Justin Mason `<jmason@iona.ie>` and Updated by Patrick Powell `<papowell@sdsu.edu>`:

One of the worst things about old LPDs is that they expected you to give it line characteristictics as octal numbers, using the fc,fs,xc,xs printcap parameters. There are a number of disadvantages to this, compared to using the `ty` parameter.

The sy format is portable, as it is supported on all UNIXes, rather than simply BSD-derived ones; it's also much easier to understand than the `fc,fs,xc,xs` format -- compare the two:

    # new format
        :sy=pass8 -parity tabs litout nl:
    # old format
        :fc#0000374:fs#0000003:xc#0:xs#0040040:

Note, also, that `sy` uses the same symbolic names as the `stty` command, which is (relatively) well documented.

Anyway, assuming you have a set of printcaps which use the `fc`,`fs`,`xc`,`xs` method, you can convert them to `sy` strings using the following table.

Each parameter is an octal number, composed by logical-or'ing the bits for the desired parameters together. The bit patterns below have been worked out from SunOS 4.1.2 /usr/include/sys/ttold.h. For example, the following fc,fs,xc,xs set:

    :fc#0000374:fs#0000003:xc#0:xs#0040040:

converts to the following sy string:

    :sy=-parity -echo -crmod -raw -lcase tandem cbreak litout decctq:

Quite often, the resulting strings seem a little complicated, but usually they can be broken down using combination modes. See the `printcap(5)` manual page for details of which combination modes LPRng supports.

In order to help you, the 'xlate' program can be used to translate from the old to the new form. For example:

    #> xlate ":fc#0000374:fs#0000003:xc#0:xs#0040040:"
    fc = 374
      clear LCASE (simulate lower case) try '-lcase'
      clear ECHO (echo input) try '-echo'
      clear CRMOD (map \r to \r\n on output) try '-crmod'
      clear RAW (no i/o processing) try '-raw'
      clear ODDP (get/send odd parity) try '-oddp'
      clear EVENP (get/send even parity) try '-evenp'
      clear ANYP (get any parity/send none) try '-parity? anyp? pass8? (caution)'
    fs = 3
      set TANDEM (send stopc on out q full) try 'tandem'
      set CBREAK (half-cooked mode) try 'cbreak'
    xc = 0
    xs = 40040
      set LITOUT (literal output) try 'litout'
      set DECCTQ (only ^Q starts after ^S) try 'decctlq'

Note that when you clear odd and even parity, then you get no parity or any parity. You should use -parity to be compatible. You might also want to add 'pass8' as well. Thus, using the xlate output, you would try:

       :sy=-lcase -echo -crmod -raw -parity pass8 tandem cbreak litout decctlq:

Bits used in the fc, fs parameters:

    TANDEM    00000001    /* send stopc on out q full */
    CBREAK    00000002    /* half-cooked mode */
    LCASE     00000004    /* simulate lower case */
    ECHO      00000010    /* echo input */
    CRMOD     00000020    /* map \r to \r\n on output */
    RAW       00000040    /* no i/o processing */
    ODDP      00000100    /* get/send odd parity */
    EVENP     00000200    /* get/send even parity */
    ANYP      00000300    /* get any parity/send none */
    NLDELAY   00001400    /* \n delay */
    NL0       00000000
    NL1       00000400    /* tty 37 */
    NL2       00001000    /* vt05 */
    NL3       00001400
    TBDELAY   00006000    /* horizontal tab delay */
      TAB0    00000000
      TAB1    00002000    /* tty 37 */
      TAB2    00004000
    XTABS     00006000    /* expand tabs on output */
    CRDELAY   00030000    /* \r delay */
        CR0   00000000
        CR1   00010000    /* tn 300 */
        CR2   00020000    /* tty 37 */
        CR3   00030000    /* concept 100 */
    VTDELAY   00040000    /* vertical tab delay */
        FF0   00000000
        FF1   00040000    /* tty 37 */
    BSDELAY   00100000    /* \b delay */
        BS0   00000000
        BS1   00100000
    ALLDELAY  00177400

Bits used in the xc, xs parameters:

    CRTBS     00000001    /* do backspacing for crt */
    PRTERA    00000002    /* \ ... / erase */
    CRTERA    00000004    /* " \b " to wipe out char */
    TILDE     00000010    /* hazeltine tilde kludge */
    MDMBUF    00000020    /* start/stop output on carrier intr */
    LITOUT    00000040    /* literal output */
    TOSTOP    00000100    /* SIGSTOP on background output */
    FLUSHO    00000200    /* flush output to terminal */
    NOHANG    00000400    /* no SIGHUP on carrier drop */
    CRTKIL    00002000    /* kill line with " \b " */
    PASS8     00004000    /* pass 8 bits */
    CTLECH    00010000    /* echo control chars as ^X */
    PENDIN    00020000    /* tp->t_rawq needs reread */
    DECCTQ    00040000    /* only ^Q starts after ^S */
    NOFLSH    00100000    /* no output flush on signal */

The following program translates the various bits to `stty` flags.

    #include <stdio.h>
    #include <string.h>
    struct bits{
      char *name;
      int bitfields;
      char *comment;
      char *try;
      int mask;
    };
    /* f flags - used with the TIOCGET and the struct sgttyb.sg_flags field */
    struct bits tiocget[] = {
    { "TANDEM",00000001, "send stopc on out q full", "tandem" },
    { "CBREAK",00000002, "half-cooked mode", "cbreak" },
    { "LCASE",00000004, "simulate lower case", "lcase" },
    { "ECHO",00000010, "echo input", "echo" },
    { "CRMOD",00000020, "map \\r to \\r\\n on output", "crmod" },
    { "RAW",00000040, "no i/o processing", "raw" },
    { "ODDP",00000100, "get/send odd parity", "oddp" },
    { "EVENP",00000200, "get/send even parity", "evenp" },
    { "ANYP",00000300, "get any parity/send none", "parity? anyp? pass8? (caution)" },
    { "NL0",0000000, "new line delay", "nl??",00001400 },
    { "NL1",00000400, "new line delay tty 37", "nl??",00001400  },
    { "NL2",00001000, "new line delay vt05", "nl??",00001400  },
    { "NL3",00001400, "new line delay", "nl??",00001400  },
    { "TAB0",00000000, "tab expansion delay", "tab??",00006000 },
    { "TAB1",00002000, "tab expansion delay tty 37", "tab??",00006000  },
    { "TAB2",00004000, "tab expansion delay", "tab??",00006000  },
    { "XTABS",00006000, "expand tabs on output", "tabs" },
    { "CR0",00000000, "cr??", "",00030000 },
    { "CR1",00010000, "tn 300", "cr??",00030000 },
    { "CR2",00020000, "tty 37", "cr??",00030000 },
    { "CR3",00030000, "concept 100", "cr??",00030000},
    { "FF1",00040000, "form feed delay tty 37", "ff??" },
    { "BS1",0010000, "backspace timing", "bs??" },
    { 0 } };
    /* x flags - used with the TIOCLGET and the struct sgttyb.sg_flags field */
    struct bits tiolget[] = {
    { "CRTBS",00000001, "do backspacing for crt", "crterase" },
    { "PRTERA",00000002, "\\ ... / erase", "prterase" },
    { "CRTERA",00000004, "\"\\b\" to wipe out char", "crterase" },
    { "TILDE",00000010, "hazeltine tilde kludge", "don't even think about this" },
    { "MDMBUF",00000020, "start/stop output on carrier intr", "crtscts" },
    { "LITOUT",00000040, "literal output", "litout" },
    { "TOSTOP",00000100, "SIGSTOP on background output", "tostop" },
    { "FLUSHO",00000200, "flush output to terminal", "noflsh?? (caution)" },
    { "NOHANG",00000400, "no SIGHUP on carrier drop", "nohand" },
    { "CRTKIL",00002000, "kill line with \"\\b\"", "crtkill" },
    { "PASS8",00004000, "pass 8 bits", "pass8" },
    { "CTLECH",00010000, "echo control chars as ^X", "echok" },
    { "PENDIN",00020000, "tp->t_rawq needs reread", "don't even think about this" },
    { "DECCTQ",00040000, "only ^Q starts after ^S", "decctlq? -ixany? (caution)" },
    { "NOFLSH",00100000, "no output flush on signal", "noflsh" },
    { 0 } };
    char *msg[] = {
     "xlate optionstrings",
     "  Example",
     "  xlate \":fc#0000374:fs#0000003:xc#0:xs#0040040:\"",
        0
    };
    usage()
    {
        char **m;
        for( m = msg; *m; ++m ){ fprintf( stderr, "%s\n", *m ); }
        exit( 1 );
    }
    main( argc, argv )
        int argc;
        char *argv[];
    {
        char *s, *end, *value;
        int c, v, set;
        struct bits *table;
        if( argc != 2 ) usage();
        for( s = argv[1]; s && *s; s = end ){
            end = strchr( s, ':' );
            if( end ){
                *end++ = 0;
            }
            while( (c = *s) && isspace( c ) ) ++s;
            if( c == 0 ) continue;
            /* now translate option */
            value = strchr( s, '#' );
            if( value == 0 ) usage();
            *value++ = 0;
            v = strtol( value, (char **)0, 0 );
            printf( "%s = %o\n", s, v);
            switch( s[0] ){
                case 'f': table = tiocget; break;
                case 'x': table = tiolget; break;
                default: usage();
            }
            switch( s[1] ){
                case 's': set = 1; break;
                case 'c': set = 0; break;
                default: usage();
            }
            /* now we scan down the values */
            for(; table->name; ++table ){
                if( (table->bitfields & v)
                    && ( ((table->bitfields & v) ^ table->bitfields)
                & (table->mask?table->mask:~0) ) == 0 ){
                    printf( "  %s %s (%s) try '%s%s'\n",
                        set?"set":"clear",
                        table->name, table->comment,
                        set? "":"-", table->try );
                }
            }
        }
    }

## 3.3 Network Printers

If you have a network printer, then you may have several options. First, your printer may have built-in LPD server support. However, this may not function as expected. It has been observed that most of these builtin servers do not correctly handle large jobs or jobs with complex PJL, PCL, or PostScript with binary information.

On the other hand, your printer may have a TCP/IP port that connects directly to the print engine. For example, on the HP JetDirect cards, sending a print file to port 9100 will cause the print engine to process and print it. In addition, this channel may provide status and other information during the printing process. You can use the netcat utility by Hobbit `<Hobbit@avian.org>` to send files directly to the printer. The simplest and easiest way to print a file to a network printer appears to be: `nc printer.ip.addr 9100 < file` .

Next Previous Contents