;
; irq_hipri.inc: high priority interrupt handling
;
; bpm ticks, trigger falling edge and midi signals.
;
; 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).
;

hp_irq:
	movwf	hp_irq_wtmp
	movff	STATUS, hp_irq_statustmp
	movff	BSR, hp_irq_bsrtmp

; which interrupt occurred ?
hp_check_irq:
	; USART receive interrupt ? (midi sync)
  	btfsc	PIR1, RCIF 	
  	bra  	hp_irq_midi_in

	; ccp1 interrupt ? (din sync)
	btfsc	PIR1, CCP1IF
	bra		hp_irq_din_tick

	; timer 1 interrupt ? (internal clock)
  	btfsc	PIR1, TMR1IF
  	bra	  	hp_irq_bpm_tick

	; trigger / din falling edge interrupt ?
	btfsc	PIR2, TMR3IF
	bra		hp_irq_trig_end

	movff	hp_irq_bsrtmp, BSR
	movf	hp_irq_wtmp, W
	movff	hp_irq_statustmp, STATUS
	retfie

;
; external din sync tick
;
hp_irq_din_tick:
	; bypass din input if set off
	IFSETTINGOFF SETTING_DIN_IN, hp_irq_din_tick_stopped

	; if we are syncing to midi ignore din sync
	IFEVENT EVENT_MIDIRUN, hp_irq_din_tick_stopped
	; check if run/stop is up ?
	call	hp_irq_check_dinsync
	IFNOEVENT EVENT_DINRUN, hp_irq_din_tick_stopped

	; echo sync to din out
;	call	din_clock
	IFSETTINGONCALL SETTING_DIN_OUT, din_clock	

	; din sync 24 ppqn, so call player twice
	call	player_tick
	call	player_tick

	; send midi clock
;	call	midi_out_clock
	IFSETTINGONCALL SETTING_MIDIS_OUT, midi_out_clock

hp_irq_din_tick_stopped:
	; clear interrupt
	bcf		PIR1, CCP1IF
	bra		hp_check_irq

;
; internal clock tick (note: 48ppqn)
;
hp_irq_bpm_tick:
	; if we are syncing to midi or din ignore internal ticks
	IFEVENT EVENT_MIDIRUN, hp_irq_bpm_done
	IFEVENT EVENT_DINRUN, hp_irq_bpm_done

	; send syncs out if applicable
	IFNOTINMODE	MODE_RUN, hp_irq_bpm_tick_cont
	movlw	1
	andwf	bpmtick, W
	bnz		hp_irq_bpm_tick_cont
	; send din clock
	;call	din_clock
	IFSETTINGONCALL	SETTING_DIN_OUT, din_clock
	; send midi clock
	;call	midi_out_clock
	IFSETTINGONCALL	SETTING_MIDIS_OUT, midi_out_clock

	; note: sync start/stop is set in 9090.inc
hp_irq_bpm_tick_cont:
	; player_tick gets called 48 ppqn
	call	player_tick

hp_irq_bpm_skip:
	; store table pointers
	movff	TBLPTRH, hp_irq_tblptrh
	movff	TBLPTRL, hp_irq_tblptrl
	movff	TABLAT, hp_irq_tablat

	; reset timer 1 according to
	;  tempo value
	movf	tempo, W
	clrf	TBLPTRH
	bcf		STATUS, C
	rlcf	WREG, W			; tempo * 2
	btfsc	STATUS, C
	incf	TBLPTRH			; +$100 if >127
	addlw	bpm_table & 0xff
	movwf	TBLPTRL
	movlw	bpm_table >> 8
	addwfc	TBLPTRH, F
	TBLRD*+				; read high byte and increment
	movff	TABLAT, TMR1H
	TBLRD*				; read low byte
	movff	TABLAT, TMR1L

	; restore table pointers
	movff	hp_irq_tblptrl, TBLPTRL
	movff	hp_irq_tblptrh, TBLPTRH
	movff	hp_irq_tablat, TABLAT

hp_irq_bpm_done:
	; clear interrupt
	bcf		PIR1, TMR1IF
	bra		hp_check_irq

;
; midi in (midi clock in)
;
hp_irq_midi_in:
	; if we are slaving to din sync, ignore midi
	; note: this should not be skipped anymore because
	;       midi is listened for more than the sync
;	IFEVENT EVENT_DINRUN, hp_irq_midi_ignore
	call	midi_handlemidi
hp_irq_midi_ignore:
	; clear interrupt
  	bcf		PIR1, RCIF
	bra		hp_check_irq

;
; trigger width timer, we should clear triggers
;
hp_irq_trig_end:
	call	player_trig_off
	; clear interrupt
	bcf		PIR2, TMR3IF
	bra		hp_check_irq

;
; handles the din sync run/stop checking
;
; note: this function does not get called if din sync input
;       is set off
hp_irq_check_dinsync:
	; check if run/stop in din sync is clear (+5 sent) ?
	btfsc	DIN_IN_PORT, DIN_IN_STARTSTOP_PIN
	bra		hp_irq_nodinrun
	; din was running, just started ?
	IFNOEVENT EVENT_DINRUN, hp_irq_dimrun_started
	return
hp_irq_dimrun_started:
	; din sync started
	call	player_start
	SETEVENT EVENT_DINRUN
	return
hp_irq_nodinrun:
	; din is stopped but DINRUN-event was set
	;  => din sync was stopped
	IFEVENT EVENT_DINRUN, hp_irq_nodinrun_reset
	return
hp_irq_nodinrun_reset:
	call	player_stop
	CLEAREVENT EVENT_DINRUN
	return

External Labels :

hp_irq_check_dinsync
player_tick
midi_handlemidi
player_trig_off
player_start
player_stop