; Program name: KeyScan

;**** NOTE ****
;This is a very old program, written for an early dialect of the SPLat language.
;A more modern program is located in the MultTrk folder under Examples.

; Key pad scan and encoding FSM.
; This program scans a 3x4 keypad and returns
; encoded key codes plus a KeyPressed flag.

;Method:

;The keypad is connected to 3 output lines and 4 input lines.
; Each of the 12 keys connects one output line to an input line.
; Each of the 12 keys interconnects a unique combination 
; of output and input.
; The program turns on just one output at a time and then
; checks each input in turn to see if it is on. If a key connected
; to the selected output is on, then the program will see an
; ON condition on the key's input.

; The FSM uses one separate state for each output/input combination.
; Hence, if a key is detected then the key code is implied by the 
; state number.

; Once a key has ben detected the program saves the key code 
; to a memory (KeyCode) location and sets another location 
; (KeyPressed) to true. Any other program can then "extract" the 
; KeyCode and clear KeyPressed. 

; KeyScan will not look for any further keys until KeyPressed 
; has been cleared. This is the responsibility of the "client"
; program.

; After a key has been detected KeyScan ensures that ALL keys are
; released for ~10-20mS. It does this in the following manner, 
; taking advantage of the 10-20mS debounce delay inherent in the 
; INPUT instruction:
; One a key is detected ALL outputs are turned on. The program 
; then delays for 100mS, doing nothing. This will give any ON 
; signal more than enough time to get through the input debounce.
; After 100mS the program waits for all keypad inputs to be off
; before resuming the search for new keypresses.

;During the 100mS debounce time interval one output, KeyBlink,
;is turned on. This is just for diagnostics/demonstration, and
;may safely be deleted. Just comment out of delete the lines
;which refer to KeyBlink. Of course, the KeyBlink output
;could be used to drive a beeper for audible feedback.

;The program is written as a Finite State Machine. As long as it is 
;called periodically through the single entry point KeyScan, it will
;do keypad scanning in the background of any other program,
;returning results to KeyCode and KeyPressed.

;Resource useage:
;All resources are given symbolic names.

;    Outputs:
;       KeyOut0, KeyOut1, KeyOut2, KeyBlink (demo only)
;    Inputs:
;       KeyIn0, KeyIn1, KeyIn2, KeyIn3
;    Private memory
;	KeyScanState
;    Shared memory (accessed by client program)
;       KeyCode (result), KeyPressed (signal flag)
;    Timer
;	KeyTimer (100mS)

;External connections:

;The following diagram symbolizes a matrix output wires
;(vertical) and input wires (horizontal) with one key
;placed at each intersection. This is how virtually all
;available keypads are wired.


;KeyIn0 ------1----2----3
;             |    |    |
;KeyIn1 ------4----5----6
;             |    |    |
;KeyIn2 ------7----8----9
;             |    |    |
;KeyIn3 ------*----0----#
;             |    |    |
;             |    |    |
;KeyOut0______|    |    |
;                  |    |
;KeyOut1___________|    |
;                       |
;KeyOut2________________|
;
;
;

;===================================================================
;Declarations
;This section will depend of actual I/O pins used
;and memories and timers allocated.

KeyOut0		EQU	0
KeyOut1		EQU	1
KeyOut2		EQU	2
KeyBlink	EQU	3
Mon0		EQU	7
Mon1		EQU	6
Mon2		EQU	5
Mon3		EQU	4

KeyIn0		EQU	0
KeyIn1		EQU	1
KeyIn2		EQU	2
KeyIn3		EQU	3

KeyTimer	EQU	0

KeyCode		EQU	23
KeyPressed	EQU	22
KeyScanState	EQU	21



;===================================================================
;Test code for KeyScan.
;This section is not part of KeyScan. It is a dummy
;application which uses KeyScan.
;All this program does is set 4 LED's to a code
;indicating which key was pressed. The code is:

; 0	----
; 1     ---*
; 2	--*-
; 3     --**

; 4	-*--
; 5     -*-*
; 6	-**-
; 7     -***

; 8	*---
; 9     *--*
; *     *-*-
; #     *-**

;Outputs used are Mon0, Mon1, Mon2, Mon3

MainLoop
	GoSub	KeyScan
	Gosub	ProcessKey
	Goto	MainLoop

;------------------------------------------
;Subroutine to process any key that has been pressed
ProcessKey
	Recall	KeyPressed
	RetIfZ			;r/no key
	LoadX	F
	Store	KeyPressed	;clear flag to signal the key has been "used"
	Recall	KeyCode
	Branch			;separate code for each key
	Target	PK0
	Target	PK1
	Target	PK2
	Target	PK3

	Target	PK4
	Target	PK5
	Target	PK6
	Target	PK7

	Target	PK8
	Target	PK9
	Target	PK10
	Target	PK11
PK0
	OFF	Mon0	
	OFF	Mon1	
	OFF	Mon2	
	OFF	Mon3	
	Return
PK1
	ON 	Mon0	
	OFF	Mon1	
	OFF	Mon2	
	OFF	Mon3	
	Return
PK2
	OFF	Mon0	
	ON 	Mon1	
	OFF	Mon2	
	OFF	Mon3	
	Return
PK3
	ON 	Mon0	
	ON 	Mon1	
	OFF	Mon2	
	OFF	Mon3	
	Return
PK4
	OFF	Mon0	
	OFF	Mon1	
	ON 	Mon2	
	OFF	Mon3	
	Return
PK5
	ON 	Mon0	
	OFF	Mon1	
	ON 	Mon2	
	OFF	Mon3	
	Return
PK6
	OFF	Mon0	
	ON 	Mon1	
	ON 	Mon2	
	OFF	Mon3	
	Return
PK7
	ON 	Mon0	
	ON 	Mon1	
	ON 	Mon2	
	OFF	Mon3	
	Return
PK8
	OFF	Mon0	
	OFF	Mon1	
	OFF	Mon2	
	ON 	Mon3	
	Return
PK9
	ON 	Mon0	
	OFF	Mon1	
	OFF	Mon2	
	ON 	Mon3	
	Return
PK10
	OFF	Mon0	
	ON 	Mon1	
	OFF	Mon2	
	ON 	Mon3	
	Return
PK11
	ON 	Mon0	
	ON 	Mon1	
	OFF	Mon2	
	ON 	Mon3	
	Return
;===================================================================
;**************  KEYSCAN FUNCTION **********************************
;===================================================================
;Main (and only) entry point
KeyScan
	Recall		KeyScanState
	Branch
	Target		Key0	;looking for key 0
	Target		Key1	;looking for key 1
	Target		Key2	;looking for key 2
	Target		Key3	;looking for key 3
	Target		Key4	;looking for key 4
	Target		Key5	;looking for key 5
	Target		Key6	;looking for key 6
	Target		Key7	;looking for key 7
	Target		Key8	;looking for key 8
	Target		Key9	;looking for key 9
	Target		Key10	;looking for key *
	Target		Key11	;looking for key #
	Target		Key12	;100mS debounce timing
	Target		Key13	;Waiting for no input
	Target		Key14	;Waiting for last key to be used by client


;----------------------------------------------
;States 0 to 11 are each coded to look for one particular key
;(input output combination)
Key0
	On	KeyOut1
	InputF	KeyIn3
	GoIFNZ	KeyFound
	GoTo	KeyNotFound
Key1
	On	KeyOut0
	InputF	KeyIn0
	GoIFNZ	KeyFound
	GoTo	KeyNotFound
Key2
	On	KeyOut1
	InputF	KeyIn0
	GoIFNZ	KeyFound
	GoTo	KeyNotFound
Key3
	On	KeyOut2
	InputF	KeyIn0
	GoIFNZ	KeyFound
	GoTo	KeyNotFound
Key4
	On	KeyOut0
	InputF	KeyIn1
	GoIFNZ	KeyFound
	GoTo	KeyNotFound
Key5
	On	KeyOut1
	InputF	KeyIn1
	GoIFNZ	KeyFound
	GoTo	KeyNotFound
Key6
	On	KeyOut2
	InputF	KeyIn1
	GoIFNZ	KeyFound
	GoTo	KeyNotFound
Key7
	On	KeyOut0
	InputF	KeyIn2
	GoIFNZ	KeyFound
	GoTo	KeyNotFound
Key8
	On	KeyOut1
	InputF	KeyIn2
	GoIFNZ	KeyFound
	GoTo	KeyNotFound
Key9
	On	KeyOut2
	InputF	KeyIn2
	GoIFNZ	KeyFound
	GoTo	KeyNotFound
Key10
	On	KeyOut0
	InputF	KeyIn3
	GoIFNZ	KeyFound
	GoTo	KeyNotFound
Key11
	On	KeyOut2
	InputF	KeyIn3
	GoIFNZ	KeyFound
	GoTo	KeyNotFound

;---------------------------------------------------
;The key just tested was off.
; Turn off all outputs (its easier to turn them all 
; off blindly than to be smart and turn off only the
; one which is on!!!)
;
KeyNotFound
	OFF	KeyOut0
	OFF	KeyOut1
	OFF	KeyOut2

;Now figure out the next keycode/state number.
;This is done by testing for zero and then either
;counting down or resetting the state to 11. This
;gives scanning 11-10-9-8 ...3-2-1-0, which is fine.

	Recall	KeyScanState
	GoIfZ	DoneZeroKey
	Recall	KeyScanState
	DECX
SaveKeyState
	Store	KeyScanState
	RETURN			; to the client we are just a gosub
DoneZeroKey
	LoadX	11
	GoTo	SaveKeyState

;-----------------------------------------------------
;Have just detected a key. KeyScanState tells us which key
KeyFound
	ON	KeyBlink	;for demo only
	Recall	KeyScanState
	Store	KeyCode		;make key code available to client
	LoadX	T
	Store	KeyPressed	;signal to client that a key was pressed

	SetTimer KeyTimer,1 	;100mS debounce timer

;Turn all outputs on
	ON	KeyOut0
	ON 	KeyOut1
	ON 	KeyOut2
	
	LoadX	12		;state number for time delay
	GoTo	SaveKeyState	;done for now

;-----------------------------------------------------
;Waiting for 100mS debounce time to elapse
Key12
	Test	KeyTimer
	RetIfNZ			;r/ if not timed out
	OFF	KeyBlink	;demo
	LoadX	13		;go to nest state
	Goto	SaveKeyState

;-----------------------------------------------------
;Waiting for all keys to be off
Key13
	Input	KeyIn0
	Input	KeyIn1
	OR
	Input	KeyIn2
	OR
	Input	KeyIn3
	OR
	RetIfNZ			;do nothing more if any key is on

;Now the debounce is done we can turn outputs off
	OFF	KeyOut0
	OFF	KeyOut1
	OFF	KeyOut2

	LoadX	14		;go to next state
	Goto	SaveKeyState
;------------------------------------------------------
;Waiting for client to use up the key
Key14
	Recall	KeyPressed
	RetIfNZ			;do nothing if client not yet reset flag
	
	LoadX	0		;go back to scanning
	Goto	SaveKeyState
