#include "../ti83plus.inc"
#define	bcall(label)	RST 28h \ .dw label
	.org    $9D93
	.db     $BB,$6D

progstart:
	di
	im 1
	bcall(_runIndicOff)
	ld  hl, AppVarName2
	rst 20h
	bcall(_ChkFindSym)	;look up appvar	
	jp c, screen1		;doesnt exist? lets continue at screen1

	inc de		;oh, it does? then lets check it
	inc de		;get to the first byte of appvar 
	ex de, hl
	ld a, (hl)
	ld l, 1
	cp l			;see if the first byte of the appvar is 1 (meaning to run the code for dealing with testguad)
				;note; becuase the interrupt will set "1" once it finds and replaces code, we want to set it
				;back to 0 when we are done so that it will look for it in the future.

	jp z, RunSafeASM	

	xor a
	ld (savesscreen+13), a

;SCREEN INFO	
screen1:
	bcall(_clrLCDfull)
	ld hl, Screentxt
	ld a,1
	ld (penrow),a
	ld a, 5
	ld (pencol),a
	bcall(_vputs)		;"Notice"


	xor a
	ld h,a
	ld l,a
	ld a,8
	ld d,a
	ld a,96
	ld e,a
	bcall(_invertrect)	;for the black rectangle at top

	ld hl, screentxtb
	ld a, 14
	ld (penrow),a
	ld a, 3
	ld (pencol),a
	bcall(_vputs)

	ld b, 5			;5 more text to show
screenloop:
	push bc
	ld a, (penrow)
	add a, 7
	ld (penrow),a
	ld a, 3
	ld (pencol),a
	bcall(_vputs)
	pop bc
	djnz screenloop		;done with loop

	ld a,49
	ld (penrow),a
	ld a,80
	ld (pencol),a
	ld hl,darrow
	bcall(_vputs)		;display down arrow


skey1:
	bcall(_getcsc)
	cp skdown
	jp z,installit
	cp skclear
	jp z, endscreennoinstall
	cp skmode
	jp z, endscreennoinstall
	cp skdel
	jp z, endscreennoinstall
	cp skenter
	jp z,installit
	jp skey1



installit:
	ld a, (savesscreen+13)
	cp 1
	jp z, screen2

	ld a, 1
	ld (savesscreen+13), a

	
modescreen:
	bcall(_clrLCDfull)
	ld a, 1
	ld (savesscreen+14),a

	ld hl, tmode
	ld a,1
	ld (penrow),a
	ld a, 5
	ld (pencol),a
	bcall(_vputs)		;"select mode"


	xor a
	ld h,a
	ld l,a
	ld a,8
	ld d,a
	ld a,96
	ld e,a
	bcall(_invertrect)	;for the black rectangle at top

	ld hl, tmodeb
	ld a, 14
	ld (penrow),a
	ld a, 3
	ld (pencol),a
	bcall(_vputs)

	ld a, (penrow)
	add a, 7
	ld (penrow),a
	ld a, 3
	ld (pencol),a
	bcall(_vputs)
	jp setnorm

selectloop:
	bcall(_getcsc)
	cp skclear
	jp z, endscreennoinstall
	cp skmode
	jp z, endscreennoinstall
	cp skdel
	jp z, endscreennoinstall
	cp skenter
	jp z,setmode
	cp 0
	jp nz, changemode
	jp selectloop

changemode:
	ld a, (savesscreen+14)
	cp 1
	jp z, setrev
	jp setnorm



setmode:
	;save to appvar here
	bcall(_homeup)
	bcall(_clrscrnfull)
	
	call installint

	ld  hl, AppVarName2
	rst 20h
	bcall(_ChkFindSym)
	jp c, contnodel
	bcall(_delvar)	;delete it incase this program was accidently run again w/o testguard executing it

contnodel:
	ld hl, AppVarName2
	rst 20h
	ld hl,40
	bcall(_CreateAppVar)	;create the appvar for install info

	inc de
	inc de
	ld hl,instinfo	;what info; loaded 0, testguard hasnt been run
	ld bc,1	;size
	ldir		;copy

screen2:				;second screen of info

	bcall(_clrLCDfull)
	set FracDrawLFont, (IY + FontFlags)
	ld a,7
	ld (penrow),a
	ld a,80
	ld (pencol),a
	ld hl,uarrow
	bcall(_vputs)
	res FracDrawLFont, (IY + FontFlags)		;this flag displays the big font characters on the graph screen through vputs
	ld a,80						;the uparrow is only abalailable in big font
	ld l,a
	ld a,90
	ld e,a
	ld a,11
	ld h,a
	ld d,a
	bcall(_clearrect)					;so this routine clears the bottom 3 pixels, to make it look like the small one
	ld hl, screentxt2
	ld a, 6
	ld (penrow),a
	ld a, 3
	ld (pencol),a
	bcall(_vputs)

	ld b, 6
screenloop2:
	push bc
	ld a, (penrow)
	add a, 7
	ld (penrow),a
	ld a, 3
	ld (pencol),a
	bcall(_vputs)
	pop bc
	djnz screenloop2
						;\
						; |-Same stuff as above....
skey2:					;/
	bcall(_getkey)
	cp kup
	jp z,screen1
	cp kclear
	jp z,endscreen
	cp kmode
	jp z,endscreen
	cp kdel
	jp z,endscreen
	cp kenter
	jp z,endscreen
	jp skey2
	
;END SCREEN INFO
endscreen:
	call installint
	bcall(_homeup)
	bcall(_clrscrnfull)
	bcall(_runIndicOn)
	res donePrgm, (iy+doneFlags)		;no done thingy-ma-bobber
	im 2
	ei					;enable my custom interrupt
	ret

endscreennoinstall:
	bcall(_homeup)
	bcall(_clrscrnfull)
	bcall(_runIndicOn)
	ret	

installint:
		;establishing interrupt VVV
	ld hl,int_start 
	ld bc,int_end-int_start 
	ld de,$9898 
	ldir 
	ld hl,$9A00 
	ld a,h 
	ld i,a 
	ld a,$98 
	ld bc,257
	bcall(_memset) 	;establishing the interrupt  ^^^
	ret
setnorm:
	ld a, 1
	ld (savesscreen+14), a
	
	ld a,0						
	ld l,a
	ld a,95
	ld e,a
	ld a,29
	ld h,a
	ld a,63
	ld d,a
	bcall(_clearrect)	

	call displaytnorm
	jp selectloop

setrev:
	ld a, 2
	ld (savesscreen+14), a
	
	ld a,0						
	ld l,a
	ld a,95
	ld e,a
	ld a,29
	ld h,a
	ld a,63
	ld d,a
	bcall(_clearrect)	

	call displaytrev
	jp selectloop
	
displaytnorm:
	set textInverse, (iy+textflags)
	ld hl, tmodeb
	ld a, 14
	ld (penrow),a
	ld a, 3
	ld (pencol),a
	bcall(_vputs)
	res textInverse, (iy+textflags)
	ld hl, tmodec
	ld a, 21
	ld (penrow),a
	ld a, 3
	ld (pencol),a
	bcall(_vputs)

	ld hl, tnormal
	ld a, 30
	ld (penrow),a
	ld a, 3
	ld (pencol),a
	bcall(_vputs)

	ld b, 3			;3 more text to show
dnscreenloop:
	push bc
	ld a, (penrow)
	add a, 6
	ld (penrow),a
	ld a, 3
	ld (pencol),a
	bcall(_vputs)
	pop bc
	djnz dnscreenloop		;done with loop
	ret

displaytrev:
	set textInverse, (iy+textflags)
	ld hl, tmodec
	ld a, 21
	ld (penrow),a
	ld a, 3
	ld (pencol),a
	bcall(_vputs)
	res textInverse, (iy+textflags)
	ld hl, tmodeb
	ld a, 14
	ld (penrow),a
	ld a, 3
	ld (pencol),a
	bcall(_vputs)



	ld hl, trevenge
	ld a, 30
	ld (penrow),a
	ld a, 3
	ld (pencol),a
	bcall(_vputs)

	ld b, 4			;3 more text to show
drscreenloop:
	push bc
	ld a, (penrow)
	add a, 6
	ld (penrow),a
	ld a, 3
	ld (pencol),a
	bcall(_vputs)
	pop bc
	djnz drscreenloop		;done with loop
	ret


leftlineup:
	ld a, (savesscreen+11)
	cp 1
	ret z
	ld a, 1
	ld (savesscreen+11),a
	ld a,5
	ld (savesscreen+9), a
	ret
leftlineupL:
	ld a, (savesscreen+11)
	cp 1
	ret z
	ld a, 1
	ld (savesscreen+11),a
	ld a,6
	ld (savesscreen+9), a
	ret
leftlineupE:
	ld a, (savesscreen+11)
	cp 1
	ret z
	ld a, 1
	ld (savesscreen+11),a
	ld a,7
	ld (savesscreen+9), a
	ret

; ##### SAFE ASM - dealing with testgard #####################
RunSafeASM:
;	ld hl, (0F804h)
;	ld hl, password
;	ld (SavesScreen), hl
	ld  hl, testname	;look up the testasm prgm
	rst 20h
	bcall(_ChkFindSym)
	jp c, cont2
	bcall(_delvar)	;it shouldnt exist because it is deleted in the interrupt, but just in case, we have this. 
cont2:
	ld  hl, execname		;prrgm EXEC
	rst 20h
	bcall(_ChkFindSym)
	jp c, exit
	;edit exec to tmpprogobj
	ld a, 16h		;temp program, delete when done executing
	ld (hl),a
	;all done with that busy work. now onto dealing with testguard

	call SendZero	;this stuff is interracting with testguard itself. You should read michael V's documentation of testguard
	call GetByte	;www.radicalsoft.org/michael/testguard.txt
	call GetByte
	ld a, 04
	call Sendabyte
	call GetByte
	call GetByte
	call SendZero
				;testguard now thinks that the calc has been cleared. What to do now? Well, we need to make the "password" screen and show a fake RAM clear


	ld hl, AppVarName2
	rst 20h
	bcall(_ChkFindSym)
	inc de
	inc de
	ld hl,instinfo	;what info
	ld bc,1	;size
	ldir		;copy




	bcall(_clrLCDfull)
	bcall(_clrscrnfull)
	bcall(_homeup)
	ld hl, text 
	xor a
	ld (currow),a
	xor a
	ld (curcol),a
	bcall(_puts)	;fake "calc cleared" screen

	ld a, 7
	ld (currow),a
	bcall(_puts)

;******
	ld  hl, AppVarName2
	rst 20h		;safevar - our appvar
	bcall(_ChkFindSym)
	inc de
	inc de
	inc de
	ex de, hl	

;anti-ti security; swap 4th and 7th byte of password, swap 3rd and 7th byte, in other words, rearrage: 1-2-7-3-5-6-4-8 to 1-2-3-4-5-6-7-8

	ld a,4
	ld (savesscreen+9), a	;default display password at column 4
	xor a
	ld (savesscreen+11),a

	ld a, (hl)
	ld (savesscreen), a
	inc hl
	ld a, (hl)
	ld (savesscreen+1), a
	push hl		;save HL, so we can align the proper column on screen for password (5 or less characters is at the 4th column; 6,7,8 				;is in the 3rd)
	ld l,a
	xor a
	cp l
	call z, leftlineupE
	pop hl
	inc hl
	inc hl
	ld a, (hl)
	ld (savesscreen+2), a
	push hl		;save HL, so we can align the proper column on screen for password (5 or less characters is at the 4th column; 6,7,8 				;is in the 3rd)
	ld l,a
	xor a
	cp l
	call z, leftlineupE
	pop hl
	inc hl	;5
	inc hl	;6
	inc hl	;7
	ld a, (hl)
	ld (savesscreen+3), a

	push hl		;save HL, so we can align the proper column on screen for password (5 or less characters is at the 4th column; 6,7,8 				;is in the 3rd)
	ld l,a
	xor a
	cp l
	call z, leftlineupL
	pop hl

	dec hl	;6
	dec hl	;5
	ld a, (hl)
	ld (savesscreen+4), a
	inc hl	;6
	ld a, (hl)
	ld (savesscreen+5), a
	dec hl	;5
	dec hl	;4
	dec hl	;3
	ld a, (hl)
	ld (savesscreen+6), a

	push hl		;save HL, so we can align the proper column on screen for password (5 or less characters is at the 4th column; 6,7,8 				;is in the 3rd)
	ld l,a
	xor a
	cp l
	call z, leftlineup
	pop hl

	inc hl	;4
	inc hl	;5
	inc hl	;6
	inc hl	;7
	inc hl	;8
	ld a, (hl)
	ld (savesscreen+7), a
	xor a
	ld (savesscreen+8), a
					;DONE! rock on - (savesscreen) is start of the password
		
	ld hl, savesscreen	;load the pass
	ld a,(savesscreen+9)
	ld (curcol),a
	ld a, 4
	ld (currow),a
	bcall(_puts)

	bcall(_getkey)
	bcall(_clrLCDfull)

	;draw the name of the calc. First, determine wether it is an 84 or 83 line
	IN a,(2)
	AND %10000000
	cp 128
	jp nz, ramclearnoSE

	IN a,(2)
	AND %00100000
	cp 32
	jp z, ramclear84seshow
	

;	ld hl, savesscreen+13
;	bcall(_GetSysInfo)
;	ld a, (savesscreen+15)
;	cp 0
;	jp z, ramclear83
;	ld a, (savesscreen+17)
;	cp 0
;	jp z, ramclear84show
	jp ramclear83seshow
	
	
ramclearnoSE:
;	ld hl, savesscreen+13
;	bcall(_GetSysInfo)
;	ld a, (savesscreen+17)
	IN a,(2)
	AND %00100000
	cp 32
	jp z, ramclear83show
	jp ramclear84show

contramclear:
	ld a,10
	bcall(_setxxop2)				;op2=10
	bcall(_getbasever)			; a=major, B=minor rom version
	ld a,b
	bcall(_setxxop1)				;op1=minor ver. number
 
	bcall(_fpdiv)				; divide it with 10
	bcall(_fpdiv)				; ------||---------
	bcall(_getbasever)		
	bcall(_setxxop2)				;op1=a
	bcall(_fpadd) 				;add minor and major version number
	ld a,38					;THANKS BEN RYVES
	ld (pencol),a
	ld a, 17
	ld (penrow), a
	ld a,4
	bcall(_dispop1a)	;ok, now we got the version number written. how about RAM cleared next?

	set FracDrawLFont, (IY + FontFlags)		;big font, little screen
	ld hl, ramcleared
	ld a, 40
	ld (penrow),a
	ld a,12
	ld (pencol),a
	bcall(_vputs)	;draws BIG text RAM cleared to the graph screen
	;keep the flag set for the blinker


	bcall(_runIndicOff)
	call keyblink	;our blinking cursor on ram cleared screen
	bcall(_clrLCDfull)
	xor a
	ld (pencol),a
	ld (penrow),a
	bcall(_runIndicOn)
	res textInverse, (iy+textflags)
	bcall(_clrLCDfull)
	res FracDrawLFont, (IY + FontFlags)		;res the flag so it doesnt do that anymore
	xor a
	ld (curcol),a
	ld (currow),a
	bcall(_clrscrnfull)
	ret

SendZero: 
	xor a 
	bcall(_SendAByte)
	ret
Sendabyte:  
	bcall(_SendAByte)
	ret

GetByte:
	bcall(_RecAByteIO)
	ret

Exit:
	ret

keyblink:						;just the blinking cursor for ram cleared screen...
	set textInverse, (iy+textflags)
	ld hl, Space
	xor a
	ld (penrow),a
	ld (pencol),a
	bcall(_vputs)

	bcall(_getcsc)
	ld l, 0
	cp l
	ret nz
	ei
	ld b, 60
haltloop:
	halt
	bcall(_getcsc)
	ld l, 0
	cp l
	ret nz
	djnz haltloop

	res textInverse, (iy+textflags)
	ld hl, Space
	xor a
	ld (penrow),a
	ld (pencol),a
	bcall(_vputs)

keyblink2:
	bcall(_getcsc)
	ld l, 0
	cp l
	ret nz
	ei
	ld b, 40
haltloop2:
	halt
	bcall(_getcsc)
	ld l, 0
	cp l
	ret nz
	djnz haltloop2
	jp keyblink
					;ends here for keyblink
ramclear84seshow:
	ld hl, ti84pse
	ld a, 10
	ld (penrow), a
	ld a, 9
	ld (pencol) ,a
	bcall(_vputs)		;these 4 display your calc type
	jp contramclear
ramclear83seshow:
	ld hl, ti83pse
	ld a, 10
	ld (penrow), a
	ld a, 9
	ld (pencol) ,a
	bcall(_vputs)
	jp contramclear
ramclear84show:
	ld hl, ti84p
	ld a, 10
	ld (penrow), a
	ld a, 28
	ld (pencol) ,a
	bcall(_vputs)
	jp contramclear
ramclear83show:
	ld hl, ti83p
	ld a, 10
	ld (penrow), a
	ld a, 28
	ld (pencol) ,a
	bcall(_vputs)
	jp contramclear

; ##### </SAFE ASM> ##########################################

;Start of the interrupt code
int_start: 
	di		;\
	exx 		; |
	ex af,af' 	;/ Required bby tios

	ld de, tenspace-int_start+9898h	;the crazy offset from tenspace is required for accessing labels and data during interruts (data ;							;also must be included in the interrupt)
	bcall(_movfrop1)				;save OP1, if we dont, it will cause a problem when calling chkfindsym, and give tios errors
							
	ld  hl, AppVarName-int_start+9898h
	rst 20h
	bcall(_ChkFindSym)			;look up my appvar, if it doesnt exist, exit the interrupt because it wont be able to save the info

	
	jp c, Exit_int-int_start+9898h

	inc de
	inc de 
	ex de, hl
	ld a, (hl)
	ld l, 1
	cp l			;see if the first byte of the appvar is 1 (meaning to run the code)
	jp z,Kill_Int-int_start+9898h		;turn off interrupt so testguard and safeguard continue working properly once safeguard has been 							;activated by testguard


	call checkifexist-int_start+9898h	;hmm... does testguards killswitch program EXEC exist?
	ld l, a
	ld a, 122					;unique ID, if it does, this is passed back from the check function
	cp l
	call z, Progfound-int_start+9898h	;Yup, exec exists. onto the beginning of the dirty work
	
Exit_int:
	ld hl, tenspace-int_start+9898h
	bcall(_mov9toop1)				;restore OP1
	jp $3A					;required to exit INTerrupts


Kill_Int:
	im 1
	di						;KIlls the interrupt permanently... or at least until IM 2 and DI are called
	bcall(_clrLCDfull)
	bcall(_homeup)
	jp Exit_Int-int_start+9898h		;exit



checkifexist:
	ld  hl, ProgName-int_start+9898h	;program EXEC (basic prog made by testguard)
	rst 20h
	bcall(_ChkFindSym)	;well, lets look it up

	ret c
	ld a,122		;ID to return, so the parent that called this function knows if it exists
	ret

ProgFound:
	bcall(_homeup)
	call ReplaceCode-int_start+9898h	;change EXEC from asm(prgmTESTASM) to asm(prgmSAFEGRD); brilliant, testguard does all the dirty 							;work
	call Killinterrupt-int_start+9898h	;kill this interrupt so it doesnt interfere with the rest of the protection process

	ret

ReplaceCode:

	ld  hl, ProgName-int_start+9898h	;look up EXEC
	rst 20h
	bcall(_ChkFindSym)
	bcall(_delvar)				;Delete it, well replace it with out own

	ld hl,ProgName-int_start+9898h	 ; the name of the prog (EXEC)
	rst 20h            			 ; do the copying	(HL TO OP1)
	ld hl, 10
	bcall(_createprog)			;create it
	inc de	;memory bytes
	inc de	;memory bytes

	ld hl, ProgData-int_start+9898h       ; program data (asm(prgmSAFEGRD))
	ld bc,10          ; program data length
	ldir              ; copy data



	ld  hl, testname2-int_start+9898h	;we are going to extract the password from prgmTESTASM now.
	rst 20h
	bcall(_ChkFindSym)			;look it up, so the data is in DE
	ld b, 54					;the password is 8 bytes, and always located exactly 54 bytes from the start of TESTASM program 							;data
rcodeloop:
	inc de
	djnz rcodeloop			;loop up 54x

	push de					;de is safe - password LOCATION here


	ld  hl, AppVarName-int_start+9898h	;now we need to load the password into the appvar
	rst 20h
	pop de					;put de into use (from the stack)
	ex de, hl					;hl has password location now
	push hl					;save hl
	bcall(_ChkFindSym)
	pop hl					;bring back hl, in use - password location
	inc de
	inc de
	inc de					;location of password to be put in appvar
	ld bc,8	;size				;8 byte appvar
	ldir
							;copy the 8bytes from testasm to my appvar

	ld  hl, testname2-int_start+9898h	;done. now lets delete testasm (this causes an error in the program for some reason
	rst 20h					;if testasm is not deleted inside the interrupt. Ideas? I think testguard checks to make
	bcall(_ChkFindSym)			;sure it exists or something.)
	bcall(_delvar)
	ret						;delete and return

Killinterrupt:
	ld  hl, AppVarName-int_start+9898h	;appvar name, into HL
	rst 20h
	bcall(_ChkFindSym)
	ret c
	inc de
	inc de
	ld hl,uninstinfo-int_start+9898h	;what to load (actually a 1, to let safeguard know when it is run, that it needs to interact with 							;testguard)
	ld bc,1	;size (bytes)
	ldir
	ret


;## DATA FOR INT ##
ProgName: 
	.db 05h,"EXEC",0

ProgData:
	.db 0BBh,6Ah,5FH,"SAFEGRD"		;our program to combat testguard!

testname2: 
	.db 06h,"TESTASM",0

AppVarName: 
	.db 15h,"SafeVar",0

UnInstInfo:
	.dw 1
tenspace:
	.db 00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h	;buffer space for OP1

;## END DATA ##
int_end:			;end interrupt here
;###### DATA ########################### jp MyRoutine-int_start+9898h <-- this is the offset, kept for future use
;regular program data VVV

execname: 
	.db 05h,"EXEC",0

AppVarName2: 
	.db 15h,"SafeVar",0

Instinfo:
	.dw 0

testname: 
	.db 06h,"TESTASM",0

Screentxt:
	.db "Notice:",0
Screentxtb:
	.db "Use  of  this  program",0
	.db "requires you  accept  all",0
	.db "terms of use. See  Readme.",0
	.db "If  you  do  not  accept",0
	.db "these  terms - press  CLEAR",0
	.db "to  abort  installation.",0

screentxt2:
	.db "SafeGuard  has  been",0
	.db "Installed successfully!",0
	.db "Please  re-install  this",0
	.db "program  before  each  use.",0
	.db "For  additional  help",0
	.db "please refer  to  the",0
	.db "Readme  included.",0

darrow:
	.db 007h,0
uarrow:
	.db 006h,0		;something to note, the uparrow only is available in large font. You must draw the large font one, then edit it
				; to make it the same size as the down arrow (which is available in small font, for some reason)

Text:
	.db "   Calculator   "
	.db "     Clear      ",0
	.db "  Press Key... ",0
Space:
	.db " ",0 ;for blinking cursow
dot:
	.db ".",0	;for version on RAM CLEARED screen

ti83pse:
	.db "TI-83 Plus Silver Edition",0

ti83p:
	.db "TI-83 Plus",0
ti84pse:
	.db "TI-84 Plus Silver Edition",0

ti84p:
	.db "TI-84 Plus",0

ramcleared:
	.db "RAM cleared",0
tmode:
	.db "Please select a mode:",0
tmodeb:
	.db "1. Normal Mode",0
tmodec:
	.db "2. Revenge Mode",0
tnormal:
	.db "Normal  Mode  will  convince",0
	.db "the  teachers  calculator",0
	.db "that  yours  has  been",0
	.db "successfully  cleared.",0
trevenge:
	.db "Revenge  Mode  will  nuke",0
	.db "the  teachers  calculator",0
	.db "and  force  it  to  receive",0
	.db "an  invalid  OS - disabling",0
	.db "it temporarily.",0
.end
END































