;-------------------------------------------------------------------------------
; Dieser Datei kann kopiert und modifiziert werden, solange dieser Header in der 
; Datei belassen wird. Der Autor haftet nicht fuer Schaeden jedweder Art, die im
; Zusammenhang mit dieser Datei enstehen.
; Patrick Urban
; Lotharstr. 176
; 47057 Duisburg
; Tel.: ++49 (0)203 352287
; e-Mail: patrick.urban@freenet.de
;-------------------------------------------------------------------------------
; Kodak Ver3: uC-code for slideprojectors which are controlled via m-objects
;
; uC-data: 4MHz, AT90S2313
; used ports: 
; PORT B: Bit 7 : 
;         Bit 6 : 
;         Bit 5 : 
;         Bit 4 : 
;         Bit 3 : brightness
;         Bit 2 : 
;         Bit 1 : transport forward
;         Bit 0 : transport backward
;
; PORT D: Bit 6 : n.u.
;         Bit 5 : n.u.
;         Bit 4 : n.u.
;         Bit 3 : n.u.
;         Bit 2 : n.u.
;         Bit 1 : Tx for UART
;         Bit 0 : Rx for UART
;
; supported commands of P-COM protocoll:
; - RandomAccess (but slide is transported step by step) (Parameter Mode)
; - SetBrightness                                        (Parameter Mode)
; - GroupAddress                                         (Parameter Mode)
; - SystemReturn                                         (StatusMode)
;-------------------------------------------------------------------------------


.include "2313def.inc"

;-- Adressen im konst-Bereich:

;-- Adressen im SRAM:

.equ SRAMOffset     = 0x0060
.equ ActSlidePos    = 0x0063
.equ NewSlidePos    = 0x0064
.equ NewBrightLow   = 0x0065
.equ NewBrightHigh  = 0x0066
.equ OldBrightLow   = 0x0067
.equ OldBrightHigh  = 0x0068

;-- Definition verschiedener Konstanten:

.equ TPulse         = 50        ; TRIAC control time1 (1/2-period) (t = TPulse * 1/f)
.equ TOffset        = 40000

.equ GlobalAdrC     = 0x1F      ; Globale Projektoradresse         ; global projector address
.equ BaudRate       = 25        ; 9600 BAUD bei 4MHz               ; baud-rate for data-transmission
.equ TraySizeC      = 80        ; number of slides in tray         ; max. number of slides in tray 
.equ BackTimeC      = 9         ; 250ns * 1024 * 256 * BackTimeC   ; time to activate a slide-transport backward
.equ ForTimeC       = 10        ; 250ns * 1024 * 256 * ForTimeC    ; time to activate a slide-transport forward
.equ TransTimeC     = 25        ; 250ns * 1024 * 256 * TransTimeC  ; time for a transport of a slide (both directions)

.equ ParameterModeC = 0x00      ; 00000 00 0 (Mode)
.equ SetResetModeC  = 0x02      ; 00000 01 0 (Mode)
.equ DirectModeC    = 0x04      ; 00000 10 0 (Mode)
.equ StatusModeC    = 0x06      ; 00000 11 0 (Mode)

.equ RandomAccessC  = 0x00      ; 0000 00X 0 (command in 'Parameter Mode')
.equ SetBrightnessC = 0x10      ; 0001 XXX 0 (command in 'Parameter Mode')
.equ GroupAddressC  = 0x30      ; 0011 000 0 (command in 'Parameter Mode')

.equ GetTrayC       = 0xA0      ;            (command in 'Status Mode')
.equ GetKeysC       = 0xB0      ;            (command in 'Status Mode')
.equ SysStatC       = 0xC0      ;            (command in 'Status Mode')
.equ SysRetC        = 0xD0      ;            (command in 'Status Mode')

.equ ResetPrjAddrC  = 0x00      ; 00CC CCCC  (used in 'Direct Mode')
.equ SetPrjAddrC    = 0x01      ; 00CC CCCC  (used in 'Direct Mode')
.equ LowerLimitLowC = 0x02      ; 00CC CCCC  (used in 'Direct Mode')
.equ LowerLimitHighC= 0x03      ; 00CC CCCC  (used in 'Direct Mode')
.equ UpperLimitLowC = 0x04      ; 00CC CCCC  (used in 'Direct Mode')
.equ UpperLimitHighC= 0x05      ; 00CC CCCC  (used in 'Direct Mode')

;----------------------------------------------------------------------------------------------------
; hier folgen Register, die staendig verfuegbar sein sollen
;----------------------------------------------------------------------------------------------------

.def LowerLimitLow  = r6
.def LowerLimitHigh = r7
.def UpperLimitLow  = r8
.def UpperLimitHigh = r9

.def Tmp1           = r16  ; universelles Register
.def Tmp2           = r17  ; universelles Register
.def Tmp3           = r18  ; universelles Register
.def Tmp4           = r19  ; universelles Register
       
.def PrjAdr         = r3   ; Adresse des Projektores aus dem EEPROM bei Programmstart  
.def GroupAdr       = r4   ; address if projector is combined in a group (0x10-0x1E)
.def MoveSlide      = r25  ; actual transport
.def FlagReg        = r21  ; 7: '1', wenn neues Kommando eingelaufen ist (3. Byte)
                           ; 6: '1', wenn Byte gesendet werden soll (Tx-Routine)
                           ; 5: '1', wenn Brightness (high und low-Byte) stabil ist
                           ; 4:
                           ; 3: '1', wenn Relais-Aktivierungszeit, '0', wenn Transportzeit
                           ; 2: '1', wenn ActSlidePos != NewSlidePos
                           ; 1: '1', wenn 2. Byte eingelaufen ist
                           ; 0: '1', wenn 1. Byte eingelaufen ist
.def PulseTime      = r22

.def BrightLow      = r23  ; actual brightness
.def BrightHigh     = r24  ; actual brightness

;----------------------------------------------------------------------------------------------------
; hier folgen Macros
;----------------------------------------------------------------------------------------------------

.macro   PUSHTmp
         push Tmp4           ;
         push Tmp3           ;
         push Tmp2           ;
         push Tmp1           ;
         in   Tmp1,SREG
         push Tmp1            
.endmacro

.macro   POPTmp
         pop  Tmp1
         out  SREG,Tmp1
         pop  Tmp1           ;
         pop  Tmp2           ;
         pop  Tmp3           ;
         pop  Tmp4           ;
.endmacro

;-------------------------------------------------------------------------------------------------------
; Interrupt Sprungziele
;-------------------------------------------------------------------------------------------------------
.cseg
.org 0
          rjmp  Reset                  ; steht immer am Anfang um zum Reset-Handling zu gelangen
.org INT0addr                          ; Externel Interrupt 0 for Zero-Phase-Detection
          rjmp  EXT_INT0
.org INT1addr                          ; not used in this application
          reti
.org OC1addr                           ; Output Compare1 
          rjmp  TIM_COMP1
.org OVF1addr                          ; Overflow1 
          reti
.org OVF0addr                          ; Wartezeit
          rjmp  TIM_OVF0
.org URXCaddr                          ; UART RX Complete Handle
          rjmp  UART_RXC    
.org UTXCaddr                          ; UART TX CompleteHandle
          rjmp  UART_TXC    
;-------------------------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------------------------
.cseg
.org 0x0100 ; das hier kann noch angepasst werden, ist aber schon ganz gut

        rjmp Reset

;-------------------------------------------------------------------------------------------------------
;-- EEPROM Write-Routine
;-------------------------------------------------------------------------------------------------------

.def	EEdwr	=r16		; data byte to write to EEPROM
.def	EEawr	=r17		; address byte to write to

EEWrite:
	sbic	EECR,EEWE	; if EEWE not clear
	rjmp	EEWrite		; wait more
	out	EEAR,EEawr	; output address

	out	EEDR,EEdwr	; output data
	sbi 	EECR,EEMWE	; set master write enable
	sbi	EECR,EEWE	; set EEPROM Write strobe
				; This instruction takes 4 clock cycles since
				; it halts the CPU for two clock cycles
	ret

;-------------------------------------------------------------------------------------------------------
;-- EEPROM Read-Routine
;-------------------------------------------------------------------------------------------------------

.def     EEdrd        = r0   ; fuer die EEPROM Leseroutine
.def     EEard        = r16  ; fuer die EEPROM Leseroutine

EERead:
        sbic  EECR,EEWE
        rjmp  EERead
        out   EEAR,EEard
        sbi   EECR,EERE
        in    EEdrd,EEDR
        ret

;-@-----------------------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------------------------
;-- set stackpointer

Reset:      ldi   Tmp1,RAMEND
            out   SPL,Tmp1

;--------------------------------------------------------------------------------
;-- clear SRAM from 0060h - 018Ch (routine breaks at 0200h)

ClearSRAM:  clr   Tmp1
            ldi   Tmp2,$02
            clr   ZH
            ldi   ZL,$60
DoMore:     st    Z+,Tmp1
            cpse  ZH,Tmp2
            rjmp  DoMore

;--
;-@------------------------------------------------------------------------------
;-- initialize registers und memory

Init:       clr   FlagReg
            clr   Tmp2
            clr   Tmp3
            clr   Tmp4

            ldi   Tmp1,low(TOffset)
            ldi   Tmp2,high(TOffset)
            sts   OldBrightLow,Tmp1
            sts   NewBrightLow,Tmp1
            sts   OldBrightHigh,Tmp2
            sts   NewBrightHigh,Tmp2

            ldi   Tmp1,high(TOffset)
            out   OCR1AH,Tmp1           ; load compare register with TPulse
            ldi   Tmp1,low(TOffset)
            out   OCR1AL,Tmp1

            ldi   Tmp1,BaudRate        ; set UART-BAUT-register
            out   UBRR,Tmp1
            
            ldi   Tmp1,0b11011000      ; enable RX Complete Interrupt, Rx and Tx
            out   UCR,Tmp1
            
            ser   Tmp1                 
            out   DDRB,Tmp1            ; set all bits of PortB to output

	    ser   MoveSlide
;            lds   MoveSlide,NewBrightLow
            out   PORTB,MoveSlide       ; set all Bits to '0'

            ldi   Tmp1,0b01111010
            out   DDRD,Tmp1            ; set Rx and INT0 to input, all other bits are set to output
                                       ; bit 7 not available for 2313

;--------------------------------------------------------------------------------
;-- Timer

            ldi   Tmp1,0b01000010      ; Timer1 OC and Timer0 OVF Interrupt Flag (3-28)
            out   TIMSK,Tmp1

;            ldi   Tmp1,high(TOffset)
;            out   TCNT1H,Tmp1          ; preload Timer1
;            ldi   Tmp1,low(TOffset)
;            out   TCNT1L,Tmp1
            ldi   Tmp1,0b00000001       ; start timer 1 with CK
            out   TCCR1B,Tmp1

;--------------------------------------------------------------------------------
                                       ; MCUCR: MCU-Control_Register (3-29)
            ldi   Tmp1,0b00000011      ; 
            out   MCUCR,Tmp1           ; Interrupt 0 wird auf die steigende Flanke ausgeloest
	    in    Tmp1,GIFR            ; setzte die Flags fuer die externen Interrupts zurueck, damit
            andi  Tmp1,$FF             ; nach dem Enablen der Interrupts nicht gleich eine Interrupt
            out   GIFR,Tmp1            ; Routine ausgefuehrt wird.

            ldi   Tmp1,0b01000000      ; enable den Interrupt INT0
            out   GIMSK,Tmp1           ; GIMSK: General-Interrupt-Mask-Register (3-27)

;--------------------------------------------------------------------------------
            sei                        ; enable Interrupts in status Register
            
;--------------------------------------------------------------------------------
;-- read Projector address from EEPROM
	
            ldi   EEard,0             ; load projector address from EEPROM
            rcall EERead
            mov   PrjAdr,EEdrd        ; and save it in register

            ldi   Tmp1,GlobalAdrC
            mov   GroupAdr,Tmp1       ; set GroupAdr to GlobalAdr

            ldi   EEard,1
            rcall EERead
            mov   LowerLimitLow,EEdrd ; and save it in register
            ldi   EEard,2
            rcall EERead
            mov   LowerLimitHigh,EEdrd ; and save it in register
            ldi   EEard,3
            rcall EERead
            mov   UpperLimitLow,EEdrd ; and save it in register
            ldi   EEard,4
            rcall EERead
            mov   UpperLimitHigh,EEdrd ; and save it in register

            lsl   LowerLimitLow        ; this shift operations (mul by 2 ) have to be done because
            rol   LowerLimitHigh       ; the brighntness is received directly multiplied by 2
            lsl   UpperLimitLow
            rol   UpperLimitHigh

            rjmp  SetLowerLimit	           

;-@-----------------------------------------------------------------------------------------------------
;-- Begin of main-programm
;-------------------------------------------------------------------------------------------------------
Main:       sbrc  FlagReg,7           ; new command ?
            rjmp  NewCommand          ; yes
            sbrc  FlagReg,2           ; actual SlidePos differs from new SlidePos in SRAM?
            rjmp  MoveTray            ; yes
            rjmp  Main                ; no, jump back to Main
            
NewCommand: cbr   FlagReg,0b10000000  ; clear 'NewCommandFlag'
            lds   Tmp1,SRAMOffset     ; load byte 1 from SRAM
            lds   Tmp2,SRAMOffset+1   ; load byte 2 from SRAM
            lds   Tmp3,SRAMOffset+2   ; load byte 3 from SRAM
            andi  Tmp1,0x06           ; mask only the command
            cpi   Tmp1,ParameterModeC 
            breq  ParaMode
            cpi   Tmp1,SetResetModeC
            breq  SetResModeTmp          
            cpi   Tmp1,DirectModeC
            breq  DirectModeTmp
            cpi   Tmp1,StatusModeC
            breq  StatusModeTmp
            rjmp  Main                ; no known mode received

SetResModeTmp: rjmp SetResMode
DirectModeTmp: rjmp DirectMode
StatusModeTmp: rjmp StatusMode


ParaMode:   mov   Tmp4,Tmp2
            andi  Tmp4,0b11110000     ; mask only command
            cpi   Tmp4,RandomAccessC
            breq  RandomAccess
            cpi   Tmp4,SetBrightnessC
            breq  SetBrightness
            cpi   Tmp4,GroupAddressC
            breq  GroupAddress
            rjmp  Main

RandomAccess:
            andi  Tmp2,0b00000010      ; blende das Kommando aus
            lsr   Tmp2                 ; verschiebe um 1 stelle nach rechts
            lsr   Tmp2                 ; verschiebe nochmal, dabei faellt das Bit 0 in das C-Flag
            ror   Tmp3                 ; Tmp3 muss auch noch einmal verschoben werden, um die unterste '0' wegzubekommen
                                       ; dabei wird das C-Flag nach Bit 7 geschoben
            sts   NewSlidePos,Tmp3     ; speichere nun die gewuenschte Position im SRAM
;	    sbrs  FlagReg,4            ; is process of slide-movement activ?
            sbr   FlagReg,0b00000100   ; no, set NewSlidePos in SRAM-Bit in Flag-Reg
            rjmp  Main

SetBrightness: 
            andi  Tmp2,0b00001110      ; blende das Kommando aus            (Tmp2 = 0000BBB0, Tmp3 = BBBBBBB0) 
            lsr   Tmp2                 ; verschiebe um 1 stelle nach rechts (Tmp2 = 00000BBB, Tmp3 = BBBBBBB0)
                                       ; damit steht jetzt in Tmp2 und Tmp3 der mit 2 multipizierte Wert der Brightness
            cp    Tmp3,LowerLimitLow
            cpc   Tmp2,LowerLimitHigh
            brlo  SetLowerLimit

            cp    Tmp3,UpperLimitLow
            cpc   Tmp2,UpperLimitHigh
            brsh  SetUpperLimit
                                       ;    Tmp2       Tmp3
                                       ; (00000xxx) (xxxxxxx0) x2
ActBright:
;	    lsl   Tmp3
;            rol   Tmp2                 ; (0000xxxx) (xxxxxx00) x4
            lsl   Tmp3
            rol   Tmp2                 ; (000xxxxx) (xxxxx000) x8
            mov   Tmp1,Tmp3            ; speichere low Byte fuer spaetere Addition
            mov   Tmp4,Tmp2            ; speichere high Byte fuer spaetere Addition
            lsl   Tmp3
            rol   Tmp2                 ; (00xxxxxx) (xxxx0000) x16
            lsl   Tmp3
            rol   Tmp2                 ; (0xxxxxxx) (xxx00000) x32

       	    add   Tmp3, Tmp1	       ; Add low bytes               x*32 + x*8 = x*40
	    adc   Tmp2, Tmp4	       ; Add high bytes with carry
            ldi   Tmp1,low(TOffset)    ;
            ldi   Tmp4,high(TOffset)   ;
            sub   Tmp1,Tmp3            ; Subtract low bytes  (calculate TOffset - 40*Brightness)
            sbc   Tmp4,Tmp2            ; Subtract high byte with carry


            sbr   FlagReg,32           ; nur wenn das Bit im FlagReg geloescht ist, darf die
                                       ; neue Brightness ausgewertet werden
            sts   NewBrightLow,Tmp1    ; save brightness (lower 8 bits)
            sts   NewBrightHigh,Tmp4   ; save brightness (higher 2 bits)
            cbr   FlagReg,32
            sts   OldBrightLow,Tmp1    ; save brightness (lower 8 bits)
            sts   OldBrightHigh,Tmp4   ; save brightness (higher 2 bits)

            rjmp  Main         

SetLowerLimit:
            mov   Tmp3,LowerLimitLow
            mov   Tmp2,LowerLimitHigh
            rjmp  ActBright                
SetUpperLimit:
            mov   Tmp3,UpperLimitLow
            mov   Tmp2,UpperLimitHigh
            rjmp  ActBright                

GroupAddress:
            lsr   Tmp3
            mov   GroupAdr,Tmp3
            rjmp  Main            

SetResMode: rjmp  Main

DirectMode:                            ; Tmp2 = 1CCCCCCD Tmp3 = DDDDDDD0
            andi  Tmp2,0b01111111      ; Tmp2 = 0CCCCCCD Tmp3 = DDDDDDD0
            lsr   Tmp2                 ; Tmp2 = 00CCCCCC Tmp3 = DDDDDDD0 
            ror   Tmp3                 ; Tmp2 = 00CCCCCC Tmp3 = DDDDDDDD
            cpi   Tmp2,ResetPrjAddrC
            breq  ResPrjAddr
            cpi   Tmp2,SetPrjAddrC
            breq  SetPrjAddr
            cpi   Tmp2,LowerLimitLowC
            breq  SetLLL
            cpi   Tmp2,LowerLimitHighC
            breq  SetLLH
            cpi   Tmp2,UpperLimitLowC
            breq  SetULL
            cpi   Tmp2,UpperLimitHighC
            breq  SetULH
            rjmp  Main

ResPrjAddr: clr   EEdwr
            ldi   EEawr,0
            rcall EEWrite
            clr   PrjAdr,0
            rjmp  Main

SetPrjAddr: mov   EEdwr,Tmp3
            ldi   EEawr,0
            rcall EEWrite
            mov   PrjAdr,Tmp3
            rjmp  Main

; new settings for the brightness will only have an effect after a reset of the uC

SetLLL:     mov   EEdwr,Tmp3
            ldi   EEawr,1
            rcall EEWrite
            mov   LowerLimitLow,Tmp3
            rjmp  Main
SetLLH:     mov   EEdwr,Tmp3
            ldi   EEawr,2
            rcall EEWrite
            mov   LowerLimitHigh,Tmp3
            rjmp  Main
SetULL:     mov   EEdwr,Tmp3
            ldi   EEawr,3
            rcall EEWrite
            mov   UpperLimitLow,Tmp3
            rjmp  Main
SetULH:     mov   EEdwr,Tmp3
            ldi   EEawr,4
            rcall EEWrite
            mov   UpperLimitHigh,Tmp3
            rjmp  Main

StatusMode: cpi   Tmp2,GetTrayC
            breq  GetTray
            cpi   Tmp2,GetKeysC
            breq  GetKeys
            cpi   Tmp2,SysStatC
            breq  SysStat
            cpi   Tmp2,SysRetC
            breq  SysRet
            rjmp  Main

GetTray:    rjmp  Main
GetKeys:    rjmp  Main
SysStat:    rjmp  Main
SysRet:     ldi   Tmp1,0b00000110
            sbr   FlagReg,0b01000000 ; set Tx-Bit in Flag-Reg
            out   UDR,Tmp1
            sbrc  FlagReg,6
            rjmp  PC-1
            ldi   Tmp1,0b11010000
            sbr   FlagReg,0b01000000 ; set Tx-Bit in Flag-Reg
            out   UDR,Tmp1
            sbrc  FlagReg,6
            rjmp  PC-1
            ldi   Tmp1,0b10000010
            sbr   FlagReg,0b01000000 ; set Tx-Bit in Flag-Reg
            out   UDR,Tmp1
            sbrc  FlagReg,6
            rjmp  PC-1
            ldi   Tmp1,0b00110001
            sbr   FlagReg,0b01000000 ; set Tx-Bit in Flag-Reg
            out   UDR,Tmp1
            sbrc  FlagReg,6
            rjmp  PC-1
            ldi   Tmp1,0b00000000
            sbr   FlagReg,0b01000000 ; set Tx-Bit in Flag-Reg
            out   UDR,Tmp1
            sbrc  FlagReg,6
            rjmp  PC-1
            rjmp  Main

;-------------------------------------------------------------------------------------------------------

MoveTray:   cbr   FlagReg,0b00000100 ; clear bit: New-Position-not-yet-reached (bit 2 in FlagReg)
;            sbr   FlagReg,0b00010000 ; set bit 4 to show that a slide-movement is in progress
            lds   Tmp1,ActSlidePos   
            lds   Tmp2,NewSlidePos   
            mov   Tmp3,Tmp1          
            mov   Tmp4,Tmp2          
            cp    Tmp4,Tmp3          ; New - Act
            brsh  NewSOH             ; New is (S)ame (O)r (H)igher
                                     
            sub   Tmp3,Tmp4          ; Act = Act - New
            cpi   Tmp3,TraySizeC/2   ; compare with tray-size                          ; 
            brsh  SlideFor          
            rjmp  SlideBack           
                                     
NewSOH:     cp    Tmp4,Tmp3          ; compare to equal
            breq  Branch1            ; actual and new position are equal
            sub   Tmp4,Tmp3          ; New = New - Act
            cpi   Tmp4,TraySizeC/2   ; compare with tray-size                          ; 
            brsh  SlideBack           
            rjmp  SlideFor          
Branch1:    rjmp  Main               
                                     
SlideFor:   cpi   Tmp1,TraySizeC     ; Overflow from TraySizeC to 0 ?
            breq  UpperLimit         ; yes: branch to UpperLimit
            inc   Tmp1               ; no:  increment actual-slide-position
            sts   ActSlidePos,Tmp1   ; store new actual-slide-position
            rjmp  SlideForA          ;
UpperLimit: clr   Tmp1               ; set actual-slide-position to 0
            sts   ActSlidePos,Tmp1   ; store new actual-slide-position
                                     
SlideForA:  sbr   FlagReg,0b00001000 ; set Relais-Time-Bit in Flag-Reg
            ldi   PulseTime,ForTimeC ; load relais-pulse-time for a transport forward
            clr   Tmp1               ; clear Timer0-register
            out   TCNT0,Tmp1         
            ldi   Tmp1,0b00000101    ; and start Timer0 with Clk/1024
            out   TCCR0,Tmp1         
            cbr   MoveSlide,2        ; activate port for transport forward
            out   PORTB,MoveSlide
            rjmp  Main               
                                     
SlideBack:  cpi   Tmp1,0             ; Underflow from 0 to TraySizeC?
            breq  LowerLimit         ; yes: branch to LowerLimit
            dec   Tmp1               ; no:  decrement actual-slide-position
            sts   ActSlidePos,Tmp1   ; store new actual-slide-position
            rjmp  SlideBackA         ;  
LowerLimit: ldi   Tmp1,TraySizeC     ; set actual-slide-position to TraySizeC
            sts   ActSlidePos,Tmp1   ; store new actual-slide-position
                                     
SlideBackA: sbr   FlagReg,0b00001000 ; set Relais-Time-Bit in Flag-Reg
            ldi   PulseTime,BackTimeC
            clr   Tmp1               ; lade das Zaehlregister mit einer 0 vor
            out   TCNT0,Tmp1         
            ldi   Tmp1,0b00000101    ; und starte den Timer0 mit Clk/1024
            out   TCCR0,Tmp1         
            cbr   MoveSlide,1        ; aktiviere das Ausgangsbit fuer den Transport rueckwaerts
            out   PORTB,MoveSlide
            rjmp  Main
            
;-------------------------------------------------------------------------------------------------------
;-- hier ist das Ende des Hauptprogramms
;-------------------------------------------------------------------------------------------------------

;-------------------------------------------------------------------------------------------------------
;-- Interrupt for INT0
;-------------------------------------------------------------------------------------------------------

EXT_INT0:   PUSHTmp
            
            sbrc  FlagReg,5           ; if interrupt occurs during writing a new
            rjmp  OldBright           ; value for brightness use old value
            lds   BrightHigh,NewBrightHigh
            lds   BrightLow,NewBrightLow
NewBright:  
            sbr   MoveSlide,8         ; start always with a '0'
            out   PortB,MoveSlide

            in    Tmp1,TCNT1L         ; read back timer1 
            in    Tmp2,TCNT1H
            add   Tmp1,BrightLow      ; add time after first pulse has to be shown on bit 3
            adc   Tmp2,BrightHigh
            out   OCR1AH,Tmp2         ; and load this new value to the output compare register
            out   OCR1AL,Tmp1

	    in    Tmp1,TIFR           ; clear interrupt flag for compare
            ori   Tmp1,0b01000000     ; to prevent unwanted ssetting of bit 3
            out   TIFR,Tmp1   

            POPTmp
            reti

OldBright:  lds   BrightHigh,OldBrightHigh
            lds   BrightLow,OldBrightLow
            rjmp  NewBright  

;-------------------------------------------------------------------------------------------------------
;-- Interrupt for Timer1 compare Handle
;-------------------------------------------------------------------------------------------------------

TIM_COMP1:  PUSHTmp

            sbrs  MoveSlide,3         ; toggle bit 3  
            rjmp  ClearPulse
            cbr   MoveSlide,8
ShowPulse:  
            out   PortB,MoveSlide 

            in    Tmp1,OCR1AL         ; load new value for pulse time
            in    Tmp2,OCR1AH
            subi  Tmp1,low(-TPulse)
            sbci  Tmp2,high(-TPulse)
  	    
            out   OCR1AH,Tmp2          ; load compare register with TPulse
            out   OCR1AL,Tmp1
            
            POPTmp
            reti

ClearPulse:
            sbr   MoveSlide,8
            rjmp  ShowPulse

;-------------------------------------------------------------------------------------------------------
;-- Interrupt for Timer0 overflow Handle
;-------------------------------------------------------------------------------------------------------

TIM_OVF0:   ;dekrementiere SlideTime so lange bis SlideTime = 0 ist
            ;deaktiviere die Ausgangsbits fuer den Transport
            ;warte, bis die Transportzeit verstrichen ist
            ;ist sie erreicht, dann :
            ;halte den Zaehler an
            ;vergleiche, ob die neue Position schon erreicht wurde (New = Act)
            ;wenn ja, dann springe zurueck
            ;ansonsten setze das Bit NewSlidePos in SRAM im Flagregister wieder

            PUSHTmp;
            dec   PulseTime           ; 
            sbrs  FlagReg,3           ; calculate time to activate the relais or calculate time for transport?
            rjmp  TransTime           ; bit is cleared -> calculate time for transport
            cpi   PulseTime,0         ; time for relais activation already expired?
            breq  ClearRelais         ; yes: branch to ClearRelais
            POPTmp
            reti

ClearRelais: 
            sbr   MoveSlide,3         ; deactivate port-bits for transport
            out   PORTB,MoveSlide
            cbr   FlagReg,0b00001000  ; clear Relais-Time-Bit, jetzt ist die Transport-Zeit dran
            ldi   PulseTime,TransTimeC
            POPTmp
            reti
            
TransTime:  cpi   PulseTime,0
            breq  ClearTrans
            POPTmp
            reti            

ClearTrans: clr   Tmp1                ; stop Timer0
            out   TCCR0,Tmp1          ;
            lds   Tmp1,ActSlidePos
            lds   Tmp2,NewSlidePos
            cp    Tmp1,Tmp2           ; is NewSlidePosition reached?
            breq  PosReached          ; yes
            sbr   FlagReg,0b00000100  ; no,set bit: New-Position-not-yet-reached (bit 2 in FlagReg) 
            
PosReached: 
;	cbr   FlagReg,0b00010000  ; clear bit to show that slide-movement has finished
            POPTmp
            reti

;-------------------------------------------------------------------------------------------------------
;-- Interrupt for UART data receive
;-------------------------------------------------------------------------------------------------------

UART_RXC:   PUSHTmp;
            in    Tmp1,UDR            ; lese das Daten-Receive-Register aus
            sbrs  Tmp1,0              ; wenn bit 0 gesetzt ist, dann ist das empfangene Byte das erste Byte
            rjmp  Byte23              ; ansonsten handelt es sich um Byte 2 oder 3
            mov   Tmp2,Tmp1           ; sichere das empfangene (1te) Byte temporaer
            lsr   Tmp2                ; Adresse wird ueberprueft:
            lsr   Tmp2                ; blende nur die Adresse ein
            lsr   Tmp2                ; shifte dafuer 3 mal nach rechts
            cp    Tmp2,PrjAdr         ; vergleiche nun, ob der Projektor angesprochen wird
            breq  StoreByte1          ; ja, Adresse war eindeutig
            cpi   Tmp2,GlobalAdrC     ; compare, if global address for all projectores is usede
            breq  StoreByte1          ; yes: global address was recognized
            cp    Tmp2,GroupAdr       ; compare, if group address is used
            breq  StoreByte1          ; yes: global address was recognized
            POPTmp                    ; no: ignore byte
            reti
           
StoreByte1: sts   SRAMOffset,Tmp1     ; speichere das erste Byte
            sbr   FlagReg,0b00000001  ; setze das '1stByteReceivedFlag' im Flagregister
            POPTmp
            reti

Byte23:     sbrs  FlagReg,0           ; wurde schon das 1 Byte empfangen und wurde der Projektor angesprochen?
            rjmp  NoWrite             ; nein, dann warte auf dass naechste Byte
            sbrs  FlagReg,1           ; ja, ist aber schon das 2te Byte eingelaufen ?
            rjmp  StoreByte2
StoreByte3: sts   SRAMOffset+2,Tmp1            
            sbr   FlagReg,0b10000000  ; setze das 'CommandCompleteFlag' im Flagregister
            cbr   FlagReg,0b00000011  ; und nehme die 1st- and 2ndByteReceivedFlags wieder weg
NoWrite:    POPTmp
            reti
            
StoreByte2: sts   SRAMOffset+1,Tmp1
            sbr   FlagReg,0b00000010  ; setze das '2ndByteReceivedFlag' im Flagregister
            POPTmp
            reti
            
;-------------------------------------------------------------------------------------------------------
;-- Interrupt for UART data-transmission
;-------------------------------------------------------------------------------------------------------

UART_TXC:   cbr   FlagReg,0b01000000  ; loesche das TX-Bit wieder, wenn Byte gesendet wurde
            reti
            
;-------------------------------------------------------------------------------------------------------
;-- EEPROM: Adresse des Projektores
;-------------------------------------------------------------------------------------------------------
.eseg
.org 0x00                
        EEPrjAdr : .DB 3                     ; Adresse dieses Proj ist 3
            
        EELowerLimitLow  : .DB  low(140)     ; lower limit of lamp brightness
        EELowerLimitHigh : .DB  high(140)
        EEUpperLimitLow  : .DB  low(950)     ; upper limit of lamp brightness
        EEUpperLimitHigh : .DB  high(950)


; SRAMOffset + 0 : 1. uebertragendes Byte
; SRAMOffset + 1 : 2. uebertragendes Byte
; SRAMOffset + 2 : 3. uebertragendes Byte            

; SRAMOffset + 3 : ActSlidePos : actual slide position
; SRAMOffset + 4 : NewSlidePos : new slide position

; NewBrightLow
; NewBrightHigh
; OldBrightLow
; OldBrightHigh


;             TIM_OVF0
;      PulseTime = PulseTime - 1
; relais-time   or   transport-time?
;      |                  |
; PulseTime = 0?     PulseTime = 0?
;   n|     y|
;  reti   
;
