Google
 

Trailing-Edge - PDP-10 Archives - decuslib10-12 - 43,50547/pltlib/sprout/ptc6.mac
There is 1 other file named ptc6.mac in the archive. Click here to see a list.
tITLE	PTC6 - Interface for PTC-6 Plotter Controller
SUBTTL	Joe Smith, 1983 at CSM

	SEARCH	MACTEN
	SALL

SPINCH:: ^D500			;Steps per inch, 400 or 500 (decimal)

;	Commands sent to the PTC-6 are formatted as follows:
;	!----------------------!-------------------!------------------!
;	!        HEADER        !     PLOT DATA     !      PROMPT      !
;	!----------------------!-------------------!------------------!
;	!<CRLF> # <Byte Count> !   Record/Record   !  Prompt/Inquire  !
;	!----------------------!-------------------!------------------!
;	!  2    1   2 Bytes    !   Max 510 Bytes   ! 1 Byte for ASCIZ !
;	!----------------------!-------------------!------------------!
;	!       1 Word         !     102 Words     !      1 Word      !
;	!----------------------!-------------------!------------------!
;
;CPS/6 - Command Structure Protocol for PTC-6
; @-H	Vector Magnitude Descriptor, see table at VCCLEN
;  I	Symbol Command, with Height, Aspect, T/S/O, Rotation, Count, Text
;  J	Symbol Command, using only Count and Text
;  K	Circle Command, 3 bytes of Radius follow
;  L	Arc Command, 3 bytes of Radius, 2 of Beginning Angle, 2 of End Angle
;  M	Hatch Command, Pattern, 2 bytes Spacing, Width, Height
;  N	Rectangle Command, 1 to 3 bytes Width, 1 to 3 bytes Height
;  P	Pen Up Command
;  Q	Pen Down Command
;  R	Select Pen, next byte is a digit from 1 to 4
;  X	Download Command, 1 byte Register Number, 2 bytes Data
;  Y	Negative Y Inhibit Command
;  Z	Set Maximum Speed Command, 1 byte Speed
;O,S,T,U,V,W are not used by controller, this routine uses @-H and P-R only

;By Joe Smith, with assistance from Todd Frauenhoff


;         Table of Contents for PTC-6 Plotter Controller
;
;
;			   Section			      Page
;
;    1. Definitions  . . . . . . . . . . . . . . . . . . . . .   2
;    2. PTCINI - Initialize plotter controller . . . . . . . .   3
;    3. PTCOUT - Output rest of buffer . . . . . . . . . . . .   4
;    4. PTCMOR - Finish a move longer than 40 inches . . . . .   5
;    5. PTCMOV - Convert moves to character string . . . . . .   5
;    6. PTCFIN - Finish up and deselect plotter controller . .   8
;    7. PTCPEN - Change to different pen . . . . . . . . . . .   8
;    8. Data Section . . . . . . . . . . . . . . . . . . . . .   9
SUBTTL	Definitions

;AC Definitions

	TF=0			;TRUE/FALSE
	S1=1			;Temp
	S2=2			;(not preserved)
	T1=3			;X coordinate
	T2=4			;Y coordinate
	T3=5			;Pen up/down code
	T4=6			;Unused
	J=14			;Base of job parameters
	P=17			;Stack Pointer

;Limit Definitions

	MAXDAT==^D510		;Absolute max number of data bytes
;Max X is 128K=16K*8; 8 long moves are 6 bytes each, +1 for VMD and +1 up/down
	ND BUFFUL,MAXDAT-<8*6>-2;Buffer is considerred full after 460 bytes

	%16K=^D<16*1024>	;Max offset in 15-1 bits
	%512=^D512		;Max offset in 10-1 bits
	%16=^D16		;Max offset in  5-1 bits

;Miscellaneous Definitions

	LF=12			;Linefeed - Command if "#" follows
	CR=15			;Carriage Return
	XON=21			;DC1 - Prompt code for PTC6

	$100=100		;64 decimal
	$40=40			;Offset to printing characters
SUBTTL	PTCINI - Initialize plotter controller

;Routine to initialize plotter controller
;Call:	MOVEI	T1,^D<+45>	;Number of step-times to raise/lower pen
;	PUSHJ	P,PTCINI##	;(T1 negative to use XON/XOFF flow control)
;	OUTSTR	(T1)		;Output init string to TTY
;	PUSHJ	WAIT		;Wait for controller to send a CR

PTCINI::MOVMM	T1,UPINCS(J)	;Time to raise/lower pen
	SKIPGE	T1		;Positive means use CR
	 SKIPA	T1,[INIXON]	;Negative means use XON
	  MOVEI	T1,INICR	;Use CR as handshake
	JRST	UNBUF1		;Reset variables and return T1 nonzero

	;"P" raises pens, "R1" selects #1, controller sends "0C<CR>" when ready
INICR:	BYTE (7) CR,LF,";","#",CR,LF,"#",$40+0,$40+3,"P","R","1",XON,0

	;"X501" sets register 5 to 01 to use XON/XOFF handshaking
INIXON:	BYTE (7) CR,LF,";","#",CR,LF,"#",$40+0,$40+7,"P"
	BYTE (7) "R","1","X","5","0","1",XON,0
SUBTTL	PTCOUT - Output rest of buffer

;Routine to dump internal buffer
;Call:	PUSHJ	P,PTCOUT##
;	OUTSTR	(T1)		;Output last buffer to TTY
;	PUSHJ	WAIT		;Wait for controller to send a CR (time in S1)

PTCOUT::MOVEI	S1,"P"		;Get pen-up command
	PUSHJ	P,OUTBYT	;Send it and fall into UNBUF

;Return pointer to completed string (called if zero in T3 or buffer full)

UNBUF:	SKIPN	T1,BYTCNT(J)	;Get byte count if any
	 POPJ	P,		;Nothing there, return zero in T1
	MOVE	S1,[BYTE(7)CR,LF,"#",$40,$40]
	MOVEM	S1,HEADER(J)	;Start of block, number of bytes
	IDIVI	T1,$100		;Separate into 6-bit fields
	ADDI	T1,$40		;High order
	DPB	T1,[POINT 7,HEADER(J),27]
	ADDI	T2,$40		;Low order
	DPB	T2,[POINT 7,HEADER(J),34]

	MOVEI	S1,XON		;Prompt code
	IDPB	S1,PNTR(J)
	MOVEI	S1,0		;End with null byte
	IDPB	S1,PNTR(J)	; for ASCIZ
	MOVEI	T1,HEADER(J)	;Return T1 nonzero as signal to dump buffer

UNBUF1:	SETZM	OLDVMD(J)	;Make no assumptions about previous commands
	SETZM	OLDPEN(J)	; ...
	MOVE	S1,[POINT 7,PLDATA(J)]
	MOVEM	S1,PNTR(J)	;Reset to start
	SETZB	S1,BYTCNT(J)	; ...
	EXCH	S1,INCS+0(J)	;Clear counter
	EXCH	S1,INCS+1(J)	;Move previous count down
	EXCH	S1,INCS+2(J)
	EXCH	S1,INCS+3(J)
	ADD	S1,INCS+3(J)	;Accumulate total incs for last 4 buffers
	ADD	S1,INCS+2(J)
	ADD	S1,INCS+1(J)	;Return count in S1
	POPJ	P,		; and addr in T1
SUBTTL	PTCMOV -- Check pen up/down status before moving

;Call:	MOVE	T1,<delta-X>
;	MOVE	T2,<delta-Y>
;	MOVEI	T3,2  (or MOVEI T3,3)
;	PUSHJ	P,PTCMOV##	;Convert to PTC-6 commands
;	JUMPE	T1,CPOPJ	;Done unless PTCMOV returned data
;	OUTSTR	(T1)		;Send output to terminal
;	PUSHJ	P,WAIT		;Wait for controller to send a CR (time in S1)

;Set pen up/down condition -- 1 = Same, 2 = Lower, 3 = Raise pen

PTCMOV::SKIPLE	T3		;Reset if zero or negative,
	CAILE	T3,3		; or out of range positive,
	 PJRST	PTCOUT		; raise pen and dump buffer (ignoring T1 & T2)

	SKIPN	S1,PENCOM-1(T3)	;Get pen up or pen down command
	 MOVE	S1,OLDPEN(J)	;Use previous status if T3 contains 1
	CAMN	S1,OLDPEN(J)	;If new position is the same,
	 JRST	MOVE1		; don't change it

	MOVEM	S1,OLDPEN(J)	;Set new status
	PUSHJ	P,OUTBYT	;Tell the controller
	MOVE	S1,UPINCS(J)	;Time required to raise/lower pen
	ADDM	S1,INCS+0(J)

MOVE1:	SKIPN	T1		;If no delta movement,
	 JUMPE	T2,MOVE9	; just return

;Convert movements from 400 steps per inch to 500 steps per inch
;T1 has X, T2 has Y, T3 is scratch
;Note that if SPINCH contains ^D400, this routine is a long no-op (trashes T3)

KLUDGE::PUSH	P,T2		;Save because of IDIVI
	IMUL	T1,SPINCH	;Multiply by 500
	ADD	T1,REM.X(J)	;(with rounding)
	IDIVI	T1,^D400	;Divide by 400 (ratio of 500/400)
	MOVEM	T2,REM.X(J)	;Save remainder for rounding next time
	POP	P,T2
	IMUL	T2,SPINCH	;Actual Steps Per INCH
	ADD	T2,REM.Y(J)
	IDIVI	T2,^D400
	MOVEM	T3,REM.Y(J)
				;Continue at BIGCHK
SUBTTL	PTCMOV -- Split giant moves into smaller ones

;Check to see if X and Y increments within limits

BIGCHK:	DMOVEM	T1,OLD.X(J)	;Save original X and Y

	MOVM	S1,T1		;Get abs(X)
	MOVM	S2,T2		;Get abs(Y)
	CAMGE	S1,S2		;Put larger in S1
	 MOVE	S1,S2
	MOVE	T3,S1		;Number of increments that will be in buffer

;Any vector more than 40 (32) inches long has to be split into 2 or more moves.

	IDIVI	S1,%16K		;Determine how many times over
	JUMPE	S1,MOVEOK	;Go plot if T1 and T2 now within range
;If S1=2 then vector must be split into 3 pieces
	ADDI	S1,1		;Round up (assume 3 in S1 in the comments below)
	IDIV	T1,S1		;Split X (wipes out T2)
	MOVE	T2,OLD.Y(J)	;Restore Y
	IDIV	T2,S1		;Split Y (wipes out T3)
	MOVN	S1,T1		;Get negative 1/3 of distance
	MOVN	S2,T2
	ADDM	S1,OLD.X(J)	;2/3 left to go
	ADDM	S2,OLD.Y(J)

;Update INCS so that SPROUT can be told to expect a long delay

	MOVM	S1,T1		;Get abs of the new X and Y
	MOVM	S2,T2
	CAMGE	S1,S2		;Put larger in T3
	 MOVE	S1,S2
	ADDM	S1,INCS(J)	;For elapsed time calculations

	PUSHJ	P,XY2STG	;Do part of vector from T1 & T2
	DMOVE	T1,OLD.X(J)
	JRST	BIGCHK		;Do rest of movement

;T1 and T2 have delta-X and delta-Y, which are less than 16K increments each

MOVEOK:	ADDM	T3,INCS(J)	;Predict elapsed time
	PUSHJ	P,XY2STG	;Convert to character string

;Check if it is time to dump the buffer

MOVE9:	MOVE	S1,BYTCNT(J)	;Get the byte count
	CAIL	S1,BUFFUL	;Almost full?
	 PJRST	UNBUF		;Yes, return addr of string in T1
	SETZB	S1,T1		;No, return with zero in T1
	POPJ	P,
SUBTTL	PTCMOV -- Convert (X,Y) to ASCII string

;Find out number of bytes needed to represent X increments

XY2STG:	MOVEI	S1,"@"		;Assume 1 byte needed to output X
	CAXL	T1,-%16		;If more than 4 bits
	CAXLE	T1,%16-1
	 MOVEI	S1,"C"		;Use 2 bytes
	CAXL	T1,-%512	;If more than 9 bits
	CAXLE	T1,%512-1
	 MOVEI	S1,"F"		;Use 3 bytes

;Find out number of bytes needed to represent Y increments

	CAXL	T2,-%16		;If more than 4 bits
	CAXLE	T2,%16-1
	 ADDI	S1,1		;Use 2 bytes
	CAXL	T2,-%512	;If more than 9 bits
	CAXLE	T2,%512-1
	 ADDI	S1,1		;Use 3 bytes

	CAME	S1,OLDVMD(J)	;Same as previous?
	 PUSHJ	P,OUTBYT	;No, send VMD (Vector Magnitude Descriptor)
	MOVEM	S1,OLDVMD(J)

;Change X and Y increments into ASCII characters for plot controller.

	HLRZ	T3,VCCLEN-"@"(S1);Number of characters to make X incs into vector string
	PUSHJ	P,OUTCOR	;Make X coordinate
	MOVE	T1,T2		;Get Y coordinate
	MOVE	S1,OLDVMD(J)	;Reset S1
	HRRZ	T3,VCCLEN-"@"(S1);Number of characters to make Y incs into vector string
				;Fall into OUTCOR and return

;Routine to translate coordinate change to characters
;Call with bit pattern in T1, number of bytes in T3

OUTCOR:	MOVE S2,[POINT 5,T1,30	;1 byte
		 POINT 5,T1,25	;2 bytes
		 POINT 5,T1,20]-1(T3);3 bytes

OUTC1:	ILDB	S1,S2		;Get 5 bits
	ADDI	S1,$40		;Make printing
	PUSHJ	P,OUTBYT	;Send it
	SOJG	T3,OUTC1	;Do all
	POPJ	P,


;Routine to output a byte in S1 and count it

OUTBYT:	IDPB	S1,PNTR(J)	;Save the character
	AOS	BYTCNT(J)	;Count it
	POPJ	P,		;Return
SUBTTL	PTCFIN - Finish up and deselect plotter controller

;Routine to release plotter controller
;Call:	PUSHJ	P,PTCFIN##
;	OUTSTR	(T1)		;Output end string to TTY

PTCFIN::MOVEI	T1,DESLCT	;Deselect plotter controller
	POPJ	P,		;Return with addr in T1

DESLCT:	ASCIZ /
#  (PTC-6 deselected)
/				;LF,"#",$40,$40 does it, rest is comment





SUBTTL	PTCPEN - Change to different pen

;Routine to change pens, call with number from 1 to 3 in S2

PTCPEN::MOVEI	S1,"R"		;Change pens
	PUSHJ	P,OUTBYT
	MOVEI	S1,"0"(S2)	;Pen number
	PJRST	OUTBYT

;This assumes that a call to PLTMOV will be made before the 510 byte limit
SUBTTL	Data Section

;Constants

PENCOM:	EXP	0,"Q","P"	;1 = No change, 2 = lower pen, 3 = raise pen

;Bytes needed for X and Y ranges

VCCLEN:	XWD	1,1	;     -16 <= X <=    15         15 => Y =>    -16
	XWD	1,2	;     -16 <= X <=    15        511 => Y =>   -512
	XWD	1,3	;     -16 <= X <=    15      16383 => Y => -16384
	XWD	2,1	;    -512 <= X <=   511         15 => Y =>    -16
	XWD	2,2	;    -512 <= X <=   511        511 => Y =>   -512
	XWD	2,3	;    -512 <= X <=   511      16383 => Y => -16384
	XWD	3,1	;  -16384 <= X <= 16383         15 => Y =>    -16
	XWD	3,2	;  -16384 <= X <= 16383        511 => Y =>   -512
	XWD	3,3	;  -16384 <= X <= 16383      16383 => Y => -16384

;Variables

IFG <BUFFUL-^D510>,<PRINTX ?PTC-6 cannot handle more than 510 bytes>
	DATSIZ==<MAXDAT/5>+1

	EXTERN	PTC6BF,J$$END	;For .ASSIGN

DEFINE LP(NAME,SIZE),<	NAME=PTC6BF+<..=J$$.>
			J$$.==J$$.+SIZE
			..==..>

	J$$.==0
	LP	PNTR,	1	;Byte pointer into PLDATA
	LP	BYTCNT,	1	;Count of characters in array
	LP	OLDPEN,	1	;Last pen up/down command sent
	LP	OLDVMD,	1	;Last Vector Magnitude Descriptor
	LP	OLD.X,	2	;For doing long vectors
		OLD.Y=OLD.X+1
	LP	UPINCS,	1	;Number of increments to raise/lower pen
	LP	INCS,	4	;Accumulated increments for 4 buffers
	LP	REM.X,	1	;Kludge for 500 vs 400 increments
	LP	REM.Y,	1
	LP	HEADER,	1	;Header block, must be at PLDATA-1
	LP	PLDATA,	DATSIZ	;Buffer where data is stored
	..==J$$.

	.ASSIGN	PTC6BF,J$$END,J$$.	;PTC6BF=J$$END, J$$END=J$$END+J$$.
	PTC6..=:J$$END-1	;Last data loc used by this routine
	PURGE	..

LITS:	END