Power Print

Products: Power Print
Developer(s): William McBrine
Date: 1988
Type: Program
Platform(s): TS 2068
Tags: Printer

Builds a custom 80-column printer driver that can run at any address you choose, and includes only the parts you ask for. It translates LLIST output properly, including the TS2068-only keywords, the © and £ characters, the block graphics and UDGs. The driver supports top, bottom and left margins, a set line length, correct TAB, AT and print-comma tab stops, and printing INVERSE, BRIGHT and FLASH text as emphasized, underlined and italic. Optional modules add large and small graphics screen dumps, a text-only screen dump and an interrupt-driven print spooler. The configuration program supports Aerco, A&J, Tasman-B and Tasman-C interfaces and saves the finished code.

The title screen reads “Printer Support Program by William J McBrine III, Copyright © 1988, McBrine Computer Products.” McBrine’s two-part manual is included as text, along with its notes and corrections and an LCODE table of Epson printer control codes.

Program Analysis

Program Structure

The BASIC configuration program works on the 3720-byte machine-code package loaded at 32768. It sets options by POKEing into the package, and the final driver is assembled by machine code. The main menu at line 3000 dispatches with a computed GO SUB:

  • 1. Backup Customization Program (line 200): saves PPRINT.B1 and pprint.C1, keeping any margin and character settings
  • 2. Produce Output File (lines 5–70, 100–150): asks for the start address, driver, spooler, interface and dump modules, then calls USR 32768 to relocate and link the chosen modules. It reports the start and length and saves the result from 36488 as outp.C1
  • 3. Set Margins, etc. (lines 300–430): translation on or off, control characters, UDG markers, margins, line length, dump margins and up to eight tab stops
  • 4. Customize Characters (lines 500–550): printer codes for ©, £, the UDG marker and the 16 block graphics
  • 5. Exit (STOP)

The output code runs only at the address it was built for. You load it there with LOAD ""CODE x and start it with RANDOMIZE USR x. RANDOMIZE USR x+2 or LPRINT CHR$ 5 switches back to the TS2040 driver. With the special control characters enabled, LPRINT CHR$ 1 and CHR$ 2 give the large and small graphics dumps, CHR$ 3 the text dump and CHR$ 4 a form feed. In the finished driver, POKE 23728 turns translation on and off, and POKE 23729 sets the control-character and UDG-marker flags.

Notable Techniques

  • Numeric inputs accept hexadecimal with a # prefix. The converter at line 1000 sets variables a to f to 10–15, so VAL of a single hex digit, letter or number, gives its value.
  • The spooler uses Z80 interrupt mode 2 with a 257-byte vector table on a 256-byte page boundary at or above 32768. It sends one character to the printer every 1/60 second while other programs run.
  • The dumps check the VIDMOD system variable for the video mode, so the large dump and the text dump also work in the 512-pixel, 64-column mode.
  • The text dump reads characters back from the display, including block graphics and UDGs, and LPRINTs them. This is much faster than a graphics dump.
  • Menu dispatch uses one Boolean-sum expression: GO SUB (5 AND a$="2")+(200 AND a$="1")+….

Potential Issues

  • As the notes and corrections say, driver 1 (printer-based) is no longer supported. Line 21 accepts only 2 or 3, though the menu still lists driver 1.
  • Nothing checks whether the driver, jump table and spooler buffer overlap. The manual warns that an overlap is disastrous.
  • The VERIFY steps the manual describes are REMmed out in this version (lines 65, 67, 210 and 220).
  • The hex converter reads only the first four digits.

This copy comes from a Larken disk in the TS User Group collection (disk l-36). It was converted for tape by removing the LKDOS RANDOMIZE USR 100, OPEN #4 and PRINT #4: prefixes from the loader and save lines, and was tested in ZEsarUX.

Related Products

The ultimate in support for your Epson-compatible printer with AERCO, Tasman or A&J parallel interface.

Image Gallery

Source Code

    1 PRINT '"                         '     :  :'''': :'''': :  : : :''': :''''   :'''': :'''' : :'''': :''' :   : :  : :  : : :'''' :     :  : :   : :   : :  :''''' '''''' ''''''' ''''' '     :''''' '   ' '   ' '''' "
    2 PRINT ''TAB 4;"Printer Support Program"'''TAB 14;"by"'''TAB 5;"William J McBrine III"'''TAB 7;"Copyright * 1988"'''TAB 3;"McBrine Computer Products"
    3 PAUSE 300: GO TO 3000
    5 CLS : LET h=0: PRINT TAB 5;" Produce Output File "
   10 PRINT '"Starting address? ";: GO SUB 900: LET add=num: POKE 32770,add-256*INT (add/256): POKE 32771,INT (add/256)
   20 PRINT '"Driver?     1. Printer-based"'TAB 12;"2. Computer-based"'TAB 12;"3. None"'TAB 11;"(screen dump(s) only)"
   21 LET a$=INKEY$: IF a$>"3" OR a$<"2" THEN GO TO 21
   22 LET drv=VAL a$: PRINT AT drv+3,12; OVER 1;"                 ";AT 7,0: POKE 32782,drv: IF drv=3 THEN POKE 32782,0
   24 PRINT '"Use spooler (y/n)? ";
   25 GO SUB 2000
   26 POKE 32784,0: IF a$="Y" OR a$="y" THEN POKE 32784,1: GO SUB 100: LET h=6
   27 PRINT '"Interface?  1. Aerco"'TAB 12;"2. A&J"'TAB 12;"3. Tasman-B"'TAB 12;"4. Tasman-C"
   28 LET a$=INKEY$: IF a$>"4" OR a$<"1" THEN GO TO 28
   29 LET int=VAL a$: PRINT AT int+h+10,12; OVER 1;"           ";AT h+14,0: POKE 32783,int-1
   30 PRINT '"Text dump (y/n)? ";
   31 GO SUB 2000
   32 POKE 32785,(a$="Y" OR a$="y")
   40 PRINT '"Graphics dump (y/n)? ";
   41 GO SUB 2000
   42 POKE 32786,(a$="Y" OR a$="y")
   49 REM do it
   50 LET len=USR 32768
   55 PRINT '"Start address: ";add'"Length of code: ";len''"OK to save (y/n)? ";
   56 GO SUB 2000
   60 IF a$="Y" OR a$="y" THEN PRINT #4: SAVE "outp.C1"CODE 36488,len
   65 REM PRINT '"Verify (y/n)? ";: GO SUB 2000
   67 REM IF a$="Y" OR a$="y" THEN PRINT : VERIFY "outp"CODE : PRINT '"Saved OK": PAUSE 60
   70 RETURN 
  100 PRINT '"Jump table address? ";
  105 GO SUB 901: LET tadd=num: IF tadd>=32768 THEN LET tadd=INT (tadd/256): GO TO 120
  110 IF tadd>255 OR tadd<128 THEN GO TO 105
  120 POKE 32777,tadd: PRINT tadd*256
  130 PRINT '"Buffer start address? ";: GO SUB 900: POKE 32778,num-256*INT (num/256): POKE 32779,INT (num/256)
  140 PRINT '"Buffer end address? ";: GO SUB 900: POKE 32780,num-256*INT (num/256): POKE 32781,INT (num/256)
  150 RETURN 
  200 CLS : PRINT "  Backup Customization Program "''"OK to save (y/n)? ";: GO SUB 2000: IF a$<>"Y" AND a$<>"y" THEN RETURN 
  210 PRINT #4: SAVE "PPRINT.B1" LINE 9999: PRINT #4: SAVE "pprint.C1"CODE 32768,3720: REM PRINT '"Verify (y/n)? ";: GO SUB 2000: IF a$<>"Y" AND a$<>"y" THEN RETURN 
  220 REM PRINT : VERIFY "PPRINT": VERIFY "pprintc"CODE : PRINT '"Saved OK": PAUSE 60
  230 RETURN 
  300 CLS : PRINT TAB 6;" Set Margins, etc. "
  310 PRINT '"Disable translation (y/n)? ";: GO SUB 2000: LET num=(a$="Y" OR a$="y")
  320 POKE 33150,num: POKE 34072,num
  330 PRINT '"Enable control chars. (y/n)? ";: GO SUB 2000: LET num=(a$="Y" OR a$="y")
  340 PRINT '"Disable UDG markers (y/n)? ";: GO SUB 2000: LET num=num+(2 AND (a$="Y" OR a$="y"))
  350 POKE 33155,num: POKE 34077,num
  360 PRINT '"Top margin? (0) ";: LET def=0: GO SUB 890: LET num=num+1: POKE 33632,num: POKE 34715,num
  370 PRINT '"Bottom margin? (0) ";: LET def=0: GO SUB 890: POKE 33635,num: POKE 34716,num
  380 PRINT '"Left margin? (0) ";: LET def=0: GO SUB 890: POKE 33638,num+1: POKE 34717,num+1
  390 LET lm=num: PRINT '"Line length? (";80-lm;") ";: LET def=80-lm: GO SUB 890: LET num=num+lm: POKE 33641,num: POKE 34718,num
  400 PRINT '"Left mar. for large dump? (8) ";: LET def=8: GO SUB 890: LET num=num+1: POKE 35979,num
  410 PRINT '"Lf. mar. for small dump? (40) ";: LET def=40: GO SUB 890: LET num=num+1: POKE 35978,num
  420 PRINT '"Define new tab stops (y/n)? ";: GO SUB 2000: IF a$<>"Y" AND a$<>"y" THEN RETURN 
  430 PRINT '"How many (max. 8)? ";: GO SUB 900: FOR x=1 TO num: GO SUB 900: POKE 33643+x,num: POKE 34718+x,num: NEXT x: POKE 33643+x,0: POKE 34718+x,0: RETURN 
  500 CLS : PRINT TAB 5;" Customize Characters "
  510 PRINT '"Code for ""*"" symbol? (64) ";: LET def=64: GO SUB 890: POKE 33526,num: POKE 34514,num
  520 PRINT '"Code for ""`"" symbol? (195) ";: LET def=195: GO SUB 890: POKE 33558,num: POKE 34555,num
  530 PRINT '"Mark for UDG's? (61) ";: LET def=61: GO SUB 890: POKE 33484,num: POKE 34472,num
  540 PRINT '"Redefine graph. chars. (y/n)? ";: GO SUB 2000: IF a$<>"Y" AND a$<>"y" THEN RETURN 
  550 FOR x=0 TO 15: PRINT 'CHR$ (128+x);" ";128+x,: GO SUB 900: POKE 33574+x,num: POKE 34674+x,num: NEXT x: RETURN 
  890 INPUT LINE a$: IF a$="" THEN LET num=def: PRINT num: RETURN 
  895 GO SUB 910: PRINT num: RETURN 
  900 GO SUB 901: PRINT num: RETURN 
  901 INPUT LINE a$: IF a$="" THEN GO TO 901
  910 IF a$(1)="#" THEN LET a$=a$(2 TO ): GO TO 1000
  920 LET num=VAL a$
  930 RETURN 
 1000 REM hex to dec
 1001 LET a=10: LET b=11: LET c=12: LET d=13: LET e=14: LET f=15
 1007 IF LEN a$<4 THEN FOR x=1 TO 4-LEN a$: LET a$="0"+a$: NEXT x
 1010 LET num=4096*VAL a$(1)+256*VAL a$(2)+16*VAL a$(3)+VAL a$(4)
 1020 RETURN 
 2000 LET a$=INKEY$: IF (a$<>"Y" AND a$<>"y") AND (a$<>"N" AND a$<>"n") THEN GO TO 2000
 2002 PRINT a$
 2005 IF INKEY$<>"" THEN GO TO 2005
 2010 RETURN 
 3000 CLS : PRINT TAB 10;" Main Menu "''"1. Backup Customization Program"''"2. Produce Output File"''"3. Set Margins, etc."''"4. Customize Characters"''"5. Exit this Program"
 3010 LET a$=INKEY$: IF a$>"5" OR a$<"1" THEN GO TO 3010
 3020 IF a$="5" THEN STOP 
 3030 GO SUB (5 AND a$="2")+(200 AND a$="1")+(300 AND a$="3")+(500 AND a$="4"): GO TO 3000
 9999 CLEAR 32767: RANDOMIZE USR 100: OPEN #4,"dd": PRINT #4: LOAD "pprint.C1"CODE : RUN

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.