; *************
; *Drumtrigger*
; *************
;
; Purpose:
; a circuit to use as an elecronic drumset
; 4 channels only - this is meant to be an addition to existing drumsets.
; Project converts signals from electronic drumpads to Midi signals only
; No sounds are produced. This is done by a connected drum-expander or
; other means which has MIDI-In capabilities.
;
; Stephan Asmus, Germany
; info@sasmus.de
; 
; This software is free for personal, non commercial use. 
; You are allowed to distribute this software or reuse parts of it under
; the same conditions. You have to name the original author, however.
; You are not allowed to make profit in reusing this software or parts
; of it.
;
; History of development:
; 2008
; Start: 03.9.2008 :framework
; 12.9. first initial version after initial tests
; 15.9.	isr routines outlined, begin testing
; 16.9. isr working
; 25.9. begin with display and menu programming
; 27.9. Feedback of Drumhits on display ready
; 28.9. Main Menu and keyhandling
; 02.10. Main menu working, begin implementing menu functions
;		 Exit, Treshold, Reset working
; 04.10. Midi_channel, Retrigger working, note assignment working
; 06.10. load/save config working
; 07.10. Midi activity LED working
; 07.10. ready for 1st release
; Version 0.2
; 2010
; 02.04. New ad isr for better peak detection, gain menu added
; 07.04. Velocity curve menu added
; 11.04. Velocity curves added 
; 12.04. Velocity curves finished
; 
;
;
; Used Processor: PIC 16F690
; Pins & Ports:
; RC0..RC3: 	LCD-Display Bus
; RC4:			LCD-Display RS
; RC5:			LCD-Display Enable; R/W wired to low (all write)
; RA0..RA2		Analog inputs from Drumpads Channel 1..3
; RB4			Analog input from Drumpad Channel 4
; RB5..RB6		Digital Input Keys
; RB7			Midi Transmit
; RC7			Midi Activity LED
; RA4..RA5		Crystal 20MHz
; RA3			unused
; RC6			unused
; see schematics for more details 
;
;Asssuming Fosc=20MHz
	
	LIST   P=PIC16F690

	#include <p16f690.inc> 

errorlevel  -302		;No bank select warnings

	__config (_HS_OSC & _WDT_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _BOD_OFF & _IESO_OFF & _FCMEN_OFF) 
;----------------------------------------------------------------
;variables
w_temp		EQU	0x20    ; used for context saving Register "W"
status_temp	EQU	0x21    ; used for context saving Register "Status"
pclath_temp	equ	0x22	; used for context saving Register "PCLATH"
pclath_save	equ 0x23	;used to save pclath within computed gotos
	cblock 0x24
	d1				;Delay-Variable 1	
	d2				;Delay-Variable 2
	d3
	Dispdata		;holds Dislay Data
	keydata			;status of keys
	ADresult		;holds Result of a AD-Conversion
	midi_chan		;midi-channel (0..15)
	midi_note		;holds current Note To Play
	midi_note_tmp	;temporary for routine Assign_midi_chan
	chan_tmp
	offset			;holds offset for veloc curves
	midi_veloc		;holds current velocity to play
	
	note1			;value of Midi note per channel
	note2
	note3
	note4
	treshold		;treshold value
	retrig1			;retrigger value per channel
	retrig2
	retrig3
	retrig4
	retrig_default	;default-Value for retrigger-time
	gain			;gain
	veloc_c			;Velocity curve
	veloc1			;velocity value per channel (0..127)
	veloc2
	veloc3
	veloc4
	veloc1d			;velocity value per channel for display (0..7)
	veloc2d
	veloc3d
	veloc4d
	adisrlc			;adisr loop counter
	circbuf:24		;circular buffer for midi data 4 Channel * 6 Bytes max
	bytestosend		;contains amount of bytes left in circular buf to send
	readptr			;readpointer to circbuf
	writeptr		;writepointer to circbuf
	look_hi			;high and lowbyte for stringpointer
	look_lo
	curr_config		;current config 0..4 (0 is default, ff no config)
	asciiO			;ASCII Ones
	asciiT			;ASCII Tens
	asciiH			;ASCII Hundreds
	eprom_adr		;eeprom Adress temp
	eprom_dat		;eeprom data temp
	
	endc
;----------------------------------------------------------------
;constants
DISPPort	equ	PORTC	;Port Register for LCD-Display
DISPRS		equ	d'4'	;Bits within Port- RS
DISPE		equ	d'5'	;and Enalble
LED			equ	d'7'	;LED
ch1_mask	equ	b'00000000'	; Mask to configure AD-Channel
ch2_mask	equ	b'00000100'
ch3_mask	equ	b'00001000'
ch4_mask	equ	b'00101000'

;----------------------------------------------------------------
;macro definitions
;----------------------------------------------------------------
;strout Macro to output string at current cursor position
strout	macro	stringaddr		
		movlw	high stringaddr	;save high byte 
		movwf	look_hi			
		movlw	low stringaddr	;save low byte
		movwf	look_lo
		call	Disp_string		;output it
		endm
; **********************************************************************
; **********************************************************************
	org 0 
	goto INIT
	ORG     0x004           ; interrupt vector location
	movwf   w_temp          ; save off current W register contents
	swapf   STATUS,W        ; move status register into W register
	clrf    STATUS          ; select Bank 0
	movwf   status_temp     ; save off contents of STATUS register
	movf	PCLATH,w
	movwf	pclath_temp
	clrf	PCLATH
					
	bsf		STATUS,RP0		; goto BANK1
	btfss	PIE1,TXIE		; serial interrupt enabled?
	goto	ISR1			; no, then we don't have to check the flag
	bcf		STATUS,RP0		; back to Bank0
	btfsc   PIR1,TXIF     	; If serial TX caused the interrupt, handle it.
	call    Serial_ISR
ISR1
	bcf		STATUS,RP0		;back to Bank0
	btfsc   INTCON,T0IF     ; If Timer 0 caused the interrupt, handle it.
	call    Timer0_ISR

	movf	pclath_temp,w
	movwf	PCLATH
	swapf   status_temp,w     ; retrieve copy of STATUS register
	movwf   STATUS            ; restore pre-isr STATUS register contents
	swapf   w_temp,f
	swapf   w_temp,w          ; restore pre-isr W register contents
	retfie                    ; return from interrupt
	
; *********************************************
; Timer 0 Interrupt handler.
; Timer 0 has overflowed
; ...so check AD and insert Midi data to buffer if necessary
; *********************************************
Timer0_ISR

	clrf	veloc1			;first, set velocities to 0...
	clrf	veloc2
	clrf	veloc3
	clrf	veloc4
;-------------------channel1-section
	;goto ch3_start				;Debugging only #################remove
ch1_start
	movf	retrig1,w
	btfsc	STATUS,Z		;retrigger=0?
	goto	ch1_1			;yes, then do new conversion
	decf	retrig1,f		;otherwise decrement retrigger_value
	goto	ch2_start		;next channel
ch1_1
	movlw	b'11000011'
	andwf	ADCON0,f		;clear all input definitions
	movlw	ch1_mask
	iorwf	ADCON0,f		;and set new input
	call	Delay4us		;wait aquisation time
	movf	treshold,w
	movwf	veloc1			;set velocity to trehold
ch1_2
	bsf		ADCON0,1		;start conversion
	btfsc	ADCON0,1		;wait for completion
	goto	$-1
	movf	ADRESH,w		;get result
	movwf	ADresult
	subwf	treshold,w		;new value > treshold?
	btfsc	STATUS,C		;
	goto	ch2_start		;no, then next channel
	movf	ADresult,w
	subwf	veloc1,w		;new value <= oldvalue?
	btfsc	STATUS,C
	goto	ch1_3			;yes, maximum found, go on
	movf	ADresult,w		;no, next conversion
	movwf	veloc1
	goto	ch1_2
ch1_3
	movf	ADresult,w
	movwf	veloc1			;save new velocity
	goto	adisr_loop		;goto isr loop to check for bigger peak

;-------------------channel2-section
ch2_start
	movf	retrig2,w
	btfsc	STATUS,Z		;retrigger=0?
	goto	ch2_1			;yes, then get do new conversion
	decf	retrig2,f		;decrement retrigger_value
	goto	ch3_start		;next channel
ch2_1
	movlw	b'11000011'
	andwf	ADCON0,f		;clear all input definitions
	movlw	ch2_mask
	iorwf	ADCON0,f		;and set new input
	call	Delay4us		;wait aquisation time
	movf	treshold,w
	movwf	veloc2			;set velocity to trehold
ch2_2
	bsf		ADCON0,1		;start conversion
	btfsc	ADCON0,1		;wait for completion
	goto	$-1
	movf	ADRESH,w		;get result
	movwf	ADresult
	subwf	treshold,w		;new value > treshold?
	btfsc	STATUS,C		;
	goto	ch3_start		;no, then next channel
	movf	ADresult,w
	subwf	veloc2,w		;new value <= oldvalue?
	btfsc	STATUS,C
	goto	ch2_3			;yes, maximum found, go on
	movf	ADresult,w		;no, next conversion
	movwf	veloc2
	goto	ch2_2
ch2_3
	movf	ADresult,w
	movwf	veloc2			;save new velocity
	goto	adisr_loop		;goto isr loop to check for bigger peak

;-------------------channel3-section
ch3_start
	movf	retrig3,w
	btfsc	STATUS,Z		;retrigger=0?
	goto	ch3_1			;yes, then do new conversion
	decf	retrig3,f		;decrement retrigger_value
	goto	ch4_start		;next channel
ch3_1
	movlw	b'11000011'
	andwf	ADCON0,f		;clear all input definitions
	movlw	ch3_mask
	iorwf	ADCON0,f		;and set new input
	call	Delay4us		;wait aquisation time
	movf	treshold,w
	movwf	veloc3			;set velocity to trehold
ch3_2
	bsf		ADCON0,1		;start conversion
	btfsc	ADCON0,1		;wait for completion
	goto	$-1
	movf	ADRESH,w		;get result
	movwf	ADresult
	subwf	treshold,w		;new value > treshold?
	btfsc	STATUS,C		;
	goto	ch4_start		;no, then next channel
	movf	ADresult,w
	subwf	veloc3,w		;new value <= oldvalue?
	btfsc	STATUS,C
	goto	ch3_3			;yes, maximum found, go on
	movf	ADresult,w		;no, next conversion
	movwf	veloc3
	goto	ch3_2
ch3_3
	movf	ADresult,w
	movwf	veloc3			;save new velocity
	goto	adisr_loop		;goto isr loop to check for bigger peak
;-------------------channel4-section
ch4_start
	;goto ch5_start			;Debugging only #################remove
	movf	retrig4,w
	btfsc	STATUS,Z		;retrigger=0?
	goto	ch4_1			;yes, then get do new conversion
	decf	retrig4,f		;decrement retrigger_value
	goto	adisr_end		;last channel, so end
ch4_1
	movlw	b'11000011'
	andwf	ADCON0,f		;clear all input definitions
	movlw	ch4_mask
	iorwf	ADCON0,f		;and set new input
	call	Delay4us		;wait aquisation time
	movf	treshold,w
	movwf	veloc4			;set velocity to trehold
ch4_2
	bsf		ADCON0,1		;start conversion
	btfsc	ADCON0,1		;wait for completion
	goto	$-1
	movf	ADRESH,w		;get result
	movwf	ADresult
	subwf	treshold,w		;new value > treshold?
	btfsc	STATUS,C		;
	goto	adisr_end		;no, then end (this is the last channel)
	movf	ADresult,w
	subwf	veloc4,w		;new value <= oldvalue?
	btfsc	STATUS,C
	goto	ch4_3			;yes, maximum found, go on
	movf	ADresult,w		;no, next conversion
	movwf	veloc4
	goto	ch4_2
ch4_3
	movf	ADresult,w
	movwf	veloc4			;save new velocity
	goto	adisr_loop		;goto isr loop to check for bigger peak
	
;we get here if peaks on at least one channel were found
;now we sample for some more time to find out if even bigger peaks exist
;and use them to send notes via midi
adisr_loop					;now check more time if even bigger peaks exist
	movlw	d'25'			;loop 25 times a 80us = 2ms
	movwf	adisrlc			;load loopcounter
adisr_loop_1
	movf	retrig1,w
	btfss	STATUS,Z		;retrigger=0?
	goto	adisr_loop_2_w	;no, then next channel
	movlw	b'11000011'
	andwf	ADCON0,f		;clear all input definitions
	movlw	ch1_mask
	iorwf	ADCON0,f		;and set new input
	call	Delay4us		;wait aquisation time
	bsf		ADCON0,1		;start conversion
	btfsc	ADCON0,1		;wait for completion
	goto	$-1
	movf	ADRESH,w		;get result
	movwf	ADresult
	subwf	veloc1,w		;new value > velocity 1?
	btfsc	STATUS,C		;
	goto	adisr_loop_2	;no, then next channel
	movf	ADresult,w		;yes, then store new (bigger) value
	movwf	veloc1
	goto	adisr_loop_2

adisr_loop_2_w
	call	Delay10us		;to compensate for spare time (because no AD on top)
	call 	Delay10us
adisr_loop_2
	movf	retrig2,w
	btfss	STATUS,Z		;retrigger=0?
	goto	adisr_loop_3_w	;no, then next channel
	movlw	b'11000011'
	andwf	ADCON0,f		;clear all input definitions
	movlw	ch2_mask
	iorwf	ADCON0,f		;and set new input
	call	Delay4us		;wait aquisation time
	bsf		ADCON0,1		;start conversion
	btfsc	ADCON0,1		;wait for completion
	goto	$-1
	movf	ADRESH,w		;get result
	movwf	ADresult
	subwf	veloc2,w		;new value > velocity 2?
	btfsc	STATUS,C		;
	goto	adisr_loop_3	;no, then next channel
	movf	ADresult,w		;yes, then store new (bigger) value
	movwf	veloc2
	goto	adisr_loop_3

adisr_loop_3_w
	call	Delay10us		;to compensate for spare time (because no AD on top)
	call 	Delay10us
adisr_loop_3
	movf	retrig3,w
	btfss	STATUS,Z		;retrigger=0?
	goto	adisr_loop_4_w	;no, then next channel
	movlw	b'11000011'
	andwf	ADCON0,f		;clear all input definitions
	movlw	ch3_mask
	iorwf	ADCON0,f		;and set new input
	call	Delay4us		;wait aquisation time
	bsf		ADCON0,1		;start conversion
	btfsc	ADCON0,1		;wait for completion
	goto	$-1
	movf	ADRESH,w		;get result
	movwf	ADresult
	subwf	veloc3,w		;new value > velocity 3?
	btfsc	STATUS,C		;
	goto	adisr_loop_4	;no, then next channel
	movf	ADresult,w		;yes, then store new (bigger) value
	movwf	veloc3
	goto	adisr_loop_4

adisr_loop_4_w
	call	Delay10us		;to compensate for spare time (because no AD on top)
	call 	Delay10us
adisr_loop_4
	movf	retrig4,w
	btfss	STATUS,Z		;retrigger=0?
	goto	adisr_loop_5_w	;no, then next channel
	movlw	b'11000011'
	andwf	ADCON0,f		;clear all input definitions
	movlw	ch4_mask
	iorwf	ADCON0,f		;and set new input
	call	Delay4us		;wait aquisation time
	bsf		ADCON0,1		;start conversion
	btfsc	ADCON0,1		;wait for completion
	goto	$-1
	movf	ADRESH,w		;get result
	movwf	ADresult
	subwf	veloc4,w		;new value > velocity 4?
	btfsc	STATUS,C		;
	goto	adisr_loop_5	;no, then next channel
	movf	ADresult,w		;yes, then store new (bigger) value
	movwf	veloc4
	goto	adisr_loop_5

adisr_loop_5_w
	call	Delay10us		;to compensate for spare time (because no AD on top)
	call 	Delay10us
adisr_loop_5

	decfsz	adisrlc,f		
	goto	adisr_loop_1	;loop until loopcounter = 0
	;----------------------------------------------------------
	;now check which channel to send (if any) and send via midi
	
	movf	veloc1,w
	subwf	treshold,w		;value > treshold?
	btfsc	STATUS,C		
	goto	adisr_ms2		;no, then next channel

	movf	gain,w
	xorlw	0x01			;is gain=1?
	btfss	STATUS,Z
	goto	adisr_ms1_g2	;no, then gain2
	movf	veloc1,w		;yes, gain =1
	bcf		STATUS,C
	rrf		veloc1,w		;so user upper 7 bit
	goto	adisr_ms1_1
adisr_ms1_g2
	movf	veloc1,w
	btfss	veloc1,7		;bit 7 set?
	goto	adisr_ms1_1		;no, use veloc unmodified
	movlw	0x7f			;yes, set to max (overflow, actually)
adisr_ms1_1
;-----ab hier eingefŸgt
	movwf	offset			;save velocity to offset
	movf	veloc_c,w		;which curve?
	bnz		adisr_ms1_10	;0? no, then check next
	movf	offset,w
	goto	adisr_ms1_2		;finish, go on
adisr_ms1_10
	movf	veloc_c,w		;check which veloc curve
	xorlw	0x01			;is it 1?
	bnz		adisr_ms1_11	;no, then next
	movlw	low veloc_curve1 ;load low part of current veloc table
	addwf	offset,f		;add measured velocity
	movlw	high veloc_curve1 ;load high part of current veloc table
	btfsc	STATUS,C		;if ovverflow then add 1
	addlw	0x01
	movwf	PCLATH			;load high address in lath
	movf	offset,w		;load computed offset
	call	veloc_curve1	;call table and receive vaalue in w
	clrf	PCLATH			; back to Page 0
	goto	adisr_ms1_2		;finish, go on
adisr_ms1_11
	movf	veloc_c,w		;check which veloc curve
	xorlw	0x02			;is it 2?
	bnz		adisr_ms1_12
	movlw	low veloc_curve2
	addwf	offset,f
	movlw	high veloc_curve2
	btfsc	STATUS,C
	addlw	0x01
	movwf	PCLATH
	movf	offset,w
	call	veloc_curve2
	clrf	PCLATH
	goto	adisr_ms1_2
adisr_ms1_12				;we get here if veloc_curve is 3
	movlw	low veloc_curve3	
	addwf	offset,f
	movlw	high veloc_curve3
	btfsc	STATUS,C
	addlw	0x01
	movwf	PCLATH
	movf	offset,w
	call	veloc_curve3
	clrf	PCLATH			; back to Page 0
adisr_ms1_2
;bis hier eingefŸgt
	movwf	midi_veloc
	swapf	midi_veloc,w	;swap nibbles
	andlw	0x0f			;and mask upper bits
	movwf	veloc1d			;now 0..7 
	movf	note1,w
	movwf	midi_note
	call	insert_serial_data
	bsf		DISPPort,LED	;LED on, we have Midi Data to send
	bsf		STATUS,RP0		;goto Bank1
	bsf		PIE1,TXIE		;enable serial interrupt
	bcf		STATUS,RP0		;back to Bank0
	movf	retrig_default,w
	movwf	retrig1

adisr_ms2
	movf	veloc2,w
	subwf	treshold,w		;value > treshold?
	btfsc	STATUS,C		
	goto	adisr_ms3		;no, then next channel

	movf	gain,w
	xorlw	0x01			;is gain=1?
	btfss	STATUS,Z
	goto	adisr_ms2_g2	;no, then gain2
	movf	veloc2,w		;yes, gain =1
	bcf		STATUS,C
	rrf		veloc2,w		;so user upper 7 bit
	goto	adisr_ms2_1
adisr_ms2_g2
	movf	veloc2,w
	btfss	veloc2,7		;bit 7 set?
	goto	adisr_ms2_1		;no, use veloc unmodified
	movlw	0x7f			;yes, set to max (overflow, actually)
adisr_ms2_1
;-----ab hier eingefŸgt
	movwf	offset			;save velocity to offset
	movf	veloc_c,w		;which curve?
	bnz		adisr_ms2_10	;0? no, then check next
	movf	offset,w
	goto	adisr_ms2_2		;finish, go on
adisr_ms2_10
	movf	veloc_c,w		;check which veloc curve
	xorlw	0x01			;is it 1?
	bnz		adisr_ms2_11	;no, then next
	movlw	low veloc_curve1 ;load low part of current veloc table
	addwf	offset,f		;add measured velocity
	movlw	high veloc_curve1 ;load high part of current veloc table
	btfsc	STATUS,C		;if ovverflow then add 1
	addlw	0x01
	movwf	PCLATH			;load high address in lath
	movf	offset,w		;load computed offset
	call	veloc_curve1	;call table and receive vaalue in w
	clrf	PCLATH			; back to Page 0
	goto	adisr_ms2_2		;finish, go on
adisr_ms2_11
	movf	veloc_c,w		;check which veloc curve
	xorlw	0x02			;is it 2?
	bnz		adisr_ms2_12
	movlw	low veloc_curve2
	addwf	offset,f
	movlw	high veloc_curve2
	btfsc	STATUS,C
	addlw	0x01
	movwf	PCLATH
	movf	offset,w
	call	veloc_curve2
	clrf	PCLATH
	goto	adisr_ms2_2
adisr_ms2_12				;we get here if veloc_curve is 3
	movlw	low veloc_curve3	
	addwf	offset,f
	movlw	high veloc_curve3
	btfsc	STATUS,C
	addlw	0x01
	movwf	PCLATH
	movf	offset,w
	call	veloc_curve3
	clrf	PCLATH
adisr_ms2_2
;bis hier eingefŸgt
	movwf	midi_veloc
	swapf	midi_veloc,w	;swap nibbles
	andlw	0x0f			;and mask upper bits
	movwf	veloc2d			;now 0..7 
	movf	note2,w
	movwf	midi_note
	call	insert_serial_data
	bsf		DISPPort,LED	;LED on, we have Midi Data to send
	bsf		STATUS,RP0		;goto Bank1
	bsf		PIE1,TXIE		;enable serial interrupt
	bcf		STATUS,RP0		;back to Bank0
	movf	retrig_default,w
	movwf	retrig2

adisr_ms3
	movf	veloc3,w
	subwf	treshold,w		;value > treshold?
	btfsc	STATUS,C		
	goto	adisr_ms4		;no, then next channel

	movf	gain,w
	xorlw	0x01			;is gain=1?
	btfss	STATUS,Z
	goto	adisr_ms3_g2	;no, then gain2
	movf	veloc3,w		;yes, gain =1
	bcf		STATUS,C
	rrf		veloc3,w		;so user upper 7 bit
	goto	adisr_ms3_1
adisr_ms3_g2
	movf	veloc3,w
	btfss	veloc3,7		;bit 7 set?
	goto	adisr_ms3_1		;no, use veloc unmodified
	movlw	0x7f			;yes, set to max (overflow, actually)
adisr_ms3_1
;-----ab hier eingefŸgt
	movwf	offset			;save velocity to offset
	movf	veloc_c,w		;which curve?
	bnz		adisr_ms3_10	;0? no, then check next
	movf	offset,w
	goto	adisr_ms3_2		;finish, go on
adisr_ms3_10
	movf	veloc_c,w		;check which veloc curve
	xorlw	0x01			;is it 1?
	bnz		adisr_ms3_11	;no, then next
	movlw	low veloc_curve1 ;load low part of current veloc table
	addwf	offset,f		;add measured velocity
	movlw	high veloc_curve1 ;load high part of current veloc table
	btfsc	STATUS,C		;if ovverflow then add 1
	addlw	0x01
	movwf	PCLATH			;load high address in lath
	movf	offset,w		;load computed offset
	call	veloc_curve1	;call table and receive vaalue in w
	clrf	PCLATH			; back to Page 0
	goto	adisr_ms3_2		;finish, go on
adisr_ms3_11
	movf	veloc_c,w		;check which veloc curve
	xorlw	0x02			;is it 2?
	bnz		adisr_ms3_12
	movlw	low veloc_curve2
	addwf	offset,f
	movlw	high veloc_curve2
	btfsc	STATUS,C
	addlw	0x01
	movwf	PCLATH
	movf	offset,w
	call	veloc_curve2
	clrf	PCLATH
	goto	adisr_ms3_2
adisr_ms3_12				;we get here if veloc_curve is 3
	movlw	low veloc_curve3	
	addwf	offset,f
	movlw	high veloc_curve3
	btfsc	STATUS,C
	addlw	0x01
	movwf	PCLATH
	movf	offset,w
	call	veloc_curve3
	clrf	PCLATH
adisr_ms3_2
;bis hier eingefŸgt
	movwf	midi_veloc
	swapf	midi_veloc,w	;swap nibbles
	andlw	0x0f			;and mask upper bits
	movwf	veloc3d			;now 0..7 
	movf	note3,w
	movwf	midi_note
	call	insert_serial_data
	bsf		DISPPort,LED	;LED on, we have Midi Data to send
	bsf		STATUS,RP0		;goto Bank1
	bsf		PIE1,TXIE		;enable serial interrupt
	bcf		STATUS,RP0		;back to Bank0
	movf	retrig_default,w
	movwf	retrig3
adisr_ms4
	movf	veloc4,w
	subwf	treshold,w		;value > treshold?
	btfsc	STATUS,C		
	goto	adisr_end		;no, then end (this was last channel)

	movf	gain,w
	xorlw	0x01			;is gain=1?
	btfss	STATUS,Z
	goto	adisr_ms4_g2	;no, then gain2
	movf	veloc4,w		;yes, gain =1
	bcf		STATUS,C
	rrf		veloc4,w		;so user upper 7 bit
	goto	adisr_ms4_1
adisr_ms4_g2
	movf	veloc4,w
	btfss	veloc4,7		;bit 7 set?
	goto	adisr_ms4_1		;no, use veloc unmodified
	movlw	0x7f			;yes, set to max (overflow, actually)
adisr_ms4_1
;-----ab hier eingefŸgt
	movwf	offset			;save velocity to offset
	movf	veloc_c,w		;which curve?
	bnz		adisr_ms4_10	;0? no, then check next
	movf	offset,w
	goto	adisr_ms4_2		;finish, go on
adisr_ms4_10
	movf	veloc_c,w		;check which veloc curve
	xorlw	0x01			;is it 1?
	bnz		adisr_ms4_11	;no, then next
	movlw	low veloc_curve1 ;load low part of current veloc table
	addwf	offset,f		;add measured velocity
	movlw	high veloc_curve1 ;load high part of current veloc table
	btfsc	STATUS,C		;if ovverflow then add 1
	addlw	0x01
	movwf	PCLATH			;load high address in lath
	movf	offset,w		;load computed offset
	call	veloc_curve1	;call table and receive vaalue in w
	clrf	PCLATH			; back to Page 0
	goto	adisr_ms4_2		;finish, go on
adisr_ms4_11
	movf	veloc_c,w		;check which veloc curve
	xorlw	0x02			;is it 2?
	bnz		adisr_ms4_12
	movlw	low veloc_curve2
	addwf	offset,f
	movlw	high veloc_curve2
	btfsc	STATUS,C
	addlw	0x01
	movwf	PCLATH
	movf	offset,w
	call	veloc_curve2
	clrf	PCLATH
	goto	adisr_ms4_2
adisr_ms4_12				;we get here if veloc_curve is 3
	movlw	low veloc_curve3	
	addwf	offset,f
	movlw	high veloc_curve3
	btfsc	STATUS,C
	addlw	0x01
	movwf	PCLATH
	movf	offset,w
	call	veloc_curve3
	clrf	PCLATH
adisr_ms4_2
;bis hier eingefŸgt
	movwf	midi_veloc
	swapf	midi_veloc,w	;swap nibbles
	andlw	0x0f			;and mask upper bits
	movwf	veloc4d			;now 0..7 
	movf	note4,w
	movwf	midi_note
	call	insert_serial_data
	bsf		DISPPort,LED	;LED on, we have Midi Data to send
	bsf		STATUS,RP0		;goto Bank1
	bsf		PIE1,TXIE		;enable serial interrupt
	bcf		STATUS,RP0		;back to Bank0
	movf	retrig_default,w
	movwf	retrig4
	
;channels ready, leave ISR
adisr_end
	BCF 	INTCON,T0IF		; Clear Timer0 flag and continue.
    return
; *********************************************
; serial Interrupt handler.
; serial TX is ready to transmit
; ...so check if more data has to be send and send it if necessary
; *********************************************
Serial_ISR
	
	movf	bytestosend,w
	btfss	STATUS,Z		;only if bytes to send left in buffer
	goto	serial_isr_1	;bytes left? then send next one
	bsf		STATUS,RP0		;goto Bank1
	bcf		PIE1,TXIE		;otherwise disable TX interrupt 
	bcf		STATUS,RP0		;goto Bank0
	bcf		DISPPort,LED	;LED off
	goto	end_serial_isr	;and goto end
	;-----
serial_isr_1
	decf	bytestosend,f	;decremet amount of data left
	movlw	circbuf			;circular buffer start-adress
	addwf	readptr,w		;add readptr to obtain actual address			
	movwf	FSR				;save to fsr
	movf	INDF,w			;fetch data from circbuf
	movwf	TXREG			;to serial out buffer
	incf	readptr,f		;increase readpointer to next position
	movlw	b'00011000'		;check if overflow
	xorwf	readptr,w		
	btfsc	STATUS,Z		;if so then
	clrf	readptr			;set readptr to 0
	
	;-----
end_serial_isr
	return
    
; ***********************************************
; insert_serial_data (only called from isr, so GIE is disabled)
; inserts new serial data to be send into ring buffer
; w contains channel number (1..4)
; ***********************************************
insert_serial_data
	

	;byte 1
	movlw	circbuf			;circular bufffer start-address
	addwf	writeptr,w		;add writeptr to obtain actuell adress
	movwf	FSR				;save to fsr
	movf	midi_chan,w		;get midi-Channel
	iorlw	0x90			;identify byte as note-on
	movwf	INDF			;to buffer
	incf	bytestosend,f	;so we have one more byte to send
	incf	writeptr,f		;increment writeptr
	movlw	b'00011000'		;check if overflow
	xorwf	writeptr,w
	btfsc	STATUS,Z		;if so then
	clrf	writeptr		;set writeptr to 0
	;byte 2
	movlw	circbuf			;circular bufffer start-address
	addwf	writeptr,w		;add writeptr to obtain actuell adress
	movwf	FSR				;save to fsr
	movf	midi_note,w		;get midi-note
	movwf	INDF			;to buffer
	incf	bytestosend,f	;so we have one more byte to send
	incf	writeptr,f		;increment writeptr
	movlw	b'00011000'		;check if overflow
	xorwf	writeptr,w
	btfsc	STATUS,Z		;if so then
	clrf	writeptr		;set writeptr to 0
	;byte 3
	movlw	circbuf			;circular bufffer start-address
	addwf	writeptr,w		;add writeptr to obtain actuell adress
	movwf	FSR				;save to fsr
	movf	midi_veloc,w	;get midi-velocity
	movwf	INDF			;to buffer
	incf	bytestosend,f	;so we have one more byte to send
	incf	writeptr,f		;increment writeptr
	movlw	b'00011000'		;check if overflow
	xorwf	writeptr,w
	btfsc	STATUS,Z		;if so then
	clrf	writeptr		;set writeptr to 0
	;byte 4
	movlw	circbuf			;circular bufffer start-address
	addwf	writeptr,w		;add writeptr to obtain actuell adress
	movwf	FSR				;save to fsr
	movf	midi_chan,w		;get midi-Channel
	iorlw	0x80			;identify byte as note-off
	movwf	INDF			;to buffer
	incf	bytestosend,f	;so we have one more byte to send
	incf	writeptr,f		;increment writeptr
	movlw	b'00011000'		;check if overflow
	xorwf	writeptr,w
	btfsc	STATUS,Z		;if so then
	clrf	writeptr		;set writeptr to 0
	;byte 5
	movlw	circbuf			;circular bufffer start-address
	addwf	writeptr,w		;add writeptr to obtain actuell adress
	movwf	FSR				;save to fsr
	movf	midi_note,w		;get midi-note
	movwf	INDF			;to buffer
	incf	bytestosend,f	;so we have one more byte to send
	incf	writeptr,f		;increment writeptr
	movlw	b'00011000'		;check if overflow
	xorwf	writeptr,w
	btfsc	STATUS,Z		;if so then
	clrf	writeptr		;set writeptr to 0
	;byte 6
	movlw	circbuf			;circular bufffer start-address
	addwf	writeptr,w		;add writeptr to obtain actuell adress
	movwf	FSR				;save to fsr
	movlw	0x00			;midi-velocity=0 (note off)
	movwf	INDF			;to buffer
	incf	bytestosend,f	;so we have one more byte to send
	incf	writeptr,f		;increment writeptr
	movlw	b'00011000'		;check if overflow
	xorwf	writeptr,w
	btfsc	STATUS,Z		;if so then
	clrf	writeptr		;set writeptr to 0
	
	return
;------------------------------------------------------------------
;initializes Processor
;------------------------------------------------------------------
INIT
	bsf 	STATUS,RP0 	;select Register Page 1 
	;configure input/output
	clrf 	TRISC		;all output
	bsf		TRISA,0		;RA0=input channel1
	bsf		TRISA,1		;RA1=channel2
	bsf		TRISA,2		;RA2=channel3
	bsf		TRISB,4		;RB4=channel4
	bsf		TRISB,5		;RB5=key "up"
	bsf		TRISB,6		;RB6=key "down"
	bcf		TRISB,7		;RB7 =TX=output
	;configure TXSTA
	bcf		TXSTA,TX9	;8-bit transmisssion
	bsf		TXSTA,TXEN	;transmit enable
	bcf		TXSTA,SYNC	;asynchronous mode
	bcf		TXSTA,BRGH	;BRGH=0
	
	;configure BAUDCTL
	bcf		BAUDCTL,4		;(SCKP)	; non inverted Data
	bcf		BAUDCTL,BRG16	;BRG16=0
	bcf		BAUDCTL,WUE		;no interrupt on receiver
	bcf		BAUDCTL,ABDEN	;no auto-baud
	movlw	0x00			;setting Baud Rate =9 = 31250bps
	movwf	SPBRGH
	movlw	0x09
	movwf	SPBRG
	;configure AD-Converter
	bcf		ADCON1,ADCS2	;set AD Conversion clock to Fosc/32
	bsf		ADCON1,ADCS1
	bcf		ADCON1,ADCS0
	bcf 	STATUS,RP0 	;back to Register Page 0 
	bsf 	STATUS,RP1	;to Bank2
	;configure analog I/O
	bsf		WPUB,WPUB5	;weak pull up RB5 (key up)
	bsf		WPUB,WPUB6	;weak pull up RB6 (key down)
	clrf 	ANSEL		;all digital I/O (used for Port C here)
	bsf		ANSEL,0		;without AN0
	bsf		ANSEL,1		;and AN1
	bsf		ANSEL,2		;and AN2
	clrf	ANSELH
	bsf		ANSELH,2	;and AN10
	bcf 	STATUS, RP1 ;back to Bank 0
	movlw	b'00001001'	;Configure AD Control: left, VDD,Channel2, AD on
	movwf	ADCON0
	;Configure RCSTA
	bsf		RCSTA,SPEN	;Serial port enable
	bcf		RCSTA,CREN	;dissable receiver
	
	;initialise Timer 0
	; 
	;we are in Bank 0...
	clrwdt				;Routine from Datasheet Microchip
	clrf	TMR0	
	bsf		STATUS, RP0	;Switch to BANK 1
	movlw b'01010011'		;Pullup enable, TMR0,Prescaler to TMR0, Prescaler 1:16
	movwf OPTION_REG
	bcf	STATUS, RP0		;Back to Bank 0

	;now set reasonable values to variables
	clrf	veloc1		;no velocity at start
	clrf	veloc2
	clrf	veloc3
	clrf	veloc4
	clrf	veloc1d
	clrf	veloc2d
	clrf	veloc3d
	clrf	veloc4d

	clrf	bytestosend	;no bytes to send yet
	clrf	readptr		;we start reading at position 1 (0)
	clrf	writeptr	;we start writing at the same position....


	;now load last configuration from eeprom adress 0

	clrf	eprom_adr		;Adress 0x00
	call	eprom_read
	bz		init1			;if 0 then it is default
	movwf	eprom_dat		;no, then load config
	movwf	curr_config		;make it current config
	clrw					;ensure w is 0
	addlw	0x0a			;add 10 (lenght of one config) 
	decfsz	eprom_dat,f		;decrement, if 0 then finish, otherwise add again
	goto	$-2
	;w now contains start-adress of config in eeprom
	movwf	eprom_adr		;1st entry for config 1=flag
	call	eprom_read		;read it, result in w
	xorlw	0xaa			;valid config?
	bnz		init1			;no, then config is not valid, go on with init
	incf	eprom_adr,f		;next adress		
	call	eprom_read		;read it, result in w
	movwf	note1
	incf	eprom_adr,f		;next adress		
	call	eprom_read		;read it, result in w
	movwf	note2
	incf	eprom_adr,f		;next adress		
	call	eprom_read		;read it, result in w
	movwf	note3
	incf	eprom_adr,f		;next adress		
	call	eprom_read		;read it, result in w
	movwf	note4
	incf	eprom_adr,f		;next adress		
	call	eprom_read		;read it, result in w
	movwf	midi_chan
	incf	eprom_adr,f		;next adress		
	call	eprom_read		;read it, result in w
	movwf	treshold
	incf	eprom_adr,f		;next adress		
	call	eprom_read		;read it, result in w
	movwf	retrig_default
	incf	eprom_adr,f		;next adress		
	call	eprom_read		;read it, result in w
	movwf	gain
	incf	eprom_adr,f		;next adress		
	call	eprom_read		;read it, result in w
	movwf	veloc_c
	goto	init2			;ready, skip default-settings
init1
	call	reset_factory	;defaults for drum specific parameters
							;which can be changed via menu
init2
	clrf	PORTC		;port C all to 0 (init)

	call	Disp_Init	;Init Display
	call	Disp_clear	;clear Display
	call	Delay10ms	;wait for Display

	strout	msg_welcome	;start-message on display
	movlw	b'11000000'		;cursor on pos 1 at 2nd row
	call	Disp_send_conf
	strout	msg_welcome1
	
	movlw	d'255'		;wait ca. 2,5s (for user to read it)
	movwf	d3

	decfsz	d3,f
	goto	$+2
	goto	$+3
	call	Delay10ms
	goto	$-4
	

	clrf 	TMR0
	clrf	INTCON			;initialize Interrupts
	bsf		INTCON,T0IE		;enable Timer0 interrupts
	bsf		STATUS,RP0		;to bank 1
	bcf		PIE1,TXIE		;disable serial interrupt for now
	bcf		STATUS,RP0		;back to bank0
	bsf		INTCON,PEIE		;enable periphal interrupts (used for serial)
	bsf 	INTCON,GIE		;enable global interrupts
							;now timer 0 fires
							

;#############################################################################
;here to start main routine###################################################
;
main
	call	Disp_clear		;clear display
	call	Delay10ms		;needs time to finish...
	strout	msg_run			;now running message on display
	movlw	b'11000000'		;cursor on pos 1 at 2nd row
	call	Disp_send_conf

	movf	curr_config,w	;current configuration to w
	xorlw	0x04
	bnz		m1
	strout	msg_conf4
m1	movf	curr_config,w	;current configuration to w
	xorlw	0x03
	bnz		m2
	strout	msg_conf3
m2	movf	curr_config,w	;current configuration to w
	xorlw	0x02
	bnz		m3
	strout	msg_conf2
m3	movf	curr_config,w	;current configuration to w
	xorlw	0x01
	bnz		m4
	strout	msg_conf1
m4	movf	curr_config,w	;current configuration to w
	bnz		m5
	strout	msg_default
m5	movf	curr_config,w	;current configuration to w
	xorlw	0xff
	bnz		mainloop
	strout 	msg_changed		;if nothing, then it should have been changed =ff
	

mainloop
							;give some visual feedback on display....
	movlw	b'11001100'		;cursor at pos 12 at 2nd row	
	call	Disp_send_conf
	movf	veloc1d,w		;load velocity 1 (display-version)
	call	Disp_send_data
	movf	veloc2d,w		;load velocity 2 (display-version)
	call	Disp_send_data
	movf	veloc3d,w		;load velocity 3 (display-version)
	call	Disp_send_data
	movf	veloc4d,w		;load velocity 4 (display-version)
	call	Disp_send_data
	movf	veloc1d,w		;decrease value if not zero yet		
	skpz
	decf	veloc1d,f
	movf	veloc2d,w		;decrease value if not zero yet		
	skpz
	decf	veloc2d,f
	movf	veloc3d,w		;decrease value if not zero yet		
	skpz
	decf	veloc3d,f
	movf	veloc4d,w		;decrease value if not zero yet		
	skpz
	decf	veloc4d,f
	call	Delay50ms		;and wait ...
	call	keycheck		;returns status of buttons in w
	skpnz					;if not 0 then handle menu
	goto	mainloop		;otherwise do nothing
	call	handle_mainmenu
	call	Delay100ms		;to insure no keybounce anymore
	call	waitforrelease
	
	goto main				;to assure right text on display
	
;---------------------------------------------------------------	
;Menu handling
;---------------------------------------------------------------
handle_mainmenu
	call	Disp_clear		;clear display
	call	Delay10ms		;needs time to finish...
	strout	msg_mainmenu	;now menu message on display
hm_exit
	movlw	b'11000000'		;cursor on pos 1 at 2nd row
	call	Disp_send_conf
	strout 	msg_exit		;first one in 2nd row
hm_exit_1
	call	waitforrelease	;wait until no key pressed
	call	getkey			;get new status
	XORLW	0x03			;enter? (exit)
	skpnz
	return					;then leave mainmenu (this is the only way out)
	movf	keydata,w		
	xorlw	0x02			;down pressed?
	skpnz
	goto	hm_exit_1			;thhen do it again (1st entry)
	;we get here if up was pressed...
hm_loadconf
	movlw	b'11000000'		;cursor on pos 1 at 2nd row
	call	Disp_send_conf
	strout 	msg_loadconf	;next text in 2nd row
	call	waitforrelease	;wait until no key pressed
	call	getkey			;get new status
	XORLW	0x03			;enter?
	skpnz
	goto	handle_loadconf	;then handle this
	movf	keydata,w		
	xorlw	0x02			;down pressed?
	skpnz
	goto	hm_exit			;then pervious menu-entry
	;we get here if up was pressed...
hm_saveconf
	movlw	b'11000000'		;cursor on pos 1 at 2nd row
	call	Disp_send_conf
	strout 	msg_saveconf	;next text in 2nd row
	call	waitforrelease	;wait until no key pressed
	call	getkey			;get new status
	XORLW	0x03			;enter?
	skpnz
	goto	handle_saveconf	;then handle this
	movf	keydata,w		
	xorlw	0x02			;down pressed?
	skpnz
	goto	hm_loadconf		;then pervious menu-entry
	;we get here if up was pressed...
hm_treshold
	movlw	b'11000000'		;cursor on pos 1 at 2nd row
	call	Disp_send_conf
	strout 	msg_treshold	;next text in 2nd row
	call	waitforrelease	;wait until no key pressed
	call	getkey			;get new status
	XORLW	0x03			;enter?
	skpnz
	goto	handle_treshold	;then handle this
	movf	keydata,w		
	xorlw	0x02			;down pressed?
	skpnz
	goto	hm_saveconf		;then pervious menu-entry
	;we get here if up was pressed...
hm_retrigger
	movlw	b'11000000'		;cursor on pos 1 at 2nd row
	call	Disp_send_conf
	strout 	msg_retrigger	;next text in 2nd row
	call	waitforrelease	;wait until no key pressed
	call	getkey			;get new status
	XORLW	0x03			;enter?
	skpnz
	goto	handle_retrigger	;then handle this
	movf	keydata,w		
	xorlw	0x02			;down pressed?
	skpnz
	goto	hm_treshold		;then pervious menu-entry
	;we get here if up was pressed...
hm_noteassign
	movlw	b'11000000'		;cursor on pos 1 at 2nd row
	call	Disp_send_conf
	strout 	msg_noteassign	;next text in 2nd row
	call	waitforrelease	;wait until no key pressed
	call	getkey			;get new status
	XORLW	0x03			;enter?
	skpnz
	goto	handle_noteassign	;then handle this
	movf	keydata,w		
	xorlw	0x02			;down pressed?
	skpnz
	goto	hm_retrigger		;then pervious menu-entry
	;we get here if up was pressed...
hm_gain
	movlw	b'11000000'		;cursor on pos 1 at 2nd row
	call	Disp_send_conf
	strout 	msg_gain		;next text in 2nd row
	call	waitforrelease	;wait until no key pressed
	call	getkey			;get new status
	XORLW	0x03			;enter?
	skpnz
	goto	handle_gain		;then handle this
	movf	keydata,w		
	xorlw	0x02			;down pressed?
	skpnz
	goto	hm_noteassign	;then pervious menu-entry
	;we get here if up was pressed...
hm_veloc_c
	movlw	b'11000000'		;cursor on pos 1 at 2nd row
	call	Disp_send_conf
	strout 	msg_veloc_c		;next text in 2nd row
	call	waitforrelease	;wait until no key pressed
	call	getkey			;get new status
	XORLW	0x03			;enter?
	skpnz
	goto	handle_veloc_c	;then handle this
	movf	keydata,w		
	xorlw	0x02			;down pressed?
	skpnz
	goto	hm_gain			;then pervious menu-entry
	;we get here if up was pressed...
hm_midichannel
	movlw	b'11000000'		;cursor on pos 1 at 2nd row
	call	Disp_send_conf
	strout 	msg_midichan	;next text in 2nd row
	call	waitforrelease	;wait until no key pressed
	call	getkey			;get new status
	XORLW	0x03			;enter?
	skpnz
	goto	handle_midichannel	;then handle this
	movf	keydata,w		
	xorlw	0x02			;down pressed?
	skpnz
	goto	hm_veloc_c		;then pervious menu-entry
	;we get here if up was pressed...
hm_resetfactory
	movlw	b'11000000'		;cursor on pos 1 at 2nd row
	call	Disp_send_conf
	strout 	msg_resetfact	;next text in 2nd row
	call	waitforrelease	;wait until no key pressed
	call	getkey			;get new status
	XORLW	0x03			;enter?
	skpnz
	goto	handle_resetfactory	;then handle this
	movf	keydata,w		
	xorlw	0x02			;down pressed?
	skpnz
	goto	hm_midichannel	;then pervious menu-entry
	goto	hm_resetfactory	;up was pressed, so once again, do nothing
;--------------------------------------------------------------------------
;configuration load/save:
;loads/saves running configs from/to eeprom data memory:
;Adresses:
;0: running config: "0":default "1..4": config 1..4
;1..7:empty
;8..16: config 1: (flag,note1,note2,note3,note4,midi_chan,treshold,retrigger,gain)
;17..25:config 2
;26..34:config 3
;35..33:config 4
;flag=0xaa means valid config, other value means non valid config 
;(i.g. no config saved on this position yet)
;--------------------------------------------------------------------------
handle_loadconf
	movlw	b'11000000'		;cursor on pos 0 at 2nd row
	call	Disp_send_conf
	strout 	msg_do_loadconf	;next text in 2nd row
	movlw	0x01			;we start with config 1
	movwf	chan_tmp		;and misuse this var temporarily 
hl0	
	movlw	b'11001110'		;cursor on pos 14 at 2nd row
	call	Disp_send_conf
	movf	chan_tmp,w		;output current config value on display
	call	bin2asc
	movf	asciiO,w
	call	Disp_send_data
	call	waitforrelease	;wait until no key pressed
	call	getkey			;get new status
	XORLW	0x01			;up?
	bnz		hl1				;no, then branch
	incf	chan_tmp,f		;yes, then increment 
	movlw	d'5'			;maximum for configs is 4
	xorwf	chan_tmp,w
	bnz		hl0
	movlw	d'4'
	movwf	chan_tmp
	goto	hl0
hl1
	movf	keydata,w		
	xorlw	0x02			;down pressed?
	bnz		hl2				;no, then end (it was enter)
	decf	chan_tmp,f		;yes, decrement
	movlw	d'0'			;minimum is 1
	xorwf	chan_tmp,w
	bnz		hl0
	movlw	d'1'
	movwf	chan_tmp
	goto	hl0
hl2
	movf	chan_tmp,w		;config is current config
	movwf	curr_config
	;check which to load, then load this one

	clrw					;ensure w is 0
hl_load
	addlw	0x0a			;add 10 (lenght of one config) 
	decfsz	chan_tmp,f		;decrement, if 0 then finish, otherwise add again
	goto	hl_load
	;w now contains start-adress of config in eeprom
	movwf	eprom_adr		;1st entry for config 1=flag
	call	eprom_read		;read it, result in w
	xorlw	0xaa			;valid config?
	bnz		hl_error		;no, then print error message
	incf	eprom_adr,f		;next adress		
	call	eprom_read		;read it, result in w
	movwf	note1
	incf	eprom_adr,f		;next adress		
	call	eprom_read		;read it, result in w
	movwf	note2
	incf	eprom_adr,f		;next adress		
	call	eprom_read		;read it, result in w
	movwf	note3
	incf	eprom_adr,f		;next adress		
	call	eprom_read		;read it, result in w
	movwf	note4
	incf	eprom_adr,f		;next adress		
	call	eprom_read		;read it, result in w
	movwf	midi_chan
	incf	eprom_adr,f		;next adress		
	call	eprom_read		;read it, result in w
	movwf	treshold
	incf	eprom_adr,f		;next adress		
	call	eprom_read		;read it, result in w
	movwf	retrig_default
	incf	eprom_adr,f		;next adress		
	call	eprom_read		;read it, result in w
	movwf	gain
	incf	eprom_adr,f		;next adress		
	call	eprom_read		;read it, result in w
	movwf	veloc_c
	;now save current config to eeprom 0x00
	clrf	eprom_adr		;Adress 0x00
	movf	curr_config,w
	movwf	eprom_dat
	call	eprom_write		;save it

	movlw	b'11000000'		;cursor on pos 0 at 2nd row
	call	Disp_send_conf
	strout 	msg_confloaded	;next text in 2nd row
	call	Delay100ms		;wait for unser to recognise it.
	call	Delay100ms
	call	Delay100ms
	call	Delay100ms
	call	Delay100ms
	call	Delay100ms
	
	goto	hl_end

hl_error	;print errorstring on display
	movlw	b'11000000'		;cursor on pos 0 at 2nd row
	call	Disp_send_conf
	strout 	msg_conferror	;next text in 2nd row
	call	Delay100ms		;wait for unser to recognise it.
	call	Delay100ms
	call	Delay100ms
	call	Delay100ms
	call	Delay100ms
	call	Delay100ms
	call	reset_factory	;and set to default values
hl_end
	goto	hm_loadconf

;save_config: saves 
handle_saveconf
	movlw	b'11000000'		;cursor on pos 0 at 2nd row
	call	Disp_send_conf
	strout 	msg_do_saveconf	;next text in 2nd row
	movlw	0x01			;we start wirth config 1
	movwf	chan_tmp		;and misuse this var temporarily 
hs0	
	movlw	b'11001110'		;cursor on pos 14 at 2nd row
	call	Disp_send_conf
	movf	chan_tmp,w		;output current config value on display
	call	bin2asc
	movf	asciiO,w
	call	Disp_send_data
	call	waitforrelease	;wait until no key pressed
	call	getkey			;get new status
	XORLW	0x01			;up?
	bnz		hs1				;no, then branch
	incf	chan_tmp,f		;yes, then increment 
	movlw	d'5'			;maximum for configs is 4
	xorwf	chan_tmp,w
	bnz		hs0
	movlw	d'4'
	movwf	chan_tmp
	goto	hs0
hs1
	movf	keydata,w		
	xorlw	0x02			;down pressed?
	bnz		hs2				;no, then end (it was enter)
	decf	chan_tmp,f		;yes, decrement
	movlw	d'0'			;minimum is 1
	xorwf	chan_tmp,w
	bnz		hs0
	movlw	d'1'
	movwf	chan_tmp
	goto	hs0
hs2
	movf	chan_tmp,w		;config is current config
	movwf	curr_config
	;check which to save, then save to this one

	clrw					;ensure w is 0
hs_save
	addlw	0x0a			;add 10 (lenght of one config) 
	decfsz	chan_tmp,f		;decrement, if 0 then finish, otherwise add again
	goto	hs_save
	;w now contains start-adress of config in eeprom
	
	movwf	eprom_adr		;1st entry for config 1=flag
	movlw	0xaa			;flag for valid config
	movwf	eprom_dat
	call	eprom_write		;save it
	movf	note1,w			;load parameter to be saved to w
	movwf	eprom_dat
	incf	eprom_adr,f		;next adress		
	call	eprom_write		;write it
	movf	note2,w			;load parameter to be saved to w
	movwf	eprom_dat
	incf	eprom_adr,f		;next adress		
	call	eprom_write		;write it
	movf	note3,w			;load parameter to be saved to w
	movwf	eprom_dat
	incf	eprom_adr,f		;next adress		
	call	eprom_write		;write it
	movf	note4,w			;load parameter to be saved to w
	movwf	eprom_dat
	incf	eprom_adr,f		;next adress		
	call	eprom_write		;write it
	movf	midi_chan,w			;load parameter to be saved to w
	movwf	eprom_dat
	incf	eprom_adr,f		;next adress		
	call	eprom_write		;write it
	movf	treshold,w			;load parameter to be saved to w
	movwf	eprom_dat
	incf	eprom_adr,f		;next adress		
	call	eprom_write		;write it
	movf	retrig_default,w			;load parameter to be saved to w
	movwf	eprom_dat
	incf	eprom_adr,f		;next adress		
	call	eprom_write		;write it
	movf	gain,w			;load parameter to be saved to w
	movwf	eprom_dat
	incf	eprom_adr,f		;next adress		
	call	eprom_write		;write it
	movf	veloc_c,w		;load parameter to be saved to w
	movwf	eprom_dat
	incf	eprom_adr,f		;next adress		
	call	eprom_write		;write it
	;now save current config to eeprom 0x00
	clrf	eprom_adr		;Adress 0x00
	movf	curr_config,w
	movwf	eprom_dat
	call	eprom_write		;save it
	
	movlw	b'11000000'		;cursor on pos 0 at 2nd row
	call	Disp_send_conf
	strout 	msg_confsaved	;next text in 2nd row
	call	Delay100ms		;wait for unser to recognise it.
	call	Delay100ms
	call	Delay100ms
	call	Delay100ms
	call	Delay100ms
	call	Delay100ms
		
	goto	hm_saveconf
;-----------------------
handle_treshold
	movlw	b'11000000'		;cursor on pos 0 at 2nd row
	call	Disp_send_conf
	strout 	msg_do_treshold	;next text in 2nd row
ht0	
	movlw	b'11001100'		;cursor on pos 12 at 2nd row
	call	Disp_send_conf
	movf	treshold,w		;output current treshold value on display
	call	bin2asc
	movf	asciiH,w
	call	Disp_send_data
	movf	asciiT,w
	call	Disp_send_data
	movf	asciiO,w
	call	Disp_send_data
	call	waitforrelease	;wait until no key pressed
	call	getkey			;get new status
	XORLW	0x01			;up?
	bnz		ht1				;no, then branch
	incf	treshold,f		;yes, then increment treshold
	movlw	0xff			;config not saved
	movwf	curr_config
	movlw	d'101'			;maximum for treshold is 100
	xorwf	treshold,w
	bnz		ht0
	movlw	d'100'
	movwf	treshold
	goto	ht0
ht1
	movf	keydata,w		
	xorlw	0x02			;down pressed?
	bnz		ht3				;no, then end (it was enter)
	decf	treshold,f		;yes, decrement treshold
	movlw	0xff			;config not saved
	movwf	curr_config
	movlw	d'9'			;minimum for treshold is 10
	xorwf	treshold,w
	bnz		ht0
	movlw	d'10'
	movwf	treshold
	goto	ht0
ht3
	goto	hm_treshold
;-----------------------
handle_retrigger
	movlw	b'11000000'		;cursor on pos 0 at 2nd row
	call	Disp_send_conf
	strout 	msg_do_retrigger	;next text in 2nd row
hr0	
	movlw	b'11001100'		;cursor on pos 12 at 2nd row
	call	Disp_send_conf
	movf	retrig_default,w	;output current retrigger value on display
	call	bin2asc
	movf	asciiH,w
	call	Disp_send_data
	movf	asciiT,w
	call	Disp_send_data
	movf	asciiO,w
	call	Disp_send_data
	call	waitforrelease	;wait until no key pressed
	call	getkey			;get new status
	XORLW	0x01			;up?
	bnz		hr1				;no, then branch
	incf	retrig_default,f	;yes, then increment value
	movlw	0xff			;config not saved
	movwf	curr_config
	movlw	d'151'			;maximum for retrigger is 150
	xorwf	retrig_default,w
	bnz		hr0
	movlw	d'150'
	movwf	retrig_default
	goto	hr0
hr1
	movf	keydata,w		
	xorlw	0x02			;down pressed?
	bnz		hr3				;no, then end (it was enter)
	decf	retrig_default,f		;yes, decrement treshold
	movlw	0xff			;config not saved
	movwf	curr_config
	movlw	d'19'			;minimum for treshold is 20
	xorwf	retrig_default,w
	bnz		hr0
	movlw	d'20'
	movwf	retrig_default
	goto	hr0
hr3
	goto	hm_retrigger
;-----------------------
handle_noteassign
	movlw	b'11000000'		;cursor on pos 0 at 2nd row
	call	Disp_send_conf
	strout 	msg_do_noteassignchan	;next text in 2nd row
	movlw	b'00001101'		;cursor on and blinking
	call	Disp_send_conf	
	movlw	0x01
	movwf	chan_tmp		;start with note 1
hn0	
	movlw	b'11001001'		;cursor on pos 9 at 2nd row
	call	Disp_send_conf
	movf	chan_tmp,w		;output current channel on display
	call	bin2asc
	movf	asciiO,w
	call	Disp_send_data
	
	movf	chan_tmp,w		;get currrent channel
	xorlw	0x01			;is it 1?
	bnz		hn01			;no then next check
	movf	note1,w			;yes, then save value to midi_note_tmp
	movwf	midi_note_tmp
	goto	hn04			;
hn01
	movf	chan_tmp,w
	xorlw	0x02			; is it 2?
	bnz		hn02
	movf	note2,w
	movwf	midi_note_tmp
	goto	hn04
hn02
	movf	chan_tmp,w
	xorlw	0x03			;is it 3?
	bnz		hn03
	movf	note3,w
	movwf	midi_note_tmp
	goto	hn04
hn03						; nothing, than it has to be channel 4...
	movf	note4,w
	movwf	midi_note_tmp
hn04						;now we can output the assigned note
	movlw	b'11001100'		;cursor on pos 12 at 2nd row
	call	Disp_send_conf
	movf	midi_note_tmp,w	;output current note assignment on display
	call	bin2asc
	movf	asciiH,w
	call	Disp_send_data
	movf	asciiT,w
	call	Disp_send_data
	movf	asciiO,w
	call	Disp_send_data
	
	movlw	b'11001001'		;cursor on pos 9 at 2nd row
	call	Disp_send_conf

	call	waitforrelease	;wait until no key pressed
	call	getkey			;get new status
	XORLW	0x01			;up?
	bnz		hn1				;no, then branch
	incf	chan_tmp,f	;yes, then increment value
	movlw	d'5'			;highest channel is 4
	xorwf	chan_tmp,w
	bnz		hn0
	movlw	d'4'
	movwf	chan_tmp
	goto	hn0
hn1
	movf	keydata,w		
	xorlw	0x02			;down pressed?
	bnz		hn3				;no, then end (it was enter)
	decf	chan_tmp,f	;yes, decrement treshold
	movlw	d'0'			;lowest channel is 1
	xorwf	chan_tmp,w
	bnz		hn0
	movlw	d'1'
	movwf	chan_tmp
	goto	hn0
hn3
	;---------------------------
	;now we change the note assignment for the choosen channel....
	movf	chan_tmp,w		;get currrent channel
	xorlw	0x01			;is it 1?
	skpnz					;no then next check
	goto	hn_note1		;yes, then handle note 1
	movf	chan_tmp,w
	xorlw	0x02			; is it 2?
	skpnz
	goto	hn_note2		;then handle note2
	movf	chan_tmp,w
	xorlw	0x03			;is it 3?
	skpnz
	goto	hn_note3		;then handle note 3
							; nothing, than it has to be channel 4...
	goto	hn_note4		;handle note 4

hn_note1
	movlw	b'11001100'		;cursor on pos 12 at 2nd row
	call	Disp_send_conf
	movf	note1,w			;output current value on display
	call	bin2asc
	movf	asciiH,w
	call	Disp_send_data
	movf	asciiT,w
	call	Disp_send_data
	movf	asciiO,w
	call	Disp_send_data
	movlw	b'11001110'		;cursor on pos 14 at 2nd row
	call	Disp_send_conf
	call	waitforrelease	;wait until no key pressed
	call	getkey			;get new status
	XORLW	0x01			;up?
	bnz		hn_n11			;no, then branch
	incf	note1,f			;yes, then increment value
	movlw	0xff			;config not saved
	movwf	curr_config
	movlw	d'128'			;maximum note is 127
	xorwf	note1,w
	bnz		hn_note1
	movlw	d'127'
	movwf	note1
	goto	hn_note1
hn_n11
	movf	keydata,w		
	xorlw	0x02			;down pressed?
	bnz		hn_n12			;no, then end (it was enter)
	decf	note1,f			;yes, decrement treshold
	movlw	0xff			;config not saved
	movwf	curr_config
	movlw	d'255'			;minimum note is 0
	xorwf	note1,w
	bnz		hn_note1
	clrf	note1
	goto	hn_note1
hn_n12
	movlw	b'00001100'		;cursor off and blinking off
	call	Disp_send_conf	
	goto	hm_noteassign	;and finish
	
hn_note2
	movlw	b'11001100'		;cursor on pos 12 at 2nd row
	call	Disp_send_conf
	movf	note2,w			;output current value on display
	call	bin2asc
	movf	asciiH,w
	call	Disp_send_data
	movf	asciiT,w
	call	Disp_send_data
	movf	asciiO,w
	call	Disp_send_data
	movlw	b'11001110'		;cursor on pos 14 at 2nd row
	call	Disp_send_conf
	call	waitforrelease	;wait until no key pressed
	call	getkey			;get new status
	XORLW	0x01			;up?
	bnz		hn_n21			;no, then branch
	incf	note2,f			;yes, then increment value
	movlw	0xff			;config not saved
	movwf	curr_config
	movlw	d'128'			;maximum note is 127
	xorwf	note2,w
	bnz		hn_note2
	movlw	d'127'
	movwf	note2
	goto	hn_note2
hn_n21
	movf	keydata,w		
	xorlw	0x02			;down pressed?
	bnz		hn_n22			;no, then end (it was enter)
	decf	note2,f			;yes, decrement treshold
	movlw	0xff			;config not saved
	movwf	curr_config
	movlw	d'255'			;minimum note is 0
	xorwf	note2,w
	bnz		hn_note2
	clrf	note2
	goto	hn_note2
hn_n22
	movlw	b'00001100'		;cursor off and blinking off
	call	Disp_send_conf	
	goto	hm_noteassign	;and finish

hn_note3
	movlw	b'11001100'		;cursor on pos 12 at 2nd row
	call	Disp_send_conf
	movf	note3,w			;output current value on display
	call	bin2asc
	movf	asciiH,w
	call	Disp_send_data
	movf	asciiT,w
	call	Disp_send_data
	movf	asciiO,w
	call	Disp_send_data
	movlw	b'11001110'		;cursor on pos 14 at 2nd row
	call	Disp_send_conf
	call	waitforrelease	;wait until no key pressed
	call	getkey			;get new status
	XORLW	0x01			;up?
	bnz		hn_n31			;no, then branch
	incf	note3,f			;yes, then increment value
	movlw	0xff			;config not saved
	movwf	curr_config
	movlw	d'128'			;maximum note is 127
	xorwf	note3,w
	bnz		hn_note3
	movlw	d'127'
	movwf	note3
	goto	hn_note3
hn_n31
	movf	keydata,w		
	xorlw	0x02			;down pressed?
	bnz		hn_n32			;no, then end (it was enter)
	decf	note3,f			;yes, decrement treshold
	movlw	0xff			;config not saved
	movwf	curr_config
	movlw	d'255'			;minimum note is 0
	xorwf	note3,w
	bnz		hn_note3
	clrf	note3
	goto	hn_note3
hn_n32
	movlw	b'00001100'		;cursor off and blinking off
	call	Disp_send_conf	
	goto	hm_noteassign	;and finish
	
hn_note4
	movlw	b'11001100'		;cursor on pos 12 at 2nd row
	call	Disp_send_conf
	movf	note4,w			;output current value on display
	call	bin2asc
	movf	asciiH,w
	call	Disp_send_data
	movf	asciiT,w
	call	Disp_send_data
	movf	asciiO,w
	call	Disp_send_data
	movlw	b'11001110'		;cursor on pos 14 at 2nd row
	call	Disp_send_conf
	call	waitforrelease	;wait until no key pressed
	call	getkey			;get new status
	XORLW	0x01			;up?
	bnz		hn_n41			;no, then branch
	incf	note4,f			;yes, then increment value
	movlw	0xff			;config not saved
	movwf	curr_config
	movlw	d'128'			;maximum note is 127
	xorwf	note4,w
	bnz		hn_note4
	movlw	d'127'
	movwf	note4
	goto	hn_note4
hn_n41
	movf	keydata,w		
	xorlw	0x02			;down pressed?
	bnz		hn_n42			;no, then end (it was enter)
	decf	note4,f			;yes, decrement treshold
	movlw	0xff			;config not saved
	movwf	curr_config
	movlw	d'255'			;minimum note is 0
	xorwf	note4,w
	bnz		hn_note4
	clrf	note4
	goto	hn_note4
hn_n42
	movlw	b'00001100'		;cursor off and blinking off
	call	Disp_send_conf	
	goto	hm_noteassign	;and finish

;-----------------------
handle_gain
	movlw	b'11000000'		;cursor on pos 0 at 2nd row
	call	Disp_send_conf
	strout 	msg_do_gain		;next text in 2nd row
hg0	
	movlw	b'11001110'		;cursor on pos 14 at 2nd row
	call	Disp_send_conf
	movf	gain,w			;output current gain value on display
	call	bin2asc
	movf	asciiO,w
	call	Disp_send_data
	call	waitforrelease	;wait until no key pressed
	call	getkey			;get new status
	XORLW	0x01			;up?
	bnz		hg1				;no, then branch
	incf	gain,f			;yes, then increment value
	movlw	0xff			;config not saved
	movwf	curr_config
	movlw	d'3'			;maximum for gain is 2
	xorwf	gain,w
	bnz		hg0
	movlw	d'2'
	movwf	gain
	goto	hg0
hg1
	movf	keydata,w		
	xorlw	0x02			;down pressed?
	bnz		hg3				;no, then end (it was enter)
	decf	gain,f			;yes, decrement treshold
	movlw	0xff			;config not saved
	movwf	curr_config
	movlw	d'0'			;minimum for gain is 1
	xorwf	gain,w
	bnz		hg0
	movlw	0x01
	movwf	gain
	goto	hg0
hg3
	goto	hm_gain
;-----------------------
handle_veloc_c
	movlw	b'11000000'		;cursor on pos 0 at 2nd row
	call	Disp_send_conf
	strout 	msg_do_veloc_c	;next text in 2nd row
hv0	
	movlw	b'11001010'		;cursor on pos 10 at 2nd row
	call	Disp_send_conf

	movf	veloc_c,w		;velocity_curve to w
	xorlw	0x03			;is it 3=Log 3?
	bnz 	hv00		;no, then skip next
	strout	msg_do_veloc_c3
hv00
	movf	veloc_c,w		;velocity_curve to w
	xorlw	0x02			;is it 2=Log 2?
	bnz 	hv01		;no, then skip next
	strout	msg_do_veloc_c2
hv01
	movf	veloc_c,w		;velocity_curve to w
	xorlw	0x01			;is it 1=Log1?
	bnz		hv02		;no, then skip next
	strout	msg_do_veloc_c1
hv02
	movf	veloc_c,w		;velocity_curve to w
	bnz		hv03		;is it 0=Lin? no, then skip next
	strout	msg_do_veloc_c0
hv03
	call	waitforrelease	;wait until no key pressed
	call	getkey			;get new status
	XORLW	0x01			;up?
	bnz		hv1				;no, then branch
	incf	veloc_c,f		;yes, then increment value
	movlw	0xff			;config not saved
	movwf	curr_config
	movlw	d'4'			;maximum for veloc_c is 3
	xorwf	veloc_c,w
	bnz		hv0
	movlw	d'3'
	movwf	veloc_c
	goto	hv0
hv1
	movf	keydata,w		
	xorlw	0x02			;down pressed?
	bnz		hv3				;no, then end (it was enter)
	decf	veloc_c,f		;yes, decrement value
	movlw	0xff			;config not saved
	movwf	curr_config
	movlw	0xff			;minimum for veloc_c is 0
	xorwf	veloc_c,w
	bnz		hv0
	clrf	veloc_c
	goto	hv0
hv3
	goto	hm_veloc_c
;-----------------------
handle_midichannel
	movlw	b'11000000'		;cursor on pos 0 at 2nd row
	call	Disp_send_conf
	strout 	msg_do_midichan	;next text in 2nd row
hm0	
	movlw	b'11001101'		;cursor on pos 13 at 2nd row
	call	Disp_send_conf
	movf	midi_chan,w		;output current retrigger value on display
	addlw	0x01			;to change output from internal 0..15 into 1..16
	call	bin2asc
	movf	asciiT,w
	call	Disp_send_data
	movf	asciiO,w
	call	Disp_send_data
	call	waitforrelease	;wait until no key pressed
	call	getkey			;get new status
	XORLW	0x01			;up?
	bnz		hm1				;no, then branch
	incf	midi_chan,f	;yes, then increment value
	movlw	0xff			;config not saved
	movwf	curr_config
	movlw	d'16'			;maximum for retrigger is 15
	xorwf	midi_chan,w
	bnz		hm0
	movlw	d'15'
	movwf	midi_chan
	goto	hm0
hm1
	movf	keydata,w		
	xorlw	0x02			;down pressed?
	bnz		hm3				;no, then end (it was enter)
	decf	midi_chan,f		;yes, decrement channel
	movlw	0xff			;config not saved
	movwf	curr_config
	movlw	d'255'			;minimum for midi_channel is 0
	xorwf	midi_chan,w
	bnz		hm0
	clrf	midi_chan
	goto	hm0
hm3
	goto	hm_midichannel
;-----------------------
handle_resetfactory
	call	reset_factory
	movlw	b'11000000'		;cursor on pos 0 at 2nd row
	call	Disp_send_conf
	strout 	msg_done		;next text in 2nd row
	call	Delay100ms		;wait for unser to recognise it.
	call	Delay100ms
	call	Delay100ms
	call	Delay100ms
	call	Delay100ms
	call	Delay100ms
	goto	hm_resetfactory
;---------------------------------------------------------------
;reset_factory
;sets vital parameters to factory-default
;---------------------------------------------------------------
reset_factory
	movlw	d'36'		;kick
	movwf	note1
	movlw	d'38'		;snare
	movwf	note2
	movlw	d'42'		;hihat
	movwf	note3
	movlw	d'55'		;crash
	movwf	note4
	movlw	d'32'		;no trigger below velocity of32
	movwf	treshold

	movlw	d'50'		;no retriggering within ca. 40ms
						;1 run is about 0,8 ms
	movwf	retrig1
	movwf	retrig2
	movwf	retrig3
	movwf	retrig4
	movwf	retrig_default
	movlw	0x09		;standard for MIDI-Channel
	movwf	midi_chan
	movlw	0x01		;Gain=1
	movwf	gain
	clrf	veloc_c		;Velocity=0=Linear
	
	clrf	curr_config ;we are in default-config now (00)
	;now save current config to eeprom 0x00
	clrf	eprom_adr		;Adress 0x00
	movf	curr_config,w
	movwf	eprom_dat
	call	eprom_write		;save it
	
	return
;---------------------------------------------------------------
;EEPROM handling routines
;---------------------------------------------------------------
;eprom read: Address in eprom_adr, return value in w
;---------------------------------------------------------------
eprom_read
	bcf		PIR2, EEIF		;clear interrupt flag (necessary?)
	movf	eprom_adr,w		;Set adress of read
	banksel	EEADR
	movwf	EEADR
	
	banksel	EECON1
	bcf		EECON1,EEPGD	;we want to read data mem
	bsf		EECON1,RD		;init read
	banksel	EEDATA
	movf	EEDATA,w
	bcf		STATUS,RP0		;back to bank 0 (our standard)
	bcf		STATUS,RP1
;	banksel	PORTA			;back to Bank 0 (our standard)
	return
;-------------------------------------------------------------------------
;eprom write Address in eprom_adr, data in eprom_dat returns when finished
;-------------------------------------------------------------------------
eprom_write
	bcf		PIR2, EEIF		;clear interrupt (to be sure)
	movf	eprom_adr,w		;load Adress
	banksel	EEADR
	movwf	EEADR
	banksel	0x00
	movf	eprom_dat,w	;load value
	banksel	EEDATA
	movwf	EEDATA
	banksel	EECON1
	bcf		EECON1,EEPGD	;we want to write data mem
	bsf		EECON1,WREN		;enable write
	
	bcf		INTCON,GIE		;we don't want interrupts now
	btfsc	INTCON,GIE		;make sure it is really cleared
	goto	$-2
	movlw	0x55			;see datasheet, required sequence
	movwf	EECON2
	movlw	0xaa
	movwf	EECON2
	bsf		EECON1,WR		;set write bit to begin write
	bsf		INTCON,GIE		;re-enable global interrupts
	
	banksel	0x00			;back to Bank0 (our default)
	btfss	PIR2,EEIF		;wait for flag to be set (polling)
	goto	$-1
	bcf		PIR2,EEIF		;clear it, write complete

	banksel	EECON1
	bcf		EECON1,WREN		;clear write enable
	banksel	0x00

	return
;---------------------------------------------------------------
;bin2asc
;converts 8-bit value in w to 3-digit ascii value
;value is in global variables asciiO to asciiH
;---------------------------------------------------------------
bin2asc
	movwf	asciiO		;start with value in asciiO
	movlw	a'0'
	movwf	asciiT
	movwf	asciiH
do100s
	movlw	d'100'
	subwf	asciiO,w
	bnc		do10s
	movwf	asciiO
	incf	asciiH,f
	goto	do100s
do10s
	movlw	d'10'
	subwf	asciiO,w
	bnc		adjust
	movwf	asciiO
	incf	asciiT,f
	goto	do10s
adjust
	movlw	a'0'
	addwf	asciiO,f
	return
;---------------------------------------------------------------	
;key handling
;returns status of keys in w
;0= nothing pressed
;1= RB5 pressed(up)
;2= RB6 pressed(down)
;3= both pressed (enter)
;---------------------------------------------------------------
;doesn't wait for anything, just checks current status
keycheck
	movf	PORTB,w
	movwf	keydata
	swapf	keydata,f			;get status of port B und 
	rrf		keydata,f			;shift bit 5 & 6 to bit  0 & 1
	movlw	b'00000011'			;finally mask Bit 0 and 1
	andwf	keydata,f
	movlw	b'00000011'
	xorwf	keydata,f			;and set seem to positive logic
								;because keys are active=low
	movf	keydata,w			;save to w for calling routine
	return
;waits for key to be pressed
getkey
	call 	keycheck
	skpnz						;if no key pressed
	goto 	getkey				;check again
	return						;otherwise return to caller
;waits for release of any key
waitforrelease
	call 	Delay10ms			;debounce
	call	keycheck
	movf	keydata,w
	skpz						;if zero then enough
	goto	waitforrelease
	call 	Delay10ms			;debounce
	return
;---------------------------------------------------------------	
;String Routines for using the LCD Display
;---------------------------------------------------------------
;disp_string
;sends string at look_hi/look_lo to display at current cursor position
;ends at 0x00 (end criteria)
Disp_string
	call 	lookup			;char of string to w
	clrf	PCLATH			;we were in pgm-mem Page1, so reset to Page 0
	andlw	0xff			;set Z-Flag if zero
	skpnz					;if zero (last char)
	return					;end routine
	call Disp_send_data
	goto Disp_string


;lookup
;jump to address in look_hi/look_lo which is a RETLW
;increment pointer afterwards
lookup
	movf	look_hi,w		;set PCLATH
	movwf	PCLATH
	movf	look_lo,w		;and get PCL
	incf	look_lo,f		;next position
	skpnz
	incf	look_hi,f		;also if overflow
	movwf	PCL				;now jump
;---------------------------------------------------------------	
;Display Routines for using the LCD Display
;---------------------------------------------------------------

;clear display and return cursor home
Disp_clear
	movlw	b'00000001'		;Clear Display
	call 	Disp_send_conf
	return
;Initialize Display	
Disp_Init
	call 	Delay50ms		;Wait for Display to be ready (first Start)
	
	movlw	b'00000010'		;Init to 4-Bit Mode (this time in 8-Bit Mode)
	movwf	DISPPort
	bsf		DISPPort,DISPE	;pulse Enable
	nop
	bcf		DISPPort,DISPE	
	call	Delay10ms
	;once more...
	movlw	b'00000010'		;Init to 4-Bit Mode (this time in 8-Bit Mode)
	movwf	DISPPort
	bsf		DISPPort,DISPE	;pulse Enable
	nop
	bcf		DISPPort,DISPE	
	call 	Delay10ms
	;once more...
	movlw	b'00000010'		;Init to 4-Bit Mode (this time in 8-Bit Mode)
	movwf	DISPPort
	bsf		DISPPort,DISPE	;pulse Enable
	nop
	bcf		DISPPort,DISPE	
	call 	Delay10ms
	
	movlw	b'00101000'		;Display Init two rows (now in 4-Bit Mode)
	call 	Disp_send_conf
	call	Delay10ms
	movlw	b'00001100'		;Display on, Cursor off, No Blinking
	call 	Disp_send_conf
	call 	Delay10ms
	movlw	b'00000001'		;Clear Display
	call 	Disp_send_conf
	call	Delay10ms
	movlw	b'00000110'		;cursor auto-increment
	call	Disp_send_conf
	call	Delay10ms
	movlw	high Disp_init_chars	;cause this routine is in Page 1
	movwf	PCLATH
	call	Disp_init_chars
	clrf	PCLATH			;we were in pgm-mem Page1, so reset to Page 0
	return

	
;Send Config-Data to Display (RS=0)
Disp_send_conf
	movwf	Dispdata		;save w
	movlw	0x80			;this is because we need to retain status
							;of upper nibble (LED at Bit 7)
	andwf	DISPPort,f		;mask upper nibble, set lower nibble to 0
	swapf	Dispdata,w		;first we send upper nibble
	andlw	0x0f			;mask it
	iorwf	DISPPort,f		;output it
	bsf		DISPPort,DISPE	;pulse Enable
	nop
	bcf		DISPPort,DISPE
	nop
	movlw	0x80
	andwf	DISPPort,f		;mask upper nibble, set lower nibble to 0
	movf	Dispdata,w		;and once again with lower nibble
	andlw	0x0f
	iorwf	DISPPort,f
	bsf		DISPPort,DISPE
	nop
	bcf		DISPPort,DISPE
	call 	Delay100us
	return
;Send Data to Display (RS=1)
Disp_send_data
	movwf	Dispdata		;save w
	movlw	0x80			;this is because we need to retain status
							;of upper nibble (LED at Bit 7)
	andwf	DISPPort,f		;mask upper nibble, set lower nibble to 0
	swapf	Dispdata,w		;first we send upper nibble
	andlw	0x0f			;mask it
	iorwf	DISPPort,f		;output it
	bsf		DISPPort,DISPRS		;RS=high for Data write
	nop
	bsf		DISPPort,DISPE	;pulse Enable
	nop
	bcf		DISPPort,DISPE
	nop
	movlw	0x80			;this is because we need to retain status
							;of upper nibble (LED at Bit 7)
	andwf	DISPPort,f		;mask upper nibble, set lower nibble to 0
	movf	Dispdata,w		;and once again with lower nibble
	andlw	0x0f
	iorwf	DISPPort,f
	bsf		DISPPort,DISPRS		;RS=high for Data write
	nop
	bsf		DISPPort,DISPE
	nop
	bcf		DISPPort,DISPE
	call 	Delay100us
	return	

;Delay-Subroutines (for fosc=20 MHz!!!)

Delay4us
	goto	$+1
	goto	$+1
	goto	$+1
	goto	$+1
	goto	$+1
	goto	$+1
	goto	$+1
	goto	$+1
	return
;-----
Delay10us
	movlw	0x0f
	movwf	d1
	decfsz	d1,f
	goto	$-1
	return
;-----
Delay100us					;Delays ca. 100us
	movlw	0xa5
	movwf	d1
	decfsz 	d1,f
	goto $-1
	return
;-----
Delay10ms					;Delays ca.10ms
	movlw	0x0e
	movwf	d1
	movlw	0x28
	movwf	d2
Delay10ms_1
	decfsz d1,f
	goto $+2
	decfsz d2,f
	goto Delay10ms_1
	
	goto	$+1
	nop
	return
;-----
Delay50ms					;Delays ca.50ms
	movlw	0x4e
	movwf	d1
	movlw	0xc4
	movwf	d2
Delay50ms_1
	decfsz d1,f
	goto $+2
	decfsz d2,f
	goto Delay50ms_1
	
	goto	$+1
	nop
	return
;-----
Delay100ms					;Delays ca.100ms
	movlw	0x03
	movwf	d1
	movlw	0x18
	movwf	d2
	movlw	0x02
	movwf	d3
Delay100ms_1
	decfsz 	d1,f
	goto 	$+2
	decfsz 	d2,f
	goto	$+2
	decfsz	d3,f
	goto 	Delay100ms_1
	
	goto	$+1
	return
;-----
;-----------------------------------------------
	org	0x800	;define next in memory Page 1 (we need space in Page 0)	
;----------
;Initializes special Characters
Disp_init_chars
	movlw	b'01000000'		;1st Character CG RAM
	call	Disp_send_conf_l
	movlw	b'00000000'		;1st line
	call	Disp_send_data_l
	movlw	b'00000000'		;2nd line
	call	Disp_send_data_l
	movlw	b'00000000'		;3rd line
	call	Disp_send_data_l
	movlw	b'00000000'		;4th line
	call	Disp_send_data_l
	movlw	b'00000000'		;5th line
	call	Disp_send_data_l
	movlw	b'00000000'		;6th line
	call	Disp_send_data_l
	movlw	b'00000000'		;7th line
	call	Disp_send_data_l
	movlw	b'00011111'		;8th line
	call	Disp_send_data_l
	;-
	movlw	b'01001000'		;2nd Character CG RAM
	call	Disp_send_conf_l
	movlw	b'00000000'		;1st line
	call	Disp_send_data_l
	movlw	b'00000000'		;2nd line
	call	Disp_send_data_l
	movlw	b'00000000'		;3rd line
	call	Disp_send_data_l
	movlw	b'00000000'		;4th line
	call	Disp_send_data_l
	movlw	b'00000000'		;5th line
	call	Disp_send_data_l
	movlw	b'00000000'		;6th line
	call	Disp_send_data_l
	movlw	b'00011111'		;7th line
	call	Disp_send_data_l
	movlw	b'00011111'		;8th line
	call	Disp_send_data_l
	;-
	movlw	b'01010000'		;3d Character CG RAM
	call	Disp_send_conf_l
	movlw	b'00000000'		;1st line
	call	Disp_send_data_l
	movlw	b'00000000'		;2nd line
	call	Disp_send_data_l
	movlw	b'00000000'		;3rd line
	call	Disp_send_data_l
	movlw	b'00000000'		;4th line
	call	Disp_send_data_l
	movlw	b'00000000'		;5th line
	call	Disp_send_data_l
	movlw	b'00011111'		;6th line
	call	Disp_send_data_l
	movlw	b'00011111'		;7th line
	call	Disp_send_data_l
	movlw	b'00011111'		;8th line
	call	Disp_send_data_l
	;-
	movlw	b'01011000'		;4th Character CG RAM
	call	Disp_send_conf_l
	movlw	b'00000000'		;1st line
	call	Disp_send_data_l
	movlw	b'00000000'		;2nd line
	call	Disp_send_data_l
	movlw	b'00000000'		;3rd line
	call	Disp_send_data_l
	movlw	b'00000000'		;4th line
	call	Disp_send_data_l
	movlw	b'00011111'		;5th line
	call	Disp_send_data_l
	movlw	b'00011111'		;6th line
	call	Disp_send_data_l
	movlw	b'00011111'		;7th line
	call	Disp_send_data_l
	movlw	b'00011111'		;8th line
	call	Disp_send_data_l
	;-
	movlw	b'01100000'		;5th Character CG RAM
	call	Disp_send_conf_l
	movlw	b'00000000'		;1st line
	call	Disp_send_data_l
	movlw	b'00000000'		;2nd line
	call	Disp_send_data_l
	movlw	b'00000000'		;3rd line
	call	Disp_send_data_l
	movlw	b'00011111'		;4th line
	call	Disp_send_data_l
	movlw	b'00011111'		;5th line
	call	Disp_send_data_l
	movlw	b'00011111'		;6th line
	call	Disp_send_data_l
	movlw	b'00011111'		;7th line
	call	Disp_send_data_l
	movlw	b'00011111'		;8th line
	call	Disp_send_data_l
	;-
	movlw	b'01101000'		;6th Character CG RAM
	call	Disp_send_conf_l
	movlw	b'00000000'		;1st line
	call	Disp_send_data_l
	movlw	b'00000000'		;2nd line
	call	Disp_send_data_l
	movlw	b'00011111'		;3rd line
	call	Disp_send_data_l
	movlw	b'00011111'		;4th line
	call	Disp_send_data_l
	movlw	b'00011111'		;5th line
	call	Disp_send_data_l
	movlw	b'00011111'		;6th line
	call	Disp_send_data_l
	movlw	b'00011111'		;7th line
	call	Disp_send_data_l
	movlw	b'00011111'		;8th line
	call	Disp_send_data_l
	;-
	movlw	b'01110000'		;7th Character CG RAM
	call	Disp_send_conf_l
	movlw	b'00000000'		;1st line
	call	Disp_send_data_l
	movlw	b'00011111'		;2nd line
	call	Disp_send_data_l
	movlw	b'00011111'		;3rd line
	call	Disp_send_data_l
	movlw	b'00011111'		;4th line
	call	Disp_send_data_l
	movlw	b'00011111'		;5th line
	call	Disp_send_data_l
	movlw	b'00011111'		;6th line
	call	Disp_send_data_l
	movlw	b'00011111'		;7th line
	call	Disp_send_data_l
	movlw	b'00011111'		;8th line
	call	Disp_send_data_l
	;-
	movlw	b'01111000'		;8th Character CG RAM
	call	Disp_send_conf_l
	movlw	b'00011111'		;1st line
	call	Disp_send_data_l
	movlw	b'00011111'		;2nd line
	call	Disp_send_data_l
	movlw	b'00011111'		;3rd line
	call	Disp_send_data_l
	movlw	b'00011111'		;4th line
	call	Disp_send_data_l
	movlw	b'00011111'		;5th line
	call	Disp_send_data_l
	movlw	b'00011111'		;6th line
	call	Disp_send_data_l
	movlw	b'00011111'		;7th line
	call	Disp_send_data_l
	movlw	b'00011111'		;8th line
	call	Disp_send_data_l
	;-
	return

; Log Call routines to access Routines in Page 0
Disp_send_conf_l
	movwf	offset			;save temporarily to offset
	movlw	high Disp_send_conf
	movwf	PCLATH
	movf	offset,w
	call	Disp_send_conf
	movlw	high Disp_send_conf_l
	movwf	PCLATH
	return

Disp_send_data_l
	movwf	offset
	movlw	high Disp_send_data
	movwf	PCLATH
	movf	offset,w
	call	Disp_send_data
	movlw	high Disp_send_data_l
	movwf	PCLATH
	return
; Message definitions for display
msg_welcome		dt	"Drumtrigger V0.2",0x00
msg_welcome1	dt	"(C) S.ASMUS 2010",0x00
msg_run			dt	"Drumtrigger 1234",0x00
msg_changed		dt	"(new conf)",0x00
msg_default		dt	"(Default)",0x00
msg_conf1		dt	"(Config 1)",0x00
msg_conf2		dt	"(Config 2)",0x00
msg_conf3		dt	"(Config 3)",0x00
msg_conf4		dt	"(Config 4)",0x00
msg_mainmenu	dt	"Mainmenu",0x00
msg_exit		dt	"|Exit          >",0x00
msg_loadconf	dt	"<Load config   >",0x00
msg_saveconf	dt	"<Save config   >",0x00
msg_treshold	dt	"<Treshold      >",0x00
msg_retrigger	dt	"<Retrigger     >",0x00
msg_gain		dt  "<Gain          >",0x00
msg_veloc_c		dt  "<Velocity curve>",0x00
msg_noteassign	dt	"<Note assign   >",0x00
msg_midichan	dt	"<MIDI channel  >",0x00
msg_resetfact	dt	"<Reset factory |",0x00

msg_do_loadconf	dt	"Load config  <x>",0x00
msg_do_saveconf	dt	"Save config  <x>",0x00
msg_do_midichan	dt	"MIDI Chan.  <xx>",0x00
msg_do_treshold	dt	"Treshold   <xxx>",0x00
msg_do_retrigger	dt	"Retrigger  <xxx>",0x00
msg_do_gain		dt  "Gain         <x>",0x00
msg_do_veloc_c  dt  "VelocCur <xxxxx>",0x00
msg_do_veloc_c0 dt  "Lin  ",0x00
msg_do_veloc_c1 dt  "Log 1",0x00
msg_do_veloc_c2 dt  "Log 2",0x00
msg_do_veloc_c3 dt  "Log 3",0x00
msg_do_noteasssign	dt	"Note assign",0x00
msg_do_noteassignchan	dt	"Channel <x><xxx>",0x00
msg_done		dt	"***** Done *****",0x00
msg_conferror	dt	"*Invalid config*",0x00
msg_confsaved	dt	"**** saved *****",0x00
msg_confloaded	dt	"**** loaded ****",0x00

;----------------
; Velocity Data
veloc_curve1
	movwf	PCL
	dt 0x00,0x00,0x12,0x1D,0x24,0x2A,0x2F,0x33,0x37,0x3A
	dt 0x3C,0x3F,0x41,0x43,0x45,0x47,0x49,0x4A,0x4C,0x4D
	dt 0x4F,0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58
	dt 0x59,0x5A,0x5B,0x5C,0x5C,0x5D,0x5E,0x5F,0x5F,0x60
	dt 0x61,0x61,0x62,0x63,0x63,0x64,0x64,0x65,0x65,0x66
	dt 0x67,0x67,0x68,0x68,0x69,0x69,0x6A,0x6A,0x6A,0x6B
	dt 0x6B,0x6C,0x6C,0x6D,0x6D,0x6D,0x6E,0x6E,0x6F,0x6F
	dt 0x6F,0x70,0x70,0x70,0x71,0x71,0x72,0x72,0x72,0x73
	dt 0x73,0x73,0x74,0x74,0x74,0x74,0x75,0x75,0x75,0x76
	dt 0x76,0x76,0x77,0x77,0x77,0x77,0x78,0x78,0x78,0x78
	dt 0x79,0x79,0x79,0x7A,0x7A,0x7A,0x7A,0x7B,0x7B,0x7B
	dt 0x7B,0x7B,0x7C,0x7C,0x7C,0x7C,0x7D,0x7D,0x7D,0x7D
	dt 0x7E,0x7E,0x7E,0x7E,0x7E,0x7F,0x7F,0x7F

veloc_curve2
	movwf	PCL
	dt 0x00,0x01,0x0A,0x10,0x14,0x18,0x1A,0x1D,0x1F,0x21
	dt 0x23,0x25,0x27,0x28,0x2A,0x2B,0x2C,0x2E,0x2F,0x30
	dt 0x31,0x32,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B
	dt 0x3C,0x3D,0x3D,0x3E,0x3F,0x40,0x41,0x42,0x43,0x44
	dt 0x44,0x45,0x46,0x47,0x48,0x48,0x49,0x4A,0x4B,0x4C
	dt 0x4C,0x4D,0x4E,0x4F,0x4F,0x50,0x51,0x51,0x52,0x53
	dt 0x54,0x54,0x55,0x56,0x57,0x57,0x58,0x59,0x59,0x5A
	dt 0x5B,0x5B,0x5C,0x5D,0x5D,0x5E,0x5F,0x5F,0x60,0x61
	dt 0x61,0x62,0x63,0x63,0x64,0x65,0x65,0x66,0x67,0x67
	dt 0x68,0x69,0x69,0x6A,0x6B,0x6B,0x6C,0x6C,0x6D,0x6E
	dt 0x6E,0x6F,0x70,0x70,0x71,0x72,0x72,0x73,0x73,0x74
	dt 0x75,0x75,0x76,0x76,0x77,0x78,0x78,0x79,0x7A,0x7A
	dt 0x7B,0x7B,0x7C,0x7D,0x7D,0x7E,0x7E,0x7F

veloc_curve3
	movwf	PCL
	dt 0x00,0x02,0x04,0x06,0x08,0x0A,0x0C,0x0E,0x0F,0x11
	dt 0x13,0x15,0x17,0x19,0x1A,0x1C,0x1E,0x20,0x21,0x23
	dt 0x25,0x27,0x28,0x2A,0x2B,0x2D,0x2F,0x30,0x32,0x33
	dt 0x35,0x36,0x38,0x39,0x3B,0x3C,0x3E,0x3F,0x41,0x42
	dt 0x43,0x45,0x46,0x47,0x49,0x4A,0x4B,0x4D,0x4E,0x4F
	dt 0x50,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x5A,0x5B
	dt 0x5C,0x5D,0x5E,0x5F,0x60,0x61,0x62,0x63,0x64,0x65
	dt 0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6B,0x6C,0x6D
	dt 0x6E,0x6E,0x6F,0x70,0x70,0x71,0x72,0x72,0x73,0x74
	dt 0x74,0x75,0x75,0x76,0x76,0x77,0x77,0x78,0x78,0x79
	dt 0x79,0x7A,0x7A,0x7A,0x7B,0x7B,0x7C,0x7C,0x7C,0x7C
	dt 0x7D,0x7D,0x7D,0x7D,0x7E,0x7E,0x7E,0x7E,0x7E,0x7E
	dt 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F

;if ((high($)) != (high(msg_saveconf)))
;	messg "##### Messages cross page boundarys ######"
;endif
	
	end