;
;************************************************************************
; 1227747 ECU 160 Baud ALDL display / Juha Niinikoski
; Test code put together 11.9.2000 
; First working code 12.9.2000 v0.01
; BLM Cell resolver & temperature conversion 13.9.2000 v0.02
; O2 mV, MAP Kpa & TPs % conversion added 14.9.2000
; PA3 display, knock warning & some bit indicators added 15.9.2000
; VFD / LCD routine clean up & display format 26.9.2000 v1.00
; Page & normal/diag switches. Diag display. 27.9.2000 v1.01
; Display shows Wait until ALDL data is present. 29.3.2001 v1.02
; Tested with 808 ECU. 808 needs more delay after clear screen. Additional
; delay makes display flicker. New display consept without clear
; screen commands. Assembly switch for knock warning 1.4.2001 v 1.10
; assembly radix switch & false sync corrected 20.05.2002 v 1.11
; P/N, Rich/Lean & low Bat  display added 05.06.2002 v 1.12
; PROM ID display at startup 05.07.2002 v 1.13
;
; Test to convert code for 2k 16F628 part 25.07.2002 v 2.00
; For correct PORTA operation CMCON register needs to be set. RAM origin changed.
; Label SYNC changed to ASYNC to avoid conflict with 628 predefined labels.
; __config changed for 16F628.
; Messages moved to RAM page 0x600. 0x700 reserved for additional messages.
; POINT6 & POINT7 Macros changed. Program memory from 0x300 to 0x5ff available for
; additional code.
; Error code logic added 26.07.2002
; Display page select push button logic 28.07.2002 v2.01
; ALDL receiver switched to TMR1. Watchdog enabled 07.08.2002 v2.02
; Yet another ALDL sync problem corrected 07.08.2002
; Added spark advance display. Require modified 747 data stream 13.05.2003 
;
;************************************************************************
;
	LIST    	P = 16F628,  R = HEX
;
	INCLUDE		"p16f628.inc"
;
	__config	_xt_osc & _wdt_on & _cp_off & _pwrte_on & _boden_on & _lvp_off

;
;************************************************************************
; LCD I/O parameters
;
lcddata	equ	porta		; Port A0:3 = LCD data
lcdctr	equ	portb		; Port B6:7 = LCD control
;
LCDRS		EQU	6		; Lcd register select output
LCDEN		EQU	7		; Lcd enable output
; 					LCD commands	
LCDCLER	EQU	b'00000001'	; Clears display, resets curcor
LCDCM		EQU	b'10000000'	; Sets cursor using bits 0 - 6
line1		equ	.0		; Line 1 range - 0 to 0x13
line2		equ	0x40		; Line 2 range - 0x40 to 0x53
line3		equ	0x14		; Line 3 range - 0x14 to 0x27
line4		equ	0x54		; line 4 range - 0x54 to 0x67
;
diag		equ	1		; diagnostic I/O 1 = on, 0 = off
#define	diag_io portb, 3	; diagnostic I/O for RX timing check
;
kw_on		equ	1		; knock warning detection 1 = on, 0 = off
;
;************************  Data RAM Assignments  **********************
;
	ORG     0x20		; Origin for 16F628 RAM
;
; Special variables
;
s_status	res	1	; Startup status. Not cleared by clear RAM 
;
; LCD I/O variables
;
GP1		res	1	; General purpose register
chcnt				; map variables to save memory
STRNUM	res	1
CHPT		res	1	; Character string pointer in string.
LCDCH		res	1	; Saves byte to be sent to lcd while
				; it is processed
DLYCNT	res	1
COUNT		res	1
TEMP		res	1

TABOFF	res	1	; Table ofset pointer in lcd string lookup
apu		res	1	; anotger gp register
;
biglcd	equ	0	; size of lcd panel
zsup		equ	1	; leading zero supress in 4 digit displays
disp5d	equ	0	; # of digits displayed
;
;mulcnd  	res	1	; 8 bit multiplicand
;mulplr  	res	1	; 8 bit multiplier
H_byte	res	1	; 16-bit register
L_byte	res	1	; 
;
; B2_BCD  Bin to BCD conversion variables
; count	res	1	; ! already defined
nflag		res	1	; negative number flag
;
mulcnd			; map variables to save memory
R0 		res	1	; hi order
mulplr
R1		res	1	; 5 digit BCD output
R2		res	1
;
A4		res	1	; hi orde value
A3		res	1	; 5 byte ASCII output
A2		res	1
A1		res	1
A0		res	1	; lo order value
;
; Interrupt routine variables
;
w_temp	res	1	; W save during interrupt
status_temp	res	1	; status save during interrupt
fsr_temp	res	1	; FSR save during interrupt
;
;
; Display page selector variables
;
#define sw portb, 1 	; Page select switch IO bit
#define swbit flags, 0	; page select switch state bit. Stored in flags
dpage		res	1	; page selector
maxpage	equ	4	; Page numper steps between 0 and maxpage
db_counter	res	1	; Debounce delay counter
db_delay	equ	.50	; switch debounce delay (rounds)
;
; ALDL variables
;
oldpa3	res	1	; incremental knock counter
;
; ALDL Error Code logic variables
;
mfflag	res	3	; copy of MALFFLAGS 1 -3
msgidx	res	1	; index to messages
bitctr	res	1	; bit counter
;
; 160 Baud receiver variables
;
filter	equ	1	; switch for input filtering 1 = on
fcount	equ	.3	; filter delay
;
rx_buff	res	1	; ALDL input shift register
bit_count	res	1	; ALDL input bit counter
rx_byte	res	1	; received ALDL data byte
int_temp	res	1	; temp storage for int routines
; 
async		equ	7	; sync pattern received
byte_rdy	equ	6	; byte ready in rx_byte
flags		res	1	; ALDL receiver state flags
;
rx_count	res	1	; characters received after last sync
msg_num	res	1	; modulo 256 counter for aldl messages
buff_ptr	res	1	; aldl buffer write pointer
aldl_buff	res	.20	; ALDL data storage 
aldl_buffe	res	1	; buffer end + 1. Junk byte for too long messages.
aldl		equ	aldl_buff - 1	; for data stream offsets (starts from 1)
;
;    1227747 ALDL data steream
;    WORD  BIT   DESCRIPTION
;    ----  ---   ---------------
;      1         MODE WORD 2
;           0     ROAD SPEED PULSE OCCURRED
;           1     ESC 43B READY FOR SECOND PE
;           2     REFERENCE PULSE OCCURRED
;           3     DIAGNOSTIC SWITCH IN FACTORY TEST POSITION (3.9K)
;           4     DIAGNOSTIC SWITCH IN DIAGNOSTIC POSITION (0 OHMS)
;           5     DIAGNOSTIC SWITCH IN ALDL POSITION (10k)
;           6     1ST TIME IDLE FLAG             0 = FIRST TIME
;           7     IDLE FLAG 1=TPS < KISTPSI & MPH < KIDLMPH

; original data stream
;      2         PROMID (MSB)
;      3         PROMID (LSB)                    PROMID = (MSB)*256 + (LSB)

; modified Rover data stream
;      2         SA (MSB) ECM memory address $0066, total SA
;      3         SA (LSB) ECM memory address $0067                  

;      4         IAC PRESENT POSITION            N = COUNTS
;      5         COOLANT TEMPERATURE             SEE TABLE 1
;      6         VEHICLE SPEED                   MPH = N
;      7         MANIFOLD ABSOLUTE PRESSURE      VOLTS = N * .0196
;      8         ENGINE RPM                      RPM = N * 25
;      9         THROTTLE POSITION SENSOR        VOLTS = N * .0196
;      10        CLOSED LOOP INTEGRATOR          NONE
;      11        OXYGEN SENSOR                   MILLIVOLTS = N * 4.34
;      12        MALFFLG1
;           0     MALF CODE 24   VEHICLE SPEED SENSOR
;           1     (MALF CODE 23)
;           2     MALF CODE 22   THROTTLE POSITION SENSOR LOW
;           3     MALF CODE 21   THROTTLE POSITION SENSOR HIGH
;           4     MALF CODE 15   COOLANT SENSOR LOW
;           5     MALF CODE 14   COOLANT SENSOR HIGH
;           6     MALF CODE 13   OXYGEN SENSOR
;           7     MALF CODE 12   NO REFERENCE PULSES
;     13        MALFFLG2
;          0     MALF CODE 42   ELECTRONIC SPARK TIMING MONITOR ERROR
;          1     (MALF CODE 41)
;          2     (MALF CODE 35)
;          3     MALF CODE 34   MAP SENSOR LOW
;          4     MALF CODE 33   MAP SENSOR HIGH
;          5     MALF CODE 32   EXHAUST GAS RECIRCULATION FAILURE
;          6     MALF CODE 31   GOVERNOR FAILURE
;          7     (MALF CODE 25)
;     14        MALFFLG3
;          0     MALF CODE 55   ADU ERROR
;          1     MALF CODE 54   FUEL PUMP RELAY FAILURE
;          2     (MALF CODE 53)
;          3     MALF CODE 52   CAL PACK MISSING
;          4     MALF CODE 51   PROM ERROR
;          5     MALF CODE 45   OXYGEN SENSOR RICH
;          6     MALF CODE 44   OXYGEN SENSOR LEAN
;          7     MALF CODE 43   ELECTRONIC SPARK CONTROL FAILURE
;     15        MWAF1
;          0     CLEAR FLOOD FLAG                       1 = CRANKED IN C/FLOOD
;          1     LEARN CONTROL ENABLE FLAG              1 = ENABLE STORE
;          2     LOW BATTERY                            1 = LOW
;          3     4-3 DOWNSHIFT FOR TCC UNLOCK
;          4     ASYNCHRONOUS FLAG
;          5     OLD HIGH GEAR FLAG                     0 = HIGH GEAR LAST TIME
;          6     RICH LEAN FLAG                         1 = RICH  0 = LEAN
;          7     CLOSED LOOP FLAG                       1 = CLOSED LOOP
;     16        BATTERY VOLTAGE                 VOLTS = N * .1
;     17        MCU2IO
;          0     AIR SWITCH                             1 = SOLENOID ENGAGED
;          1     AIR DIVERT                             1 = SOLENOID ENGAGED
;          2     OF3 A/C                                1 = A/C DISABLED
;          3     TCC                                    1 = TCC LOCKED
;          4     PARK NEUTRAL                           0 = DRIVE
;          5     HIGH GEAR                              0 = SWITCH OPEN
;          6     FRTJ (NOT USED)
;          7     AIR CONDITIONER                        0 = A/C REQUESTED
;     18        OLDPA3                          N = COUNTS
;     19        BASE PULSE COURSE CORRECTION(BLM)
;     20        O2 CROSS COUNTS                 N = COUNTS
;
;
;***********************************************************************
;
	ORG     0		; Restart vector
	goto	main0
;
	ORG	4		; INT vector
	goto irqserv	; serve interrupts
;***********************************************************************
; Out 2 hex caharacters from W
; This routine must stay in  page 0 !
;
out2hexs
	movwf	temp
	movlw	' '
	call putlcd
	goto	o2h1
;
; Out 2 hex withou space
out2hex
	movwf	temp
;
o2h1	swapf	temp, w
	andlw	0x0f
	call	hextable
	nop
	call putlcd
;
	movf	temp, w
	andlw	0x0f
	call	hextable
	nop
	call putlcd
;
	return
;
HexTable
	clrf	pclath	; ! this routine must reside in page 0
	addwf	pcl
	retlw	'0'		;0
	retlw	'1'		;1
	retlw	'2'		;2
	retlw	'3'		;3
	retlw	'4'		;4
	retlw	'5'		;5
	retlw	'6'		;6
	retlw	'7'		;7
	retlw	'8'		;8
	retlw	'9'		;9
	retlw	'A'		;A
	retlw	'B'		;b
	retlw	'C'		;C
	retlw 'D'		;D
	retlw	'E'		;E
	retlw	'F'		;F
;
;***********************************************************************
;
main0
;***********************************************************************
; set up WDT prescaler 
; 
	movf	status, w			; first save startup status
	movwf	s_status
	clrwdt
	bsf 	status, rp0			; select bank 1
	bsf	option_reg, psa		; take prescaler(default1:128) for WDT use
	clrwdt
	bcf	option_reg, intedg	; RB0 interrupt with falling edge
	bcf 	option_reg, not_rbpu	; B-port pull ups on
	bsf	pie1, tmr1ie		; enable TMR1 IRQ
	bcf	status, rp0			; back to bank 0
	bsf	intcon, peie		; enable peripheral IRQs

;***********************************************************************
; 16F628 cpu Bank 0 RAM cleaning 
; zeroes ram 0x21  - 0x7F
;
	movlw		0x21			; start of 16F628 ram. s_status not cleared.
	movwf		fsr
ramc1	clrf		indf			; clear indirect location
	incf		fsr, f		; next location
	clrwdt
	btfss		fsr, 7		; cleans up to 0x7f
	goto		ramc1	
;
;***********************************************************************
; Set up lcd port & IRQ system.
;
; Outputs
;		RA0 - 3		lcd data
;		RB6			lcd register select
;		RA7			lcd enable

	clrf	lcddata
	clrf	lcdctr
	movlw	0x07				; turn comparators off
	movwf	cmcon
      bsf	status, rp0			; select bank 1
	movlw	b'11110000'			; Set port A data directions, A0:3=outputs
	movwf	trisa
	movlw	b'00110111'			; Set port B data directions
	movwf	trisb				; RB0 = int input
	bcf	status, rp0			; select bank 0	
	bsf	swbit				; assume page select switch = open
;
	call	initlcd			; init LCD routines
	clrwdt
;
;
;
;**********************************************************************
;
; Display  banner messages
;
	btfsc	s_status, not_to		; Watchdog bite ?
	goto	ok_start
	movlw	'W'				; WDT bite
	call	putlcd
	movlw	'D'
	call	putlcd
	movlw	'T'
	call	putlcd
	goto	start_delay
;
ok_start
	movlw	.1				; Hello message 
	call	string
	movlw	line2
	call	lcdcur			; Position text on line 2
	movlw	.2				; Version message
	call	string
;
start_delay
	movlw	.30				; wait about 3s
	call	wait100
;
	movlw	line4
	call	lcdcur			; line 4
	movlw	.19				; Wait message
	call	string
	clrwdt
;
;**************************************************************
;
; Init ALDL application variables
;
;	clrf	rx_buff
;	clrf	bit_count
;	clrf	rx_byte
;	clrf	flags
;
	movlw	aldl_buff			; init aldl buffer pointer
	movwf	buff_ptr
;
; Enable interrupts = Let's go
;
	bsf	intcon, gie			; enable interrupts
	bsf	intcon, inte		; enable RB0 ALDL input interrupts
;
wfs
	clrwdt
	btfss	flags, async
	goto	wfs				; wait for first sync
;
;**************************************************************
;
; Display PROM ID for few rounds
;
	movlw	.10				; # of ALDL frames while
	movwf	H_byte			; PROM ID is shown 
;
dispid
	movlw	line4
	call	lcdcur			; line 4
	movlw	'I'				; ID
	call	putlcd
	movlw	'D'
	call	putlcd
;
	movf	aldl+2, w			; get PROMID (MSB)
	call	out2hexs 
	movf	aldl+3, w			; get PROMID (LSB)
	call	out2hex
	movlw	.10
	call	disp_wspaces		; clear rest of the line
;
dispid1
	clrwdt
	btfss	flags, async
	goto	dispid1			; wait for sync
	bcf	flags, async
;
	decfsz H_byte, f			; wait few rounds
	goto	dispid
;
;**************************************************************
;
; Main loop is executed every time when sync pattern have occured at aldl bus.
; page variable defines page to be displayed
;
main1
	call	pagesw		; handle page switch button
	btfss	flags, async
	goto	main1			; wait for sync
;
	clrwdt			; if no sync received within 2s then restart(WDT bite)
	bcf	flags, async
	incf	msg_num, f		; increment message counter
;__________________________
;
; select page to be displayed
; this routine must stay in page 0
;
	clrf	pclath		; page 0
	movf	dpage, w		; compute jump
	addwf	pcl
	goto	disp_page1		; 0 page1
	goto	disp_page2		; 1 page 2
	goto	disp_page3		; 2 error codes
	goto	disp_page4		; 3 spark advance, modified 747 data stream
	goto	disp_diag		; 4 diag diaplay
;
;__________________________
disp_page1
	movlw	line1
	call	lcdcur		; line 1
;
	call	disp_rpm
	call	disp_space
     	call	disp_iac
	call	disp_space
	call	disp_a
	call	disp_space
;
	if	kw_on
	call	knock			; this overrides line 1 if knock
	endif
;__________________________
	movlw	line2
	call	lcdcur		; line 2
;
	call	disp_tps
	call	disp_space
	call	disp_o2
	call	disp_space
	call	disp_i
	call	disp_space
;__________________________
	movlw	line3
	call	lcdcur		; line 3
;
	call	disp_map
	call	disp_space
	call	disp_int
	call	disp_space
	call	disp_c
	call	disp_space
;__________________________
	movlw	line4
	call	lcdcur		; line 4
;
	call	disp_bcl
	call	disp_space
	call	disp_blm
	call	disp_space
	call	disp_l
	call	disp_space
;
	goto main1
;
;______________________________________________
;
; second display page
;
;
disp_page2
;
	movlw	line1
	call	lcdcur		; line 1
;
	call	disp_bat
	call	disp_space
     	call	disp_tmp
	call	disp_space
	call	disp_lb
	call	disp_space
;__________________________
	movlw	line2
	call	lcdcur		; line 2
;
	call	disp_spd
	call	disp_space
	call	disp_pa3
	movlw	.3
	call	disp_wspaces
;__________________________
	movlw	line3
	call	lcdcur		; line 3
;
	call	disp_occ
	call	disp_space
	call	disp_o2
	call	disp_space
	call	disp_rl
	call	disp_space
;__________________________
	movlw	line4
	call	lcdcur		; line 4
;
	call	disp_msg_num
	call	disp_space
	call	disp_rx_count
	call	disp_space
	call	disp_d
	call	disp_space
;
	goto main1
;
;______________________________________________
;
; malfunction code display
;
disp_page3
;
	call	disp_malf		; display malfunction codes
	goto	main1
;
;______________________________________________
;
; display for modified data stream spark advance value
;
disp_page4
;
	movlw	line1
	call	lcdcur		; line 1
;
	call	disp_tps
	movlw	.12			; fill rest of the line with spaces
	call	disp_wspaces
;
	if	kw_on
	call	knock			; this overrides line 1 if knock
	endif
;__________________________
	movlw	line2
	call	lcdcur		; line 2
;
	call	disp_rpm
	movlw	.12			; fill rest of the line with spaces
	call	disp_wspaces
;__________________________
	movlw	line3
	call	lcdcur		; line 3
;
	call	disp_map
	movlw	.12			; fill rest of the line with spaces
	call	disp_wspaces
;__________________________
	movlw	line4
	call	lcdcur		; line 4
;
	call	disp_adv		; display hex value and aproximate advance
	movlw	.4
	call	disp_wspaces	; clear rest of the line

;
	goto main1
;______________________________________________
;
; diagnostics display = show raw aldl data
; hex display only.
;
disp_diag
;
disp_diag1
	movlw	aldl_buff		; set buffer pointer
	movwf	chpt
;
	movlw	line1
	call	lcdcur		; line 1
	call	disp_line
	movlw	.5			; fill rest of the line with spaces
	call	disp_wspaces
	movlw	line2
	call	lcdcur		; line 2
	call	disp_line
	movlw	.5
	call	disp_wspaces
	movlw	line3
	call	lcdcur		; line 3
	call	disp_line
	movlw	.5
	call	disp_wspaces
	movlw	line4
	call	lcdcur		; line 4
	call	disp_line
	movlw	.5
	call	disp_wspaces
	goto	main1
;
disp_line
	movlw	.5			; set character counter
	movwf	chcnt
;
disp_line1
	movf	chpt, w
	incf	chpt, f		; uppdate character pointer
	movwf	fsr			; set indirect pointer
	movf	indf, w		; get data
;
	call	out2hexs		; display in hex format
;
	decfsz chcnt, f
	goto	disp_line1		; continue this line
	return
;
;***************************************************************
; ALDL parameter display routines
; Independent routines for each displayed paremeter
;

;
; display spark advance
;
disp_adv				; modified data stream byte2 and 3 = advance
	movlw	.46			; display Advance
	call	string

	movf	aldl+2, w		; get Advance (MSB), modified data stream
	call	out2hexs 
	movf	aldl+3, w		; get Advance (LSB), modified data stream
	call	out2hex
	movlw	' '
	call	putlcd

	incf aldl+2, w		; get sa MSB data and test if negative (0xFF)
	skpz				; if negative force to zero
	movf	aldl+3, w		; get sa LSB data
	movwf	mulcnd
	movlw	.56
	movwf	mulplr		; multiply it by 56 ( should be 3,516 )
	call	mpy
	call	div16			; and divide by 16 ( actual multiplier = 3,5 )
	goto	disp_end2		; show results

;
; display IAC
;
disp_iac			; unit = count, range 0 - 255
	movlw	.3		; display IAC
	call	string
	movf	aldl+4, w	; get IAC count
	goto	disp_end
;
;
; do coarse ad value to temperature conversion
;
tst10	macro ad1
	movlw	ad1
	subwf	aldl+5, w	; test if equal or less
	skpc
	call	add10		; 10 degrees increment
	endm
;
tst5	macro ad2
	movlw	ad2
	subwf	aldl+5, w	; test if equal or less
	skpc
	call	add5		; 5 degrees increment
	endm
;
add5	movlw	.5		; increnent temperature 5 deg
	addwf	l_byte, f
	return
add10	movlw	.10		; 10 deg
	addwf l_byte, f
	return
;
disp_tmp			; unit = degrees Celcius, range 0 - 125
	movlw	.4		; display Temp
	call	string
	clrf	h_byte
	clrf	l_byte	; show 0 if .lt. 10 degrees
;
; do raw test and skip conversion
;
	tst10	.218		; 10
	tst10	.199		; 20
	tst10	.177		; 30
	tst10	.152		; 40
	tst10	.126		; 50
	tst10	.102		; 60
	tst5	.92		; 65
	tst5	.81		; 70
	tst5	.72		; 75
	tst5	.64		; 80
	tst5	.56		; 85
	tst5	.50		; 90
	tst5	.44		; 95
	tst5	.39		; 100
	tst5	.34		; 105
	tst10	.25		; 115
	tst10	.21		; 125	stop testin now it is boiling anyway
;
	goto	disp_end2	; show conversion result from l_byte
;
disp_spd			; unit = MPH or KPH, range = 0 - 255
	movlw	.5		; display Vechicle Speed
	call	string
	movf	aldl+6, w	; get speed
	goto	disp_end
;
disp_map			; unit = Kpa, range = 10 - 104
	movlw	.6		; display MAP
	call	string
	movf	aldl+7, w	; get MAP AD value count
	movwf	mulcnd
	movlw	.94		; multiply by 94
	movwf	mulplr
	call	mpy
	call	div256	; then divide by 256
	movlw	.10		; offset
	addwf	l_byte, f	; add offset
	goto	disp_end2
;
disp_rpm			; unit = RPM, range = 0 - 6375
	movlw	.7		; display RPM
	call	string
	movf	aldl+8, w	; get rpm data
	movwf	mulcnd
	movlw	.25
	movwf	mulplr	; multiply it by 25
	call	mpy
	goto	disp_end2
;
disp_tps			; unit = %, range = 0- 100
	movlw	.8		; display TPS
	call	string
	movf	aldl+9, w	; get TPS AD count
	movwf	mulcnd
	movlw	.100		; multiply by 100
	movwf	mulplr
	call	mpy
	call	div256	; then divide by 256
	goto	disp_end2
;
disp_int			; unit = unit, range = 0 - 255
	movlw	.9		; display Integrator
	call	string
	movf	aldl+.10, w	; get Integrator
	goto	disp_end
;
disp_o2			; unit = mV, range = 0 - 1115
	movlw	.10		; display O2 volts
	call	string
	movf	aldl+.11, w	; get o2 raw value
	movwf	mulcnd	; do conversion mV = ad*70/16
	movlw	.70
	movwf	mulplr	; multiply it by 70
	call	mpy
	call	div16		; divide by 16
	goto	disp_end2	; show result
;
disp_blm			; unit = unit, range = 0 - 255
	movlw	.11		; display BLM
	call	string
	movf	aldl+.19, w	; get BLM value
	goto	disp_end
;
disp_occ			; unit = unit, range = 0 - 255
	movlw	.12		; display O2 cross counts
	call	string
	movf	aldl+.20, w	; get o2 cross count
	goto	disp_end
;
disp_bat			; unit = 0.1V, ramge = 0 - 255
	movlw	.13		; display battery voltage
	call	string
	movf	aldl+.16, w	; get battery voltage
	goto	disp_end
;
disp_bcl			; unit = cell #, range = 0 - 15
;
; Resolve & display current BLM cell. Current BLM cell information 
; does not come with ALDL data. You have to reconstruct it from MAp and RPM
; information. Cell border values are from ASDZ hack. Check yours !
;
hi_map	equ	.192	; map cell border values
mid_map	equ	.128
lo_map	equ	.20
hi_rpm	equ	.104	; rpm cell border values
mid_rpm	equ	.72
lo_rpm	equ	.30
;
map		equ	aldl+7	; map data
rpm		equ	aldl+8	; rpm data
;
	movlw	.14		; resolve & display current blm cell
	call	string
;
	movlw	.15
	movwf	l_byte	; initial BLM value
;
test_map
	movlw	hi_map	; start testing from highest map value
	subwf	map, w	; test
	skpnc
	goto	test_rpm	; MAP is higher or equal
	movlw	.4
	subwf	l_byte, f	; decrement MAP cell
;
	movlw	mid_map
	subwf	map, w	; test
	skpnc
	goto	test_rpm	; MAP is higher or equal
	movlw	.4
	subwf	l_byte, f	; decrement MAP cell
;
	movlw	lo_map
	subwf	map, w	; test
	skpnc
	goto	test_rpm	; MAP is higher or equal
	movlw	.4
	subwf	l_byte, f	; decrement MAP cell
;
test_rpm
	movlw	hi_rpm	; start testing from highest rpm value
	subwf	rpm, w	; test
	skpnc
	goto	test_end	; RPM is higher or equal
	decf	l_byte, f	; decrement MAP cell
;
	movlw	mid_rpm
	subwf	rpm, w	; test
	skpnc
	goto	test_end	; RPM is higher or equal
	decf	l_byte, f	; decrement MAP cell
;
	movlw	lo_rpm
	subwf	rpm, w	; test
	skpnc
	goto	test_end	; RPM is higher or equal
	decf	l_byte, f	; decrement MAP cell
;
; l_byte on current BLM cell #, display it
test_end
	goto	disp_end1		; l_byte already in place
;
disp_pa3			; unit = unit, range = 0 - 255
	movlw	.15		; display OLDPA3 parameter
	call	string
	movf	aldl+.18, w	; get OLDPA3 value
	goto	disp_end
;
knock				; display if knock detected
	movf	aldl+.18, w	; get OLDPA3 value
	xorwf	oldpa3,w	; check is same as before
	skpnz
	return		; yes = no action
	movf	aldl+.18, w	; get OLDPA3 value
	movwf	oldpa3	; store as old value
	call	lcdclr		; write over what ever we have on the display
	movlw	.16		; display knock warning message
	call	string
	movlw	.8		; fill rest of the line with spaces
	goto	disp_wspaces
;
disp_rx_count
	movlw	.18
	call	string
	movf	rx_count, w		; show how many bytes received since
	clrf	rx_count		; reset character counter
	goto	disp_end
;
disp_msg_num
	movlw	.17
	call	string
	movf	msg_num, w		; show aldl message number
	goto	disp_end
;
disp_end
	movwf	l_byte		; this is common part for almost
disp_end1
	clrf	h_byte		; all parameter display routines
disp_end2
	call	b2_bcd		; convert to decimal
	call	disp5			; show result
	movlw	' '
	call	putlcd
	return
;
; Display various flags
;
disp_c				; display cloced loop flag
	movlw	' '			; assume not set
	btfsc	aldl+.15, 7		; test closed loop flag MWAF1.7
	movlw	'C'			; closed loop indicator
	call	putlcd
	return
;
disp_l				; display enable learn flag
	movlw	' '			; assume not set
	btfsc	aldl+.15, 1		; test enable learn flag MWAF1.1
	movlw	'L'			; learn indicator
	call	putlcd
	return
;
disp_a				; display async inj flag
	movlw	' '			; assume not set
	btfsc	aldl+.15, 4		; test async inj flag flag MWAF1.4
	movlw	'A'			; async indicator
	call	putlcd
	return
;
disp_i				; display idle flag
	movlw	' '			; assume not set
	btfsc	aldl+.1, 7		; test idle flag MODE WORD 2.7
	movlw	'I'			; Idle indicator
	call	putlcd
	return
;
;
disp_d				; display P/N  flag, 0 = Drive
	movlw	' '			; assume  set
	btfss	aldl+.17, 4		; test P/N flag MCU2IO.4
	movlw	'D'			; drive indicator
	call	putlcd
	return
;
disp_rl				; display rich / lean flag, 1 = Rich
	movlw	'R'			; assume set
	btfss	aldl+.15, 6		; test rich/lean MWAF1.6
	movlw	'L'			; rich / lean indicators
	call	putlcd
	return
;
disp_lb				; display low battery flag
	movlw	' '			; assume not set
	btfsc	aldl+.15, 2		; test low battery  MWAF1.2
	movlw	'B'			; low battery indicator
	call	putlcd
	return
;
disp_space
	movlw	' '			; display one space
	goto putlcd
;
disp_Wspaces
	movwf	A0			; display W number of spaces
dws	movlw	' '			; display one space
	call putlcd
	decfsz A0, f
	goto	dws
	return
;
; Display malfunction codes
; Not wery neat routine but it works
;
disp_malf
	movf	aldl+.12, w		; copy malfunction bytes to work register
	movwf	mfflag
	movf	aldl+.13, w
	movwf	mfflag+1
	movf	aldl+.14, w
	movwf	mfflag+2

	clrf	msgidx		; message index = 0
	decf	msgidx, f		; addjust index for first round
	movlw	.24+1			; set 3 bytes to bit counter
	movwf	bitctr

	call	lcdclr		; clear display
	movlw	.20			; print Code-message
	call	string
;
; First LCD line
malf1
	decfsz bitctr, f		; test if all done
	goto malf2
	goto malf99			; yes, and no codes  found

malf2
	incf	msgidx		; uppdate message index
	clrc	
	rlf	mfflag+2, f		; test malfunction bits
	rlf	mfflag+1, f		; starting from MALFFLAG1.7
	rlf	mfflag, f

	skpc
	goto	malf1			; continue error seek
					; error found
	movf	msgidx, w		; get current message index
	addlw	emsg			; compute error message number
	call	string		; display it

	movlw	line2			; change to second line and continue testing
	call	lcdcur		; line 2
;
; Second LCD line
malf4
	decfsz bitctr, f		; test if all done
	goto malf5
	return			; yes
malf5
	incf	msgidx		; uppdate message index
	clrc	
	rlf	mfflag+2, f		; test malfunction bits
	rlf	mfflag+1, f	
	rlf	mfflag, f

	skpc
	goto	malf4			; continue error seek

	movlw	.20			; print Code-message
	call	string
	movf	msgidx, w		; get current message index
	addlw	emsg			; compute error message number
	call	string		; display it

	movlw	line3			; change to second line and continue testing
	call	lcdcur		; line 3
;
; Third LCD line
malf7
	decfsz bitctr, f		; test if all done
	goto malf8
	return			; yes

malf8
	incf	msgidx		; uppdate message index
	clrc	
	rlf	mfflag+2, f		; test malfunction bits
	rlf	mfflag+1, f	
	rlf	mfflag, f

	skpc
	goto	malf7			; continue error seek
	movlw	.20			; print Code-message
	call	string

	movf	msgidx, w		; get current message index
	addlw	emsg			; compute error message number
	call	string		; display it
	movlw	line4			; change to second line and continue testing
	call	lcdcur		; line 4
;
; Fourth LCD line
malf10
	decfsz bitctr, f		; test if all done
	goto malf11
	return			; yes

malf11
	incf	msgidx		; uppdate message index
	clrc	
	rlf	mfflag+2, f		; test malfunction bits
	rlf	mfflag+1, f	
	rlf	mfflag, f

	skpc
	goto	malf10		; continue error seek

	movlw	.20			; print Code-message
	call	string
	movf	msgidx, w		; get current message index
	addlw	emsg			; compute error message number
	call	string		; display it
;
	return			; We are out of display lines. Stop seeking error codes.
;
malf99
	movlw	' '			; No codes found
	call	putlcd
	movlw	'N'
	call	putlcd
	movlw	'o'
	call	putlcd
	return
;
;***************************************************************
;
; Interrupt services.
; 160 Baud ALDL receiver
; flags.sync = 1 when sync pattern found. Bit must be cleared by application.
; flags.byte_rdy = 1 when character received. Bit must be cleared by application.
; rx_byte = received character. Must be read before next byte_rdy.
; Data is also stored in aldl_buff starting from sync. buff_ptr = buffer pointer.
; Rx_count shows # of characters received after last sync pattern (for diagnostics)
;
;
irqserv
;
	movwf	w_temp			; save W & status
	swapf	status, w
	movwf	status_temp
	movf	fsr, w			; save fsr
	movwf	fsr_temp
;
; test which interrupt
	bcf	status, rp0			; be shure we are in bank 0
	btfss	intcon, intf		; check if rb0 irq
	goto	tmr1int			; was not rb0 irq, must be tmr1
;
; ALDL data input RB0 interrupt at falling edge
;
rb0int
; Data is sampled about 2 mS after start bit falling edge
; XTAL = 4.000 MHz => clock = 1.000 MHz, cycle = 1uS
;
; 2mS delay before sampling generated with TMR1 value 65536 - 2000 = 63536  0xF830.
;
	bcf	intcon, intf		; reset irq flag
	movlw	0xF8				; set TMR1 for 2 mS delay
	movwf	tmr1H
	movlw	0x30
	movwf	tmr1L
	bcf	pir1, tmr1if		; clear irq flag
	bsf	t1con, tmr1on		; enable tmr1
	goto	irqret
;
; TMR1 interrupt do data sampling & receive bit
;
tmr1int
	bcf	pir1, tmr1if		; clear irq flag
	bcf	t1con, tmr1on		; disable tmr1
;
	if filter
;
; Do simple filtering for aldl (RB0) input line. ! very noicy input
; may lock this filter up !
;
test
	movlw	fcount			; # of tests to determine B0 input state
	movwf	int_temp
	btfss	portb, 0			; remember logical 1 = bit 0 !
	goto	test1				; filter logical 1
test0
	nop
	btfss	portb, 0			; check if still 0
	goto	test				; no restsrt filtering
	decfsz int_temp
	goto	test0
	clrc					; set 0 bit
	goto	test9
test1
	nop
	btfsc	portb, 0			; check if still 1
	goto test				; no restart filtering
	decfsz int_temp
	goto	test1
	setc
test9						; it is 1
;
	else
;
; simple aldl input line sampling without filtering
;
	clrc					; quess for 0
	btfss	portb, 0			; check it
	setc					; data is 1
	endif
;
	if diag
	bsf	diag_io			; signal data sampling point
	endif
;
	rlf	rx_buff, f			; shift bit in
;
; test if sync pattern received
;
	skpc
	goto	rx_char
	incfsz rx_buff, w			; test if buffer was all ones
	goto	rx_char
;
; sync received
	movlw	.9				; 160 baud character bit count
	movwf	bit_count
	bsf	flags, async		; set sync received flag
;
	movlw	aldl_buff			; reset aldl buffer pointer
	movwf	buff_ptr
	clrf	rx_buff			; prevent false sync (first bit of first byte == 1)
;			
	goto	irqret
;
rx_char
	decfsz bit_count, f		; test if all bits received
	goto	irqret
;
	movlw	.9				; reset bit counter
	movwf	bit_count
	movf	buff_ptr, w			; set FSR
	movwf	fsr
	movf	rx_buff, w			; transfer ready character
	movwf	rx_byte
	bsf	flags, byte_rdy		; set byte ready flag
;
	incf	rx_count, f			; increment character counter
	movwf	indf				; store also to aldl buffer @ fsr
;
	movlw	aldl_buffe			; one over
	xorwf	buff_ptr, w			; do boundary check
	skpnz
	goto	irqret			; stop at last buffer byte

	incf	buff_ptr, f			; if not last byte increment buffer pointer
	clrf	rx_buff			; prevent false sync (last bit of last byte == 1)
;	
irqret
	if diag
	bcf	diag_io			; reset timing measurement output
	endif
;
	movf	fsr_temp, w			; restore fsr
	movwf	fsr
	swapf	status_temp, w		; restore status & W
	movwf	status
	swapf	w_temp, f
	swapf	w_temp, w	
;
	retfie
;
;***************************************************************
;
; LCD I/O routines
;

;******
;	CLKLCD clocks data/command to the lcd by making the EN line
;	high then low.
CLKLCD	MACRO	
	BSF     lcdctr,LCDEN	; Lcd enable high
	BCF     lcdctr,LCDEN	; Lcd enable low
	ENDM
;******
;	TABSET sets up the lcd table offset pointer before string output 
;	starts

TABSET	MACRO
	MOVLW	b'11111111'	; Offset is incremented on each call to
				; table - first call must generate zero value 
				; offset.
	MOVWF	TABOFF
	ENDM
;******
;	POINT increments the string pointer offset and adds it to the
;	PLC ready for string lookup

POINT	MACRO
	INCF	TABOFF
	MOVFW	TABOFF
	ADDWF	PCL
	ENDM
;******
;	POINT6 increments the string pointer offset and adds it to the
;	PLC ready for string lookup. Sets PCLATH to 3
POINT6	MACRO
	MOVLW	.6		; Page 6xx
	MOVWF	PCLATH
	INCF	TABOFF
	MOVFW	TABOFF
	ADDWF	PCL
	ENDM
;******
;	POINT4 increments the string pointer offset and adds it to the
;	PLC ready for string lookup. Sets PCLATH to 4 ( for 16F877 etc) 
POINT7	MACRO
	MOVLW	.7
	MOVWF	PCLATH
	INCF	TABOFF
	MOVFW	TABOFF
	ADDWF	PCL
	ENDM

;--------------------------------------------------------------------------
;******
;	STRING sends the string with number in W register - to the lcd		
STRING
	MOVWF	STRNUM
	TABSET		; Xero the offset
	CALL	DOSTR		; Character from string
	RETURN
;******
;	BCDLCD sends the bcd character in W to lcd
BCDLCD	IORLW	b'00110000'	; Convert to ascii
;******
;	PUTLCD sends the ASCII character in W to lcd
PUTLCD
	MOVWF	LCDCH
	CALL	CHALCD	; Character to lcd
	RETURN
;
;******
;	WAITGP waits for the number of ms in GP1

WAITGP
	MOVLW	.74		; 1ms DELAY
	CALL	DL1
	MOVLW	.255
	CALL	DL1
	DECF	GP1			; TOTAL DELAY N * 1 ms
	BNZ	WAITGP		; Loop until delay is complete
	RETURN			; Exit from WAITGP
;
wait100	movwf	apu		; wait n * 100 ms  W = delay
wa101	movlw	.100
	movwf	gp1
	call	waitgp		; wait 100 ms
	clrwdt			; feed watchdog during long delays	
	decfsz apu
	goto	wa101
	return

;--------------------------------------------------------------------------
		
;   			LCD Setup 

;--------------------------------------------------------------------------
;
INITLCD
	;******
	;	Reset the lcd
	
INITA	MOVLW	.20		; Delay for 20 ms to let lcd settle
	MOVWF	GP1
	CALL	WAITGP		; Wait for lcd

	MOVLW	b'00000011'	; Reset

	MOVWF   lcddata		; Command to lcd port
	CLKLCD			; Clock the nibble to the lcd
	
	MOVLW	.6		; Delay to let lcd settle
	MOVWF	GP1
	CALL	WAITGP		; Wait for lcd
		
	MOVLW	b'00000011'	; Reset

	MOVWF   lcddata		; Command to lcd port
	CLKLCD			; Clock the nibble to the lcd

	MOVLW	.5		; Delay for 5 ms to let lcd settle
	MOVWF	GP1
	CALL	WAITGP		; Wait for lcd

	MOVLW	b'00000011'	; Reset

	MOVWF   lcddata		; Command to lcd port
	CLKLCD			; Clock the nibble to the lcd

	MOVLW	.5		; Delay for 5 ms to let lcd settle
	MOVWF	GP1
	CALL	WAITGP		; Wait for lcd

	MOVLW	b'00000010'	; 4 bit interface
	MOVWF   lcddata		; Command to lcd port
	CLKLCD			; Clock the nibble to the lcd

	MOVLW	.5		; Delay for 5 ms to let lcd settle
	MOVWF	GP1
	CALL	WAITGP		; Wait for lcd

	MOVLW	b'00000010'	; 4 bit interface
	MOVWF   lcddata		; Command to lcd port
	CLKLCD			; Clock the nibble to the lcd

	MOVLW	b'00001000'	; 2 LINES, 5*7
	MOVWF   lcddata		; Command to lcd port
	CLKLCD			; Clock the nibble to the lcd

	MOVLW	.5		; Delay for 5 ms to let lcd settle
	MOVWF	GP1
	CALL	WAITGP		; Wait for lcd

	MOVLW	b'00000000'	; Display OFF
	MOVWF   lcddata		; Command to lcd port
	CLKLCD			; Clock the nibble to the lcd

	MOVLW	b'00001000'	; 
	MOVWF   lcddata		; Command to lcd port
	CLKLCD			; Clock the nibble to the lcd

	MOVLW	.5		; Delay for 5 ms to let lcd settle
	MOVWF	GP1
	CALL	WAITGP		; Wait for lcd

	MOVLW	b'00000000'	; Display clear
	MOVWF   lcddata		; Command to lcd port
	CLKLCD			; Clock the nibble to the lcd

	MOVLW	b'00000001'	; 
	MOVWF   lcddata		; Command to lcd port
	CLKLCD			; Clock the nibble to the lcd

	MOVLW	.5		; Delay for 5 ms to let lcd settle
	MOVWF	GP1
	CALL	WAITGP		; Wait for lcd

	MOVLW	b'00000000'	; Entry mode set
	MOVWF   lcddata		; Command to lcd port
	CLKLCD			; Clock the nibble to the lcd

	MOVLW	b'00000110'	; 
	MOVWF   lcddata		; Command to lcd port
	CLKLCD			; Clock the nibble to the lcd

	MOVLW	.5		; Delay for 5 ms to let lcd settle
	MOVWF	GP1
	CALL	WAITGP		; Wait for lcd

	MOVLW	b'00000000'	; Display on
	MOVWF   lcddata		; Command to lcd port
	CLKLCD			; Clock the nibble to the lcd

	MOVLW	b'00001100'	; 
	MOVWF   lcddata		; Command to lcd port
	CLKLCD			; Clock the nibble to the lcd

	MOVLW	.5		; Delay for 5 ms to let lcd settle
	MOVWF	GP1
	CALL	WAITGP		; Wait for lcd
	RETURN
;
;********************************************************************
;                  Binary To BCD Conversion Routine
;       The 16 bit binary number is input in locations H_byte and
; 	L_byte with the high byte in H_byte.
;       The 5 digit BCD number is returned in R0, R1 and R2 with R0
; 	containing the MSD in its right most nibble.
;
B2_BCD  bcf     STATUS,0                ; clear the carry bit
	movlw   .16
	movwf   count
	clrf    R0
	clrf    R1
	clrf    R2
loop16  rlf     L_byte, F
	rlf     H_byte, F
	rlf     R2, F
	rlf     R1, F
	rlf     R0, F
;
	decfsz  count, F
	goto    adjDEC
	goto	bcdasc	; continue with ascii conv RETLW   0
;
adjDEC  movlw   R2
	movwf   FSR
	call    adjBCD
;
	movlw   R1
	movwf   FSR
	call    adjBCD
;
	movlw   R0
	movwf   FSR
	call    adjBCD
;
	goto    loop16
;
adjBCD  movlw   3
	addwf   0,W
	movwf   temp
	btfsc   temp,3          ; test if result > 7
	movwf   0
	movlw   0x30
	addwf   0,W
	movwf   temp
	btfsc   temp,7          ; test if result > 7
	movwf   0               ; save as MSD
	RETLW   0
;
; continue with ASCII conversion
bcdasc	movf	r2, w		; convert low order byte r0
	movwf	A1
	andlw	0x0f
	addlw	0x30		; low order nible = ASCII number
	movwf	A0
	swapf	A1, w
	andlw	0x0f
	addlw	0x30		; hi order nible = ASCII
	movwf	A1
;
	movf	r1, w		; convert low order byte r1
	movwf	A3
	andlw	0x0f
	addlw	0x30		; low order nible = ASCII number
	movwf	A2
	swapf	A3, w
	andlw	0x0f		; sets also Z-flag
;
	if	zsup
	bz	lzsup
	addlw	0x30		; if non zero show number
	goto	lz1
lzsup	movlw	0x20		; if zero replace with space
lz1	movwf	A3
	else
	addlw	0x30		; hi order nible = ASCII
	movwf	A3
	endif
;
	movf	r0, w		; convert low order byte r2
	andlw	0x0f
	addlw	0x30		; hi order nible = ASCII
	movwf	A4		; save but dont care later 
;
	retlw   0
;
;**************************************************************
; display ascii result of bcd conversion
;
disp5
	if	disp5d
	movf	A4, w	
	call	putlcd
	endif
	movf	A3, w		; display 4 digits
	call	putlcd
	movf	A2, w
	call	putlcd
	movf	A1, w
	call	putlcd
	movf	A0, w
	call	putlcd
	retlw	0
;
;**************************************************************
; Divide H_byte & L_byte by 16 or 8
;
div16	movlw	.4		; 4 * shift right = div by 16
	goto	div80
;
div8	movlw	.3		; 3 * shift right = div by 8
;
div80	movwf	temp
div81	clrc
	rrf	h_byte, f
	rrf	l_byte, f
	decfsz	temp, f
	goto	div81
	retlw	0
;
div256
	movf	h_byte, w	; divide by 256
	movwf	l_byte
	clrf	h_byte
	return
;
;  8 * 8 multiply.  The 16 bit result is stored in 2 bytes
; Before calling the subroutine "mpy", the multiplier should
; be loaded in location "mulplr", and the multiplicand in
; "mulcnd".  The 16 bit result is stored in locations
; H_byte & L_byte.

mpy
        clrf    H_byte
        clrf    L_byte
        movlw   8
        movwf   count
        movf    mulcnd, W
        bcf     STATUS, C        ; Clear the carry bit in the status Reg.
loop    rrf     mulplr, F
        btfsc   STATUS, C
        addwf   H_byte, F
        rrf     H_byte, F
        rrf     L_byte, F
        decfsz  count, F
        goto    loop
        retlw   0
;
;************************************
;
; Part of LCD routine moved out from 0x300 page to get
; more room for messages
;
;	LCD64/2 gives a delay of 64us or 1.6ms while the lcd accepts the
;	data or command.

LCD64	MOVLW	.22		; Gives 65 us delay
	GOTO	DL1
;
LCD2	MOVLW	.65		; Gives 1.6ms delay
	CALL	DL1
	MOVLW	.255
	CALL	DL1
	MOVLW	.255
	GOTO	DL1
;
DL1	MOVWF	DLYCNT
DL11	DECF	DLYCNT, F
	BTFSS	STATUS, Z
	GOTO	DL11
	RETLW	.0		; Exit from CHA/COMLCD routines
;
;
;--------------------------------------------------------------------------

;			Subroutines to handle the lcd

;--------------------------------------------------------------------------
;	CHALCD writes the character in W register to the lcd.
;	On entry, the display character is in LCDCH.
CHALCD	
	; Get the upper nibble and load to the lcd port

	SWAPF   LCDCH,W		; Get the ms nibble to ls position
	ANDLW   07H			; Strip to ms nibble in ls position,
					; and mask top bit in case this is the lset 
					; character in a string
	MOVWF   lcddata		; Data to lcd port
	BSF	lcdctr,LCDRS	; Select lcd data
					; Clock the ms nibble to the lcd
	CLKLCD
	; Get the lower nibble and load to the lcd port
	MOVFW   LCDCH		; Get back the character
	ANDLW   0FH			; Strip to ms nibble in ls position
	MOVWF   lcddata		; Data to lcd port	
	BSF	lcdctr,LCDRS	; Select lcd data
		; Clock the ls nibble to the lcd.
	CLKLCD
	BCF	lcdctr,LCDRS
	GOTO	LCD64			; Delay then exit from CHALCD
;*****
;	COMLCD writes the command in W register to the lcd
;	On entry, the command character is in LCDCH.
COMLCD	
	; Get the upper nibble and load to the lcd port
	SWAPF   LCDCH,W		; Get the ms nibble to ls position
	ANDLW   0FH			; Strip to ms nibble in ls position
	MOVWF   lcddata		; Command to lcd port
		; Clock the ms nibble to the lcd
	CLKLCD
	; Get the lower nibble and load to the lcd port
	MOVFW   LCDCH		; Get back the character
	ANDLW   0FH			; Strip to ms nibble in ls position
	MOVWF   lcddata		; Command to lcd port	
		; Clock the ls nibble to the lcd.
	CLKLCD	
	GOTO	LCD2			; Delay then exit from COMLCD
;******
;	LCDCL1R clears the display and resets the cursor
LCDCLR
	MOVLW	LCDCLER		; LCD clear command
	MOVWF	LCDCH
	GOTO	COMLCD
;******
;	LCDCUR sets cursor to position on  using value in W register
;	line1 - 4 are defined for 4 * 20 display
;
LCDCUR
	IORLW	LCDCM
	MOVWF	LCDCH
	GOTO	COMLCD
;
;--------------------------------------------------------------------------
;
;			Page select switch logic
;
;--------------------------------------------------------------------------
;
pagesw
	tstf	db_counter		; debounce delay
	skpnz
	goto	pagesw_test		; test switches only whwn dwlay expired
	decf	db_counter, f	; do delay
	return
;
pagesw_test
	btfsc	sw			; check button pressed ?
	goto	pagesw_open
;
pagesw_closed			; 0 = button pressed = switch closed
	btfss	swbit			; check if allready closed state ?
	return			; yes, do nothing.
;
	movlw	db_delay		; set debounce delay
	movwf	db_counter
;
	bcf	swbit			; flag closed state
	movlw	maxpage		; test if max reached
	xorwf	dpage, w
	skpz				; yes
	goto	pagesw_inc
	clrf	dpage			; return to zero
	return
;
pagesw_inc
	incf	dpage, f		; increment counter
	return
;
pagesw_open
	btfsc	swbit			; check if allready open state ?
	return			; yes, do nothing.
;
	movlw	db_delay		; set debounce delay
	movwf	db_counter
;
	bsf	swbit			; flag open state
	return
;
;--------------------------------------------------------------------------
;
;			0x600  page of ROM
;
;--------------------------------------------------------------------------
;	Text strings and control subroutines must be stored on the correct
;	page or this pcogram WILL NOT FUNCTION CORRECTLY.
;	Only move code around if you are absoluteley clear as to what you
;	are doing!

	ORG 0x600	; First page for messages

LAST	EQU	b'10000000'	; Value to add to last character in a string 
;******
;	DOSTR uses CALLSTR table to direct flow to the correct lookup table 
;	for lcd strings. Gets string characters and outputs to lcd

DOSTR	
	MOVLW	.6			; 6xx Page
	MOVWF	PCLATH		; Keep the pageing ok
	MOVFW	STRNUM		; Get the string number
	CALL	CALLSTR
	MOVWF	LCDCH
	CALL	CHALCD		; Character to lcd
	BTFSS	LCDCH,7		; Test if end of string	flagged - bit 7 set
	GOTO	DOSTR			; Loop until all sent
	RETURN
;******
;	CALLSTR is the dispatch table for lcd string lookup
;
CALLSTR	ADDWF	PCL
	NOP		; 0
	GOTO	MSG1	; 1'Banner display'
	GOTO	MSG2	; 2'version info'
	GOTO	MSG3	; 3'IAC'
	GOTO	MSG4	; 4'TMP'
	GOTO	MSG5	; 5'SPD'
	GOTO	MSG6	; 6'MAP'
	GOTO	MSG7	; 7'RPM'
	GOTO	MSG8	; 8'TPS'
	GOTO	MSG9	; 9'Int'
	GOTO	MSG10	; 10'O2 '
	GOTO	MSG11	; 11'BLM'
	GOTO	MSG12	; 12'Occ'
	GOTO	MSG13 ; 13'Bat'
	GOTO	MSG14	; 14'Cel' BLM cell
	GOTO	MSG15	; 15'PA3'
	GOTO	MSG16	; 16'Knock'
	GOTO	MSG17	; 17'Msg' ALDL message #
	GOTO	MSG18	; 18'Rxc' ALDL message character count
	GOTO 	MSG19	; 19'Wait data'
	GOTO 	MSG20	; 20'Code '

emsg	equ	.21	; starting index for error messages
;aldl.12 / malfflg1 messages
	GOTO	MSG27	; 21'12 No ref pulse'
	GOTO	MSG26	; 22'13 oxygen sensor'
	GOTO	MSG25	; 23'14 coolant sensor high'
	GOTO	MSG24	; 24'15 coolant sensor low'
	GOTO	MSG23	; 25'21 TPS high'
	GOTO	MSG22	; 26'22 TPS low'
	GOTO	MSG99	; 27'23 xx'
	GOTO	MSG24	; 28'24 VSS'
;
;aldl.13 / malfflg2 messages
	GOTO	MSG99	; 29'25 xx'
	GOTO	MSG32	; 30'31 governor failure'
	GOTO	MSG31	; 31'32 EGR failure'
	GOTO	MSG30	; 32'33 MAP high'
	GOTO	MSG29 ; 33'34 MAP low'
	GOTO	MSG99	; 34'35 xx'
	GOTO	MSG99	; 35'41 xx'
	GOTO	MSG28	; 36'42 EST monitor'
;
;aldl.14 / malfflg3
	GOTO	MSG39	; 37'43 ESC failure'
	GOTO	MSG38	; 38'44 Oxy sensor lean'
	GOTO	MSG37	; 39'45 Oxy sensor rich'
	GOTO 	MSG36	; 40'51 PROM Error'
	GOTO	MSG35	; 41'52 Cal Pack missing'
	GOTO	MSG99	; 42'53 xx'
	GOTO	MSG34	; 43'54 Fuel Pump Relay'
	GOTO 	MSG33	; 44'55 ADU Error'
;
	GOTO 	MSG20	; 45
	GOTO	MSG40	; 46'ADV'
;
;			THE TEXT STRINGS!
MSG1	POINT6	; Use macro POINT6 when the string is in 0x600 
			; address area
	RETLW	'R' 
	RETLW	'o' 
	RETLW	'v' 
	RETLW	'e' 
	RETLW	'r' 
	RETLW	' ' 
	RETLW	'A' 
	RETLW	'L' 
	RETLW	'D' 
	RETLW	'L' 
	RETLW	' ' 
	RETLW	'D'
	RETLW	'i'
	RETLW	's'
	RETLW	'p'
	RETLW	'l'
	RETLW	'a'
	RETLW	'y'+LAST
;
MSG2	POINT6
	RETLW	'v' 
	RETLW	' ' 
	RETLW	'2' 
	RETLW	'.' 
	RETLW	'0' 
	RETLW	'2' 
	RETLW	' '
	RETLW	'J' 
	RETLW	'N'   
	RETLW	'i'+LAST
;
MSG3	POINT6
	RETLW	'I' 
	RETLW	'A' 
	RETLW	'C'+LAST
;
MSG4	POINT6		
	RETLW	'T' 
	RETLW	'M' 
	RETLW	'P'+LAST
;
MSG5	POINT6
	RETLW	'S' 
	RETLW	'P' 
	RETLW	'D'+LAST
;
MSG6	POINT6
	RETLW	'M'
	RETLW	'A'  
	RETLW	'P'+LAST
;
MSG7	POINT6
	RETLW	'R' 
	RETLW	'p' 
	RETLW	'm'+LAST
;
MSG8	POINT6
	RETLW	'T' 
	RETLW	'P' 
	RETLW	'S'+LAST
;
MSG9	POINT6
	RETLW	'I' 
	RETLW	'n' 
	RETLW	't'+LAST
;
MSG10	POINT6
	RETLW	'O'
	RETLW	'2'
	RETLW	' '+LAST
;
MSG11	POINT6
	RETLW	'B'
	RETLW	'L'
	RETLW	'M'+LAST
;
MSG12	POINT6
	RETLW	'O'
	RETLW	'c'
	RETLW	'c'+LAST
;
MSG13	POINT6
	RETLW 'B'
	RETLW 'a'
	RETLW	't'+LAST
;
MSG14	POINT6
	RETLW 'C'
	RETLW 'e'
	RETLW	'l'+LAST
MSG15	POINT6
	RETLW	'P'
	RETLW	'A'
	RETLW '3'+LAST
MSG16	POINT6
	RETLW ' '
	RETLW ' '
	RETLW ' '
	RETLW '!'
	RETLW ' '
	RETLW 'K'
	RETLW	'n'
	RETLW	'o'
	RETLW	'c'
	RETLW	'k'
	RETLW ' '
	RETLW '!'+LAST
;
MSG17	POINT6
	RETLW 'M'
	RETLW 's'
	RETLW	'g' + LAST
;
MSG18	POINT6
	RETLW 'R'
	RETLW 'x'
	RETLW	'c' + LAST
;
MSG19	POINT6
	RETLW 'W'
	RETLW 'a'
	RETLW 'i'
	RETLW 't'
	RETLW ' '
	RETLW 'd'
	RETLW 'a'
	RETLW 't'
	RETLW	'a' + LAST
;
MSG99	point6
	dt	"Er"		; General Error message
	dt	'r' + last

;--------------------------------------------------------------------------

;			0x700  page of ROM

;--------------------------------------------------------------------------

	org	0x700			; Second page for messages
;
MSG20	point7
	dt	"Code"
	dt	0x20 + last
;
;      12        MALFFLG1
;           0     MALF CODE 24   VEHICLE SPEED SENSOR
;           1     (MALF CODE 23)
;           2     MALF CODE 22   THROTTLE POSITION SENSOR LOW
;           3     MALF CODE 21   THROTTLE POSITION SENSOR HIGH
;           4     MALF CODE 15   COOLANT SENSOR LOW
;           5     MALF CODE 14   COOLANT SENSOR HIGH
;           6     MALF CODE 13   OXYGEN SENSOR
;           7     MALF CODE 12   NO REFERENCE PULSES
;     13        MALFFLG2
;          0     MALF CODE 42   ELECTRONIC SPARK TIMING MONITOR ERROR
;          1     (MALF CODE 41)
;          2     (MALF CODE 35)
;          3     MALF CODE 34   MAP SENSOR LOW
;          4     MALF CODE 33   MAP SENSOR HIGH
;          5     MALF CODE 32   EXHAUST GAS RECIRCULATION FAILURE
;          6     MALF CODE 31   GOVERNOR FAILURE
;          7     (MALF CODE 25)
;     14        MALFFLG3
;          0     MALF CODE 55   ADU ERROR
;          1     MALF CODE 54   FUEL PUMP RELAY FAILURE
;          2     (MALF CODE 53)
;          3     MALF CODE 52   CAL PACK MISSING
;          4     MALF CODE 51   PROM ERROR
;          5     MALF CODE 45   OXYGEN SENSOR RICH
;          6     MALF CODE 44   OXYGEN SENSOR LEAN
;          7     MALF CODE 43   ELECTRONIC SPARK CONTROL FAILURE
;
; MALFFLG1 codes
;
MSG21	point7
	dt	"24 VS"		; bit 0
	dt	'S' + last
;
MSG22	point7
	dt	"22 TPS "	; bit 2
	dt	'L' + last
;
MSG23	point7
	dt	"22 TPS "		; bit 3
	dt	'H' + last
;
MSG24	point7
	dt	"15 COOL "	; bit 4
	dt	'L' + last
;
MSG25	point7
	dt	"14 COOL "	; bit 5
	dt	'H' + last
;
MSG26	point7
	dt	"13 OX"		; bit 6
	dt	'Y' + last
;
MSG27	point7
	dt	"12 NO REF "	; bit 7
	dt	'P' + last
;
; MALFFLG2 codes
;
MSG28	point7
	dt	"42 ES"		; bit 0
	dt	'T' + last
;
MSG29	point7
	dt	"34 MAP "	; bit 3
	dt	'L' + last
;
MSG30	point7
	dt	"33 MAP "		; bit 4
	dt	'H' + last
;
MSG31	point7
	dt	"32 EG"		; bit 5
	dt	'R' + last
;
MSG32	point7
	dt	"31 GV"	; bit 6
	dt	'R' + last
;
; MALFFLG3 codes
;
MSG33	point7
	dt	"55 AD"		; bit 0
	dt	'U' + last
;
MSG34	point7
	dt	"54 FP RL"	; bit 1
	dt	'Y' + last
;
MSG35	point7
	dt	"52 CAL "	; bit 3
	dt	'P' + last
;
MSG36	point7
	dt	"51 PRO"		; bit 4
	dt	'M' + last
;
MSG37	point7
	dt	"45 OXY "	; bit 5
	dt	'R' + last
;
MSG38	point7
	dt	"44 OXY "	; bit 6
	dt	'L' + last
;
MSG39	point7
	dt	"43 ES"		; bit 7
	dt	'C' + last
;
MSG40	point7
	dt	"AD"		; Spark Advance
	dt	'V' + last
;
	END