;
; lcd.inc: 16x2 led display handling routines
;
; displaytech 162 specified:
;  "Clear" and "Return home" commands - 1.64ms
;  Other commands ~50us
;  Enable pulse atleast 220ns
;  Enable cycle atleast 500ns
;
; 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).
;

;
; lcd screens
s_none			equ		0		; empty lcd
s_pw_main		equ		1		; pattern write / default
s_pw_instrsel	equ		2		;  - / instrument select pressed
s_pw_laststep	equ		3		;  - / last step pressed
s_pw_clear		equ		4		;  - / clear pressed
s_pw_shuffleflam	equ	5		;  - / shuffle/flam pressed
s_pw_scale		equ		6		;  - / scale pressed
s_pw_laststepinstr	equ	7		;  - / last step + instrsel pressed
s_pw_cleardone	equ		8		;  - / instrument cleared

s_pw_pattbuffered equ	9		;  - / pattern copied to buffer
s_pw_pattpasted	equ		10		;  - / pattern copied from buffer
s_pw_instrbuffered equ	11		;  - / instrument copied to buffer
s_pw_instrpasted equ	12		;  - / instrument copied from buffer
s_pw_instrrandomized equ 13		;  - / instrument randomized
s_pw_instrrold	equ		14		;  - / instrument rol:led
s_pw_instrrord	equ		15		;  - / instrument ror:red
s_pw_pattrold	equ		16		;  - / pattern rol:led
s_pw_pattrord	equ		17		;  - / pattern ror:red
s_pw_entername	equ		18		;  - / enter pattern name

s_pp_main		equ		20		; pattern play / default
s_pp_chaincleared equ	21		; - / chain cleared
s_pp_setchain	equ		22		; - / set chain

s_pattdump		equ		30		; pattern dumped
s_memdump		equ		31		; memory dumped

s_tp_main		equ		40		; track play / default

s_tw_main		equ		50		; track write / default
s_tw_clearconfirm equ	51		; - / confirm track clear
s_tw_trackcleared equ	52		; - / track cleared
s_tw_measureinserted equ 53		; - / measure inserted
s_tw_entername	equ		54		; - / enter track name
s_tw_measuredeleted equ 55		; - / measure deleted

s_s_main:		equ		56		; settings / default

s_sysex				equ 60		; receiving sysex
s_sysexdone			equ 61		; sysex done
;
; refreshes the lcd display according
;  to the currentdisplay variable
;
lcd_refresh:
	; skip checks if display hasn't been changed
	DISPLAYNOTCHANGED	lcd_refresh_nc
	; handle different displays
	DISPLAY	s_pw_main, pw_lcd_main
	DISPLAY s_pw_instrsel, pw_lcd_instrsel
	DISPLAY s_pw_laststep, pw_lcd_laststep
	DISPLAY s_pw_clear, pw_lcd_clear
	DISPLAY s_pw_shuffleflam, pw_lcd_shuffleflam
	DISPLAY s_pw_scale, pw_lcd_scale
	DISPLAY s_pw_laststepinstr, pw_lcd_laststepinstr
	DISPLAY s_pw_cleardone, pw_lcd_clear_done
	DISPLAY	s_pp_main, pp_lcd_main
	DISPLAY	s_pp_chaincleared, pp_lcd_chaincleared
	DISPLAY	s_pp_setchain, pp_lcd_setchain
	DISPLAY	s_pattdump, px_lcd_pattdump
	DISPLAY s_memdump, px_lcd_memdump
	DISPLAY s_pw_pattbuffered, pw_lcd_pattbuffered
	DISPLAY s_pw_pattpasted, pw_lcd_pattpasted
	DISPLAY s_pw_instrbuffered, pw_lcd_instrbuffered
	DISPLAY s_pw_instrpasted, pw_lcd_instrpasted
	DISPLAY s_pw_instrrandomized, pw_lcd_instrrandomized
	DISPLAY s_pw_instrrold, pw_lcd_instrrold
	DISPLAY s_pw_instrrord, pw_lcd_instrrord
	DISPLAY s_pw_pattrold, pw_lcd_pattrold
	DISPLAY s_pw_pattrord, pw_lcd_pattrord
	DISPLAY s_tp_main, tp_lcd_main
	DISPLAY s_tw_main, tw_lcd_main
	DISPLAY s_tw_clearconfirm, tw_lcd_clearconfirm
	DISPLAY s_tw_trackcleared, tw_lcd_trackcleared
	DISPLAY s_tw_measureinserted, tw_lcd_measureinserted
	DISPLAY s_pw_entername, pw_lcd_entername
	DISPLAY s_tw_entername, tw_lcd_entername
	DISPLAY s_tw_measuredeleted, tw_lcd_measuredeleted
	DISPLAY	s_sysex, lcd_sysex
	DISPLAY	s_sysexdone, lcd_sysexdone
	DISPLAY	s_s_main, s_lcd_main

lcd_refresh_nc:
	return

; pattern write / default display
pw_lcd_main:
	; A01:Pattern name
	movlw	0
	call	lcd_set_cursor
	movf	currentbank, W
	addlw	"A"					; "A"
	call	lcd_send_char
	incf	currentpattern, W
	call	lcd_send_bcd		; "01"
	movlw	":"
	call	lcd_send_char		; ":"
	lfsr	FSR1, pat_name
	IFMODE	MODE_FILL, pw_lcd_main_fill
	movlw	12					; pad name to 12 chars
	; "Pattern name"
	call	lcd_send_text_fsr1
pw_lcd_main_cont:
	TABLE_ADDR	text_patternwrite2
	call	lcd_send_text		; "W/"
	call	lcd_send_instrument	; print instrument name
	IFMODE	MODE_FLAMWRITE, pw_lcd_main_flam
	call	lcd_send_bpm		; bpm
	DISPLAYREFRESHED
	return
pw_lcd_main_fill:
	movlw	6					; only 6 chars of name
	; "Patter[Fill]"
	call	lcd_send_text_fsr1
	TABLE_ADDR	text_fill
	call	lcd_send_text		; "[Fill]"
	bra 	pw_lcd_main_cont
pw_lcd_main_flam:
	; "W/Bass dru[Flam]"
	TABLE_ADDR	text_flam
	call	lcd_send_text
	DISPLAYREFRESHED
	return

; pattern write / pattern copied to buffer
pw_lcd_pattbuffered:
	btfsc	mode, MODE_FILL
	bra		pw_pattbuffered_fill
	TABLE_ADDR	text_pattbuffered1
	bra		pw_pattbuffered_cont
pw_pattbuffered_fill:
	TABLE_ADDR	text_pattbuffered1fill
pw_pattbuffered_cont:
	call	lcd_send_text
	TABLE_ADDR	text_pattbuffered2
	call	lcd_send_text
	DISPLAYREFRESHED
	DISPLAYDELAY time_lcd_medium
	return

; pattern write / pattern pasted from buffer
pw_lcd_pattpasted:
	TABLE_ADDR	text_pattpasted1
	call	lcd_send_text
	btfsc	mode, MODE_FILL
	bra		pw_pattpasted_fill
	TABLE_ADDR	text_pattpasted2
	bra		pw_pattpasted_cont
pw_pattpasted_fill:
	TABLE_ADDR	text_pattpasted2fill
pw_pattpasted_cont:
	call	lcd_send_text
	DISPLAYREFRESHED
	DISPLAYDELAY time_lcd_medium
	return

; pattern write / instrument copied to buffer
pw_lcd_instrbuffered:
	movlw	LCD_LINE1
	call	lcd_set_cursor
	call	lcd_send_instrument	; Instrument
	btfss	mode, MODE_FILL
	bra		pw_instrbuffered_nonfill
	TABLE_ADDR	text_fill
	call	lcd_send_text		;          [Fill]
	bra		pw_instrbuffered_line2
pw_instrbuffered_nonfill:
	movlw	4					; pad with 4 blanks if not in fill mode
	call	lcd_send_blanks
pw_instrbuffered_line2:
	TABLE_ADDR	text_instrbuffered2
	call	lcd_send_text
	DISPLAYREFRESHED
	DISPLAYDELAY time_lcd_medium
	return

; pattern write / instrument pasted from buffer
pw_lcd_instrpasted:
	TABLE_ADDR	text_instrpasted1
	call	lcd_send_text			; Buffer pasted to
	movlw	LCD_LINE2
	call	lcd_set_cursor
	call	lcd_send_instrument		; Bass drum
	btfss	mode, MODE_FILL
	bra		pw_instrpasted_nonfill
	TABLE_ADDR	text_fill2
	call	lcd_send_text			;           [Fill]
	bra		pw_instrpasted_cont
pw_instrpasted_nonfill:
	movlw	6					; pad with 4 blanks if not in fill mode
	call	lcd_send_blanks
pw_instrpasted_cont:
	DISPLAYREFRESHED
	DISPLAYDELAY time_lcd_medium
	return

; pattern write / instrument randomized
pw_lcd_instrrandomized:
	movlw	LCD_LINE1
	call	lcd_set_cursor
	call	lcd_send_instrument	; Instrument
	btfss	mode, MODE_FILL
	bra		pw_instrrandomized_nonfill
	TABLE_ADDR	text_fill
	call	lcd_send_text		;          [Fill]
pw_instrrandomized_nonfill:
	TABLE_ADDR	text_instrrandomized2
	call	lcd_send_text
	DISPLAYREFRESHED
	DISPLAYDELAY time_lcd_medium
	return

; pattern write / instrument rotated left
pw_lcd_instrrold:
	movlw	LCD_LINE1
	call	lcd_set_cursor
	call	lcd_send_instrument	; Instrument
	btfss	mode, MODE_FILL
	bra		pw_instrroldfill
	TABLE_ADDR	text_fill
	call	lcd_send_text		;          [Fill]
pw_instrroldfill:
	TABLE_ADDR	text_instrrold2
	call	lcd_send_text
	DISPLAYREFRESHED
	DISPLAYDELAY time_lcd_medium
	return

; pattern write / instrument rotated right
pw_lcd_instrrord:
	movlw	LCD_LINE1
	call	lcd_set_cursor
	call	lcd_send_instrument	; Instrument
	btfss	mode, MODE_FILL
	bra		pw_instrrordfill
	TABLE_ADDR	text_fill
	call	lcd_send_text		;          [Fill]
pw_instrrordfill:
	TABLE_ADDR	text_instrrord2
	call	lcd_send_text
	DISPLAYREFRESHED
	DISPLAYDELAY time_lcd_medium
	return

; pattern write / pattern rotated left
pw_lcd_pattrold:
	btfsc	mode, MODE_FILL
	bra		pw_pattrold_fill
	TABLE_ADDR	text_pattrold1
	bra		pw_pattrold_cont
pw_pattrold_fill:
	TABLE_ADDR	text_pattrold1fill
pw_pattrold_cont:
	call	lcd_send_text
	TABLE_ADDR	text_pattrold2
	call	lcd_send_text
	DISPLAYREFRESHED
	DISPLAYDELAY time_lcd_medium
	return

; pattern write / pattern rotated right
pw_lcd_pattrord:
	btfsc	mode, MODE_FILL
	bra		pw_pattrord_fill
	TABLE_ADDR	text_pattrord1
	bra		pw_pattrord_cont
pw_pattrord_fill:
	TABLE_ADDR	text_pattrord1fill
pw_pattrord_cont:
	call	lcd_send_text
	TABLE_ADDR	text_pattrord2
	call	lcd_send_text
	DISPLAYREFRESHED
	DISPLAYDELAY time_lcd_medium
	return

; pattern write / enter pattern name
pw_lcd_entername:
	; A01:Pattern name
	movlw	0
	call	lcd_set_cursor
	movf	currentbank, W
	addlw	"A"					; "A"
	call	lcd_send_char
	incf	currentpattern, W
	call	lcd_send_bcd		; "01"
	movlw	":"
	call	lcd_send_char		; ":"
	lfsr	FSR1, pat_name
	movlw	12					; pad name to 12 chars
	; "Pattern name"
	call	lcd_send_text_fsr1
	TABLE_ADDR	text_entername
	call	lcd_send_text		; "Enter to save   "
	DISPLAYREFRESHED
	return

; pattern write / instrument select pressed
pw_lcd_instrsel:
	TABLE_ADDR	text_instrsel
	call	lcd_send_text		; Select instr.
	bra 	pw_lcd_main_cont	; second line as with main

; pattern write / last step pressed
pw_lcd_laststep:
	TABLE_ADDR	text_laststep
	call	lcd_send_text		;   Last step: xx
	LENGTHTOW	1
	call	lcd_send_bcd
	bra 	pw_lcd_main_cont	; second line as with main

; pattern write / last step + instrument select pressed
pw_lcd_laststepinstr:
	TABLE_ADDR	text_laststep_instr
	call	lcd_send_text		; "Instr. last step"
	movlw	LCD_LINE2
	call	lcd_set_cursor
	movlw	" "
	call	lcd_send_char
	movlw	" "
	call	lcd_send_char
	call	lcd_send_instrument	; "  Snare drum: xx"
	movlw	":"
	call	lcd_send_char
	movlw	" "
	call	lcd_send_char
	; get instrument last step to W using
	;  FSR1 and temp
	movf	selectedinst, W
	INSTRLENGTHTOW	1, temp		
	call	lcd_send_bcd
	DISPLAYREFRESHED
	return

; pattern write / shuffle flam pressed
pw_lcd_shuffleflam:
	TABLE_ADDR text_shuffleflam
	call	lcd_send_text		;      Shuffle: x
	SHUFFLETOW	1
	call	lcd_send_digit
	TABLE_ADDR text_shuffleflam2
	call	lcd_send_text		;         Flam: y
	FLAMTOW	1
	call	lcd_send_digit
	DISPLAYREFRESHED
	return

; pattern write / clear pressed
pw_lcd_clear:
	IFRUNNING	pw_lcd_clear_running
	; sequencer stopped, show info text
	TABLE_ADDR	text_clear_stop
	call	lcd_send_text		; Select instr.
	TABLE_ADDR	text_clear_stop2
	call	lcd_send_text		;  to clear
	DISPLAYREFRESHED
	return
pw_lcd_clear_running:
	TABLE_ADDR	text_clear_run
	call	lcd_send_text
	call	lcd_refreshbpm
	DISPLAYREFRESHED
	return

; pattern write / instrument cleared in stop mode
; Note: display_arg should specify the instrument
;        index of the cleared instrument.
pw_lcd_clear_done:
	movlw	LCD_LINE1
	call	lcd_set_cursor
	movf	display_arg, W
	call	lcd_send_instrument_wreg	; "Snare drum"
	clrf	display_arg
	movlw	6
	call	lcd_send_blanks				; "Snare drum      "
	TABLE_ADDR	text_clear_stop_done2
	call	lcd_send_text				; " ... cleared!   "
	DISPLAYREFRESHED
	call	lcd_delay_short
	return

; pattern write / scale pressed
pw_lcd_scale:
	TABLE_ADDR text_scale
	call	lcd_send_text		; Selected scale:

;	movlw	LCD_LINE2
;	call	lcd_set_cursor
;	movlw	1
;	call	lcd_send_bcd
;	movlw	LCD_LINE2 + 6
;	call	lcd_set_cursor	
;	SCALETOW	1
;	call	lcd_send_bcd
;;	call	lcd_send_digit
;	DISPLAYREFRESHED
;	call	lcd_delay_medium
;	return

	; resolve selected scale
	SCALETOW	1
	movwf	temp
	movlw	SCALE_16
	cpfseq	temp
	bra 	pw_lcd_scale_not16
	; scale == 1/16th notes
	TABLE_ADDR text_scale_16
	bra 	pw_lcd_scale_line2
pw_lcd_scale_not16:
	movlw	SCALE_32
	cpfseq	temp
	bra 	pw_lcd_scale_not32
	; scale == 1/32th notes
	TABLE_ADDR text_scale_32
	bra 	pw_lcd_scale_line2
pw_lcd_scale_not32:
	movlw	SCALE_8TR
	cpfseq	temp
	bra 	pw_lcd_scale_not8tr
	; scale == 1/8th triplets
	TABLE_ADDR text_scale_8tr
	bra 	pw_lcd_scale_line2
pw_lcd_scale_not8tr:
	; scale must be 1/16th triplets
	TABLE_ADDR text_scale_16tr
pw_lcd_scale_line2:
	call	lcd_send_text		; 1/16 notes
	DISPLAYREFRESHED
	; wait for a bit
	call	lcd_delay_medium
	return

; pattern play / default display
pp_lcd_main:
	; A01:Pattern name
	movlw	0
	call	lcd_set_cursor
	movf	currentbank, W
	addlw	"A"					; "A"
	call	lcd_send_char
	incf	currentpattern, W
	call	lcd_send_bcd		; "01"
	movlw	":"
	call	lcd_send_char		; ":"
	lfsr	FSR1, pat_name
	IFMODE	MODE_FILL, pp_lcd_main_fill
	movlw	12					; pad name to 12 chars
	; "Pattern name"
	call	lcd_send_text_fsr1
pp_lcd_main_cont:
	; if next pattern != current pattern show (if running)
	;  "Next: A02   234b"
	IFNOTRUNNING pp_lcd_main_nonext
	movf	nextpattern, W
	cpfseq	currentpattern
	bra 	pp_lcd_main_next
	movf	nextbank, W
	cpfseq	currentbank
	bra 	pp_lcd_main_next
pp_lcd_main_nonext:
	movlw	LCD_LINE2
	call	lcd_set_cursor
	movlw	12
pp_lcd_main_nextcont:
	call	lcd_send_blanks
	call	lcd_send_bpm		; bpm
	DISPLAYREFRESHED
	return
pp_lcd_main_fill:
	movlw	6					; only 6 chars of name
	; "Patter[Fill]"
	call	lcd_send_text_fsr1
	TABLE_ADDR	text_fill
	call	lcd_send_text		; "[Fill]"
	bra 	pp_lcd_main_cont
pp_lcd_main_next:
	TABLE_ADDR	text_next
	call	lcd_send_text		; "Next: "
	movf	nextbank, W
	addlw	"A"					; "A"
	call	lcd_send_char
	incf	nextpattern, W
	call	lcd_send_bcd		; "02"
	movlw	3					; 3 blanks before bpm
	bra 	pp_lcd_main_nextcont

; pattern play / (chain cleared) scale pressed
pp_lcd_chaincleared:
	TABLE_ADDR text_chaincleared
	call	lcd_send_text		; Chain cleared!
	movlw	LCD_LINE2
	call	lcd_set_cursor
	movlw	12
	call	lcd_send_blanks
	call	lcd_send_bpm	
	DISPLAYREFRESHED
	; wait for a bit
	call	lcd_delay_medium
	return

; pattern play / (set chain) last step pressed
pp_lcd_setchain:
	TABLE_ADDR text_setchain
	call	lcd_send_text		;  Program chain:
	TABLE_ADDR text_setchain2
	call	lcd_send_text		; Step keys append
	DISPLAYREFRESHED
	return

; receiving sysex
lcd_sysex:
	TABLE_ADDR text_sysex
	call	lcd_send_text
	TABLE_ADDR text_sysex2
	call	lcd_send_text
	DISPLAYREFRESHED
	return

; sysex done
lcd_sysexdone:
	TABLE_ADDR text_sysexdone
	call	lcd_send_text
	TABLE_ADDR text_sysexdone2
	call	lcd_send_text
	DISPLAYREFRESHED
	DISPLAYDELAY time_lcd_long
	return

; pattern dump started
px_lcd_spattdump:
	TABLE_ADDR text_spattdump
	call	lcd_send_text		; Cur.pattern dump   
	TABLE_ADDR text_spattdump2
	call	lcd_send_text		; = Please wait! =
	DISPLAYREFRESHED
	return

; memory dump started
px_lcd_smemdump:
	TABLE_ADDR text_smemdump
	call	lcd_send_text		; Full memory dump    
	TABLE_ADDR text_smemdump2
	call	lcd_send_text		; = Please wait! =
	DISPLAYREFRESHED
	return

; pattern dumped
px_lcd_pattdump:
	TABLE_ADDR text_pattdump
	call	lcd_send_text		; Current pattern    
	TABLE_ADDR text_pattdump2
	call	lcd_send_text		;    sent to midi!
	DISPLAYREFRESHED
	DISPLAYDELAY time_lcd_long
	return

; memory dumped
px_lcd_memdump:
	TABLE_ADDR text_memdump
	call	lcd_send_text		; Full memory dump    
	TABLE_ADDR text_memdump2
	call	lcd_send_text		;    sent to midi!
	DISPLAYREFRESHED
	DISPLAYDELAY time_lcd_long
	return

; track play / default view
;
; T01:my demo song
; 001/003:A02   x2
tp_lcd_main:
	movlw	LCD_LINE1
	call	lcd_set_cursor
	movlw	"T"					; T
	call	lcd_send_char
	incf	currenttrack, W
	call	lcd_send_bcd		; T01
	movlw	":"
	call	lcd_send_char		; T01:
	lfsr	FSR1, track_name
	IFMODE	MODE_FILL, tp_lcd_main_fill
	movlw	12
	call	lcd_send_text_fsr1	; T01:my demo song
	bra		tp_lcd_main_cont
tp_lcd_main_fill:
	movlw	6					; only 6 chars of track name
	; "my dem[Fill]"
	call	lcd_send_text_fsr1
	TABLE_ADDR	text_fill
	call	lcd_send_text		; "[Fill]"
tp_lcd_main_cont:
	movlw	LCD_LINE2
	call	lcd_set_cursor
	lfsr	FSR1, currentmeasure
	call	lcd_send_bcd3_fsr1_inc	; 001
	movlw	"/"
	call	lcd_send_char		; 001/
	lfsr	FSR1, currenttracklen
	call	lcd_send_bcd3_fsr1	; 001/003
	movlw	":"
	call	lcd_send_char		; 001/003:
	movf	currentmeasuredata, W
	DECODE_BANK_FROM_MEASURE
	addlw	"A"
	call	lcd_send_char		; 001/003:A
	movf	currentmeasuredata, W
	DECODE_PATTERN_FROM_MEASURE
	incf	WREG
	call	lcd_send_bcd		; 001/003:A01
	movlw	3
	call	lcd_send_blanks
	movf	currentmeasuredata, W
	DECODE_REPEAT_FROM_MEASURE
	bz		tp_main_nor
	movlw	"x"
	call	lcd_send_char		; 001/003:A01   x
	movf	currentmeasuredata, W
	DECODE_REPEAT_FROM_MEASURE
	incf	WREG
	call	lcd_send_digit		; 001/003:A01   x2
tp_main_nor:
	movlw	2
	call	lcd_send_blanks
	DISPLAYREFRESHED
	return

; track write / default view
;
; Edit T01 001/002
; A02: pattern  x2
tw_lcd_main:
	TABLE_ADDR text_trackwrite
	call	lcd_send_text		; Edit
	movlw	"T"                 ; Edit T
	call	lcd_send_char
	incf	currenttrack, W
	call	lcd_send_bcd        ; Edit T01
	movlw	1
	call	lcd_send_blanks
	lfsr	FSR1, currentmeasure
	call	lcd_send_bcd3_fsr1_inc  ; Edit T01 001
	movlw	"/"
	call	lcd_send_char       ; Edit T01 001/
	lfsr	FSR1, currenttracklen
	call	lcd_send_bcd3_fsr1  ; Edit T01 001/003
	movlw	LCD_LINE2
	call	lcd_set_cursor
	movf	editedmeasuredata, W
	DECODE_BANK_FROM_MEASURE
	addlw	"A"
	call	lcd_send_char		; A
	movf	editedmeasuredata, W
	DECODE_PATTERN_FROM_MEASURE
	incf	WREG
	call	lcd_send_bcd		; A01
	movlw	":"
	call	lcd_send_char       ; A01:
	lfsr	FSR1, pat_name
	movf	editedmeasuredata, W
	DECODE_REPEAT_FROM_MEASURE
	bz		tw_main_nor			; no repeat ?
	movlw	9
	call	lcd_send_text_fsr1  ; A01:pattern n
	movlw	1
	call	lcd_send_blanks		; print 9 chars of pattern name
	movlw	"x"
	call	lcd_send_char       ; A01:pattern n x
	movf	editedmeasuredata, W
	DECODE_REPEAT_FROM_MEASURE
	incf	WREG
	call	lcd_send_digit      ; A01:pattern n x2
	DISPLAYREFRESHED
	return
tw_main_nor:
	movlw	12
	call	lcd_send_text_fsr1  ; A01:pattern name
	DISPLAYREFRESHED
	return

; track write / confirm track clear view
tw_lcd_clearconfirm:
	TABLE_ADDR	text_clearconfirm1
	call	lcd_send_text		; Clear track
	incf	currenttrack, W
	call	lcd_send_bcd		;             01
	movlw	1
	call	lcd_send_blanks
	movlw	'?'
	call	lcd_send_char		;                ?
	TABLE_ADDR	text_clearconfirm2
	call	lcd_send_text		; Enter to confirm
	DISPLAYREFRESHED
	return

; track write / track cleared view
tw_lcd_trackcleared:
	TABLE_ADDR	text_trackcleared1
	call	lcd_send_text		; Track
	incf	currenttrack, W
	call	lcd_send_bcd        ;       01
	movlw	8
	call	lcd_send_blanks
	TABLE_ADDR	text_trackcleared2
	call	lcd_send_text		;       cleared!
	DISPLAYREFRESHED
	DISPLAYDELAY time_lcd_medium
	return

; A01 inserted
;   to measure 003
tw_lcd_measureinserted:
	movlw	LCD_LINE1
	call	lcd_set_cursor
	movf	editedmeasuredata, W
	DECODE_BANK_FROM_MEASURE
	addlw	"A"
	call	lcd_send_char			; A
	movf	editedmeasuredata, W
	DECODE_PATTERN_FROM_MEASURE
	incf	WREG
	call	lcd_send_bcd			; A01
	TABLE_ADDR	text_measureinserted1
	call	lcd_send_text			;     inserted
	TABLE_ADDR	text_measureinserted2
	call	lcd_send_text			;   to measure 
	lfsr	FSR1, currentmeasure
	call	lcd_send_bcd3_fsr1_inc  ;              001
	DISPLAYREFRESHED
	DISPLAYDELAY time_lcd_short
	return

; track write / measure deleted
tw_lcd_measuredeleted:
	TABLE_ADDR	text_measuredeleted1	; Measure
	call	lcd_send_text
	TABLE_ADDR	text_measuredeleted2	;      deleted
	call	lcd_send_text
	DISPLAYREFRESHED
	DISPLAYDELAY time_lcd_short
	return

; track write / enter track name
tw_lcd_entername:
	; T01:Track name
	movlw	0
	call	lcd_set_cursor
	movlw	'T'
	call	lcd_send_char		; T
	incf	currenttrack, W
	call	lcd_send_bcd		; T01
	movlw	":"
	call	lcd_send_char		; T01:
	lfsr	FSR1, track_name
	movlw	12					; pad name to 12 chars
	; "Track name"
	call	lcd_send_text_fsr1
	TABLE_ADDR	text_entername
	call	lcd_send_text		; "Enter to save   "
	DISPLAYREFRESHED
	return

;
; "Din sync input ?"
; "             OFF"
;
s_lcd_main:
	; write selected setting to upper row
	movlw	0
	call	lcd_set_cursor
	TABLE_ADDR	text_settings
	swapf	selected_setting, W	; selected * 16
	addwf	TBLPTRL
	btfsc	STATUS, C
	incf	TBLPTRH
	call	lcd_send_text_nocursor	
	movf	select_pressed, W
	bz		s_lcd_main_noselect
	; select pressed
	TABLE_ADDR	text_settings_select
	call	lcd_send_text
	bra		s_lcd_main_done
s_lcd_main_noselect:
	; not in selection mode
	movlw	5					; 5 == "midi channel"
	cpfseq	selected_setting
	bra		s_lcd_main_notchannel
s_lcd_main_channel:
	; selected setting is midi channel
	movlw	LCD_LINE2
	call	lcd_set_cursor
	movlw	14
	call	lcd_send_blanks		; 14 blanks
	movf	settings_midi_channel, W
	call	lcd_send_bcd		; "01"
	bra		s_lcd_main_done
s_lcd_main_notchannel:
	; print out current on/off status of the setting
	movf	selected_setting, W
	call	get_bit
	andwf	settings, W
	bz		s_lcd_main_off
s_lcd_main_on:
	; setting is on
	TABLE_ADDR	text_settings_on
	call	lcd_send_text
	bra		s_lcd_main_done
s_lcd_main_off:
	; settings is off
	TABLE_ADDR	text_settings_off
	call	lcd_send_text
s_lcd_main_done:
	DISPLAYREFRESHED
	return



;
; =-> general lcd screen functions
;

LCD_LINE1	equ		0x00	; beginning of the line 1
LCD_LINE2	equ		0x40	; beginning of the line 2

;
; initializes lcd display
;
lcd_init:
	; we should wait for power up delay
	call	lcd_delay105ms

	; clear rs
	bcf		PORT_LCD, LCD_RS_PIN
	; set function
	movlw	b'00000011'			; 0x03
	call	lcd_send_nybble
	call	lcd_delay5ms		; wait for 5ms

	; set function, 2nd
	movlw	b'00000011'			; 0x03
	call	lcd_send_nybble
	call	lcd_delay2ms

	; set function, 3rd
	movlw	b'00000011'			; 0x03
	call	lcd_send_nybble
	call	lcd_delay2ms

	; set 4-bit mode
	movlw	b'00000010'			; 0x02
	call	lcd_send_nybble
	call	lcd_delay2ms

;
; we are now in 4-bit mode and commands
;  should work ok
;

	; 2x16 chars / font
	movlw	b'00101000'			; 0x28
	call	lcd_send_command
	call	lcd_delay2ms

	; auto-increment
	movlw	b'00000110'			; 0x06
	call	lcd_send_command
	call	lcd_delay2ms

	; set display on
	movlw	b'00001100'			; 0x0f (0x0d)
	call	lcd_send_command
	call	lcd_delay2ms

	; send cgram characters
	TABLE_ADDR	cgram
	movlw	0
	call	lcd_send_cgram

	; clear lcd
	call	lcd_clear
	call	lcd_delay2ms
	return

;
; set lcd cursor on
;
lcd_cursor_on:
	movlw	b'00001110'
	call	lcd_send_command
	call	lcd_delay2ms
	return

;
; set lcd cursor off
;
lcd_cursor_off:
	movlw	b'00001100'
	call	lcd_send_command
	call	lcd_delay2ms
	return

;
; clears lcd
;
lcd_clear:
	movlw	b'00000001'			; 0x01
	call	lcd_send_command
	call	lcd_delay2ms		; wait atleast 1.64ms
	return

;
; set lcd cursor position
;
lcd_set_cursor:
	iorlw	0x80
	call	lcd_send_command
	return

;
; sends text from table pointer (program memory)
;  to lcd
;
; the actual string must be preceeded
;  with a cursor position
; ie.
;  mytext:	db 0x40, "My text", 0
; 
;  goes to cursor position 0x40 (= second line)
lcd_send_text:
	; get cursor pos
	tblrd*+
	movf	TABLAT, W
lcd_send_text_posw:
	call	lcd_set_cursor
lcd_send_text_nocursor:
lcd_send_text_loop:
	tblrd*+					; get character
	movf	TABLAT, W
	bz		lcd_send_text_end	; end of string
	call	lcd_send_char		; send character
	bra 	lcd_send_text_loop
lcd_send_text_end:
	return

;
; sends blanks (" ") to lcd. Number
;  of blanks sent is specified with
;  WREG.
;
; bcd_temp and W are thrashed.
lcd_send_blanks:
	movwf	bcd_temp
lcd_send_blanks_loop:
	movlw	" "
	call	lcd_send_char
	decfsz	bcd_temp
	bra 	lcd_send_blanks_loop
	return

;
; sends text from FSR1 (data memory)
;  to lcd
;
; the number of characters to be written
;  should be loaded to WREG - string can
;  be terminated with 0 and then the 
;  output string is padded with whitespace
;  to match the length in WREG.
;
; thrashes bcd_temp
;
lcd_send_text_fsr1:
	movwf	bcd_temp
lcd_send_text_fsr1_loop:
	movf	POSTINC1, W				; get character
	bz		lcd_send_text_fsr1_end	; end of string
	call	lcd_send_char			; send character
	decfsz	bcd_temp
	bra 	lcd_send_text_fsr1_loop
lcd_send_text_fsr1_end:
	tstfsz	bcd_temp
	bra 	lcd_send_text_fsr1_pad
	return
lcd_send_text_fsr1_pad:
	; pad with whitespace for bcd_temp amount
	movlw	" "
	call	lcd_send_char
	decfsz	bcd_temp
	bra 	lcd_send_text_fsr1_pad
	return

;
; prints a char from WREG to lcd
;
lcd_send_char:
	bsf		PORT_LCD, LCD_RS_PIN	; rs to high on characters
	movwf	lcd_temp
	swapf	lcd_temp, W				; upper nybble first
	call	lcd_send_nybble
	movf	lcd_temp, W				; lower nybble
	call	lcd_send_nybble
	bcf		PORT_LCD, LCD_RS_PIN	; rs to low
	call	lcd_delay				; delay atleast 50us
	return

;
; prints a digit (lower 4 bits) from WREG to lcd
;
lcd_send_digit:
	andlw	0x0f			; %00001111
	addlw	-0x0a			; > 10 ?
	btfsc	STATUS, C
	addlw	0x07			; += 7 if > 10
	addlw	0x3a			; += 0x3a
	bra 	lcd_send_char

;
; encodes bcd from WREG and prints the result
;  to lcd
;
lcd_send_bcd:
	movwf	bcd_temp
	clrf	bcd_result_0
	swapf	bcd_temp, W 
	addwf	bcd_temp, W 
	andlw	0x0f
	btfsc	STATUS, DC
	addlw	0x16 
	btfsc	STATUS, DC
	addlw	0x06 
	addlw	0x06 
	btfss	STATUS, DC
	addlw	-0x06 

	btfsc	bcd_temp, 4
	addlw	0x16 - 1 + 0x6 
	btfss	STATUS, DC
	addlw	-0x06 

	btfsc	bcd_temp, 5 
	addlw	0x30 

	btfsc	bcd_temp, 6 
	addlw	0x60 

	btfsc	bcd_temp, 7 
	addlw	0x20 

	addlw	0x60 
	rlcf	bcd_result_0, F 
	btfss	bcd_result_0, 0 
	addlw	-0x60 

	movwf	bcd_result_1
	btfsc	bcd_temp,7 
	incf	bcd_result_0, F

	movf	bcd_result_1, W
	swapf	bcd_result_1, W
	call	lcd_send_digit
	movf	bcd_result_1, W
	call	lcd_send_digit
	return

;
; prints a 3 digit value from a two byte value in FSR1.
;
; for example if FSR1 points to 01 01 a value "257" is sent
; to the LCD. Note: supports only numbers between 0 - 511
;
; thrashes lcd_temp, bcd_temp
;
lcd_send_bcd3_fsr1:
	movff	POSTINC1, bcd_result_0
	movf	INDF1, W
	bra		lcd_send_bcd3_fsr1_s
; call this to print out value + 1
lcd_send_bcd3_fsr1_inc: 
	movff	POSTINC1, bcd_result_0
	infsnz	INDF1, W				; increment value from fsr1
	incf	bcd_result_0			;  to bcd_result_x by one
lcd_send_bcd3_fsr1_s:
	clrf    bcd_temp
	movwf	bcd_result_1
	movf	bcd_result_0, W
	bz      lcd_send_bcd3_fsr1_below256
	; 256 - 511
	incf    bcd_temp
	incf    bcd_temp
	movlw   56
	addwf   bcd_result_1, W         ; 210 -> 266 -> 10
	bnc     lcd_send_bcd3_fsr1_go
	incf    bcd_temp
	sublw   100
	bra     lcd_send_bcd3_fsr1_go    
lcd_send_bcd3_fsr1_below256:
	movf    bcd_result_1, W
lcd_send_bcd3_fsr1_go:
	movwf   lcd_temp                ; 0 - 255
	movlw   100
lcd_send_bcd3_fsr1_hundreds:
	subwf   lcd_temp                ; 0 - 155
	btfss	STATUS, C
	bra		lcd_send_bcd3_fsr1_fin
	incf    bcd_temp                ; +100
	bra     lcd_send_bcd3_fsr1_hundreds
lcd_send_bcd3_fsr1_fin:
	addwf   lcd_temp, W             ; 55
	movwf   bcd_result_0                
	movf    bcd_temp, W
	call    lcd_send_digit          ; "2..
	movf    bcd_result_0, W
	call    lcd_send_bcd            ; ..55"
	return

;
; prints out the name of the
;  currently selected instrument
;  to the current cursor position
;
; thrashes lcd_temp
lcd_send_instrument:
	movf	selectedinst, W
	bra 	lcd_send_instrument_wreg

;
; prints out the name of the specified
;  instrument to the current cursor
;  position
;
; instrument index is specified with
;  WREG.
;
; thrashes lcd_temp, bcd_temp
lcd_send_instrument_wreg:
	movwf	bcd_temp
	TABLE_ADDR	text_instruments
	rlncf	bcd_temp, W		; * 2
	rlncf	WREG				; * 4
	movwf	lcd_temp
	rlncf	bcd_temp, W
	addwf	lcd_temp			; * 6
	rlncf	lcd_temp, W			; * 12
	addwf	TBLPTRL
	btfsc	STATUS, C
	incf	TBLPTRH
	; TBLPTR == instr text
	call	lcd_send_text_nocursor
	return


;
; refreshes the bpm (tempo var) to
;  lcd display if needed
;
lcd_refreshbpm:
	IFNOEVENT	EVENT_TEMPOCHANGE, lcd_no_tempo_changed
	; if in flam write mode the flam-text overwrites the bpm text
	IFMODE	MODE_FLAMWRITE, lcd_no_tempo_changed
	; tempo changed, redraw bpm counter
	call	lcd_send_bpm
	CLEAREVENT	EVENT_TEMPOCHANGE
lcd_no_tempo_changed:
	return

;
; prints out the bpm (tempo var) to lcd
;  lower right corner with "bpm" suffix
;
; note: if EVENT_DINRUN is set the 
;       bpm is not printed.
;
lcd_send_bpm:
	movlw	LCD_LINE2 + 12	; row 2, char 12
	call	lcd_set_cursor
	IFEVENT	EVENT_DINRUN, lcd_send_bpm_blanks
	clrf	bcd_result_0	; hundreds
	movf	tempo, W
	addlw	30			
	; tempo range 30 - 285
	; so tempo 0 == 30 bpm
	btfss	STATUS, C
	bra 	lcd_send_bpm_ok
	incf	bcd_result_0
	incf	bcd_result_0	; over 255, hundreds == 2
	addlw	56				; correction for overflow
lcd_send_bpm_ok:
	call	lcd_send_number_hundreds_set
	movlw	0				; "bpm" character
	call	lcd_send_char
	return
lcd_send_bpm_blanks:
	movlw	4
	call	lcd_send_blanks
	return
;
; encodes a number in W to three digit
;  decimal and send the number to lcd.
;
lcd_send_number:
	clrf	bcd_result_0	; hundreds
lcd_send_number_hundreds_set:
	movwf	bcd_temp
lcd_numb_find_pos:
	movf	bcd_temp, W
	bnn		lcd_below_128
	; number is over 128
	incf	bcd_result_0	; hundreds+=1
	movlw	100
	subwf	bcd_temp
	bra 	lcd_numb_find_pos
lcd_below_128:
	movlw	99
	cpfsgt	bcd_temp		; number > 99 ?
	bra 	lcd_below_100
	incf	bcd_result_0	; hundreds+=1
	decf	bcd_temp
	subwf	bcd_temp		; number -= 100
	bra 	lcd_below_128
lcd_below_100:
	tstfsz	bcd_result_0
	bra 	lcd_numb1
	movlw	" "				; pad with space if necessary
	call	lcd_send_char
	bra 	lcd_numb2
lcd_numb1:
	movf	bcd_result_0, W
	call	lcd_send_digit
lcd_numb2:
	movf	bcd_temp, W		; rest is below 100, "bcd-ready"
	call	lcd_send_bcd	
	return
	
; sends full 8 bit command from W to lcd in 4-bit mode
lcd_send_command:
	movwf	lcd_temp
	swapf	lcd_temp, W				; upper nybble first
	bcf		PORT_LCD, LCD_RS_PIN	; rs to low on commands
	call	lcd_send_nybble
	movf	lcd_temp, W				; lower nybble
	call	lcd_send_nybble
	call	lcd_delay				; delay atleast 50us
	return

;
; sends cgram data from tblptr to
;  cursor position in W
;
; note: thrashes bcd_temp
;
lcd_send_cgram:
	iorlw	0x40				; set cursor to cgram
	call	lcd_send_command
	movlw	8					; 8 rows / character
	movwf	bcd_temp	
lcd_cgram_loop:
	TBLRD*+
	movf	TABLAT, W
	call	lcd_send_char		; send character data
	decfsz	bcd_temp
	bra 	lcd_cgram_loop
	return

; sends 4 (low) bits from W to lcd
lcd_send_nybble:
	bcf		PORT_LCD, LCD_D7_PIN
	bcf		PORT_LCD, LCD_D6_PIN
	bcf		PORT_LCD, LCD_D5_PIN
	bcf		PORT_LCD, LCD_D4_PIN
	btfsc	WREG, 3
	bsf		PORT_LCD, LCD_D7_PIN
	btfsc	WREG, 2
	bsf		PORT_LCD, LCD_D6_PIN
	btfsc	WREG, 1
	bsf		PORT_LCD, LCD_D5_PIN
	btfsc	WREG, 0
	bsf		PORT_LCD, LCD_D4_PIN
	call	lcd_strobe
	return

; strobe lcd enable
lcd_strobe:
	bsf		PORT_LCD_EN, LCD_EN_PIN
	call	lcd_delay
	bcf		PORT_LCD_EN, LCD_EN_PIN
	call	lcd_delay
	return

;;; delay routines -->

;
; ~100us delay
;
lcd_delay:
	movlw	1
; custom delay, WREG * 256 iteration delay
lcd_delay_custom:
	movwf	lcd_delay_h
	clrf	lcd_delay_l
lcd_ldelay_loop:
	clrwdt					; 256 * 0.1us = 25.6us
	decfsz	lcd_delay_l		; 255 * 0.1us + 0.3us = 25.8us
	bra 	lcd_ldelay_loop	; 255 * 0.2us = 51us
							; =~ 102.4us / iteration
	decfsz	lcd_delay_h
	bra 	lcd_ldelay_loop
	return 					; =~ 

;
; ~105ms delay
;
lcd_delay105ms:
	call	lcd_delay15ms
	call	lcd_delay15ms
	call	lcd_delay15ms
	call	lcd_delay15ms
	call	lcd_delay15ms
	call	lcd_delay15ms
	call	lcd_delay15ms
	return

;
; ~15ms delay
;
lcd_delay15ms:
	movlw	146
	bra 	lcd_delay_custom

;
; ~5ms delay
;
lcd_delay5ms:
	movlw	49
	bra 	lcd_delay_custom

;
; ~1.8ms delay
;
lcd_delay2ms:
	movlw	18
	bra 	lcd_delay_custom

;
; ~0.5s delay, breaks with keypress
;
lcd_delay_short:
	bra 	lcd_delay_long2

;
; ~1s delay, breaks with keypress
;
lcd_delay_medium:
	call	lcd_delay_long2
	bra 	lcd_delay_long2

;
; ~1.5s long delay, breaks with keypress
;
lcd_delay_long:
	call	lcd_delay_long2
	call	lcd_delay_long2
	bra 	lcd_delay_long2

; help decay, breaks with keypress
;lcd_delay_help:
;	bra 	lcd_delay_long2

; waits ~520ms or keypress
lcd_delay_long2:
	clrf	lcd_delay_z
lcd_ldelay_long_loop:
	; if no key is pressed just delay
	IFNOEVENTCALL	EVENT_KEY, lcd_delay2ms	
	decfsz	lcd_delay_z
	bra 	lcd_ldelay_long_loop
	return


External Labels :

lcd_set_cursor
lcd_send_char
lcd_send_bcd
lcd_send_text_fsr1
lcd_send_text
lcd_send_instrument
lcd_send_bpm
lcd_send_blanks
lcd_send_digit
lcd_refreshbpm
lcd_send_instrument_wreg
lcd_delay_short
lcd_delay_medium
lcd_send_bcd3_fsr1_inc
lcd_send_bcd3_fsr1
lcd_send_text_nocursor
get_bit
lcd_delay105ms
lcd_send_nybble
lcd_delay5ms
lcd_delay2ms
lcd_send_command
lcd_send_cgram
lcd_clear
lcd_delay
lcd_send_number_hundreds_set
lcd_strobe
lcd_delay15ms
lcd_delay_long2