;From: andrew.mcmeikan at mitswa.com.au

                ;be carefull when assembling
                ;there is a lookup table that MUST NOT cross a
                ;256 byte boundry ---- CHECK IT

                LIST      P=16C84, F=INHX8M
                ;thermal printer controler
innerloop = 0ff
lilloop = 01
bigloop =0ff


strobe          macro   bt
	SETB	$13.bt	;bit for strobe
	CLRB	0b.7	;dont want interupts
	CALL	outsr	;clock it out
	CALL	lildly	;let it burn in
	SETB	0b.7	;re-enable interupts
	CLRB	$13.bt	;so next outsr clears it
                endm


	ORG	$0000

	JMP	main

	ORG	$0004
                ;entry occurs in here when host pulls strobe signal low
                ;to indicate data that requires printing
                ;useing this int routine occupies two levels of stack
                ;one for the return address and one for outsr's return
                ;centronics pinouts
                ; pin 1 strobe is connected to  RB0
                ; pin 2 data1   "       "       RA1
                ; pin 3 data2   "       "       RA2
                ; pin 4 data3   "       "       RA3
                ; pin 5 data4   "       "       RA4
                ; pin 6 data5   "       "       RB1
                ; pin 7 data6   "       "       RB2
                ; pin 8 data7   "       "       RB3
                ; pin 9 data8   "       "       RB4
                ; pin10 ack     "       "       Cap from BSY this dips low
                ;                                       when want next byte
                ; pin11 busy   is connected to  RA0  High= offline
                ; pin12 Paper out is connected to photocell High=no paper
                ;pins 19 to 30 are signal grounds GND
                ; pin31 INT    is connected to RESET (via diode)
                ;                       and is used to initialize printer


	MOV	0c, W	;save 'W' in reg file 0c
	MOV	W, <>3	;grab the flags
	MOV	0d, W	;in reg 'd'
                                        ;should now be safe to continue!
	SETB	5.0	;say we are busy


                ;read both ports to get byte of data
	MOV	W, >>5	;read port a shifting data down one
	AND	W, #0f	;only keep bottom bits
	MOV	$16, W	;keep incomming data here
	MOV	W, >>6	;read port b shifting down one
	AND	W, #0f	;wipe out extraneous bits
	MOV	$17, W	;waste another register
	MOV	W, <>$17	;get 'b' data lower into upper W
	OR	$16, W	;or top bits into data
                ;bit pattern from host now in 0x16

	INC	0e	;increment our count of bytes

                ;clock data into thermal head
	MOV	W, #08	;for 8 bits
	MOV	$17, W	;better keep count of it
clkhd:	RL	$16	;rotate it thru carry
	SETB	$12.4	;set data high
	SB	3.0	;check the carry flag
	CLRB	$12.4	;clear data if required
	CALL	outsr
	SETB	$12.5	;clock that bit in
	CALL	outsr
	CLRB	$12.5	;drop clock again
	CALL	outsr
	DECSZ	$17	;have we finished loop yet ?
	JMP	clkhd	;guess not
                ;no point doing the extra shift as we are just
                ;throwing the data away once it is in the head


                ;if byte count=max then lets latch and let the main routine
                ;                                         print it
	MOV	W, #$c0	;try 192           ;216 max bytes per line 1728 bits
	MOV	W, 0e-w	;check max against our byte count
	SB	3.2	;the same? result of zero?
	JMP	continue	;no its ok, head not full yet

                ;need to latch thermal head
                ; We do not not lower busy here
                ;as main routine will do so once it has reset
                ;the counter.

	SETB	$12.6	;latch bit for thermal head
	CALL	outsr	;send- no one else better be using it
	CLRB	$12.6	;put back
	CALL	outsr	;send that to

	JMP	exint	;leave int handler

continue:       ;tell host we are no longer busy, get next byte
	CLRB	5.0	;bring BSY low
                ;and fall thru to exit :)
exint:                                  ;now restore to before interupt
	MOV	W, <>0d	;put flags back in order in W
	MOV	3, W	;stickem bick in flags
	SWAP	0c	;flip saved W
	MOV	W, <>0c	;flip it back into W
	CLRB	0b.1	;clear INTF flag so we can get more
;*** WARNING: SX saves/restores W, STATUS, and FSR automatically.
;                RETFIE
	RETI



main            ;thermal printer control program 192 dpi 9 inch 1728 pixels
                ;need to set up direction bits for ports
                ;and set initial pin levels

	MOV	W, #0	;pullups and interrupt on neg edge
	MOV	!OPTION, W	;set options
	MOV	W, #0ff
	TEST	5	;set all pins high on port a
	MOV	W, #0fe	;RA0 as output
;*** WARNING: TRIS expanded in two instructions. Check if previous instruction is a skip instruction.
;                tris    5               ;porta as input except RA0
	;porta as input except RA0
	MOV	W, #01f	;make bits 6,7 &5 low
	TEST	6
	MOV	W, #01f	;port b 5,6,7 as output
;*** WARNING: TRIS expanded in two instructions. Check if previous instruction is a skip instruction.
;                tris    6               ;make it so !
	;make it so !
	MOV	W, #08	;specify which phase to start on
	MOV	$15, W	;store it somewhere safe
	CLR	0e	;zero byte count for head
	MOV	W, #00	;phases off clk,lat,data, strb off
	MOV	$12, W	;data for shift reg 1
	MOV	W, #00	;all strobes off (low)
	MOV	$13, W	;data for shift reg 2
	CALL	outsr	;set all pins high except for stepper
	MOV	W, #$90	;enable RB0 and GIE interupt bits
	MOV	0b, W	;interupts now turned on!
	CLRB	5.0	;say we are not busy
p1=8;9 ;1
p2=4;8 ;3         ;ok here are definitions of how the shift registers are wired
p3=2;0c;2         ; ok on 0x12    bit0    stepper phase A
p4=1;4 ;6         ;               bit1    "       "     B
p5=8;6 ;4         ;               bit2    "       "     C
p6=4;2 ;0c        ;               bit3    "       "     D
p7=2;3 ;8         ;               bit4    Data for thermal head
p8=1;1 ;9         ;               bit5    Clock for thermal Head
                ;               bit6    Latch for thermal head
                ;               bit7    strobe 1 for thermal head

                ;       0x13    bit0 to bit7 rest of strobes for head


mloop:          ;this is the loopy bit of main
                ;we sit in here till we get a full head
                ;then we reset the counter, send an ack to the host
                ;print the line out and advance the paper, then we sit until
                ;the head is full again :)
                                        ;first check if the head is full
	MOV	W, #$c0	;try 192            ;216 max bytes per line 1728 bits
	MOV	W, 0e-w	;check max against our byte count
	SB	3.2	;the same? result of zero?
	JMP	mloop	;no not yet keep waiting
	CLR	0e	;Ok we've spotted the head full


                ;need to strobe head drivers
	SETB	$12.7	;strb1
	CLRB	$b.7	;turn off interupts
	CALL	outsr	;Fire!
	CALL	lildly	;let it burn!
	SETB	0b.7	;re-enable interupts
	CLRB	$12.7	;ok thats done

                strobe 0
                strobe 1
                strobe 2
                strobe 3
                strobe 4
                strobe 5
                strobe 6
                strobe 7

	CLRB	0b.7	;turn off interupts
	CALL	outsr	;yay! all strobes Fired!
	CLRB	5.0	;ok we aren't busy any more
	SETB	0b.7	;re-enable interupts

	CALL	papadv	;move paper on to next line
	JMP	mloop	;lets go back and see if another
                                        ;line is ready yet

phlook:         ;this routine looks up the value for a particular phase
                ;important that this lookup resides within a 256 byte block
                ;as PCL is directly modified.  if called with value grater
                ;than 8 ,will cause who knows what kind of crash!
	ADD	02, W	;ok now its going to jump :)
	NOP	;err dont expect zero ?!?!
	RETW	#p8	;return with phase 8
	RETW	#p7	;coz we are counting down
	RETW	#p6	;remember... see next routine!
	RETW	#p5
	RETW	#p4
	RETW	#p3
	RETW	#p2
	RETW	#p1
	SLEEP	;coz its all gone wrong if it
                                        ;gets here or past!
                                        ;check the listing to be sure
                                        ;it fits between page boundries!

papadv:         ;this routine is to activate a paper advance one step
                ;it will use register #15 to keep track of which
                ;point in the phase cycle it is
	MOV	W, #0f0	;prep mask
	CLRB	0b.7	;diable interupts
	AND	$12, W	;nock off bottom bits
	MOV	W, $15	;grab our phase number into W
	CALL	phlook
	OR	$12, W	;new pattern now set
	SETB	0b.7	;ints re-enabled
	DEC	$15	;get next phase number
	SNB	3.2	;did we hit zero?
	JMP	recount	;yep need to reload the counter
	CLRB	0b.7	;turn off interupts coz of (outsr)
	CALL	outsr	;jump to out put new phase
	SETB	0b.7	;turn on interupts again
	RET	;and go back
recount:	MOV	W, #08	;we hit zero reset it back to 8
	MOV	$15, W	;use it next time round
	CLRB	0b.7	;clear interupt enable
	CALL	outsr	;I know its just below us
	SETB	0b.7	;but tis only way to keep
	RET	;the interupts rightly enabled

outsr:          ;this routine takes bytes at 0x12 and 0x13
                ;and clocks them out onto the shift registers
                ;shift registers accessed on port b bits 5,6 & 7
                ;bit 6 as clock - clocks data on POSITIVE edge
                ;bit 7 as data  - non inverted
                ;bit 5 as strobe - latches data on NEGATIVE edge
                ; we are sending lsb first ie bit# 1 on shift register
                ; output pin #8
                ; sending byte at address 0x12 first then 0x13
                ; this puts 0x12 on the last shift register in line
                ;uses reg # 14 to keep count of bits

                ;since this code is NON-RE-ENTERENT, do NOT call it
                ;while interupts are enabled, coz the int handler
                ;calls this routine to access the thermal head.

	MOV	W, #08	;for 8 bits
	MOV	$14, W	;better keep count of it
shiftbits:	RR	$12	;rotate it thru carry
	SETB	6.7	;set data high
	SB	3.0	;check the carry flag
	CLRB	6.7	;clear data if required
	SETB	6.6	;clock that bit in
	CLRB	6.6	;drop clock again
	DECSZ	$14	;have we finished loop yet ?
	JMP	shiftbits	;guess not
	RR	$12	;preserve the data, shift the carry
                        ;now we have finished one byte lets do the other
	MOV	W, #08	;for 8 bits
	MOV	$14, W	;better keep count of it
shiftbitsagain:	RR	$13	;rotate it thru carry
	SETB	6.7	;set data high
	SB	3.0	;check the carry flag
	CLRB	6.7	;clear data if required
	SETB	6.6	;clock that bit in
	CLRB	6.6	;drop clock again
	DECSZ	$14	;have we finished loop yet ?
	JMP	shiftbitsagain	;guess not
	RR	$13	;preserve the data, shift the carry
                        ;now we have really finished clocking bits
	SETB	6.5	;bring up the strobe line
	CLRB	6.5	;and LATCH it
	RET	;back to where ever.


lildly	MOV	W, #lilloop
	MOV	$11, W
	JMP	reload
bigdly	MOV	W, #bigloop
	MOV	$11, W
reload	MOV	W, #innerloop
	MOV	$10, W
inloop	NOP
	DECSZ	$10
	JMP	inloop
	DECSZ	$11
	JMP	reload
	RET



	ORG	$2000
                DATA    00
                DATA    00
                DATA    00
                DATA    00


	ORG	$2007
                DATA    0x19            ;fuse settings

	ORG	$2100
                ;data    00
                ;data    00
                ;data    00

                END