[comp.sources.amiga] tek4695 printer driver

ain@j.cc.purdue.edu (Patrick White) (01/10/88)

Program Name:	tek4695 printer driver
Submitted By:	Phil Staub <phils%tekig.tek.com@relay.cs.net>
Summary:	This is an updated tek4695 printer driver -- fixes some
		bugs and adds some new capabilities.
Poster Boy:  Pat White  (ain@j.cc.purdue.edu)
Untested.

NOTES:
   I didn't assemble this program, so it is untested.


-- Pat White   (co-moderator comp.sources/binaries.amiga)
UUCP: j.cc.purdue.edu!ain  BITNET: PATWHITE@PURCCVM   PHONE: (317) 743-8421
U.S.  Mail:  320 Brown St. apt. 406,    West Lafayette, IN 47906

========================================


Here are the sources for an updated version of a Tektronix 4695 printer
driver I wrote a while back. It fixes a few bugs and adds a few new
capabilities. 

One of the bugs it fixes sort of prompted one of the new features: It now
supports the set foreground and set background color escape sequences for
text printing. These escape sequences used to crash the machine.

Another bug fixed is that I had some reports of some programs guru'ing when
finishing up a graphic dump. This was apparently due to function #4 being
called in render() more than once without an intervening call on the
function which allocates the buffers (I think it's function 1). Since this 
function frees a couple of buffers, it's not nice to call the function 
multiple times.

Also, I re-arranged render() to minimize the overhead in plotting pixels,
since that happens *many* times. I'm not sure how much effect this has, but
at least it "feels" a little quicker.

Finally, I added support for underlined characters in text mode. This is
something which I don't think was there before, but I can't remember for
sure.

Enjoy
Phil

==============================

#!/bin/sh
# shar:    Shell Archiver
#	Run the following text with /bin/sh to create:
#	data.c
#	dospecial.c
#	include.asm
#	include.c
#	init.asm
#	macros.i
#	makefile
#	printertag.asm
#	render.c
#	wait.asm
# This archive created: Mon Dec 14 22:45:05 1987
cat << \SHAR_EOF > data.c
/* Tektronix 4695 command table */

/****** printer.device/printers/Tektronix_4695_functions ********************
 *
 *	Name
 *	Tektronix 4695 functions implemented:
 *
 *		aIND, aNEL,
 *		aSLPP,
 *		aTBC0, aTBC3, aTBCALL, aTBSALL
 *
 *		special functions implemented:
 *		aRIN, aSLRM, aSFC, aSBC
 *
 **************************************************************************/

char *CommandTable[] = {
	"\377",		 	/* reset 	RIS	*/
	"\377",			/* initialize 	RIN	*/
	"\012",			/* index	IND	*/
	"\015\012",		/* new line	NEL	*/
	"\377",			/* rev index	RI	*/
	"\021",			/* norm ch set  SGR0	*/
	"\377",			/* italics on	SGR3	*/
	"\377",			/* italics off	SGR23	*/
	"\022",			/* underline on	SGR4	*/
	"\021",			/* underlin off	SGR24	*/
	"\377",			/* bold on	SGR1	*/
	"\377",			/* bold off	SGR22	*/
	"\377",			/* set fore col	SFC	*/
	"\377",			/* set back col	SBC	*/
	"\377",			/* norm space	SHORP0	*/
	"\377",			/* elite on	SHORP2	*/
	"\377",			/* elite off	SHORP1	*/
	"\377",			/*  fine on	SHORP4	*/
	"\377",			/*  fine off	SHORP3	*/
	"\377",			/* enlarged on SHORP6	*/
	"\377",			/* enlarged off SHORP5	*/
	"\377",			/* shadow print on DEN6	*/
	"\377",			/* shadow print off DEN5	*/
	"\377",			/* double strike on DEN4	*/
	"\377",			/* double strike off DEN3	*/
	"\377",			/* NLQ on DEN2	*/
	"\377",			/* NLQ off DEN1	*/
	"\377",			/* superscript on SUS2	*/
	"\377",			/* superscript off SUS1	*/
	"\377",			/* subscript on SUS4	*/
	"\377",			/* subscript off SUS3	*/
	"\377",			/* normalize the line SUS0	*/
	"\377",			/* partial line up PLU	*/
	"\377",			/* partial line down PLD	*/
	"\377",			/* US Character Set FNT0	*/
	"\377",			/* French Character set FNT1	*/
	"\377",			/* German Character setFNT2	*/
	"\377",			/* UK character set FNT3	*/
	"\377",			/* Danish I character set FNT4	*/
	"\377",			/* Swedish character set FNT5	*/
	"\377",			/* Italian char set	FNT6	*/
	"\377",			/* Spanish char set	FNT7	*/
	"\377",			/* Jap char set		FNT8	*/
	"\377",			/* Norw char set	FNT9	*/
	"\377",			/* Danish II char set	FNT10	*/
	"\377",			/* Prop on		PROP2	*/
	"\377",			/* Prop off		PROP1	*/
	"\377",			/* prop clear		PROP0	*/
	"\377",			/* set prop offset	TSS	*/
	"\377",			/* auto left justify	JFY5	*/
	"\377",			/* auto right justify	JFY7	*/
	"\377",			/* auto full justify	JFY6	*/
	"\377",			/* auto justify off	JFY0	*/
	"\377",			/* letter space (justify) JFY3	*/
	"\377",			/* word fill (auto center) JFY1	*/
	"\377",			/* 8LPI			VERP0	*/
	"\377",			/* 6LPI			VERP1	*/
	"\377",			/* set lines/page	SLPP	*/
	"\377",			/* perf skip		PERF	*/
	"\377",			/* perf skip off	PERF0	*/
	"\377",			/* left margin set	LMS	*/
	"\377",			/* right margin set	RMS	*/
	"\377",			/* top margin set	TMS	*/
	"\377",			/* bottom margin set	BMS	*/
	"\377",			/* set t&b margin	STBM	*/
	"\377",			/* set l&r margin	SLRM	*/	
	"\377",			/* clear all margins	CAM	*/
	"\377",			/* horizontal tab set	HTS	*/
	"\377",			/* vertical tab set	VTS	*/
	"\377",			/* clear horiz tab	TBC0	*/
	"\0332",		/* clear all horiz tabs	TBC3	*/
	"\377",			/* clear vert tab	TBC1	*/
	"\377",			/* clear all vert tabs	TBC4	*/
	"\0332",		/* clear all tabs	TBCALL	*/
	"\377", 		/* set default tabs	TBSALL	*/
	"\377"			/* extended commands	EXTEND	*/
};
SHAR_EOF
cat << \SHAR_EOF > dospecial.c
/* Tektronix 4695 special printer functions */

/******* printer.device/printers/Tektronix_4695_special_functions **********
 *
 *	Name
 *	Tektronix 4695 special functions implemented:
 *
 *	aRIN, aSLRM, aSFC, aSBC
 *************************************************************************/

#include	<exec/types.h>
#include	<devices/printer.h>
#include	<devices/prtbase.h>
#include	<clib/macros.h>

extern struct PrinterData *PD;

long
DoSpecial(command,outputBuffer,vline,currentVMI,crlfFlag,Parms)
char *outputBuffer;
UWORD *command;
BYTE *vline;
UBYTE *currentVMI;
BYTE *crlfFlag;
UBYTE Parms[];
{
	static BYTE FGColorTable[] = 
		{'1','3','5','4','7','2','6','0','1','1'};
	static BYTE BGColorTable[] = 
		{'1','3','5','4','7','2','6','0','0','0'};

	extern UBYTE	TextColors;

	char	buf[80], shortbuf[3];

	buf[0] = shortbuf[2] = '\0';
	switch(*command) {

		case aRIN: {
			/* default text color */
			TextColors = 0x70;	/* white background, black text */
			strcat(buf,"\r\n");
		}	/* fall through to set default tabs */

		case aTBSALL: {
			Parms[0] = (PD->pd_Preferences.PrintLeftMargin);
			Parms[1] = (PD->pd_Preferences.PrintRightMargin);
			/* fall through to set the margins and default tabs */
		}

		case aSLRM: {
			/* actually sets both left and right margins and default tabs */
			/* default tabs are set every 8 columns */
			register int	LeftMargin = Parms[0];
			register int	RightMargin = 100 - Parms[1];
			register int	count;

			/* ensure that both margins are valid:
			 * 	odd numbers 
			 *	5 <= margin <= 95
			 *	(we assume that left margin is to left of right margin)
			 */
			LeftMargin  = MIN(95,(MAX(5,(LeftMargin  | 1))));
			RightMargin = MIN(95,(MAX(5,(RightMargin | 1))));

			/* Build the initialization string */
			strcat(buf,"\033W10\033H");

			/* put in the number of tabs */
			count = (Parms[1] - LeftMargin) / 8;
			shortbuf[0] = (count / 10) + '0';
			shortbuf[1] = (count % 10) + '0';
			strcat(buf,shortbuf);

			/* continue by putting in the left margin */
			shortbuf[0] = (LeftMargin / 10) + '0';
			shortbuf[1] = (LeftMargin % 10) + '0';
			strcat(buf,shortbuf);

			/* now insert tab specifications */
			while (count--)
				strcat(buf,"08");

			/* finally put in the right margin */
			shortbuf[0] = (RightMargin / 10) + '0';
			shortbuf[1] = (RightMargin % 10) + '0';
			strcat(buf,shortbuf);

			/* now copy into the output buffer and return the length */
			strcpy(outputBuffer,buf);
			return(strlen(buf));
		}

		case aSFC:
			if (Parms[0] < 40) 
				TextColors = ((TextColors)&240)+(Parms[0]-30);
			/* fall through to aSBC */

		case aSBC: {
			register char *p_out = outputBuffer;

			if (Parms[0] >= 40)
				TextColors = ((TextColors)&15)+((Parms[0]-40)*16);
			*p_out++ = '\033';
			*p_out++ = 'C';
			*p_out++ = FGColorTable[TextColors&15];
			*p_out   = BGColorTable[((TextColors&240)/16)];
			return(4);	/* we just stuffed 4 characters into the output
						 * buffer. now we return the length */
		}

		case aSLPP: {
			char	buf[5];
			int	len = (Parms[0]+5)/6;	/* len is in inches, 
										 * Parms is in lines */

			strcpy(buf,"\033L");
			buf[2] = (len / 10) + '0';
			buf[3] = (len % 10) + '0';
			strcpy(outputBuffer,buf);
			return(4);
		}

		case aRIS:
			PD->pd_PWaitEnabled = 253;
			break;

		default:	
			break;
	}
	return(0);
}

/*	turn this on to get a routine to print things to debugging terminal */
/*
db(num)
{
	kprintf("%ld\n",num);
	while (KGetChar() != '\r')
		;
}
*/
SHAR_EOF
cat << \SHAR_EOF > include.asm
;:ts=8
	far	code
	far	data
	public	.begin
	dseg
	end
SHAR_EOF
cat << \SHAR_EOF > include.c
#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/memory.h>
#include "devices/printer.h"
#include "devices/prtbase.h"
#include <functions.h>
SHAR_EOF
cat << \SHAR_EOF > init.asm
	far	code
	far	data
;
;	Excerpt from Amiga ROM Kernel Reference Manual: Libraries and 
;	Devices.  Used by permission, 1987, Phil Staub.
;
;**************************************************************************
;                                                                         *
;	Copyright 1985, Commodore-Amiga Inc. All rights reserved.         *
;	No part of this program may be reproduced, transmitted            *
;	transcribed, stored in retrieval system, or translated into       *
;	any language or computer language, in any form or by any means,   *
;	electronic, mechanical, magnetic, optical, chemical,              *
;	manual or ohterwise, without the prior written permission of      *
;	Commodore-Amiga Incorporated, 983 University Ave. Building #D,    *
;	Los Gatos, California, 95030                                      *
;                                                                         *
;**************************************************************************
	section	printer

;	included files

	include	"exec/types.i"
	include	"exec/nodes.i"
	include	"exec/lists.i"
	include	"exec/memory.i"
	include	"exec/ports.i"
	include	"exec/libraries.i"

	include	"macros.i"

;	imported functions

	XREF_EXE	CloseLibrary
	XREF_EXE	OpenLibrary
	XREF		_AbsExecBase

	XREF		_PEDData

;	exported globals

	XDEF	_Init
	XDEF	_Expunge
	XDEF	_Open
	XDEF	_Close
	XDEF	_PD
	XDEF	_PED
	XDEF	_SysBase
	XDEF	_DOSBase
	XDEF	_GfxBase
	XDEF	_IntuitionBase
	XDEF	_TextColors		; Added to avoid using currentVMI to hold color

;***********************************************
	section	printer,data
_PD		DC.L	0
_PED		DC.L	0
_SysBase	DC.L	0
_DOSBase	DC.L	0
_GfxBase	DC.L	0
_IntuitionBase	DC.L	0
_TextColors	DC.L	0		; Added to avoid using currentVMI to hold color
;***********************************************
	section	printer,code
_Init:
	move.l	4(a7),_PD
	lea	_PEDData(pc),a0
	move.l	a0,_PED
	move.l	a6,-(a7)
	move.l	_AbsExecBase,a6
	move.l	a6,_SysBase

;	open the dos library
	lea	DLName(pc),a1
	moveq	#0,d0
	CALLEXE	OpenLibrary
	move.l	d0,_DOSBase
	beq.l	initDLErr

;	open the graphics library
	lea	GLName(pc),a1
	moveq	#0,d0
	CALLEXE	OpenLibrary
	move.l	d0,_GfxBase
	beq.l	initGLErr

;	open the intuition library
	lea	ILName(pc),a1
	moveq	#0,d0
	CALLEXE	OpenLibrary
	move.l	d0,_IntuitionBase
	beq.l	initILErr

	move.b	#$70,_TextColors	; set default text color: black on white
	moveq	#0,d0

pdiRTS:
	move.l	(a7)+,a6
	rts

initPAErr:
	move.l	_IntuitionBase,a1
	LINKEXE	CloseLibrary

initILErr:
	move.l	_GfxBase,a1
	LINKEXE	CloseLibrary

initGLErr:
	move.l	_DOSBase,a1
	LINKEXE	CloseLibrary

initDLErr:
	moveq	#-1,d0
	bra.s	pdiRTS

ILName:
	dc.b	'intuition.library'
	dc.b	0
DLName:
	dc.b	'dos.library'
	dc.b	0
GLName:
	dc.b	'graphics.library'
	dc.b	0
	ds.w	0

;
_Expunge:
	move.l	_IntuitionBase,a1
	LINKEXE	CloseLibrary

	move.l	_GfxBase,a1
	LINKEXE	CloseLibrary

	move.l	_DOSBase,a1
	LINKEXE	CloseLibrary

_Open:
	moveq	#0,d0
	rts

_Close:
	moveq	#0,d0
	rts

	end
SHAR_EOF
cat << \SHAR_EOF > macros.i
;**************************************************************************
;	printer device macro definitions
;**************************************************************************

;	external definition macros

XREF_EXE	macro
	XREF		_LVO\1
		endm

XREF_DOS	macro
	XREF		_LVO\1
		endm

XREF_GFX	macro
	XREF		_LVO\1
		endm

XREF_ITU	macro
	XREF		_LVO\1
		endm

;	library dispatch macros

CALLEXE	macro
	CALLLIB	_LVO\1
		endm

LINKEXE	macro
	LINKLIB	_LVO\1,_SysBase
		endm

CALLDOS	macro
	LINKLIB	_LVO\1,_DOSBase
		endm

LINKGFX	macro
	LINKLIB	_LVO\1,_GfxBase
		endm

LINKITU	macro
	LINKLIB	_LVO\1,_IntuitionBase
		endm

SHAR_EOF
cat << \SHAR_EOF > makefile
OBJS = 	printertag.o init.o wait.o data.o dospecial.o render.o

CFLAGS = +P +Q +Iinclude.pre

all:	include.pre Tektronix_4695

Tektronix_4695:	$(OBJS)
	ln -o Tektronix_4695 $(OBJS) -lcl32

include.pre:	include.c
	cc -a +P +Q +Hinclude.pre include.c
SHAR_EOF
cat << \SHAR_EOF > printertag.asm
	far	code
	far	data
;
;	Excerpt from Amiga ROM Kernel Reference Manual: Libraries and 
;	Devices.  Used by permission, 1987, Phil Staub.
;
;**************************************************************************
;                                                                         *
;	Copyright 1985, Commodore-Amiga Inc. All rights reserved.         *
;	No part of this program may be reproduced, transmitted            *
;	transcribed, stored in retrieval system, or translated into       *
;	any language or computer language, in any form or by any means,   *
;	electronic, mechanical, magnetic, optical, chemical,              *
;	manual or ohterwise, without the prior written permission of      *
;	Commodore-Amiga Incorporated, 983 University Ave. Building #D,    *
;	Los Gatos, California, 95030                                      *
;                                                                         *
;**************************************************************************
	section	printer

	include	"exec/types.i"
	include	"exec/nodes.i"
	include	"exec/strings.i"
	include	"devices/prtbase.i"

	xref	_Init
	xref	_Expunge
	xref	_Open
	xref	_Close
	xref	_CommandTable
	xref	_DoSpecial
	xref	_Render

	xdef	_PEDData
	xdef	.begin
	xdef	_main

VERSION	EQU	31
REVISION	EQU	24
.begin:
_main:
	moveq	#0,d0
	rts
	dc.w	VERSION
	dc.w	REVISION
_PEDData:
	dc.l	printerName
	dc.l	_Init
	dc.l	_Expunge
	dc.l	_Open
	dc.l	_Close
	dc.b	PPC_COLORGFX
	dc.b	PCC_YMCB
	dc.b	80
	dc.b	1
	dc.w	4
	dc.l	1024
	dc.l	0
	dc.w	120
	dc.w	120
	dc.l	_CommandTable
	dc.l	_DoSpecial
	dc.l	_Render
	dc.l	60
	dc.l	0

printerName:
	dc.b	"Tektronix 4695"
	dc.b	0
	end
SHAR_EOF
cat << \SHAR_EOF > render.c
/**********************************************************************/
#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/memory.h>
#include "devices/printer.h"
#include "devices/prtbase.h"
#include <functions.h>

extern struct PrinterData *PD;

/* for the Tektronix 4695 */
long Render(ct,x,y,status)
register ULONG ct;	/* was UBYTE for Lattice compiler */
register ULONG x,y;	/* was UWORD for Lattice compiler */
ULONG status;	/* was UBYTE for Lattice compiler */
{
	static UWORD ROWSIZE;
	static UWORD COLORSIZE;
	static UWORD BUFSIZE;
	static UWORD colors[4];
	static BYTE huns,tens,ones;
	static UWORD bufptr;
	static UBYTE *initbuf;

	register struct PrinterData *pp = PD;
	register UBYTE *ptr;
	UWORD i;
	BYTE err; 

	/* placing pixels in the row buffers is a *very* time critical task.
	 * for this reason, we do this here, rather than in the switch below.
	 */
	if ((UBYTE)status == 1) 
	{	/* put pixel in buffer (called a max of 16384
		 * times per print cycle)
		 */
		register UWORD i;

		i = bufptr+(UWORD)x/8+((UWORD)y&3)*ROWSIZE+colors[(UBYTE)ct];
		PD->pd_PrintBuf[i] |= (1 << (7-((UWORD)x&7)));
		return(0);
	}

	switch((UBYTE)status) {

		/* each case in this switch exits via a "return", so 
		 * there is no "break"
		 */
		case 0:	/* alloc memory for printer buffer (uses dbl buf) */

			ROWSIZE = ((UWORD)x+7)/8;
			huns = ROWSIZE/100;
			tens = (ROWSIZE - huns*100)/10;
			ones = (ROWSIZE - huns*100 - tens*10);

			ROWSIZE += 6;	/* escape sequence overhead */
			COLORSIZE = ROWSIZE*4;	 /* one for each color */
			BUFSIZE = COLORSIZE*4+2; /* 4 colors + CR/LF */

			/* colors we get are swizzled from the way we 
			 *want them 
			 */
			colors[0] = 6;		/* start of color 0 */
			colors[1] = COLORSIZE*2+6; /* start of color 1 */
			colors[2] = COLORSIZE+6;   /* start of color 2 */
			colors[3] = COLORSIZE*3+6; /* start of color 3 */

			/* allocate a buffer which is used to init the 
			 * print buffers, then initialize it
			 */
			initbuf = (UBYTE *)
				AllocMem((long)BUFSIZE,(long)MEMF_PUBLIC);
			if(err = (initbuf==0)) 
				return(err);

			/* clear and init buffer */
			ptr = initbuf;
			for (i = 0; i < BUFSIZE; i++)
				*ptr++ = 0;
			for (i = 0; i < 16; i++) {
				ptr = &initbuf[i*ROWSIZE];
				*ptr++ = '\033';
				*ptr++ = 'I';
				*ptr++ = i+'0';
				*ptr++ = huns + '0';
				*ptr++ = tens + '0';
				*ptr++ = ones + '0';
			}
			initbuf[BUFSIZE-2] = '\033';
			initbuf[BUFSIZE-1] = 'A';

			/* try to allocate the print buffer */
			pp->pd_PrintBuf = (UBYTE *)
				AllocMem((long)BUFSIZE*2,(long)MEMF_PUBLIC);
			if(err = (pp->pd_PrintBuf==0)) 
				return(err);

			/* 1 second delay */
			if(err = PWait(1L,0L)) 
				return(err);

			/* set up for first buffer */
			bufptr = 0;
			return(0);

		case 2: /* dump buffer to printer */
			if (err = 
				(*(pp->pd_PWrite))(&pp->pd_PrintBuf[bufptr],
							(long)BUFSIZE))
				return (err);
			bufptr = BUFSIZE - bufptr;
			return(0);

		case 3: /* re-initialize a buffer */
			{ 
			register UBYTE *s, *d;
			register UWORD i;

			d = &pp->pd_PrintBuf[bufptr];
			s = initbuf;

			for (i = 0; i < BUFSIZE; i++)
				*d++ = *s++;

			return(0);
			}

		case 4:	/* free the print buffer memory */
			err = (*(pp->pd_PBothReady))();
			if (pp->pd_PrintBuf) {
				FreeMem(pp->pd_PrintBuf,(long)BUFSIZE*2L);
				pp->pd_PrintBuf = 0;
			}
			if (initbuf) {
				FreeMem(initbuf,(long)BUFSIZE);
				initbuf = 0;
			}
			return(err);

		default:
			return(0);
	}
}
SHAR_EOF
cat << \SHAR_EOF > wait.asm
	far	code
	far	data
	section printer
	include	'exec/types.i'
	include	'exec/ports.i'
	include	'exec/devices.i'
	include	'exec/io.i'
	include	'devices/timer.i'

XREF_EXE	MACRO
	XREF	_LVO\1
	ENDM
XREF_DOS	MACRO
	XREF	_LVO\1
	ENDM
XREF_GFX	MACRO
	XREF	_LVO\1
	ENDM
XREF_ITU	MACRO
	XREF	_LVO\1
	ENDM

CALLEXE	MACRO
	CALLLIB	_LVO\1
	ENDM

LINKEXE	MACRO
	LINKLIB	_LVO\1,_SysBase
	ENDM

LINKDOS	MACRO
	LINKLIB	_LVO\1,_DOSBase
	ENDM

LINKGFX	MACRO
	LINKLIB	_LVO\1,_GfxBase
	ENDM

LINKITU	MACRO
	LINKLIB	_LVO\1,_IntuitionBase
	ENDM

	INCLUDE	'devices/prtbase.i'
	XREF_EXE	Forbid
	XREF_EXE	Permit
	XREF_EXE	WaitIO
	XREF	_SysBase

	XREF	_PD

	XDEF	_PWait

_PWait:
	movem.l	a4/a6,-(a7)
	move.l	_PD,a4
	move.l	pd_PBothReady(a4),a0
	jsr	(a0)
	tst.l	d0
	bne.s	error

	lea	pd_TIOR(a4),a1
	move.w	#TR_ADDREQUEST,IO_COMMAND(a1)
	move.l	12(a7),IOTV_TIME+TV_SECS(a1)
	move.l	16(a7),IOTV_TIME+TV_MICRO(a1)
	clr.b	IO_FLAGS(a1)
	move.l	IO_DEVICE(a1),a6
	jsr	DEV_BEGINIO(a6)
	LINKEXE	Forbid
	lea	pd_TIOR(a4),a1
	LINKEXE	WaitIO
	LINKEXE	Permit
	moveq	#0,d0
	tst.l	d0
error:
	movem.l	(a7)+,a4/a6
	rts
	end
SHAR_EOF
#	End of shell archive
exit 0