; program with:
; avrdude -p t2313 -c STK200 -i 50 -U flash:w:smatrig.hex   + code wheel = 4 (128kHz internal clock)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; TODO
; one shot on/off
; triggering while turnig the code wheel (position 8,A)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.nolist
.include "tn2313def.inc"
.list


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; registers

.def temp0 = r16
.def temp1 = r17
.def temp2 = r18
.def status = r19
;.def state1 = r19
;.def state2 = r20
.def clk_prescaler    = r21
.def timer_prescaler  = r22
.def timer_threshold  = r23
.def timer_init       = r24

.equ q = 0     ; flipflop
.equ qbar = 1
.equ firstflashmode = 2 ; set for first flash triggering
.equ secondflashmode = 3 ; set for second flash triggering
.equ lightningcatchmode = 4 ; set for lightning triggering
.equ lastswitchstate = 5 ; last state of botton

.equ OUTPUT_PORT = PORTB
.equ OUTPUT_PIN = 3

.equ SWITCH_PORT = PORTD
.equ SWITCH_PINPORT = PIND
.equ SWITCH_PIN = 2

.equ BUZZER_PORT = PORTD
.equ BUZZER_PIN = 5


.equ MICENABLE_PORT = PORTD
.equ MICENABLE_PIN = 6

.equ OPTO_PORT = PORTD
.equ LCD_CMD_PORT = PORTB
.equ RS = 0


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; constants

.equ tau_short = 4 ;verzögerungskonstante für wait_short (16mhz)
.equ tau_long = 2 ;verzögerungskonstante für wait_long (16mhz)

.equ trig_duration = 205

.equ mirrorup = 3
.equ mirrordown = 235

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; interrupt vector

.org 0x0000 rjmp RESET ; Reset Handler
.org 0x0001 rjmp EXT_INT0 ; External Interrupt0 Handler
.org 0x0002 rjmp EXT_INT1 ; External Interrupt1 Handler
;.org 0x0003 rjmp TIM1_CAPT ; Timer1 Capture Handler
;.org 0x0004 rjmp TIM1_COMPA ; Timer1 CompareA Handler
;.org 0x0005 rjmp TIM1_OVF ; Timer1 Overflow Handler
;.org 0x0006 rjmp TIM0_OVF ; Timer0 Overflow Handler
;.org 0x0007 rjmp USART0_RXC ; USART0 RX Complete Handler
;.org 0x0008 rjmp USART0_DRE ; USART0,UDR Empty Handler
;.org 0x0009 rjmp USART0_TXC ; USART0 TX Complete Handler
.org 0x000A rjmp ANA_COMP ; Analog Comparator Handler
.org 0x000B rjmp PCINT ; Pin Change Interrupt
;.org 0x000C rjmp TIMER1_COMPB ; Timer1 Compare B Handler
;.org 0x000D rjmp TIMER0_COMPA ; Timer0 Compare A Handler
;.org 0x000E rjmp TIMER0_COMPB ; Timer0 Compare B Handler
;.org 0x000F rjmp USI_START ; USI Start Handler
;.org 0x0010 rjmp USI_OVERFLOW ; USI Overflow Handler
;.org 0x0011 rjmp EE_READY ; EEPROM Ready Handler
;.org 0x0012 rjmp WDT_OVERFLOW ; Watchdog Overflow Handler

RESET:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; reduce clock
	ldi temp0, 0b10000000
	out CLKPR, temp0
;	0000 1
;	0001 2
;	0010 4
;	0011 8
;	0100 16
;	0101 32
;	0110 64
;	0111 128
;	1000 256
	ldi temp0, 0b00000000 ;/ 4
	out CLKPR, temp0

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; init stack
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	ldi temp0, LOW(RAMEND)
	out SPL, temp0

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; init variables
    ;ldi state1, 0xff
	;ldi state2, 0x00

	ldi status, (1<<qbar)|(0<<q)|(0<<lastswitchstate)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; configure pins (1=out, 0=in)
    ldi temp0, 0b00000000
	out DDRA, temp0

    ldi temp0, 0b00001000
	out DDRB, temp0

    ldi temp0, 0b01100000
	out DDRD, temp0


	sbi SWITCH_PORT, SWITCH_PIN ; pull-up switch

	cbi BUZZER_PORT, BUZZER_PIN ; switch off buzzer

	cbi MICENABLE_PORT, MICENABLE_PIN ; switch off micro

	cbi OUTPUT_PORT, OUTPUT_PIN ; set output low

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; configure timers
	; timer 0 (buzzer)
	ldi temp0, (0<<COM0B1)|(0<<COM0B0)|(1<<WGM01)|(0<<WGM00) ; buzzer ready and off
	out TCCR0A, temp0
	ldi temp0, (0<<CS02)|(0<<CS01)|(0<<CS00)|(0<<WGM02)
	out TCCR0B, temp0

	ldi temp0, 9
    out OCR0A, temp0
    out OCR0B, temp0

	; timer 1
	ldi temp0, (0<<COM1A1)|(0<<COM1A0)|(0<<WGM11)|(1<<WGM10) ;normal operation of pins
	out TCCR1A, temp0
	ldi temp0, (0<<CS12)|(0<<CS11)|(0<<CS10)|(0<<WGM13)|(1<<WGM12) ; stop timer
	out TCCR1B, temp0

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; minimize power

	;disable comparator
	ldi temp0, (1<<ACD)
	out ACSR, temp0

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; configure interrupts

; ISC11 ISC10 Description
; 0     0     The low level of INT1 generates an interrupt request.
; 0     1     Any logical change on INT1 generates an interrupt request.
; 1     0     The falling edge of INT1 generates an interrupt request.
; 1     1     The rising edge of INT1 generates an interrupt request.
;    ldi temp0, (1<<ISC11)|(1<<ISC10) ; interrupt on rising edge of INT1
;    out MCUCR, temp0

    ldi temp0, (1<<PCINT4)|(1<<PCINT5)|(1<<PCINT6)|(1<<PCINT7) ; set pin change interrupt for code switch
    out PCMSK, temp0


    ldi temp0, (1<<PCIE) ; enable pin change interrupt to detect code wheel action
    out GIMSK, temp0


	sei


	ldi temp0, 120
	rcall wait_long

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; read code switch

	in temp0, PINB


; shift input from top of byte to bottom (code wheel is connected to the upper nibble of port)
; lsr shifts down and feeds 0s to the highest bit
	lsr temp0
	lsr temp0
	lsr temp0
	lsr temp0

; subtract 1 from value to eliminate offset (code wheel starts with 1 not 0)
	dec temp0


; load base flash address of function table, see end of code (functable)
	ldi zh, high(functable<<1)
	ldi zl, low(functable<<1)

; double function number before addition because of 2-byte addresses in flash memory
	lsl temp0 ;  doubling by bit shift

; add doubled value of code wheel to base address
	ldi temp1, 0
	add zl, temp0
	adc zh, temp1

; load function address to temps
	lpm temp0, z+
	lpm temp1, z

; copy temps to z
	movw zl:zh, temp0:temp1

; call function (jump to address pointed by z)
	icall 

; main loop
main:
	rjmp main ; inf loop (hopefully never entered)










;===========================================================
;
; functions
;
;===========================================================
; activate output as long as the stwitch is pressed
; the method:
; put the uC into powerdown mode and set INT0 (botton) as 
; wake-up source. if the key is held down the prog jumps repetitively into
; the interrupt routine, but still executes one command between 
; each interrupt execution. that's low-level programming!
manual:
	; enable int0
	in temp0, GIMSK
    ori temp0, (1<<INT0)
	out GIMSK, temp0

; chose sleepmode and interrupt type
	ldi temp0, (0<<SM1)|(1<<SM0)|(1<<SE)|(0<<ISC11)|(0<<ISC10)|(0<<ISC01)|(0<<ISC00)
	out MCUCR, temp0                     ; low level on INT0 generates interrupt


manual_0:
	sbis SWITCH_PINPORT, SWITCH_PIN
	rjmp manual_1

	; if switch not pressed
	cbi OUTPUT_PORT, OUTPUT_PIN
	sleep
	rjmp manual_0

manual_1:
	; if switch pressed
	sbi OUTPUT_PORT, OUTPUT_PIN
	rjmp manual_0





;-----------------------------------------------------------
; toggle output by pressing switch
; implements flipflop
bulb:
	; enable int0
	in temp0, GIMSK
    ori temp0, (1<<INT0)
	out GIMSK, temp0

	; chose sleepmode and interrupt type
	ldi temp0, (0<<SM1)|(1<<SM0)|(1<<SE)|(0<<ISC11)|(0<<ISC10)|(0<<ISC01)|(0<<ISC00)
	out MCUCR, temp0                     ; low level on INT0 generates interrupt

bulb_0:
	sbis SWITCH_PINPORT, SWITCH_PIN
	rjmp bulb_1

	; if switch not pressed

	; save switch state
	cbr status, (1<<lastswitchstate)

	; copy q to qbar via flag T (prepare for toggle)
	bst status, q
	bld status, qbar

	sleep

	rjmp bulb_0

bulb_1:
	; if switch pressed	

	; first time pressed?
	sbrc status, lastswitchstate
	rjmp bulb_0

	; save switch state
	sbr status, (1<<lastswitchstate)


	; toggle flipflop by copying negated qbar to q
	sbrs status, qbar
	sbr status, (1<<q)
	sbrc status, qbar
	cbr status, (1<<q)

	sbrc status, q         ; copy fliplop state (q) to output
	sbi OUTPUT_PORT, OUTPUT_PIN
	sbrs status, q
	cbi OUTPUT_PORT, OUTPUT_PIN

	; beep on start and stop of function
	sbrc status, q
	rcall beep
	sbrs status, q
	rcall doublebeep

	rjmp bulb_0





;-----------------------------------------------------------
; standard lightning triggering
flash:
;0 0 The low level of INT1 generates an interrupt request.
;0 1 Any logical change on INT1 generates an interrupt request.
;1 0 The falling edge of INT1 generates an interrupt request.
;1 1 The rising edge of INT1 generates an interrupt request.

 	ldi temp0, (0<<SM1)|(0<<SM0)|(1<<SE)|(1<<ISC11)|(1<<ISC10)|(0<<ISC01)|(0<<ISC00) ; idle mode + rising edge int
	out MCUCR, temp0

	; disable preflash supression, trigger immediately
	;cbr status, (1<<ttlmode)
	sbr status, (1<<firstflashmode)

	in temp0, GIMSK
    ori temp0, (1<<INT1)
	out GIMSK, temp0

flash_0:
	sleep
	rjmp flash_0


;-----------------------------------------------------------
; ttl lightning triggering
flash_ttl:
;0 0 The low level of INT1 generates an interrupt request.
;0 1 Any logical change on INT1 generates an interrupt request.
;1 0 The falling edge of INT1 generates an interrupt request.
;1 1 The rising edge of INT1 generates an interrupt request.

 	ldi temp0, (0<<SM1)|(0<<SM0)|(1<<SE)|(1<<ISC11)|(1<<ISC10)|(0<<ISC01)|(0<<ISC00) ; idle mode + rising edge int
	out MCUCR, temp0

	; enable preflash supression
	sbr status, (1<<secondflashmode)

	in temp0, GIMSK
    ori temp0, (1<<INT1)
	out GIMSK, temp0

flash_ttl_0:
	sleep
	rjmp flash_ttl_0



;-----------------------------------------------------------
; lightning triggering
; principle: use timer1 to generate mirror-lockup periodic trigger.
; (slightly above 30 sec)
; set trigger if counter below threshold, clear if above.
; allow second trigger if time event between b and c
; test time in interrupt routine
;
; timing:
;----______________________________  pin
;0  a b                         c
;0-a mirror-lockup trigger
;b allow second trigger if counter below b
;c block second trigger if counter above c

lightning:
; reduce clock to get 32 s from 8 bits (30s is the mirror-up time)
;	0000 1
;	0001 2
;	0010 4
;	0011 8
;	0100 16
;	0101 32
;	0110 64
;	0111 128
;	1000 256
	ldi temp0, 0b10000000
	ldi temp1, 0b00000100

	out CLKPR, temp0
	out CLKPR, temp1 ;/ 8
;-------------

; enable int0 for switch
	in temp0, GIMSK
    ori temp0, (1<<INT0)
	out GIMSK, temp0

lightning_botton:

	sbis SWITCH_PINPORT, SWITCH_PIN
	rjmp lightning_1


	; if switch not pressed

	; save switch state
	cbr status, (1<<lastswitchstate)

	; copy q to qbar via flag T (prepare for toggle)
	bst status, q
	bld status, qbar

	; prepare sleep mode
	sbrc status, q
	ldi temp0, (0<<SM1)|(0<<SM0)|(1<<SE)|(1<<ISC11)|(1<<ISC10)|(0<<ISC01)|(0<<ISC00) ; idle mode for operation
	sbrs status, q
	ldi temp0, (0<<SM1)|(1<<SM0)|(1<<SE)|(1<<ISC11)|(1<<ISC10)|(0<<ISC01)|(0<<ISC00) ; power down mode for waiting

	out MCUCR, temp0
	sleep                   ; wait for activation
	rjmp lightning_botton


lightning_1:
	; if switch pressed	

	; first time pressed?
	sbrc status, lastswitchstate
	rjmp lightning_botton

	; save switch state
	sbr status, (1<<lastswitchstate)


	; toggle flipflop by copying negated qbar to q
	sbrs status, qbar
	sbr status, (1<<q)
	sbrc status, qbar
	cbr status, (1<<q)

	sbrs status, q
	rjmp lightning_stop


	; start procedures

	; set threshold
	ldi temp1, 0x00
	ldi temp0, 2
	out OCR1AH, temp1
	out OCR1AL, temp0

	; set counter close to top for immediate update of threshold
	ldi temp1, 0x00
	ldi temp0, 253
	out TCNT1H, temp1
	out TCNT1L, temp0   ;reset timer


	; timer 1
	; 1 0 Clear OC1A/OC1B on Compare Match, set OC1A/OC1B at TOP
	ldi temp0, (1<<COM1A1)|(0<<COM1A0)|(0<<WGM11)|(1<<WGM10)
	out TCCR1A, temp0

	;1 0 1 clkI/O/1024 (From prescaler)
	ldi temp0, (1<<CS12)|(0<<CS11)|(1<<CS10)|(0<<WGM13)|(1<<WGM12) ; stop timer
	out TCCR1B, temp0

	; set counter close to top for immediate triggering after function has been chosen
	ldi temp1, 0x00
	ldi temp0, 252
	out TCNT1H, temp1
	out TCNT1L, temp0   ;reset timer

	; prepare

	sbr status, (1<<lightningcatchmode)

	; beep on start of function
	rcall beep

	in temp0, GIMSK
    ori temp0, (1<<INT1)
	out GIMSK, temp0

	rjmp lightning_botton


	; stop procedures
	lightning_stop:

	; - disable int1
	; - clear trigger
	; - beep

	in temp0, GIMSK
    andi temp0, ~(1<<INT1)
	out GIMSK, temp0

	; clear interrupt flag
	in temp0, EIFR
	ori temp0, (1<<INTF1)
	out EIFR, temp0

	; switch to normal pin operation
	ldi temp0, (0<<COM1A1)|(0<<COM1A0)|(0<<WGM11)|(1<<WGM10) ;normal operation of pins    dirty!!!
	out TCCR1A, temp0


	cbi OUTPUT_PORT, OUTPUT_PIN

	; beep on stop of function
	rcall doublebeep

	rjmp lightning_botton





;-----------------------------------------------------------
sound:
; reduce clock
	ldi temp0, 0b10000000
	out CLKPR, temp0

	ldi temp0, 0b00000001 ;/ 4
	out CLKPR, temp0

	;;;;;;sbi MICENABLE_PORT, MICENABLE_PIN


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;,
	; wait to avoid selftriggering by the code wheel snapping
;	-ldi temp0, 255
;	-rcall wait_long

	;ldi temp0, (1<<AIN1D)|(1<<AIN0D)
	;out DIDR, temp0
;	ldi temp0, (1<<ACBG)|(1<<ACIE)
;	out ACSR, temp0

	;;;;;;;;;;;;ldi temp0, (0<<SM1)|(0<<SM0)|(1<<SE)|(0<<ISC11)|(0<<ISC10)|(0<<ISC01)|(0<<ISC00)
	;;;;;;;;;;out MCUCR, temp0



; enable int0 for switch
	in temp0, GIMSK
    ori temp0, (1<<INT0)
	out GIMSK, temp0
 
sound_botton:
	sbis SWITCH_PINPORT, SWITCH_PIN
	rjmp sound_pressed


	; if switch not pressed

	; copy q to qbar via flag T (prepare for toggle)
	bst status, q
	bld status, qbar

	; save switch state
	cbr status, (1<<lastswitchstate)

	; prepare sleep mode
	sbrc status, q
	ldi temp0, (0<<SM1)|(0<<SM0)|(1<<SE)|(0<<ISC11)|(0<<ISC10)|(0<<ISC01)|(0<<ISC00) ; idle mode
	sbrs status, q
	ldi temp0, (0<<SM1)|(1<<SM0)|(1<<SE)|(0<<ISC11)|(0<<ISC10)|(0<<ISC01)|(0<<ISC00) ; power down mode

	out MCUCR, temp0
	sleep
	rjmp sound_botton


sound_pressed:
	; if switch pressed	

	; first time pressed?
	sbrc status, lastswitchstate
	rjmp sound_botton

	; save switch state
	sbr status, (1<<lastswitchstate)

	; toggle flipflop by copying negated qbar to q
	sbrs status, qbar
	sbr status, (1<<q)
	sbrc status, qbar
	cbr status, (1<<q)

	sbrs status, q
	rjmp sound_stop

	; start procedures
		; enable mic
		sbi MICENABLE_PORT, MICENABLE_PIN

		; enable comparator (may cause an comparator interrupt!)
		ldi temp0, (1<<ACBG)|(0<<ACD)|(0<<ACIE)
		out ACSR, temp0

		; beep on start of function
		rcall beep

		; wait to avoid selftriggering by the code wheel snapping
		ldi temp0, 255
		rcall wait_long
		ldi temp0, 255
		rcall wait_long


		; clear interrupt flag
		in temp0, ACSR
		ori temp0, (1<<ACI)
		out ACSR, temp0

		; enable interrupt
		in temp0, ACSR
		ori temp0, (1<<ACIE)
		out ACSR, temp0


	rjmp sound_botton


	; stop procedures
	sound_stop:
		; disable sound interrupt
		ldi temp0, (0<<ACIE)
		out ACSR, temp0

		; disable mic
		cbi MICENABLE_PORT, MICENABLE_PIN
		; beep on stop of function
		rcall doublebeep

	rjmp sound_botton


;--------------------







;sound_0:
;	sleep
;	rjmp sound_0
; init one-shot timer
; enable mic
; enable comparator interrupt
; sleep




; clock prescaler
;	0000 1
;	0001 2
;	0010 4
;	0011 8
;	0100 16
;	0101 32
;	0110 64
;	0111 128
;	1000 256

; timer prescaler
;	0 0 0 No clock source (Timer/Counter stopped).
;	0 0 1 clkI/O/1 (No prescaling)
;	0 1 0 clkI/O/8 (From prescaler)
;	0 1 1 clkI/O/64 (From prescaler)
;	1 0 0 clkI/O/256 (From prescaler)
;	1 0 1 clkI/O/1024 (From prescaler)


interval1: ; ~.5s
	ldi clk_prescaler,   0b00001000 ; 256    <- cpu clock divider
	ldi timer_prescaler, 0b00000001 ; 1      <- timer clock divider
	ldi timer_threshold, 120        ;        <- trigger threshhold x / 255
	ldi timer_init,       20        ;        <- counter init (reduction of trigger delay after pressing botton)
	rcall interval
	
interval2: ; ~1s
	ldi clk_prescaler,   0b00000110 ; 64
	ldi timer_prescaler, 0b00000010 ; 8
	ldi timer_threshold, 175
	ldi timer_init,      100
	rcall interval

interval3: ; ~2s
	ldi clk_prescaler,   0b00000111 ; 128
	ldi timer_prescaler, 0b00000010 ; 8
	ldi timer_threshold, 215
	ldi timer_init,      135
	rcall interval

interval4: ; ~4s
	ldi clk_prescaler,   0b00001000 ; 256
	ldi timer_prescaler, 0b00000010 ; 8
	ldi timer_threshold, 235
	ldi timer_init,      222
	rcall interval

interval5: ; ~8s
	ldi clk_prescaler,   0b00000110 ; 64
	ldi timer_prescaler, 0b00000011 ; 64
	ldi timer_threshold, 245
	ldi timer_init,      236
	rcall interval

interval6: ; ~16s
	ldi clk_prescaler,   0b00000111 ; 128
	ldi timer_prescaler, 0b00000011 ; 64
	ldi timer_threshold, 250
	ldi timer_init,      242
	rcall interval

interval7: ; ~32s
	ldi clk_prescaler,   0b00001000 ; 256
	ldi timer_prescaler, 0b00000011 ; 64
	ldi timer_threshold, 253
	ldi timer_init,      245
	rcall interval

interval8: ; ~1min
	ldi clk_prescaler,   0b00000101 ; 32
	ldi timer_prescaler, 0b00000101 ; 1024
	ldi timer_threshold, 254
	ldi timer_init,      248
	rcall interval

interval9: ; ~2min
	ldi clk_prescaler,   0b00001000 ; 256
	ldi timer_prescaler, 0b00000100 ; 256
	ldi timer_threshold, 254
	ldi timer_init,      248
	rcall interval



;-----------------------------------------------------------
interval:
; generates pulses with 1 s interval. the switch toggles the 
; output. two different sleepmodes are used. powerdown for 
; disabled output and idle during pulse generation (counter
; must be on). the of/off machanism is similar to mode 'bulb'
; uses pwm mode 1, because the modes with non-fixed top were
; not working

; reduce clock to match interval (with lowest energy)
	ldi temp0, 0b10000000
	out CLKPR, temp0
	out CLKPR, clk_prescaler ;/ 256

; enable int0 for switch
	in temp0, GIMSK
    ori temp0, (1<<INT0)
	out GIMSK, temp0
 
interval_botton:
	sbis SWITCH_PINPORT, SWITCH_PIN
	rjmp interval_1


	; if switch not pressed

	; copy q to qbar via flag T (prepare for toggle)
	bst status, q
	bld status, qbar

	; save switch state
	cbr status, (1<<lastswitchstate)

	; prepare sleep mode
	sbrc status, q
	ldi temp0, (0<<SM1)|(0<<SM0)|(1<<SE)|(0<<ISC11)|(0<<ISC10)|(0<<ISC01)|(0<<ISC00) ; idle mode
	sbrs status, q
	ldi temp0, (0<<SM1)|(1<<SM0)|(1<<SE)|(0<<ISC11)|(0<<ISC10)|(0<<ISC01)|(0<<ISC00) ; power down mode

	out MCUCR, temp0
	sleep
	rjmp interval_botton


interval_1:
	; if switch pressed	

	; first time pressed?
	sbrc status, lastswitchstate
	rjmp interval_botton

	; save switch state
	sbr status, (1<<lastswitchstate)

	; toggle flipflop by copying negated qbar to q
	sbrs status, qbar
	sbr status, (1<<q)
	sbrc status, qbar
	cbr status, (1<<q)

	sbrs status, q
	rjmp interval_stop


	; start procedures

		;set threshold
		ldi temp1, 0x00
		out OCR1AH, temp1
		out OCR1AL, timer_threshold

		; start timer
		in temp0, TCCR1B
		cbr temp0, (1<<CS12)|(1<<CS11)|(1<<CS10)
		ori temp0, (0<<CS12)|(0<<CS11)|(1<<CS10) ; start timer
		out TCCR1B, temp0

		; set counter close to top for immediate update of threshold
		ldi temp1, 0x00
		ldi temp0, 253
		out TCNT1H, temp1
		out TCNT1L, temp0   ;reset timer

		; beep on start of function
		rcall beep

		; set counter close to threshold for immediate impuls output
		out TCNT1H, temp0
		out TCNT1L, timer_init

		; set prescaler
		in temp0, TCCR1B
		cbr timer_prescaler, ~((1<<CS12)|(1<<CS11)|(1<<CS10))
		cbr temp0, (1<<CS12)|(1<<CS11)|(1<<CS10)
		or temp0, timer_prescaler ;   (0<<CS12)|(0<<CS11)|(1<<CS10) ; start timer
		out TCCR1B, temp0

		; enable timer output
		in temp0, TCCR1A
		ori temp0, (1<<COM1A1)|(1<<COM1A0)
		out TCCR1A, temp0


	rjmp interval_botton


	; stop procedures
	interval_stop:
		; disable timer
		;ldi temp0, (0<<COM1A1)|(0<<COM1A0)|(0<COM1B1)|(0<<COM1B0)|(0<<WGM11)|(1<<WGM10) 
		;out TCCR1A, temp0
		in temp0, TCCR1A
		andi temp0, ~((1<<COM1A1)|(1<<COM1A0))
		;ldi temp0, (1<<COM1A1)|(1<<COM1A0)|(0<COM1B1)|(0<<COM1B0)|(0<<WGM11)|(1<<WGM10)	
		out TCCR1A, temp0

		; beep on stop of function
		rcall doublebeep

	rjmp interval_botton














;-----------------------------------------------------------
beep:
	in temp2, SREG ;disable interrupts to protect clock change operation
	cli

	in temp1, CLKPR
	andi temp1, 0b00001111

	ldi temp0, 0b10000000
	out CLKPR, temp0

	ldi temp0, 0b00000001 ;/ 2
	out CLKPR, temp0

	in temp0, TCCR0B
	ori temp0, (0<<CS02)|(0<<CS01)|(1<<CS00)
	out TCCR0B, temp0

	in temp0, TCCR0A
	ori temp0, (1<<COM0B0)
	out TCCR0A, temp0

	ldi temp0, 80
	rcall wait_long

	in temp0, TCCR0A
	andi temp0, ~(1<<COM0B0)
	out TCCR0A, temp0

	in temp0, TCCR0B
	andi temp0, ~((0<<CS02)|(0<<CS01)|(1<<CS00))
	out TCCR0B, temp0

	ldi temp0, 0b10000000
	out CLKPR, temp0
	out CLKPR, temp1

	out SREG, temp2 ; restor SREG

	ret

;-----------------------------------------------------------
doublebeep:
	in temp2, SREG ;disable interrupts to protect clock change operation
	cli

	in temp1, CLKPR
	andi temp1, 0b00001111

	ldi temp0, 0b10000000
	out CLKPR, temp0
	ldi temp0, 0b00000001 ;/ 2
	out CLKPR, temp0

	in temp0, TCCR0B
	ori temp0, (0<<CS02)|(0<<CS01)|(1<<CS00)
	out TCCR0B, temp0

	in temp0, TCCR0A
	ori temp0, (1<<COM0B0)
	out TCCR0A, temp0

	ldi temp0, 80
	rcall wait_long

	in temp0, TCCR0A
	andi temp0, ~(1<<COM0B0)
	out TCCR0A, temp0


	ldi temp0, 180
	rcall wait_long


	in temp0, TCCR0A
	ori temp0, (1<<COM0B0)
	out TCCR0A, temp0

	ldi temp0, 80
	rcall wait_long

	in temp0, TCCR0A
	andi temp0, ~(1<<COM0B0)
	out TCCR0A, temp0

	in temp0, TCCR0B
	andi temp0, ~((0<<CS02)|(0<<CS01)|(1<<CS00))
	out TCCR0B, temp0

	ldi temp0, 0b10000000
	out CLKPR, temp0
	out CLKPR, temp1

	out SREG, temp2 ; restor SREG

	ret




;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; interrupt routines
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; switch
EXT_INT0:
	;sbi PORTB, 3

	push temp0
	push temp1
	in temp0, SREG
	push temp0
	; TODO!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 	; stay in loop until botton released
EXT_INT0_0:
	;sbis SWITCH_PINPORT, SWITCH_PIN
	;rjmp EXT_INT0_0

	; set botton flag


	; clear INT0 interrupt flag
	;in temp0, EIFR
	;ori temp0, (1<<INTF0)
	;out EIFR, temp0

	pop temp0
	out SREG, temp0
	pop temp1
	pop temp0
	reti





;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; lightinig
EXT_INT1:
	;sbrs status, ttlmode
	sbrc status, firstflashmode
	sbi OUTPUT_PORT, OUTPUT_PIN

	push temp0
	push temp1
	in temp0, SREG
	push temp0


	sbrc status, firstflashmode
	rjmp immediate_trigger

	sbrc status, secondflashmode
	rjmp secondflash

	sbrc status, lightningcatchmode
	rjmp lightningcatch

	rjmp end_int1


;-----------------------------------------------------------
; immediate trigger
immediate_trigger:
	ldi temp0, trig_duration
	rcall wait_long
	ldi temp0, trig_duration
	rcall wait_long
	ldi temp0, trig_duration
	rcall wait_long
	ldi temp0, trig_duration
	rcall wait_long
	ldi temp0, trig_duration
	rcall wait_long
	ldi temp0, trig_duration
	rcall wait_long
	ldi temp0, trig_duration
	rcall wait_long
	ldi temp0, trig_duration
	rcall wait_long
	ldi temp0, trig_duration
	rcall wait_long
	ldi temp0, trig_duration
	rcall wait_long
	cbi OUTPUT_PORT, OUTPUT_PIN

	rjmp end_int1


;-----------------------------------------------------------
; wait for second flash
secondflash:


	ldi temp1, 15   ; TODO 16 bit (wait time of ca 100 ms needed)
waitforsecondflash_outer:  ; double loop
	ldi temp0, 255

waitforsecondflash_inner:          ; <-------- 6 cycles
	in temp2, EIFR
	sbrc temp2, INTF1
	rjmp ttlflash
	dec temp0
	brne waitforsecondflash_inner  ; <--------

	dec temp1
	brne waitforsecondflash_outer

	rjmp end_int1

ttlflash:

	sbi OUTPUT_PORT, OUTPUT_PIN
	ldi temp0, trig_duration
	rcall wait_long
	ldi temp0, trig_duration
	rcall wait_long
	cbi OUTPUT_PORT, OUTPUT_PIN

	rjmp end_int1 ; 


;-----------------------------------------------------------
; trigger on lightning if mirror up
lightningcatch:
	in temp0, TCNT1L ; ???
	cpi temp0, mirrorup
	brlo end_int1 ; br if < (mirror not yet up)
	cpi temp0, mirrordown
	brsh end_int1 ; br if >= (mirror down again)

	; switch to normal pin operation
	ldi temp0, (0<<COM1A1)|(0<<COM1A0)|(0<<WGM11)|(1<<WGM10) ;normal operation of pins    dirty!!!
	out TCCR1A, temp0
	;in bla out

; trigger cam
	sbi OUTPUT_PORT, OUTPUT_PIN
	ldi temp0, 100
	rcall wait_long
	cbi OUTPUT_PORT, OUTPUT_PIN

; reset timer
	ldi temp1, 0x00
	ldi temp0, 220      ;<-- wait a few seconds to ensure that exposure has finished (220->4s)
	out TCNT1H, temp1
	out TCNT1L, temp0

; connect pin with timer
	ldi temp0, (1<<COM1A1)|(0<<COM1A0)|(0<<WGM11)|(1<<WGM10) ; timer output on pin    dirty!!!
	out TCCR1A, temp0

	rjmp end_int1 ; for the sake of completness



end_int1:
	; clear interrupt flag
	in temp0, EIFR
	ori temp0, (1<<INTF1)
	out EIFR, temp0

	pop temp0
	out SREG, temp0
	pop temp1
	pop temp0
	reti



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; microphone
ANA_COMP:
	push temp0
	push temp1
	in temp0, SREG
	push temp0

    ;cli

	sbi OUTPUT_PORT, OUTPUT_PIN
	ldi temp0, 250
	rcall wait_long
	ldi temp0, 250
	rcall wait_long
	cbi OUTPUT_PORT, OUTPUT_PIN

	in temp0, ACSR
	ori temp0, (1<<ACI)
	out ACSR, temp0

	pop temp0
	out SREG, temp0
	pop temp1
	pop temp0
	reti

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; pin change
PCINT:
    rjmp RESET

	reti








;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; routine für kurzes warten
; wartezeit wird in microsekunden über temp0 übergeben.
; temp1 wird überschrieben
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
wait_short:
ws1:
	nop
	ldi temp1, tau_short
ws2:
	dec temp1
	brne ws2
	dec temp0
	brne ws1
	ret


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; routine für langes warten
; wartezeit wird in milisekunden über temp0 übergeben, 
; temp1 und temp2 werden auf dem stack gesichert.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
wait_long:

	push temp1
	push temp2
wl1:
	ldi temp1, tau_long
wl2:
	ldi temp2, 2 ;(atmega@16mhz)
wl3:
	dec temp2
	brne wl3
	dec temp1
	brne wl2
	dec temp0
	brne wl1

	pop temp2
	pop temp1

	ret


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; table with functions for each code wheel position
;
; map:
; PB7 - CW8
; BP6 - CW2
; PB5 - CW1
; PB4 - CW4

functable:  ;                 code wheel positon
        ;off           ;  0   0
    .dw  interval4     ;  1   4
	.dw  interval1     ;  2   1
	.dw  interval5     ;  3   5
	.dw  interval2     ;  4   2
	.dw  interval6     ;  5   6       use function with fast clock here to allow faster programming
	.dw  interval3     ;  6   3
	.dw  interval7     ;  7   7
	.dw  interval8     ;  8   8
	.dw  flash_ttl     ;  9   C
	.dw  interval9     ; 10   9
	.dw  flash         ; 11   D
	.dw  sound         ; 12   A
	.dw  bulb          ; 13   E
	.dw  lightning     ; 14   B
	.dw  manual        ; 15   F

;3.dw manual, interval1, sound, interval2,  lightning, interval3,interval0, interval4


	.dseg
table:	.byte 16


