;-------------------------------------------------------------------------;
;
;		Project:	test registers utility with lcd 2x16 char
;    	Filename:	jreboard_10_16f628.asm
;    	Date:		2012/03/04                             
;    	Author:		Giuseppe Aquilani
;    	Web:		http://www.ik0jre.net/
;       email:		ik0jre "at" ik0jre.net - giuseppe.aquilani "at" virgilio.it
;
;		History:	0.0 2011/11/19 start develop 
;					0.1 2011/12/12	beta release
;					0.2	2011/12/17 add printrestore
;					0.3	2011/12/24 add backup intcon on write eeprom routine
;					1.0	2012/03/04 change ll lines used
;		Description:
;		This software is written for PIC16F628A but can modify for other PIC 
;		with small change.
;		It can helps to known registers contents and PIC's binary logic.
;		The software uses only two buttons for all operations.
;		The buttons (RA0-RA1 input)have multifunction role because the 
;		software can manages three states:
;		1)	bounce (ignored)
;		2)	short time pression
;		3)	long time pression 
;		In "Loading status" we can select (RA0 pression) menù for choose
;		default application to run as default startup that can be one of
;		1) Main Menù	- Menù for run every application
;		2) Monitor Regs	- Monitoring two register's status in loop
;		3) Set Port BIT	- Set PORTA, PORTB logic level BIT high or low
;		4) Calculator	- Verify STATUS register next subwf or addwf
;		5) Register	set	- Turn register from 00 to FF and next set BIT
;		6) Restore Def	- Restore default application value
;-----------------------------------------------------------------------;
;		Processor:	16F628A
;		Pin used:	
;			*** LCD display in 4 bit mode ***
;			RA0-RA3	:	D4-D7 LCD Lines
;			RA6 RA7 :	RS E - LCD Lines (R/W to GND, write everytime)
;			RB6-RB7 :	input for switch control
;
;		Schema:	 http://www.ik0jre.net web site 
;		NOTE:
;		#define NOPROTECTPORT variable 
;		RB6-RB7 cannot be disabled as input  (used for buttons)
;		DB0-DB3 DB6-DB7 cannot be disabled as output (used for LCD)	
;-------------------------------------------------------------------------;
;		COPYRIGHT
;		This software are free. You can freely use at only condition 
;		write the author's name IK0JRE or/and Giuseppe Aquilani
;		on source code and schema description
;-------------------------------------------------------------------------;
;#define PIC16F628 1
;-------------------------------------------------------------------------;
;		PROGRAM 
;-------------------------------------------------------------------------;
       	PROCESSOR       16F628A
        INCLUDE         <P16F628A.INC>
		; __CONFIG		_CP_OFF&_PWRTE_ON&_WDT_OFF&_XT_OSC&_BODEN_OFF&_LVP_OFF
		__CONFIG		0x3F10	; osc int I/O RA6,RA7, PUT on,MCRLE disable
		RADIX 			DEC
        ERRORLEVEL      -302	; Register in operand not in bank 0.
		ERRORLEVEL 		-207 	; Found label after column 1.
;-------------------------------------------------------------------------;
;		Definitions and constants
;-------------------------------------------------------------------------;
#define	bank0	bcf	STATUS,RP0 ;bank 0 select
#define	bank1	bsf	STATUS,RP0 ;bank 1 select
;-------------------------------------------------------------------------;
;		LCD Data and port used from project
;-------------------------------------------------------------------------;	
;	LCD data ports D4 - D7 == RAB0-RA3 
;	LCD	CONTROL	EN = RA7, RS = RA6, R/W = GND
;	CONTROL BUTTON use:
;	RB6 for menu exit
;	RB7	for navigate and select/change value
#define LCDPORT 	PORTA
#define BTNPORT		PORTB
#define LCDTRIS 	TRISA
#define BTNTRIS		TRISB


#define	LCD_RS     LCDPORT,0x06	; Register Select
#define	LCD_EN     LCDPORT,0x07	; Enable Output / "CLK"
;-------------------------------------------------------------------------;
;	Filters	defines - avoid mistake in I/O settings
;-------------------------------------------------------------------------;
#define BTNFLTR	0xC0	;for BTN IOR
#define LCDFLTR	0x30	;for LCD AND
;-------------------------------------------------------------------------;
;		General defines
;-------------------------------------------------------------------------;
#define BTINPUT1		BTNPORT,6		; 0 down 1 up
#define BTINPUT2		BTNPORT,7		; 0 down 1 up
#define QSTIME			250		; almost Quarter of second in mS at 4 MHz
;-------------------------------------------------------------------------;
; 	for standard number use a table at TAB_DISP_A table
;	but for special character status use a defines
;	NOTE: the following defines are used for status
;-------------------------------------------------------------------------;
; 	My file registers
; pic16f84  start from bank0 0x0c 
; pic16f628 start from bank0 0x20
;#ifdef PIC16F628 
	#define RAMADDR 0x20
;#else
;	#define RAMADDR 0x0C
;#endif
;-------------------------------------------------------------------------;
	cblock RAMADDR
LTMENUVAR:		1 	; local temporary var for  "---only gsetup menu---"
LSMENUVAR:		1 	; can reused it in every sub menu
VREGX:			1
VAPPSTART:		1	; global status	- start address for for index memory
RegToRead:		3	; var set next read from eeprom
VSub:			2	;var to add or sub VSub+0 - Vsub+1
VAddSubOp:		1	;var sub/add operator 10H = '+' 11H = '-' - end address
VAPPRUNN:		1	; global value for running application 
DISPTVAR:		1	; generic var used in regdis and calctest
DISPTREG:		1
DELAYMSC:		2
LCDBUFF:		1	; temp var for trasfer data to LCD
LCDTEMP:		1	; temp var for swap nibble in lcd command
TLCDReg:		2	; var for settings line and col.
VLCDCurs:		2	; lcd cursor for gsetup
VLCDSCurs:		2	; lcd cursor for submenu
VSMCurs:		2	; lcd cursor submenu
VBtn1C:			2	; count btn1 push add 0x39 0x3A 		
VStack:			4	; Virtual stack or temporary local var
RegIDX:			1	; register index for a FSR use
IrqCount:		1	; irq var inc every interrupt if enable 0x40
RW_TEMP: 		1	; register for WREG backup on IRQ routine
RSTATUS_TEMP:	1	; register for FREG backup on IRQ routine
INTCON_TEMP:	1	;  register for INTCON backup on write/read eeprom routine
 endc 

;-------------------------------------------------------------------------;
; 				Macro 
;-------------------------------------------------------------------------;

;-------------------------------------------------------------------------;
; 				EEPROM DATA
;-------------------------------------------------------------------------;
	ORG H'2100'
	DE  0x00, 0x05, 0x39, 0x0B,0xFE, 0x05, 0x10   	
;	DE  0x00, 0x3E, 0x38, 0xFE, 0x05, 0x10   		
; RunApp-ID,reg 1, reg 2, reg 3,subop1, subop2, add/sub operator
;-------------------------------------------------------------------------;
	org 	0x00		;start routine on reset			
	goto 	InitMain
	org		0x04		;reset vector
	goto	IrqVect
;-------------------------------------------------------------------------;
InitMain
	call SettingsPorts	
	bank0
;register to read
	clrf	IrqCount
	call 	LCD_INIT
	call 	ReadEData

	movlw 	0x03
	movwf 	VBtn1C+0	;count down for sync button down in MonitorRegs
	movwf 	VBtn1C+1

	clrf 	VStack+0
	clrf 	VStack+1
	clrf	RegIDX

	btfss BTINPUT1 
	call StartAppM	;RunApp
MAIN
	bank0 
; choose if there is an application for run  
; var VAPPSTART can be:
; 0 = RunApp
; 1 = MonitorRegs
; 2 = SetPortBIT
; 3 = DoCalc
; 4 = Registers Set
; 5 = Restore default value
; I use some techniques for multiple choice and follow is one of
; test what application to run by test 2 bit at once (16 lines VS 24)
; 5 = 00000101
; 3 = 00000011
; 1 = 00000001	 
; in some routine I use a suctraction technique
; note that all application 
	btfss	VAPPSTART,2		; bit 2 is set ?
	goto	mtest3			; no cannot be 5 or 4
	btfsc	VAPPSTART,0		; yes bit 2 is set and bit 0 ?
	goto	mrun5			; yes bit 2 nd 0 are set = 5
	call 	RegistersSet	; no is 4
	goto 	MAIN 	
mrun5
	clrf	VAPPSTART		;is 5 - restore default value
	movlw	PORTA ;IrqCount 		; var inc every TM0 overflow if enabled
	movwf 	RegToRead+0
	movlw	VBtn1C+0		; view increment for test button pression
	movwf 	RegToRead+1
	movlw	INTCON			; intcon register for enable interrupt
	movwf	RegToRead+2
	movlw	0xFE
	movwf 	VSub+0
	movlw	0x05
	movwf 	VSub+1
	movlw	0x10
	movwf 	VAddSubOp		; + operator
	call	WriteEData
	call 	PrintRestore
	goto 	InitMain		
mtest3
	btfss	VAPPSTART,1		; is 2 or 3 ?	
	goto 	mtest1			; no test 0 or 1
	btfsc	VAPPSTART,0		; bit 1 is set test bit 0
	call	DoCalc			; bit 1 and 0 are set
	call 	SetPortBIT		; only bit 1 is set
	goto 	MAIN 	
mtest1
	btfsc	VAPPSTART,0		; is 1 ?
	call 	MonitorRegs		; yes
	call 	RunApp			; no is 0
	goto 	MAIN			;start main loop again
;-------------------------------------------------------------------------;
;	Interrupt routine
;-------------------------------------------------------------------------;
IrqVect
	bank0
	movwf	RW_TEMP			; saving Wreg
	swapf	STATUS,W 		; saving STATUS REG in 2 steps
	movwf	RSTATUS_TEMP 	; lower and hi nibble are swapped 

	incf	IrqCount,F
	movlw	0xF8
	andwf	INTCON,F

	swapf 	RSTATUS_TEMP,W
	movwf	STATUS			;restore status reg
	swapf	RW_TEMP,F
	swapf	RW_TEMP,W		;restore wreg
	retfie
;-------------------------------------------------------------------------;
; LCD display numbers table
;-------------------------------------------------------------------------;
TAB_DISP_LCD
	andlw 0x1F			; mask value over 0x11 	
	addwf	PCL,F		; increment PCL register
 	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' 	;10
	retlw	'B' 	;11
	retlw	'C' 	;12
	retlw	'D' 	;13
	retlw	'E' 	;14
	retlw	'F' 	;15
	retlw	'+' 	;16
	retlw	'-' 	;17
;-------------------------------------------------------------------------;
; LCD display HEX (inv) numbers table
;-------------------------------------------------------------------------;
TAB_BIT_INV
	andlw 	0x07
	addwf	PCL,F	; increment PCL register
 	retlw	128 	;0
	retlw	64 		;1				
	retlw 	32 		;2	
	retlw	16	 	;3	
	retlw	8	 	;4	
	retlw	4	 	;5	
	retlw	2	 	;6	
	retlw	1 		;7
;-------------------------------------------------------------------------;
; Settings Ports
;-------------------------------------------------------------------------;
SettingsPorts
    ;general setting
	bank0
	movlw 	0x07
	movwf 	CMCON			;disable comparator
	movlw 	0
	movwf 	LCDPORT
	movwf 	BTNPORT
	bank1
	movlw 	0
	movwf 	LCDTRIS			; clear TRISA register
	movwf 	BTNTRIS			; clear TRISB register
  	clrf	OPTION_REG	
  	bsf 	OPTION_REG,7 	; enable pull'up

	bsf 	BTNTRIS,6			;enable RA1 button
	bsf 	BTNTRIS,7			;enable RA2 button
 	bank0
	return
;-------------------------------------------------------------------------;
;	RunApp
;	Select app to run 
;	use vars:
;	LTMENUVAR, VLCDCurs
;-------------------------------------------------------------------------;
RunApp
	call 	LCDClear
 	clrf 	VLCDCurs+0 		;clear var
	movlw	0x10
	movwf 	VLCDCurs+1 		;set var
	clrf	LTMENUVAR
rawritemenu
	btfsc LTMENUVAR,1		; test what  half display to print 
	goto gln3
gln1
	movlw 1
	call SetLCDPos 
	movlw '1'
	call LCDdata
	movlw ':'
	call LCDdata
	movlw 'M'
	call LCDdata
	movlw 'o'
	call LCDdata
	movlw 'n'
	call LCDdata
	movlw 'i'
	call LCDdata
	movlw 't'
	call LCDdata
	movlw 'o'
	call LCDdata
	movlw 'r'
	call LCDdata
	movlw ' '
	call LCDdata
	movlw 'R'
	call LCDdata
	movlw 'e'
	call LCDdata
	movlw 'g'
	call LCDdata
	movlw 's'
	call LCDdata
	movlw ' '
	call LCDdata
gln2
	movlw 0x11
	call SetLCDPos 
   	movlw '2'
	call LCDdata
	movlw ':'
	call LCDdata
 	movlw 'S'
	call LCDdata
	movlw 'e'
	call LCDdata
	movlw 't'
	call LCDdata
	movlw ' '
	call LCDdata
	movlw 'P'
	call LCDdata
	movlw 'o'
	call LCDdata
	movlw 'r'
	call LCDdata
	movlw 't'
	call LCDdata
	movlw ' '
	call LCDdata
	movlw 'B'
	call LCDdata
	movlw 'I'
	call LCDdata
	movlw 'T'
	call LCDdata
	movlw ' '
	call LCDdata
	goto gwaitbt2   ; test button
gln3
	movlw 1
	call SetLCDPos 
	movlw '3'
	call LCDdata
	movlw ':'
	call LCDdata
	movlw 'C'
	call LCDdata
	movlw 'a'
	call LCDdata
	movlw 'l'
	call LCDdata
	movlw 'c'
	call LCDdata
	movlw ' '
	call LCDdata
	movlw ' '
	call LCDdata
	movlw ' '
	call LCDdata
	movlw ' '
	call LCDdata
	movlw ' '
	call LCDdata
	movlw ' '
	call LCDdata
	movlw ' '
	call LCDdata
	movlw ' '
	call LCDdata
	movlw ' '
	call LCDdata
gln4
	movlw 0x11
	call SetLCDPos 
	movlw '4'
	call LCDdata
	movlw ':'
	call LCDdata
	movlw 'R'
	call LCDdata
	movlw 'e'
	call LCDdata
	movlw 'g'
	call LCDdata
	movlw 'i'
	call LCDdata
	movlw 's'
	call LCDdata
	movlw 't'
	call LCDdata
	movlw 'e'
	call LCDdata
	movlw 'r'
	call LCDdata
	movlw 's'
	call LCDdata
	movlw ' '
	call LCDdata
	movlw 'S'
	call LCDdata
	movlw 'e'
	call LCDdata
	movlw 't'
	call LCDdata
gwaitbt2
	movf  	VLCDCurs+1,W
	call 	SetLCDPos 	; move to curr pos
	movlw 	' '			; erase old pos
	call 	LCDdata
 	movf 	VLCDCurs+0,W
	call 	SetLCDPos 	; move to new pos
	movlw 	'>'			; write tag char
	call 	LCDdata
gtstbtn2
	btfsc 	BTINPUT2 	; btn2 is down ?	 
	goto 	gtestbt1	; no test btn1
						; yes button 2 is down
	call 	DelayQS		; delay about 250 mS
;;;;;;;;;; button down
gshbtn2
	btfss 	BTINPUT2
	goto 	glngbtn2
 
	movlw 	0x10
	xorwf 	VLCDCurs+1,F	; move pointer cursor

	movlw 	0x10
	xorwf 	VLCDCurs+0,F

	incf 	LTMENUVAR,F
    movlw 	0x04
	subwf 	LTMENUVAR,W
	btfsc 	STATUS,Z
    clrf 	LTMENUVAR
	goto 	rawritemenu
glngbtn2
	movlw 	0x0D 			; set display blinking 
	call 	LCDCmd	
	btfss 	BTINPUT2
	goto 	$-1
	movlw 	0x0C 			; unset display blinking 
	call 	LCDCmd	
gselectm 
; for verify user's choice here use a subwf technique
; than bit verify (only for canonical write)
	; call a menu one of
	; 0 = MonitorRegs
	; 1 = Set Port BIT
	; 2 = Calc
	; 3 = Registers Set
 	movlw	0x03
	subwf 	LTMENUVAR,W
	btfsc	STATUS,Z		;test menu 3
	call	RegistersSet	

 	movlw	0x02
	subwf 	LTMENUVAR,W
	btfsc	STATUS,Z		;test menu 2
	call	DoCalc

 	movlw	0x01
	subwf 	LTMENUVAR,W
	btfsc	STATUS,Z		;test menu 1
	call	SetPortBIT

	movf	LTMENUVAR,W
	btfsc	STATUS,Z		;test menu 0
	call 	MonitorRegs
	goto 	RunApp
gtestbt1
   	btfsc 	BTINPUT1
	goto  	gtstbtn2
	call 	DelayHS	; anti bounce routine

   	btfsc 	BTINPUT1
	goto  	gtstbtn2

	movf	VAPPSTART,W
	btfsc	STATUS,Z
	goto 	gtstbtn2
	call	PrintExit
   	btfss 	BTINPUT1	;wait for button release
	goto $-1

	return
;-------------------------------------------------------------------------;
; MonitorRegs function: 
; read two register address from RegToRead var and display reg status on lcd 
; VAR:
; VAPPRUNN, VStack 0-1, VBtn1C 0-1,RegToRead 0-1
;-------------------------------------------------------------------------;
MonitorRegs
	call 	LCDClear
	bank0
	movlw	0x01
	movwf 	VAPPRUNN		; global ID 0x01
StartRead
	bank0
	decf 	VBtn1C+0,F		; loop count for test RA1 - RA2 pression

	clrf	VStack+0		;lcd start	position
	movf 	RegToRead+0,W	; take second reg's address to read
	movwf	VStack+1
	call	PrintNumX
;print space
	movlw 	0x02
	call 	SetLCDPos
	movlw 	' '
	call 	LCDdata
;print data
	movlw	0x03
	movwf	VStack+0
	movf	RegToRead+0,W ;DISPTREG
	movwf	VStack+1
	call	PrintRegX 
; second reg  to read
	movlw 	0x10	
	movwf	VStack+0		;lcd start	position
	movf 	RegToRead+1,W
	movwf	VStack+1
	call	PrintNumX
;print space
	movlw 	0x12
	call 	SetLCDPos
	movlw 	' '
	call 	LCDdata
;print data
	movlw	0x13
	movwf	VStack+0
	movf	RegToRead+1,W
	movwf	VStack+1
	call	PrintRegX 
;test button
	btfsc 	BTINPUT1 
	goto 	StartRead

	decfsz 	VBtn1C+1,F	; btn count if zero must test loop count var
	goto 	StartRead 	; not zero loop
	movf  	VBtn1C+0,W	;is zero  test var loop 
	btfsc 	STATUS,Z      ;is zero
	goto 	gotosetup		;yes goto tu setup

	movlw 	0x03		; no reset var and loop
	movwf 	VBtn1C+0
	movwf 	VBtn1C+1
	goto 	StartRead
gotosetup				; reset vars and go to setup routine
	movlw 	0x03
	movwf 	VBtn1C+0
	movwf 	VBtn1C+1

	call 	LCDClear
	movf 	VAPPRUNN,W
	movwf 	VStack+0
	call 	GlobalSetup
	btfsc	STATUS,Z		; if setup choice was return to app skip
	goto 	MonitorRegs	 	; return a new call 
;must test if return or goto to runapp
	call 	PrintExit

	movf	VAPPRUNN,W		; must verify
	subwf	VAPPSTART,W		; is default application to start is
	btfsc	STATUS,Z		; the same is running
	goto	RunApp			; yes run app

	return				
;-------------------------------------------------------------------------;
; SetPortBIT called from startup select app
; cannot use LSMENUVAR and VLCDSCurs
;-------------------------------------------------------------------------;
SetPortBIT
	movlw	0x02
	movwf 	VAPPRUNN		; global ID 0x02
	;;clrf 	RegIDX
	call 	LCDClear
	movlw 	0x3
	movwf 	VSMCurs+0		; load default cursor position to index
	clrf 	VSMCurs+1		; identify line 0-10H
spbstart					; print info
	movlw 0	
	call SetLCDPos 
	movlw 'A'			; pos 0x06
	call LCDdata
	movlw ':'
	call LCDdata
	movlw ' '
	call LCDdata

	movlw 0x10	
	call SetLCDPos 
	movlw 'B'			; pos 0x06
	call LCDdata
	movlw ':'
	call LCDdata
	movlw ' '
	call LCDdata

spbprnreg				; print register data
	bank0
	movlw 	0x03		; start position for display
	movwf 	VStack+0	; load in virtual stack
	movlw 	PORTA		; load PORTA base address 
	;;addwf	RegIDX,W	; add register index 0-1	
	movwf 	VStack+1	; load in virtual stack
	call 	PrintRegX	; print data to display


	movlw 	0x13		; start position for display
	movwf 	VStack+0	; load in virtual stack
	movlw 	PORTB		; load TRIS base address 
	;;addwf	RegIDX,W	; add register index 0-1	
	movwf 	VStack+1	; load in virtual stack
	call 	PrintRegX	; print data to display

spbmovcur
	movf  VSMCurs+0,W	; move the display cursor
	call SetLCDPos 
	movlw 0x0E 			; set display underscore 
	call LCDCmd			; start cursor position	
spbtstbtn2				; test button 2 0=down 1=up
	btfsc BTINPUT2	 	; is down ?
	goto spbtstbtn1		; no test another button

	call DelayQS		; is down - anti bouce delay
spbshbtn2				; short pression
	btfss BTINPUT2	 	; is down too ?
	goto spblnbtn2		; yes goto long pression routine
	incf  VSMCurs+0,F	; no - do everthing for short pression

	movlw	0x0B
	addwf	VSMCurs+1,W

	subwf 	VSMCurs+0,W	
    btfss	STATUS,Z	; is max value to move ?
	goto 	spbmovcur	; no - print the cursor

	movlw 	0x03			; yes - reset default cursor value
	addwf	VSMCurs+1,W
	movwf 	VSMCurs+0
	goto 	spbmovcur	; print the cursor

spblnbtn2 				; button 2 long pression
	movlw 0x0C 			; unset cursor blinking 
	call LCDCmd	

    ; controllo linea
	movlw 	0x10
	subwf 	VSMCurs+0,W
	btfss	STATUS,C	; skip if portb 
	goto	spbsetporta
;set portb
	movlw	0x13
	subwf	VSMCurs+0,W
	movwf	VStack+0
	movlw	PORTB
	movwf	VStack+1
	call	InvBitNRegX
	goto	spbbt2exit
;set porta
spbsetporta
	movlw	0x3
	subwf	VSMCurs+0,W
	movwf	VStack+0
	movlw	PORTA
	movwf	VStack+1
	call	InvBitNRegX
		
spbbt2exit
	movlw 0x0D 			; no - set blinking 
	call LCDCmd	

	btfss BTINPUT2	 	; button 2 is down too ?
	goto $-1			; yes - wait for released

	goto spbprnreg ;spbmovcur		; print the cursor
spbtstbtn1
	btfsc 	BTINPUT1	 	; is button1 down ?
	goto 	spbtstbtn2	; continue button testing
	call	DelayQS		; yes - delay for anti-bounce
spbshbtn1
	btfss 	BTINPUT1	 	; wait for button1 release
	goto 	spblngbtn1
	movlw	0x10
	xorwf	VSMCurs+1,F
	movlw 	0x03			
	addwf	VSMCurs+1,W
	movwf 	VSMCurs+0
	goto	spbmovcur
spblngbtn1
	btfss 	BTINPUT1	 	; wait for button1 release
	goto 	$-1

	movlw 0x0C 			; unset display blinking 
	call LCDCmd	

	movf	VAPPRUNN,W
	movwf	VStack+0
	call	GlobalSetup
	btfsc	STATUS,Z	; if setup choice was return to app skip
	goto	SetPortBIT	; else recall app

stupexit
	call 	PrintExit
	movf	VAPPRUNN,W		; must verify
	subwf	VAPPSTART,W		; is default application to start is
	btfsc	STATUS,Z		; the same is running
	goto	RunApp			; yes run app

	return
;-------------------------------------------------------------------------;
; DoCalc function: Test STATUS REG
; Used vars: DISPTVAR, DISPTREG,VAPPRUNN,VLCDSCurs,Vsub,VAddSubOp,VStack
; BTN1: increment up by 1 number short pression by 5 for long pression
; BTN2: select number/operator in short pression; exit in long pression 
;-------------------------------------------------------------------------;
DoCalc
	call LCDClear
	bank0
	movlw	0x03
	movwf 	VAPPRUNN		; global ID 0x03

	clrf DISPTVAR	;will have a result of operation
	clrf DISPTREG	;will have a copy of status register

	movlw	0x01
	movwf	VLCDSCurs	;active cursor position
; print constant string
	movlw 5
	call SetLCDPos
	movlw ' '
	call LCDdata
	movlw '='
	call LCDdata
	movlw ' '
	call LCDdata
	movlw 0x10
	call SetLCDPos 
	
	movlw 'S'
	call LCDdata
	movlw 'T'
	call LCDdata
	movlw 'A'
	call LCDdata
	movlw 'T'
	call LCDdata
	movlw 'U'
	call LCDdata
	movlw 'S'
	call LCDdata
	movlw ':'
	call LCDdata
	movlw ' '
	call LCDdata
; end costant
dcPrnAll
;print first operator
	bank0					;disp numbers to calc
	clrf	VStack+0		;initial cursor position
	movf	VSub+0,W
	movwf	VStack+1
	call	PrintNumX
;print operator sub/add
	movlw 	0x02
	call 	SetLCDPos 
	movf 	VAddSubOp,W
   	call 	TAB_DISP_LCD	; print operator sub/add
	call 	LCDdata
;print second number
	movlw	0x03
	movwf	VStack+0
	movf	VSub+1,W
	movwf	VStack+1
	call	PrintNumX
dcCalc
;------here do a calc but before must verify operator -------------
	movf 	VSub+0,W
	movwf	DISPTVAR
	movf 	VSub+1,W
	btfss   VAddSubOp,0 ; test what operator need
	goto 	$+3 		; goto add
	subwf 	DISPTVAR,F	; calc w sub operator
	goto 	$+2			; end calc skip
	addwf 	DISPTVAR,F 	; calc w add operator DISPTVAR have got result
;-------end calc block---------------------------------------------
	swapf 	STATUS,W	; read status contents with no flags modify
	movwf 	DISPTREG
	swapf 	DISPTREG,F	;now DISPTREG have got a copy of STATUS value
dcResult
	movlw	0x08
	movwf 	VStack+0 
	movlw	DISPTVAR	; trasfer a pointer
	movwf 	VStack+1 
	call 	PrintRegX	;call general purpose routine 
dcStatus				; Print status reg contents 
	movlw	0x018
	movwf 	VStack+0 
	movlw	DISPTREG	; trasfer a pointer
	movwf 	VStack+1 
	call 	PrintRegX	;call general purpose routine 

	movf	VLCDSCurs,W	; set correct cursor position
	call	SetLCDPos
	movlw	0x0E		; set underscore	blinking
	call 	LCDCmd
dctstbtn2	; now we must do a button control for calling calc setup 
	btfsc 	BTINPUT2
	goto 	dctstbtn1
	movlw	0x0C		; reset no blinking & no underscore
	call 	LCDCmd
	call 	DelayQS
dcshbtn2				; BTN2 short pression
	btfss 	BTINPUT2
	goto	dclngbtn2
	btfsc	VLCDSCurs,0	; is the first number active on cursor ?
	incf	VSub+0,F 	; yes is first number
	btfsc	VLCDSCurs,2 ; is the second number active on cursor ?
	incf	VSub+1,F	; yes is the second number
	btfss	VLCDSCurs,1	; is operator add/sub active on cursor ?
	goto	dcPrnAll	; no skip
	movlw	0x11		; yes exchange + - symbols
	xorwf	VAddSubOp,F	; with 2 xor operation
	movlw	0x10
	addwf	VAddSubOp,F
	goto 	dcPrnAll
dclngbtn2				; BTN2 long pression
	btfsc 	BTINPUT2
	goto	dcshbtn2
	movlw	0x05		; fast increment
	btfsc	VLCDSCurs,0	; test what number is active
	addwf	VSub+0,F	; is first number
	btfsc	VLCDSCurs,2	; is second number ?
	addwf	VSub+1,F	; yes is second number
	goto 	dcPrnAll
dcclrinc
	movlw 	0x01		; reset cursor index
	movwf	VLCDSCurs
	goto	dcPrnAll
dcinc
	incf	VLCDSCurs,F	;increment cursor
	goto	dcPrnAll
dctstbtn1
	btfsc 	BTINPUT1
	goto 	dctstbtn2
	call 	DelayQS
dcshbtn1
	btfss 	BTINPUT1
	goto	dclngbtn1
	btfss 	VLCDSCurs,2		; is last digit ?
	goto	dctst2			; no test 2
	goto	dcclrinc		; yes is 4
dctst2
	btfss 	VLCDSCurs,1		; is 2 ?
	goto	dcinc			; no is 1
	incf	VLCDSCurs,F
	incf	VLCDSCurs,F
	goto	dcPrnAll
dclngbtn1
	movlw	0x0C			; reset underscore	or blinking
	call 	LCDCmd
	call	WriteEData		; write in eeprom

	call	PrintExit		; Print message to lcd
	btfss 	BTINPUT1
	goto	$-1

	movf	VAPPRUNN,W		; must verify
	subwf	VAPPSTART,W		; is default application to start is
	btfsc	STATUS,Z		; the same is running
	goto	RunApp			; yes run app
dcexit						; no return to caller application
	return
;-------------------------------------------------------------------------;
; RegisterSet
; description: 
; can read one register address (first time use RegToRead) next the user can
; move up down and set bit to register
; BTN1: switch for up,down and set; long pression exit 
; BTN2:	inc, dec register address or move to MSB-LSB bit, long pression
; rise speed or exchange bit value (0-1 or 1-0)
; Variables :
; VAPPRUNN, DISPTVAR,DISPTREG VStack(0,1,2),VSMCurs+0, RegToRead
;-------------------------------------------------------------------------;
RegistersSet
	call 	LCDClear
	bank0
	movlw	0x04
	movwf 	VAPPRUNN		; global ID 0x04 not used 

	movlw '>'				; set default cursor
	movwf 	VStack+2		; use as flag inc/dec
	clrf	VSMCurs+0
RVReset
;	clrf 	DISPTVAR		; clear vars
	clrf 	DISPTREG
	movf 	RegToRead+2,W	; default register address to display

;	movwf 	DISPTVAR		
	movwf 	DISPTREG
RVRead
	bank0
;1	movf	DISPTVAR,W		
;1	movwf	DISPTREG

	movlw 	0x06
	call 	SetLCDPos 
	
	movf	VStack+2,W
	call	LCDdata
;print register address
	movlw 	0x07
	movwf 	VStack+0
	movf 	DISPTREG,W	;DISPTVAR,W	;1 DISPTREG,W
	movwf 	VStack+1
	call	PrintNumX
RVPrnReg
	movlw	0x14
	movwf 	VStack+0	
	movf	DISPTREG,W ;DISPTVAR,W
	movwf 	VStack+1
	call	PrintRegX
RVMovCur
	movf 	VSMCurs+0,W
	call	SetLCDPos
RVtstBtn2
	btfsc 	BTINPUT2
	goto	RVtstBtn1
	movlw	50			; delay only 50 ms because  I want a fast inc register number
	call 	DelayMS
	btfsc 	BTINPUT2
	goto	RVtstBtn1
;test increment
	movlw	'>'			; inc mode
	subwf	VStack+2,W
	btfsc	STATUS,Z	; is inc	mode ?
	goto	RVincf
;test decrement
	movlw	'<'			; dec mode
	subwf	VStack+2,W
	btfsc	STATUS,Z	; is dec mode ?
	goto	RVdecf
;test set bit
	movlw	'W'			; dec mode
	subwf	VStack+2,W
	btfsc	STATUS,Z	; is dec mode ?
	goto	RVsetbit
RVincf
	incf	DISPTREG,F ;DISPTVAR,F
	goto 	RVRead
RVdecf
	decf	DISPTREG,F ;DISPTVAR,F
	goto 	RVRead
RVsetbit
	movlw	150
	call 	DelayMS

	btfss 	BTINPUT2
	goto	RVlnsetbit	
	movlw	0x1B
	subwf	VSMCurs+0,W
	btfss	STATUS,Z
	goto	RVsbinc
	movlw	0x14
	movwf	VSMCurs+0
	goto	RVPrnReg
RVlnsetbit
	movlw	0x0D
	call	LCDCmd

	movlw 	0x14
	subwf 	VSMCurs+0,W
	movwf	VStack+0	;bit to invert
	movf	DISPTREG,W ;DISPTVAR,W
	movwf	VStack+1	; register to write
	call	InvBitNRegX

	movlw	0x0C		; disable cursor
	call	LCDCmd
	movlw	0x14
	movwf 	VStack+0	; VStack+1 always fill before
	call	PrintRegX	; read and print register value
	btfss 	BTINPUT2
	goto	$-1			; wait for button release  

	movlw	0x0E		; enable cursor underscored
	call	LCDCmd
	goto	RVMovCur 	; return to main loop
RVsbinc
	incf 	VSMCurs+0,F	; increment cursor
	goto 	RVPrnReg 	; read and print reg
;----- end btn2 routine
RVtstBtn1
	btfsc 	BTINPUT1 
	goto	RVMovCur ;RVRead;	RVtstBtn2
	call 	DelayQS

	btfss 	BTINPUT1 	;is down too ?
	goto	RVlngBtn1 	;yes go to long pression routine		
RVshBtn1				; no is short pression routine	
	movlw	'W'		
	subwf	VStack+2,W
	btfsc	STATUS,Z	; is inc	mode ?
	goto	RVinc

	movlw	'>'			; inc mode
	subwf	VStack+2,W
	btfsc	STATUS,Z	; is inc	mode ?
	goto	RVcdec

	movlw	'W'		
	movwf 	VStack+2
	
	movlw	0x0E
	call	LCDCmd
	movlw	0x14
	movwf	VSMCurs+0
	goto 	RVRead ;RVMovCur ;RVPrnReg ;RVRead
RVcdec
	movlw	'<'		
	movwf 	VStack+2
	goto 	RVRead
RVinc
	movlw	'>'		
	movwf 	VStack+2
	movlw	0x06
	movwf	VSMCurs+0
	movlw	0x0C
	call	LCDCmd
	goto 	RVRead
RVlngBtn1
	movlw	0x0C
	call	LCDCmd
	call	PrintExit
	movf	DISPTREG,W ;DISPTVAR,W
	movwf	RegToRead+2
	call	WriteEData
	btfss 	BTINPUT1 	;is down too ?
	goto	$-1			;yes wait for release
	
RVgotosetup				; reset vars and go to setup routine
	movf	VAPPRUNN,W		; must verify
	subwf	VAPPSTART,W		; is default application to start is
	btfsc	STATUS,Z		; the same is running
	goto	RunApp			; yes run app
	;call 	LCDClear
	;call	PrintExit
	return					; never return
;-------------------------------------------------------------------------;
; 	StartMenu
; 	use vars:
;	LSMENUVAR	(shared with other subroutine)
;	VLCDScurs	(shared with other subroutine)
;-------------------------------------------------------------------------;
StartAppM
	call 	LCDClear
	bank0
	clrf 	VLCDSCurs+0 			;clear var
	movlw	0x10
	movwf 	VLCDSCurs+1 			;set var
	clrf 	LSMENUVAR
samwritemenu
; test what  half display to print
	btfsc 	LSMENUVAR,2 
	goto 	samln5
	btfsc 	LSMENUVAR,1 
	goto 	samln3
	; if need more lines test LSMENUVAR here
samln1
	movlw 	0
	call LCDCmd
	movlw 	0x01
	call SetLCDPos 
	movlw '1'
	call LCDdata
	movlw ':'	
	call LCDdata	
	movlw ' '
	call LCDdata
	movlw 'M'
	call LCDdata
	movlw 'a'
	call LCDdata
	movlw 'i'
	call LCDdata
	movlw 'n'
	call LCDdata
	movlw ' '
	call LCDdata
	movlw 'M'
	call LCDdata
	movlw 'e'
	call LCDdata
	movlw 'n'
	call LCDdata
	movlw 'u'
	call LCDdata
	movlw ' '
	call LCDdata
	movlw ' '
	call LCDdata
	movlw ' '
	call LCDdata
samln2
	movlw 0x11
	call SetLCDPos 
	movlw '2'
	call LCDdata
	movlw ':'	
	call LCDdata
	movlw ' '
	call LCDdata
	movlw 'M'
	call LCDdata
	movlw 'o'
	call LCDdata
	movlw 'n'
	call LCDdata
	movlw 'i'
	call LCDdata		
	movlw 't'
	call LCDdata
	movlw 'o'
	call LCDdata
	movlw 'r'
	call LCDdata
	movlw ' '
	call LCDdata
	movlw 'R'
	call LCDdata
	movlw 'e'
	call LCDdata
	movlw 'g'
	call LCDdata
	movlw 's'
	call LCDdata
	goto samwaitbt2   ; test button
samln3
	movlw 1
	call SetLCDPos 
	movlw '3'
	call LCDdata
	movlw ':'
	call LCDdata
	movlw ' '
	call LCDdata
	movlw 'S'
	call LCDdata
	movlw 'e'
	call LCDdata
	movlw 't'
	call LCDdata
	movlw ' '
	call LCDdata
	movlw 'P'
	call LCDdata
	movlw 'o'
	call LCDdata
	movlw 'r'
	call LCDdata
	movlw 't'
	call LCDdata
	movlw ' '
	call LCDdata
	movlw 'B'
	call LCDdata
	movlw 'I'
	call LCDdata
	movlw 'T'
	call LCDdata
samln4
	movlw 0x11
	call SetLCDPos 
	movlw '4'
	call LCDdata
	movlw ':'
	call LCDdata
	movlw ' '
	call LCDdata
	movlw 'C'
	call LCDdata
	movlw 'a'
	call LCDdata
	movlw 'l'
	call LCDdata
	movlw 'c'
	call LCDdata
	movlw 'u'
	call LCDdata
	movlw 'l'
	call LCDdata
	movlw 'a'
	call LCDdata
	movlw 't'
	call LCDdata
	movlw 'o'
	call LCDdata
	movlw 'r'
	call LCDdata
	movlw ' '
	call LCDdata
	movlw ' '
	call LCDdata
	goto	samwaitbt2
samln5
	movlw 0x01
	call SetLCDPos 
	movlw '5'
	call LCDdata
	movlw ':'
	call LCDdata
	movlw ' '
	call LCDdata
	movlw 'R'
	call LCDdata
	movlw 'e'
	call LCDdata
	movlw 'g'
	call LCDdata
	movlw 'i'
	call LCDdata
	movlw 's'
	call LCDdata
	movlw 't'
	call LCDdata
	movlw 'e'
	call LCDdata
	movlw 'r'
	call LCDdata
	movlw ' '
	call LCDdata
	movlw 'S'
	call LCDdata
	movlw 'e'
	call LCDdata
	movlw 't'
	call LCDdata
	movlw ' '
	call LCDdata
samln6
	movlw 0x11
	call SetLCDPos 
	movlw '6'
	call LCDdata
	movlw ':'
	call LCDdata
	movlw ' '
	call LCDdata
	movlw 'R'
	call LCDdata
	movlw 'e'
	call LCDdata
	movlw 's'
	call LCDdata
	movlw 't'
	call LCDdata
	movlw 'o'
	call LCDdata
	movlw 'r'
	call LCDdata
	movlw 'e'
	call LCDdata
	movlw ' '
	call LCDdata
	movlw 'D'
	call LCDdata
	movlw 'e'
	call LCDdata
	movlw 'f'
	call LCDdata
	movlw ' '
	call LCDdata
	movlw 'V'
	call LCDdata
samwaitbt2
	movf 	VLCDSCurs+1,W 
	call 	SetLCDPos 		; move to curr pos
	movlw 	' '			; erase old pos
	call 	LCDdata
 	movf 	VLCDSCurs+0,W 
	call 	SetLCDPos 		; move to new po
	movlw 	'>'			; write tag char
	call 	LCDdata
samtstbtn2
	btfsc 	BTINPUT2 	; btn2 is down ?	 
	goto 	samtstbt1	; no test btn1
	call 	DelayQS
samshbtn2
	btfss 	BTINPUT2
	goto 	samlnbtn2
	movlw 	0x10
	xorwf 	VLCDSCurs+1,F 	; move pointer cursor
	movlw 	0x10
	xorwf 	VLCDSCurs+0,F 

	incf 	LSMENUVAR,F
	movlw 	6
	subwf 	LSMENUVAR,W
	btfsc 	STATUS,Z
    clrf 	LSMENUVAR
	goto 	samwritemenu
samlnbtn2				; long pression routine
	movlw 	0x0D 			; set display blinking 
	call 	LCDCmd	
	btfss 	BTINPUT2
	goto 	$-1
	movlw 	0x0C 			; unset display blinking 
	call 	LCDCmd	
	; save data to global var
	; 0 = Main Menu
	; 1 = MonitorRegs
	; 2 = Set Port BIT
	; 3 = Calc
	; 4 = Registers Set
	; 5 = Rst Def Value	
	movf 	LSMENUVAR,W
	movwf 	VAPPSTART
	call 	PrintSave
	call 	WriteEData	; write data to eeprom
	goto 	InitMain 	; "reboot"
samtstbt1
	btfsc 	BTINPUT1	 
	goto  	samtstbtn2
	call 	DelayHS	; anti bounce routine
   	btfsc 	BTINPUT1
	goto  	samtstbtn2
	call	PrintExit
   	btfss 	BTINPUT1
	goto 	$-1
	return

;-------------------------------------------------------------------------;
; 	GlobalSetup
; 	use vars:
;	LSMENUVAR	(shared with other subroutine)
;	VLCDScurs	(shared with other subroutine)
; 	VStack+0 	contains application code 
;-------------------------------------------------------------------------;
GlobalSetup
	call 	LCDClear
	;call PrintWait
	call DelayHS

	btfss 	BTINPUT1	;wait for button release
	goto 	$-1

	clrf 	VLCDSCurs+0  			;clear var
	movlw	0x10
	movwf 	VLCDSCurs+1  			;clear var

	clrf 	LSMENUVAR 
	; if need more lines test LSMENUVAR here
gsln1
	movlw 1
	call SetLCDPos 
	movlw '1'
	call LCDdata
	movlw ':'	
	call LCDdata	
	movlw ' '
	call LCDdata
	movlw 'S'
	call LCDdata
	movlw 'e'
	call LCDdata
	movlw 't'
	call LCDdata
	movlw 'u'
	call LCDdata
	movlw 'p'
	call LCDdata
gsln2
	movlw 0x11
	call SetLCDPos 
	movlw '2'
	call LCDdata
	movlw ':'	
	call LCDdata
	movlw ' '
	call LCDdata
	movlw 'E'
	call LCDdata
	movlw 'x'
	call LCDdata
	movlw 'i'
	call LCDdata
	movlw 't'
	call LCDdata		
	movlw ' '
	call LCDdata
	movlw 'A'
	call LCDdata
	movlw 'p'
	call LCDdata
	movlw 'p'
	call LCDdata	

gswaitbt2
	movf  VLCDSCurs+1,W 
	call SetLCDPos 		; move to curr pos
	movlw ' '			; erase old pos
	call LCDdata
 	movf VLCDSCurs+0,W 
	call SetLCDPos 		; move to new po
	movlw '>'			; write tag char
	call LCDdata
gststbtn2
	btfsc BTINPUT2 		; btn2 is down ?	 
	goto gstestbt1		; no test btn1
   
	call DelayQS
gsshbtn2
	btfss 	BTINPUT2
	goto 	gslnbtn2

	movlw 	0x10
	xorwf 	VLCDSCurs+1,F 	; move pointer cursor

	movlw 	0x10
	xorwf 	VLCDSCurs+0,F 

	incf 	LSMENUVAR,F
    btfsc 	LSMENUVAR,1
	clrf 	LSMENUVAR
	goto 	gsln1		
		
gslnbtn2					; long pression routine
	movlw 	0x0D 			; set display blinking 
	call 	LCDCmd	
	call 	DelayHS			; can wait 1/2 second
;	btfss 	BTINPUT2		; or can wait for button release
;	goto 	$-1
	movlw 	0x0C 			; unset display blinking 
	call 	LCDCmd	

	movf 	LSMENUVAR,W		
	btfss	STATUS,Z		; is setup ?
	retlw	0x01			; setup choice was return to app

	btfsc	VStack+0,1		; is SetPortBit App ?
	call 	SetupTRISXIO	; yes call for set TRIS regs
	btfsc	VStack+0,0		; is Monitor reg app ?
	call	SetupRegs		; yes call setupregs to monitor
	goto	gstexit			; nothing to do - exit
gstestbt1
	btfsc 	BTINPUT1	 
	goto 	gsln1
gstexit
	call 	LCDClear
	retlw	0x0
	;return
;-------------------------------------------------------------------------;
; SetupRegs (called from MOnitorRegs)
; VAR:
; RegIDX, RegToRead+0, RegToRead+1, VStack+2
;-------------------------------------------------------------------------;
SetupRegs
	clrf 	RegIDX
	call 	LCDClear
stregstart					; print info
	movlw 	0					
	call 	SetLCDPos 
	movlw 	'R'
	call 	LCDdata
	movlw 	' '
	call 	LCDdata
	movlw 	'1'				; pos 3
	addwf	RegIDX,W		; add ascii index
	call 	LCDdata
	movlw 	' '
	call 	LCDdata
	movlw 	't'
	call 	LCDdata
	movlw 	'o'
	call 	LCDdata
	movlw 	' '
	call 	LCDdata
	movlw 	'm'
	call 	LCDdata
	movlw 	'o'
	call 	LCDdata
	movlw 	'n'			
	call 	LCDdata
	movlw 	'i'
	call 	LCDdata
	movlw 	't'
	call 	LCDdata
	movlw 	'o'
	call 	LCDdata
	movlw 	'r'
	call 	LCDdata
	movlw 	'?'
	call 	LCDdata
	; print address
	bank0
	movlw 	0x15		; start position for display
	call 	SetLCDPos 
	movlw 	'>'
	call 	LCDdata
;	movlw 	' '
;	call 	LCDdata
	movlw 	RegToRead+0 ; load in virtual stack
	addwf	RegIDX,W	; add register index 0-1
	movwf	FSR
	movf	INDF,W	
	movwf 	VStack+2	; load in virtual stack
stregprreg
	movlw 	0x17		; start position for display
	movwf	VStack+0
	movf	VStack+2,W
	movwf	VStack+1
	call	PrintNumX
stregtstbtn2				; test button 2 0=down 1=up
	btfsc 	BTINPUT2	 	; is down ?
	goto 	stregtstbtn1	; no test another button
	call 	DelayQS			; is down - anti bonuce delay
stregshbtn2					; short pression
	btfss 	BTINPUT2	 	; is down too ?
	goto 	streglnbtn2		; yes goto long pression routine

	incf 	VStack+2,F		; no - do everthing for short pression
	goto 	stregprreg		; no - print the cursor
streglnbtn2
	btfsc BTINPUT2
    goto	stregtstbtn2
	movlw	5
	addwf	VStack+2,F		; no - do everthing for short pression
	goto 	stregprreg		; no - print the cursor
stregtstbtn1
	btfsc 	BTINPUT1	 	; is button1 down ?
	goto 	stregtstbtn2	; no - goto to control button 2
	call	DelayQS			; yes - delay for anti-bounce
	btfss 	BTINPUT1	 	; wait for button1 release
	goto $-1

	btfsc	RegIDX,0		; is portb done ?
	goto	stregexit		; yes - exit
	; save current var
	movf	VStack+2,W
	movwf	RegToRead+0

	incf 	RegIDX,F	; no - inc and continue for set portb
	goto 	stregstart	; print all info
stregexit
	movf	VStack+2,W
	movwf	RegToRead+1
	call 	WriteEData
	call 	LCDClear
	return
;-------------------------------------------------------------------------;
; 	SetupTRISXIO (Called from SetPortBit)
;	used vars:
;	VSMCurs, VStack, RegIDX
;-------------------------------------------------------------------------;
SetupTRISXIO
	clrf 	RegIDX
	call 	LCDClear
stiostart					; print info
	movlw 0x01					
	call 	SetLCDPos 
	movlw 	'S'
	call 	LCDdata
	movlw 	'e'
	call 	LCDdata
	movlw 	't'
	call 	LCDdata
	movlw 	' '
	call 	LCDdata
	movlw 	'T'
	call 	LCDdata
	movlw 	'r'
	call 	LCDdata
	movlw 	'i'
	call 	LCDdata
	movlw 	's'
	call 	LCDdata
	movlw 	' '
	call 	LCDdata
	movlw 	'A'			; pos 0AH
	addwf	RegIDX,W	; add ascii index
	call 	LCDdata
	movlw 	' '
	call 	LCDdata
	movlw 	'I'
	call 	LCDdata
	movlw 	'/'
	call 	LCDdata
	movlw 	'O'
	call 	LCDdata
stioprnreg				; print register data
	bank0
	movlw 	0x14		; start position for display
	movwf 	VStack+0	; load in virtual stack
	movlw 	TRISA		; load TRIS base address 
	addwf	RegIDX,W	; add register index 0-1	
	movwf 	VStack+1	; load in virtual stack
	call 	PrintRegX	; print data to display

	movlw 	0x0D 			; set display blinking 
	call 	LCDCmd	
stiorstcur				; start cursor positin
	movlw 	0x14
	movwf 	VSMCurs+0		; load default cursor position to index
stiomovcur
	movf  	VSMCurs+0,W	; move the display cursor
	call 	SetLCDPos 
stiotstbtn2				; test button 2 0=down 1=up
	btfsc 	BTINPUT2	 	; is down ?
	goto 	stiotstbtn1	; no test another button
	call 	DelayQS		; is down - anti bouce delay
stioshbtn2				; short pression
	btfss 	BTINPUT2	 	; is down too ?
	goto 	stiolnbtn2		; yes goto long pression routine

	incf  	VSMCurs+0,F	; no - do everthing for short pression
	movlw	0x1C
	subwf 	VSMCurs+0,W	
    btfss	STATUS,Z	; is max value to move ?
	goto 	stiomovcur	; no - print the cursor
	movlw 	0x14			; yes - reset defualt cursor value
	movwf 	VSMCurs+0

	goto 	stiomovcur	; print the cursor
stiolnbtn2 				; button 2 long pression
	movlw 	0x0C 			; unset cursor blinking 
	call 	LCDCmd	

	movf	VSMCurs+0,W
	movwf	VStack+0	; load current cursor position to virtual stack

	movlw 	0x14		
	subwf 	VStack+0,F	; subctract default lcd offset

	movlw 	TRISA		; load TRIS base address
	addwf	RegIDX,W
	movwf 	VStack+1	; load reg addrest to virtual stack
	
	call	InvBitNRegX	; set register

	movlw	0x14
	movwf	VStack+0
	call 	PrintRegX	; read, reload and print data register

	btfss 	BTINPUT2	 	; button 2 is down too ?
	goto 	$-1			; yes - wait for released

	movlw 	0x0D 			; no - set blinking 
	call 	LCDCmd	
	goto 	stiomovcur		; print the cursor
stiotstbtn1
	btfsc 	BTINPUT1	 ; is button1 down ?
	goto 	stiotstbtn2	; no - goto to control button 2
	call	DelayQS		; yes - delay for anti-bounce
	btfss 	BTINPUT1	 	; wait for button1 release
	goto 	$-1

	btfsc	RegIDX,0	; is portb done ?
	goto	stioexit	; yes - exit
	incf 	RegIDX,F	; no - inc and continue for set portb
	movlw 	0x0C		; unset display blinking 
	call 	LCDCmd	
	goto 	stiostart	; print all info
stioexit
	movlw 	0x0C 		; unset display blinking 
	call 	LCDCmd	
	call 	PrintExit
	return

;-------------------------------------------------------------------------;
; 	InvBitRegX - Tested
;	need :
;	VStack+0 = bit position to change(inverted)
;	VStack+1 = register's address to write result
;-------------------------------------------------------------------------;
InvBitNRegX
	bank0
	movf 	VStack+1,W	; reg address
	movwf	FSR
	movf	INDF,W		; read register data 
	movwf	VREGX
	movf 	VStack+0,W	
	call 	TAB_BIT_INV	; get bit value
	xorwf	VREGX,F		; exclusive or for invert bit
; verify if modify register are TRIS A o B
btntrisfilter
	movf 	VStack+1,W		; reg address
	sublw	BTNTRIS
	btfss	STATUS,Z
	goto 	lcdtrisfilter	;goto apply filter b
	movlw	BTNFLTR 
	iorwf	VREGX,F
	goto	inbnwritereg
lcdtrisfilter
	movf 	VStack+1,W	; reg address
	sublw	LCDTRIS
	btfss	STATUS,Z
	goto 	inbnwritereg
	movlw	LCDFLTR
	andwf	VREGX,F
; end filter for tris register
inbnwritereg
	movf 	VStack+1,W	; reg address
	movwf	FSR	
	movf 	VREGX,W
	movwf 	INDF		; set register
	return
;-------------------------------------------------------------------------;
; 	PrintNumX
;	need :
;	VStack+0 = cursor start position
;	VStack+1 = number value
;-------------------------------------------------------------------------;
PrintNumX
	movf	VStack+0,W		; start position for display
	call 	SetLCDPos 
	swapf 	VStack+1,W
	andlw	0x0F
	call	TAB_DISP_LCD
	call 	LCDdata
	movf 	VStack+1,W
	andlw	0x0F
	call	TAB_DISP_LCD
	call 	LCDdata
	movlw 	0x15			; start position for display
	call 	SetLCDPos 	
	return
;-------------------------------------------------------------------------;
; 	PrintRegX
;	need :
;	VStack+0 = cursor start position
;	VStack+1 = register's address (pointer) to read an print
;-------------------------------------------------------------------------;
PrintRegX
	bank0
	movf 	VStack+1,W	;register address
	movwf	FSR
	movf	INDF,W
	movwf	VREGX
	movf	VStack+0,W	
	call 	SetLCDPos 
	movlw	0x08
	movwf	LSMENUVAR
prxloop
  	btfsc 	VREGX,7
	goto  	$+3
	movlw 	'0'
	goto  	$+2 ; call lcddata
	movlw 	'1'
	call 	LCDdata
    rlf 	VREGX,F
	decfsz 	LSMENUVAR,F
	goto 	prxloop
	return
;-------------------------------------------------------------------------;
; PrintSave
;-------------------------------------------------------------------------;
PrintSave
	call 	LCDClear
	movlw 	0x06
	call 	SetLCDPos 
	movlw 	'S'
	call 	LCDdata
	movlw 	'a'
	call 	LCDdata
	movlw 	'v'
	call 	LCDdata
	movlw 	'e'
	call 	LCDdata
	call 	DelayS
	call 	LCDClear
	return
;-------------------------------------------------------------------------;
; PrintExit
;-------------------------------------------------------------------------;
PrintExit
	call 	LCDClear
 	movlw 	0x06
	call 	SetLCDPos 
	movlw 	'E'
	call 	LCDdata
	movlw 	'x'
	call 	LCDdata
	movlw 	'i'
	call 	LCDdata
	movlw 	't'
	call 	LCDdata
	call 	DelayS
	call 	LCDClear
	return
;-------------------------------------------------------------------------;
; PrintRestore
;-------------------------------------------------------------------------;
PrintRestore
	call 	LCDClear
 	movlw 	0x04
	call 	SetLCDPos 
	movlw 	'R'
	call 	LCDdata
	movlw 	'e'
	call 	LCDdata
	movlw 	's'
	call 	LCDdata
	movlw 	't'
	call 	LCDdata
	movlw 	'o'
	call 	LCDdata
	movlw 	'r'
	call 	LCDdata
	movlw 	'e'
	call 	LCDdata
	call 	DelayS
	call 	LCDClear
	return
;-------------------------------------------------------------------------;
; PrintVars	(used only in debug manual breakpoint)
;	need :
;	VStack+0 = Pointer to Var 1
;	VStack+1 = Pointer to Var 2
;	use VStack+3 as bck local vars for call PrintRegX
;-------------------------------------------------------------------------;
PrintVars
	movf 	VStack+0,W	;bck for call PrintRegX
	movwf	VStack+3	;unused from PrintRegX

	call 	LCDClear
;print first line and reg
	movlw 	0
	call 	SetLCDPos 
	movlw 	'V'
	call 	LCDdata
	movlw 	'0'
	call 	LCDdata
	movlw 	'='
	call 	LCDdata
	movlw 	' '
	call 	LCDdata

	movf 	VStack+0,W
	movwf	VStack+1
	movlw	0x03		;lcd position
	movwf 	VStack+0
	call	PrintRegX
;print second line and reg
	movlw 0x10
	call SetLCDPos 
	movlw 'V'
	call LCDdata
	movlw '1'
	call LCDdata
	movlw '='
	call LCDdata
	movlw ' '
	call LCDdata

	movlw 	0x13
	movwf	VStack+0
	movf	VStack+3,W
	movwf	VStack+1	
	call	PrintRegX

    call DelayS

	btfsc BTINPUT1	 
	goto $-1

	call 	LCDClear
	return
;-------------------------------------------------------------------------;
; Save Data in eeprom
; read global variables and stores in eeprom  
; VAPPSTART, RegToRead+0,RegToRead+1,VSub+0,VSub+1,VAddSubOp
; VStack+3 as temporary var
;-------------------------------------------------------------------------;
WriteEData
; *** right sequence should be: ***;
; backup interrupt status		
; disable interrupt
; restore interrupt status
; difference in eedata ed in eeadr pic16f84 bank0 for pic16f628 in bank1
	swapf 	INTCON,W
	movwf	INTCON_TEMP
	bank0
	clrf	VStack+3	; loop counter and address delta pointer

wedloop
	movlw	VAPPSTART		;start memory address to read
	movwf	FSR				; now memory indf to read
    movf 	VStack+3,W		; delta address to write

	bank1
	movwf 	EEADR			;address to read/write VStack+3

	addwf	FSR,F			;add W in FSR: VAPPSTART address + delta VStack+3
	
	bcf 	INTCON,GIE		;disable interrupt for write data eeprom
    btfsc 	INTCON,GIE
	goto 	$-2				; and wait while interrupt is enable

	movf	INDF,W			;load data from VAPPSTART+VStack+3 address

	bank1
	movwf 	EEDATA 			; trasfer data to write
	bsf 	EECON1,WREN		; enable write
	;start write sequence
	movlw	0x55
	movwf 	EECON2
	movlw	0xaa
	movwf	EECON2
	bsf		EECON1,WR 	;write
	nop
	call 	DelayQS
	bank0
	incf	VStack+3,F

	movlw 	0x07		;test if loop end
	subwf	VStack+3,W
	btfss	STATUS,Z 
	goto 	wedloop	

	swapf 	INTCON_TEMP,W 
	movwf	INTCON
;TODO verify data next single by write 
	return
;-------------------------------------------------------------------------;
; ReadEData in eeprom
; read eeprom and stores in global variables
; VAPPSTART,VStack+3,RegToRead 0-2,VSub+0,VSub+1,VAddSubOp
; need vars are in the same memory block from VAPPSTART to VAddSubOp
;-------------------------------------------------------------------------;
ReadEData
	clrf	VStack+3	; loop counter and delta address pointer
   ; load data from eeprom
redloop
	bank0
	movlw	VAPPSTART	;address to read
	movwf	FSR
    movf 	VStack+3,W	; load delta address pointer
	bank1
	movwf 	EEADR		; address to read
	bank0
	addwf 	FSR,F
	bank1
	bsf 	EECON1,RD	; eeprom read
	bank1
	movf 	EEDATA,W	; W = EEDATA
	bank0
    movwf	INDF
	incf	VStack+3,F

	movlw 	0x07		;test loop end
	subwf	VStack+3,W
	btfss	STATUS,Z 
	goto 	redloop	
	
	return
;-------------------------------------------------------------------------;
; Late's function for 4MHz about 1mS x W
; late are in TCy time (at 4MHz TCy = 1uS) = (((4 x 255) + 1) x (W + 1))+4
;-------------------------------------------------------------------------;
DelayMS			
		movwf   DELAYMSC+1		;1
        clrf    DELAYMSC+0		;1
DelayMSLoop
		nop						;1		
		decfsz  DELAYMSC+0,F	;1 +	
		goto    DelayMSLoop		;2
		decfsz  DELAYMSC+1,F	;1 + 2	
		goto    DelayMSLoop		;2
		return					;2
;-------------------------------------------------------------------------;
; Late 1 Second function (about  at 4 MHz)
;-------------------------------------------------------------------------;
DelayS
		movlw QSTIME
		call DelayMS	
		movlw QSTIME
		call DelayMS	
DelayHS
		movlw QSTIME
		call DelayMS	
DelayQS
		movlw QSTIME
		call DelayMS	
        return
;-------------------------------------------------------------------------;
;	start LCD routine block
;-------------------------------------------------------------------------;
LCD_INIT
	call 	DelayHS	
	bank0
	bcf		LCD_EN			; clear LCD clock line
;	bcf		LCD_RW			; set write direction
	bcf		LCD_RS			; clear command/data line

 	movlw	11110000b	
	andwf	LCDPORT,f			; clear only data lines
   	call 	DelayMS
	; LCD INITIALIZATION 
	movlw	0011b			; send 3 on [DB7:DB4] and RS = 0
	call	LCDSend 
;;	call  	LCDSync		
	call  	LCDSync		
	call  	LCDSync		
	call 	DelayMS
	; enable 4 bit mode
	movlw	0010b			; send 2 [DB7:DB4]
	call 	LCDSend
;;	call 	LCDSync	
	call 	DelayMS
	; settings display
	movlw 	00101000b		;command 0x28 - 4 bit, 2 lines, 5x7 dots
	call 	LCDCmd
;	movlw 00001100b			;command 0x12 - display on, cursor off, blinking off
;	call 	LCDCmd
	;optional
	movlw 	00000110b		; send 0x06 move cursor right
	call	LCDCmd
	movlw 	00001100b		; send 0x0C turn on display
	call	LCDCmd
	call 	DelayMS
	call 	LCDClear
	call 	DelayMS
	movlw 	0
	call 	SetLCDPos 

	movlw 'I'
	call LCDdata
	movlw 'K'
	call LCDdata
	movlw '0'
	call LCDdata
	movlw 'J'
	call LCDdata
	movlw 'R'
	call LCDdata
	movlw 'E'
	call LCDdata

	call 	DelayHS	

	movlw 	0x10	;line 1 c 1
	call 	SetLCDPos 

	movlw 'R'
	call LCDdata
	movlw 'B'
	call LCDdata
	movlw '6'
	call LCDdata
	movlw ' '
	call LCDdata
	movlw 'x'
	call LCDdata
	movlw ' '
	call LCDdata
	movlw 'D'
	call LCDdata
	movlw 'e'
	call LCDdata
	movlw 'f'
	call LCDdata
	movlw '.'
	call LCDdata
	movlw ' '
	call LCDdata
	movlw 'A'
	call LCDdata
	movlw 'p'
	call LCDdata
	movlw 'p'
	call LCDdata
; print waiting effect
	movlw 	0x06	;line 0 ch 8
	call 	SetLCDPos 
	movlw 	0x0A
	movwf 	LTMENUVAR
loadcycle
	movlw '.'
	call 	LCDdata
	call 	DelayQS		
	decfsz 	LTMENUVAR,F
	goto 	loadcycle
	call 	DelayS	
;	call 	LCDClear
;	return
;-------------------------------------------------------------------------;
;	LCDClear
;-------------------------------------------------------------------------;
LCDClear
	movlw 	0x01 		; clear display
;	call 	LCDCmd
LCDCmd	
	bank0	
	bcf		LCD_RS		; select command registers
	goto	LCDWrite
LCDdata					; transmit data to LCD	
	bsf		LCD_RS		; select data registers
LCDWrite	
;	bcf		LCD_RW
	movwf	LCDTEMP		; save data to var
	swapf	LCDTEMP,W	; swap hi- and lo-nibble, store in w
	call    LCDSend		; send hi-nibble
;;	call	LCDSync
    movf	LCDTEMP,W	; send lo-nibble	
	call 	LCDSend		; include lcdsync
;;	call	LCDSync
	movlw	11110000b   ; reset LCD controls
	andwf	LCDPORT,F	    ; clear data lines only ?
	bcf		LCD_RS		; set data register
	;bcf	LCD_RW		; reset to write direction
	return
;-------------------------------------------------------------------------;
LCDSend
		movwf	LCDBUFF		; save command/data
		movlw	11110000b	; mask for bit needed
		andwf	LCDPORT,F		; clear data lines only
		movf 	LCDBUFF,W
		andlw	00001111b	; mask for bit needed
		iorwf	LCDPORT,f		; put to LCD data lines
;;	return no need 
;-------------------------------------------------------------------------;
LCDSync
		movlw 	0x02
		call 	DelayMS
		bsf     LCD_EN
		nop
		nop
		bcf     LCD_EN
		return
;-------------------------------------------------------------------------;
SetLCDPos       
		bank0
		movwf   TLCDReg+0	; Set cursor position on LCD
		movlw   0x80		; W = D7-D4 row, D3-D0 col
		movwf   TLCDReg+1	; 00h=line 0 - 10h=line 1
        movf    TLCDReg+0,W
        andlw   0x0F
        iorwf   TLCDReg+1,F
        btfsc   TLCDReg+0,4
        bsf     TLCDReg+1,6
        movf    TLCDReg+1,W
        call    LCDCmd
        return
;-------------------------------------------------------------------------;
; end LCD routine BLOCK
;-------------------------------------------------------------------------;

	END

