;
; keysleds.inc: key and led handling
;
; Lights up the leds in ledbus according to
;  the bits in memory location leds_busa_1, 
;  leds_busa_2 and leds_busb_1. Additionally
;  reads the pressed key from keybus. The pressed 
;  key is stored in memory location last_key as
;  a key code defined in constants.h.
;
; author: Marko Kanala, raato ]a t[ mulletronic.com
;
; LICENSE
; Creative Commons Attribution-NonCommercial-ShareALike 2.5
;
; You are free:
;
; * to copy, distribute, display, and perform the work
; * to make derivative works
;
; Under the following conditions:
;	
; 1. Attribution. You must attribute the work in the manner specified by the 
;    author or licensor.
; 2. Noncommercial. You may not use this work for commercial purposes.
; 3. Share Alike. If you alter, transform, or build upon this work, you may 
;    distribute the resulting work only under a license identical to this one.
;
; * For any reuse or distribution, you must make clear to others the license 
;   terms of this work.
; * Any of these conditions can be waived if you get permission from the 
;   copyright holder.
;
; Your fair use and other rights are in no way affected by the above.
;
; This is a human-readable summary of the Legal Code.
; See full license at http://creativecommons.org/licenses/by-nc-sa/2.5/legalcode
;
; Copyright: Marko Kanala (raato@mulletronic.com).
;

do_keysleds:
	; call pattern display 12 times / column to light up the
	;  pattern display leds
	; note: pattern display column mux
	;	 	 is tied to same port as key/led mux
	decf	led_scaler
	bn		change_led_column
	bra		do_patterndisplay

change_led_column:
	btfss	PORT_KEYBUS, KEYBUS_A_PIN
	bra		check_key_b

	; decode keybus a
	movlw	KEY_S1	    		; bus a starts from step key 1
	addwf	led_counter, W
	; store pressed key in bus a
	movwf	irq_key

check_key_b:
	btfss	PORT_KEYBUS, KEYBUS_B_PIN
	bra		keys_checked
	; key in keybus b was pressed

	; decode keybus b
	movlw	KEY_BANKA			; bus b starts from bank a key
	addwf	led_counter, W

	movwf	lp_irq_temp			; store to temp
	; check specially for keys that can be held down
	movlw	KEY_SHIFTFUNC
	cpfseq	lp_irq_temp			; is the bus b key shift ?
	bra		not_shift
	bsf		irq_downkey, DOWNKEY_SHIFTFUNC
	bra		keys_checked
not_shift:
	movlw	KEY_CLEAR			; clear ?
	cpfseq	lp_irq_temp
	bra		not_clear
	bsf		irq_downkey, DOWNKEY_CLEAR
	bra		keys_checked
not_clear:
	movlw	KEY_LASTSTEP		; laststep?
	cpfseq	lp_irq_temp
	bra		not_laststep
	bsf		irq_downkey, DOWNKEY_LASTSTEP
	bra		keys_checked
not_laststep:
	movlw	KEY_INSTRSEL		; instrsel ?
	cpfseq	lp_irq_temp
	bra		not_instrsel
	bsf		irq_downkey, DOWNKEY_INSTRSEL
	bra		keys_checked
not_instrsel:
	movlw	KEY_SHUFFLEFLAM		; shuffleflam ?
	cpfseq	lp_irq_temp
	bra		not_downkey
	bsf		irq_downkey, DOWNKEY_SHUFFLEFLAM
	bra		keys_checked

	; note: downkeys do NOT generate key events
	;        and must be checked separately if so
	;        desired
not_downkey:
	; store pressed key in bus b
	movff	lp_irq_temp, irq_key

keys_checked:
	; if we're in the last key of the bus process the keypress(es)
	movlw	15
	cpfseq	led_counter
	bra		keys_done

	; compare the current key with last key
	movlw	KEY_NONE		; key pressed ?
	xorwf	irq_key, W
	btfsc	STATUS, Z
	bra		irq_no_key		; nope

	movf	irq_key, W		; new key pressed ?
	xorwf	last_key, W
	btfsc	STATUS, Z
	bra		lk_no_new_key	; nope
	; current key differs
	movf	irq_key, W
	movwf	last_key
	movwf	keypress
	; generate key event
	bsf		event, EVENT_KEY
	bra		irq_keycheckdone

irq_no_key:
	clrf	last_key		; no key was pressed
	clrf	keypress
	bra		irq_keycheckdone

lk_no_new_key:
	clrf	irq_key			; no NEW key was pressed

irq_keycheckdone:
	; get the pressed downkeys
	movff	irq_downkey, downkeys
	; clear downkey temp for next round
	clrf	irq_downkey

keys_done:
	; increment led counter and rollover at 16
	incf	led_counter
	movlw	16
	cpfslt	led_counter
	; last led / key
	clrf	led_counter

	; reset pattern display scaler counter
	movlw	11
	movwf	led_scaler
;	bsf		port_ledbus, pat_disp_lit_pin ; clear lit pd

	movlw	-8
	addwf	led_counter, W		; W = led_counter - 8
	bn		first_half

	; second half of the leds
	lfsr	FSR0, leds_busa_2
	bra		go_leds

first_half:
	; check for lit leds in first half
	lfsr	FSR0, leds_busa_1
	movf	led_counter, W		; W = led_counter

go_leds:
	call	get_bit
	movwf	led_counter_tmp		; store "bit-byte"

	; switch off bus a led
	bsf		PORT_LEDBUS, LEDBUS_A_PIN
	
	; W = bit, note that we advance to bus b with post-increment
	andwf	POSTINC0, W
	bz		bus_a_not_lit

	; led lit in bus a
	bcf		PORT_LEDBUS, LEDBUS_A_PIN

bus_a_not_lit:
	movf	led_counter_tmp, W

	; switch off bus b led
	bsf		PORT_LEDBUS, LEDBUS_B_PIN

	; W = bit
	andwf	INDF0, W
	bz		bus_b_not_lit

	; led lit in bus b
	bcf		PORT_LEDBUS, LEDBUS_B_PIN

bus_b_not_lit:

	; retain upper 4 bits of led mux (pattern display) and
	;  select the correct column from led 4067
	swapf	led_scaler, W
	iorwf	led_counter, W
	movwf	LAT_LEDMUX

	; set pattern display immediately on column change
	bra		do_patterndisplay

External Labels :

get_bit